Merge "msm: gsi: check channel state on timeout"
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
index c811c28..e46fd5c 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
@@ -88,7 +88,28 @@
controller. These pin configurations are installed in the pinctrl
device node. Refer to pinctrl-bindings.txt
+msm_ext_disp is a device which manages the interaction between external
+display interfaces, e.g. Display Port, and the audio subsystem.
+
+Optional properties:
+- qcom,ext-disp: phandle for msm-ext-display module
+- compatible: Must be "qcom,msm-ext-disp"
+
+[Optional child nodes]: These nodes are for devices which are
+dependent on msm_ext_disp. If msm_ext_disp is disabled then
+these devices will be disabled as well. Ex. Audio Codec device.
+
+- ext_disp_audio_codec: Node for Audio Codec.
+- compatible : "qcom,msm-ext-disp-audio-codec-rx";
+
Example:
+ ext_disp: qcom,msm-ext-disp {
+ compatible = "qcom,msm-ext-disp";
+ ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ };
+ };
+
sde_dp: qcom,dp_display@0{
cell-index = <0>;
compatible = "qcom,dp-display";
@@ -131,6 +152,7 @@
"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+ qcom,ext-disp = <&ext_disp>;
qcom,aux-cfg0-settings = [1c 00];
qcom,aux-cfg1-settings = [20 13 23 1d];
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
index 28a0920..0c63c7e 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
@@ -18,10 +18,9 @@
Definition: Should be "qcom,cam-icp".
- compat-hw-name
-
Usage: required
Value type: <string>
- Definition: Should be "qcom,a5" or "qcom,ipe".
+ Definition: Should be "qcom,a5" or "qcom,ipe0" or "qcom,ipe1" or "qcom,bps".
- num-a5
Usage: required
@@ -63,7 +62,7 @@
- compatible
Usage: required
Value type: <string>
- Definition: Should be "qcom,cam-cdm-intf".
+ Definition: Should be "qcom,cam-a5" or "qcom,cam-ipe" or "qcom,cam-bps".
- reg-names
Usage: optional
@@ -128,9 +127,9 @@
Definition: Name of firmware image.
Examples:
-a5: qcom,a5@a10000 {
+a5: qcom,a5@ac00000 {
cell-index = <0>;
- compatible = "qcom,cam_a5";
+ compatible = "qcom,cam-a5";
reg = <0xac00000 0x6000>,
<0xac10000 0x8000>,
<0xac18000 0x3000>;
@@ -169,7 +168,7 @@
qcom,ipe0 {
cell-index = <0>;
- compatible = "qcom,cam_ipe";
+ compatible = "qcom,cam-ipe";
regulator-names = "ipe0-vdd";
ipe0-vdd-supply = <&ipe_0_gdsc>;
clock-names = "ipe_0_ahb_clk",
@@ -189,7 +188,7 @@
qcom,ipe1 {
cell-index = <1>;
- compatible = "qcom,cam_ipe";
+ compatible = "qcom,cam-ipe";
regulator-names = "ipe1-vdd";
ipe1-vdd-supply = <&ipe_1_gdsc>;
clock-names = "ipe_1_ahb_clk",
@@ -209,7 +208,7 @@
bps: qcom,bps {
cell-index = <0>;
- compatible = "qcom,cam_bps";
+ compatible = "qcom,cam-bps";
regulator-names = "bps-vdd";
bps-vdd-supply = <&bps_gdsc>;
clock-names = "bps_ahb_clk",
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
index 2ed913c..72e2ab4 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
@@ -84,6 +84,11 @@
- Scratch region: 0x02
- IO region: 0x03
+- iova-granularity
+ Usage: optional
+ Value type: <u32>
+ Definition: Should specify IOVA granularity for shared memory region.
+
Example:
qcom,cam_smmu@0 {
compatible = "qcom,msm-cam-smmu";
@@ -114,7 +119,8 @@
iova-region-start = <0x7400000>;
iova-region-len = <0x6400000>;
iova-region-id = <0x1>;
- status = "ok";
+ iova-granularity = <0x15>;
+ status = "ok";
};
iova-mem-region-io {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 3fa0ab3..f54cbdc 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -163,62 +163,62 @@
"CCI_I2C_CLK1";
i2c_freq_100Khz: qcom,i2c_standard_mode {
- qcom,hw-thigh = <201>;
- qcom,hw-tlow = <174>;
- qcom,hw-tsu-sto = <204>;
- qcom,hw-tsu-sta = <231>;
- qcom,hw-thd-dat = <22>;
- qcom,hw-thd-sta = <162>;
- qcom,hw-tbuf = <227>;
- qcom,hw-scl-stretch-en = <0>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <3>;
- qcom,cci-clk-src = <37500000>;
+ hw-thigh = <201>;
+ hw-tlow = <174>;
+ hw-tsu-sto = <204>;
+ hw-tsu-sta = <231>;
+ hw-thd-dat = <22>;
+ hw-thd-sta = <162>;
+ hw-tbuf = <227>;
+ hw-scl-stretch-en = <0>;
+ hw-trdhld = <6>;
+ hw-tsp = <3>;
+ cci-clk-src = <37500000>;
status = "ok";
};
i2c_freq_400Khz: qcom,i2c_fast_mode {
- qcom,hw-thigh = <38>;
- qcom,hw-tlow = <56>;
- qcom,hw-tsu-sto = <40>;
- qcom,hw-tsu-sta = <40>;
- qcom,hw-thd-dat = <22>;
- qcom,hw-thd-sta = <35>;
- qcom,hw-tbuf = <62>;
- qcom,hw-scl-stretch-en = <0>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <3>;
- qcom,cci-clk-src = <37500000>;
+ hw-thigh = <38>;
+ hw-tlow = <56>;
+ hw-tsu-sto = <40>;
+ hw-tsu-sta = <40>;
+ hw-thd-dat = <22>;
+ hw-thd-sta = <35>;
+ hw-tbuf = <62>;
+ hw-scl-stretch-en = <0>;
+ hw-trdhld = <6>;
+ hw-tsp = <3>;
+ cci-clk-src = <37500000>;
status = "ok";
};
i2c_freq_custom: qcom,i2c_custom_mode {
- qcom,hw-thigh = <38>;
- qcom,hw-tlow = <56>;
- qcom,hw-tsu-sto = <40>;
- qcom,hw-tsu-sta = <40>;
- qcom,hw-thd-dat = <22>;
- qcom,hw-thd-sta = <35>;
- qcom,hw-tbuf = <62>;
- qcom,hw-scl-stretch-en = <1>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <3>;
- qcom,cci-clk-src = <37500000>;
+ hw-thigh = <38>;
+ hw-tlow = <56>;
+ hw-tsu-sto = <40>;
+ hw-tsu-sta = <40>;
+ hw-thd-dat = <22>;
+ hw-thd-sta = <35>;
+ hw-tbuf = <62>;
+ hw-scl-stretch-en = <1>;
+ hw-trdhld = <6>;
+ hw-tsp = <3>;
+ cci-clk-src = <37500000>;
status = "ok";
};
i2c_freq_1Mhz: qcom,i2c_fast_plus_mode {
- qcom,hw-thigh = <16>;
- qcom,hw-tlow = <22>;
- qcom,hw-tsu-sto = <17>;
- qcom,hw-tsu-sta = <18>;
- qcom,hw-thd-dat = <16>;
- qcom,hw-thd-sta = <15>;
- qcom,hw-tbuf = <24>;
- qcom,hw-scl-stretch-en = <0>;
- qcom,hw-trdhld = <3>;
- qcom,hw-tsp = <3>;
- qcom,cci-clk-src = <37500000>;
+ hw-thigh = <16>;
+ hw-tlow = <22>;
+ hw-tsu-sto = <17>;
+ hw-tsu-sta = <18>;
+ hw-thd-dat = <16>;
+ hw-thd-sta = <15>;
+ hw-tbuf = <24>;
+ hw-scl-stretch-en = <0>;
+ hw-trdhld = <3>;
+ hw-tsp = <3>;
+ cci-clk-src = <37500000>;
status = "ok";
};
};
@@ -795,7 +795,7 @@
cam_a5: qcom,a5@ac00000 {
cell-index = <0>;
- compatible = "qcom,cam_a5";
+ compatible = "qcom,cam-a5";
reg = <0xac00000 0x6000>,
<0xac10000 0x8000>,
<0xac18000 0x3000>;
@@ -832,7 +832,7 @@
cam_ipe0: qcom,ipe0 {
cell-index = <0>;
- compatible = "qcom,cam_ipe";
+ compatible = "qcom,cam-ipe";
regulator-names = "ipe0-vdd";
ipe0-vdd-supply = <&ipe_0_gdsc>;
clock-names = "ipe_0_ahb_clk",
@@ -853,7 +853,7 @@
cam_ipe1: qcom,ipe1 {
cell-index = <1>;
- compatible = "qcom,cam_ipe";
+ compatible = "qcom,cam-ipe";
regulator-names = "ipe1-vdd";
ipe1-vdd-supply = <&ipe_1_gdsc>;
clock-names = "ipe_1_ahb_clk",
@@ -874,7 +874,7 @@
cam_bps: qcom,bps {
cell-index = <0>;
- compatible = "qcom,cam_bps";
+ compatible = "qcom,cam-bps";
regulator-names = "bps-vdd";
bps-vdd-supply = <&bps_gdsc>;
clock-names = "bps_ahb_clk",
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 377f2fe..f33e400 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -369,6 +369,14 @@
label = "wb_display";
};
+ ext_disp: qcom,msm-ext-disp {
+ compatible = "qcom,msm-ext-disp";
+
+ ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ };
+ };
+
sde_dp: qcom,dp_display@0{
cell-index = <0>;
compatible = "qcom,dp-display";
@@ -410,6 +418,7 @@
"crypto_clk", "pixel_clk_rcg", "pixel_parent";
qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+ qcom,ext-disp = <&ext_disp>;
qcom,aux-cfg0-settings = [20 00];
qcom,aux-cfg1-settings = [24 13 23 1d];
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
new file mode 100644
index 0000000..13b5bfd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+&soc {
+ cam_csiphy0: qcom,csiphy@ac65000 {
+ cell-index = <0>;
+ compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+ reg = <0x0ac65000 0x1000>;
+ reg-names = "csiphy";
+ reg-cam-base = <0x65000>;
+ interrupts = <0 477 0>;
+ interrupt-names = "csiphy";
+ regulator-names = "gdscr";
+ gdscr-supply = <&titan_top_gdsc>;
+ csi-vdd-voltage = <1200000>;
+ mipi-csi-vdd-supply = <&pm8998_l26>;
+ mipi-dsi-vdd-supply = <&pm8998_l1>;
+ clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSIPHY0_CLK>,
+ <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>;
+ clock-names = "camnoc_axi_clk",
+ "soc_ahb_clk",
+ "slow_ahb_src_clk",
+ "cpas_ahb_clk",
+ "cphy_rx_clk_src",
+ "csiphy0_clk",
+ "csi0phytimer_clk_src",
+ "csi0phytimer_clk";
+ clock-cntl-level = "turbo";
+ clock-rates =
+ <0 0 0 0 384000000 0 269333333 0>;
+ status = "ok";
+ };
+
+ cam_csiphy1: qcom,csiphy@ac66000{
+ cell-index = <1>;
+ compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+ reg = <0xac66000 0x1000>;
+ reg-names = "csiphy";
+ reg-cam-base = <0x66000>;
+ interrupts = <0 478 0>;
+ interrupt-names = "csiphy";
+ regulator-names = "gdscr";
+ gdscr-supply = <&titan_top_gdsc>;
+ csi-vdd-voltage = <1200000>;
+ mipi-csi-vdd-supply = <&pm8998_l26>;
+ mipi-dsi-vdd-supply = <&pm8998_l1>;
+ clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSIPHY1_CLK>,
+ <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>;
+ clock-names = "camnoc_axi_clk",
+ "soc_ahb_clk",
+ "slow_ahb_src_clk",
+ "cpas_ahb_clk",
+ "cphy_rx_clk_src",
+ "csiphy1_clk",
+ "csi1phytimer_clk_src",
+ "csi1phytimer_clk";
+ clock-cntl-level = "turbo";
+ clock-rates =
+ <0 0 0 0 384000000 0 269333333 0>;
+
+ status = "ok";
+ };
+
+ cam_csiphy2: qcom,csiphy@ac67000 {
+ cell-index = <2>;
+ compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+ reg = <0xac67000 0x1000>;
+ reg-names = "csiphy";
+ reg-cam-base = <0x67000>;
+ interrupts = <0 479 0>;
+ interrupt-names = "csiphy";
+ regulator-names = "gdscr";
+ gdscr-supply = <&titan_top_gdsc>;
+ csi-vdd-voltage = <1200000>;
+ mipi-csi-vdd-supply = <&pm8998_l26>;
+ mipi-dsi-vdd-supply = <&pm8998_l1>;
+ clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSIPHY2_CLK>,
+ <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>;
+ clock-names = "camnoc_axi_clk",
+ "soc_ahb_clk",
+ "slow_ahb_src_clk",
+ "cpas_ahb_clk",
+ "cphy_rx_clk_src",
+ "csiphy2_clk",
+ "csi2phytimer_clk_src",
+ "csi2phytimer_clk";
+ clock-cntl-level = "turbo";
+ clock-rates =
+ <0 0 0 0 384000000 0 269333333 0>;
+ status = "ok";
+ };
+
+ cam_csiphy3: qcom,csiphy@ac68000 {
+ cell-index = <3>;
+ compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+ reg = <0xac67000 0x1000>;
+ reg-names = "csiphy";
+ reg-cam-base = <0x68000>;
+ interrupts = <0 448 0>;
+ interrupt-names = "csiphy";
+ regulator-names = "gdscr";
+ gdscr-supply = <&titan_top_gdsc>;
+ csi-vdd-voltage = <1200000>;
+ mipi-csi-vdd-supply = <&pm8998_l26>;
+ mipi-dsi-vdd-supply = <&pm8998_l1>;
+ clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSIPHY3_CLK>,
+ <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>,
+ <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>;
+ clock-names = "camnoc_axi_clk",
+ "soc_ahb_clk",
+ "slow_ahb_src_clk",
+ "cpas_ahb_clk",
+ "cphy_rx_clk_src",
+ "csiphy3_clk",
+ "csi3phytimer_clk_src",
+ "csi3phytimer_clk";
+ clock-cntl-level = "turbo";
+ clock-rates =
+ <0 0 0 0 384000000 0 269333333 0>;
+ status = "ok";
+ };
+
+ qcom,cam_smmu {
+ compatible = "qcom,msm-cam-smmu";
+ status = "ok";
+
+ msm_cam_smmu_ife {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x808 0x0>,
+ <&apps_smmu 0x810 0x8>,
+ <&apps_smmu 0xc08 0x0>,
+ <&apps_smmu 0xc10 0x8>;
+ label = "ife";
+ ife_iova_mem_map: iova-mem-map {
+ /* IO region is approximately 3.4 GB */
+ iova-mem-region-io {
+ iova-region-name = "io";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0xd8c00000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+
+ msm_cam_icp_fw {
+ compatible = "qcom,msm-cam-smmu-fw-dev";
+ label="icp";
+ memory-region = <&pil_camera_mem>;
+ };
+
+ msm_cam_smmu_icp {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x107A 0x2>,
+ <&apps_smmu 0x1020 0x8>,
+ <&apps_smmu 0x1040 0x8>,
+ <&apps_smmu 0x1030 0x0>,
+ <&apps_smmu 0x1050 0x0>;
+ label = "icp";
+ icp_iova_mem_map: iova-mem-map {
+ iova-mem-region-firmware {
+ /* Firmware region is 5MB */
+ iova-region-name = "firmware";
+ iova-region-start = <0x0>;
+ iova-region-len = <0x500000>;
+ iova-region-id = <0x0>;
+ status = "ok";
+ };
+
+ iova-mem-region-shared {
+ /* Shared region is 100MB long */
+ iova-region-name = "shared";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0x6400000>;
+ iova-region-id = <0x1>;
+ iova-granularity = <0x15>;
+ status = "ok";
+ };
+
+ iova-mem-region-io {
+ /* IO region is approximately 3.3 GB */
+ iova-region-name = "io";
+ iova-region-start = <0xd800000>;
+ iova-region-len = <0xd2800000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+
+ msm_cam_smmu_cpas_cdm {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1000 0x0>;
+ label = "cpas-cdm0";
+ cpas_cdm_iova_mem_map: iova-mem-map {
+ iova-mem-region-io {
+ /* IO region is approximately 3.4 GB */
+ iova-region-name = "io";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0xd8c00000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+
+ msm_cam_smmu_secure {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1001 0x0>;
+ label = "cam-secure";
+ cam_secure_iova_mem_map: iova-mem-map {
+ /* Secure IO region is approximately 3.4 GB */
+ iova-mem-region-io {
+ iova-region-name = "io";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0xd8c00000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+ };
+
+ qcom,cam-cpas@ac40000 {
+ cell-index = <0>;
+ compatible = "qcom,cam-cpas";
+ label = "cpas";
+ arch-compat = "cpas_top";
+ status = "ok";
+ reg-names = "cam_cpas_top", "cam_camnoc";
+ reg = <0xac40000 0x1000>,
+ <0xac42000 0x5000>;
+ reg-cam-base = <0x40000 0x42000>;
+ interrupt-names = "cpas_camnoc";
+ interrupts = <0 459 0>;
+ regulator-names = "camss-vdd";
+ camss-vdd-supply = <&titan_top_gdsc>;
+ clock-names = "gcc_ahb_clk",
+ "gcc_axi_clk",
+ "soc_ahb_clk",
+ "slow_ahb_clk_src",
+ "cpas_ahb_clk",
+ "camnoc_axi_clk";
+ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+ <&clock_gcc GCC_CAMERA_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>;
+ src-clock-name = "slow_ahb_clk_src";
+ clock-rates = <0 0 0 0 0 0>,
+ <0 0 0 19200000 0 0>,
+ <0 0 0 80000000 0 0>,
+ <0 0 0 80000000 0 0>,
+ <0 0 0 80000000 0 0>,
+ <0 0 0 80000000 0 0>,
+ <0 0 0 80000000 0 0>;
+ clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs",
+ "svs_l1", "nominal", "turbo";
+ qcom,msm-bus,name = "cam_ahb";
+ qcom,msm-bus,num-cases = <7>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_AMPSS_M0
+ MSM_BUS_SLAVE_CAMERA_CFG 0 0>,
+ <MSM_BUS_MASTER_AMPSS_M0
+ MSM_BUS_SLAVE_CAMERA_CFG 0 153000>,
+ <MSM_BUS_MASTER_AMPSS_M0
+ MSM_BUS_SLAVE_CAMERA_CFG 0 153000>,
+ <MSM_BUS_MASTER_AMPSS_M0
+ MSM_BUS_SLAVE_CAMERA_CFG 0 300000>,
+ <MSM_BUS_MASTER_AMPSS_M0
+ MSM_BUS_SLAVE_CAMERA_CFG 0 300000>,
+ <MSM_BUS_MASTER_AMPSS_M0
+ MSM_BUS_SLAVE_CAMERA_CFG 0 600000>,
+ <MSM_BUS_MASTER_AMPSS_M0
+ MSM_BUS_SLAVE_CAMERA_CFG 0 600000>;
+ vdd-corners = <RPMH_REGULATOR_LEVEL_OFF
+ RPMH_REGULATOR_LEVEL_RETENTION
+ RPMH_REGULATOR_LEVEL_MIN_SVS
+ RPMH_REGULATOR_LEVEL_LOW_SVS
+ RPMH_REGULATOR_LEVEL_SVS
+ RPMH_REGULATOR_LEVEL_SVS_L1
+ RPMH_REGULATOR_LEVEL_NOM
+ RPMH_REGULATOR_LEVEL_NOM_L1
+ RPMH_REGULATOR_LEVEL_NOM_L2
+ RPMH_REGULATOR_LEVEL_TURBO
+ RPMH_REGULATOR_LEVEL_TURBO_L1>;
+ vdd-corner-ahb-mapping = "suspend", "suspend",
+ "minsvs", "lowsvs", "svs", "svs_l1",
+ "nominal", "nominal", "nominal",
+ "turbo", "turbo";
+ client-id-based;
+ client-names =
+ "csiphy0", "csiphy1", "csiphy2", "cci0",
+ "csid0", "csid1", "csid2",
+ "ife0", "ife1", "ife2", "ipe0",
+ "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0",
+ "icp0", "jpeg-dma0", "jpeg-enc0", "fd0";
+ client-axi-port-names =
+ "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
+ "cam_hf_1", "cam_hf_2", "cam_hf_2",
+ "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
+ "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
+ "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1";
+ client-bus-camnoc-based;
+ qcom,axi-port-list {
+ qcom,axi-port1 {
+ qcom,axi-port-name = "cam_hf_1";
+ qcom,axi-port-mnoc {
+ qcom,msm-bus,name = "cam_hf_1_mnoc";
+ qcom,msm-bus-vector-dyn-vote;
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_CAMNOC_HF0
+ MSM_BUS_SLAVE_EBI_CH0 0 0>,
+ <MSM_BUS_MASTER_CAMNOC_HF0
+ MSM_BUS_SLAVE_EBI_CH0 0 0>;
+ };
+ qcom,axi-port-camnoc {
+ qcom,msm-bus,name = "cam_hf_1_camnoc";
+ qcom,msm-bus-vector-dyn-vote;
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_CAMNOC_HF0_UNCOMP
+ MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>,
+ <MSM_BUS_MASTER_CAMNOC_HF0_UNCOMP
+ MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>;
+ };
+ };
+ qcom,axi-port2 {
+ qcom,axi-port-name = "cam_hf_2";
+ qcom,axi-port-mnoc {
+ qcom,msm-bus,name = "cam_hf_2_mnoc";
+ qcom,msm-bus-vector-dyn-vote;
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_CAMNOC_HF1
+ MSM_BUS_SLAVE_EBI_CH0 0 0>,
+ <MSM_BUS_MASTER_CAMNOC_HF1
+ MSM_BUS_SLAVE_EBI_CH0 0 0>;
+ };
+ qcom,axi-port-camnoc {
+ qcom,msm-bus,name = "cam_hf_2_camnoc";
+ qcom,msm-bus-vector-dyn-vote;
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_CAMNOC_HF1_UNCOMP
+ MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>,
+ <MSM_BUS_MASTER_CAMNOC_HF1_UNCOMP
+ MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>;
+ };
+ };
+ qcom,axi-port3 {
+ qcom,axi-port-name = "cam_sf_1";
+ qcom,axi-port-mnoc {
+ qcom,msm-bus,name = "cam_sf_1_mnoc";
+ qcom,msm-bus-vector-dyn-vote;
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_CAMNOC_SF
+ MSM_BUS_SLAVE_EBI_CH0 0 0>,
+ <MSM_BUS_MASTER_CAMNOC_SF
+ MSM_BUS_SLAVE_EBI_CH0 0 0>;
+ };
+ qcom,axi-port-camnoc {
+ qcom,msm-bus,name = "cam_sf_1_camnoc";
+ qcom,msm-bus-vector-dyn-vote;
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_CAMNOC_SF_UNCOMP
+ MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>,
+ <MSM_BUS_MASTER_CAMNOC_SF_UNCOMP
+ MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 64d6d52..131d932 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -11,6 +11,7 @@
*/
#include "sdm845.dtsi"
+#include "sdm845-v2-camera.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM845 V2";
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 3d66fff..f0a6d9e 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -120,6 +120,18 @@
BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
goto error;
}
+ } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
+ /* SCO Tx */
+ reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
+ reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
+ reg_val, reg);
+ ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
+ if (ret) {
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+ ret, reg);
+ goto error;
+ }
}
/* Enable Tx port hw auto recovery for underrun or overrun error */
@@ -144,9 +156,15 @@
if (is_fm_port(port_num))
reg_val = en | CHRK_SB_PGD_PORT_WM_L8;
+ else if (port_num == CHRK_SB_PGD_PORT_TX_SCO)
+ reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en;
else
reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en;
+ if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO)
+ BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x",
+ reg_val, reg);
+
ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
if (ret)
BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 9f126b3..2cf303e 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1792,6 +1792,12 @@
mutex_unlock(&hash_access_lock);
return err;
}
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
@@ -1828,6 +1834,12 @@
mutex_unlock(&hash_access_lock);
return err;
}
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 55c484e..31e5b76 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -13,6 +13,7 @@
select SND_SOC_HDMI_CODEC if SND_SOC
select SYNC_FILE
select HDCP_QSEECOM
+ select MSM_EXT_DISPLAY
default y
help
DRM/KMS driver for MSM/snapdragon.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b625996..4015832 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -14,6 +14,8 @@
dp/dp_panel.o \
dp/dp_link.o \
dp/dp_ctrl.o \
+ dp/dp_audio.o \
+ dp/dp_debug.o \
dp/dp_display.o \
dp/dp_drm.o \
dp/dp_hdcp2p2.o \
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
new file mode 100644
index 0000000..c263115
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -0,0 +1,794 @@
+/*
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
+
+#include <linux/of_platform.h>
+#include <linux/msm_ext_display.h>
+
+#include <drm/drm_dp_helper.h>
+
+#include "dp_catalog.h"
+#include "dp_audio.h"
+#include "dp_panel.h"
+
+#define HEADER_BYTE_2_BIT 0
+#define PARITY_BYTE_2_BIT 8
+#define HEADER_BYTE_1_BIT 16
+#define PARITY_BYTE_1_BIT 24
+#define HEADER_BYTE_3_BIT 16
+#define PARITY_BYTE_3_BIT 24
+
+struct dp_audio_private {
+ struct platform_device *ext_pdev;
+ struct platform_device *pdev;
+ struct dp_catalog_audio *catalog;
+ struct msm_ext_disp_init_data ext_audio_data;
+ struct dp_panel *panel;
+
+ bool ack_enabled;
+ bool session_on;
+ bool engine_on;
+
+ u32 channels;
+
+ struct completion hpd_comp;
+
+ struct dp_audio dp_audio;
+};
+
+static u8 dp_audio_get_g0_value(u8 data)
+{
+ u8 c[4];
+ u8 g[4];
+ u8 ret_data = 0;
+ u8 i;
+
+ for (i = 0; i < 4; i++)
+ c[i] = (data >> i) & 0x01;
+
+ g[0] = c[3];
+ g[1] = c[0] ^ c[3];
+ g[2] = c[1];
+ g[3] = c[2];
+
+ for (i = 0; i < 4; i++)
+ ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+ return ret_data;
+}
+
+static u8 dp_audio_get_g1_value(u8 data)
+{
+ u8 c[4];
+ u8 g[4];
+ u8 ret_data = 0;
+ u8 i;
+
+ for (i = 0; i < 4; i++)
+ c[i] = (data >> i) & 0x01;
+
+ g[0] = c[0] ^ c[3];
+ g[1] = c[0] ^ c[1] ^ c[3];
+ g[2] = c[1] ^ c[2];
+ g[3] = c[2] ^ c[3];
+
+ for (i = 0; i < 4; i++)
+ ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+ return ret_data;
+}
+
+static u8 dp_audio_calculate_parity(u32 data)
+{
+ u8 x0 = 0;
+ u8 x1 = 0;
+ u8 ci = 0;
+ u8 iData = 0;
+ u8 i = 0;
+ u8 parity_byte;
+ u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
+
+ for (i = 0; i < num_byte; i++) {
+ iData = (data >> i*4) & 0xF;
+
+ ci = iData ^ x1;
+ x1 = x0 ^ dp_audio_get_g1_value(ci);
+ x0 = dp_audio_get_g0_value(ci);
+ }
+
+ parity_byte = x1 | (x0 << 4);
+
+ return parity_byte;
+}
+
+static u32 dp_audio_get_header(struct dp_catalog_audio *catalog,
+ enum dp_catalog_audio_sdp_type sdp,
+ enum dp_catalog_audio_header_type header)
+{
+ catalog->sdp_type = sdp;
+ catalog->sdp_header = header;
+ catalog->get_header(catalog);
+
+ return catalog->data;
+}
+
+static void dp_audio_set_header(struct dp_catalog_audio *catalog,
+ u32 data,
+ enum dp_catalog_audio_sdp_type sdp,
+ enum dp_catalog_audio_header_type header)
+{
+ catalog->sdp_type = sdp;
+ catalog->sdp_header = header;
+ catalog->data = data;
+ catalog->set_header(catalog);
+}
+
+static void dp_audio_stream_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x02;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
+ new_value = value;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = audio->channels - 1;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x1;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x17;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = (0x0 | (0x11 << 2));
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x84;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x1b;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = (0x0 | (0x11 << 2));
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ new_value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x05;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x0F;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
+
+ /* Config header and parity byte 3 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
+
+ new_value = 0x0;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_3_BIT)
+ | (parity_byte << PARITY_BYTE_3_BIT));
+ pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 value, new_value;
+ u8 parity_byte;
+
+ /* Config header and parity byte 1 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
+
+ new_value = 0x06;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_1_BIT)
+ | (parity_byte << PARITY_BYTE_1_BIT));
+ pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
+
+ /* Config header and parity byte 2 */
+ value = dp_audio_get_header(catalog,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
+
+ new_value = 0x0F;
+ parity_byte = dp_audio_calculate_parity(new_value);
+ value |= ((new_value << HEADER_BYTE_2_BIT)
+ | (parity_byte << PARITY_BYTE_2_BIT));
+ pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
+ dp_audio_set_header(catalog, value,
+ DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
+}
+
+static void dp_audio_setup_sdp(struct dp_audio_private *audio)
+{
+ audio->catalog->config_sdp(audio->catalog);
+
+ dp_audio_stream_sdp(audio);
+ dp_audio_timestamp_sdp(audio);
+ dp_audio_infoframe_sdp(audio);
+ dp_audio_copy_management_sdp(audio);
+ dp_audio_isrc_sdp(audio);
+}
+
+static void dp_audio_setup_acr(struct dp_audio_private *audio)
+{
+ u32 select = 0;
+ struct dp_catalog_audio *catalog = audio->catalog;
+
+ switch (audio->dp_audio.bw_code) {
+ case DP_LINK_BW_1_62:
+ select = 0;
+ break;
+ case DP_LINK_BW_2_7:
+ select = 1;
+ break;
+ case DP_LINK_BW_5_4:
+ select = 2;
+ break;
+ case DP_LINK_RATE_810:
+ select = 3;
+ break;
+ default:
+ pr_debug("Unknown link rate\n");
+ select = 0;
+ break;
+ }
+
+ catalog->data = select;
+ catalog->config_acr(catalog);
+}
+
+static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+ u32 safe_to_exit_level = 0;
+
+ switch (audio->dp_audio.lane_count) {
+ case 1:
+ safe_to_exit_level = 14;
+ break;
+ case 2:
+ safe_to_exit_level = 8;
+ break;
+ case 4:
+ safe_to_exit_level = 5;
+ break;
+ default:
+ pr_debug("setting the default safe_to_exit_level = %u\n",
+ safe_to_exit_level);
+ safe_to_exit_level = 14;
+ break;
+ }
+
+ catalog->data = safe_to_exit_level;
+ catalog->safe_to_exit_level(catalog);
+}
+
+static void dp_audio_enable(struct dp_audio_private *audio, bool enable)
+{
+ struct dp_catalog_audio *catalog = audio->catalog;
+
+ catalog->data = enable;
+ catalog->enable(catalog);
+
+ audio->engine_on = enable;
+}
+
+static struct dp_audio_private *get_audio_get_data(struct platform_device *pdev)
+{
+ struct msm_ext_disp_data *ext_data;
+ struct dp_audio *dp_audio;
+
+ if (!pdev) {
+ pr_err("invalid input\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ ext_data = platform_get_drvdata(pdev);
+ if (!ext_data) {
+ pr_err("invalid ext disp data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dp_audio = ext_data->intf_data;
+ if (!ext_data) {
+ pr_err("invalid intf data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return container_of(dp_audio, struct dp_audio_private, dp_audio);
+}
+
+static int dp_audio_info_setup(struct platform_device *pdev,
+ struct msm_ext_disp_audio_setup_params *params)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ audio->channels = params->num_of_channels;
+
+ dp_audio_setup_sdp(audio);
+ dp_audio_setup_acr(audio);
+ dp_audio_safe_to_exit_level(audio);
+ dp_audio_enable(audio, true);
+end:
+ return rc;
+}
+
+static int dp_audio_get_edid_blk(struct platform_device *pdev,
+ struct msm_ext_disp_audio_edid_blk *blk)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct sde_edid_ctrl *edid;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ if (!audio->panel || !audio->panel->edid_ctrl) {
+ pr_err("invalid panel data\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ edid = audio->panel->edid_ctrl;
+
+ blk->audio_data_blk = edid->audio_data_block;
+ blk->audio_data_blk_size = edid->adb_size;
+
+ blk->spk_alloc_data_blk = edid->spkr_alloc_data_block;
+ blk->spk_alloc_data_blk_size = edid->sadb_size;
+end:
+ return rc;
+}
+
+static int dp_audio_get_cable_status(struct platform_device *pdev, u32 vote)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ if (!audio->panel) {
+ pr_err("invalid panel data\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ return audio->session_on;
+end:
+ return rc;
+}
+
+static int dp_audio_get_intf_id(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ return EXT_DISPLAY_TYPE_DP;
+end:
+ return rc;
+}
+
+static void dp_audio_teardown_done(struct platform_device *pdev)
+{
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio))
+ return;
+
+ if (!audio->panel) {
+ pr_err("invalid panel data\n");
+ return;
+ }
+
+ dp_audio_enable(audio, false);
+
+ complete_all(&audio->hpd_comp);
+
+ pr_debug("audio engine disabled\n");
+}
+
+static int dp_audio_ack_done(struct platform_device *pdev, u32 ack)
+{
+ int rc = 0, ack_hpd;
+ struct dp_audio_private *audio;
+
+ audio = get_audio_get_data(pdev);
+ if (IS_ERR(audio)) {
+ rc = PTR_ERR(audio);
+ goto end;
+ }
+
+ if (ack & AUDIO_ACK_SET_ENABLE) {
+ audio->ack_enabled = ack & AUDIO_ACK_ENABLE ?
+ true : false;
+
+ pr_debug("audio ack feature %s\n",
+ audio->ack_enabled ? "enabled" : "disabled");
+ goto end;
+ }
+
+ if (!audio->ack_enabled)
+ goto end;
+
+ ack_hpd = ack & AUDIO_ACK_CONNECT;
+
+ pr_debug("acknowledging audio (%d)\n", ack_hpd);
+
+ if (!audio->engine_on)
+ complete_all(&audio->hpd_comp);
+end:
+ return rc;
+}
+
+static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
+{
+ int rc = 0;
+ struct device_node *pd = NULL;
+ const char *phandle = "qcom,ext-disp";
+ struct msm_ext_disp_init_data *ext;
+ struct msm_ext_disp_audio_codec_ops *ops;
+
+ ext = &audio->ext_audio_data;
+ ops = &ext->codec_ops;
+
+ ext->type = EXT_DISPLAY_TYPE_DP;
+ ext->pdev = audio->pdev;
+ ext->intf_data = &audio->dp_audio;
+
+ ops->audio_info_setup = dp_audio_info_setup;
+ ops->get_audio_edid_blk = dp_audio_get_edid_blk;
+ ops->cable_status = dp_audio_get_cable_status;
+ ops->get_intf_id = dp_audio_get_intf_id;
+ ops->teardown_done = dp_audio_teardown_done;
+ ops->acknowledge = dp_audio_ack_done;
+
+ if (!audio->pdev->dev.of_node) {
+ pr_err("cannot find audio dev.of_node\n");
+ rc = -ENODEV;
+ goto end;
+ }
+
+ pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0);
+ if (!pd) {
+ pr_err("cannot parse %s handle\n", phandle);
+ rc = -ENODEV;
+ goto end;
+ }
+
+ audio->ext_pdev = of_find_device_by_node(pd);
+ if (!audio->ext_pdev) {
+ pr_err("cannot find %s pdev\n", phandle);
+ rc = -ENODEV;
+ goto end;
+ }
+
+ rc = msm_ext_disp_register_intf(audio->ext_pdev, ext);
+ if (rc)
+ pr_err("failed to register disp\n");
+end:
+ if (pd)
+ of_node_put(pd);
+
+ return rc;
+}
+
+static int dp_audio_on(struct dp_audio *dp_audio)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct msm_ext_disp_init_data *ext;
+
+ if (!dp_audio) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+
+ ext = &audio->ext_audio_data;
+
+ audio->session_on = true;
+
+ rc = ext->intf_ops.audio_config(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_CONNECT);
+ if (rc) {
+ pr_err("failed to config audio, err=%d\n", rc);
+ goto end;
+ }
+
+ rc = ext->intf_ops.audio_notify(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_CONNECT);
+ if (rc) {
+ pr_err("failed to notify audio, err=%d\n", rc);
+ goto end;
+ }
+
+ reinit_completion(&audio->hpd_comp);
+ rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
+ if (!rc) {
+ pr_err("timeout\n");
+ rc = -ETIMEDOUT;
+ goto end;
+ }
+
+ pr_debug("success\n");
+end:
+ return rc;
+}
+
+static int dp_audio_off(struct dp_audio *dp_audio)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct msm_ext_disp_init_data *ext;
+
+ if (!dp_audio) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+ ext = &audio->ext_audio_data;
+
+ rc = ext->intf_ops.audio_notify(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_DISCONNECT);
+ if (rc) {
+ pr_err("failed to notify audio, err=%d\n", rc);
+ goto end;
+ }
+
+ reinit_completion(&audio->hpd_comp);
+ rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
+ if (!rc) {
+ pr_err("timeout\n");
+ rc = -ETIMEDOUT;
+ goto end;
+ }
+
+ pr_debug("success\n");
+end:
+ rc = ext->intf_ops.audio_config(audio->ext_pdev,
+ EXT_DISPLAY_TYPE_DP,
+ EXT_DISPLAY_CABLE_DISCONNECT);
+ if (rc)
+ pr_err("failed to config audio, err=%d\n", rc);
+
+ audio->session_on = false;
+ audio->engine_on = false;
+
+ return rc;
+}
+
+struct dp_audio *dp_audio_get(struct platform_device *pdev,
+ struct dp_panel *panel,
+ struct dp_catalog_audio *catalog)
+{
+ int rc = 0;
+ struct dp_audio_private *audio;
+ struct dp_audio *dp_audio;
+
+ if (!pdev || !panel || !catalog) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
+ if (!audio) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ init_completion(&audio->hpd_comp);
+
+ audio->pdev = pdev;
+ audio->panel = panel;
+ audio->catalog = catalog;
+
+ dp_audio = &audio->dp_audio;
+
+ dp_audio->on = dp_audio_on;
+ dp_audio->off = dp_audio_off;
+
+ rc = dp_audio_init_ext_disp(audio);
+ if (rc)
+ goto error;
+
+ catalog->init(catalog);
+
+ return dp_audio;
+error:
+ return ERR_PTR(rc);
+}
+
+void dp_audio_put(struct dp_audio *dp_audio)
+{
+ struct dp_audio_private *audio;
+
+ if (!dp_audio)
+ return;
+
+ audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+
+ kzfree(audio);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h
new file mode 100644
index 0000000..d6e6b74
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_audio.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _DP_AUDIO_H_
+#define _DP_AUDIO_H_
+
+#include <linux/platform_device.h>
+
+#include "dp_panel.h"
+#include "dp_catalog.h"
+
+/**
+ * struct dp_audio
+ * @lane_count: number of lanes configured in current session
+ * @bw_code: link rate's bandwidth code for current session
+ */
+struct dp_audio {
+ u32 lane_count;
+ u32 bw_code;
+
+ /**
+ * on()
+ *
+ * Enables the audio by notifying the user module.
+ *
+ * @dp_audio: an instance of struct dp_audio.
+ *
+ * Returns the error code in case of failure, 0 in success case.
+ */
+ int (*on)(struct dp_audio *dp_audio);
+
+ /**
+ * off()
+ *
+ * Disables the audio by notifying the user module.
+ *
+ * @dp_audio: an instance of struct dp_audio.
+ *
+ * Returns the error code in case of failure, 0 in success case.
+ */
+ int (*off)(struct dp_audio *dp_audio);
+};
+
+/**
+ * dp_audio_get()
+ *
+ * Creates and instance of dp audio.
+ *
+ * @pdev: caller's platform device instance.
+ * @panel: an instance of dp_panel module.
+ * @catalog: an instance of dp_catalog_audio module.
+ *
+ * Returns the error code in case of failure, otherwize
+ * an instance of newly created dp_module.
+ */
+struct dp_audio *dp_audio_get(struct platform_device *pdev,
+ struct dp_panel *panel,
+ struct dp_catalog_audio *catalog);
+
+/**
+ * dp_audio_put()
+ *
+ * Cleans the dp_audio instance.
+ *
+ * @dp_audio: an instance of dp_audio.
+ */
+void dp_audio_put(struct dp_audio *dp_audio);
+#endif /* _DP_AUDIO_H_ */
+
+
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 95a7dc4..ec5b3000 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -59,9 +59,12 @@
{0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
};
+/* audio related catalog functions */
struct dp_catalog_private {
struct device *dev;
struct dp_io *io;
+
+ u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
struct dp_catalog dp_catalog;
};
@@ -700,40 +703,190 @@
end:
return 0;
}
- /* audio related catalog functions */
-static int dp_catalog_audio_acr_ctrl(struct dp_catalog_audio *audio)
+
+static void dp_catalog_audio_init(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = {
+ {
+ MMSS_DP_AUDIO_STREAM_0,
+ MMSS_DP_AUDIO_STREAM_1,
+ MMSS_DP_AUDIO_STREAM_1,
+ },
+ {
+ MMSS_DP_AUDIO_TIMESTAMP_0,
+ MMSS_DP_AUDIO_TIMESTAMP_1,
+ MMSS_DP_AUDIO_TIMESTAMP_1,
+ },
+ {
+ MMSS_DP_AUDIO_INFOFRAME_0,
+ MMSS_DP_AUDIO_INFOFRAME_1,
+ MMSS_DP_AUDIO_INFOFRAME_1,
+ },
+ {
+ MMSS_DP_AUDIO_COPYMANAGEMENT_0,
+ MMSS_DP_AUDIO_COPYMANAGEMENT_1,
+ MMSS_DP_AUDIO_COPYMANAGEMENT_1,
+ },
+ {
+ MMSS_DP_AUDIO_ISRC_0,
+ MMSS_DP_AUDIO_ISRC_1,
+ MMSS_DP_AUDIO_ISRC_1,
+ },
+ };
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+
+ catalog->audio_map = sdp_map;
}
-static int dp_catalog_audio_stream_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 sdp_cfg = 0;
+ u32 sdp_cfg2 = 0;
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+ base = catalog->io->ctrl_io.base;
+
+ /* AUDIO_TIMESTAMP_SDP_EN */
+ sdp_cfg |= BIT(1);
+ /* AUDIO_STREAM_SDP_EN */
+ sdp_cfg |= BIT(2);
+ /* AUDIO_COPY_MANAGEMENT_SDP_EN */
+ sdp_cfg |= BIT(5);
+ /* AUDIO_ISRC_SDP_EN */
+ sdp_cfg |= BIT(6);
+ /* AUDIO_INFOFRAME_SDP_EN */
+ sdp_cfg |= BIT(20);
+
+ pr_debug("sdp_cfg = 0x%x\n", sdp_cfg);
+ dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg);
+
+ sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+ /* IFRM_REGSRC -> Do not use reg values */
+ sdp_cfg2 &= ~BIT(0);
+ /* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
+ sdp_cfg2 &= ~BIT(1);
+
+ pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2);
+ dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2);
}
-static int dp_catalog_audio_timestamp_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
+ void __iomem *base;
+ enum dp_catalog_audio_sdp_type sdp;
+ enum dp_catalog_audio_header_type header;
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ sdp_map = catalog->audio_map;
+ sdp = audio->sdp_type;
+ header = audio->sdp_header;
+
+ audio->data = dp_read(base + sdp_map[sdp][header]);
}
-static int dp_catalog_audio_infoframe_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
+ void __iomem *base;
+ enum dp_catalog_audio_sdp_type sdp;
+ enum dp_catalog_audio_header_type header;
+ u32 data;
+
+ if (!audio)
+ return;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ sdp_map = catalog->audio_map;
+ sdp = audio->sdp_type;
+ header = audio->sdp_header;
+ data = audio->data;
+
+ dp_write(base + sdp_map[sdp][header], data);
}
-static int dp_catalog_audio_copy_mgmt_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 acr_ctrl, select;
+
+ dp_catalog_get_priv(audio);
+
+ select = audio->data;
+ base = catalog->io->ctrl_io.base;
+
+ acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14);
+
+ pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl);
+
+ dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
}
-static int dp_catalog_audio_isrc_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 mainlink_levels, safe_to_exit_level;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ safe_to_exit_level = audio->data;
+
+ mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS);
+ mainlink_levels &= 0xFE0;
+ mainlink_levels |= safe_to_exit_level;
+
+ pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
+ mainlink_levels, safe_to_exit_level);
+
+ dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels);
}
-static int dp_catalog_audio_setup_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_enable(struct dp_catalog_audio *audio)
{
- return 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ bool enable;
+ u32 audio_ctrl;
+
+ dp_catalog_get_priv(audio);
+
+ base = catalog->io->ctrl_io.base;
+ enable = !!audio->data;
+
+ audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG);
+
+ if (enable)
+ audio_ctrl |= BIT(0);
+ else
+ audio_ctrl &= ~BIT(0);
+
+ pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl);
+ dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl);
+
+ /* make sure audio engine is disabled */
+ wmb();
}
struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
@@ -771,13 +924,13 @@
.read_hdcp_status = dp_catalog_ctrl_read_hdcp_status,
};
struct dp_catalog_audio audio = {
- .acr_ctrl = dp_catalog_audio_acr_ctrl,
- .stream_sdp = dp_catalog_audio_stream_sdp,
- .timestamp_sdp = dp_catalog_audio_timestamp_sdp,
- .infoframe_sdp = dp_catalog_audio_infoframe_sdp,
- .copy_mgmt_sdp = dp_catalog_audio_copy_mgmt_sdp,
- .isrc_sdp = dp_catalog_audio_isrc_sdp,
- .setup_sdp = dp_catalog_audio_setup_sdp,
+ .init = dp_catalog_audio_init,
+ .config_acr = dp_catalog_audio_config_acr,
+ .enable = dp_catalog_audio_enable,
+ .config_sdp = dp_catalog_audio_config_sdp,
+ .set_header = dp_catalog_audio_set_header,
+ .get_header = dp_catalog_audio_get_header,
+ .safe_to_exit_level = dp_catalog_audio_safe_to_exit_level,
};
struct dp_catalog_panel panel = {
.timing_cfg = dp_catalog_panel_timing_cfg,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 7fde025..06b7b08 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -77,16 +77,34 @@
u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
};
+enum dp_catalog_audio_sdp_type {
+ DP_AUDIO_SDP_STREAM,
+ DP_AUDIO_SDP_TIMESTAMP,
+ DP_AUDIO_SDP_INFOFRAME,
+ DP_AUDIO_SDP_COPYMANAGEMENT,
+ DP_AUDIO_SDP_ISRC,
+ DP_AUDIO_SDP_MAX,
+};
+
+enum dp_catalog_audio_header_type {
+ DP_AUDIO_SDP_HEADER_1,
+ DP_AUDIO_SDP_HEADER_2,
+ DP_AUDIO_SDP_HEADER_3,
+ DP_AUDIO_SDP_HEADER_MAX,
+};
+
struct dp_catalog_audio {
+ enum dp_catalog_audio_sdp_type sdp_type;
+ enum dp_catalog_audio_header_type sdp_header;
u32 data;
- int (*acr_ctrl)(struct dp_catalog_audio *audio);
- int (*stream_sdp)(struct dp_catalog_audio *audio);
- int (*timestamp_sdp)(struct dp_catalog_audio *audio);
- int (*infoframe_sdp)(struct dp_catalog_audio *audio);
- int (*copy_mgmt_sdp)(struct dp_catalog_audio *audio);
- int (*isrc_sdp)(struct dp_catalog_audio *audio);
- int (*setup_sdp)(struct dp_catalog_audio *audio);
+ void (*init)(struct dp_catalog_audio *audio);
+ void (*enable)(struct dp_catalog_audio *audio);
+ void (*config_acr)(struct dp_catalog_audio *audio);
+ void (*config_sdp)(struct dp_catalog_audio *audio);
+ void (*set_header)(struct dp_catalog_audio *audio);
+ void (*get_header)(struct dp_catalog_audio *audio);
+ void (*safe_to_exit_level)(struct dp_catalog_audio *audio);
};
struct dp_catalog_panel {
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
new file mode 100644
index 0000000..82e34df
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -0,0 +1,498 @@
+/*
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
+
+#include <linux/debugfs.h>
+
+#include "dp_parser.h"
+#include "dp_power.h"
+#include "dp_catalog.h"
+#include "dp_aux.h"
+#include "dp_ctrl.h"
+#include "dp_debug.h"
+#include "drm_connector.h"
+#include "dp_display.h"
+
+#define DEBUG_NAME "drm_dp"
+
+struct dp_debug_private {
+ struct dentry *root;
+
+ struct dp_usbpd *usbpd;
+ struct dp_link *link;
+ struct dp_panel *panel;
+ struct drm_connector **connector;
+ struct device *dev;
+
+ struct dp_debug dp_debug;
+};
+
+static ssize_t dp_debug_write_hpd(struct file *file,
+ const char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char buf[SZ_8];
+ size_t len = 0;
+ int hpd;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ /* Leave room for termination char */
+ len = min_t(size_t, count, SZ_8 - 1);
+ if (copy_from_user(buf, user_buff, len))
+ goto end;
+
+ buf[len] = '\0';
+
+ if (kstrtoint(buf, 10, &hpd) != 0)
+ goto end;
+
+ debug->usbpd->connect(debug->usbpd, hpd);
+end:
+ return -len;
+}
+
+static ssize_t dp_debug_write_edid_modes(struct file *file,
+ const char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char buf[SZ_32];
+ size_t len = 0;
+ int hdisplay = 0, vdisplay = 0, vrefresh = 0;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ goto end;
+
+ /* Leave room for termination char */
+ len = min_t(size_t, count, SZ_32 - 1);
+ if (copy_from_user(buf, user_buff, len))
+ goto clear;
+
+ buf[len] = '\0';
+
+ if (sscanf(buf, "%d %d %d", &hdisplay, &vdisplay, &vrefresh) != 3)
+ goto clear;
+
+ if (!hdisplay || !vdisplay || !vrefresh)
+ goto clear;
+
+ debug->dp_debug.debug_en = true;
+ debug->dp_debug.hdisplay = hdisplay;
+ debug->dp_debug.vdisplay = vdisplay;
+ debug->dp_debug.vrefresh = vrefresh;
+ goto end;
+clear:
+ pr_debug("clearing debug modes\n");
+ debug->dp_debug.debug_en = false;
+end:
+ return len;
+}
+
+static ssize_t dp_debug_read_connected(struct file *file,
+ char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char buf[SZ_8];
+ u32 len = 0;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ len += snprintf(buf, SZ_8, "%d\n", debug->usbpd->hpd_high);
+
+ if (copy_to_user(user_buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+ return len;
+}
+
+static ssize_t dp_debug_read_edid_modes(struct file *file,
+ char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char *buf;
+ u32 len = 0;
+ int rc = 0;
+ struct drm_connector *connector;
+ struct drm_display_mode *mode;
+
+ if (!debug) {
+ pr_err("invalid data\n");
+ rc = -ENODEV;
+ goto error;
+ }
+
+ connector = *debug->connector;
+
+ if (!connector) {
+ pr_err("connector is NULL\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (*ppos)
+ goto error;
+
+ buf = kzalloc(SZ_4K, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ list_for_each_entry(mode, &connector->modes, head) {
+ len += snprintf(buf + len, SZ_4K - len,
+ "%s %d %d %d %d %d %d %d %d %d 0x%x\n",
+ mode->name, mode->vrefresh, mode->hdisplay,
+ mode->hsync_start, mode->hsync_end, mode->htotal,
+ mode->vdisplay, mode->vsync_start, mode->vsync_end,
+ mode->vtotal, mode->flags);
+ }
+
+ if (copy_to_user(user_buff, buf, len)) {
+ kfree(buf);
+ rc = -EFAULT;
+ goto error;
+ }
+
+ *ppos += len;
+ kfree(buf);
+
+ return len;
+error:
+ return rc;
+}
+
+static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len)
+{
+ if (rc >= *max_size) {
+ pr_err("buffer overflow\n");
+ return -EINVAL;
+ }
+ *len += rc;
+ *max_size = SZ_4K - *len;
+
+ return 0;
+}
+
+static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
+ size_t count, loff_t *ppos)
+{
+ struct dp_debug_private *debug = file->private_data;
+ char *buf;
+ u32 len = 0, rc = 0;
+ u64 lclk = 0;
+ u32 max_size = SZ_4K;
+
+ if (!debug)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(SZ_4K, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\tdp_panel\n\t\tmax_pclk_khz = %d\n",
+ debug->panel->max_pclk_khz);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\tdrm_dp_link\n\t\trate = %u\n",
+ debug->panel->link_info.rate);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tnum_lanes = %u\n",
+ debug->panel->link_info.num_lanes);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tcapabilities = %lu\n",
+ debug->panel->link_info.capabilities);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\tdp_panel_info:\n\t\tactive = %dx%d\n",
+ debug->panel->pinfo.h_active,
+ debug->panel->pinfo.v_active);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tback_porch = %dx%d\n",
+ debug->panel->pinfo.h_back_porch,
+ debug->panel->pinfo.v_back_porch);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tfront_porch = %dx%d\n",
+ debug->panel->pinfo.h_front_porch,
+ debug->panel->pinfo.v_front_porch);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tsync_width = %dx%d\n",
+ debug->panel->pinfo.h_sync_width,
+ debug->panel->pinfo.v_sync_width);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tactive_low = %dx%d\n",
+ debug->panel->pinfo.h_active_low,
+ debug->panel->pinfo.v_active_low);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\th_skew = %d\n",
+ debug->panel->pinfo.h_skew);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\trefresh rate = %d\n",
+ debug->panel->pinfo.refresh_rate);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tpixel clock khz = %d\n",
+ debug->panel->pinfo.pixel_clk_khz);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tbpp = %d\n",
+ debug->panel->pinfo.bpp);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ /* Link Information */
+ rc = snprintf(buf + len, max_size,
+ "\tdp_link:\n\t\ttest_requested = %d\n",
+ debug->link->test_requested);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tlane_count = %d\n", debug->link->lane_count);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tbw_code = %d\n", debug->link->bw_code);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ lclk = drm_dp_bw_code_to_link_rate(debug->link->bw_code) * 1000;
+ rc = snprintf(buf + len, max_size,
+ "\t\tlclk = %lld\n", lclk);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tv_level = %d\n", debug->link->v_level);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ rc = snprintf(buf + len, max_size,
+ "\t\tp_level = %d\n", debug->link->p_level);
+ if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+ goto error;
+
+ if (copy_to_user(user_buff, buf, len))
+ goto error;
+
+ *ppos += len;
+
+ kfree(buf);
+ return len;
+error:
+ kfree(buf);
+ return -EINVAL;
+}
+
+static const struct file_operations dp_debug_fops = {
+ .open = simple_open,
+ .read = dp_debug_read_info,
+};
+
+static const struct file_operations edid_modes_fops = {
+ .open = simple_open,
+ .read = dp_debug_read_edid_modes,
+ .write = dp_debug_write_edid_modes,
+};
+
+static const struct file_operations hpd_fops = {
+ .open = simple_open,
+ .write = dp_debug_write_hpd,
+};
+
+static const struct file_operations connected_fops = {
+ .open = simple_open,
+ .read = dp_debug_read_connected,
+};
+
+static int dp_debug_init(struct dp_debug *dp_debug)
+{
+ int rc = 0;
+ struct dp_debug_private *debug = container_of(dp_debug,
+ struct dp_debug_private, dp_debug);
+ struct dentry *dir, *file, *edid_modes;
+ struct dentry *hpd, *connected;
+ struct dentry *root = debug->root;
+
+ dir = debugfs_create_dir(DEBUG_NAME, NULL);
+ if (IS_ERR_OR_NULL(dir)) {
+ rc = PTR_ERR(dir);
+ pr_err("[%s] debugfs create dir failed, rc = %d\n",
+ DEBUG_NAME, rc);
+ goto error;
+ }
+
+ file = debugfs_create_file("dp_debug", 0444, dir,
+ debug, &dp_debug_fops);
+ if (IS_ERR_OR_NULL(file)) {
+ rc = PTR_ERR(file);
+ pr_err("[%s] debugfs create file failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ edid_modes = debugfs_create_file("edid_modes", 0644, dir,
+ debug, &edid_modes_fops);
+ if (IS_ERR_OR_NULL(edid_modes)) {
+ rc = PTR_ERR(edid_modes);
+ pr_err("[%s] debugfs create edid_modes failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ hpd = debugfs_create_file("hpd", 0644, dir,
+ debug, &hpd_fops);
+ if (IS_ERR_OR_NULL(hpd)) {
+ rc = PTR_ERR(hpd);
+ pr_err("[%s] debugfs hpd failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ connected = debugfs_create_file("connected", 0444, dir,
+ debug, &connected_fops);
+ if (IS_ERR_OR_NULL(connected)) {
+ rc = PTR_ERR(connected);
+ pr_err("[%s] debugfs connected failed, rc=%d\n",
+ DEBUG_NAME, rc);
+ goto error_remove_dir;
+ }
+
+ root = dir;
+ return rc;
+error_remove_dir:
+ debugfs_remove(dir);
+error:
+ return rc;
+}
+
+struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
+ struct dp_usbpd *usbpd, struct dp_link *link,
+ struct drm_connector **connector)
+{
+ int rc = 0;
+ struct dp_debug_private *debug;
+ struct dp_debug *dp_debug;
+
+ if (!dev || !panel || !usbpd || !link) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL);
+ if (!debug) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ debug->dp_debug.debug_en = false;
+ debug->usbpd = usbpd;
+ debug->link = link;
+ debug->panel = panel;
+ debug->dev = dev;
+ debug->connector = connector;
+
+ dp_debug = &debug->dp_debug;
+ dp_debug->vdisplay = 0;
+ dp_debug->hdisplay = 0;
+ dp_debug->vrefresh = 0;
+
+ dp_debug_init(dp_debug);
+
+ return dp_debug;
+error:
+ return ERR_PTR(rc);
+}
+
+static int dp_debug_deinit(struct dp_debug *dp_debug)
+{
+ struct dp_debug_private *debug;
+
+ if (!dp_debug)
+ return -EINVAL;
+
+ debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
+
+ debugfs_remove(debug->root);
+
+ return 0;
+}
+
+void dp_debug_put(struct dp_debug *dp_debug)
+{
+ struct dp_debug_private *debug;
+
+ if (!dp_debug)
+ return;
+
+ debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
+
+ dp_debug_deinit(dp_debug);
+
+ kzfree(debug);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
new file mode 100644
index 0000000..7fd5330
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -0,0 +1,60 @@
+/*
+ * 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 _DP_DEBUG_H_
+#define _DP_DEBUG_H_
+
+#include "dp_panel.h"
+#include "dp_link.h"
+#include "dp_usbpd.h"
+
+/**
+ * struct dp_debug
+ * @debug_en: specifies whether debug mode enabled
+ * @vdisplay: used to filter out vdisplay value
+ * @hdisplay: used to filter out hdisplay value
+ * @vrefresh: used to filter out vrefresh value
+ */
+struct dp_debug {
+ bool debug_en;
+ int vdisplay;
+ int hdisplay;
+ int vrefresh;
+};
+
+/**
+ * dp_debug_get() - configure and get the DisplayPlot debug module data
+ *
+ * @dev: device instance of the caller
+ * @panel: instance of panel module
+ * @usbpd: instance of usbpd module
+ * @link: instance of link module
+ * @connector: double pointer to display connector
+ * return: pointer to allocated debug module data
+ *
+ * This function sets up the debug module and provides a way
+ * for debugfs input to be communicated with existing modules
+ */
+struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
+ struct dp_usbpd *usbpd, struct dp_link *link,
+ struct drm_connector **connector);
+/**
+ * dp_debug_put()
+ *
+ * Cleans up dp_debug instance
+ *
+ * @dp_debug: instance of dp_debug
+ */
+void dp_debug_put(struct dp_debug *dp_debug);
+#endif /* _DP_DEBUG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index b4dafe4..4dcf3b4 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -31,8 +31,10 @@
#include "dp_link.h"
#include "dp_panel.h"
#include "dp_ctrl.h"
+#include "dp_audio.h"
#include "dp_display.h"
#include "sde_hdcp.h"
+#include "dp_debug.h"
static struct dp_display *g_dp_display;
@@ -59,6 +61,7 @@
bool core_initialized;
bool power_on;
bool hpd_irq_on;
+ bool audio_supported;
struct platform_device *pdev;
struct dentry *root;
@@ -72,6 +75,9 @@
struct dp_link *link;
struct dp_panel *panel;
struct dp_ctrl *ctrl;
+ struct dp_audio *audio;
+ struct dp_debug *debug;
+
struct dp_hdcp hdcp;
struct dp_usbpd_cb usbpd_cb;
@@ -120,80 +126,6 @@
return IRQ_HANDLED;
}
-static ssize_t debugfs_dp_info_read(struct file *file, char __user *buff,
- size_t count, loff_t *ppos)
-{
- struct dp_display_private *dp = file->private_data;
- char *buf;
- u32 len = 0;
-
- if (!dp)
- return -ENODEV;
-
- if (*ppos)
- return 0;
-
- buf = kzalloc(SZ_4K, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- len += snprintf(buf + len, (SZ_4K - len), "name = %s\n", dp->name);
- len += snprintf(buf + len, (SZ_4K - len),
- "\tResolution = %dx%d\n",
- dp->panel->pinfo.h_active,
- dp->panel->pinfo.v_active);
-
- if (copy_to_user(buff, buf, len)) {
- kfree(buf);
- return -EFAULT;
- }
-
- *ppos += len;
-
- kfree(buf);
- return len;
-}
-
-static const struct file_operations dp_debug_fops = {
- .open = simple_open,
- .read = debugfs_dp_info_read,
-};
-
-static int dp_display_debugfs_init(struct dp_display_private *dp)
-{
- int rc = 0;
- struct dentry *dir, *file;
-
- dir = debugfs_create_dir(dp->name, NULL);
- if (IS_ERR_OR_NULL(dir)) {
- rc = PTR_ERR(dir);
- pr_err("[%s] debugfs create dir failed, rc = %d\n",
- dp->name, rc);
- goto error;
- }
-
- file = debugfs_create_file("dp_debug", 0444, dir, dp, &dp_debug_fops);
- if (IS_ERR_OR_NULL(file)) {
- rc = PTR_ERR(file);
- pr_err("[%s] debugfs create file failed, rc=%d\n",
- dp->name, rc);
- goto error_remove_dir;
- }
-
- dp->root = dir;
- return rc;
-error_remove_dir:
- debugfs_remove(dir);
-error:
- return rc;
-}
-
-static int dp_display_debugfs_deinit(struct dp_display_private *dp)
-{
- debugfs_remove(dp->root);
- return 0;
-}
-
static void dp_display_hdcp_cb_work(struct work_struct *work)
{
struct dp_display_private *dp;
@@ -429,12 +361,6 @@
dp->dp_display.drm_dev = drm;
priv = drm->dev_private;
- rc = dp_display_debugfs_init(dp);
- if (rc) {
- pr_err("[%s]Debugfs init failed, rc=%d\n", dp->name, rc);
- goto end;
- }
-
rc = dp->parser->parse(dp->parser);
if (rc) {
pr_err("device tree parsing failed\n");
@@ -488,7 +414,6 @@
(void)dp->power->power_client_deinit(dp->power);
(void)dp->panel->sde_edid_deregister(dp->panel);
(void)dp->aux->drm_aux_deregister(dp->aux);
- (void)dp_display_debugfs_deinit(dp);
dp_display_deinitialize_hdcp(dp);
}
@@ -501,11 +426,16 @@
{
int rc = 0;
u32 max_pclk_from_edid = 0;
+ struct edid *edid;
rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
return rc;
+ edid = dp->panel->edid_ctrl->edid;
+
+ dp->audio_supported = drm_detect_monitor_audio(edid);
+
max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
@@ -565,6 +495,9 @@
dp->hdcp.ops->off(dp->hdcp.data);
}
+ if (dp->audio_supported)
+ dp->audio->off(dp->audio);
+
dp->dp_display.is_connected = false;
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
@@ -620,6 +553,9 @@
/* cancel any pending request */
dp->ctrl->abort(dp->ctrl);
+ if (dp->audio_supported)
+ dp->audio->off(dp->audio);
+
dp->dp_display.is_connected = false;
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
@@ -760,6 +696,20 @@
pr_err("failed to initialize ctrl, rc = %d\n", rc);
goto err;
}
+
+ dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio);
+ if (IS_ERR(dp->audio)) {
+ rc = PTR_ERR(dp->audio);
+ pr_err("failed to initialize audio, rc = %d\n", rc);
+ }
+
+ dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
+ dp->link, &dp->dp_display.connector);
+ if (IS_ERR(dp->debug)) {
+ rc = PTR_ERR(dp->debug);
+ pr_err("failed to initialize debug, rc = %d\n", rc);
+ goto err;
+ }
err:
return rc;
}
@@ -821,6 +771,12 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
+ if (dp->audio_supported) {
+ dp->audio->bw_code = dp->link->bw_code;
+ dp->audio->lane_count = dp->link->lane_count;
+ dp->audio->on(dp->audio);
+ }
+
complete_all(&dp->notification_comp);
dp_display_update_hdcp_info(dp);
@@ -916,6 +872,20 @@
return 0;
}
+static struct dp_debug *dp_get_debug(struct dp_display *dp_display)
+{
+ struct dp_display_private *dp;
+
+ if (!dp_display) {
+ pr_err("invalid input\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ return dp->debug;
+}
+
static int dp_display_unprepare(struct dp_display *dp)
{
return 0;
@@ -979,6 +949,7 @@
g_dp_display->prepare = dp_display_prepare;
g_dp_display->unprepare = dp_display_unprepare;
g_dp_display->request_irq = dp_request_irq;
+ g_dp_display->get_debug = dp_get_debug;
rc = component_add(&pdev->dev, &dp_display_comp_ops);
if (rc)
@@ -1010,6 +981,7 @@
static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
{
+ dp_audio_put(dp->audio);
dp_ctrl_put(dp->ctrl);
dp_link_put(dp->link);
dp_panel_put(dp->panel);
@@ -1018,6 +990,7 @@
dp_catalog_put(dp->catalog);
dp_parser_put(dp->parser);
dp_usbpd_put(dp->usbpd);
+ dp_debug_put(dp->debug);
}
static int dp_display_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 3caa277..5943629 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -45,6 +45,7 @@
int (*prepare)(struct dp_display *dp_display);
int (*unprepare)(struct dp_display *dp_display);
int (*request_irq)(struct dp_display *dp_display);
+ struct dp_debug *(*get_debug)(struct dp_display *dp_display);
};
int dp_display_get_num_of_displays(void);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index c388048..802f295 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -22,6 +22,7 @@
#include "msm_kms.h"
#include "sde_connector.h"
#include "dp_drm.h"
+#include "dp_debug.h"
#define to_dp_bridge(x) container_of((x), struct dp_bridge, base)
@@ -456,6 +457,7 @@
void *display)
{
struct dp_display *dp_disp;
+ struct dp_debug *debug;
if (!mode || !display) {
pr_err("invalid params\n");
@@ -463,9 +465,20 @@
}
dp_disp = display;
+ debug = dp_disp->get_debug(dp_disp);
- if (mode->clock > dp_disp->max_pclk_khz)
- return MODE_BAD;
- else
- return MODE_OK;
+ if (debug->debug_en) {
+ if (mode->hdisplay == debug->hdisplay &&
+ mode->vdisplay == debug->vdisplay &&
+ mode->vrefresh == debug->vrefresh &&
+ mode->clock <= dp_disp->max_pclk_khz)
+ return MODE_OK;
+ else
+ return MODE_ERROR;
+ } else {
+ if (mode->clock > dp_disp->max_pclk_khz)
+ return MODE_BAD;
+ else
+ return MODE_OK;
+ }
}
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 7bc1433..df43267 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -73,6 +73,8 @@
struct dp_usbpd dp_usbpd;
enum dp_usbpd_alt_mode alt_mode;
u32 dp_usbpd_config;
+
+ bool forced_disconnect;
};
static const char *dp_usbpd_pin_name(u8 pin)
@@ -342,6 +344,9 @@
dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS);
break;
case USBPD_SVDM_ATTENTION:
+ if (pd->forced_disconnect)
+ break;
+
pd->vdo = *vdos;
dp_usbpd_get_status(pd);
@@ -378,12 +383,38 @@
}
}
+static int dp_usbpd_connect(struct dp_usbpd *dp_usbpd, bool hpd)
+{
+ int rc = 0;
+ struct dp_usbpd_private *pd;
+
+ if (!dp_usbpd) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
+
+ dp_usbpd->hpd_high = hpd;
+ pd->forced_disconnect = !hpd;
+
+ if (hpd)
+ pd->dp_cb->configure(pd->dev);
+ else
+ pd->dp_cb->disconnect(pd->dev);
+
+error:
+ return rc;
+}
+
struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb)
{
int rc = 0;
const char *pd_phandle = "qcom,dp-usbpd-detection";
struct usbpd *pd = NULL;
struct dp_usbpd_private *usbpd;
+ struct dp_usbpd *dp_usbpd;
struct usbpd_svid_handler svid_handler = {
.svid = USB_C_DP_SID,
.vdm_received = NULL,
@@ -423,7 +454,11 @@
kfree(usbpd);
goto error;
}
- return &usbpd->dp_usbpd;
+
+ dp_usbpd = &usbpd->dp_usbpd;
+ dp_usbpd->connect = dp_usbpd_connect;
+
+ return dp_usbpd;
error:
return ERR_PTR(rc);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h
index 67f380a..2682e98 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.h
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h
@@ -48,6 +48,8 @@
* @hpd_high: Hot Plug Detect signal is high.
* @hpd_irq: Change in the status since last message
* @alt_mode_cfg_done: bool to specify alt mode status
+ * @debug_en: bool to specify debug mode
+ * @connect: simulate disconnect or connect for debug mode
*/
struct dp_usbpd {
enum dp_usbpd_port port;
@@ -60,6 +62,9 @@
bool hpd_high;
bool hpd_irq;
bool alt_mode_cfg_done;
+ bool debug_en;
+
+ int (*connect)(struct dp_usbpd *dp_usbpd, bool hpd);
};
/**
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index e9de729..017dbfb 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -26,6 +26,7 @@
struct drm_device *dev;
struct drm_atomic_state *state;
uint32_t crtc_mask;
+ bool nonblock;
struct kthread_work commit_work;
};
@@ -62,7 +63,8 @@
static void commit_destroy(struct msm_commit *c)
{
end_atomic(c->dev->dev_private, c->crtc_mask);
- kfree(c);
+ if (c->nonblock)
+ kfree(c);
}
static void msm_atomic_wait_for_commit_done(
@@ -449,7 +451,8 @@
SDE_ATRACE_END("complete_commit");
}
-static struct msm_commit *commit_init(struct drm_atomic_state *state)
+static struct msm_commit *commit_init(struct drm_atomic_state *state,
+ bool nonblock)
{
struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
@@ -458,6 +461,7 @@
c->dev = state->dev;
c->state = state;
+ c->nonblock = nonblock;
kthread_init_work(&c->commit_work, _msm_drm_commit_work_cb);
@@ -502,6 +506,11 @@
break;
}
+ if (!ret && !commit->nonblock) {
+ kthread_flush_work(&commit->commit_work);
+ kfree(commit);
+ }
+
return ret;
}
@@ -535,7 +544,7 @@
return ret;
}
- c = commit_init(state);
+ c = commit_init(state, nonblock);
if (!c) {
ret = -ENOMEM;
goto error;
@@ -603,20 +612,13 @@
* current layout.
*/
- if (nonblock) {
- ret = msm_atomic_commit_dispatch(dev, state, c);
- if (ret) {
- DRM_ERROR("%s: atomic commit failed\n", __func__);
- drm_atomic_state_free(state);
- commit_destroy(c);
- goto error;
- }
- SDE_ATRACE_END("atomic_commit");
- return 0;
+ ret = msm_atomic_commit_dispatch(dev, state, c);
+ if (ret) {
+ DRM_ERROR("%s: atomic commit failed\n", __func__);
+ drm_atomic_state_free(state);
+ commit_destroy(c);
+ goto error;
}
-
- complete_commit(c);
-
SDE_ATRACE_END("atomic_commit");
return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 6f1d2b7..0f08296 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -2952,7 +2952,7 @@
*/
if (((secure == SDE_DRM_SEC_ONLY) &&
(fb_ns || fb_sec || fb_sec_dir)) ||
- (fb_sec || fb_sec_dir)) {
+ (fb_sec && fb_sec_dir)) {
SDE_ERROR(
"crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d, NS_Dir%d\n",
crtc->base.id,
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 3b92f7a..d2637a4 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1927,6 +1927,12 @@
return;
}
+ if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort &&
+ sde_enc->cur_master->hw_mdptop &&
+ sde_enc->cur_master->hw_mdptop->ops.intf_audio_select)
+ sde_enc->cur_master->hw_mdptop->ops.intf_audio_select(
+ sde_enc->cur_master->hw_mdptop);
+
if (sde_enc->cur_master->hw_mdptop &&
sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
index 5cbfe8e..6896ba7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
@@ -13,10 +13,10 @@
#define _SDE_HW_COLOR_PROC_COMMON_V4_H_
#define GAMUT_TABLE_SEL_OFF 0x4
-#define GAMUT_SCALEA_OFFSET_OFF 0x10
-#define GAMUT_SCALEB_OFFSET_OFF 0x50
-#define GAMUT_LOWER_COLOR_OFF 0xc
#define GAMUT_UPPER_COLOR_OFF 0x8
+#define GAMUT_LOWER_COLOR_OFF 0xc
+#define GAMUT_SCALEA_OFFSET_OFF 0x10
+#define GAMUT_SCALEB_OFFSET_OFF 0xe0
#define GAMUT_TABLE0_SEL BIT(12)
#define GAMUT_MAP_EN BIT(1)
#define GAMUT_EN BIT(0)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
index 4da0456..dcfd81d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
@@ -18,6 +18,7 @@
u32 *opcode)
{
u32 reg, tbl_len, tbl_off, scale_off, i, j;
+ u32 scale_tbl_len, scale_tbl_off;
u32 *scale_data;
if (!payload || !opcode || !hw) {
@@ -50,7 +51,7 @@
*opcode = gamut_mode_5 << 2;
*opcode |= GAMUT_MAP_EN;
tbl_len = GAMUT_3D_MODE5_TBL_SZ;
- tbl_off = 0;
+ tbl_off = GAMUT_MODE_5_OFF;
scale_off = GAMUT_SCALEB_OFFSET_OFF;
break;
default:
@@ -75,12 +76,18 @@
}
if ((*opcode & GAMUT_MAP_EN)) {
- scale_data = &payload->scale_off[0][0];
- tbl_off = base + scale_off;
- tbl_len = GAMUT_3D_SCALE_OFF_TBL_NUM * GAMUT_3D_SCALE_OFF_SZ;
- for (i = 0; i < tbl_len; i++)
- SDE_REG_WRITE(hw, tbl_off + (i * sizeof(u32)),
- scale_data[i]);
+ if (scale_off == GAMUT_SCALEA_OFFSET_OFF)
+ scale_tbl_len = GAMUT_3D_SCALE_OFF_SZ;
+ else
+ scale_tbl_len = GAMUT_3D_SCALEB_OFF_SZ;
+ for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
+ scale_tbl_off = base + scale_off + i * scale_tbl_len;
+ scale_data = &payload->scale_off[i][0];
+ for (j = 0; j < scale_tbl_len; j++)
+ SDE_REG_WRITE(hw,
+ scale_tbl_off + (j * sizeof(u32)),
+ scale_data[j]);
+ }
}
SDE_REG_WRITE(hw, base, *opcode);
return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 70427ab..55cb260 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -26,6 +26,7 @@
REG_DMA_HEADERS_BUFFER_SZ)
#define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * \
GAMUT_3D_SCALE_OFF_TBL_NUM * sizeof(u32))
+#define GAMUT_SCALE_OFF_LEN_12 (GAMUT_3D_SCALEB_OFF_SZ * sizeof(u32))
#define GC_LUT_MEM_SIZE ((sizeof(struct drm_msm_pgc_lut)) + \
REG_DMA_HEADERS_BUFFER_SZ)
@@ -430,6 +431,8 @@
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_cp_cfg *hw_cfg = cfg;
u32 op_mode, reg, tbl_len, tbl_off, scale_off, i;
+ u32 scale_tbl_len, scale_tbl_off;
+ u32 *scale_data;
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_reg_dma_ops *dma_ops;
int rc;
@@ -493,14 +496,24 @@
}
if (op_mode & GAMUT_MAP_EN) {
- REG_DMA_SETUP_OPS(dma_write_cfg,
- ctx->cap->sblk->gamut.base + scale_off,
- payload->scale_off[0], GAMUT_SCALE_OFF_LEN,
- REG_BLK_WRITE_SINGLE, 0, 0);
- rc = dma_ops->setup_payload(&dma_write_cfg);
- if (rc) {
- DRM_ERROR("write scale/off reg failed ret %d\n", rc);
- return;
+ if (scale_off == GAMUT_SCALEA_OFFSET_OFF)
+ scale_tbl_len = GAMUT_SCALE_OFF_LEN;
+ else
+ scale_tbl_len = GAMUT_SCALE_OFF_LEN_12;
+
+ for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
+ scale_tbl_off = ctx->cap->sblk->gamut.base + scale_off +
+ (i * scale_tbl_len);
+ scale_data = &payload->scale_off[i][0];
+ REG_DMA_SETUP_OPS(dma_write_cfg, scale_tbl_off,
+ scale_data, scale_tbl_len,
+ REG_BLK_WRITE_SINGLE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write scale/off reg failed ret %d\n",
+ rc);
+ return;
+ }
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index 07628a17..1a00517 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -685,10 +685,8 @@
hw_cmd);
rc = sde_rotator_inline_commit(hw->rot_ctx, &rot_cmd, cmd_type);
- if (rc) {
- SDE_ERROR("failed to commit inline rotation %d\n", rc);
+ if (rc)
return rc;
- }
/* return to caller */
data->priv_handle = rot_cmd.priv_handle;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 613ac53..ecb445d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -348,6 +348,18 @@
SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static);
}
+static void sde_hw_intf_audio_select(struct sde_hw_mdp *mdp)
+{
+ struct sde_hw_blk_reg_map *c;
+
+ if (!mdp)
+ return;
+
+ c = &mdp->hw;
+
+ SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1);
+}
+
static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
unsigned long cap)
{
@@ -360,6 +372,7 @@
ops->get_safe_status = sde_hw_get_safe_status;
ops->setup_dce = sde_hw_setup_dce;
ops->reset_ubwc = sde_hw_reset_ubwc;
+ ops->intf_audio_select = sde_hw_intf_audio_select;
}
static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 86c4219..0ca5af9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -182,6 +182,12 @@
* @m: pointer to mdss catalog data
*/
void (*reset_ubwc)(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m);
+
+ /**
+ * intf_audio_select - select the external interface for audio
+ * @mdp: mdp top context driver
+ */
+ void (*intf_audio_select)(struct sde_hw_mdp *mdp);
};
struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h
index c95bace..cc020d9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hwio.h
+++ b/drivers/gpu/drm/msm/sde/sde_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* 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
@@ -52,6 +52,7 @@
#define SPLIT_DISPLAY_LOWER_PIPE_CTRL 0x3F0
#define SPLIT_DISPLAY_TE_LINE_INTERVAL 0x3F4
#define INTF_SW_RESET_MASK 0x3FC
+#define HDMI_DP_CORE_SELECT 0x408
#define MDP_OUT_CTL_0 0x410
#define MDP_VSYNC_SEL 0x414
#define DCE_SEL 0x450
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 8a39a34..bd2d56c 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1575,14 +1575,13 @@
* enumerating over all planes attached to the same rotator
* @plane: Pointer to drm plane
* @state: Pointer to drm state to be updated
- * return: none
+ * return: 0 if success; error code otherwise
*/
-static void sde_plane_rot_calc_cfg(struct drm_plane *plane,
+static int sde_plane_rot_calc_cfg(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct sde_plane_state *pstate;
struct sde_plane_rot_state *rstate;
- struct sde_hw_blk *hw_blk;
struct drm_crtc_state *cstate;
struct drm_rect *in_rot, *out_rot;
struct drm_plane *attached_plane;
@@ -1593,24 +1592,19 @@
if (!plane || !state || !state->state) {
SDE_ERROR("invalid parameters\n");
- return;
+ return -EINVAL;
}
cstate = _sde_plane_get_crtc_state(state);
if (IS_ERR_OR_NULL(cstate)) {
ret = PTR_ERR(cstate);
SDE_ERROR("invalid crtc state %d\n", ret);
- return;
+ return ret;
}
pstate = to_sde_plane_state(state);
rstate = &pstate->rot;
- if (!rstate->rot_hw) {
- SDE_ERROR("invalid rotator hw\n");
- return;
- }
-
in_rot = &rstate->in_rot_rect;
in_rot->x1 = state->src_x;
in_rot->y1 = state->src_y;
@@ -1636,8 +1630,6 @@
rstate->out_src_rect = rstate->out_rot_rect;
- hw_blk = &rstate->rot_hw->base;
-
/* enumerating over all planes attached to the same rotator */
drm_atomic_crtc_state_for_each_plane(attached_plane, cstate) {
struct drm_plane_state *attached_state;
@@ -1710,6 +1702,71 @@
attached_out_rect.y2 = dst_y + dst_h;
}
+ /* check source split left/right mismatch */
+ if (attached_out_rect.y1 != rstate->out_src_rect.y1 ||
+ attached_out_rect.y2 != rstate->out_src_rect.y2) {
+ SDE_ERROR(
+ "plane%d.%u src:%dx%d+%d+%d rot:0x%llx fb:%d plane%d.%u src:%dx%d+%d+%d rot:0x%llx fb:%d mismatch\n",
+ plane->base.id,
+ rstate->sequence_id,
+ state->src_w >> 16,
+ state->src_h >> 16,
+ state->src_x >> 16,
+ state->src_y >> 16,
+ sde_plane_get_property(pstate,
+ PLANE_PROP_ROTATION),
+ state->fb ?
+ state->fb->base.id :
+ -1,
+ attached_plane->base.id,
+ attached_rstate->sequence_id,
+ attached_state->src_w >> 16,
+ attached_state->src_h >> 16,
+ attached_state->src_x >> 16,
+ attached_state->src_y >> 16,
+ sde_plane_get_property(attached_pstate,
+ PLANE_PROP_ROTATION),
+ attached_state->fb ?
+ attached_state->fb->base.id :
+ -1);
+ SDE_ERROR(
+ "plane%d.%u sspp:%dx%d+%d+%d plane%d.%u sspp:%dx%d+%d+%d\n",
+ plane->base.id,
+ rstate->sequence_id,
+ (rstate->out_src_rect.x2 -
+ rstate->out_src_rect.x1) >> 16,
+ (rstate->out_src_rect.y2 -
+ rstate->out_src_rect.y1) >> 16,
+ rstate->out_src_rect.x1 >> 16,
+ rstate->out_src_rect.y1 >> 16,
+ attached_plane->base.id,
+ attached_rstate->sequence_id,
+ (attached_out_rect.x2 -
+ attached_out_rect.x1) >> 16,
+ (attached_out_rect.y2 -
+ attached_out_rect.y1) >> 16,
+ attached_out_rect.x1 >> 16,
+ attached_out_rect.y1 >> 16);
+ SDE_EVT32(DRMID(plane),
+ rstate->sequence_id,
+ rstate->out_src_rect.x1 >> 16,
+ rstate->out_src_rect.y1 >> 16,
+ (rstate->out_src_rect.x2 -
+ rstate->out_src_rect.x1) >> 16,
+ (rstate->out_src_rect.y2 -
+ rstate->out_src_rect.y1) >> 16,
+ attached_plane->base.id,
+ attached_rstate->sequence_id,
+ attached_out_rect.x1 >> 16,
+ attached_out_rect.y1 >> 16,
+ (attached_out_rect.x2 -
+ attached_out_rect.x1) >> 16,
+ (attached_out_rect.y2 -
+ attached_out_rect.y1) >> 16,
+ SDE_EVTLOG_ERROR);
+ return -EINVAL;
+ }
+
/* find relative sspp position */
if (attached_out_rect.x1 < rstate->out_src_rect.x1)
xpos++;
@@ -1762,6 +1819,8 @@
rstate->out_rot_rect.y1 >> 16,
drm_rect_width(&rstate->out_rot_rect) >> 16,
drm_rect_height(&rstate->out_rot_rect) >> 16);
+
+ return 0;
}
/**
@@ -1840,8 +1899,8 @@
rot_cmd->src_rect_y = rstate->in_rot_rect.y1 >> 16;
rot_cmd->src_rect_w = drm_rect_width(&rstate->in_rot_rect) >> 16;
rot_cmd->src_rect_h = drm_rect_height(&rstate->in_rot_rect) >> 16;
- rot_cmd->dst_rect_x = rstate->out_rot_rect.x1 >> 16;
- rot_cmd->dst_rect_y = rstate->out_rot_rect.y1 >> 16;
+ rot_cmd->dst_rect_x = 0;
+ rot_cmd->dst_rect_y = 0;
rot_cmd->dst_rect_w = drm_rect_width(&rstate->out_rot_rect) >> 16;
rot_cmd->dst_rect_h = drm_rect_height(&rstate->out_rot_rect) >> 16;
@@ -1886,10 +1945,8 @@
}
ret = rstate->rot_hw->ops.commit(rstate->rot_hw, rot_cmd, hw_cmd);
- if (ret) {
- SDE_ERROR("failed to commit rotator %d\n", ret);
+ if (ret)
return ret;
- }
rstate->out_rotation = rstate->in_rotation;
rstate->out_fb_flags = rot_cmd->dst_modifier ?
@@ -2017,7 +2074,9 @@
}
/* need to re-calc based on all newly validated plane states */
- sde_plane_rot_calc_cfg(plane, new_state);
+ ret = sde_plane_rot_calc_cfg(plane, new_state);
+ if (ret)
+ return ret;
/* check if stream buffer is already attached to rotator */
if (sde_plane_enabled(new_state) && !new_rstate->out_fb)
@@ -2251,7 +2310,9 @@
SDE_DEBUG("plane%d.%d use rotator, fb %d\n",
plane->base.id, rstate->sequence_id, fb_id);
- sde_plane_rot_calc_cfg(plane, state);
+ ret = sde_plane_rot_calc_cfg(plane, state);
+ if (ret)
+ return ret;
ret = sde_plane_rot_submit_command(plane, state,
SDE_HW_ROT_CMD_VALIDATE);
diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h
index ddf89d6..02748a6 100644
--- a/drivers/gpu/msm/adreno_a6xx.h
+++ b/drivers/gpu/msm/adreno_a6xx.h
@@ -73,7 +73,7 @@
uint32_t context_idr;
};
-#define A6XX_CP_SMMU_INFO_MAGIC_REF 0x3618CDA3UL
+#define A6XX_CP_SMMU_INFO_MAGIC_REF 0x241350D5UL
#define A6XX_CP_CTXRECORD_MAGIC_REF 0xAE399D6EUL
/* Size of each CP preemption record */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index 1ee82b5..01c629d 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -382,6 +382,7 @@
req_hdl_param.v4l2_sub_dev_flag = 0;
req_hdl_param.media_entity_flag = 0;
req_hdl_param.priv = ctx;
+ req_hdl_param.ops = ctx->crm_ctx_intf;
ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param);
if (ctx->dev_hdl <= 0) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index 9150795..f74938d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -110,4 +110,13 @@
*/
void cam_hfi_deinit(void);
+/**
+ * hfi_enable_ipe_bps_pc() - Enable interframe pc
+ * Host sends a command to firmware to enable interframe
+ * power collapse for IPE and BPS hardware.
+ *
+ * @enable: flag to enable/disable
+ */
+int hfi_enable_ipe_bps_pc(bool enable);
+
#endif /* _HFI_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
index e7163ac..65dc4b3 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
@@ -158,6 +158,7 @@
#define HFI_PROP_SYS_DEBUG_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x1)
#define HFI_PROP_SYS_IMAGE_VER (HFI_PROPERTY_ICP_COMMON_START + 0x3)
#define HFI_PROP_SYS_SUPPORTED (HFI_PROPERTY_ICP_COMMON_START + 0x4)
+#define HFI_PROP_SYS_IPEBPS_PC (HFI_PROPERTY_ICP_COMMON_START + 0x5)
/* Capabilities reported at sys init */
#define HFI_CAPS_PLACEHOLDER_1 (HFI_COMMON_BASE + 0x1)
@@ -246,6 +247,14 @@
uint32_t debug_mode;
} __packed;
+/**
+ * struct hfi_ipe_bps_pc
+ * payload structure to configure HFI_PROPERTY_SYS_IPEBPS_PC
+ * @enable: Flag to enable IPE, BPS interfrane power collapse
+ */
+struct hfi_ipe_bps_pc {
+ uint32_t enable;
+} __packed;
/**
* struct hfi_cmd_sys_init
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index 48e1f1c..68ce696f 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -193,6 +193,32 @@
return rc;
}
+int hfi_enable_ipe_bps_pc(bool enable)
+{
+ uint8_t *prop;
+ struct hfi_cmd_prop *dbg_prop;
+ uint32_t size = 0;
+
+ size = sizeof(struct hfi_cmd_prop) +
+ sizeof(struct hfi_ipe_bps_pc);
+
+ prop = kzalloc(size, GFP_KERNEL);
+ if (!prop)
+ return -ENOMEM;
+
+ dbg_prop = (struct hfi_cmd_prop *)prop;
+ dbg_prop->size = size;
+ dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY;
+ dbg_prop->num_prop = 1;
+ dbg_prop->prop_data[0] = HFI_PROP_SYS_IPEBPS_PC;
+ dbg_prop->prop_data[1] = enable;
+
+ hfi_write_cmd(prop);
+ kfree(prop);
+
+ return 0;
+}
+
void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size)
{
switch (type) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c
index 08b934e..daffae8 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c
@@ -166,7 +166,7 @@
static const struct of_device_id cam_a5_dt_match[] = {
{
- .compatible = "qcom,cam_a5",
+ .compatible = "qcom,cam-a5",
.data = &cam_a5_hw_info,
},
{}
@@ -176,7 +176,7 @@
static struct platform_driver cam_a5_driver = {
.probe = cam_a5_probe,
.driver = {
- .name = "cam_a5",
+ .name = "cam-a5",
.owner = THIS_MODULE,
.of_match_table = cam_a5_dt_match,
},
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
index 557eaf1..55a2e1b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
@@ -133,6 +133,77 @@
return rc;
}
+static int cam_bps_handle_pc(struct cam_hw_info *bps_dev)
+{
+ struct cam_hw_soc_info *soc_info = NULL;
+ struct cam_bps_device_core_info *core_info = NULL;
+ struct cam_bps_device_hw_info *hw_info = NULL;
+ int pwr_ctrl;
+ int pwr_status;
+
+ soc_info = &bps_dev->soc_info;
+ core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+ hw_info = core_info->bps_hw_info;
+
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+ true, &pwr_ctrl);
+ if (!(pwr_ctrl & BPS_COLLAPSE_MASK)) {
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+ true, &pwr_status);
+
+ cam_cpas_reg_write(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP,
+ hw_info->pwr_ctrl, true, 0x1);
+
+ if ((pwr_status >> BPS_PWR_ON_MASK))
+ return -EINVAL;
+ }
+ cam_bps_get_gdsc_control(soc_info);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true,
+ &pwr_ctrl);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+ true, &pwr_status);
+ CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+ pwr_ctrl, pwr_status);
+
+ return 0;
+}
+
+static int cam_bps_handle_resume(struct cam_hw_info *bps_dev)
+{
+ struct cam_hw_soc_info *soc_info = NULL;
+ struct cam_bps_device_core_info *core_info = NULL;
+ struct cam_bps_device_hw_info *hw_info = NULL;
+ int pwr_ctrl;
+ int pwr_status;
+ int rc = 0;
+
+ soc_info = &bps_dev->soc_info;
+ core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+ hw_info = core_info->bps_hw_info;
+
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl);
+ if (pwr_ctrl & BPS_COLLAPSE_MASK) {
+ CAM_ERR(CAM_ICP, "BPS: resume failed : %d", pwr_ctrl);
+ return -EINVAL;
+ }
+
+ rc = cam_bps_transfer_gdsc_control(soc_info);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status);
+ CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+ pwr_ctrl, pwr_status);
+
+ return rc;
+}
+
int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
void *cmd_args, uint32_t arg_size)
{
@@ -192,6 +263,12 @@
core_info->cpas_start = false;
}
break;
+ case CAM_ICP_BPS_CMD_POWER_COLLAPSE:
+ rc = cam_bps_handle_pc(bps_dev);
+ break;
+ case CAM_ICP_BPS_CMD_POWER_RESUME:
+ rc = cam_bps_handle_resume(bps_dev);
+ break;
default:
break;
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h
index 8a15a7b..0a28bb4f 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h
@@ -19,7 +19,13 @@
#include <linux/platform_device.h>
#include <linux/dma-buf.h>
+#define BPS_COLLAPSE_MASK 0x1
+#define BPS_PWR_ON_MASK 0x2
+
struct cam_bps_device_hw_info {
+ uint32_t hw_idx;
+ uint32_t pwr_ctrl;
+ uint32_t pwr_status;
uint32_t reserved;
};
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c
index ddff677..419bb52 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c
@@ -25,7 +25,10 @@
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
-struct cam_bps_device_hw_info cam_bps_hw_info = {
+static struct cam_bps_device_hw_info cam_bps_hw_info = {
+ .hw_idx = 0,
+ .pwr_ctrl = 0x5c,
+ .pwr_status = 0x58,
.reserved = 0,
};
EXPORT_SYMBOL(cam_bps_hw_info);
@@ -100,7 +103,7 @@
rc = -EINVAL;
return rc;
}
- hw_info = (struct cam_bps_device_hw_info *)match_dev->data;
+ hw_info = &cam_bps_hw_info;
core_info->bps_hw_info = hw_info;
rc = cam_bps_init_soc_resources(&bps_dev->soc_info, cam_bps_irq,
@@ -135,7 +138,7 @@
static const struct of_device_id cam_bps_dt_match[] = {
{
- .compatible = "qcom,cam_bps",
+ .compatible = "qcom,cam-bps",
.data = &cam_bps_hw_info,
},
{}
@@ -145,7 +148,7 @@
static struct platform_driver cam_bps_driver = {
.probe = cam_bps_probe,
.driver = {
- .name = "cam_bps",
+ .name = "cam-bps",
.owner = THIS_MODULE,
.of_match_table = cam_bps_dt_match,
},
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
index 54e898c..07dacb2 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
@@ -82,3 +82,53 @@
return rc;
}
+
+int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+ int i;
+ int rc;
+
+ for (i = 0; i < soc_info->num_rgltr; i++) {
+ rc = regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_FAST);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+ soc_info->rgltr_name[i]);
+ goto rgltr_set_mode_failed;
+ }
+ }
+ return 0;
+
+rgltr_set_mode_failed:
+ for (i = i - 1; i >= 0; i--)
+ if (soc_info->rgltr[i])
+ regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_NORMAL);
+
+ return rc;
+}
+
+int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+ int i;
+ int rc;
+
+ for (i = 0; i < soc_info->num_rgltr; i++) {
+ rc = regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_NORMAL);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+ soc_info->rgltr_name[i]);
+ goto rgltr_set_mode_failed;
+ }
+ }
+ return 0;
+
+rgltr_set_mode_failed:
+ for (i = i - 1; i >= 0; i--)
+ if (soc_info->rgltr[i])
+ regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_FAST);
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
index b16db01..3cffb09 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
@@ -22,4 +22,8 @@
int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info);
+
+int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info);
+
#endif /* _CAM_BPS_SOC_H_*/
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 1b3afc0..f878403 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
@@ -46,12 +46,88 @@
#include "hfi_sys_defs.h"
#include "cam_debug_util.h"
-#define ICP_WORKQ_NUM_TASK 30
+#define ICP_WORKQ_NUM_TASK 30
#define ICP_WORKQ_TASK_CMD_TYPE 1
#define ICP_WORKQ_TASK_MSG_TYPE 2
static struct cam_icp_hw_mgr icp_hw_mgr;
+static int cam_icp_mgr_ipe_bps_resume(struct cam_icp_hw_mgr *hw_mgr,
+ struct cam_icp_hw_ctx_data *ctx_data)
+{
+ struct cam_hw_intf *ipe0_dev_intf = NULL;
+ struct cam_hw_intf *ipe1_dev_intf = NULL;
+ struct cam_hw_intf *bps_dev_intf = NULL;
+ int rc = 0;
+
+ if (!icp_hw_mgr.icp_pc_flag)
+ return rc;
+
+ ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+ ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+ bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+ if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+ CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close");
+ return -EINVAL;
+ }
+
+ bps_dev_intf->hw_ops.process_cmd(
+ bps_dev_intf->hw_priv,
+ CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0);
+
+ ipe0_dev_intf->hw_ops.process_cmd(
+ ipe0_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
+
+ if (ipe1_dev_intf) {
+ ipe1_dev_intf->hw_ops.process_cmd(
+ ipe1_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
+ }
+
+ rc = hfi_enable_ipe_bps_pc(true);
+
+ return rc;
+}
+
+static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr,
+ struct cam_icp_hw_ctx_data *ctx_data, int dev_type)
+{
+ int rc = 0;
+ struct cam_hw_intf *ipe0_dev_intf = NULL;
+ struct cam_hw_intf *ipe1_dev_intf = NULL;
+ struct cam_hw_intf *bps_dev_intf = NULL;
+
+ if (!icp_hw_mgr.icp_pc_flag)
+ return rc;
+
+ ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+ ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+ bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+ if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+ CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close");
+ return -EINVAL;
+ }
+
+ rc = bps_dev_intf->hw_ops.process_cmd(
+ bps_dev_intf->hw_priv,
+ CAM_ICP_BPS_CMD_POWER_COLLAPSE, NULL, 0);
+
+ rc = ipe0_dev_intf->hw_ops.process_cmd(
+ ipe0_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
+
+ if (ipe1_dev_intf) {
+ rc = ipe1_dev_intf->hw_ops.process_cmd(
+ ipe1_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
+ }
+
+ return rc;
+}
+
static int cam_icp_hw_mgr_create_debugfs_entry(void)
{
icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL);
@@ -66,6 +142,14 @@
return -ENOMEM;
}
+ if (!debugfs_create_bool("icp_pc",
+ 0644,
+ icp_hw_mgr.dentry,
+ &icp_hw_mgr.icp_pc_flag)) {
+ CAM_ERR(CAM_ICP, "failed to create icp_pc entry");
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -88,34 +172,27 @@
return rc;
}
-static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr)
+static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag)
{
int i;
uint32_t idx;
uint64_t request_id;
struct cam_icp_hw_ctx_data *ctx_data = NULL;
struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
- struct hfi_msg_frame_process_done *frame_done;
struct hfi_frame_process_info *hfi_frame_process;
struct cam_hw_done_event_data buf_data;
ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
- if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
- CAM_ERR(CAM_ICP, "failed with error : %u",
- ioconfig_ack->err_type);
- return -EIO;
- }
-
- frame_done =
- (struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data;
- if (frame_done->result) {
- CAM_ERR(CAM_ICP, "result : %u", frame_done->result);
- return -EIO;
- }
-
- ctx_data = (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
request_id = ioconfig_ack->user_data2;
+ ctx_data = (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+ if (!ctx_data) {
+ CAM_ERR(CAM_ICP, "Invalid Context");
+ return -EINVAL;
+ }
+ CAM_DBG(CAM_ICP, "ctx : %pK, request_id :%lld",
+ (void *)ctx_data->context_priv, request_id);
+ mutex_lock(&ctx_data->ctx_mutex);
hfi_frame_process = &ctx_data->hfi_frame_process;
for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
if (hfi_frame_process->request_id[i] == request_id)
@@ -124,23 +201,55 @@
if (i >= CAM_FRAME_CMD_MAX) {
CAM_ERR(CAM_ICP, "pkt not found in ctx data for req_id =%lld",
request_id);
+ mutex_unlock(&ctx_data->ctx_mutex);
return -EINVAL;
}
idx = i;
buf_data.request_id = hfi_frame_process->request_id[idx];
- ctx_data->ctxt_event_cb(ctx_data->context_priv, false, &buf_data);
-
- /* now release memory for hfi frame process command */
- CAM_DBG(CAM_ICP, "matching request id: %lld",
- hfi_frame_process->request_id[idx]);
- mutex_lock(&ctx_data->hfi_frame_process.lock);
+ ctx_data->ctxt_event_cb(ctx_data->context_priv, flag, &buf_data);
hfi_frame_process->request_id[idx] = 0;
clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
- mutex_unlock(&ctx_data->hfi_frame_process.lock);
+ mutex_unlock(&ctx_data->ctx_mutex);
+
return 0;
}
+static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr)
+{
+ struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+ struct hfi_msg_frame_process_done *frame_done;
+
+ if (!msg_ptr) {
+ CAM_ERR(CAM_ICP, "msg ptr is NULL");
+ return -EINVAL;
+ }
+
+ ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+ if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
+ CAM_ERR(CAM_ICP, "failed with error : %u",
+ ioconfig_ack->err_type);
+ cam_icp_mgr_handle_frame_process(msg_ptr,
+ ICP_FRAME_PROCESS_FAILURE);
+ return -EIO;
+ }
+
+ frame_done =
+ (struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data;
+ if (!frame_done) {
+ cam_icp_mgr_handle_frame_process(msg_ptr,
+ ICP_FRAME_PROCESS_FAILURE);
+ return -EINVAL;
+ }
+
+ if (frame_done->result)
+ return cam_icp_mgr_handle_frame_process(msg_ptr,
+ ICP_FRAME_PROCESS_FAILURE);
+ else
+ return cam_icp_mgr_handle_frame_process(msg_ptr,
+ ICP_FRAME_PROCESS_SUCCESS);
+}
+
static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr)
{
struct cam_icp_hw_ctx_data *ctx_data = NULL;
@@ -148,6 +257,11 @@
struct hfi_msg_ipe_config *ipe_config_ack = NULL;
struct hfi_msg_bps_common *bps_config_ack = NULL;
+ if (!msg_ptr) {
+ CAM_ERR(CAM_ICP, "msg ptr is NULL");
+ return -EINVAL;
+ }
+
ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
if (ioconfig_ack->opcode == HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO) {
@@ -164,10 +278,7 @@
CAM_ERR(CAM_ICP, "wrong ctx data from IPE response");
return -EINVAL;
}
-
- mutex_lock(&ctx_data->ctx_mutex);
ctx_data->scratch_mem_size = ipe_config_ack->scratch_mem_size;
- mutex_unlock(&ctx_data->ctx_mutex);
} else {
bps_config_ack =
(struct hfi_msg_bps_common *)(ioconfig_ack->msg_data);
@@ -205,9 +316,7 @@
return -EINVAL;
}
- mutex_lock(&ctx_data->ctx_mutex);
ctx_data->fw_handle = create_handle_ack->fw_handle;
- mutex_unlock(&ctx_data->ctx_mutex);
CAM_DBG(CAM_ICP, "fw_handle = %x", ctx_data->fw_handle);
complete(&ctx_data->wait_complete);
@@ -240,6 +349,11 @@
{
int rc;
+ if (!msg_ptr) {
+ CAM_ERR(CAM_ICP, "msg ptr is NULL");
+ return -EINVAL;
+ }
+
switch (msg_ptr[ICP_PACKET_OPCODE]) {
case HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO:
case HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO:
@@ -258,10 +372,11 @@
default:
CAM_ERR(CAM_ICP, "Invalid opcode : %u",
msg_ptr[ICP_PACKET_OPCODE]);
+ rc = -EINVAL;
break;
}
- return 0;
+ return rc;
}
static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr)
@@ -315,7 +430,6 @@
msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
- mutex_lock(&hw_mgr->hw_mgr_mutex);
switch (msg_ptr[ICP_PACKET_TYPE]) {
case HFI_MSG_SYS_INIT_DONE:
CAM_DBG(CAM_ICP, "received SYS_INIT_DONE");
@@ -347,11 +461,10 @@
default:
CAM_ERR(CAM_ICP, "invalid msg : %u",
msg_ptr[ICP_PACKET_TYPE]);
+ rc = -EINVAL;
break;
}
- mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
-
return rc;
}
@@ -521,20 +634,18 @@
static void cam_icp_mgr_put_ctx(struct cam_icp_hw_ctx_data *ctx_data)
{
- mutex_lock(&ctx_data->ctx_mutex);
ctx_data->in_use = false;
- mutex_unlock(&ctx_data->ctx_mutex);
}
static int cam_icp_mgr_abort_handle(
struct cam_icp_hw_ctx_data *ctx_data)
{
int rc = 0;
+ unsigned long rem_jiffies;
int timeout = 5000;
struct hfi_cmd_work_data *task_data;
struct hfi_cmd_ipebps_async abort_cmd;
struct crm_workq_task *task;
- unsigned long rem_jiffies;
task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
if (!task)
@@ -585,10 +696,10 @@
{
int rc = 0;
int timeout = 5000;
+ unsigned long rem_jiffies;
struct hfi_cmd_work_data *task_data;
struct hfi_cmd_ipebps_async destroy_cmd;
struct crm_workq_task *task;
- unsigned long rem_jiffies;
task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
if (!task)
@@ -643,25 +754,20 @@
return -EINVAL;
}
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
if (!hw_mgr->ctx_data[ctx_id].in_use) {
mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
return 0;
}
- mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
-
cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]);
- mutex_lock(&hw_mgr->hw_mgr_mutex);
- mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
hw_mgr->ctx_data[ctx_id].in_use = false;
hw_mgr->ctx_data[ctx_id].fw_handle = 0;
hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0;
- mutex_lock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
- mutex_unlock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
- mutex_destroy(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
hw_mgr->ctxt_cnt--;
kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info);
@@ -737,8 +843,8 @@
sizeof(fw_buf_info));
if (rc)
CAM_ERR(CAM_ICP, "nullify the fw buf failed");
-
mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
for (i = 0; i < CAM_ICP_CTX_MAX; i++)
cam_icp_mgr_release_ctx(hw_mgr, i);
@@ -748,7 +854,8 @@
cam_icp_free_hfi_mem();
hw_mgr->fw_download = false;
mutex_unlock(&hw_mgr->hw_mgr_mutex);
- return 0;
+
+ return rc;
}
static int cam_icp_mgr_device_init(struct cam_icp_hw_mgr *hw_mgr)
@@ -808,6 +915,10 @@
struct cam_icp_a5_set_fw_buf_info fw_buf_info;
a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+ return -EINVAL;
+ }
a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
irq_cb.icp_hw_mgr_cb = cam_icp_hw_mgr_cb;
@@ -853,6 +964,10 @@
struct hfi_mem_info hfi_mem;
a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+ return -EINVAL;
+ }
a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva;
@@ -891,6 +1006,11 @@
int timeout = 5000;
a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+ return -EINVAL;
+ }
+
reinit_completion(&hw_mgr->a5_complete);
CAM_DBG(CAM_ICP, "Sending HFI init command");
rc = a5_dev_intf->hw_ops.process_cmd(
@@ -931,6 +1051,11 @@
}
a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ return -EINVAL;
+ }
a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
rc = cam_icp_allocate_hfi_mem();
if (rc) {
@@ -955,11 +1080,12 @@
mutex_unlock(&hw_mgr->hw_mgr_mutex);
goto hfi_init_failed;
}
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = cam_icp_mgr_send_fw_init(hw_mgr);
- if (rc)
+ if (rc) {
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
goto fw_init_failed;
+ }
rc = a5_dev_intf->hw_ops.process_cmd(
a5_dev_intf->hw_priv,
@@ -967,6 +1093,7 @@
NULL, 0);
hw_mgr->fw_download = true;
hw_mgr->ctxt_cnt = 0;
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
CAM_DBG(CAM_ICP, "FW download done successfully");
if (!download_fw_args)
cam_icp_mgr_hw_close(hw_mgr, NULL);
@@ -990,7 +1117,6 @@
{
struct cam_hw_done_event_data buf_data;
- buf_data.num_handles = config_args->num_out_map_entries;
buf_data.request_id = *(uint64_t *)config_args->priv;
ctx_data->ctxt_event_cb(ctx_data->context_priv, true, &buf_data);
@@ -1047,22 +1173,22 @@
return -EINVAL;
}
- mutex_lock(&hw_mgr->hw_mgr_mutex);
ctx_data = config_args->ctxt_to_hw_map;
+ mutex_lock(&ctx_data->ctx_mutex);
if (!ctx_data->in_use) {
CAM_ERR(CAM_ICP, "ctx is not in use");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = -EINVAL;
goto config_err;
}
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
if (rc)
goto config_err;
+ mutex_unlock(&ctx_data->ctx_mutex);
return 0;
config_err:
+ mutex_unlock(&ctx_data->ctx_mutex);
cam_icp_mgr_handle_config_err(config_args, ctx_data);
return rc;
}
@@ -1177,16 +1303,13 @@
{
int32_t index;
- mutex_lock(&ctx_data->hfi_frame_process.lock);
index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap,
ctx_data->hfi_frame_process.bits);
if (index < 0 || index >= CAM_FRAME_CMD_MAX) {
CAM_ERR(CAM_ICP, "request idx is wrong: %d", index);
- mutex_unlock(&ctx_data->hfi_frame_process.lock);
return -EINVAL;
}
set_bit(index, ctx_data->hfi_frame_process.bitmap);
- mutex_unlock(&ctx_data->hfi_frame_process.lock);
ctx_data->hfi_frame_process.request_id[index] =
packet->header.request_id;
@@ -1215,29 +1338,34 @@
}
ctx_data = prepare_args->ctxt_to_hw_map;
- mutex_lock(&hw_mgr->hw_mgr_mutex);
+ mutex_lock(&ctx_data->ctx_mutex);
if (!ctx_data->in_use) {
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ mutex_unlock(&ctx_data->ctx_mutex);
CAM_ERR(CAM_ICP, "ctx is not in use");
return -EINVAL;
}
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
packet = prepare_args->packet;
rc = cam_icp_mgr_pkt_validation(packet);
- if (rc)
+ if (rc) {
+ mutex_unlock(&ctx_data->ctx_mutex);
return rc;
+ }
rc = cam_icp_mgr_process_cmd_desc(hw_mgr, packet,
&fw_cmd_buf_iova_addr);
- if (rc)
+ if (rc) {
+ mutex_unlock(&ctx_data->ctx_mutex);
return rc;
+ }
/* Update Buffer Address from handles and patch information */
rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl);
- if (rc)
+ if (rc) {
+ mutex_unlock(&ctx_data->ctx_mutex);
return rc;
+ }
cam_icp_mgr_process_io_cfg(hw_mgr, ctx_data,
packet, prepare_args);
@@ -1248,12 +1376,12 @@
if (prepare_args->in_map_entries[0].sync_id > 0)
cam_sync_destroy(
prepare_args->in_map_entries[0].sync_id);
+ mutex_unlock(&ctx_data->ctx_mutex);
return rc;
}
hfi_cmd = (struct hfi_cmd_ipebps_async *)
&ctx_data->hfi_frame_process.hfi_frame_cmd[idx];
-
cam_icp_mgr_prepare_frame_process_cmd(
ctx_data, hfi_cmd, packet->header.request_id,
fw_cmd_buf_iova_addr);
@@ -1262,6 +1390,7 @@
prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
+ mutex_unlock(&ctx_data->ctx_mutex);
return rc;
}
@@ -1270,7 +1399,7 @@
struct hfi_frame_process_info *hfi_frame_process;
int idx;
- mutex_lock(&ctx_data->hfi_frame_process.lock);
+ mutex_lock(&ctx_data->ctx_mutex);
hfi_frame_process = &ctx_data->hfi_frame_process;
for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) {
if (!hfi_frame_process->request_id[idx])
@@ -1283,7 +1412,7 @@
hfi_frame_process->request_id[idx] = 0;
clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
}
- mutex_unlock(&ctx_data->hfi_frame_process.lock);
+ mutex_unlock(&ctx_data->ctx_mutex);
return 0;
}
@@ -1303,10 +1432,16 @@
ctx_data = release_hw->ctxt_to_hw_map;
ctx_id = ctx_data->ctx_id;
- if (ctx_id < 0 || ctx_id >= CAM_ICP_CTX_MAX) {
+ if (ctx_id < 0 || ctx_id >= CAM_ICP_CTX_MAX)
CAM_ERR(CAM_ICP, "Invalid ctx id: %d", ctx_id);
+
+ mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+ if (!hw_mgr->ctx_data[ctx_id].in_use) {
+ CAM_DBG(CAM_ICP, "ctx is not in use: %d", ctx_id);
+ mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
return -EINVAL;
}
+ mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
if (release_hw->active_req) {
cam_icp_mgr_abort_handle(ctx_data);
@@ -1314,8 +1449,11 @@
}
rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
- if (!hw_mgr->ctxt_cnt)
+ if (!hw_mgr->ctxt_cnt) {
+ cam_icp_mgr_ipe_bps_power_collapse(hw_mgr,
+ NULL, 0);
cam_icp_mgr_hw_close(hw_mgr, NULL);
+ }
return rc;
}
@@ -1342,7 +1480,6 @@
ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
reinit_completion(&ctx_data->wait_complete);
-
ioconfig_cmd.num_fw_handles = 1;
ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
ioconfig_cmd.payload.indirect = io_buf_addr;
@@ -1386,7 +1523,6 @@
create_handle.pkt_type = HFI_CMD_IPEBPS_CREATE_HANDLE;
create_handle.handle_type = dev_type;
create_handle.user_data1 = (uint64_t)ctx_data;
-
reinit_completion(&ctx_data->wait_complete);
task_data = (struct hfi_cmd_work_data *)task->payload;
task_data->data = (void *)&create_handle;
@@ -1426,7 +1562,6 @@
ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt);
ping_pkt.pkt_type = HFI_CMD_SYS_PING;
ping_pkt.user_data = (uint64_t)ctx_data;
-
init_completion(&ctx_data->wait_complete);
task_data = (struct hfi_cmd_work_data *)task->payload;
task_data->data = (void *)&ping_pkt;
@@ -1469,6 +1604,12 @@
return -EINVAL;
}
+ if (icp_dev_acquire_info.dev_type >= CAM_ICP_RES_TYPE_MAX) {
+ CAM_ERR(CAM_ICP, "Invalid device type: %d",
+ icp_dev_acquire_info.dev_type);
+ return -EFAULT;
+ }
+
acquire_size = sizeof(struct cam_icp_acquire_dev_info) +
(icp_dev_acquire_info.num_out_res *
sizeof(struct cam_icp_res_info));
@@ -1493,7 +1634,7 @@
ctx_data->icp_dev_acquire_info->scratch_mem_size);
p_icp_out = ctx_data->icp_dev_acquire_info->out_res;
- for (i = 0; i < ctx_data->icp_dev_acquire_info->num_out_res; i++)
+ for (i = 0; i < icp_dev_acquire_info.num_out_res; i++)
CAM_DBG(CAM_ICP, "out[i] %x %x %x %x",
p_icp_out[i].format,
p_icp_out[i].width,
@@ -1539,12 +1680,9 @@
mutex_lock(&ctx_data->ctx_mutex);
rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data);
- if (rc) {
- mutex_unlock(&ctx_data->ctx_mutex);
+ if (rc)
goto acquire_info_failed;
- }
icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
- mutex_unlock(&ctx_data->ctx_mutex);
/* Get IOCONFIG command info */
if (icp_dev_acquire_info->secure_mode)
@@ -1573,6 +1711,9 @@
rc = cam_icp_mgr_download_fw(hw_mgr, ctx_data);
if (rc)
goto get_io_buf_failed;
+ rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data);
+ if (rc)
+ goto ipe_bps_resume_failed;
mutex_lock(&hw_mgr->hw_mgr_mutex);
}
mutex_unlock(&hw_mgr->hw_mgr_mutex);
@@ -1596,7 +1737,6 @@
goto ioconfig_failed;
}
- mutex_lock(&ctx_data->ctx_mutex);
ctx_data->context_priv = args->context_data;
args->ctxt_to_hw_map = ctx_data;
@@ -1606,15 +1746,14 @@
if (!ctx_data->hfi_frame_process.bitmap)
goto ioconfig_failed;
ctx_data->hfi_frame_process.bits = bitmap_size * BITS_PER_BYTE;
- mutex_init(&ctx_data->hfi_frame_process.lock);
hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb;
icp_dev_acquire_info->scratch_mem_size = ctx_data->scratch_mem_size;
- mutex_unlock(&ctx_data->ctx_mutex);
if (copy_to_user((void __user *)args->acquire_info,
icp_dev_acquire_info, sizeof(struct cam_icp_acquire_dev_info)))
goto copy_to_user_failed;
+ mutex_unlock(&ctx_data->ctx_mutex);
CAM_DBG(CAM_ICP, "scratch size = %x fw_handle = %x",
(unsigned int)icp_dev_acquire_info->scratch_mem_size,
(unsigned int)ctx_data->fw_handle);
@@ -1629,8 +1768,10 @@
ctx_data->hfi_frame_process.bitmap = NULL;
ioconfig_failed:
cam_icp_mgr_destroy_handle(ctx_data);
-send_ping_failed:
create_handle_failed:
+send_ping_failed:
+ cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, ctx_data, 0);
+ipe_bps_resume_failed:
if (!hw_mgr->ctxt_cnt)
cam_icp_mgr_hw_close(hw_mgr, NULL);
get_io_buf_failed:
@@ -1638,6 +1779,7 @@
hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL;
acquire_info_failed:
cam_icp_mgr_put_ctx(ctx_data);
+ mutex_unlock(&ctx_data->ctx_mutex);
return rc;
}
@@ -1653,17 +1795,18 @@
return -EINVAL;
}
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
if (copy_from_user(&icp_hw_mgr.icp_caps,
(void __user *)query_cap->caps_handle,
sizeof(struct cam_icp_query_cap_cmd))) {
CAM_ERR(CAM_ICP, "copy_from_user failed");
- return -EFAULT;
+ rc = -EFAULT;
+ goto end;
}
- mutex_lock(&hw_mgr->hw_mgr_mutex);
rc = hfi_get_hw_caps(&icp_hw_mgr.icp_caps);
if (rc)
- goto hfi_get_caps_fail;
+ goto end;
icp_hw_mgr.icp_caps.dev_iommu_handle.non_secure = hw_mgr->iommu_hdl;
icp_hw_mgr.icp_caps.dev_iommu_handle.secure = hw_mgr->iommu_sec_hdl;
@@ -1672,70 +1815,30 @@
&icp_hw_mgr.icp_caps, sizeof(struct cam_icp_query_cap_cmd))) {
CAM_ERR(CAM_ICP, "copy_to_user failed");
rc = -EFAULT;
- goto hfi_get_caps_fail;
}
-
-hfi_get_caps_fail:
+end:
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
-int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)
+static int cam_icp_mgr_alloc_devs(struct device_node *of_node)
{
- int count, i, rc = 0;
+ int rc;
uint32_t num_dev;
- const char *name = NULL;
- struct device_node *child_node = NULL;
- struct platform_device *child_pdev = NULL;
- struct cam_hw_intf *child_dev_intf = NULL;
- struct cam_hw_mgr_intf *hw_mgr_intf;
-
- hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl;
- if (!of_node || !hw_mgr_intf) {
- CAM_ERR(CAM_ICP, "Invalid args of_node %pK hw_mgr %pK",
- of_node, hw_mgr_intf);
- return -EINVAL;
- }
-
- hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr;
- hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps;
- hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw;
- hw_mgr_intf->hw_release = cam_icp_mgr_release_hw;
- hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update;
- hw_mgr_intf->hw_config = cam_icp_mgr_config_hw;
- hw_mgr_intf->download_fw = cam_icp_mgr_download_fw;
- hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
-
- mutex_init(&icp_hw_mgr.hw_mgr_mutex);
- spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
-
- for (i = 0; i < CAM_ICP_CTX_MAX; i++)
- mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex);
-
- /* Get number of device objects */
- count = of_property_count_strings(of_node, "compat-hw-name");
- if (!count) {
- CAM_ERR(CAM_ICP, "no compat hw found, count = %d", count);
- rc = -EINVAL;
- goto num_dev_failed;
- }
-
- /* Get number of a5 device nodes and a5 mem allocation */
rc = of_property_read_u32(of_node, "num-a5", &num_dev);
if (rc) {
CAM_ERR(CAM_ICP, "getting num of a5 failed");
- goto num_dev_failed;
+ goto num_a5_failed;
}
icp_hw_mgr.devices[CAM_ICP_DEV_A5] = kzalloc(
sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL);
if (!icp_hw_mgr.devices[CAM_ICP_DEV_A5]) {
rc = -ENOMEM;
- goto num_dev_failed;
+ goto num_a5_failed;
}
- /* Get number of ipe device nodes and ipe mem allocation */
rc = of_property_read_u32(of_node, "num-ipe", &num_dev);
if (rc) {
CAM_ERR(CAM_ICP, "getting number of ipe dev nodes failed");
@@ -1749,7 +1852,6 @@
goto num_ipe_failed;
}
- /* Get number of bps device nodes and bps mem allocation */
rc = of_property_read_u32(of_node, "num-bps", &num_dev);
if (rc) {
CAM_ERR(CAM_ICP, "read num bps devices failed");
@@ -1762,6 +1864,36 @@
goto num_bps_failed;
}
+ return 0;
+num_bps_failed:
+ kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
+num_ipe_failed:
+ kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
+num_a5_failed:
+ return rc;
+}
+
+static int cam_icp_mgr_init_devs(struct device_node *of_node)
+{
+ int rc = 0;
+ int count, i;
+ const char *name = NULL;
+ struct device_node *child_node = NULL;
+ struct platform_device *child_pdev = NULL;
+ struct cam_hw_intf *child_dev_intf = NULL;
+
+ rc = cam_icp_mgr_alloc_devs(of_node);
+ if (rc)
+ return rc;
+
+ count = of_property_count_strings(of_node, "compat-hw-name");
+ if (!count) {
+ CAM_ERR(CAM_ICP, "no compat hw found in dev tree, cnt = %d",
+ count);
+ rc = -EINVAL;
+ goto compat_hw_name_failed;
+ }
+
for (i = 0; i < count; i++) {
rc = of_property_read_string_index(of_node, "compat-hw-name",
i, &name);
@@ -1797,20 +1929,24 @@
icp_hw_mgr.devices[child_dev_intf->hw_type]
[child_dev_intf->hw_idx] = child_dev_intf;
+ if (!child_dev_intf->hw_ops.process_cmd)
+ goto compat_hw_name_failed;
+
of_node_put(child_node);
}
- rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl);
- if (rc) {
- CAM_ERR(CAM_ICP, "icp get iommu handle failed: %d", rc);
- goto compat_hw_name_failed;
- }
+ return 0;
+compat_hw_name_failed:
+ kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]);
+ kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
+ kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
+ return rc;
+}
- rc = cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH);
- if (rc) {
- CAM_ERR(CAM_ICP, "icp attach failed: %d", rc);
- goto icp_attach_failed;
- }
+static int cam_icp_mgr_create_wq(void)
+{
+ int rc;
+ int i;
rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
&icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ);
@@ -1850,10 +1986,7 @@
icp_hw_mgr.cmd_work->task.pool[i].payload =
&icp_hw_mgr.cmd_work_data[i];
- init_completion(&icp_hw_mgr.a5_complete);
-
- return rc;
-
+ return 0;
msg_work_data_failed:
kfree(icp_hw_mgr.cmd_work_data);
cmd_work_data_failed:
@@ -1861,17 +1994,70 @@
msg_work_failed:
cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work);
cmd_work_failed:
+ return rc;
+}
+
+int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)
+{
+ int i, rc = 0;
+ struct cam_hw_mgr_intf *hw_mgr_intf;
+
+ hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl;
+ if (!of_node || !hw_mgr_intf) {
+ CAM_ERR(CAM_ICP, "Invalid args of_node %pK hw_mgr %pK",
+ of_node, hw_mgr_intf);
+ return -EINVAL;
+ }
+
+ hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr;
+ hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps;
+ hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw;
+ hw_mgr_intf->hw_release = cam_icp_mgr_release_hw;
+ hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update;
+ hw_mgr_intf->hw_config = cam_icp_mgr_config_hw;
+ hw_mgr_intf->download_fw = cam_icp_mgr_download_fw;
+ hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
+
+ mutex_init(&icp_hw_mgr.hw_mgr_mutex);
+ spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
+
+ for (i = 0; i < CAM_ICP_CTX_MAX; i++)
+ mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex);
+
+ rc = cam_icp_mgr_init_devs(of_node);
+ if (rc)
+ goto dev_init_failed;
+
+ rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "icp get iommu handle failed: %d", rc);
+ goto icp_get_hdl_failed;
+ }
+
+ rc = cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "icp attach failed: %d", rc);
+ goto icp_attach_failed;
+ }
+
+ rc = cam_icp_mgr_create_wq();
+ if (rc)
+ goto icp_wq_create_failed;
+
+ init_completion(&icp_hw_mgr.a5_complete);
+
+ return rc;
+
+icp_wq_create_failed:
cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_DETACH);
icp_attach_failed:
cam_smmu_destroy_handle(icp_hw_mgr.iommu_hdl);
- icp_hw_mgr.iommu_hdl = 0;
-compat_hw_name_failed:
+ icp_hw_mgr.iommu_hdl = -1;
+icp_get_hdl_failed:
kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]);
-num_bps_failed:
kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
-num_ipe_failed:
kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
-num_dev_failed:
+dev_init_failed:
mutex_destroy(&icp_hw_mgr.hw_mgr_mutex);
for (i = 0; i < CAM_ICP_CTX_MAX; i++)
mutex_destroy(&icp_hw_mgr.ctx_data[i].ctx_mutex);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 6fa32fa..27a86b2 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -42,6 +42,9 @@
#define ICP_PACKET_OPCODE 2
#define ICP_MAX_OUTPUT_SUPPORTED 6
+#define ICP_FRAME_PROCESS_SUCCESS 0
+#define ICP_FRAME_PROCESS_FAILURE 1
+
/**
* struct icp_hfi_mem_info
* @qtbl: Memory info of queue table
@@ -158,6 +161,11 @@
* @cmd_work_data: Pointer to command work queue task
* @msg_work_data: Pointer to message work queue task
* @ctxt_cnt: Active context count
+ * @ipe_ctxt_cnt: IPE Active context count
+ * @bps_ctxt_cnt: BPS Active context count
+ * @dentry: Debugfs entry
+ * @a5_debug: A5 debug flag
+ * @icp_pc_flag: Flag to enable/disable power collapse
*/
struct cam_icp_hw_mgr {
struct mutex hw_mgr_mutex;
@@ -179,8 +187,11 @@
struct hfi_cmd_work_data *cmd_work_data;
struct hfi_msg_work_data *msg_work_data;
uint32_t ctxt_cnt;
+ uint32_t ipe_ctxt_cnt;
+ uint32_t bps_ctxt_cnt;
struct dentry *dentry;
bool a5_debug;
+ bool icp_pc_flag;
};
static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
index b7b3d7b..79c3388 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
@@ -131,6 +131,78 @@
return rc;
}
+static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev)
+{
+ struct cam_hw_soc_info *soc_info = NULL;
+ struct cam_ipe_device_core_info *core_info = NULL;
+ struct cam_ipe_device_hw_info *hw_info = NULL;
+ int pwr_ctrl;
+ int pwr_status;
+
+ soc_info = &ipe_dev->soc_info;
+ core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+ hw_info = core_info->ipe_hw_info;
+
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+ true, &pwr_ctrl);
+ if (!(pwr_ctrl & IPE_COLLAPSE_MASK)) {
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+ true, &pwr_status);
+ cam_cpas_reg_write(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP,
+ hw_info->pwr_ctrl, true, 0x1);
+
+ if (pwr_status >> IPE_PWR_ON_MASK)
+ return -EINVAL;
+
+ }
+ cam_ipe_get_gdsc_control(soc_info);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+ true, &pwr_ctrl);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+ true, &pwr_status);
+ CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+ pwr_ctrl, pwr_status);
+
+ return 0;
+}
+
+static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev)
+{
+ struct cam_hw_soc_info *soc_info = NULL;
+ struct cam_ipe_device_core_info *core_info = NULL;
+ struct cam_ipe_device_hw_info *hw_info = NULL;
+ int pwr_ctrl;
+ int pwr_status;
+ int rc = 0;
+
+ soc_info = &ipe_dev->soc_info;
+ core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+ hw_info = core_info->ipe_hw_info;
+
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+ true, &pwr_ctrl);
+ if (pwr_ctrl & IPE_COLLAPSE_MASK) {
+ CAM_ERR(CAM_ICP, "IPE: resume failed : %d", pwr_ctrl);
+ return -EINVAL;
+ }
+ rc = cam_ipe_transfer_gdsc_control(soc_info);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl);
+ cam_cpas_reg_read(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+ true, &pwr_status);
+ CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+ pwr_ctrl, pwr_status);
+
+ return rc;
+}
+
int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type,
void *cmd_args, uint32_t arg_size)
{
@@ -185,6 +257,12 @@
core_info->cpas_start = false;
}
break;
+ case CAM_ICP_IPE_CMD_POWER_COLLAPSE:
+ rc = cam_ipe_handle_pc(ipe_dev);
+ break;
+ case CAM_ICP_IPE_CMD_POWER_RESUME:
+ rc = cam_ipe_handle_resume(ipe_dev);
+ break;
default:
break;
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h
index 8f0e882..bd83972 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h
@@ -19,7 +19,13 @@
#include <linux/platform_device.h>
#include <linux/dma-buf.h>
+#define IPE_COLLAPSE_MASK 0x1
+#define IPE_PWR_ON_MASK 0x2
+
struct cam_ipe_device_hw_info {
+ uint32_t hw_idx;
+ uint32_t pwr_ctrl;
+ uint32_t pwr_status;
uint32_t reserved;
};
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c
index d95246f..d13363e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c
@@ -25,8 +25,19 @@
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
-struct cam_ipe_device_hw_info cam_ipe_hw_info = {
- .reserved = 0,
+static struct cam_ipe_device_hw_info cam_ipe_hw_info[] = {
+ {
+ .hw_idx = 0,
+ .pwr_ctrl = 0x4c,
+ .pwr_status = 0x48,
+ .reserved = 0,
+ },
+ {
+ .hw_idx = 1,
+ .pwr_ctrl = 0x54,
+ .pwr_status = 0x50,
+ .reserved = 0,
+ },
};
EXPORT_SYMBOL(cam_ipe_hw_info);
@@ -106,7 +117,7 @@
rc = -EINVAL;
return rc;
}
- hw_info = (struct cam_ipe_device_hw_info *)match_dev->data;
+ hw_info = &cam_ipe_hw_info[ipe_dev_intf->hw_idx];
core_info->ipe_hw_info = hw_info;
rc = cam_ipe_init_soc_resources(&ipe_dev->soc_info, cam_ipe_irq,
@@ -142,7 +153,7 @@
static const struct of_device_id cam_ipe_dt_match[] = {
{
- .compatible = "qcom,cam_ipe",
+ .compatible = "qcom,cam-ipe",
.data = &cam_ipe_hw_info,
},
{}
@@ -152,7 +163,7 @@
static struct platform_driver cam_ipe_driver = {
.probe = cam_ipe_probe,
.driver = {
- .name = "cam_ipe",
+ .name = "cam-ipe",
.owner = THIS_MODULE,
.of_match_table = cam_ipe_dt_match,
},
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
index 26dd6d2..e7b2733f 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
@@ -20,6 +20,57 @@
#include "cam_soc_util.h"
#include "cam_debug_util.h"
+
+int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+ int i;
+ int rc;
+
+ for (i = 0; i < soc_info->num_rgltr; i++) {
+ rc = regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_FAST);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+ soc_info->rgltr_name[i]);
+ goto rgltr_set_mode_failed;
+ }
+ }
+ return 0;
+
+rgltr_set_mode_failed:
+ for (i = i - 1; i >= 0; i--)
+ if (soc_info->rgltr[i])
+ regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_NORMAL);
+
+ return rc;
+}
+
+int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+ int i;
+ int rc;
+
+ for (i = 0; i < soc_info->num_rgltr; i++) {
+ rc = regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_NORMAL);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+ soc_info->rgltr_name[i]);
+ goto rgltr_set_mode_failed;
+ }
+ }
+ return 0;
+
+rgltr_set_mode_failed:
+ for (i = i - 1; i >= 0; i--)
+ if (soc_info->rgltr[i])
+ regulator_set_mode(soc_info->rgltr[i],
+ REGULATOR_MODE_FAST);
+
+ return rc;
+}
+
static int cam_ipe_get_dt_properties(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
index 12ab444..ed8bb6e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
@@ -22,4 +22,7 @@
int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info);
+
+int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info);
#endif /* CAM_IPE_SOC_H */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 4a5b1c3..4893960 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1961,6 +1961,16 @@
fill_fence = false;
}
+ /*
+ * reg update will be done later for the initial configure.
+ * need to plus one to the op_code and only take the lower
+ * bits to get the type of operation since UMD definition
+ * of op_code has some difference from KMD.
+ */
+ if (((prepare->packet->header.op_code + 1) & 0xF) ==
+ CAM_ISP_PACKET_INIT_DEV)
+ return rc;
+
/* add reg update commands */
for (i = 0; i < ctx->num_base; i++) {
/* Add change base */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 3fd42f7..efdda4f 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -833,6 +833,7 @@
for (i = 0; i < link->num_devs; i++) {
dev = &link->l_dev[i];
if (dev != NULL) {
+ link_data.dev_hdl = dev->dev_hdl;
if (dev->ops && dev->ops->link_setup)
dev->ops->link_setup(&link_data);
dev->dev_hdl = 0;
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 644cb63..3fe7b00 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -790,21 +790,43 @@
for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
struct sync_table_row *row =
sync_dev->sync_table + i;
- if (row->state == CAM_SYNC_STATE_INVALID)
- continue;
- /* Signal all remaining objects as ERR,but we don't care
- * about the return status here apart from logging it
+ /*
+ * Signal all ACTIVE objects as ERR, but we don't
+ * care about the return status here apart from logging
+ * it.
*/
- rc = cam_sync_signal(i, CAM_SYNC_STATE_SIGNALED_ERROR);
- if (rc < 0)
- CAM_ERR(CAM_SYNC,
- "Cleanup signal failed: idx = %d", i);
+ if (row->state == CAM_SYNC_STATE_ACTIVE) {
+ rc = cam_sync_signal(i,
+ CAM_SYNC_STATE_SIGNALED_ERROR);
+ if (rc < 0)
+ CAM_ERR(CAM_SYNC,
+ "Cleanup signal fail idx:%d\n",
+ i);
+ }
+ }
- rc = cam_sync_destroy(i);
- if (rc < 0)
- CAM_ERR(CAM_SYNC,
- "Cleanup destroy failed: idx = %d", i);
+ /*
+ * Flush the work queue to wait for pending signal callbacks to
+ * finish
+ */
+ flush_workqueue(sync_dev->work_queue);
+
+ /*
+ * Now that all callbacks worker threads have finished,
+ * destroy the sync objects
+ */
+ for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
+ struct sync_table_row *row =
+ sync_dev->sync_table + i;
+
+ if (row->state != CAM_SYNC_STATE_INVALID) {
+ rc = cam_sync_destroy(i);
+ if (rc < 0)
+ CAM_ERR(CAM_SYNC,
+ "Cleanup destroy fail:idx:%d\n",
+ i);
+ }
}
}
mutex_unlock(&sync_dev->table_lock);
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 d36d601..b0fe8db 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -11,7 +11,7 @@
*
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/platform_device.h>
#include <linux/module.h>
@@ -1663,18 +1663,20 @@
static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr,
struct sde_mdp_format_params *in_fmt,
- struct sde_mdp_format_params *out_fmt, bool rotation)
+ struct sde_mdp_format_params *out_fmt, bool rotation, u32 mode)
{
u8 in_v_subsample, in_h_subsample;
u8 out_v_subsample, out_h_subsample;
- if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true)) {
- SDEROT_ERR("Invalid input format %x\n", in_fmt->format);
+ if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true, mode)) {
+ SDEROT_ERR("Invalid input format 0x%x (%4.4s)\n",
+ in_fmt->format, (char *)&in_fmt->format);
goto verify_error;
}
- if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false)) {
- SDEROT_ERR("Invalid output format %x\n", out_fmt->format);
+ if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false, mode)) {
+ SDEROT_ERR("Invalid output format 0x%x (%4.4s)\n",
+ out_fmt->format, (char *)&out_fmt->format);
goto verify_error;
}
@@ -1723,8 +1725,10 @@
return true;
verify_error:
- SDEROT_ERR("in_fmt=0x%x, out_fmt=0x%x\n",
- in_fmt->format, out_fmt->format);
+ SDEROT_ERR("in_fmt=0x%x (%4.4s), out_fmt=0x%x (%4.4s), mode=%d\n",
+ in_fmt->format, (char *)&in_fmt->format,
+ out_fmt->format, (char *)&out_fmt->format,
+ mode);
return false;
}
@@ -1843,6 +1847,7 @@
{
struct sde_mdp_format_params *in_fmt, *out_fmt;
bool rotation;
+ u32 mode;
if (!mgr || !config) {
SDEROT_ERR("null parameters\n");
@@ -1851,6 +1856,9 @@
rotation = (config->flags & SDE_ROTATION_90) ? true : false;
+ mode = config->output.sbuf ? SDE_ROTATOR_MODE_SBUF :
+ SDE_ROTATOR_MODE_OFFLINE;
+
in_fmt = __verify_input_config(mgr, config);
if (!in_fmt)
return -EINVAL;
@@ -1859,7 +1867,7 @@
if (!out_fmt)
return -EINVAL;
- if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation)) {
+ if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation, mode)) {
SDEROT_ERR(
"Rot format pairing invalid, in_fmt:0x%x, out_fmt:0x%x\n",
config->input.format,
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 731ff1e..3d368a1 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -141,6 +141,12 @@
SDE_ROTATOR_TRIGGER_COMMAND,
};
+enum sde_rotator_mode {
+ SDE_ROTATOR_MODE_OFFLINE,
+ SDE_ROTATOR_MODE_SBUF,
+ SDE_ROTATOR_MODE_MAX,
+};
+
struct sde_rotation_item {
/* rotation request flag */
uint32_t flags;
@@ -463,9 +469,9 @@
int (*ops_hw_validate_entry)(struct sde_rot_mgr *mgr,
struct sde_rot_entry *entry);
u32 (*ops_hw_get_pixfmt)(struct sde_rot_mgr *mgr, int index,
- bool input);
+ bool input, u32 mode);
int (*ops_hw_is_valid_pixfmt)(struct sde_rot_mgr *mgr, u32 pixfmt,
- bool input);
+ bool input, u32 mode);
int (*ops_hw_get_downscale_caps)(struct sde_rot_mgr *mgr, char *caps,
int len);
int (*ops_hw_get_maxlinewidth)(struct sde_rot_mgr *mgr);
@@ -474,19 +480,19 @@
};
static inline int sde_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr,
- u32 pixfmt, bool input)
+ u32 pixfmt, bool input, u32 mode)
{
if (mgr && mgr->ops_hw_is_valid_pixfmt)
- return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input);
+ return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input, mode);
return false;
}
static inline u32 sde_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
- int index, bool input)
+ int index, bool input, u32 mode)
{
if (mgr && mgr->ops_hw_get_pixfmt)
- return mgr->ops_hw_get_pixfmt(mgr, index, input);
+ return mgr->ops_hw_get_pixfmt(mgr, index, input, mode);
return 0;
}
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 bf7a917..acd4b7d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/vmalloc.h>
#include <linux/kernel.h>
@@ -1433,7 +1433,8 @@
sde_rot_mgr_lock(rot_dev->mgr);
for (i = 0;; i++) {
- pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input);
+ pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input,
+ SDE_ROTATOR_MODE_SBUF);
if (!pixfmt)
break;
if (pixfmts && i < len)
@@ -1610,7 +1611,7 @@
ret = sde_rotator_session_config(rot_dev->mgr,
ctx->private, &rotcfg);
if (ret) {
- SDEROT_ERR("fail session config s:%d\n",
+ SDEROT_WARN("fail session config s:%d\n",
ctx->session_id);
goto error_session_config;
}
@@ -1621,7 +1622,7 @@
ret = sde_rotator_validate_request(rot_dev->mgr, ctx->private,
req);
if (ret) {
- SDEROT_ERR("fail validate request s:%d\n",
+ SDEROT_WARN("fail validate request s:%d\n",
ctx->session_id);
goto error_validate_request;
}
@@ -1857,7 +1858,8 @@
bool found = false;
for (i = 0, index = 0; index <= f->index; i++) {
- pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false);
+ pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false,
+ SDE_ROTATOR_MODE_OFFLINE);
if (!pixfmt)
return -EINVAL;
@@ -1901,7 +1903,8 @@
bool found = false;
for (i = 0, index = 0; index <= f->index; i++) {
- pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true);
+ pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true,
+ SDE_ROTATOR_MODE_OFFLINE);
if (!pixfmt)
return -EINVAL;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
index 27e9ba6..7585a6b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
@@ -850,6 +850,11 @@
case SDE_PIX_FMT_Y_CRCB_H2V2_TILE:
*dst_pixfmt = SDE_PIX_FMT_Y_CRCB_H2V2_TILE;
break;
+ case V4L2_PIX_FMT_RGB565:
+ case SDE_PIX_FMT_RGB_565_UBWC:
+ case SDE_PIX_FMT_RGB_565_TILE:
+ *dst_pixfmt = SDE_PIX_FMT_RGB_565_TILE;
+ break;
case SDE_PIX_FMT_RGBA_8888:
case SDE_PIX_FMT_RGBA_8888_UBWC:
case SDE_PIX_FMT_RGBA_8888_TILE:
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
index 5bb6198..545dcfc 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
@@ -37,6 +37,7 @@
#define SDE_PIX_FMT_RGBA_1010102_TILE v4l2_fourcc('Q', 'T', '1', '0')
#define SDE_PIX_FMT_RGBX_1010102_TILE v4l2_fourcc('Q', 'T', '1', '1')
#define SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE v4l2_fourcc('Q', 'T', '1', '2')
+#define SDE_PIX_FMT_RGB_565_TILE v4l2_fourcc('Q', 'T', '1', '3')
#define SDE_ROT_MAX_PLANES 4
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 9f4a854..1b4913b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
@@ -501,9 +501,10 @@
* @mgr: Pointer to rotator manager
* @index: index of pixel format
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
- int index, bool input)
+ int index, bool input, u32 mode)
{
if (input) {
if (index < ARRAY_SIZE(sde_hw_rotator_input_pixfmts))
@@ -523,9 +524,10 @@
* @mgr: Pointer to rotator manager
* @pixfmt: pixel format to be verified
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
- bool input)
+ bool input, u32 mode)
{
int i;
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 205eeef..3c47dd7 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -11,7 +11,7 @@
*
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/platform_device.h>
#include <linux/module.h>
@@ -107,7 +107,7 @@
#define SDE_ROTREG_READ(base, off) \
readl_relaxed(base + (off))
-static u32 sde_hw_rotator_v3_inpixfmts[] = {
+static const u32 sde_hw_rotator_v3_inpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -167,7 +167,7 @@
SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
};
-static u32 sde_hw_rotator_v3_outpixfmts[] = {
+static const u32 sde_hw_rotator_v3_outpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -227,7 +227,7 @@
SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
};
-static u32 sde_hw_rotator_v4_inpixfmts[] = {
+static const u32 sde_hw_rotator_v4_inpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -307,7 +307,7 @@
SDE_PIX_FMT_XBGR_2101010_TILE,
};
-static u32 sde_hw_rotator_v4_outpixfmts[] = {
+static const u32 sde_hw_rotator_v4_outpixfmts[] = {
SDE_PIX_FMT_XRGB_8888,
SDE_PIX_FMT_ARGB_8888,
SDE_PIX_FMT_ABGR_8888,
@@ -387,6 +387,23 @@
SDE_PIX_FMT_XBGR_2101010_TILE,
};
+static const u32 sde_hw_rotator_v4_inpixfmts_sbuf[] = {
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010,
+ SDE_PIX_FMT_Y_CBCR_H2V2,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC,
+ SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
+};
+
+static const u32 sde_hw_rotator_v4_outpixfmts_sbuf[] = {
+ SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
+ SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE,
+ SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
+};
+
static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = {
{0x214, 0x21c, 16, 1, 0x200}, /* arb clients main */
{0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */
@@ -2637,17 +2654,33 @@
set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map);
set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map);
set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map);
- rot->inpixfmts = sde_hw_rotator_v4_inpixfmts;
- rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
- rot->outpixfmts = sde_hw_rotator_v4_outpixfmts;
- rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
+ rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v4_inpixfmts;
+ rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
+ rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v4_outpixfmts;
+ rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
+ rot->inpixfmts[SDE_ROTATOR_MODE_SBUF] =
+ sde_hw_rotator_v4_inpixfmts_sbuf;
+ rot->num_inpixfmt[SDE_ROTATOR_MODE_SBUF] =
+ ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts_sbuf);
+ rot->outpixfmts[SDE_ROTATOR_MODE_SBUF] =
+ sde_hw_rotator_v4_outpixfmts_sbuf;
+ rot->num_outpixfmt[SDE_ROTATOR_MODE_SBUF] =
+ ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts_sbuf);
rot->downscale_caps =
"LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
} else {
- rot->inpixfmts = sde_hw_rotator_v3_inpixfmts;
- rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
- rot->outpixfmts = sde_hw_rotator_v3_outpixfmts;
- rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
+ rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v3_inpixfmts;
+ rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
+ rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+ sde_hw_rotator_v3_outpixfmts;
+ rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+ ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
rot->downscale_caps = (hw_version == SDE_ROT_TYPE_V1_0) ?
"LINEAR/2/4/8/16/32/64 TILE/2/4 TP10/2" :
"LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
@@ -3055,9 +3088,10 @@
* @mgr: Pointer to rotator manager
* @index: index of pixel format
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
- int index, bool input)
+ int index, bool input, u32 mode)
{
struct sde_hw_rotator *rot;
@@ -3068,14 +3102,19 @@
rot = mgr->hw_data;
+ if (mode >= SDE_ROTATOR_MODE_MAX) {
+ SDEROT_ERR("invalid rotator mode %d\n", mode);
+ return 0;
+ }
+
if (input) {
- if ((index < rot->num_inpixfmt) && rot->inpixfmts)
- return rot->inpixfmts[index];
+ if ((index < rot->num_inpixfmt[mode]) && rot->inpixfmts[mode])
+ return rot->inpixfmts[mode][index];
else
return 0;
} else {
- if ((index < rot->num_outpixfmt) && rot->outpixfmts)
- return rot->outpixfmts[index];
+ if ((index < rot->num_outpixfmt[mode]) && rot->outpixfmts[mode])
+ return rot->outpixfmts[mode][index];
else
return 0;
}
@@ -3086,12 +3125,13 @@
* @mgr: Pointer to rotator manager
* @pixfmt: pixel format to be verified
* @input: true for input port; false for output port
+ * @mode: operating mode
*/
static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
- bool input)
+ bool input, u32 mode)
{
struct sde_hw_rotator *rot;
- u32 *pixfmts;
+ const u32 *pixfmts;
u32 num_pixfmt;
int i;
@@ -3102,12 +3142,17 @@
rot = mgr->hw_data;
+ if (mode >= SDE_ROTATOR_MODE_MAX) {
+ SDEROT_ERR("invalid rotator mode %d\n", mode);
+ return false;
+ }
+
if (input) {
- pixfmts = rot->inpixfmts;
- num_pixfmt = rot->num_inpixfmt;
+ pixfmts = rot->inpixfmts[mode];
+ num_pixfmt = rot->num_inpixfmt[mode];
} else {
- pixfmts = rot->outpixfmts;
- num_pixfmt = rot->num_outpixfmt;
+ pixfmts = rot->outpixfmts[mode];
+ num_pixfmt = rot->num_outpixfmt[mode];
}
if (!pixfmts || !num_pixfmt) {
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
index 67f7f4b..4c1316c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
@@ -259,10 +259,10 @@
* @sbuf_ctx: list of active sbuf context in FIFO order
* @vid_trigger: video mode trigger select
* @cmd_trigger: command mode trigger select
- * @inpixfmts: array of supported input pixel formats forucc
- * @num_inpixfmt: size of the supported input pixel format array
- * @outpixfmts: array of supported output pixel formats in fourcc
- * @num_outpixfmt: size of the supported output pixel formats array
+ * @inpixfmts: array of supported input pixel formats fourcc per mode
+ * @num_inpixfmt: size of the supported input pixel format array per mode
+ * @outpixfmts: array of supported output pixel formats in fourcc per mode
+ * @num_outpixfmt: size of the supported output pixel formats array per mode
* @downscale_caps: capability string of scaling
* @maxlinewidth: maximum line width supported
*/
@@ -320,10 +320,10 @@
struct list_head sbuf_ctx[ROT_QUEUE_MAX];
- u32 *inpixfmts;
- u32 num_inpixfmt;
- u32 *outpixfmts;
- u32 num_outpixfmt;
+ const u32 *inpixfmts[SDE_ROTATOR_MODE_MAX];
+ u32 num_inpixfmt[SDE_ROTATOR_MODE_MAX];
+ const u32 *outpixfmts[SDE_ROTATOR_MODE_MAX];
+ u32 num_outpixfmt[SDE_ROTATOR_MODE_MAX];
const char *downscale_caps;
u32 maxlinewidth;
};
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index a93f054..45e8771 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -901,6 +901,7 @@
exit:
*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX);
+ trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index e49ea72..4512409 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -164,6 +164,9 @@
case HFI_VIDEO_CODEC_VP9:
hal_codec = HAL_VIDEO_CODEC_VP9;
break;
+ case HFI_VIDEO_CODEC_TME:
+ hal_codec = HAL_VIDEO_CODEC_TME;
+ break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hfi_codec);
@@ -220,6 +223,9 @@
case HAL_VIDEO_CODEC_VP9:
hfi_codec = HFI_VIDEO_CODEC_VP9;
break;
+ case HAL_VIDEO_CODEC_TME:
+ hfi_codec = HFI_VIDEO_CODEC_TME;
+ break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hal_codec);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index efe4ca3..52b9b32 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -997,6 +997,15 @@
num_properties--;
break;
}
+ case HFI_PROPERTY_TME_VERSION_SUPPORTED:
+ {
+ capabilities->tme_version =
+ *((u32 *)(data_ptr + next_offset));
+ next_offset +=
+ sizeof(u32);
+ num_properties--;
+ break;
+ }
default:
dprintk(VIDC_DBG,
"%s: default case - data_ptr %pK, prop_id 0x%x\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 988f79c..f17f3da 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -373,6 +373,15 @@
.default_value = 0,
.step = OPERATING_FRAME_RATE_STEP,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
+ .name = "Low Latency Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+ .step = 1,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -1062,6 +1071,14 @@
ctrl->val >> 16);
inst->clk_data.operating_rate = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
+ if (ctrl->val ==
+ V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE)
+ hal_property.enable = 1;
+ else
+ hal_property.enable = 0;
+ inst->clk_data.low_latency_mode = (bool) hal_property.enable;
+ break;
default:
break;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 69070d5..03b4e4d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -117,6 +117,17 @@
"Level unknown",
};
+static const char *const tme_profile[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+};
+
+static const char *const tme_level[] = {
+ "Integer",
+};
+
static const char *const hevc_profile[] = {
"Main",
"Main10",
@@ -486,6 +497,46 @@
.qmenu = hevc_tier_level,
},
{
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE,
+ .name = "TME Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3)
+ ),
+ .qmenu = tme_profile,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL,
+ .name = "TME Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER)
+ ),
+ .qmenu = tme_level,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION,
+ .name = "TME Payload Version",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 0xFFFFFFF,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ .qmenu = NULL,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
.name = "Rotation",
.type = V4L2_CTRL_TYPE_MENU,
@@ -1064,6 +1115,13 @@
.get_frame_size = get_frame_size_tp10_ubwc,
.type = OUTPUT_PORT,
},
+ {
+ .name = "TME",
+ .description = "TME MBI format",
+ .fourcc = V4L2_PIX_FMT_TME,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
};
static int msm_venc_set_csc(struct msm_vidc_inst *inst);
@@ -1345,6 +1403,29 @@
temp_ctrl->val);
pdata = &profile_level;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE:
+ temp_ctrl =
+ TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL);
+
+ property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE);
+
+ property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.level = msm_comm_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
{
property_id = HAL_PARAM_VPE_ROTATION;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 971e57a..d08d40f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1453,6 +1453,9 @@
}
ctrl->val = bufreq->buffer_count_min_host;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION:
+ ctrl->val = inst->capability.tme_version;
+ break;
default:
/*
* Other controls aren't really volatile, shouldn't need to
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 51023f0..d557959 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -510,7 +510,7 @@
u32 vpp_cycles_per_mb;
u32 mbs_per_second;
- mbs_per_second = msm_comm_get_inst_load(inst,
+ mbs_per_second = msm_comm_get_inst_load_per_core(inst,
LOAD_CALC_NO_QUIRKS);
/*
@@ -524,6 +524,8 @@
inst->clk_data.entry->low_power_cycles :
inst->clk_data.entry->vpp_cycles;
+ vpp_cycles = mbs_per_second * vpp_cycles_per_mb;
+
vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
/* 10 / 7 is overhead factor */
@@ -533,7 +535,7 @@
vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
/* 10 / 7 is overhead factor */
- vsp_cycles += ((inst->prop.fps * filled_len * 8) / 7) * 10;
+ vsp_cycles += ((inst->prop.fps * filled_len * 8) * 10) / 7;
} else {
dprintk(VIDC_ERR, "Unknown session type = %s\n", __func__);
@@ -619,7 +621,7 @@
temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
continue;
- mbs_per_second = msm_comm_get_inst_load(temp,
+ mbs_per_second = msm_comm_get_inst_load_per_core(temp,
LOAD_CALC_NO_QUIRKS);
cycles = temp->clk_data.entry->vpp_cycles;
@@ -820,7 +822,7 @@
core = inst->core;
dcvs = &inst->clk_data;
- load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+ load = msm_comm_get_inst_load_per_core(inst, LOAD_CALC_NO_QUIRKS);
cycles = inst->clk_data.entry->vpp_cycles;
allowed_clks_tbl = core->resources.allowed_clks_tbl;
if (inst->session_type == MSM_VIDC_ENCODER) {
@@ -1044,10 +1046,7 @@
} else {
continue;
}
- if (inst->clk_data.core_id == 3)
- cycles = cycles / 2;
-
- current_inst_mbs_per_sec = msm_comm_get_inst_load(inst,
+ current_inst_mbs_per_sec = msm_comm_get_inst_load_per_core(inst,
LOAD_CALC_NO_QUIRKS);
load += current_inst_mbs_per_sec * cycles;
}
@@ -1122,9 +1121,11 @@
if (inst->session_type == MSM_VIDC_ENCODER && hier_mode) {
if (current_inst_load / 2 + core0_load <= max_freq &&
current_inst_load / 2 + core1_load <= max_freq) {
- inst->clk_data.core_id = VIDC_CORE_ID_3;
- msm_vidc_power_save_mode_enable(inst, false);
- goto decision_done;
+ if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) {
+ inst->clk_data.core_id = VIDC_CORE_ID_3;
+ msm_vidc_power_save_mode_enable(inst, false);
+ goto decision_done;
+ }
}
}
@@ -1133,9 +1134,11 @@
core0_lp_load <= max_freq &&
current_inst_lp_load / 2 +
core1_lp_load <= max_freq) {
- inst->clk_data.core_id = VIDC_CORE_ID_3;
- msm_vidc_power_save_mode_enable(inst, true);
- goto decision_done;
+ if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) {
+ inst->clk_data.core_id = VIDC_CORE_ID_3;
+ msm_vidc_power_save_mode_enable(inst, true);
+ goto decision_done;
+ }
}
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 69a9fc1..ac53d83 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -489,6 +489,26 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0:
+ return HAL_TME_PROFILE_0;
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1:
+ return HAL_TME_PROFILE_1;
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2:
+ return HAL_TME_PROFILE_2;
+ case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3:
+ return HAL_TME_PROFILE_3;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER:
+ return HAL_TME_LEVEL_INTEGER;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
switch (value) {
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE:
@@ -533,6 +553,51 @@
return -EINVAL;
}
+int msm_comm_get_v4l2_profile(int fourcc, int profile)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ profile);
+ case V4L2_PIX_FMT_HEVC:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+ profile);
+ case V4L2_PIX_FMT_VP8:
+ case V4L2_PIX_FMT_VP9:
+ case V4L2_PIX_FMT_MPEG2:
+ return 0;
+ default:
+ dprintk(VIDC_WARN, "Unknown codec id %x\n", fourcc);
+ return 0;
+ }
+}
+
+int msm_comm_get_v4l2_level(int fourcc, int level)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ level);
+ case V4L2_PIX_FMT_HEVC:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+ level);
+ case V4L2_PIX_FMT_VP8:
+ return msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ level);
+ case V4L2_PIX_FMT_VP9:
+ case V4L2_PIX_FMT_MPEG2:
+ return 0;
+ default:
+ dprintk(VIDC_WARN, "Unknown codec id %x\n", fourcc);
+ return 0;
+ }
+}
+
int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
const struct v4l2_ctrl_ops *ctrl_ops)
@@ -737,6 +802,17 @@
return load;
}
+int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst,
+ enum load_calc_quirks quirks)
+{
+ int load = msm_comm_get_inst_load(inst, quirks);
+
+ if (inst->clk_data.core_id == VIDC_CORE_ID_3)
+ load = load / 2;
+
+ return load;
+}
+
int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type, enum load_calc_quirks quirks)
{
@@ -792,7 +868,6 @@
case V4L2_PIX_FMT_H264_MVC:
codec = HAL_VIDEO_CODEC_MVC;
break;
-
case V4L2_PIX_FMT_MPEG1:
codec = HAL_VIDEO_CODEC_MPEG1;
break;
@@ -808,6 +883,9 @@
case V4L2_PIX_FMT_HEVC:
codec = HAL_VIDEO_CODEC_HEVC;
break;
+ case V4L2_PIX_FMT_TME:
+ codec = HAL_VIDEO_CODEC_TME;
+ break;
default:
dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
codec = HAL_UNUSED_CODEC;
@@ -1252,6 +1330,9 @@
static void msm_vidc_comm_update_ctrl_limits(struct msm_vidc_inst *inst)
{
if (inst->session_type == MSM_VIDC_ENCODER) {
+ if (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) ==
+ HAL_VIDEO_CODEC_TME)
+ return;
msm_vidc_comm_update_ctrl(inst,
V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE,
&inst->capability.hier_p_hybrid);
@@ -1529,6 +1610,12 @@
* ptr[2] = bit depth
* ptr[3] = pic struct (progressive or interlaced)
* ptr[4] = colour space
+ * ptr[5] = crop_data(top)
+ * ptr[6] = crop_data(left)
+ * ptr[7] = crop_data(height)
+ * ptr[8] = crop_data(width)
+ * ptr[9] = profile
+ * ptr[10] = level
*/
inst->entropy_mode = event_notify->entropy_mode;
@@ -1553,10 +1640,17 @@
ptr[6] = event_notify->crop_data.left;
ptr[7] = event_notify->crop_data.height;
ptr[8] = event_notify->crop_data.width;
+ ptr[9] = msm_comm_get_v4l2_profile(
+ inst->fmts[OUTPUT_PORT].fourcc,
+ event_notify->profile);
+ ptr[10] = msm_comm_get_v4l2_level(
+ inst->fmts[OUTPUT_PORT].fourcc,
+ event_notify->level);
dprintk(VIDC_DBG,
- "Event payload: height = %d width = %d\n",
- event_notify->height, event_notify->width);
+ "Event payload: height = %d width = %d profile = %d level = %d\n",
+ event_notify->height, event_notify->width,
+ ptr[9], ptr[10]);
dprintk(VIDC_DBG,
"Event payload: bit_depth = %d pic_struct = %d colour_space = %d\n",
@@ -5698,7 +5792,9 @@
dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
inst, inst->prop.fps, fps);
inst->prop.fps = fps;
- if (inst->session_type == MSM_VIDC_ENCODER) {
+ if (inst->session_type == MSM_VIDC_ENCODER &&
+ get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) !=
+ HAL_VIDEO_CODEC_TME) {
frame_rate.frame_rate = inst->prop.fps * BIT(16);
frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
pdata = &frame_rate;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 4a06f19..a272a10 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -85,6 +85,8 @@
int msm_comm_check_core_init(struct msm_vidc_core *core);
int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
enum load_calc_quirks quirks);
+int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst,
+ enum load_calc_quirks quirks);
int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type, enum load_calc_quirks quirks);
int msm_comm_set_color_format(struct msm_vidc_inst *inst,
@@ -102,6 +104,8 @@
void msm_comm_print_inst_info(struct msm_vidc_inst *inst);
int msm_comm_v4l2_to_hal(int id, int value);
int msm_comm_hal_to_v4l2(int id, int value);
+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);
enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc);
u32 get_frame_size_nv12(int plane, u32 height, u32 width);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 027e76e..7ca6ab0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -44,6 +44,7 @@
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 69fc2e0..82c3ffc 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1090,6 +1090,7 @@
return rc;
}
+ trace_msm_vidc_perf_clock_scale(cl->name, freq);
dprintk(VIDC_PROF, "Scaling clock %s to %u\n",
cl->name, freq);
}
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 6852587..f350f25 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -273,6 +273,7 @@
HAL_VIDEO_CODEC_VP8 = 0x00001000,
HAL_VIDEO_CODEC_HEVC = 0x00002000,
HAL_VIDEO_CODEC_VP9 = 0x00004000,
+ HAL_VIDEO_CODEC_TME = 0x00008000,
HAL_VIDEO_CODEC_HEVC_HYBRID = 0x80000000,
HAL_UNUSED_CODEC = 0x10000000,
};
@@ -385,6 +386,17 @@
HAL_VPX_LEVEL_VERSION_3 = 0x00000008,
};
+enum hal_tme_profile {
+ HAL_TME_PROFILE_0 = 0x00000001,
+ HAL_TME_PROFILE_1 = 0x00000002,
+ HAL_TME_PROFILE_2 = 0x00000004,
+ HAL_TME_PROFILE_3 = 0x00000008,
+};
+
+enum hal_tme_level {
+ HAL_TME_LEVEL_INTEGER = 0x00000001,
+};
+
struct hal_frame_rate {
enum hal_buffer buffer_type;
u32 frame_rate;
@@ -1203,6 +1215,7 @@
enum buffer_mode_type alloc_mode_out;
enum buffer_mode_type alloc_mode_in;
u32 pixelprocess_capabilities;
+ u32 tme_version;
};
struct vidc_hal_sys_init_done {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 1d1928a..5e7595c 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1367,6 +1367,8 @@
descr = "HEVC"; break;
case V4L2_PIX_FMT_VP9:
descr = "VP9"; break;
+ case V4L2_PIX_FMT_TME:
+ descr = "TME"; break;
default:
WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
if (fmt->description[0])
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 2f927bd..501d4a4 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -1068,6 +1068,8 @@
struct audio_client *ac;
struct audio_aio_write_param param;
+ memset(¶m, 0, sizeof(param));
+
if (!audio || !buf_node) {
pr_err("%s NULL pointer audio=[0x%pK], buf_node=[0x%pK]\n",
__func__, audio, buf_node);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index e5fe6ba..aef0db2 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -178,4 +178,11 @@
module is used to configure and read the configuration from the
Serial Engines.
+config MSM_EXT_DISPLAY
+ bool "MSM External Display Driver"
+ help
+ Enabling this option adds MSM External Display Driver.
+ External Display driver was added to support the communication
+ between external display driver and its counterparts.
+
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index ff1d0e2..27179b9 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -12,3 +12,4 @@
obj-$(CONFIG_MSM_11AD) += msm_11ad/
obj-$(CONFIG_SEEMP_CORE) += seemp_core/
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
+obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
new file mode 100644
index 0000000..3be414b
--- /dev/null
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -0,0 +1,525 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+#include <linux/of_platform.h>
+#include <linux/msm_ext_display.h>
+
+struct msm_ext_disp_list {
+ struct msm_ext_disp_init_data *data;
+ struct list_head list;
+};
+
+struct msm_ext_disp {
+ struct msm_ext_disp_data ext_disp_data;
+ struct platform_device *pdev;
+ enum msm_ext_disp_type current_disp;
+ struct msm_ext_disp_audio_codec_ops *ops;
+ struct extcon_dev audio_sdev;
+ bool audio_session_on;
+ struct list_head display_list;
+ struct mutex lock;
+};
+
+static const unsigned int msm_ext_disp_supported_cable[] = {
+ EXTCON_DISP_DP,
+ EXTCON_DISP_HDMI,
+ EXTCON_NONE,
+};
+
+static int msm_ext_disp_extcon_register(struct msm_ext_disp *ext_disp)
+{
+ int ret = 0;
+
+ if (!ext_disp) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ memset(&ext_disp->audio_sdev, 0x0, sizeof(ext_disp->audio_sdev));
+ ext_disp->audio_sdev.supported_cable = msm_ext_disp_supported_cable;
+ ext_disp->audio_sdev.dev.parent = &ext_disp->pdev->dev;
+ ret = extcon_dev_register(&ext_disp->audio_sdev);
+ if (ret) {
+ pr_err("audio registration failed");
+ return ret;
+ }
+
+ pr_debug("extcon registration done\n");
+
+ return ret;
+}
+
+static void msm_ext_disp_extcon_unregister(struct msm_ext_disp *ext_disp)
+{
+ if (!ext_disp) {
+ pr_err("Invalid params\n");
+ return;
+ }
+
+ extcon_dev_unregister(&ext_disp->audio_sdev);
+}
+
+static const char *msm_ext_disp_name(enum msm_ext_disp_type type)
+{
+ switch (type) {
+ case EXT_DISPLAY_TYPE_HDMI: return "EXT_DISPLAY_TYPE_HDMI";
+ case EXT_DISPLAY_TYPE_DP: return "EXT_DISPLAY_TYPE_DP";
+ default: return "???";
+ }
+}
+
+static int msm_ext_disp_add_intf_data(struct msm_ext_disp *ext_disp,
+ struct msm_ext_disp_init_data *data)
+{
+ struct msm_ext_disp_list *node;
+
+ if (!ext_disp && !data) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ node->data = data;
+ list_add(&node->list, &ext_disp->display_list);
+
+ pr_debug("Added new display (%s)\n", msm_ext_disp_name(data->type));
+
+ return 0;
+}
+
+static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp,
+ enum msm_ext_disp_type type,
+ struct msm_ext_disp_init_data **data)
+{
+ int ret = 0;
+ struct msm_ext_disp_list *node;
+ struct list_head *position = NULL;
+
+ if (!ext_disp || !data || type < EXT_DISPLAY_TYPE_HDMI ||
+ type >= EXT_DISPLAY_TYPE_MAX) {
+ pr_err("Invalid params\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ *data = NULL;
+ list_for_each(position, &ext_disp->display_list) {
+ node = list_entry(position, struct msm_ext_disp_list, list);
+ if (node->data->type == type) {
+ *data = node->data;
+ break;
+ }
+ }
+
+ if (!*data) {
+ pr_err("Display not found (%s)\n", msm_ext_disp_name(type));
+ ret = -ENODEV;
+ }
+end:
+ return ret;
+}
+
+static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state new_state)
+{
+ int ret = 0;
+ int state;
+
+ state = ext_disp->audio_sdev.state;
+ ret = extcon_set_state_sync(&ext_disp->audio_sdev,
+ ext_disp->current_disp, !!new_state);
+
+ pr_debug("Audio state %s %d\n",
+ ext_disp->audio_sdev.state == state ?
+ "is same" : "switched to",
+ ext_disp->audio_sdev.state);
+
+ return ret;
+}
+
+static struct msm_ext_disp *msm_ext_disp_validate_and_get(
+ struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ struct msm_ext_disp_data *ext_disp_data;
+ struct msm_ext_disp *ext_disp;
+
+ if (!pdev) {
+ pr_err("invalid platform device\n");
+ goto err;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("invalid drvdata\n");
+ goto err;
+ }
+
+ ext_disp = container_of(ext_disp_data,
+ struct msm_ext_disp, ext_disp_data);
+
+ if (state < EXT_DISPLAY_CABLE_DISCONNECT ||
+ state >= EXT_DISPLAY_CABLE_STATE_MAX) {
+ pr_err("invalid HPD state (%d)\n", state);
+ goto err;
+ }
+
+ if (state == EXT_DISPLAY_CABLE_CONNECT) {
+ if (ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX &&
+ ext_disp->current_disp != type) {
+ pr_err("invalid interface call\n");
+ goto err;
+ }
+ } else {
+ if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX ||
+ ext_disp->current_disp != type) {
+ pr_err("invalid interface call\n");
+ goto err;
+ }
+ }
+ return ext_disp;
+err:
+ return ERR_PTR(-EINVAL);
+}
+
+static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ int ret = 0;
+ struct msm_ext_disp_init_data *data = NULL;
+
+ ret = msm_ext_disp_get_intf_data(ext_disp, type, &data);
+ if (ret || !data) {
+ pr_err("interface %s not found\n", msm_ext_disp_name(type));
+ goto end;
+ }
+
+ if (state == EXT_DISPLAY_CABLE_CONNECT) {
+ /* connect codec with interface */
+ *ext_disp->ops = data->codec_ops;
+
+ /* update pdev for interface to use */
+ ext_disp->ext_disp_data.intf_pdev = data->pdev;
+ ext_disp->ext_disp_data.intf_data = data->intf_data;
+
+ ext_disp->current_disp = type;
+
+ pr_debug("codec ops set for %s\n", msm_ext_disp_name(type));
+ } else if (state == EXT_DISPLAY_CABLE_DISCONNECT) {
+ *ext_disp->ops = (struct msm_ext_disp_audio_codec_ops){NULL};
+ ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
+
+ pr_debug("codec ops cleared for %s\n", msm_ext_disp_name(type));
+ }
+end:
+ return ret;
+}
+
+static int msm_ext_disp_audio_config(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp;
+
+ ext_disp = msm_ext_disp_validate_and_get(pdev, type, state);
+ if (IS_ERR(ext_disp)) {
+ ret = PTR_ERR(ext_disp);
+ goto end;
+ }
+
+ mutex_lock(&ext_disp->lock);
+ ret = msm_ext_disp_update_audio_ops(ext_disp, type, state);
+ mutex_unlock(&ext_disp->lock);
+end:
+ return ret;
+}
+
+static int msm_ext_disp_audio_notify(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp;
+
+ ext_disp = msm_ext_disp_validate_and_get(pdev, type, state);
+ if (IS_ERR(ext_disp)) {
+ ret = PTR_ERR(ext_disp);
+ goto end;
+ }
+
+ mutex_lock(&ext_disp->lock);
+ ret = msm_ext_disp_process_audio(ext_disp, type, state);
+ mutex_unlock(&ext_disp->lock);
+end:
+ return ret;
+}
+
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops)
+{
+ return msm_ext_disp_register_audio_codec(pdev, ops);
+}
+
+int msm_ext_disp_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp = NULL;
+ struct msm_ext_disp_data *ext_disp_data = NULL;
+
+ if (!pdev || !ops) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("Invalid drvdata\n");
+ return -EINVAL;
+ }
+
+ ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+ ext_disp_data);
+
+ mutex_lock(&ext_disp->lock);
+
+ if ((ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX)
+ && ext_disp->ops) {
+ pr_err("Codec already registered\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ext_disp->ops = ops;
+
+ pr_debug("audio codec registered\n");
+
+end:
+ mutex_unlock(&ext_disp->lock);
+
+ return ret;
+}
+
+static int msm_ext_disp_validate_intf(struct msm_ext_disp_init_data *init_data)
+{
+ if (!init_data) {
+ pr_err("Invalid init_data\n");
+ return -EINVAL;
+ }
+
+ if (!init_data->pdev) {
+ pr_err("Invalid display intf pdev\n");
+ return -EINVAL;
+ }
+
+ if (!init_data->codec_ops.get_audio_edid_blk ||
+ !init_data->codec_ops.cable_status ||
+ !init_data->codec_ops.audio_info_setup) {
+ pr_err("Invalid codec operation pointers\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int msm_ext_disp_register_intf(struct platform_device *pdev,
+ struct msm_ext_disp_init_data *init_data)
+{
+ int ret = 0;
+ struct msm_ext_disp_init_data *data = NULL;
+ struct msm_ext_disp *ext_disp = NULL;
+ struct msm_ext_disp_data *ext_disp_data = NULL;
+
+ if (!pdev || !init_data) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("Invalid drvdata\n");
+ return -EINVAL;
+ }
+
+ ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+ ext_disp_data);
+
+ mutex_lock(&ext_disp->lock);
+
+ ret = msm_ext_disp_validate_intf(init_data);
+ if (ret)
+ goto end;
+
+ ret = msm_ext_disp_get_intf_data(ext_disp, init_data->type, &data);
+ if (!ret) {
+ pr_err("%s already registered\n",
+ msm_ext_disp_name(init_data->type));
+ goto end;
+ }
+
+ ret = msm_ext_disp_add_intf_data(ext_disp, init_data);
+ if (ret)
+ goto end;
+
+ init_data->intf_ops.audio_config = msm_ext_disp_audio_config;
+ init_data->intf_ops.audio_notify = msm_ext_disp_audio_notify;
+
+ pr_debug("%s registered\n", msm_ext_disp_name(init_data->type));
+
+ mutex_unlock(&ext_disp->lock);
+
+ return ret;
+
+end:
+ mutex_unlock(&ext_disp->lock);
+
+ return ret;
+}
+
+static int msm_ext_disp_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct device_node *of_node = NULL;
+ struct msm_ext_disp *ext_disp = NULL;
+
+ if (!pdev) {
+ pr_err("No platform device found\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ of_node = pdev->dev.of_node;
+ if (!of_node) {
+ pr_err("No device node found\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ ext_disp = devm_kzalloc(&pdev->dev, sizeof(*ext_disp), GFP_KERNEL);
+ if (!ext_disp) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ platform_set_drvdata(pdev, &ext_disp->ext_disp_data);
+ ext_disp->pdev = pdev;
+
+ ret = msm_ext_disp_extcon_register(ext_disp);
+ if (ret)
+ goto extcon_dev_failure;
+
+ ret = of_platform_populate(of_node, NULL, NULL, &pdev->dev);
+ if (ret) {
+ pr_err("Failed to add child devices. Error = %d\n", ret);
+ goto child_node_failure;
+ } else {
+ pr_debug("%s: Added child devices.\n", __func__);
+ }
+
+ mutex_init(&ext_disp->lock);
+
+ INIT_LIST_HEAD(&ext_disp->display_list);
+ ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
+
+ return ret;
+
+child_node_failure:
+ msm_ext_disp_extcon_unregister(ext_disp);
+extcon_dev_failure:
+ devm_kfree(&ext_disp->pdev->dev, ext_disp);
+end:
+ return ret;
+}
+
+static int msm_ext_disp_remove(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_ext_disp *ext_disp = NULL;
+ struct msm_ext_disp_data *ext_disp_data = NULL;
+
+ if (!pdev) {
+ pr_err("No platform device\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ ext_disp_data = platform_get_drvdata(pdev);
+ if (!ext_disp_data) {
+ pr_err("No drvdata found\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+ ext_disp_data);
+
+ msm_ext_disp_extcon_unregister(ext_disp);
+
+ mutex_destroy(&ext_disp->lock);
+ devm_kfree(&ext_disp->pdev->dev, ext_disp);
+
+end:
+ return ret;
+}
+
+static const struct of_device_id msm_ext_dt_match[] = {
+ {.compatible = "qcom,msm-ext-disp",},
+ { /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, msm_ext_dt_match);
+
+static struct platform_driver this_driver = {
+ .probe = msm_ext_disp_probe,
+ .remove = msm_ext_disp_remove,
+ .driver = {
+ .name = "msm-ext-disp",
+ .of_match_table = msm_ext_dt_match,
+ },
+};
+
+static int __init msm_ext_disp_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_register(&this_driver);
+ if (ret)
+ pr_err("failed, ret = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit msm_ext_disp_exit(void)
+{
+ platform_driver_unregister(&this_driver);
+}
+
+subsys_initcall(msm_ext_disp_init);
+module_exit(msm_ext_disp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM External Display");
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index b3de8d0..faca084 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -1034,6 +1034,9 @@
struct smb_charger *chg = power_supply_get_drvdata(psy);
switch (prop) {
+ case POWER_SUPPLY_PROP_STATUS:
+ rc = smblib_set_prop_batt_status(chg, val);
+ break;
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
rc = smblib_set_prop_input_suspend(chg, val);
break;
@@ -1111,6 +1114,7 @@
enum power_supply_property psp)
{
switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
case POWER_SUPPLY_PROP_CAPACITY:
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 5ae653e..c57f7ef 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -1634,6 +1634,12 @@
if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
return 0;
+ if (!usb_online && dc_online
+ && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ return 0;
+ }
+
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
@@ -1887,6 +1893,20 @@
return 0;
}
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ /* Faking battery full */
+ if (val->intval == POWER_SUPPLY_STATUS_FULL)
+ chg->fake_batt_status = val->intval;
+ else
+ chg->fake_batt_status = -EINVAL;
+
+ power_supply_changed(chg->batt_psy);
+
+ return 0;
+}
+
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val)
{
@@ -4719,6 +4739,7 @@
INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
chg->fake_capacity = -EINVAL;
chg->fake_input_current_limited = -EINVAL;
+ chg->fake_batt_status = -EINVAL;
switch (chg->mode) {
case PARALLEL_MASTER:
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 5b59597..2746555 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -307,6 +307,7 @@
int *thermal_mitigation;
int dcp_icl_ua;
int fake_capacity;
+ int fake_batt_status;
bool step_chg_enabled;
bool sw_jeita_enabled;
bool is_hdc;
@@ -427,6 +428,8 @@
const union power_supply_propval *val);
int smblib_set_prop_batt_capacity(struct smb_charger *chg,
const union power_supply_propval *val);
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_input_current_limited(struct smb_charger *chg,
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 168383ec..9f47fb3 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -115,6 +115,7 @@
*/
struct ion_handle {
struct kref ref;
+ unsigned int user_ref_count;
struct ion_client *client;
struct ion_buffer *buffer;
struct rb_node node;
@@ -433,6 +434,50 @@
return ret;
}
+/* Must hold the client lock */
+static void user_ion_handle_get(struct ion_handle *handle)
+{
+ if (handle->user_ref_count++ == 0)
+ kref_get(&handle->ref);
+}
+
+/* Must hold the client lock */
+static struct ion_handle *user_ion_handle_get_check_overflow(
+ struct ion_handle *handle)
+{
+ if (handle->user_ref_count + 1 == 0)
+ return ERR_PTR(-EOVERFLOW);
+ user_ion_handle_get(handle);
+ return handle;
+}
+
+/* passes a kref to the user ref count.
+ * We know we're holding a kref to the object before and
+ * after this call, so no need to reverify handle.
+ */
+static struct ion_handle *pass_to_user(struct ion_handle *handle)
+{
+ struct ion_client *client = handle->client;
+ struct ion_handle *ret;
+
+ mutex_lock(&client->lock);
+ ret = user_ion_handle_get_check_overflow(handle);
+ ion_handle_put_nolock(handle);
+ mutex_unlock(&client->lock);
+ return ret;
+}
+
+/* Must hold the client lock */
+static int user_ion_handle_put_nolock(struct ion_handle *handle)
+{
+ int ret = 0;
+
+ if (--handle->user_ref_count == 0)
+ ret = ion_handle_put_nolock(handle);
+
+ return ret;
+}
+
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
struct ion_buffer *buffer)
{
@@ -650,6 +695,25 @@
ion_handle_put_nolock(handle);
}
+static void user_ion_free_nolock(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ bool valid_handle;
+
+ WARN_ON(client != handle->client);
+
+ valid_handle = ion_handle_validate(client, handle);
+ if (!valid_handle) {
+ WARN(1, "%s: invalid handle passed to free.\n", __func__);
+ return;
+ }
+ if (!handle->user_ref_count > 0) {
+ WARN(1, "%s: User does not have access!\n", __func__);
+ return;
+ }
+ user_ion_handle_put_nolock(handle);
+}
+
void ion_free(struct ion_client *client, struct ion_handle *handle)
{
BUG_ON(client != handle->client);
@@ -1514,7 +1578,7 @@
data.allocation.flags, true);
if (IS_ERR(handle))
return PTR_ERR(handle);
-
+ pass_to_user(handle);
data.allocation.handle = handle->id;
cleanup_handle = handle;
@@ -1531,7 +1595,7 @@
mutex_unlock(&client->lock);
return PTR_ERR(handle);
}
- ion_free_nolock(client, handle);
+ user_ion_free_nolock(client, handle);
ion_handle_put_nolock(handle);
mutex_unlock(&client->lock);
break;
@@ -1555,10 +1619,15 @@
struct ion_handle *handle;
handle = ion_import_dma_buf_fd(client, data.fd.fd);
- if (IS_ERR(handle))
+ if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
- else
- data.handle.handle = handle->id;
+ } else {
+ handle = pass_to_user(handle);
+ if (IS_ERR(handle))
+ ret = PTR_ERR(handle);
+ else
+ data.handle.handle = handle->id;
+ }
break;
}
case ION_IOC_SYNC:
@@ -1590,8 +1659,10 @@
if (dir & _IOC_READ) {
if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
if (cleanup_handle) {
- ion_free(client, cleanup_handle);
- ion_handle_put(cleanup_handle);
+ mutex_lock(&client->lock);
+ user_ion_free_nolock(client, cleanup_handle);
+ ion_handle_put_nolock(cleanup_handle);
+ mutex_unlock(&client->lock);
}
return -EFAULT;
}
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 2524807..6fa5a66 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -91,8 +91,11 @@
if (type == ACL_TYPE_ACCESS) {
umode_t mode = inode->i_mode;
-
+ struct posix_acl *old_acl = acl;
error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+
+ if (!acl)
+ posix_acl_release(old_acl);
if (error)
return error;
if (mode != inode->i_mode)
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 7034e17..b2d55a3 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -258,8 +258,10 @@
if (type == ACL_TYPE_ACCESS) {
umode_t mode;
-
+ struct posix_acl *old_acl = acl;
error = posix_acl_update_mode(inode, &mode, &acl);
+ if (!acl)
+ posix_acl_release(old_acl);
if (error)
return error;
error = xfs_set_mode(inode, mode);
diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h
new file mode 100644
index 0000000..08e0def
--- /dev/null
+++ b/include/linux/msm_ext_display.h
@@ -0,0 +1,182 @@
+/* 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.
+ */
+
+#ifndef _MSM_EXT_DISPLAY_H_
+#define _MSM_EXT_DISPLAY_H_
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/extcon.h>
+
+#define AUDIO_ACK_SET_ENABLE BIT(5)
+#define AUDIO_ACK_ENABLE BIT(4)
+#define AUDIO_ACK_CONNECT BIT(0)
+
+/*
+ * Flags to be used with the HPD operation of the external display
+ * interface:
+ * MSM_EXT_DISP_HPD_AUDIO: audio will be routed to external display
+ * MSM_EXT_DISP_HPD_VIDEO: video will be routed to external display
+ */
+#define MSM_EXT_DISP_HPD_AUDIO BIT(0)
+#define MSM_EXT_DISP_HPD_VIDEO BIT(1)
+
+/**
+ * struct ext_disp_cable_notify - cable notify handler structure
+ * @link: a link for the linked list
+ * @status: current status of HDMI/DP cable connection
+ * @hpd_notify: callback function to provide cable status
+ */
+struct ext_disp_cable_notify {
+ struct list_head link;
+ int status;
+ void (*hpd_notify)(struct ext_disp_cable_notify *h);
+};
+
+struct msm_ext_disp_audio_edid_blk {
+ u8 *audio_data_blk;
+ unsigned int audio_data_blk_size; /* in bytes */
+ u8 *spk_alloc_data_blk;
+ unsigned int spk_alloc_data_blk_size; /* in bytes */
+};
+
+struct msm_ext_disp_audio_setup_params {
+ u32 sample_rate_hz;
+ u32 num_of_channels;
+ u32 channel_allocation;
+ u32 level_shift;
+ bool down_mix;
+ u32 sample_present;
+};
+
+/*
+ * External Display identifier for use to determine which interface
+ * the audio driver is interacting with.
+ */
+enum msm_ext_disp_type {
+ EXT_DISPLAY_TYPE_HDMI = EXTCON_DISP_HDMI,
+ EXT_DISPLAY_TYPE_DP = EXTCON_DISP_DP,
+ EXT_DISPLAY_TYPE_MAX = 0xFFFFFFFF
+};
+
+/*
+ * External Display cable state used by display interface to indicate
+ * connect/disconnect of interface.
+ */
+enum msm_ext_disp_cable_state {
+ EXT_DISPLAY_CABLE_DISCONNECT,
+ EXT_DISPLAY_CABLE_CONNECT,
+ EXT_DISPLAY_CABLE_STATE_MAX
+};
+
+/**
+ * External Display power state used by display interface to indicate
+ * power on/off of the interface.
+ */
+enum msm_ext_disp_power_state {
+ EXT_DISPLAY_POWER_OFF,
+ EXT_DISPLAY_POWER_ON,
+ EXT_DISPLAY_POWER_MAX
+};
+
+/**
+ * struct msm_ext_disp_intf_ops - operations exposed to display interface
+ * @audio_config: configures the audio operations exposed to codec driver
+ * @audio_notify: notifies the audio connection state to user modules.
+ * @video_notify: notifies the video connection state to user modules.
+ */
+struct msm_ext_disp_intf_ops {
+ int (*audio_config)(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state);
+
+ int (*audio_notify)(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state);
+
+
+ int (*video_notify)(struct platform_device *pdev,
+ enum msm_ext_disp_type type,
+ enum msm_ext_disp_cable_state state);
+};
+
+/**
+ * struct msm_ext_disp_audio_codec_ops - operations exposed to audio codec
+ * @audio_info_setup: configure audio on interface
+ * @get_audio_edid_blk: retrieve audio edid block
+ * @cable_status: cable connected/disconnected
+ * @get_intf_id: id of connected interface
+ * @teardown_done: audio session teardown done by qdsp
+ * @acknowledge: acknowledge audio status received by user modules
+ */
+struct msm_ext_disp_audio_codec_ops {
+ int (*audio_info_setup)(struct platform_device *pdev,
+ struct msm_ext_disp_audio_setup_params *params);
+ int (*get_audio_edid_blk)(struct platform_device *pdev,
+ struct msm_ext_disp_audio_edid_blk *blk);
+ int (*cable_status)(struct platform_device *pdev, u32 vote);
+ int (*get_intf_id)(struct platform_device *pdev);
+ void (*teardown_done)(struct platform_device *pdev);
+ int (*acknowledge)(struct platform_device *pdev, u32 ack);
+};
+
+/**
+ * struct msm_ext_disp_init_data - data needed to register a display interface
+ * @type: external display type
+ * @intf_ops: external display interface operations
+ * @codec_ops: audio codec operations
+ * @pdev: platform device instance of the interface driver
+ * @intf_data: interface specific data
+ */
+struct msm_ext_disp_init_data {
+ enum msm_ext_disp_type type;
+ struct msm_ext_disp_intf_ops intf_ops;
+ struct msm_ext_disp_audio_codec_ops codec_ops;
+ struct platform_device *pdev;
+ void *intf_data;
+};
+
+/**
+ * struct msm_ext_disp_data - data needed by interface modules
+ * @intf_pdev: platform device instance of the interface
+ * @intf_data: data related to interface module
+ */
+struct msm_ext_disp_data {
+ struct platform_device *intf_pdev;
+ void *intf_data;
+};
+
+/**
+ * msm_ext_disp_register_audio_codec() - audio codec registration
+ * @pdev: platform device pointer
+ * @codec_ops: audio codec operations
+ */
+int msm_ext_disp_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops);
+
+/**
+ * msm_hdmi_register_audio_codec() - wrapper for hdmi audio codec
+ * registration
+ * @pdev: platform device pointer
+ * @codec_ops: audio codec operations
+ */
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+ struct msm_ext_disp_audio_codec_ops *ops);
+
+/**
+ * msm_ext_disp_register_intf() - display interface registration
+ * @init_data: data needed to register the display interface
+ */
+int msm_ext_disp_register_intf(struct platform_device *pdev,
+ struct msm_ext_disp_init_data *init_data);
+
+#endif /*_MSM_EXT_DISPLAY_H_*/
diff --git a/include/trace/events/msm_vidc.h b/include/trace/events/msm_vidc.h
index ea698bf..c6c446a 100644
--- a/include/trace/events/msm_vidc.h
+++ b/include/trace/events/msm_vidc.h
@@ -310,6 +310,39 @@
TP_ARGS(buffer_op, domain_num, partition_num, align, iova, buffer_size)
);
+DECLARE_EVENT_CLASS(msm_vidc_perf,
+
+ TP_PROTO(const char *name, unsigned long value),
+
+ TP_ARGS(name, value),
+
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ __field(unsigned long, value)
+ ),
+
+ TP_fast_assign(
+ __entry->name = name;
+ __entry->value = value;
+ ),
+
+ TP_printk("%s %lu", __entry->name, __entry->value)
+);
+
+DEFINE_EVENT(msm_vidc_perf, msm_vidc_perf_clock_scale,
+
+ TP_PROTO(const char *clock_name, unsigned long frequency),
+
+ TP_ARGS(clock_name, frequency)
+);
+
+DEFINE_EVENT(msm_vidc_perf, msm_vidc_perf_bus_vote,
+
+ TP_PROTO(const char *governor_mode, unsigned long ab),
+
+ TP_ARGS(governor_mode, ab)
+);
+
#endif
#include <trace/define_trace.h>
diff --git a/include/uapi/drm/msm_drm_pp.h b/include/uapi/drm/msm_drm_pp.h
index c7f2308..5f70a57 100644
--- a/include/uapi/drm/msm_drm_pp.h
+++ b/include/uapi/drm/msm_drm_pp.h
@@ -104,6 +104,7 @@
#define GAMUT_3D_MODE5_TBL_SZ 32
#define GAMUT_3D_MODE13_TBL_SZ 550
#define GAMUT_3D_SCALE_OFF_SZ 16
+#define GAMUT_3D_SCALEB_OFF_SZ 12
#define GAMUT_3D_TBL_NUM 4
#define GAMUT_3D_SCALE_OFF_TBL_NUM 3
#define GAMUT_3D_MAP_EN (1 << 0)
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 731b2f0..5183111 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1079,6 +1079,26 @@
#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 110)
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 111)
+
+enum v4l2_mpeg_vidc_video_tme_profile {
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0 = 0,
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1 = 1,
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2 = 2,
+ V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3 = 3,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 112)
+
+enum v4l2_mpeg_vidc_video_tme_level {
+ V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER = 0,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 113)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 4f1f9e9..85b7e87 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -613,6 +613,7 @@
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_TME v4l2_fourcc('T', 'M', 'E', '0') /* for TME stream */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index be87b1e..4f12e5c 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -769,11 +769,49 @@
* + max(Extradata, Y_Stride * 48), 4096)
*/
COLOR_FMT_P010_UBWC,
+ /* Venus P010:
+ * YUV 4:2:0 image with a plane of 10 bit Y samples followed
+ * by an interleaved U/V plane containing 10 bit 2x2 subsampled
+ * colour difference samples.
+ *
+ * <-------- Y/UV_Stride -------->
+ * <------- Width ------->
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * U V U V U V U V U V U V . . . . ^
+ * U V U V U V U V U V U V . . . . |
+ * U V U V U V U V U V U V . . . . |
+ * U V U V U V U V U V U V . . . . UV_Scanlines
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . . . --> Buffer size alignment
+ *
+ * Y_Stride : Width * 2 aligned to 128
+ * UV_Stride : Width * 2 aligned to 128
+ * Y_Scanlines: Height aligned to 32
+ * UV_Scanlines: Height/2 aligned to 16
+ * Extradata: Arbitrary (software-imposed) padding
+ * Total size = align((Y_Stride * Y_Scanlines
+ * + UV_Stride * UV_Scanlines
+ * + max(Extradata, Y_Stride * 8), 4096)
+ */
+ COLOR_FMT_P010,
};
#define COLOR_FMT_RGBA1010102_UBWC COLOR_FMT_RGBA1010102_UBWC
#define COLOR_FMT_RGB565_UBWC COLOR_FMT_RGB565_UBWC
#define COLOR_FMT_P010_UBWC COLOR_FMT_P010_UBWC
+#define COLOR_FMT_P010 COLOR_FMT_P010
static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
{
@@ -818,6 +856,10 @@
alignment = 256;
stride = MSM_MEDIA_ALIGN(width * 2, alignment);
break;
+ case COLOR_FMT_P010:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width*2, alignment);
+ break;
default:
break;
}
@@ -856,6 +898,10 @@
alignment = 256;
stride = MSM_MEDIA_ALIGN(width * 2, alignment);
break;
+ case COLOR_FMT_P010:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width*2, alignment);
+ break;
default:
break;
}
@@ -882,6 +928,7 @@
case COLOR_FMT_NV12:
case COLOR_FMT_NV12_MVTB:
case COLOR_FMT_NV12_UBWC:
+ case COLOR_FMT_P010:
alignment = 32;
break;
case COLOR_FMT_NV12_BPP10_UBWC:
@@ -916,6 +963,7 @@
case COLOR_FMT_NV12_MVTB:
case COLOR_FMT_NV12_BPP10_UBWC:
case COLOR_FMT_P010_UBWC:
+ case COLOR_FMT_P010:
alignment = 16;
break;
case COLOR_FMT_NV12_UBWC:
@@ -1204,6 +1252,7 @@
switch (color_fmt) {
case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
+ case COLOR_FMT_P010:
uv_alignment = 4096;
y_plane = y_stride * y_sclines;
uv_plane = uv_stride * uv_sclines + uv_alignment;
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index a26036d..49237ae 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -70,6 +70,9 @@
static struct hrtimer sched_clock_timer;
static int irqtime = -1;
+static u64 suspend_ns;
+static u64 suspend_cycles;
+static u64 resume_cycles;
core_param(irqtime, irqtime, int, 0400);
@@ -274,6 +277,11 @@
struct clock_read_data *rd = &cd.read_data[0];
update_sched_clock();
+
+ suspend_ns = rd->epoch_ns;
+ suspend_cycles = rd->epoch_cyc;
+ pr_info("suspend ns:%17llu suspend cycles:%17llu\n",
+ rd->epoch_ns, rd->epoch_cyc);
hrtimer_cancel(&sched_clock_timer);
rd->read_sched_clock = suspended_sched_clock_read;
@@ -285,6 +293,8 @@
struct clock_read_data *rd = &cd.read_data[0];
rd->epoch_cyc = cd.actual_read_sched_clock();
+ resume_cycles = rd->epoch_cyc;
+ pr_info("resume cycles:%17llu\n", rd->epoch_cyc);
hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
rd->read_sched_clock = cd.actual_read_sched_clock;
}
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index ad1d616..e82cff5 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -304,7 +304,7 @@
if (!*fmt)
return 0;
- seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
+ seq_printf(m, "0x%lx : \"", 0L);
/*
* Tabs and new lines need to be converted.
diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c
index 834594a..bbf0a3a 100644
--- a/net/netfilter/xt_quota2.c
+++ b/net/netfilter/xt_quota2.c
@@ -16,6 +16,7 @@
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <asm/atomic.h>
#include <net/netlink.h>
@@ -43,6 +44,8 @@
unsigned char payload[0];
} ulog_packet_msg_t;
#endif
+#define QUOTA2_SYSFS_WORK_MAX_SIZE 64
+#define QUOTA2_SYSFS_NUM_ENVP 3
/**
* @lock: lock to protect quota writers from each other
@@ -54,17 +57,16 @@
atomic_t ref;
char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)];
struct proc_dir_entry *procfs_entry;
+ char last_iface[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ char last_prefix[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ struct work_struct work;
};
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-/* Harald's favorite number +1 :D From ipt_ULOG.C */
-static int qlog_nl_event = 112;
-module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(event_num,
- "Event number for NETLINK_NFLOG message. 0 disables log."
- "111 is what ipt_ULOG uses.");
-static struct sock *nflognl;
-#endif
+#define to_quota_counter(x) container_of(x, struct xt_quota_counter, work)
+
+static struct class *quota_class;
+static struct device *quota_device;
+static struct kobject *quota_kobj;
static LIST_HEAD(counter_list);
static DEFINE_SPINLOCK(counter_list_lock);
@@ -75,68 +77,39 @@
static kgid_t quota_list_gid = KGIDT_INIT(0);
module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-static void quota2_log(unsigned int hooknum,
- const struct sk_buff *skb,
- const struct net_device *in,
+static void quota2_work(struct work_struct *work)
+{
+ char alert_msg[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ char iface_name[QUOTA2_SYSFS_WORK_MAX_SIZE];
+ char *envp[QUOTA2_SYSFS_NUM_ENVP] = {alert_msg, iface_name, NULL};
+ struct xt_quota_counter *counter = to_quota_counter(work);
+
+ snprintf(alert_msg, sizeof(alert_msg), "ALERT_NAME=%s", counter->name);
+ snprintf(iface_name, sizeof(iface_name), "INTERFACE=%s",
+ counter->last_iface);
+
+ kobject_uevent_env(quota_kobj, KOBJ_CHANGE, envp);
+}
+
+static void quota2_log(const struct net_device *in,
const struct net_device *out,
+ struct xt_quota_counter *q,
const char *prefix)
{
- ulog_packet_msg_t *pm;
- struct sk_buff *log_skb;
- size_t size;
- struct nlmsghdr *nlh;
-
- if (!qlog_nl_event)
+ if (!prefix)
return;
- size = NLMSG_SPACE(sizeof(*pm));
- size = max(size, (size_t)NLMSG_GOODSIZE);
- log_skb = alloc_skb(size, GFP_ATOMIC);
- if (!log_skb) {
- pr_err("xt_quota2: cannot alloc skb for logging\n");
- return;
- }
+ strlcpy(q->last_prefix, prefix, QUOTA2_SYSFS_WORK_MAX_SIZE);
- nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event,
- sizeof(*pm), 0);
- if (!nlh) {
- pr_err("xt_quota2: nlmsg_put failed\n");
- kfree_skb(log_skb);
- return;
- }
- pm = nlmsg_data(nlh);
- if (skb->tstamp.tv64 == 0)
- __net_timestamp((struct sk_buff *)skb);
- pm->data_len = 0;
- pm->hook = hooknum;
- if (prefix != NULL)
- strlcpy(pm->prefix, prefix, sizeof(pm->prefix));
- else
- *(pm->prefix) = '\0';
if (in)
- strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+ strlcpy(q->last_iface, in->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
+ else if (out)
+ strlcpy(q->last_iface, out->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
else
- pm->indev_name[0] = '\0';
+ strlcpy(q->last_iface, "UNKNOWN", QUOTA2_SYSFS_WORK_MAX_SIZE);
- if (out)
- strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
- else
- pm->outdev_name[0] = '\0';
-
- NETLINK_CB(log_skb).dst_group = 1;
- pr_debug("throwing 1 packets to netlink group 1\n");
- netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC);
+ schedule_work(&q->work);
}
-#else
-static void quota2_log(unsigned int hooknum,
- const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const char *prefix)
-{
-}
-#endif /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
static ssize_t quota_proc_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
@@ -193,6 +166,9 @@
INIT_LIST_HEAD(&e->list);
atomic_set(&e->ref, 1);
strlcpy(e->name, q->name, sizeof(e->name));
+ strlcpy(e->last_prefix, "UNSET", sizeof(e->last_prefix));
+ strlcpy(e->last_iface, "UNSET", sizeof(e->last_iface));
+ INIT_WORK(&e->work, quota2_work);
}
return e;
}
@@ -326,11 +302,7 @@
} else {
/* We are transitioning, log that fact. */
if (e->quota) {
- quota2_log(par->hooknum,
- skb,
- par->in,
- par->out,
- q->name);
+ quota2_log(par->in, par->out, e, q->name);
}
/* we do not allow even small packets from now on */
e->quota = 0;
@@ -368,11 +340,25 @@
int ret;
pr_debug("xt_quota2: init()");
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
- nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL);
- if (!nflognl)
- return -ENOMEM;
-#endif
+ quota_class = class_create(THIS_MODULE, "xt_quota2");
+ ret = PTR_ERR(quota_class);
+ if (IS_ERR(quota_class)) {
+ pr_err("xt_quota2: couldn't create class");
+ class_destroy(quota_class);
+ return ret;
+ }
+
+ quota_device = device_create(quota_class, NULL, MKDEV(0, 0), NULL,
+ "counters");
+ ret = PTR_ERR(quota_device);
+ if (IS_ERR(quota_device)) {
+ pr_err("xt_quota2: couldn't create device");
+ device_destroy(quota_class, MKDEV(0, 0));
+ class_destroy(quota_class);
+ return ret;
+ }
+
+ quota_kobj = "a_device->kobj;
proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
if (proc_xt_quota == NULL)
@@ -389,6 +375,8 @@
{
xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
remove_proc_entry("xt_quota", init_net.proc_net);
+ device_destroy(quota_class, MKDEV(0, 0));
+ class_destroy(quota_class);
}
module_init(quota_mt2_init);
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 5fbfe3d..66ecd6a 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -202,7 +202,7 @@
config SND_SOC_660
tristate "SoC Machine driver for SDM660/670 boards"
- depends on ARCH_SDM660 || ARCH_SDM670
+ depends on ARCH_QCOM
select SND_SOC_INT_CODEC
select SND_SOC_EXT_CODEC
help
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index c885265..503af58 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -1282,6 +1282,9 @@
.step = SOFT_VOLUME_STEP,
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_value kctl_elem_value;
+ uint16_t target_asm_bit_width = 0;
pr_debug("%s: stream_id %d\n", __func__, ac->stream_id);
stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
@@ -1290,6 +1293,23 @@
return -EINVAL;
}
+ kctl = snd_soc_card_get_kcontrol(soc_prtd->card,
+ DSP_BIT_WIDTH_MIXER_CTL);
+ if (kctl) {
+ kctl->get(kctl, &kctl_elem_value);
+ target_asm_bit_width = kctl_elem_value.value.integer.value[0];
+ if (target_asm_bit_width > 0) {
+ pr_debug("%s enforce ASM bitwidth to %d from %d\n",
+ __func__,
+ target_asm_bit_width,
+ bits_per_sample);
+ bits_per_sample = target_asm_bit_width;
+ }
+ } else {
+ pr_info("%s: failed to get mixer ctl for %s.\n",
+ __func__, DSP_BIT_WIDTH_MIXER_CTL);
+ }
+
if ((prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE) ||
(prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_3LE))
bits_per_sample = 24;
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index a885e1e..53826fe 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -392,6 +392,7 @@
static int msm_afe_quat_mi2s_lb_vol_ctrl;
static int msm_afe_slimbus_7_lb_vol_ctrl;
static int msm_afe_slimbus_8_lb_vol_ctrl;
+static int msm_asm_bit_width;
static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
static const DECLARE_TLV_DB_LINEAR(afe_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
@@ -412,6 +413,38 @@
return 0;
}
+static int msm_asm_bit_width_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s get ASM bitwidth = %d\n",
+ __func__, msm_asm_bit_width);
+
+ ucontrol->value.integer.value[0] = msm_asm_bit_width;
+
+ return 0;
+}
+
+static int msm_asm_bit_width_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 16:
+ msm_asm_bit_width = 16;
+ break;
+ case 24:
+ msm_asm_bit_width = 24;
+ break;
+ case 32:
+ msm_asm_bit_width = 32;
+ break;
+ default:
+ msm_asm_bit_width = 0;
+ break;
+ }
+
+ return 0;
+}
+
static int msm_qti_pp_get_pri_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1132,6 +1165,11 @@
msm_qti_pp_set_quat_mi2s_fm_vol_mixer, fm_rx_vol_gain),
};
+static const struct snd_kcontrol_new dsp_bit_width_controls[] = {
+ SOC_SINGLE_EXT(DSP_BIT_WIDTH_MIXER_CTL, SND_SOC_NOPM, 0, 0x20,
+ 0, msm_asm_bit_width_get, msm_asm_bit_width_put),
+};
+
static const struct snd_kcontrol_new pri_mi2s_lb_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("PRI MI2S LOOPBACK Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_qti_pp_get_pri_mi2s_lb_vol_mixer,
@@ -1403,5 +1441,8 @@
snd_soc_add_platform_controls(platform, msm_multichannel_ec_controls,
ARRAY_SIZE(msm_multichannel_ec_controls));
+
+ snd_soc_add_platform_controls(platform, dsp_bit_width_controls,
+ ARRAY_SIZE(dsp_bit_width_controls));
}
#endif /* CONFIG_QTI_PP */
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
index b67e873..ec69d37 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
@@ -13,6 +13,7 @@
#define _MSM_QTI_PP_H_
#include <sound/soc.h>
+#define DSP_BIT_WIDTH_MIXER_CTL "ASM Bit Width"
int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
uint32_t *payload);
int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd);