Merge "aarch64: add core okl4 hypervisor config"
diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
index 72c46f2..99f8c4c 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
@@ -164,10 +164,7 @@
"dfps_immediate_porch_mode_vfp" = FPS change request is
implemented immediately by changing panel vertical
front porch values.
-- qcom,min-refresh-rate: Minimum refresh rate supported by the panel.
-- qcom,max-refresh-rate: Maximum refresh rate supported by the panel. If max refresh
- rate is not specified, then the frame rate of the panel in
- qcom,mdss-dsi-panel-framerate is used.
+- qcom,dsi-supported-dfps-list: List containing all the supported refresh rates.
- qcom,mdss-dsi-bl-pmic-control-type: A string that specifies the implementation of backlight
control for this panel.
"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
@@ -527,6 +524,10 @@
- qcom,mdss-dsi-panel-cmds-only-by-right: Boolean used to mention whether the panel support DSI1 or
DSI0 to send commands. If this was set, that mean the panel only support
DSI1 to send commands, otherwise DSI0 will send comands.
+- qcom,dsi-dyn-clk-enable: Boolean to indicate dsi dynamic clock switch feature
+ is supported.
+- qcom,dsi-dyn-clk-list: An u32 array which lists all the supported dsi bit clock
+ frequencies in Hz for the given panel.
Required properties for sub-nodes: None
Optional properties:
@@ -649,8 +650,7 @@
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
- qcom,min-refresh-rate = <30>;
- qcom,max-refresh-rate = <60>;
+ qcom,dsi-supported-dfps-list = <48 55 60>;
qcom,mdss-dsi-bl-pmic-bank-select = <0>;
qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>;
qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
@@ -781,5 +781,7 @@
<2 2 1>;
qcom,default-topology-index = <0>;
qcom,mdss-dsi-dma-schedule-line = <5>;
+ qcom,dsi-dyn-clk-enable;
+ qcom,dsi-dyn-clk-list = <798240576 801594528 804948480>;
};
};
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
index 27878b6..59f882d 100644
--- a/arch/arm/configs/msm8909w-perf_defconfig
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -458,6 +458,8 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
index 28e102e..04a60b0 100644
--- a/arch/arm/configs/msm8909w_defconfig
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -452,6 +452,8 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index 5006f28..33a4f67 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -160,6 +160,7 @@
};
+#include "msm8937-camera.dtsi"
#include "msm8937-pinctrl.dtsi"
#include "msm8937-cpu.dtsi"
#include "msm8937-ion.dtsi"
@@ -1818,13 +1819,20 @@
status = "ok";
};
+ qcom,csiphy@1b34000 {
+ compatible = "qcom,csiphy-v3.4.2", "qcom,csiphy";
+ };
+
+ qcom,csiphy@1b35000 {
+ compatible = "qcom,csiphy-v3.4.2", "qcom,csiphy";
+ };
+
};
#include "pm8937-rpm-regulator.dtsi"
#include "msm8937-regulator.dtsi"
#include "pm8937.dtsi"
#include "msm8937-audio.dtsi"
-#include "msm8937-camera.dtsi"
#include "msm-gdsc-8916.dtsi"
#include "msm8937-coresight.dtsi"
#include "msm8937-thermal.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-sde-display.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-sde-display.dtsi
index 99bf1e5..382fc1d5 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-sde-display.dtsi
@@ -58,7 +58,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
ports {
#address-cells = <1>;
@@ -81,7 +81,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -112,11 +112,10 @@
&dsi_dual_nt35597_truly_video {
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
- qcom,mdss-dsi-min-refresh-rate = <53>;
- qcom,mdss-dsi-max-refresh-rate = <60>;
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
+ qcom,dsi-supported-dfps-list = <53 55 60>;
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
index cb46865..d5cf3dd 100644
--- a/arch/arm64/boot/dts/qcom/qcs605.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -18,40 +18,52 @@
qcom,msm-id = <347 0x0>;
};
+&removed_region {
+ reg = <0 0x85fc0000 0 0x1540000>;
+};
+
+&pil_camera_mem {
+ reg = <0 0x8b800000 0 0x500000>;
+};
+
&pil_modem_mem {
- reg = <0 0x8b000000 0 0x3100000>;
+ reg = <0 0x8bd00000 0 0x3100000>;
};
&pil_video_mem {
- reg = <0 0x8e100000 0 0x500000>;
+ reg = <0 0x8ee00000 0 0x500000>;
};
&wlan_msa_mem {
- reg = <0 0x8e600000 0 0x100000>;
+ reg = <0 0x8f300000 0 0x100000>;
};
&pil_cdsp_mem {
- reg = <0 0x8e700000 0 0x800000>;
+ reg = <0 0x8f400000 0 0x800000>;
};
&pil_mba_mem {
- reg = <0 0x8ef00000 0 0x200000>;
+ reg = <0 0x8fc00000 0 0x200000>;
};
&pil_adsp_mem {
- reg = <0 0x8f100000 0 0x1e00000>;
+ reg = <0 0x8fe00000 0 0x1e00000>;
};
&pil_ipa_fw_mem {
- reg = <0 0x90f00000 0 0x10000>;
+ reg = <0 0x91c00000 0 0x10000>;
};
&pil_ipa_gsi_mem {
- reg = <0 0x90f10000 0 0x5000>;
+ reg = <0 0x91c10000 0 0x5000>;
};
&pil_gpu_mem {
- reg = <0 0x90f15000 0 0x2000>;
+ reg = <0 0x91c15000 0 0x2000>;
+};
+
+&qseecom_mem {
+ reg = <0 0x9e800000 0 0x1000000>;
};
&adsp_mem {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
index 73c7be2..15874ff 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
@@ -43,6 +43,7 @@
qcom,mi2s-audio-intf;
qcom,auxpcm-audio-intf;
qcom,ext-disp-audio-rx;
+ qcom,afe-rxtx-lb;
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
@@ -73,7 +74,8 @@
<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
<&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>,
- <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>;
+ <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>,
+ <&afe_loopback_tx>;
asoc-cpu-names = "msm-dai-q6-dp.24608",
"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
@@ -99,7 +101,8 @@
"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
"msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913",
- "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929";
+ "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929",
+ "msm-dai-q6-dev.24577";
};
tasha_snd: sound-tasha {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index 92d4317..aaa516b 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -139,7 +139,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -162,7 +162,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -186,7 +186,7 @@
qcom,dsi-phy = <&mdss_dsi_phy1>;
clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>,
<&mdss_dsi1_pll PCLK_MUX_1_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -210,7 +210,7 @@
qcom,dsi-phy = <&mdss_dsi_phy1>;
clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>,
<&mdss_dsi1_pll PCLK_MUX_1_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -234,7 +234,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -252,7 +252,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -270,7 +270,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -288,7 +288,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -306,7 +306,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -324,7 +324,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -342,7 +342,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -365,7 +365,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -388,7 +388,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -410,7 +410,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -432,7 +432,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -455,7 +455,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -478,7 +478,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -501,7 +501,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -524,7 +524,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
ports {
#address-cells = <1>;
@@ -621,11 +621,10 @@
&dsi_dual_nt35597_truly_video {
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
- qcom,mdss-dsi-min-refresh-rate = <53>;
- qcom,mdss-dsi-max-refresh-rate = <60>;
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
+ qcom,dsi-supported-dfps-list = <53 55 60>;
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
@@ -694,11 +693,10 @@
&dsi_nt35597_truly_dsc_video {
qcom,mdss-dsi-t-clk-post = <0x0b>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
- qcom,mdss-dsi-min-refresh-rate = <53>;
- qcom,mdss-dsi-max-refresh-rate = <60>;
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
+ qcom,dsi-supported-dfps-list = <53 55 60>;
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
@@ -935,11 +933,10 @@
&dsi_nt35695b_truly_fhd_video {
qcom,mdss-dsi-t-clk-post = <0x07>;
qcom,mdss-dsi-t-clk-pre = <0x1c>;
- qcom,mdss-dsi-min-refresh-rate = <48>;
- qcom,mdss-dsi-max-refresh-rate = <60>;
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
+ qcom,dsi-supported-dfps-list = <48 53 55 60>;
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c
@@ -990,11 +987,10 @@
&dsi_hx8399_truly_cmd {
qcom,mdss-dsi-t-clk-post = <0x0E>;
qcom,mdss-dsi-t-clk-pre = <0x30>;
- qcom,mdss-dsi-min-refresh-rate = <55>;
- qcom,mdss-dsi-max-refresh-rate = <60>;
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
+ qcom,dsi-supported-dfps-list = <55 60>;
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 0de0331..8c746e5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -116,7 +116,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -140,7 +140,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -164,7 +164,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -188,7 +188,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -212,7 +212,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -235,7 +235,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -259,7 +259,7 @@
qcom,dsi-phy = <&mdss_dsi_phy1>;
clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>,
<&mdss_dsi1_pll PCLK_MUX_1_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -283,7 +283,7 @@
qcom,dsi-phy = <&mdss_dsi_phy1>;
clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>,
<&mdss_dsi1_pll PCLK_MUX_1_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -307,7 +307,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -325,7 +325,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -343,7 +343,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -361,7 +361,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -379,7 +379,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -397,7 +397,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -415,7 +415,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -439,7 +439,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -463,7 +463,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -487,7 +487,7 @@
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
- clock-names = "src_byte_clk", "src_pixel_clk";
+ clock-names = "mux_byte_clk", "mux_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
pinctrl-0 = <&sde_dsi_active &sde_te_active>;
@@ -561,11 +561,10 @@
&dsi_dual_nt35597_truly_video {
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
- qcom,mdss-dsi-min-refresh-rate = <53>;
- qcom,mdss-dsi-max-refresh-rate = <60>;
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
+ qcom,dsi-supported-dfps-list = <53 55 60>;
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
@@ -634,11 +633,10 @@
&dsi_nt35597_truly_dsc_video {
qcom,mdss-dsi-t-clk-post = <0x0b>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
- qcom,mdss-dsi-min-refresh-rate = <53>;
- qcom,mdss-dsi-max-refresh-rate = <60>;
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
+ qcom,dsi-supported-dfps-list = <53 55 60>;
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index b54b566..b90bbfe 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -70,6 +70,7 @@
rc = PTR_ERR(vreg->reg);
pr_err("%s: regulator_get(%s) failed. rc=%d\n",
__func__, vreg->name, rc);
+ vreg->reg = NULL;
goto out;
}
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 0986c32..4c40fa2 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -231,11 +231,11 @@
BT_DBG("hu %p wq awake device", hu);
+ spin_lock(&qca->hci_ibs_lock);
+
/* Vote for serial clock */
serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
- spin_lock(&qca->hci_ibs_lock);
-
/* Send wake indication to device */
if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
BT_ERR("Failed to send WAKE to device");
@@ -260,9 +260,10 @@
BT_DBG("hu %p wq awake rx", hu);
+ spin_lock(&qca->hci_ibs_lock);
+
serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
- spin_lock(&qca->hci_ibs_lock);
qca->rx_ibs_state = HCI_IBS_RX_AWAKE;
/* Always acknowledge device wake up,
@@ -287,7 +288,11 @@
BT_DBG("hu %p rx clock vote off", hu);
+ spin_lock(&qca->hci_ibs_lock);
+
serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+
+ spin_unlock(&qca->hci_ibs_lock);
}
static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work)
@@ -298,6 +303,8 @@
BT_DBG("hu %p tx clock vote off", hu);
+ spin_lock(&qca->hci_ibs_lock);
+
/* Run HCI tx handling unlocked */
hci_uart_tx_wakeup(hu);
@@ -305,6 +312,8 @@
* It is up to the tty driver to pend the clocks off until tx done.
*/
serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
+
+ spin_unlock(&qca->hci_ibs_lock);
}
static void hci_ibs_tx_idle_timeout(unsigned long arg)
@@ -520,8 +529,12 @@
BT_DBG("hu %p qca close", hu);
+ spin_lock(&qca->hci_ibs_lock);
+
serial_clock_vote(HCI_IBS_VOTE_STATS_UPDATE, hu);
+ spin_unlock(&qca->hci_ibs_lock);
+
skb_queue_purge(&qca->tx_wait_q);
skb_queue_purge(&qca->txq);
del_timer(&qca->tx_idle_timer);
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 7b23db4..aa8dccc 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -95,6 +95,9 @@
#define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c
#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164
#define PLL_FASTLOCK_EN_BAND 0x16c
+#define PLL_FREQ_TUNE_ACCUM_INIT_LOW 0x170
+#define PLL_FREQ_TUNE_ACCUM_INIT_MID 0x174
+#define PLL_FREQ_TUNE_ACCUM_INIT_HIGH 0x178
#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c
#define PLL_PLL_LOCK_OVERRIDE 0x180
#define PLL_PLL_LOCK_DELAY 0x184
@@ -112,6 +115,7 @@
#define PHY_CMN_RBUF_CTRL 0x01c
#define PHY_CMN_PLL_CNTRL 0x038
#define PHY_CMN_CTRL_0 0x024
+#define PHY_CMN_CTRL_2 0x02c
/* Bit definition of SSC control registers */
#define SSC_CENTER BIT(0)
@@ -123,6 +127,43 @@
#define SSC_START BIT(6)
#define SSC_START_MUX BIT(7)
+/* Dynamic Refresh Control Registers */
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 (0x014)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 (0x018)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 (0x01C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 (0x020)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 (0x024)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 (0x028)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 (0x02C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 (0x030)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 (0x034)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 (0x038)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 (0x03C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 (0x040)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 (0x044)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 (0x048)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 (0x04C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 (0x050)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 (0x054)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 (0x058)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 (0x05C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 (0x060)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 (0x064)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 (0x068)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 (0x06C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 (0x070)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 (0x074)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 (0x078)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 (0x07C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 (0x080)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 (0x084)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 (0x088)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 (0x08C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 (0x090)
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR (0x094)
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 (0x098)
+
+#define DSI_PHY_TO_PLL_OFFSET (0x600)
enum {
DSI_PLL_0,
DSI_PLL_1,
@@ -644,6 +685,7 @@
rsc->vco_current_rate = rate;
rsc->vco_ref_clk_rate = vco->ref_clk_rate;
+ rsc->dfps_trigger = false;
rc = mdss_pll_resource_enable(rsc, true);
if (rc) {
@@ -674,6 +716,237 @@
return 0;
}
+static int dsi_pll_read_stored_trim_codes(struct mdss_pll_resources *pll_res,
+ unsigned long vco_clk_rate)
+{
+ int i;
+ bool found = false;
+
+ if (!pll_res->dfps)
+ return -EINVAL;
+
+ for (i = 0; i < pll_res->dfps->vco_rate_cnt; i++) {
+ struct dfps_codes_info *codes_info =
+ &pll_res->dfps->codes_dfps[i];
+
+ pr_debug("valid=%d vco_rate=%d, code %d %d %d\n",
+ codes_info->is_valid, codes_info->clk_rate,
+ codes_info->pll_codes.pll_codes_1,
+ codes_info->pll_codes.pll_codes_2,
+ codes_info->pll_codes.pll_codes_3);
+
+ if (vco_clk_rate != codes_info->clk_rate &&
+ codes_info->is_valid)
+ continue;
+
+ pll_res->cache_pll_trim_codes[0] =
+ codes_info->pll_codes.pll_codes_1;
+ pll_res->cache_pll_trim_codes[1] =
+ codes_info->pll_codes.pll_codes_2;
+ pll_res->cache_pll_trim_codes[2] =
+ codes_info->pll_codes.pll_codes_3;
+ found = true;
+ break;
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ pr_debug("trim_code_0=0x%x trim_code_1=0x%x trim_code_2=0x%x\n",
+ pll_res->cache_pll_trim_codes[0],
+ pll_res->cache_pll_trim_codes[1],
+ pll_res->cache_pll_trim_codes[2]);
+
+ return 0;
+}
+
+static void shadow_dsi_pll_dynamic_refresh_10nm(struct dsi_pll_10nm *pll,
+ struct mdss_pll_resources *rsc)
+{
+ u32 data;
+ u32 offset = DSI_PHY_TO_PLL_OFFSET;
+ u32 upper_addr = 0;
+ struct dsi_pll_regs *reg = &pll->reg_setup;
+
+ data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+ data &= ~BIT(5);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL0,
+ PHY_CMN_CLK_CFG1, PHY_CMN_PLL_CNTRL, data, 0);
+ upper_addr |= (upper_8_bit(PHY_CMN_CLK_CFG1) << 0);
+ upper_addr |= (upper_8_bit(PHY_CMN_PLL_CNTRL) << 1);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL1,
+ PHY_CMN_RBUF_CTRL,
+ (PLL_DECIMAL_DIV_START_1 + offset),
+ 0, reg->decimal_div_start);
+ upper_addr |= (upper_8_bit(PHY_CMN_RBUF_CTRL) << 2);
+ upper_addr |= (upper_8_bit(PLL_DECIMAL_DIV_START_1 + offset) << 3);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL2,
+ (PLL_FRAC_DIV_START_LOW_1 + offset),
+ (PLL_FRAC_DIV_START_MID_1 + offset),
+ reg->frac_div_start_low, reg->frac_div_start_mid);
+ upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_LOW_1 + offset) << 4);
+ upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_MID_1 + offset) << 5);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL3,
+ (PLL_FRAC_DIV_START_HIGH_1 + offset),
+ (PLL_PLL_PROP_GAIN_RATE_1 + offset),
+ reg->frac_div_start_high, reg->pll_prop_gain_rate);
+ upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_HIGH_1 + offset) << 6);
+ upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 7);
+
+ data = MDSS_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE) & 0x03;
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL4,
+ (PLL_PLL_OUTDIV_RATE + offset),
+ (PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset),
+ data, 0);
+ upper_addr |= (upper_8_bit(PLL_PLL_OUTDIV_RATE + offset) << 8);
+ upper_addr |= (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset) << 9);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL5,
+ (PLL_FREQ_TUNE_ACCUM_INIT_MID + offset),
+ (PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset),
+ rsc->cache_pll_trim_codes[1],
+ rsc->cache_pll_trim_codes[0]);
+ upper_addr |=
+ (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MID + offset) << 10);
+ upper_addr |=
+ (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset) << 11);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL6,
+ (PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset),
+ (PLL_PLL_BAND_SET_RATE_1 + offset),
+ 0x07, rsc->cache_pll_trim_codes[2]);
+ upper_addr |=
+ (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset) << 12);
+ upper_addr |= (upper_8_bit(PLL_PLL_BAND_SET_RATE_1 + offset) << 13);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL7,
+ (PLL_CALIBRATION_SETTINGS + offset),
+ (PLL_BAND_SEL_CAL_SETTINGS + offset), 0x44, 0x3a);
+ upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 14);
+ upper_addr |= (upper_8_bit(PLL_BAND_SEL_CAL_SETTINGS + offset) << 15);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL8,
+ (PLL_PLL_LOCKDET_RATE_1 + offset),
+ (PLL_PLL_LOCK_DELAY + offset), 0x10, 0x06);
+ upper_addr |= (upper_8_bit(PLL_PLL_LOCKDET_RATE_1 + offset) << 16);
+ upper_addr |= (upper_8_bit(PLL_PLL_LOCK_DELAY + offset) << 17);
+
+ data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL17,
+ PHY_CMN_CTRL_2, PHY_CMN_CLK_CFG0, 0x40, data);
+ if (rsc->slave)
+ MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base,
+ DSI_DYNAMIC_REFRESH_PLL_CTRL10,
+ PHY_CMN_CLK_CFG0, PHY_CMN_CTRL_0,
+ data, 0x7f);
+
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL18,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ /* Dummy register writes */
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL19,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL20,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL21,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL22,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL23,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL24,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL25,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL26,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL27,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL28,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL29,
+ PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+
+ /* Registers to configure after PLL enable delay */
+ data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1) | BIT(5);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL30,
+ PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, data, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL31,
+ PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, data, data);
+ if (rsc->slave) {
+ data = MDSS_PLL_REG_R(rsc->slave->phy_base, PHY_CMN_CLK_CFG1) |
+ BIT(5);
+ MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base,
+ DSI_DYNAMIC_REFRESH_PLL_CTRL30,
+ PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL,
+ data, 0x01);
+ MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base,
+ DSI_DYNAMIC_REFRESH_PLL_CTRL31,
+ PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1,
+ data, data);
+ }
+
+ MDSS_PLL_REG_W(rsc->dyn_pll_base,
+ DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, upper_addr);
+ MDSS_PLL_REG_W(rsc->dyn_pll_base,
+ DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0);
+ wmb(); /* commit register writes */
+}
+
+static int shadow_vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int rc;
+ struct dsi_pll_10nm *pll;
+ struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw);
+ struct mdss_pll_resources *rsc = vco->priv;
+
+ if (!rsc) {
+ pr_err("pll resource not found\n");
+ return -EINVAL;
+ }
+
+ pll = rsc->priv;
+ if (!pll) {
+ pr_err("pll configuration not found\n");
+ return -EINVAL;
+ }
+
+ rc = dsi_pll_read_stored_trim_codes(rsc, rate);
+ if (rc) {
+ pr_err("cannot find pll codes rate=%ld\n", rate);
+ return -EINVAL;
+ }
+ pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate);
+
+ rsc->vco_current_rate = rate;
+ rsc->vco_ref_clk_rate = vco->ref_clk_rate;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("failed to enable mdss dsi pll(%d), rc=%d\n",
+ rsc->index, rc);
+ return rc;
+ }
+
+ dsi_pll_setup_config(pll, rsc);
+
+ dsi_pll_calc_dec_frac(pll, rsc);
+
+ /* program dynamic refresh control registers */
+ shadow_dsi_pll_dynamic_refresh_10nm(pll, rsc);
+
+ /* update cached vco rate */
+ rsc->vco_cached_rate = rate;
+ rsc->dfps_trigger = true;
+
+ mdss_pll_resource_enable(rsc, false);
+
+ return 0;
+}
+
static int dsi_pll_10nm_lock_status(struct mdss_pll_resources *pll)
{
int rc;
@@ -739,7 +1012,7 @@
phy_reg_update_bits_sub(rsc, PHY_CMN_CLK_CFG1, 0x03, rsc->cached_cfg1);
if (rsc->slave)
phy_reg_update_bits_sub(rsc->slave, PHY_CMN_CLK_CFG1,
- 0x03, rsc->cached_cfg1);
+ 0x03, rsc->slave->cached_cfg1);
wmb(); /* ensure dsiclk_sel is always programmed before pll start */
/* Start PLL */
@@ -789,6 +1062,7 @@
}
rsc->handoff_resources = false;
+ rsc->dfps_trigger = false;
pr_debug("stop PLL (%d)\n", rsc->index);
@@ -840,16 +1114,18 @@
/*
* During unprepare in continuous splash use case we want driver
* to pick all dividers instead of retaining bootloader configurations.
+ * Also handle use cases where dynamic refresh triggered before
+ * first suspend/resume.
*/
- if (!pll->handoff_resources) {
+ if (!pll->handoff_resources || pll->dfps_trigger) {
pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base,
- PHY_CMN_CLK_CFG0);
+ PHY_CMN_CLK_CFG0);
pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base,
- PLL_PLL_OUTDIV_RATE);
+ PLL_PLL_OUTDIV_RATE);
pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0,
- pll->cached_cfg1, pll->cached_outdiv);
+ pll->cached_cfg1, pll->cached_outdiv);
- pll->vco_cached_rate = clk_hw_get_rate(hw);
+ pll->vco_cached_rate = clk_get_rate(hw->clk);
}
/*
@@ -859,9 +1135,15 @@
* does not change.For such usecases, we need to ensure that the cached
* value is programmed prior to PLL being locked
*/
- if (pll->handoff_resources)
+ if (pll->handoff_resources) {
pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base,
- PHY_CMN_CLK_CFG1);
+ PHY_CMN_CLK_CFG1);
+ if (pll->slave)
+ pll->slave->cached_cfg1 =
+ MDSS_PLL_REG_R(pll->slave->phy_base,
+ PHY_CMN_CLK_CFG1);
+ }
+
dsi_pll_disable(vco);
mdss_pll_resource_enable(pll, false);
}
@@ -889,7 +1171,7 @@
}
if ((pll->vco_cached_rate != 0) &&
- (pll->vco_cached_rate == clk_hw_get_rate(hw))) {
+ (pll->vco_cached_rate == clk_get_rate(hw->clk))) {
rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate,
pll->vco_cached_rate);
if (rc) {
@@ -902,6 +1184,9 @@
pll->cached_cfg1);
MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0,
pll->cached_cfg0);
+ if (pll->slave)
+ MDSS_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0,
+ pll->cached_cfg0);
MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE,
pll->cached_outdiv);
}
@@ -1037,6 +1322,14 @@
reg_val &= ~0xF0;
reg_val |= (div << 4);
MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val);
+
+ /*
+ * cache the current parent index for cases where parent
+ * is not changing but rate is changing. In that case
+ * clock framework won't call parent_set and hence dsiclk_sel
+ * bit won't be programmed. e.g. dfps update use case.
+ */
+ pll->cached_cfg0 = reg_val;
}
static int pixel_clk_set_div(void *context, unsigned int reg, unsigned int div)
@@ -1174,6 +1467,12 @@
.unprepare = vco_10nm_unprepare,
};
+static const struct clk_ops clk_ops_shadow_vco_10nm = {
+ .recalc_rate = vco_10nm_recalc_rate,
+ .set_rate = shadow_vco_10nm_set_rate,
+ .round_rate = vco_10nm_round_rate,
+};
+
static struct regmap_bus mdss_mux_regmap_bus = {
.reg_write = mdss_set_mux_sel,
.reg_read = mdss_get_mux_sel,
@@ -1248,6 +1547,19 @@
},
};
+static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = {
+ .ref_clk_rate = 19200000UL,
+ .min_rate = 1000000000UL,
+ .max_rate = 3500000000UL,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_vco_clk",
+ .parent_names = (const char *[]){"bi_tcxo"},
+ .num_parents = 1,
+ .ops = &clk_ops_shadow_vco_10nm,
+ .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
.ref_clk_rate = 19200000UL,
.min_rate = 1000000000UL,
@@ -1261,6 +1573,19 @@
},
};
+static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = {
+ .ref_clk_rate = 19200000UL,
+ .min_rate = 1000000000UL,
+ .max_rate = 3500000000UL,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_vco_clk",
+ .parent_names = (const char *[]){"bi_tcxo"},
+ .num_parents = 1,
+ .ops = &clk_ops_shadow_vco_10nm,
+ .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
static struct clk_regmap_div dsi0pll_pll_out_div = {
.reg = PLL_PLL_OUTDIV_RATE,
.shift = 0,
@@ -1277,6 +1602,23 @@
},
};
+static struct clk_regmap_div dsi0pll_shadow_pll_out_div = {
+ .reg = PLL_PLL_OUTDIV_RATE,
+ .shift = 0,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_pll_out_div",
+ .parent_names = (const char *[]){
+ "dsi0pll_shadow_vco_clk"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_regmap_div dsi1pll_pll_out_div = {
.reg = PLL_PLL_OUTDIV_RATE,
.shift = 0,
@@ -1293,6 +1635,23 @@
},
};
+static struct clk_regmap_div dsi1pll_shadow_pll_out_div = {
+ .reg = PLL_PLL_OUTDIV_RATE,
+ .shift = 0,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_pll_out_div",
+ .parent_names = (const char *[]){
+ "dsi1pll_shadow_vco_clk"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_regmap_div dsi0pll_bitclk_src = {
.shift = 0,
.width = 4,
@@ -1307,6 +1666,21 @@
},
};
+static struct clk_regmap_div dsi0pll_shadow_bitclk_src = {
+ .shift = 0,
+ .width = 4,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_bitclk_src",
+ .parent_names = (const char *[]){
+ "dsi0pll_shadow_pll_out_div"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_regmap_div dsi1pll_bitclk_src = {
.shift = 0,
.width = 4,
@@ -1321,6 +1695,21 @@
},
};
+static struct clk_regmap_div dsi1pll_shadow_bitclk_src = {
+ .shift = 0,
+ .width = 4,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_bitclk_src",
+ .parent_names = (const char *[]){
+ "dsi1pll_shadow_pll_out_div"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_fixed_factor dsi0pll_post_vco_div = {
.div = 4,
.mult = 1,
@@ -1328,7 +1717,19 @@
.name = "dsi0pll_post_vco_div",
.parent_names = (const char *[]){"dsi0pll_pll_out_div"},
.num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi0pll_shadow_post_vco_div = {
+ .div = 4,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_post_vco_div",
+ .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_fixed_factor_ops,
},
};
@@ -1340,7 +1741,19 @@
.name = "dsi1pll_post_vco_div",
.parent_names = (const char *[]){"dsi1pll_pll_out_div"},
.num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi1pll_shadow_post_vco_div = {
+ .div = 4,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_post_vco_div",
+ .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_fixed_factor_ops,
},
};
@@ -1357,6 +1770,18 @@
},
};
+static struct clk_fixed_factor dsi0pll_shadow_byteclk_src = {
+ .div = 8,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_byteclk_src",
+ .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
static struct clk_fixed_factor dsi1pll_byteclk_src = {
.div = 8,
.mult = 1,
@@ -1369,6 +1794,18 @@
},
};
+static struct clk_fixed_factor dsi1pll_shadow_byteclk_src = {
+ .div = 8,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_byteclk_src",
+ .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
static struct clk_fixed_factor dsi0pll_post_bit_div = {
.div = 2,
.mult = 1,
@@ -1381,6 +1818,18 @@
},
};
+static struct clk_fixed_factor dsi0pll_shadow_post_bit_div = {
+ .div = 2,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_post_bit_div",
+ .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
static struct clk_fixed_factor dsi1pll_post_bit_div = {
.div = 2,
.mult = 1,
@@ -1393,15 +1842,29 @@
},
};
+static struct clk_fixed_factor dsi1pll_shadow_post_bit_div = {
+ .div = 2,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_post_bit_div",
+ .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
static struct clk_regmap_mux dsi0pll_byteclk_mux = {
.shift = 0,
.width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0_phy_pll_out_byteclk",
- .parent_names = (const char *[]){"dsi0pll_byteclk_src"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi0pll_byteclk_src",
+ "dsi0pll_shadow_byteclk_src"},
+ .num_parents = 2,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT),
.ops = &clk_regmap_mux_closest_ops,
},
},
@@ -1413,9 +1876,11 @@
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1_phy_pll_out_byteclk",
- .parent_names = (const char *[]){"dsi1pll_byteclk_src"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi1pll_byteclk_src",
+ "dsi1pll_shadow_byteclk_src"},
+ .num_parents = 2,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT),
.ops = &clk_regmap_mux_closest_ops,
},
},
@@ -1439,6 +1904,25 @@
},
};
+static struct clk_regmap_mux dsi0pll_shadow_pclk_src_mux = {
+ .reg = PHY_CMN_CLK_CFG1,
+ .shift = 0,
+ .width = 2,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_pclk_src_mux",
+ .parent_names = (const char *[]){
+ "dsi0pll_shadow_bitclk_src",
+ "dsi0pll_shadow_post_bit_div",
+ "dsi0pll_shadow_pll_out_div",
+ "dsi0pll_shadow_post_vco_div"},
+ .num_parents = 4,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
.reg = PHY_CMN_CLK_CFG1,
.shift = 0,
@@ -1457,6 +1941,25 @@
},
};
+static struct clk_regmap_mux dsi1pll_shadow_pclk_src_mux = {
+ .reg = PHY_CMN_CLK_CFG1,
+ .shift = 0,
+ .width = 2,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_pclk_src_mux",
+ .parent_names = (const char *[]){
+ "dsi1pll_shadow_bitclk_src",
+ "dsi1pll_shadow_post_bit_div",
+ "dsi1pll_shadow_pll_out_div",
+ "dsi1pll_shadow_post_vco_div"},
+ .num_parents = 4,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
static struct clk_regmap_div dsi0pll_pclk_src = {
.shift = 0,
.width = 4,
@@ -1472,6 +1975,21 @@
},
};
+static struct clk_regmap_div dsi0pll_shadow_pclk_src = {
+ .shift = 0,
+ .width = 4,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_pclk_src",
+ .parent_names = (const char *[]){
+ "dsi0pll_shadow_pclk_src_mux"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_regmap_div dsi1pll_pclk_src = {
.shift = 0,
.width = 4,
@@ -1487,15 +2005,32 @@
},
};
+static struct clk_regmap_div dsi1pll_shadow_pclk_src = {
+ .shift = 0,
+ .width = 4,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_pclk_src",
+ .parent_names = (const char *[]){
+ "dsi1pll_shadow_pclk_src_mux"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_regmap_mux dsi0pll_pclk_mux = {
.shift = 0,
.width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0_phy_pll_out_dsiclk",
- .parent_names = (const char *[]){"dsi0pll_pclk_src"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi0pll_pclk_src",
+ "dsi0pll_shadow_pclk_src"},
+ .num_parents = 2,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT),
.ops = &clk_regmap_mux_closest_ops,
},
},
@@ -1507,9 +2042,11 @@
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1_phy_pll_out_dsiclk",
- .parent_names = (const char *[]){"dsi1pll_pclk_src"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi1pll_pclk_src",
+ "dsi1pll_shadow_pclk_src"},
+ .num_parents = 2,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT),
.ops = &clk_regmap_mux_closest_ops,
},
},
@@ -1526,6 +2063,14 @@
[PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw,
[PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw,
[PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw,
+ [SHADOW_VCO_CLK_0] = &dsi0pll_shadow_vco_clk.hw,
+ [SHADOW_PLL_OUT_DIV_0_CLK] = &dsi0pll_shadow_pll_out_div.clkr.hw,
+ [SHADOW_BITCLK_SRC_0_CLK] = &dsi0pll_shadow_bitclk_src.clkr.hw,
+ [SHADOW_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_byteclk_src.hw,
+ [SHADOW_POST_BIT_DIV_0_CLK] = &dsi0pll_shadow_post_bit_div.hw,
+ [SHADOW_POST_VCO_DIV_0_CLK] = &dsi0pll_shadow_post_vco_div.hw,
+ [SHADOW_PCLK_SRC_MUX_0_CLK] = &dsi0pll_shadow_pclk_src_mux.clkr.hw,
+ [SHADOW_PCLK_SRC_0_CLK] = &dsi0pll_shadow_pclk_src.clkr.hw,
[VCO_CLK_1] = &dsi1pll_vco_clk.hw,
[PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw,
[BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw,
@@ -1536,6 +2081,14 @@
[PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw,
[PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw,
[PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw,
+ [SHADOW_VCO_CLK_1] = &dsi1pll_shadow_vco_clk.hw,
+ [SHADOW_PLL_OUT_DIV_1_CLK] = &dsi1pll_shadow_pll_out_div.clkr.hw,
+ [SHADOW_BITCLK_SRC_1_CLK] = &dsi1pll_shadow_bitclk_src.clkr.hw,
+ [SHADOW_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_byteclk_src.hw,
+ [SHADOW_POST_BIT_DIV_1_CLK] = &dsi1pll_shadow_post_bit_div.hw,
+ [SHADOW_POST_VCO_DIV_1_CLK] = &dsi1pll_shadow_post_vco_div.hw,
+ [SHADOW_PCLK_SRC_MUX_1_CLK] = &dsi1pll_shadow_pclk_src_mux.clkr.hw,
+ [SHADOW_PCLK_SRC_1_CLK] = &dsi1pll_shadow_pclk_src.clkr.hw,
};
int dsi_pll_clock_register_10nm(struct platform_device *pdev,
@@ -1580,18 +2133,20 @@
/* Establish client data */
if (ndx == 0) {
-
rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_pll_out_div.clkr.regmap = rmap;
+ dsi0pll_shadow_pll_out_div.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_bitclk_src.clkr.regmap = rmap;
+ dsi0pll_shadow_bitclk_src.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_pclk_src.clkr.regmap = rmap;
+ dsi0pll_shadow_pclk_src.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
@@ -1600,12 +2155,16 @@
rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_pclk_src_mux.clkr.regmap = rmap;
+ dsi0pll_shadow_pclk_src_mux.clkr.regmap = rmap;
+
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_byteclk_mux.clkr.regmap = rmap;
dsi0pll_vco_clk.priv = pll_res;
- for (i = VCO_CLK_0; i <= PCLK_MUX_0_CLK; i++) {
+ dsi0pll_shadow_vco_clk.priv = pll_res;
+
+ for (i = VCO_CLK_0; i <= SHADOW_PCLK_SRC_0_CLK; i++) {
clk = devm_clk_register(&pdev->dev,
mdss_dsi_pllcc_10nm[i]);
if (IS_ERR(clk)) {
@@ -1620,20 +2179,21 @@
rc = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, clk_data);
-
-
} else {
rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pll_out_div.clkr.regmap = rmap;
+ dsi1pll_shadow_pll_out_div.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_bitclk_src.clkr.regmap = rmap;
+ dsi1pll_shadow_bitclk_src.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_src.clkr.regmap = rmap;
+ dsi1pll_shadow_pclk_src.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
@@ -1642,12 +2202,16 @@
rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_src_mux.clkr.regmap = rmap;
+ dsi1pll_shadow_pclk_src_mux.clkr.regmap = rmap;
+
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_byteclk_mux.clkr.regmap = rmap;
- dsi1pll_vco_clk.priv = pll_res;
- for (i = VCO_CLK_1; i <= PCLK_MUX_1_CLK; i++) {
+ dsi1pll_vco_clk.priv = pll_res;
+ dsi1pll_shadow_vco_clk.priv = pll_res;
+
+ for (i = VCO_CLK_1; i <= SHADOW_PCLK_SRC_1_CLK; i++) {
clk = devm_clk_register(&pdev->dev,
mdss_dsi_pllcc_10nm[i]);
if (IS_ERR(clk)) {
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 2f92270..e4b5184 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -35,6 +35,8 @@
writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \
(base) + (offset))
+#define upper_8_bit(x) ((((x) >> 2) & 0x100) >> 8)
+
enum {
MDSS_DSI_PLL_10NM,
MDSS_DP_PLL_10NM,
@@ -45,30 +47,23 @@
MDSS_PLL_TARGET_8996,
};
-#define DFPS_MAX_NUM_OF_FRAME_RATES 20
-
-struct dfps_panel_info {
- uint32_t enabled;
- uint32_t frame_rate_cnt;
- uint32_t frame_rate[DFPS_MAX_NUM_OF_FRAME_RATES]; /* hz */
-};
+#define DFPS_MAX_NUM_OF_FRAME_RATES 16
struct dfps_pll_codes {
uint32_t pll_codes_1;
uint32_t pll_codes_2;
+ uint32_t pll_codes_3;
};
struct dfps_codes_info {
uint32_t is_valid;
- uint32_t frame_rate; /* hz */
uint32_t clk_rate; /* hz */
struct dfps_pll_codes pll_codes;
};
struct dfps_info {
- struct dfps_panel_info panel_dfps;
+ uint32_t vco_rate_cnt;
struct dfps_codes_info codes_dfps[DFPS_MAX_NUM_OF_FRAME_RATES];
- void *dfps_fb_base;
};
struct mdss_pll_resources {
@@ -139,7 +134,7 @@
/*
* caching the pll trim codes in the case of dynamic refresh
*/
- int cache_pll_trim_codes[2];
+ int cache_pll_trim_codes[3];
/*
* for maintaining the status of saving trim codes
@@ -181,6 +176,11 @@
*/
struct dfps_info *dfps;
+ /*
+ * for cases where dfps trigger happens before first
+ * suspend/resume and handoff is not finished.
+ */
+ bool dfps_trigger;
};
struct mdss_pll_vco_calc {
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 6e16d9f..8f9c8b6 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2316,6 +2316,11 @@
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_ADJUST, new_policy);
+ /* adjust if necessary - hardware incompatibility */
+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+ CPUFREQ_INCOMPATIBLE, new_policy);
+
+
/*
* verify the cpu speed can be set within this limit, which might be
* different to the first one
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index c8d1158..d58144f 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1239,8 +1239,7 @@
goto exit;
}
- k_align_dst += creq->vbuf.dst[dst_i].len +
- byteoffset;
+ k_align_dst += creq->vbuf.dst[dst_i].len;
creq->data_len -= creq->vbuf.dst[dst_i].len;
dst_i++;
} else {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 011e3b8..efb36bf 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -70,6 +70,8 @@
ctrl->ops.wait_for_cmd_mode_mdp_idle =
dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle;
ctrl->ops.set_continuous_clk = dsi_ctrl_hw_cmn_set_continuous_clk;
+ ctrl->ops.wait4dynamic_refresh_done =
+ dsi_ctrl_hw_cmn_wait4dynamic_refresh_done;
switch (version) {
case DSI_CTRL_VERSION_1_4:
@@ -218,6 +220,14 @@
phy->ops.clamp_ctrl = dsi_phy_hw_v3_0_clamp_ctrl;
phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset;
phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo;
+ phy->ops.dyn_refresh_ops.dyn_refresh_config =
+ dsi_phy_hw_v3_0_dyn_refresh_config;
+ phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
+ dsi_phy_hw_v3_0_dyn_refresh_pipe_delay;
+ phy->ops.dyn_refresh_ops.dyn_refresh_helper =
+ dsi_phy_hw_v3_0_dyn_refresh_helper;
+ phy->ops.dyn_refresh_ops.cache_phy_timings =
+ dsi_phy_hw_v3_0_cache_phy_timings;
}
/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index c55bbe0..944dd52 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -66,15 +66,17 @@
* @mode: DSI mode information.
* @host: DSI host configuration.
* @timing: DSI phy lane configurations.
+ * @use_mode_bit_clk: Boolean to indicate whether to recalculate bit clk.
*
* This function setups the catalog information in the dsi_phy_hw object.
*
* return: error code for failure and 0 for success.
*/
int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy,
- struct dsi_mode_info *mode,
- struct dsi_host_common_cfg *host,
- struct dsi_phy_per_lane_cfgs *timing);
+ struct dsi_mode_info *mode,
+ struct dsi_host_common_cfg *host,
+ struct dsi_phy_per_lane_cfgs *timing,
+ bool use_mode_bit_clk);
/* Definitions for 14nm PHY hardware driver */
void dsi_phy_hw_v2_0_regulator_enable(struct dsi_phy_hw *phy,
@@ -226,4 +228,14 @@
void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable);
+/* dynamic refresh specific functions */
+void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
+void dsi_phy_hw_v3_0_dyn_refresh_config(struct dsi_phy_hw *phy,
+ struct dsi_phy_cfg *cfg, bool is_master);
+void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
+ struct dsi_dyn_clk_delay *delay);
+
+int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl);
+int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
+ u32 *dst, u32 size);
#endif /* _DSI_CATALOG_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index bdc60d2..cdcb331 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -317,4 +317,18 @@
*/
int dsi_clk_update_parent(struct dsi_clk_link_set *parent,
struct dsi_clk_link_set *child);
+
+/**
+ * dsi_clk_prepare_enable() - prepare and enable dsi src clocks
+ * @clk: list of src clocks.
+ *
+ * @return: Zero on success and err no on failure
+ */
+int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk);
+
+/**
+ * dsi_clk_disable_unprepare() - disable and unprepare dsi src clocks
+ * @clk: list of src clocks.
+ */
+void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk);
#endif /* _DSI_CLK_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index fdaf283..9592603f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -113,8 +113,9 @@
/**
* dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
- * @clks: DSI link clock information.
- * @pixel_clk: Pixel clock rate in KHz.
+ * @clks: DSI link clock information.
+ * @pixel_clk: Pixel clock rate in KHz.
+ * @index: Index of the DSI controller.
*
* return: error code in case of failure or 0 for success.
*/
@@ -136,9 +137,9 @@
/**
* dsi_clk_set_byte_clk_rate() - set frequency for byte clock
- * @client: DSI clock client pointer.
- * @byte_clk: Pixel clock rate in Hz.
- * @index: Index of the DSI controller.
+ * @client: DSI clock client pointer.
+ * @byte_clk: Byte clock rate in Hz.
+ * @index: Index of the DSI controller.
* return: error code in case of failure or 0 for success.
*/
int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
@@ -146,6 +147,7 @@
int rc = 0;
struct dsi_clk_client_info *c = client;
struct dsi_clk_mngr *mngr;
+ u64 byte_intf_rate;
mngr = c->mngr;
rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
@@ -154,8 +156,16 @@
else
mngr->link_clks[index].freq.byte_clk_rate = byte_clk;
- return rc;
+ if (mngr->link_clks[index].hs_clks.byte_intf_clk) {
+ byte_intf_rate = mngr->link_clks[index].freq.byte_clk_rate / 2;
+ rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_intf_clk,
+ byte_intf_rate);
+ if (rc)
+ pr_err("failed to set clk rate for byte intf clk=%d\n",
+ rc);
+ }
+ return rc;
}
/**
@@ -183,6 +193,41 @@
return rc;
}
+/**
+ * dsi_clk_prepare_enable() - prepare and enable dsi src clocks
+ * @clk: list of src clocks.
+ *
+ * @return: Zero on success and err no on failure.
+ */
+int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk)
+{
+ int rc;
+
+ rc = clk_prepare_enable(clk->byte_clk);
+ if (rc) {
+ pr_err("failed to enable byte src clk %d\n", rc);
+ return rc;
+ }
+
+ rc = clk_prepare_enable(clk->pixel_clk);
+ if (rc) {
+ pr_err("failed to enable pixel src clk %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * dsi_clk_disable_unprepare() - disable and unprepare dsi src clocks
+ * @clk: list of src clocks.
+ */
+void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk)
+{
+ clk_disable_unprepare(clk->pixel_clk);
+ clk_disable_unprepare(clk->byte_clk);
+}
+
int dsi_core_clk_start(struct dsi_core_clks *c_clks)
{
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 31c3b1a..378ef4c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -2736,7 +2736,12 @@
goto error;
}
- if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR))) {
+ if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR |
+ DSI_MODE_FLAG_DYN_CLK))) {
+ /*
+ * for dynamic clk swith case link frequence would
+ * be updated dsi_display_dynamic_clk_switch().
+ */
rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle);
if (rc) {
pr_err("[%s] failed to update link frequencies, rc=%d\n",
@@ -3455,6 +3460,27 @@
}
/**
+ * dsi_ctrl_wait4dynamic_refresh_done() - Poll for dynamci refresh
+ * done interrupt.
+ * @dsi_ctrl: DSI controller handle.
+ */
+int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl)
+{
+ int rc = 0;
+
+ if (!ctrl)
+ return 0;
+
+ mutex_lock(&ctrl->ctrl_lock);
+
+ if (ctrl->hw.ops.wait4dynamic_refresh_done)
+ rc = ctrl->hw.ops.wait4dynamic_refresh_done(&ctrl->hw);
+
+ mutex_unlock(&ctrl->ctrl_lock);
+ return rc;
+}
+
+/**
* dsi_ctrl_drv_register() - register platform driver for dsi controller
*/
void dsi_ctrl_drv_register(void)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index 61c6116..47009bf 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -783,4 +783,11 @@
* @enable: variable to control continuous clock.
*/
void dsi_ctrl_set_continuous_clk(struct dsi_ctrl *dsi_ctrl, bool enable);
+
+/**
+ * dsi_ctrl_wait4dynamic_refresh_done() - Poll for dynamic refresh done
+ * interrupt.
+ * @dsi_ctrl: DSI controller handle.
+ */
+int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl);
#endif /* _DSI_CTRL_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 348ef36..f34cb10 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -810,6 +810,12 @@
* @enable: Bool to control continuous clock request.
*/
void (*set_continuous_clk)(struct dsi_ctrl_hw *ctrl, bool enable);
+
+ /**
+ * hw.ops.wait4dynamic_refresh_done() - Wait for dynamic refresh done
+ * @ctrl: Pointer to the controller host hardware.
+ */
+ int (*wait4dynamic_refresh_done)(struct dsi_ctrl_hw *ctrl);
};
/*
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 7c58c43..7139a51 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -1443,6 +1443,13 @@
reg &= ~(0x7 << 23);
}
+ if (idx & BIT(DSI_PLL_UNLOCK_ERR)) {
+ if (en)
+ reg |= BIT(28);
+ else
+ reg &= ~BIT(28);
+ }
+
DSI_W32(ctrl, 0x10c, reg);
wmb(); /* ensure error is masked */
}
@@ -1509,3 +1516,25 @@
DSI_W32(ctrl, DSI_LANE_CTRL, reg);
wmb(); /* make sure request is set */
}
+
+int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl)
+{
+ int rc;
+ u32 const sleep_us = 1000;
+ u32 const timeout_us = 84000; /* approximately 5 vsyncs */
+ u32 reg = 0, dyn_refresh_done = BIT(28);
+
+ rc = readl_poll_timeout(ctrl->base + DSI_INT_CTRL, reg,
+ (reg & dyn_refresh_done), sleep_us, timeout_us);
+ if (rc) {
+ pr_err("wait4dynamic refresh timedout %d\n", rc);
+ return rc;
+ }
+
+ /* ack dynamic refresh done status */
+ reg = DSI_R32(ctrl, DSI_INT_CTRL);
+ reg |= dyn_refresh_done;
+ DSI_W32(ctrl, DSI_INT_CTRL, reg);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
index 39ac021..0ee8b39 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -138,44 +138,7 @@
#define DSI_SCRATCH_REGISTER_1 (0x01F8)
#define DSI_SCRATCH_REGISTER_2 (0x01FC)
#define DSI_DYNAMIC_REFRESH_CTRL (0x0200)
-#define DSI_DYNAMIC_REFRESH_PIPE_DELAY (0x0204)
-#define DSI_DYNAMIC_REFRESH_PIPE_DELAY2 (0x0208)
-#define DSI_DYNAMIC_REFRESH_PLL_DELAY (0x020C)
#define DSI_DYNAMIC_REFRESH_STATUS (0x0210)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 (0x0214)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 (0x0218)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 (0x021C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 (0x0220)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 (0x0224)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 (0x0228)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 (0x022C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 (0x0230)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 (0x0234)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 (0x0238)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 (0x023C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 (0x0240)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 (0x0244)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 (0x0248)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 (0x024C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 (0x0250)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 (0x0254)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 (0x0258)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 (0x025C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 (0x0260)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 (0x0264)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 (0x0268)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 (0x026C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 (0x0270)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 (0x0274)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 (0x0278)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 (0x027C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 (0x0280)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 (0x0284)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 (0x0288)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 (0x028C)
-#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 (0x0290)
-#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR (0x0294)
-#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 (0x0298)
#define DSI_VIDEO_COMPRESSION_MODE_CTRL (0x02A0)
#define DSI_VIDEO_COMPRESSION_MODE_CTRL2 (0x02A4)
#define DSI_COMMAND_COMPRESSION_MODE_CTRL (0x02A8)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
index 3b2ef70..a6ada73 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
@@ -79,6 +79,7 @@
* @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch
* @DSI_MODE_FLAG_VRR: Seamless transition is DynamicFPS.
* New timing values are sent from DAL.
+ * @DSI_MODE_FLAG_DYN_CLK: Seamless transition is dynamic clock change
*/
enum dsi_mode_flags {
DSI_MODE_FLAG_SEAMLESS = BIT(0),
@@ -86,6 +87,7 @@
DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2),
DSI_MODE_FLAG_DMS = BIT(3),
DSI_MODE_FLAG_VRR = BIT(4),
+ DSI_MODE_FLAG_DYN_CLK = BIT(5),
};
/**
@@ -595,12 +597,50 @@
* @DSI_FIFO_OVERFLOW: DSI FIFO Overflow error
* @DSI_FIFO_UNDERFLOW: DSI FIFO Underflow error
* @DSI_LP_Rx_TIMEOUT: DSI LP/RX Timeout error
+ * @DSI_PLL_UNLOCK_ERR: DSI PLL unlock error
*/
enum dsi_error_status {
DSI_FIFO_OVERFLOW = 1,
DSI_FIFO_UNDERFLOW,
DSI_LP_Rx_TIMEOUT,
+ DSI_PLL_UNLOCK_ERR,
DSI_ERR_INTR_ALL,
};
+/* structure containing the delays required for dynamic clk */
+struct dsi_dyn_clk_delay {
+ u32 pipe_delay;
+ u32 pipe_delay2;
+ u32 pll_delay;
+};
+
+/* dynamic refresh control bits */
+enum dsi_dyn_clk_control_bits {
+ DYN_REFRESH_INTF_SEL = 1,
+ DYN_REFRESH_SYNC_MODE,
+ DYN_REFRESH_SW_TRIGGER,
+ DYN_REFRESH_SWI_CTRL,
+};
+
+/* convert dsi pixel format into bits per pixel */
+static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt)
+{
+ switch (fmt) {
+ case DSI_PIXEL_FORMAT_RGB888:
+ case DSI_PIXEL_FORMAT_MAX:
+ return 24;
+ case DSI_PIXEL_FORMAT_RGB666:
+ case DSI_PIXEL_FORMAT_RGB666_LOOSE:
+ return 18;
+ case DSI_PIXEL_FORMAT_RGB565:
+ return 16;
+ case DSI_PIXEL_FORMAT_RGB111:
+ return 3;
+ case DSI_PIXEL_FORMAT_RGB332:
+ return 8;
+ case DSI_PIXEL_FORMAT_RGB444:
+ return 12;
+ }
+ return 24;
+}
#endif /* _DSI_DEFS_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index dbc94a1..f8170b2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -1505,14 +1505,12 @@
static void adjust_timing_by_ctrl_count(const struct dsi_display *display,
struct dsi_display_mode *mode)
{
- if (display->ctrl_count > 1) {
- mode->timing.h_active /= display->ctrl_count;
- mode->timing.h_front_porch /= display->ctrl_count;
- mode->timing.h_sync_width /= display->ctrl_count;
- mode->timing.h_back_porch /= display->ctrl_count;
- mode->timing.h_skew /= display->ctrl_count;
- mode->pixel_clk_khz /= display->ctrl_count;
- }
+ mode->timing.h_active /= display->ctrl_count;
+ mode->timing.h_front_porch /= display->ctrl_count;
+ mode->timing.h_sync_width /= display->ctrl_count;
+ mode->timing.h_back_porch /= display->ctrl_count;
+ mode->timing.h_skew /= display->ctrl_count;
+ mode->pixel_clk_khz /= display->ctrl_count;
}
static int dsi_display_is_ulps_req_valid(struct dsi_display *display,
@@ -2220,7 +2218,7 @@
m_ctrl = &display->ctrl[display->clk_master_idx];
rc = dsi_ctrl_set_clock_source(m_ctrl->ctrl,
- &display->clock_info.src_clks);
+ &display->clock_info.mux_clks);
if (rc) {
pr_err("[%s] failed to set source clocks for master, rc=%d\n",
display->name, rc);
@@ -2234,7 +2232,7 @@
continue;
rc = dsi_ctrl_set_clock_source(ctrl->ctrl,
- &display->clock_info.src_clks);
+ &display->clock_info.mux_clks);
if (rc) {
pr_err("[%s] failed to set source clocks, rc=%d\n",
display->name, rc);
@@ -2957,13 +2955,37 @@
struct dsi_clk_link_set *src = &display->clock_info.src_clks;
struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
+ struct dsi_dyn_clk_caps *dyn_clk_caps = &(display->panel->dyn_clk_caps);
+
+ mux->byte_clk = devm_clk_get(&display->pdev->dev, "mux_byte_clk");
+ if (IS_ERR_OR_NULL(mux->byte_clk)) {
+ rc = PTR_ERR(mux->byte_clk);
+ pr_err("failed to get mux_byte_clk, rc=%d\n", rc);
+ mux->byte_clk = NULL;
+ goto error;
+ };
+
+ mux->pixel_clk = devm_clk_get(&display->pdev->dev, "mux_pixel_clk");
+ if (IS_ERR_OR_NULL(mux->pixel_clk)) {
+ rc = PTR_ERR(mux->pixel_clk);
+ mux->pixel_clk = NULL;
+ pr_err("failed to get mux_pixel_clk, rc=%d\n", rc);
+ goto error;
+ };
src->byte_clk = devm_clk_get(&display->pdev->dev, "src_byte_clk");
if (IS_ERR_OR_NULL(src->byte_clk)) {
rc = PTR_ERR(src->byte_clk);
src->byte_clk = NULL;
pr_err("failed to get src_byte_clk, rc=%d\n", rc);
- goto error;
+ /*
+ * Skip getting rest of clocks since one failed. This is a
+ * non-critical failure since these clocks are requied only for
+ * dynamic refresh use cases.
+ */
+ rc = 0;
+ dyn_clk_caps->dyn_clk_support = false;
+ goto done;
}
src->pixel_clk = devm_clk_get(&display->pdev->dev, "src_pixel_clk");
@@ -2971,37 +2993,16 @@
rc = PTR_ERR(src->pixel_clk);
src->pixel_clk = NULL;
pr_err("failed to get src_pixel_clk, rc=%d\n", rc);
- goto error;
+ /*
+ * Skip getting rest of clocks since one failed. This is a
+ * non-critical failure since these clocks are requied only for
+ * dynamic refresh use cases.
+ */
+ rc = 0;
+ dyn_clk_caps->dyn_clk_support = false;
+ goto done;
}
- mux->byte_clk = devm_clk_get(&display->pdev->dev, "mux_byte_clk");
- if (IS_ERR_OR_NULL(mux->byte_clk)) {
- rc = PTR_ERR(mux->byte_clk);
- pr_debug("failed to get mux_byte_clk, rc=%d\n", rc);
- mux->byte_clk = NULL;
- /*
- * Skip getting rest of clocks since one failed. This is a
- * non-critical failure since these clocks are requied only for
- * dynamic refresh use cases.
- */
- rc = 0;
- goto done;
- };
-
- mux->pixel_clk = devm_clk_get(&display->pdev->dev, "mux_pixel_clk");
- if (IS_ERR_OR_NULL(mux->pixel_clk)) {
- rc = PTR_ERR(mux->pixel_clk);
- mux->pixel_clk = NULL;
- pr_debug("failed to get mux_pixel_clk, rc=%d\n", rc);
- /*
- * Skip getting rest of clocks since one failed. This is a
- * non-critical failure since these clocks are requied only for
- * dynamic refresh use cases.
- */
- rc = 0;
- goto done;
- };
-
shadow->byte_clk = devm_clk_get(&display->pdev->dev, "shadow_byte_clk");
if (IS_ERR_OR_NULL(shadow->byte_clk)) {
rc = PTR_ERR(shadow->byte_clk);
@@ -3013,6 +3014,7 @@
* dynamic refresh use cases.
*/
rc = 0;
+ dyn_clk_caps->dyn_clk_support = false;
goto done;
};
@@ -3028,6 +3030,7 @@
* dynamic refresh use cases.
*/
rc = 0;
+ dyn_clk_caps->dyn_clk_support = false;
goto done;
};
@@ -3722,6 +3725,305 @@
return true;
}
+static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
+ u32 bit_clk_rate)
+{
+ int rc = 0;
+ int i;
+
+ pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate);
+ if (!display->panel) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (bit_clk_rate == 0) {
+ pr_err("Invalid bit clock rate\n");
+ return -EINVAL;
+ }
+
+ display->config.bit_clk_rate_hz = bit_clk_rate;
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
+ struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
+ u32 num_of_lanes = 0, bpp;
+ u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate;
+ struct dsi_host_common_cfg *host_cfg;
+
+ mutex_lock(&ctrl->ctrl_lock);
+
+ host_cfg = &display->panel->host_config;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_0)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_1)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_2)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_3)
+ num_of_lanes++;
+
+ if (num_of_lanes == 0) {
+ pr_err("Invalid lane count\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ bpp = dsi_pixel_format_to_bpp(host_cfg->dst_format);
+
+ bit_rate = display->config.bit_clk_rate_hz * num_of_lanes;
+ bit_rate_per_lane = bit_rate;
+ do_div(bit_rate_per_lane, num_of_lanes);
+ pclk_rate = bit_rate;
+ do_div(pclk_rate, bpp);
+ byte_clk_rate = bit_rate_per_lane;
+ do_div(byte_clk_rate, 8);
+ pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
+ bit_rate, bit_rate_per_lane);
+ pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n",
+ byte_clk_rate, pclk_rate);
+
+ ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
+ ctrl->clk_freq.pix_clk_rate = pclk_rate;
+ rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
+ ctrl->clk_freq, ctrl->cell_index);
+ if (rc) {
+ pr_err("Failed to update link frequencies\n");
+ goto error;
+ }
+
+ ctrl->host_config.bit_clk_rate_hz = bit_clk_rate;
+error:
+ mutex_unlock(&ctrl->ctrl_lock);
+
+ /* TODO: recover ctrl->clk_freq in case of failure */
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static void _dsi_display_calc_pipe_delay(struct dsi_display *display,
+ struct dsi_dyn_clk_delay *delay,
+ struct dsi_display_mode *mode)
+{
+ u32 esc_clk_rate_hz;
+ u32 pclk_to_esc_ratio, byte_to_esc_ratio, hr_bit_to_esc_ratio;
+ u32 hsync_period = 0;
+ struct dsi_display_ctrl *m_ctrl;
+ struct dsi_ctrl *dsi_ctrl;
+ struct dsi_phy_cfg *cfg;
+
+ m_ctrl = &display->ctrl[display->clk_master_idx];
+ dsi_ctrl = m_ctrl->ctrl;
+
+ cfg = &(m_ctrl->phy->cfg);
+
+ esc_clk_rate_hz = dsi_ctrl->clk_freq.esc_clk_rate * 1000;
+ pclk_to_esc_ratio = ((dsi_ctrl->clk_freq.pix_clk_rate * 1000) /
+ esc_clk_rate_hz);
+ byte_to_esc_ratio = ((dsi_ctrl->clk_freq.byte_clk_rate * 1000) /
+ esc_clk_rate_hz);
+ hr_bit_to_esc_ratio = ((dsi_ctrl->clk_freq.byte_clk_rate * 4 * 1000) /
+ esc_clk_rate_hz);
+
+ hsync_period = DSI_H_TOTAL_DSC(&mode->timing);
+ delay->pipe_delay = (hsync_period + 1) / pclk_to_esc_ratio;
+ if (!display->panel->video_config.eof_bllp_lp11_en)
+ delay->pipe_delay += (17 / pclk_to_esc_ratio) +
+ ((21 + (display->config.common_config.t_clk_pre + 1) +
+ (display->config.common_config.t_clk_post + 1)) /
+ byte_to_esc_ratio) +
+ ((((cfg->timing.lane_v3[8] >> 1) + 1) +
+ ((cfg->timing.lane_v3[6] >> 1) + 1) +
+ ((cfg->timing.lane_v3[3] * 4) +
+ (cfg->timing.lane_v3[5] >> 1) + 1) +
+ ((cfg->timing.lane_v3[7] >> 1) + 1) +
+ ((cfg->timing.lane_v3[1] >> 1) + 1) +
+ ((cfg->timing.lane_v3[4] >> 1) + 1)) /
+ hr_bit_to_esc_ratio);
+
+ delay->pipe_delay2 = 0;
+ if (display->panel->host_config.force_hs_clk_lane)
+ delay->pipe_delay2 = (6 / byte_to_esc_ratio) +
+ ((((cfg->timing.lane_v3[1] >> 1) + 1) +
+ ((cfg->timing.lane_v3[4] >> 1) + 1)) /
+ hr_bit_to_esc_ratio);
+
+ /* 130 us pll delay recommended by h/w doc */
+ delay->pll_delay = ((130 * esc_clk_rate_hz) / 1000000) * 2;
+}
+
+static int _dsi_display_dyn_update_clks(struct dsi_display *display,
+ struct link_clk_freq *bkp_freq)
+{
+ int rc = 0, i;
+ struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+ m_ctrl = &display->ctrl[display->clk_master_idx];
+
+ dsi_clk_prepare_enable(&display->clock_info.src_clks);
+
+ rc = dsi_clk_update_parent(&display->clock_info.shadow_clks,
+ &display->clock_info.mux_clks);
+ if (rc) {
+ pr_err("failed update mux parent to shadow\n");
+ goto exit;
+ }
+
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl->ctrl)
+ continue;
+ rc = dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
+ ctrl->ctrl->clk_freq.byte_clk_rate, i);
+ if (rc) {
+ pr_err("failed to set byte rate for index:%d\n", i);
+ goto recover_byte_clk;
+ }
+ rc = dsi_clk_set_pixel_clk_rate(display->dsi_clk_handle,
+ ctrl->ctrl->clk_freq.pix_clk_rate, i);
+ if (rc) {
+ pr_err("failed to set pix rate for index:%d\n", i);
+ goto recover_pix_clk;
+ }
+ }
+
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (ctrl == m_ctrl)
+ continue;
+ dsi_phy_dynamic_refresh_trigger(ctrl->phy, false);
+ }
+ dsi_phy_dynamic_refresh_trigger(m_ctrl->phy, true);
+
+ /* wait for dynamic refresh done */
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ rc = dsi_ctrl_wait4dynamic_refresh_done(ctrl->ctrl);
+ if (rc) {
+ pr_err("wait4dynamic refresh failed for dsi:%d\n", i);
+ goto recover_pix_clk;
+ } else {
+ pr_info("dynamic refresh done on dsi: %s\n",
+ i ? "slave" : "master");
+ }
+ }
+
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ dsi_phy_dynamic_refresh_clear(ctrl->phy);
+ }
+
+ rc = dsi_clk_update_parent(&display->clock_info.src_clks,
+ &display->clock_info.mux_clks);
+ if (rc)
+ pr_err("could not switch back to src clks %d\n", rc);
+
+ dsi_clk_disable_unprepare(&display->clock_info.src_clks);
+
+ return rc;
+
+recover_pix_clk:
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl->ctrl)
+ continue;
+ dsi_clk_set_pixel_clk_rate(display->dsi_clk_handle,
+ bkp_freq->pix_clk_rate, i);
+ }
+
+recover_byte_clk:
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl->ctrl)
+ continue;
+ dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
+ bkp_freq->byte_clk_rate, i);
+ }
+
+exit:
+ dsi_clk_disable_unprepare(&display->clock_info.src_clks);
+
+ return rc;
+}
+
+static int dsi_display_dynamic_clk_switch(struct dsi_display *display,
+ struct dsi_display_mode *mode)
+{
+ int rc = 0, mask, i;
+ struct dsi_display_ctrl *m_ctrl, *ctrl;
+ struct dsi_dyn_clk_delay delay;
+ struct link_clk_freq bkp_freq;
+
+ dsi_panel_acquire_panel_lock(display->panel);
+
+ m_ctrl = &display->ctrl[display->clk_master_idx];
+
+ dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON);
+
+ /* mask PLL unlock, FIFO overflow and underflow errors */
+ mask = BIT(DSI_PLL_UNLOCK_ERR) | BIT(DSI_FIFO_UNDERFLOW) |
+ BIT(DSI_FIFO_OVERFLOW);
+ dsi_display_mask_ctrl_error_interrupts(display, mask, true);
+
+ /* update the phy timings based on new mode */
+ for (i = 0; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ dsi_phy_update_phy_timings(ctrl->phy, &display->config);
+ }
+
+ /* back up existing rates to handle failure case */
+ bkp_freq.byte_clk_rate = m_ctrl->ctrl->clk_freq.byte_clk_rate;
+ bkp_freq.pix_clk_rate = m_ctrl->ctrl->clk_freq.pix_clk_rate;
+ bkp_freq.esc_clk_rate = m_ctrl->ctrl->clk_freq.esc_clk_rate;
+
+ rc = dsi_display_update_dsi_bitrate(display, mode->timing.clk_rate_hz);
+ if (rc) {
+ pr_err("failed set link frequencies %d\n", rc);
+ goto exit;
+ }
+
+ /* calculate pipe delays */
+ _dsi_display_calc_pipe_delay(display, &delay, mode);
+
+ /* configure dynamic refresh ctrl registers */
+ for (i = 0; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl->phy)
+ continue;
+ if (ctrl == m_ctrl)
+ dsi_phy_config_dynamic_refresh(ctrl->phy, &delay, true);
+ else
+ dsi_phy_config_dynamic_refresh(ctrl->phy, &delay,
+ false);
+ }
+
+ rc = _dsi_display_dyn_update_clks(display, &bkp_freq);
+
+exit:
+ dsi_display_mask_ctrl_error_interrupts(display, mask, false);
+
+ dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS,
+ DSI_CLK_OFF);
+
+ /* store newly calculated phy timings in mode private info */
+ dsi_phy_dyn_refresh_cache_phy_timings(m_ctrl->phy,
+ mode->priv_info->phy_timing_val,
+ mode->priv_info->phy_timing_len);
+
+ dsi_panel_release_panel_lock(display->panel);
+
+ return rc;
+}
+
static int dsi_display_dfps_update(struct dsi_display *display,
struct dsi_display_mode *dsi_mode)
{
@@ -3987,6 +4289,16 @@
display->name, rc);
goto error;
}
+ } else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) {
+ rc = dsi_display_dynamic_clk_switch(display, mode);
+ if (rc)
+ pr_err("dynamic clk change failed %d\n", rc);
+ /*
+ * skip rest of the opearations since
+ * dsi_display_dynamic_clk_switch() already takes
+ * care of them.
+ */
+ return rc;
}
for (i = 0; i < display->ctrl_count; i++) {
@@ -4222,84 +4534,6 @@
return rc;
}
-static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display,
- u32 bit_clk_rate)
-{
- int rc = 0;
- int i;
-
- pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate);
- if (!display->panel) {
- pr_err("Invalid params\n");
- return -EINVAL;
- }
-
- if (bit_clk_rate == 0) {
- pr_err("Invalid bit clock rate\n");
- return -EINVAL;
- }
-
- display->config.bit_clk_rate_hz = bit_clk_rate;
-
- for (i = 0; i < display->ctrl_count; i++) {
- struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
- struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
- u32 num_of_lanes = 0;
- u32 bpp = 3;
- u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate;
- struct dsi_host_common_cfg *host_cfg;
-
- mutex_lock(&ctrl->ctrl_lock);
-
- host_cfg = &display->panel->host_config;
- if (host_cfg->data_lanes & DSI_DATA_LANE_0)
- num_of_lanes++;
- if (host_cfg->data_lanes & DSI_DATA_LANE_1)
- num_of_lanes++;
- if (host_cfg->data_lanes & DSI_DATA_LANE_2)
- num_of_lanes++;
- if (host_cfg->data_lanes & DSI_DATA_LANE_3)
- num_of_lanes++;
-
- if (num_of_lanes == 0) {
- pr_err("Invalid lane count\n");
- rc = -EINVAL;
- goto error;
- }
-
- bit_rate = display->config.bit_clk_rate_hz * num_of_lanes;
- bit_rate_per_lane = bit_rate;
- do_div(bit_rate_per_lane, num_of_lanes);
- pclk_rate = bit_rate;
- do_div(pclk_rate, (8 * bpp));
- byte_clk_rate = bit_rate_per_lane;
- do_div(byte_clk_rate, 8);
- pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
- bit_rate, bit_rate_per_lane);
- pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n",
- byte_clk_rate, pclk_rate);
-
- ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
- ctrl->clk_freq.pix_clk_rate = pclk_rate;
- rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
- ctrl->clk_freq, ctrl->cell_index);
- if (rc) {
- pr_err("Failed to update link frequencies\n");
- goto error;
- }
-
- ctrl->host_config.bit_clk_rate_hz = bit_clk_rate;
-error:
- mutex_unlock(&ctrl->ctrl_lock);
-
- /* TODO: recover ctrl->clk_freq in case of failure */
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
static ssize_t sysfs_dynamic_dsi_clk_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -4350,6 +4584,11 @@
return rc;
}
+ if (display->panel->panel_mode != DSI_OP_CMD_MODE) {
+ pr_err("only supported for command mode\n");
+ return -ENOTSUPP;
+ }
+
if (clk_rate <= 0) {
pr_err("%s: bitrate should be greater than 0\n", __func__);
return -EINVAL;
@@ -4365,7 +4604,7 @@
mutex_lock(&display->display_lock);
display->cached_clk_rate = clk_rate;
- rc = dsi_display_request_update_dsi_bitrate(display, clk_rate);
+ rc = dsi_display_update_dsi_bitrate(display, clk_rate);
if (!rc) {
pr_info("%s: bit clk is ready to be configured to '%d'\n",
__func__, clk_rate);
@@ -5151,7 +5390,8 @@
u32 *count)
{
struct dsi_dfps_capabilities dfps_caps;
- int num_dfps_rates, rc = 0;
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
+ int num_dfps_rates, num_bit_clks, rc = 0;
if (!display || !display->panel) {
pr_err("invalid display:%d panel:%d\n", display != NULL,
@@ -5168,12 +5408,16 @@
return rc;
}
- num_dfps_rates = !dfps_caps.dfps_support ? 1 :
- dfps_caps.max_refresh_rate -
- dfps_caps.min_refresh_rate + 1;
+ num_dfps_rates = !dfps_caps.dfps_support ? 1 : dfps_caps.dfps_list_len;
- /* Inflate num_of_modes by fps in dfps */
- *count = display->panel->num_timing_nodes * num_dfps_rates;
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
+
+ num_bit_clks = !dyn_clk_caps->dyn_clk_support ? 1 :
+ dyn_clk_caps->bit_clk_list_len;
+
+ /* Inflate num_of_modes by fps and bit clks in dfps */
+ *count = display->panel->num_timing_nodes *
+ num_dfps_rates * num_bit_clks;
return 0;
}
@@ -5196,6 +5440,73 @@
return 0;
}
+static void _dsi_display_populate_bit_clks(struct dsi_display *display,
+ int start, int end, u32 *mode_idx)
+{
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
+ struct dsi_display_mode *src, *dst;
+ struct dsi_host_common_cfg *cfg;
+ int i, j, total_modes, bpp, lanes = 0;
+
+ if (!display || !mode_idx)
+ return;
+
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
+ if (!dyn_clk_caps->dyn_clk_support)
+ return;
+
+ cfg = &(display->panel->host_config);
+ bpp = dsi_pixel_format_to_bpp(cfg->dst_format);
+
+ if (cfg->data_lanes & DSI_LOGICAL_LANE_0)
+ lanes++;
+ if (cfg->data_lanes & DSI_LOGICAL_LANE_1)
+ lanes++;
+ if (cfg->data_lanes & DSI_LOGICAL_LANE_2)
+ lanes++;
+ if (cfg->data_lanes & DSI_LOGICAL_LANE_3)
+ lanes++;
+
+ dsi_display_get_mode_count_no_lock(display, &total_modes);
+
+ for (i = start; i < end; i++) {
+ src = &display->modes[i];
+ if (!src)
+ return;
+ /*
+ * TODO: currently setting the first bit rate in
+ * the list as preferred rate. But ideally should
+ * be based on user or device tree preferrence.
+ */
+ src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0];
+ src->pixel_clk_khz =
+ div_u64(src->timing.clk_rate_hz * lanes, bpp);
+ src->pixel_clk_khz /= 1000;
+ src->pixel_clk_khz *= display->ctrl_count;
+ }
+
+ for (i = 1; i < dyn_clk_caps->bit_clk_list_len; i++) {
+ if (*mode_idx >= total_modes)
+ return;
+ for (j = start; j < end; j++) {
+ src = &display->modes[j];
+ dst = &display->modes[*mode_idx];
+
+ if (!src || !dst) {
+ pr_err("invalid mode index\n");
+ return;
+ }
+ memcpy(dst, src, sizeof(struct dsi_display_mode));
+ dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i];
+ dst->pixel_clk_khz =
+ div_u64(dst->timing.clk_rate_hz * lanes, bpp);
+ dst->pixel_clk_khz /= 1000;
+ dst->pixel_clk_khz *= display->ctrl_count;
+ (*mode_idx)++;
+ }
+ }
+}
+
void dsi_display_put_mode(struct dsi_display *display,
struct dsi_display_mode *mode)
{
@@ -5206,9 +5517,10 @@
struct dsi_display_mode **out_modes)
{
struct dsi_dfps_capabilities dfps_caps;
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
u32 num_dfps_rates, panel_mode_count, total_mode_count;
u32 mode_idx, array_idx = 0;
- int i, rc = -EINVAL;
+ int i, start, end, rc = -EINVAL;
if (!display || !out_modes) {
pr_err("Invalid params\n");
@@ -5240,9 +5552,9 @@
goto error;
}
- num_dfps_rates = !dfps_caps.dfps_support ? 1 :
- dfps_caps.max_refresh_rate -
- dfps_caps.min_refresh_rate + 1;
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
+
+ num_dfps_rates = !dfps_caps.dfps_support ? 1 : dfps_caps.dfps_list_len;
panel_mode_count = display->panel->num_timing_nodes;
@@ -5263,14 +5575,14 @@
goto error;
}
- if (display->ctrl_count > 1) { /* TODO: remove if */
- panel_mode.timing.h_active *= display->ctrl_count;
- panel_mode.timing.h_front_porch *= display->ctrl_count;
- panel_mode.timing.h_sync_width *= display->ctrl_count;
- panel_mode.timing.h_back_porch *= display->ctrl_count;
- panel_mode.timing.h_skew *= display->ctrl_count;
- panel_mode.pixel_clk_khz *= display->ctrl_count;
- }
+ panel_mode.timing.h_active *= display->ctrl_count;
+ panel_mode.timing.h_front_porch *= display->ctrl_count;
+ panel_mode.timing.h_sync_width *= display->ctrl_count;
+ panel_mode.timing.h_back_porch *= display->ctrl_count;
+ panel_mode.timing.h_skew *= display->ctrl_count;
+ panel_mode.pixel_clk_khz *= display->ctrl_count;
+
+ start = array_idx;
for (i = 0; i < num_dfps_rates; i++) {
struct dsi_display_mode *sub_mode =
@@ -5284,24 +5596,24 @@
}
memcpy(sub_mode, &panel_mode, sizeof(panel_mode));
-
- if (dfps_caps.dfps_support) {
- curr_refresh_rate =
- sub_mode->timing.refresh_rate;
- sub_mode->timing.refresh_rate =
- dfps_caps.min_refresh_rate +
- (i % num_dfps_rates);
-
- dsi_display_get_dfps_timing(display,
- sub_mode, curr_refresh_rate);
-
- sub_mode->pixel_clk_khz =
- (DSI_H_TOTAL(&sub_mode->timing) *
- DSI_V_TOTAL(&sub_mode->timing) *
- sub_mode->timing.refresh_rate) / 1000;
- }
array_idx++;
+
+ if (!dfps_caps.dfps_support)
+ continue;
+
+ curr_refresh_rate = sub_mode->timing.refresh_rate;
+ sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i];
+
+ dsi_display_get_dfps_timing(display, sub_mode,
+ curr_refresh_rate);
}
+
+ end = array_idx;
+ /*
+ * if dynamic clk switch is supported then update all the bit
+ * clk rates.
+ */
+ _dsi_display_populate_bit_clks(display, start, end, &array_idx);
}
exit:
@@ -5385,7 +5697,8 @@
if (cmp->timing.v_active == m->timing.v_active &&
cmp->timing.h_active == m->timing.h_active &&
- cmp->timing.refresh_rate == m->timing.refresh_rate) {
+ cmp->timing.refresh_rate == m->timing.refresh_rate &&
+ cmp->pixel_clk_khz == m->pixel_clk_khz) {
*out_mode = m;
rc = 0;
break;
@@ -5394,9 +5707,10 @@
mutex_unlock(&display->display_lock);
if (!*out_mode) {
- pr_err("[%s] failed to find mode for v_active %u h_active %u rate %u\n",
+ pr_err("[%s] failed to find mode for v_active %u h_active %u fps %u pclk %u\n",
display->name, cmp->timing.v_active,
- cmp->timing.h_active, cmp->timing.refresh_rate);
+ cmp->timing.h_active, cmp->timing.refresh_rate,
+ cmp->pixel_clk_khz);
rc = -ENOENT;
}
@@ -5404,7 +5718,7 @@
}
/**
- * dsi_display_validate_mode_vrr() - Validate if varaible refresh case.
+ * dsi_display_validate_mode_change() - Validate if varaible refresh case.
* @display: DSI display handle.
* @cur_dsi_mode: Current DSI mode.
* @mode: Mode value structure to be validated.
@@ -5412,16 +5726,15 @@
* is change in fps but vactive and hactive are same.
* Return: error code.
*/
-int dsi_display_validate_mode_vrr(struct dsi_display *display,
- struct dsi_display_mode *cur_dsi_mode,
- struct dsi_display_mode *mode)
+int dsi_display_validate_mode_change(struct dsi_display *display,
+ struct dsi_display_mode *cur_mode,
+ struct dsi_display_mode *adj_mode)
{
int rc = 0;
- struct dsi_display_mode adj_mode, cur_mode;
struct dsi_dfps_capabilities dfps_caps;
- u32 curr_refresh_rate;
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
- if (!display || !mode) {
+ if (!display || !adj_mode) {
pr_err("Invalid params\n");
return -EINVAL;
}
@@ -5433,65 +5746,43 @@
mutex_lock(&display->display_lock);
- adj_mode = *mode;
- cur_mode = *cur_dsi_mode;
-
- if ((cur_mode.timing.refresh_rate != adj_mode.timing.refresh_rate) &&
- (cur_mode.timing.v_active == adj_mode.timing.v_active) &&
- (cur_mode.timing.h_active == adj_mode.timing.h_active)) {
-
- curr_refresh_rate = cur_mode.timing.refresh_rate;
- rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
- if (rc) {
- pr_err("[%s] failed to get dfps caps from panel\n",
- display->name);
- goto error;
+ if ((cur_mode->timing.v_active == adj_mode->timing.v_active) &&
+ (cur_mode->timing.h_active == adj_mode->timing.h_active)) {
+ /* dfps change use case */
+ if (cur_mode->timing.refresh_rate !=
+ adj_mode->timing.refresh_rate) {
+ dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
+ if (!dfps_caps.dfps_support) {
+ pr_err("invalid mode dfps not supported\n");
+ rc = -ENOTSUPP;
+ goto error;
+ }
+ pr_debug("Mode switch is seamless variable refresh\n");
+ adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
+ SDE_EVT32(cur_mode->timing.refresh_rate,
+ adj_mode->timing.refresh_rate,
+ cur_mode->timing.h_front_porch,
+ adj_mode->timing.h_front_porch);
}
- cur_mode.timing.refresh_rate =
- adj_mode.timing.refresh_rate;
-
- rc = dsi_display_get_dfps_timing(display,
- &cur_mode, curr_refresh_rate);
- if (rc) {
- pr_err("[%s] seamless vrr not possible rc=%d\n",
- display->name, rc);
- goto error;
+ /* dynamic clk change use case */
+ if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) {
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
+ if (!dyn_clk_caps->dyn_clk_support) {
+ pr_err("dyn clk change not supported\n");
+ rc = -ENOTSUPP;
+ goto error;
+ }
+ if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) {
+ pr_err("dfps and dyn clk not supported in same commit\n");
+ rc = -ENOTSUPP;
+ goto error;
+ }
+ pr_debug("dynamic clk change detected\n");
+ adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK;
+ SDE_EVT32(cur_mode->pixel_clk_khz,
+ adj_mode->pixel_clk_khz);
}
- switch (dfps_caps.type) {
- /*
- * Ignore any round off factors in porch calculation.
- * Worse case is set to 5.
- */
- case DSI_DFPS_IMMEDIATE_VFP:
- if (abs(DSI_V_TOTAL(&cur_mode.timing) -
- DSI_V_TOTAL(&adj_mode.timing)) > 5)
- pr_err("Mismatch vfp fps:%d new:%d given:%d\n",
- adj_mode.timing.refresh_rate,
- cur_mode.timing.v_front_porch,
- adj_mode.timing.v_front_porch);
- break;
-
- case DSI_DFPS_IMMEDIATE_HFP:
- if (abs(DSI_H_TOTAL(&cur_mode.timing) -
- DSI_H_TOTAL(&adj_mode.timing)) > 5)
- pr_err("Mismatch hfp fps:%d new:%d given:%d\n",
- adj_mode.timing.refresh_rate,
- cur_mode.timing.h_front_porch,
- adj_mode.timing.h_front_porch);
- break;
-
- default:
- pr_err("Unsupported DFPS mode %d\n",
- dfps_caps.type);
- rc = -ENOTSUPP;
- }
-
- pr_debug("Mode switch is seamless variable refresh\n");
- mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
- SDE_EVT32(curr_refresh_rate, adj_mode.timing.refresh_rate,
- cur_mode.timing.h_front_porch,
- adj_mode.timing.h_front_porch);
}
error:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 5612016..f65f0f5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -398,13 +398,14 @@
u32 flags);
/**
- * dsi_display_validate_mode_vrr() - validates mode if variable refresh case
+ * dsi_display_validate_mode_change() - validates mode if variable refresh case
+ * or dynamic clk change case
* @display: Handle to display.
* @mode: Mode to be validated..
*
* Return: 0 if error code.
*/
-int dsi_display_validate_mode_vrr(struct dsi_display *display,
+int dsi_display_validate_mode_change(struct dsi_display *display,
struct dsi_display_mode *cur_dsi_mode,
struct dsi_display_mode *mode);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index 1278d59..68a7277 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -63,6 +63,8 @@
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
if (msm_is_mode_seamless_vrr(drm_mode))
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
+ if (msm_is_mode_seamless_dyn_clk(drm_mode))
+ dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK;
dsi_mode->timing.h_sync_polarity =
!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
@@ -105,13 +107,18 @@
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS;
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
+ if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)
+ drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYN_CLK;
if (dsi_mode->timing.h_sync_polarity)
drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
if (dsi_mode->timing.v_sync_polarity)
drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
- drm_mode_set_name(drm_mode);
+ /* set mode name */
+ snprintf(drm_mode->name, DRM_DISPLAY_MODE_LEN, "%dx%dx%dx%d",
+ drm_mode->hdisplay, drm_mode->vdisplay, drm_mode->vrefresh,
+ drm_mode->clock);
}
static int dsi_bridge_attach(struct drm_bridge *bridge)
@@ -156,7 +163,8 @@
}
if (c_bridge->dsi_mode.dsi_mode_flags &
- (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) {
+ (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR |
+ DSI_MODE_FLAG_DYN_CLK)) {
pr_debug("[%d] seamless pre-enable\n", c_bridge->id);
return;
}
@@ -279,6 +287,12 @@
memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
+
+ /* restore bit_clk_rate also for dynamic clk use cases */
+ c_bridge->dsi_mode.timing.clk_rate_hz =
+ dsi_drm_find_bit_clk_rate(c_bridge->display, adjusted_mode);
+
+ pr_debug("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz);
}
static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
@@ -337,17 +351,20 @@
convert_to_dsi_mode(&crtc_state->crtc->state->mode,
&cur_dsi_mode);
- rc = dsi_display_validate_mode_vrr(c_bridge->display,
+ rc = dsi_display_validate_mode_change(c_bridge->display,
&cur_dsi_mode, &dsi_mode);
- if (rc)
- pr_debug("[%s] vrr mode mismatch failure rc=%d\n",
+ if (rc) {
+ pr_err("[%s] seamless mode mismatch failure rc=%d\n",
c_bridge->display->name, rc);
+ return false;
+ }
cur_mode = crtc_state->crtc->mode;
/* No DMS/VRR when drm pipeline is changing */
if (!drm_mode_equal(&cur_mode, adjusted_mode) &&
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
+ (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) &&
(!crtc_state->active_changed ||
display->is_cont_splash_enabled))
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
@@ -359,6 +376,33 @@
return true;
}
+u64 dsi_drm_find_bit_clk_rate(void *display,
+ const struct drm_display_mode *drm_mode)
+{
+ int i = 0, count = 0;
+ struct dsi_display *dsi_display = display;
+ struct dsi_display_mode *dsi_mode;
+ u64 bit_clk_rate = 0;
+
+ if (!dsi_display || !drm_mode)
+ return 0;
+
+ dsi_display_get_mode_count(dsi_display, &count);
+
+ for (i = 0; i < count; i++) {
+ dsi_mode = &dsi_display->modes[i];
+ if ((dsi_mode->timing.v_active == drm_mode->vdisplay) &&
+ (dsi_mode->timing.h_active == drm_mode->hdisplay) &&
+ (dsi_mode->pixel_clk_khz == drm_mode->clock) &&
+ (dsi_mode->timing.refresh_rate == drm_mode->vrefresh)) {
+ bit_clk_rate = dsi_mode->timing.clk_rate_hz;
+ break;
+ }
+ }
+
+ return bit_clk_rate;
+}
+
int dsi_conn_get_mode_info(const struct drm_display_mode *drm_mode,
struct msm_mode_info *mode_info,
u32 max_mixer_width, void *display)
@@ -382,7 +426,7 @@
mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines;
mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer;
mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom;
- mode_info->clk_rate = dsi_mode.priv_info->clk_rate_hz;
+ mode_info->clk_rate = dsi_drm_find_bit_clk_rate(display, drm_mode);
memcpy(&mode_info->topology, &dsi_mode.priv_info->topology,
sizeof(struct msm_display_topology));
@@ -507,6 +551,9 @@
panel->dfps_caps.max_refresh_rate);
}
+ sde_kms_info_add_keystr(info, "dyn bitclk support",
+ panel->dyn_clk_caps.dyn_clk_support ? "true" : "false");
+
switch (panel->phy_props.rotation) {
case DSI_PANEL_ROTATE_NONE:
sde_kms_info_add_keystr(info, "panel orientation", "none");
@@ -662,6 +709,9 @@
}
m->width_mm = connector->display_info.width_mm;
m->height_mm = connector->display_info.height_mm;
+ /* set the first mode in list as preferred */
+ if (i == 0)
+ m->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, m);
}
end:
@@ -768,6 +818,9 @@
c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_VRR;
}
+ /* ensure dynamic clk switch flag is reset */
+ c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_DYN_CLK;
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index 2bad8c0..8d3e764 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -150,4 +150,6 @@
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
struct drm_display_mode *drm_mode);
+u64 dsi_drm_find_bit_clk_rate(void *display,
+ const struct drm_display_mode *drm_mode);
#endif /* _DSI_DRM_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
index 174be9f..9ccff4b 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -45,4 +45,14 @@
#define DSI_R64(dsi_hw, off) readq_relaxed((dsi_hw)->base + (off))
#define DSI_W64(dsi_hw, off, val) writeq_relaxed((val), (dsi_hw)->base + (off))
+#define PLL_CALC_DATA(addr0, addr1, data0, data1) \
+ (((data1) << 24) | ((((addr1)/4) & 0xFF) << 16) | \
+ ((data0) << 8) | (((addr0)/4) & 0xFF))
+
+#define DSI_DYN_REF_REG_W(base, offset, addr0, addr1, data0, data1) \
+ writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \
+ (base) + (offset))
+
+#define DSI_GEN_R32(base, offset) readl_relaxed(base + (offset))
+#define DSI_GEN_W32(base, offset, val) writel_relaxed((val), base + (offset))
#endif /* _DSI_HW_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 61c3fcb..b43b23c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1130,6 +1130,46 @@
return rc;
}
+static int dsi_panel_parse_dyn_clk_caps(struct dsi_dyn_clk_caps *dyn_clk_caps,
+ struct device_node *of_node,
+ const char *name)
+{
+ int rc = 0;
+ bool supported = false;
+
+ supported = of_property_read_bool(of_node, "qcom,dsi-dyn-clk-enable");
+
+ if (!supported) {
+ dyn_clk_caps->dyn_clk_support = false;
+ return rc;
+ }
+
+ of_find_property(of_node, "qcom,dsi-dyn-clk-list",
+ &dyn_clk_caps->bit_clk_list_len);
+ dyn_clk_caps->bit_clk_list_len /= sizeof(u32);
+ if (dyn_clk_caps->bit_clk_list_len < 1) {
+ pr_err("[%s] failed to get supported bit clk list\n", name);
+ return -EINVAL;
+ }
+
+ dyn_clk_caps->bit_clk_list = kcalloc(dyn_clk_caps->bit_clk_list_len,
+ sizeof(u32), GFP_KERNEL);
+ if (!dyn_clk_caps->bit_clk_list)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(of_node, "qcom,dsi-dyn-clk-list",
+ dyn_clk_caps->bit_clk_list,
+ dyn_clk_caps->bit_clk_list_len);
+ if (rc) {
+ pr_err("[%s] failed to parse supported bit clk list\n", name);
+ return -EINVAL;
+ }
+
+ dyn_clk_caps->dyn_clk_support = true;
+
+ return 0;
+}
+
static int dsi_panel_parse_dfps_caps(struct dsi_dfps_capabilities *dfps_caps,
struct device_node *of_node,
const char *name)
@@ -1137,7 +1177,7 @@
int rc = 0;
bool supported = false;
const char *type;
- u32 val = 0;
+ u32 val = 0, i;
supported = of_property_read_bool(of_node,
"qcom,mdss-dsi-pan-enable-dynamic-fps");
@@ -1145,68 +1185,68 @@
if (!supported) {
pr_debug("[%s] DFPS is not supported\n", name);
dfps_caps->dfps_support = false;
- } else {
-
- type = of_get_property(of_node,
- "qcom,mdss-dsi-pan-fps-update",
- NULL);
- if (!type) {
- pr_err("[%s] dfps type not defined\n", name);
- rc = -EINVAL;
- goto error;
- } else if (!strcmp(type, "dfps_suspend_resume_mode")) {
- dfps_caps->type = DSI_DFPS_SUSPEND_RESUME;
- } else if (!strcmp(type, "dfps_immediate_clk_mode")) {
- dfps_caps->type = DSI_DFPS_IMMEDIATE_CLK;
- } else if (!strcmp(type, "dfps_immediate_porch_mode_hfp")) {
- dfps_caps->type = DSI_DFPS_IMMEDIATE_HFP;
- } else if (!strcmp(type, "dfps_immediate_porch_mode_vfp")) {
- dfps_caps->type = DSI_DFPS_IMMEDIATE_VFP;
- } else {
- pr_err("[%s] dfps type is not recognized\n", name);
- rc = -EINVAL;
- goto error;
- }
-
- rc = of_property_read_u32(of_node,
- "qcom,mdss-dsi-min-refresh-rate",
- &val);
- if (rc) {
- pr_err("[%s] Min refresh rate is not defined\n", name);
- rc = -EINVAL;
- goto error;
- }
- dfps_caps->min_refresh_rate = val;
-
- rc = of_property_read_u32(of_node,
- "qcom,mdss-dsi-max-refresh-rate",
- &val);
- if (rc) {
- pr_debug("[%s] Using default refresh rate\n", name);
- rc = of_property_read_u32(of_node,
- "qcom,mdss-dsi-panel-framerate",
- &val);
- if (rc) {
- pr_err("[%s] max refresh rate is not defined\n",
- name);
- rc = -EINVAL;
- goto error;
- }
- }
- dfps_caps->max_refresh_rate = val;
-
- if (dfps_caps->min_refresh_rate > dfps_caps->max_refresh_rate) {
- pr_err("[%s] min rate > max rate\n", name);
- rc = -EINVAL;
- }
-
- pr_debug("[%s] DFPS is supported %d-%d, mode %d\n", name,
- dfps_caps->min_refresh_rate,
- dfps_caps->max_refresh_rate,
- dfps_caps->type);
- dfps_caps->dfps_support = true;
+ return rc;
}
+ type = of_get_property(of_node,
+ "qcom,mdss-dsi-pan-fps-update",
+ NULL);
+ if (!type) {
+ pr_err("[%s] dfps type not defined\n", name);
+ rc = -EINVAL;
+ goto error;
+ } else if (!strcmp(type, "dfps_suspend_resume_mode")) {
+ dfps_caps->type = DSI_DFPS_SUSPEND_RESUME;
+ } else if (!strcmp(type, "dfps_immediate_clk_mode")) {
+ dfps_caps->type = DSI_DFPS_IMMEDIATE_CLK;
+ } else if (!strcmp(type, "dfps_immediate_porch_mode_hfp")) {
+ dfps_caps->type = DSI_DFPS_IMMEDIATE_HFP;
+ } else if (!strcmp(type, "dfps_immediate_porch_mode_vfp")) {
+ dfps_caps->type = DSI_DFPS_IMMEDIATE_VFP;
+ } else {
+ pr_err("[%s] dfps type is not recognized\n", name);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ of_find_property(of_node, "qcom,dsi-supported-dfps-list",
+ &dfps_caps->dfps_list_len);
+ dfps_caps->dfps_list_len /= sizeof(u32);
+ if (dfps_caps->dfps_list_len < 1) {
+ pr_err("[%s] dfps refresh list not present\n", name);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ dfps_caps->dfps_list = kcalloc(dfps_caps->dfps_list_len, sizeof(u32),
+ GFP_KERNEL);
+ if (!dfps_caps->dfps_list) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ rc = of_property_read_u32_array(of_node, "qcom,dsi-supported-dfps-list",
+ dfps_caps->dfps_list,
+ dfps_caps->dfps_list_len);
+ if (rc) {
+ pr_err("[%s] dfps refresh rate list parse failed\n", name);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ dfps_caps->dfps_support = true;
+
+ /* calculate max and min fps */
+ of_property_read_u32(of_node, "qcom,mdss-dsi-panel-framerate", &val);
+ dfps_caps->max_refresh_rate = val;
+ dfps_caps->min_refresh_rate = val;
+
+ for (i = 0; i < dfps_caps->dfps_list_len; i++) {
+ if (dfps_caps->dfps_list[i] < dfps_caps->min_refresh_rate)
+ dfps_caps->min_refresh_rate = dfps_caps->dfps_list[i];
+ else if (dfps_caps->dfps_list[i] > dfps_caps->max_refresh_rate)
+ dfps_caps->max_refresh_rate = dfps_caps->dfps_list[i];
+ }
error:
return rc;
}
@@ -2930,6 +2970,14 @@
pr_err("failed to parse dfps configuration, rc=%d\n",
rc);
+ if (panel->panel_mode == DSI_OP_VIDEO_MODE) {
+ rc = dsi_panel_parse_dyn_clk_caps(&panel->dyn_clk_caps,
+ of_node, panel->name);
+ if (rc)
+ pr_err("failed to parse dynamic clk config, rc=%d\n",
+ rc);
+ }
+
rc = dsi_panel_parse_phy_props(&panel->phy_props,
of_node, panel->name);
if (rc) {
@@ -3329,7 +3377,7 @@
if (mode->priv_info) {
config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
config->video_timing.dsc = &mode->priv_info->dsc;
- config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+ config->bit_clk_rate_hz = mode->timing.clk_rate_hz;
}
config->esc_clk_rate_hz = 19200000;
mutex_unlock(&panel->panel_lock);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index fef7d3f..ab8ccee 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -70,10 +70,18 @@
};
struct dsi_dfps_capabilities {
- bool dfps_support;
enum dsi_dfps_type type;
u32 min_refresh_rate;
u32 max_refresh_rate;
+ u32 *dfps_list;
+ u32 dfps_list_len;
+ bool dfps_support;
+};
+
+struct dsi_dyn_clk_caps {
+ bool dyn_clk_support;
+ u32 *bit_clk_list;
+ u32 bit_clk_list_len;
};
struct dsi_pinctrl_info {
@@ -170,6 +178,7 @@
enum dsi_op_mode panel_mode;
struct dsi_dfps_capabilities dfps_caps;
+ struct dsi_dyn_clk_caps dyn_clk_caps;
struct dsi_panel_phy_props phy_props;
struct dsi_display_mode *cur_mode;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 3d6711f..ebc699a 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -107,6 +107,9 @@
phy->hw.base = ptr;
+ ptr = msm_ioremap(pdev, "dyn_refresh_base", phy->name);
+ phy->hw.dyn_pll_base = ptr;
+
pr_debug("[%s] map dsi_phy registers to %pK\n",
phy->name, phy->hw.base);
@@ -616,11 +619,8 @@
return -EINVAL;
}
- mutex_lock(&dsi_phy->phy_lock);
-
pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
- mutex_unlock(&dsi_phy->phy_lock);
return rc;
}
@@ -848,7 +848,7 @@
rc = phy->hw.ops.calculate_timing_params(&phy->hw,
&phy->mode,
&config->common_config,
- &phy->cfg.timing);
+ &phy->cfg.timing, false);
if (rc) {
pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
goto error;
@@ -866,6 +866,27 @@
return rc;
}
+/* update dsi phy timings for dynamic clk switch use case */
+int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
+ struct dsi_host_config *config)
+{
+ int rc = 0;
+
+ if (!phy || !config) {
+ pr_err("invalid argument\n");
+ return -EINVAL;
+ }
+
+ memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
+ rc = phy->hw.ops.calculate_timing_params(&phy->hw, &phy->mode,
+ &config->common_config,
+ &phy->cfg.timing, true);
+ if (rc)
+ pr_err("failed to calculate phy timings %d\n", rc);
+
+ return rc;
+}
+
int dsi_phy_lane_reset(struct msm_dsi_phy *phy)
{
int ret = 0;
@@ -1030,10 +1051,111 @@
rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
if (!rc)
phy->cfg.is_phy_timing_present = true;
+
mutex_unlock(&phy->phy_lock);
return rc;
}
+/**
+ * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
+ * @phy: DSI PHY handle
+ * @is_master: Boolean to indicate if for master or slave.
+ */
+void dsi_phy_dynamic_refresh_trigger(struct msm_dsi_phy *phy, bool is_master)
+{
+ u32 off;
+
+ if (!phy)
+ return;
+
+ mutex_lock(&phy->phy_lock);
+ /*
+ * program PLL_SWI_INTF_SEL and SW_TRIGGER bit only for
+ * master and program SYNC_MODE bit only for slave.
+ */
+ if (is_master)
+ off = BIT(DYN_REFRESH_INTF_SEL) | BIT(DYN_REFRESH_SWI_CTRL) |
+ BIT(DYN_REFRESH_SW_TRIGGER);
+ else
+ off = BIT(DYN_REFRESH_SYNC_MODE) | BIT(DYN_REFRESH_SWI_CTRL);
+
+ if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper)
+ phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, off);
+
+ mutex_unlock(&phy->phy_lock);
+}
+
+/**
+ * dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers
+ * @phy: DSI PHY handle
+ * @delay: pipe delays for dynamic refresh
+ * @is_master: Boolean to indicate if for master or slave.
+ */
+void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
+ struct dsi_dyn_clk_delay *delay,
+ bool is_master)
+{
+ struct dsi_phy_cfg *cfg;
+
+ if (!phy)
+ return;
+
+ mutex_lock(&phy->phy_lock);
+
+ cfg = &phy->cfg;
+
+ if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_config)
+ phy->hw.ops.dyn_refresh_ops.dyn_refresh_config(&phy->hw, cfg,
+ is_master);
+ if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay)
+ phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay(
+ &phy->hw, delay);
+
+ mutex_unlock(&phy->phy_lock);
+}
+
+/**
+ * dsi_phy_cache_phy_timings - cache the phy timings calculated as part of
+ * dynamic refresh.
+ * @phy: DSI PHY Handle.
+ * @dst: Pointer to cache location.
+ * @size: Number of phy lane settings.
+ */
+int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy, u32 *dst,
+ u32 size)
+{
+ int rc = 0;
+
+ if (!phy || !dst || !size)
+ return -EINVAL;
+
+ if (phy->hw.ops.dyn_refresh_ops.cache_phy_timings)
+ rc = phy->hw.ops.dyn_refresh_ops.cache_phy_timings(
+ &phy->cfg.timing, dst, size);
+
+ if (rc)
+ pr_err("failed to cache phy timings %d\n", rc);
+
+ return rc;
+}
+
+/**
+ * dsi_phy_dynamic_refresh_clear() - clear dynamic refresh config
+ * @phy: DSI PHY handle
+ */
+void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy)
+{
+ if (!phy)
+ return;
+
+ mutex_lock(&phy->phy_lock);
+
+ if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper)
+ phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, 0);
+
+ mutex_unlock(&phy->phy_lock);
+}
+
void dsi_phy_drv_register(void)
{
platform_driver_register(&dsi_phy_platform_driver);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
index 4163411..65c7a16 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
@@ -278,4 +278,45 @@
*/
void dsi_phy_drv_unregister(void);
+/**
+ * dsi_phy_update_phy_timings() - Update dsi phy timings
+ * @phy: DSI PHY handle
+ * @config: DSI Host config parameters
+ *
+ * Return: error code.
+ */
+int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
+ struct dsi_host_config *config);
+
+/**
+ * dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers
+ * @phy: DSI PHY handle
+ * @delay: pipe delays for dynamic refresh
+ * @is_master: Boolean to indicate if for master or slave
+ */
+void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
+ struct dsi_dyn_clk_delay *delay,
+ bool is_master);
+/**
+ * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
+ * @phy: DSI PHY handle
+ * @is_master: Boolean to indicate if for master or slave.
+ */
+void dsi_phy_dynamic_refresh_trigger(struct msm_dsi_phy *phy, bool is_master);
+
+/**
+ * dsi_phy_dynamic_refresh_clear() - clear dynamic refresh config
+ * @phy: DSI PHY handle
+ */
+void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy);
+
+/**
+ * dsi_phy_dyn_refresh_cache_phy_timings - cache the phy timings calculated
+ * as part of dynamic refresh.
+ * @phy: DSI PHY Handle.
+ * @dst: Pointer to cache location.
+ * @size: Number of phy lane settings.
+ */
+int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy,
+ u32 *dst, u32 size);
#endif /* _DSI_PHY_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
index d24a613..67a1157 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
@@ -159,6 +159,43 @@
bool (*is_lanes_in_ulps)(u32 ulps, u32 ulps_lanes);
};
+struct phy_dyn_refresh_ops {
+ /**
+ * dyn_refresh_helper - helper function to config particular registers
+ * @phy: Pointer to DSI PHY hardware instance.
+ * @offset: register offset to program.
+ */
+ void (*dyn_refresh_helper)(struct dsi_phy_hw *phy, u32 offset);
+
+ /**
+ * dyn_refresh_config - configure dynamic refresh ctrl registers
+ * @phy: Pointer to DSI PHY hardware instance.
+ * @cfg: Pointer to DSI PHY timings.
+ * @is_master: Boolean to indicate whether for master or slave.
+ */
+ void (*dyn_refresh_config)(struct dsi_phy_hw *phy,
+ struct dsi_phy_cfg *cfg, bool is_master);
+
+ /**
+ * dyn_refresh_pipe_delay - configure pipe delay registers for dynamic
+ * refresh.
+ * @phy: Pointer to DSI PHY hardware instance.
+ * @delay: structure containing all the delays to be programed.
+ */
+ void (*dyn_refresh_pipe_delay)(struct dsi_phy_hw *phy,
+ struct dsi_dyn_clk_delay *delay);
+
+ /**
+ * cache_phy_timings - cache the phy timings calculated as part of
+ * dynamic refresh.
+ * @timings: Pointer to calculated phy timing parameters.
+ * @dst: Pointer to cache location.
+ * @size: Number of phy lane settings.
+ */
+ int (*cache_phy_timings)(struct dsi_phy_per_lane_cfgs *timings,
+ u32 *dst, u32 size);
+};
+
/**
* struct dsi_phy_hw_ops - Operations for DSI PHY hardware.
* @regulator_enable: Enable PHY regulators.
@@ -218,11 +255,14 @@
* @mode: Mode information for which timing has to be calculated.
* @config: DSI host configuration for this mode.
* @timing: Timing parameters for each lane which will be returned.
+ * @use_mode_bit_clk: Boolean to indicate whether reacalculate dsi
+ * bitclk or use the existing bitclk(for dynamic clk case).
*/
int (*calculate_timing_params)(struct dsi_phy_hw *phy,
struct dsi_mode_info *mode,
struct dsi_host_common_cfg *config,
- struct dsi_phy_per_lane_cfgs *timing);
+ struct dsi_phy_per_lane_cfgs *timing,
+ bool use_mode_bit_clk);
/**
* phy_timing_val() - Gets PHY timing values.
@@ -257,12 +297,15 @@
void *timing_ops;
struct phy_ulps_config_ops ulps_ops;
+ struct phy_dyn_refresh_ops dyn_refresh_ops;
};
/**
* struct dsi_phy_hw - DSI phy hardware object specific to an instance
* @base: VA for the DSI PHY base address.
* @length: Length of the DSI PHY register base map.
+ * @dyn_pll_base: VA for the DSI dynamic refresh base address.
+ * @length: Length of the DSI dynamic refresh register base map.
* @index: Instance ID of the controller.
* @version: DSI PHY version.
* @feature_map: Features supported by DSI PHY.
@@ -271,6 +314,8 @@
struct dsi_phy_hw {
void __iomem *base;
u32 length;
+ void __iomem *dyn_pll_base;
+ u32 dyn_refresh_len;
u32 index;
enum dsi_phy_version version;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
index 1d4f2ab..6c6286d 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
@@ -51,7 +51,6 @@
#define DSIPHY_CMN_LANE_STATUS0 0x0F4
#define DSIPHY_CMN_LANE_STATUS1 0x0F8
-
/* n = 0..3 for data lanes and n = 4 for clock lane */
#define DSIPHY_LNX_CFG0(n) (0x200 + (0x80 * (n)))
#define DSIPHY_LNX_CFG1(n) (0x204 + (0x80 * (n)))
@@ -66,6 +65,47 @@
#define DSIPHY_LNX_LPRX_CTRL(n) (0x228 + (0x80 * (n)))
#define DSIPHY_LNX_TX_DCTRL(n) (0x22C + (0x80 * (n)))
+/* dynamic refresh control registers */
+#define DSI_DYN_REFRESH_CTRL (0x000)
+#define DSI_DYN_REFRESH_PIPE_DELAY (0x004)
+#define DSI_DYN_REFRESH_PIPE_DELAY2 (0x008)
+#define DSI_DYN_REFRESH_PLL_DELAY (0x00C)
+#define DSI_DYN_REFRESH_STATUS (0x010)
+#define DSI_DYN_REFRESH_PLL_CTRL0 (0x014)
+#define DSI_DYN_REFRESH_PLL_CTRL1 (0x018)
+#define DSI_DYN_REFRESH_PLL_CTRL2 (0x01C)
+#define DSI_DYN_REFRESH_PLL_CTRL3 (0x020)
+#define DSI_DYN_REFRESH_PLL_CTRL4 (0x024)
+#define DSI_DYN_REFRESH_PLL_CTRL5 (0x028)
+#define DSI_DYN_REFRESH_PLL_CTRL6 (0x02C)
+#define DSI_DYN_REFRESH_PLL_CTRL7 (0x030)
+#define DSI_DYN_REFRESH_PLL_CTRL8 (0x034)
+#define DSI_DYN_REFRESH_PLL_CTRL9 (0x038)
+#define DSI_DYN_REFRESH_PLL_CTRL10 (0x03C)
+#define DSI_DYN_REFRESH_PLL_CTRL11 (0x040)
+#define DSI_DYN_REFRESH_PLL_CTRL12 (0x044)
+#define DSI_DYN_REFRESH_PLL_CTRL13 (0x048)
+#define DSI_DYN_REFRESH_PLL_CTRL14 (0x04C)
+#define DSI_DYN_REFRESH_PLL_CTRL15 (0x050)
+#define DSI_DYN_REFRESH_PLL_CTRL16 (0x054)
+#define DSI_DYN_REFRESH_PLL_CTRL17 (0x058)
+#define DSI_DYN_REFRESH_PLL_CTRL18 (0x05C)
+#define DSI_DYN_REFRESH_PLL_CTRL19 (0x060)
+#define DSI_DYN_REFRESH_PLL_CTRL20 (0x064)
+#define DSI_DYN_REFRESH_PLL_CTRL21 (0x068)
+#define DSI_DYN_REFRESH_PLL_CTRL22 (0x06C)
+#define DSI_DYN_REFRESH_PLL_CTRL23 (0x070)
+#define DSI_DYN_REFRESH_PLL_CTRL24 (0x074)
+#define DSI_DYN_REFRESH_PLL_CTRL25 (0x078)
+#define DSI_DYN_REFRESH_PLL_CTRL26 (0x07C)
+#define DSI_DYN_REFRESH_PLL_CTRL27 (0x080)
+#define DSI_DYN_REFRESH_PLL_CTRL28 (0x084)
+#define DSI_DYN_REFRESH_PLL_CTRL29 (0x088)
+#define DSI_DYN_REFRESH_PLL_CTRL30 (0x08C)
+#define DSI_DYN_REFRESH_PLL_CTRL31 (0x090)
+#define DSI_DYN_REFRESH_PLL_UPPER_ADDR (0x094)
+#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2 (0x098)
+
static inline int dsi_conv_phy_to_logical_lane(
struct dsi_lane_map *lane_map, enum dsi_phy_data_lanes phy_lane)
{
@@ -500,3 +540,163 @@
timing_cfg->lane_v3[i] = timing_val[i];
return 0;
}
+
+void dsi_phy_hw_v3_0_dyn_refresh_config(struct dsi_phy_hw *phy,
+ struct dsi_phy_cfg *cfg, bool is_master)
+{
+ u32 reg;
+
+ if (is_master) {
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
+ DSIPHY_CMN_GLBL_CTRL, DSIPHY_CMN_VREG_CTRL,
+ 0x10, 0x59);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10,
+ DSIPHY_CMN_TIMING_CTRL_0, DSIPHY_CMN_TIMING_CTRL_1,
+ cfg->timing.lane_v3[0], cfg->timing.lane_v3[1]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11,
+ DSIPHY_CMN_TIMING_CTRL_2, DSIPHY_CMN_TIMING_CTRL_3,
+ cfg->timing.lane_v3[2], cfg->timing.lane_v3[3]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12,
+ DSIPHY_CMN_TIMING_CTRL_4, DSIPHY_CMN_TIMING_CTRL_5,
+ cfg->timing.lane_v3[4], cfg->timing.lane_v3[5]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13,
+ DSIPHY_CMN_TIMING_CTRL_6, DSIPHY_CMN_TIMING_CTRL_7,
+ cfg->timing.lane_v3[6], cfg->timing.lane_v3[7]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14,
+ DSIPHY_CMN_TIMING_CTRL_8, DSIPHY_CMN_TIMING_CTRL_9,
+ cfg->timing.lane_v3[8], cfg->timing.lane_v3[9]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15,
+ DSIPHY_CMN_TIMING_CTRL_10, DSIPHY_CMN_TIMING_CTRL_11,
+ cfg->timing.lane_v3[10], cfg->timing.lane_v3[11]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL16,
+ DSIPHY_CMN_CTRL_0, DSIPHY_CMN_LANE_CTRL0,
+ 0x7f, 0x1f);
+ } else {
+ reg = DSI_R32(phy, DSIPHY_CMN_CLK_CFG0);
+ reg &= ~BIT(5);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
+ DSIPHY_CMN_CLK_CFG0, DSIPHY_CMN_PLL_CNTRL,
+ reg, 0x0);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1,
+ DSIPHY_CMN_RBUF_CTRL, DSIPHY_CMN_GLBL_CTRL,
+ 0x0, 0x10);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
+ DSIPHY_CMN_VREG_CTRL, DSIPHY_CMN_TIMING_CTRL_0,
+ 0x59, cfg->timing.lane_v3[0]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
+ DSIPHY_CMN_TIMING_CTRL_1, DSIPHY_CMN_TIMING_CTRL_2,
+ cfg->timing.lane_v3[1], cfg->timing.lane_v3[2]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
+ DSIPHY_CMN_TIMING_CTRL_3, DSIPHY_CMN_TIMING_CTRL_4,
+ cfg->timing.lane_v3[3], cfg->timing.lane_v3[4]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
+ DSIPHY_CMN_TIMING_CTRL_5, DSIPHY_CMN_TIMING_CTRL_6,
+ cfg->timing.lane_v3[5], cfg->timing.lane_v3[6]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
+ DSIPHY_CMN_TIMING_CTRL_7, DSIPHY_CMN_TIMING_CTRL_8,
+ cfg->timing.lane_v3[7], cfg->timing.lane_v3[8]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
+ DSIPHY_CMN_TIMING_CTRL_9, DSIPHY_CMN_TIMING_CTRL_10,
+ cfg->timing.lane_v3[9], cfg->timing.lane_v3[10]);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
+ DSIPHY_CMN_TIMING_CTRL_11, DSIPHY_CMN_CTRL_0,
+ cfg->timing.lane_v3[11], 0x7f);
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
+ DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_2,
+ 0x1f, 0x40);
+ /*
+ * fill with dummy register writes since controller will blindly
+ * send these values to DSI PHY.
+ */
+ reg = DSI_DYN_REFRESH_PLL_CTRL11;
+ while (reg <= DSI_DYN_REFRESH_PLL_CTRL29) {
+ DSI_DYN_REF_REG_W(phy->dyn_pll_base, reg,
+ DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_0,
+ 0x1f, 0x7f);
+ reg += 0x4;
+ }
+
+ DSI_GEN_W32(phy->dyn_pll_base,
+ DSI_DYN_REFRESH_PLL_UPPER_ADDR, 0);
+ DSI_GEN_W32(phy->dyn_pll_base,
+ DSI_DYN_REFRESH_PLL_UPPER_ADDR2, 0);
+ }
+
+ wmb(); /* make sure all registers are updated */
+}
+
+void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
+ struct dsi_dyn_clk_delay *delay)
+{
+ if (!delay)
+ return;
+
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY,
+ delay->pipe_delay);
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2,
+ delay->pipe_delay2);
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY,
+ delay->pll_delay);
+}
+
+void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset)
+{
+ u32 reg;
+
+ /*
+ * if no offset is mentioned then this means we want to clear
+ * the dynamic refresh ctrl register which is the last step
+ * of dynamic refresh sequence.
+ */
+ if (!offset) {
+ reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+ reg &= ~(BIT(0) | BIT(8));
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+ wmb(); /* ensure dynamic fps is cleared */
+ return;
+ }
+
+ if (offset & BIT(DYN_REFRESH_INTF_SEL)) {
+ reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+ reg |= BIT(13);
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+ }
+
+ if (offset & BIT(DYN_REFRESH_SYNC_MODE)) {
+ reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+ reg |= BIT(16);
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+ }
+
+ if (offset & BIT(DYN_REFRESH_SWI_CTRL)) {
+ reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+ reg |= BIT(0);
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+ }
+
+ if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) {
+ reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+ reg |= BIT(8);
+ DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+ wmb(); /* ensure dynamic fps is triggered */
+ }
+}
+
+int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
+ u32 *dst, u32 size)
+{
+ int i;
+
+ if (!timings || !dst || !size)
+ return -EINVAL;
+
+ if (size != DSI_PHY_TIMING_V3_SIZE) {
+ pr_err("size mis-match\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i++)
+ dst[i] = timings->lane_v3[i];
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c
index fdfaa5d..44d0928 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c
@@ -511,11 +511,14 @@
* @mode: Mode information for which timing has to be calculated.
* @config: DSI host configuration for this mode.
* @timing: Timing parameters for each lane which will be returned.
+ * @use_mode_bit_clk: Boolean to indicate whether reacalculate dsi
+ * bit clk or use the existing bit clk(for dynamic clk case).
*/
int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy,
- struct dsi_mode_info *mode,
- struct dsi_host_common_cfg *host,
- struct dsi_phy_per_lane_cfgs *timing)
+ struct dsi_mode_info *mode,
+ struct dsi_host_common_cfg *host,
+ struct dsi_phy_per_lane_cfgs *timing,
+ bool use_mode_bit_clk)
{
/* constants */
u32 const esc_clk_mhz = 192; /* TODO: esc clock is hardcoded */
@@ -541,7 +544,7 @@
struct phy_timing_ops *ops = phy->ops.timing_ops;
memset(&desc, 0x0, sizeof(desc));
- h_total = DSI_H_TOTAL(mode);
+ h_total = DSI_H_TOTAL_DSC(mode);
v_total = DSI_V_TOTAL(mode);
bpp = bits_per_pixel[host->dst_format];
@@ -558,7 +561,10 @@
num_of_lanes++;
- x = mult_frac(v_total * h_total, inter_num, num_of_lanes);
+ if (use_mode_bit_clk)
+ x = mode->clk_rate_hz;
+ else
+ x = mult_frac(v_total * h_total, inter_num, num_of_lanes);
y = rounddown(x, 1);
clk_params.bitclk_mbps = rounddown(DIV_ROUND_UP_ULL(y, 1000000), 1);
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 20cae2e..a4d71f7 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -124,7 +124,8 @@
int conn_cnt = 0;
if (msm_is_mode_seamless(&crtc_state->mode) ||
- msm_is_mode_seamless_vrr(&crtc_state->adjusted_mode))
+ msm_is_mode_seamless_vrr(&crtc_state->adjusted_mode) ||
+ msm_is_mode_seamless_dyn_clk(&crtc_state->adjusted_mode))
return true;
if (msm_is_mode_seamless_dms(&crtc_state->adjusted_mode) && !enable)
@@ -168,6 +169,10 @@
&connector->encoder->crtc->state->adjusted_mode))
return true;
+ if (msm_is_mode_seamless_dyn_clk(
+ &connector->encoder->crtc->state->adjusted_mode))
+ return true;
+
if (msm_is_mode_seamless_dms(
&connector->encoder->crtc->state->adjusted_mode))
return true;
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index e99ff9c..f5f6853 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -38,6 +38,8 @@
#define MSM_MODE_FLAG_SEAMLESS_DMS (1<<2)
/* Request to switch the fps */
#define MSM_MODE_FLAG_SEAMLESS_VRR (1<<3)
+/* Request to switch the bit clk */
+#define MSM_MODE_FLAG_SEAMLESS_DYN_CLK (1<<4)
/* As there are different display controller blocks depending on the
* snapdragon version, the kms support is split out and the appropriate
@@ -175,6 +177,13 @@
: false;
}
+static inline bool msm_is_mode_seamless_dyn_clk(
+ const struct drm_display_mode *mode)
+{
+ return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYN_CLK)
+ : false;
+}
+
static inline bool msm_needs_vblank_pre_modeset(
const struct drm_display_mode *mode)
{
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 04f16ca..85b9f7e 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -1949,6 +1949,9 @@
sde_kms_info_add_keystr(info, "mode_name", mode->name);
+ sde_kms_info_add_keyint(info, "bit_clk_rate",
+ mode_info.clk_rate);
+
topology_idx = (int)sde_rm_get_topology_name(
mode_info.topology);
if (topology_idx < SDE_RM_TOPOLOGY_MAX) {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 73829da..e0094d7 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -748,8 +748,9 @@
SDE_DEBUG("\n");
if ((msm_is_mode_seamless(adjusted_mode) ||
- msm_is_mode_seamless_vrr(adjusted_mode)) &&
- (!crtc->enabled)) {
+ (msm_is_mode_seamless_vrr(adjusted_mode) ||
+ msm_is_mode_seamless_dyn_clk(adjusted_mode))) &&
+ (!crtc->enabled)) {
SDE_ERROR("crtc state prevents seamless transition\n");
return false;
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 6876796..a769915 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, 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
@@ -472,6 +472,7 @@
{
struct kgsl_device *device;
struct adreno_device *adreno_dev;
+ struct adreno_gpudev *gpudev;
struct adreno_context *drawctxt;
struct adreno_ringbuffer *rb;
int ret, count, i;
@@ -482,6 +483,7 @@
device = context->device;
adreno_dev = ADRENO_DEVICE(device);
+ gpudev = ADRENO_GPU_DEVICE(adreno_dev);
drawctxt = ADRENO_CONTEXT(context);
rb = drawctxt->rb;
@@ -562,6 +564,9 @@
mutex_unlock(&device->mutex);
+ if (gpudev->preemption_context_destroy)
+ gpudev->preemption_context_destroy(context);
+
/* wake threads waiting to submit commands from this context */
wake_up_all(&drawctxt->waiting);
wake_up_all(&drawctxt->wq);
@@ -570,18 +575,10 @@
void adreno_drawctxt_destroy(struct kgsl_context *context)
{
struct adreno_context *drawctxt;
- struct adreno_device *adreno_dev;
- struct adreno_gpudev *gpudev;
if (context == NULL)
return;
- adreno_dev = ADRENO_DEVICE(context->device);
- gpudev = ADRENO_GPU_DEVICE(adreno_dev);
-
- if (gpudev->preemption_context_destroy)
- gpudev->preemption_context_destroy(context);
-
drawctxt = ADRENO_CONTEXT(context);
kfree(drawctxt);
}
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
index 0ba4faa..4db9da1 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
@@ -1951,7 +1951,7 @@
return retval;
}
- retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
+ retval = fwu_wait_for_idle(WRITE_WAIT_MS, true);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to wait for idle status (%d blocks remaining)\n",
@@ -1961,6 +1961,8 @@
block_ptr += (transfer * fwu->block_size);
remaining -= transfer;
+ dev_dbg(rmi4_data->pdev->dev.parent, "%s: remaining %d\n",
+ __func__, remaining);
} while (remaining);
return 0;
@@ -2010,7 +2012,7 @@
return retval;
}
- retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
+ retval = fwu_wait_for_idle(WRITE_WAIT_MS, true);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to wait for idle status (block %d)\n",
@@ -2019,6 +2021,8 @@
}
block_ptr += fwu->block_size;
+ dev_dbg(rmi4_data->pdev->dev.parent, "%s: remaining %d\n",
+ __func__, block_cnt - blk);
}
return 0;
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vdec.c b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
index bb4b6c8..2ff610a 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
@@ -1943,6 +1943,7 @@
inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = DEFAULT_FPS;
+ inst->prop.operating_rate = 0;
memcpy(&inst->fmts[OUTPUT_PORT], &vdec_formats[2],
sizeof(struct msm_vidc_format));
memcpy(&inst->fmts[CAPTURE_PORT], &vdec_formats[0],
@@ -2551,8 +2552,33 @@
*/
hal_property.enable = !(ctrl->val);
pdata = &hal_property;
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE:
+ inst->flags &= ~VIDC_REALTIME;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE:
+ inst->flags |= VIDC_REALTIME;
+ break;
+ default:
+ dprintk(VIDC_WARN,
+ "inst(%pK) invalid priority ctrl value %#x\n",
+ inst, ctrl->val);
+ break;
+ }
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+ if ((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+ (ctrl->val >> 16) > inst->capability.frame_rate.max) {
+ dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+ (ctrl->val >> 16));
+ rc = -ENOTSUPP;
+ } else {
+ dprintk(VIDC_DBG,
+ "inst(%pK) operating rate changed from %d to %d\n",
+ inst, inst->prop.operating_rate >> 16,
+ ctrl->val >> 16);
+ inst->prop.operating_rate = ctrl->val;
+ }
break;
default:
break;
diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.c b/drivers/media/platform/msm/vidc_3x/msm_venc.c
index ef6e360..5e98a5c 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_venc.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_venc.c
@@ -3625,8 +3625,33 @@
*/
enable.enable = !(ctrl->val);
pdata = &enable;
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE:
+ inst->flags &= ~VIDC_REALTIME;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE:
+ inst->flags |= VIDC_REALTIME;
+ break;
+ default:
+ dprintk(VIDC_WARN,
+ "inst(%pK) invalid priority ctrl value %#x\n",
+ inst, ctrl->val);
+ break;
+ }
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+ if ((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+ (ctrl->val >> 16) > inst->capability.frame_rate.max) {
+ dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+ (ctrl->val >> 16));
+ rc = -ENOTSUPP;
+ } else {
+ dprintk(VIDC_DBG,
+ "inst(%pK) operating rate changed from %d to %d\n",
+ inst, inst->prop.operating_rate >> 16,
+ ctrl->val >> 16);
+ inst->prop.operating_rate = ctrl->val;
+ }
break;
case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
{
@@ -4067,6 +4092,7 @@
inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = DEFAULT_FPS;
+ inst->prop.operating_rate = 0;
inst->capability.pixelprocess_capabilities = 0;
memcpy(&inst->fmts[CAPTURE_PORT], &venc_formats[4],
sizeof(struct msm_vidc_format));
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
index 998b397..a80ae03 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
@@ -258,14 +258,9 @@
return 0;
}
-static inline bool is_non_realtime_session(struct msm_vidc_inst *inst)
+static inline bool is_realtime_session(struct msm_vidc_inst *inst)
{
- int rc = 0;
- struct v4l2_control ctrl = {
- .id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY
- };
- rc = msm_comm_g_ctrl(inst, &ctrl);
- return (!rc && ctrl.value);
+ return !!(inst->flags & VIDC_REALTIME);
}
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst)
@@ -297,17 +292,15 @@
static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
{
- int rc;
u32 fps;
- struct v4l2_control ctrl;
int mb_per_frame;
+ u32 oper_rate;
mb_per_frame = msm_comm_get_mbs_per_frame(inst);
+ oper_rate = inst->prop.operating_rate;
- ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE;
- rc = msm_comm_g_ctrl(inst, &ctrl);
- if (!rc && ctrl.value) {
- fps = (ctrl.value >> 16) ? ctrl.value >> 16 : 1;
+ if (oper_rate) {
+ fps = (oper_rate >> 16) ? oper_rate >> 16 : 1;
/*
* Check if operating rate is less than fps.
* If Yes, then use fps to scale the clocks
@@ -354,7 +347,7 @@
* ----------------|----------------------|------------------------|
*/
- if (is_non_realtime_session(inst) &&
+ if (is_realtime_session(inst) &&
(quirks & LOAD_CALC_IGNORE_NON_REALTIME_LOAD)) {
if (!inst->prop.fps) {
dprintk(VIDC_INFO, "instance:%pK fps = 0\n", inst);
@@ -535,7 +528,7 @@
list_for_each_entry(inst, &core->instances, list) {
int codec = 0, yuv = 0;
- struct v4l2_control ctrl;
+ u32 oper_rate;
codec = inst->session_type == MSM_VIDC_DECODER ?
inst->fmts[OUTPUT_PORT].fourcc :
@@ -552,11 +545,11 @@
vote_data[i].height = max(inst->prop.height[CAPTURE_PORT],
inst->prop.height[OUTPUT_PORT]);
- ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE;
- rc = msm_comm_g_ctrl(inst, &ctrl);
- if (!rc && ctrl.value)
- vote_data[i].fps = (ctrl.value >> 16) ?
- ctrl.value >> 16 : 1;
+ oper_rate = inst->prop.operating_rate;
+
+ if (oper_rate)
+ vote_data[i].fps = (oper_rate >> 16) ?
+ oper_rate >> 16 : 1;
else
vote_data[i].fps = inst->prop.fps;
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
index 00cbafb..56b86d7 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
@@ -173,6 +173,7 @@
u32 height[MAX_PORT_NUM];
u32 fps;
u32 bitrate;
+ u32 operating_rate;
};
struct buf_queue {
@@ -239,6 +240,7 @@
VIDC_TURBO = BIT(1),
VIDC_THUMBNAIL = BIT(2),
VIDC_LOW_POWER = BIT(3),
+ VIDC_REALTIME = BIT(4),
};
struct msm_vidc_core {
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 1119292..7b221c3 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -94,6 +94,7 @@
#define CORE_DDR_DLL_LOCK (1 << 11)
#define CORE_CLK_PWRSAVE (1 << 1)
+#define CORE_VNDR_SPEC_ADMA_ERR_SIZE_EN (1 << 7)
#define CORE_HC_MCLK_SEL_DFLT (2 << 8)
#define CORE_HC_MCLK_SEL_HS400 (3 << 8)
#define CORE_HC_MCLK_SEL_MASK (3 << 8)
@@ -4924,6 +4925,12 @@
writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
+ /* This enable ADMA error interrupt in case of length mismatch */
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) |
+ CORE_VNDR_SPEC_ADMA_ERR_SIZE_EN),
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
+
/*
* Ensure SDHCI FIFO is enabled by disabling alternative FIFO
*/
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f446c66..01c8b90 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3289,7 +3289,7 @@
} else if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
host->mmc->err_stats[MMC_ERR_DAT_CRC]++;
return -EILSEQ;
- } else if (intmask & MMC_ERR_ADMA) {
+ } else if (intmask & SDHCI_INT_ADMA_ERROR) {
host->mmc->err_stats[MMC_ERR_ADMA]++;
return -EIO;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 690d564..ec1d4d9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -1771,7 +1771,7 @@
buff = kzalloc(buff_size, GFP_KERNEL);
if (buff == NULL)
- return 0;
+ return -ENOMEM;
if (!ipa3_ctx->nat_mem.dev.is_dev_init) {
pos += scnprintf(buff + pos, buff_size - pos,
diff --git a/drivers/soc/qcom/sysmon-qmi.c b/drivers/soc/qcom/sysmon-qmi.c
index f4c7779..ea4b5a5 100644
--- a/drivers/soc/qcom/sysmon-qmi.c
+++ b/drivers/soc/qcom/sysmon-qmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -88,6 +88,7 @@
static void sysmon_clnt_svc_exit(struct work_struct *work);
static const int notif_map[SUBSYS_NOTIF_TYPE_COUNT] = {
+ [0 ... SUBSYS_NOTIF_TYPE_COUNT - 1] = SSCTL_SSR_EVENT_INVALID,
[SUBSYS_BEFORE_POWERUP] = SSCTL_SSR_EVENT_BEFORE_POWERUP,
[SUBSYS_AFTER_POWERUP] = SSCTL_SSR_EVENT_AFTER_POWERUP,
[SUBSYS_BEFORE_SHUTDOWN] = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN,
@@ -147,6 +148,11 @@
}
}
+static bool is_ssctl_event(enum subsys_notif_type notif)
+{
+ return notif_map[notif] != SSCTL_SSR_EVENT_INVALID;
+}
+
static void sysmon_clnt_svc_arrive(struct work_struct *work)
{
int rc;
@@ -318,8 +324,8 @@
const char *dest_ss = dest_desc->name;
int ret;
- if (notif < 0 || notif >= SUBSYS_NOTIF_TYPE_COUNT || event_ss == NULL
- || dest_ss == NULL)
+ if (notif < 0 || notif >= SUBSYS_NOTIF_TYPE_COUNT ||
+ !is_ssctl_event(notif) || event_ss == NULL || dest_ss == NULL)
return -EINVAL;
mutex_lock(&sysmon_list_lock);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index dcc183d..359c09a 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -3735,6 +3735,7 @@
if (cpu_to_affin)
unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier);
put_dwc3:
+ platform_device_put(mdwc->dwc3);
if (mdwc->bus_perf_client)
msm_bus_scale_unregister_client(mdwc->bus_perf_client);
@@ -3788,6 +3789,7 @@
if (mdwc->hs_phy)
mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
+ platform_device_put(mdwc->dwc3);
of_platform_depopulate(&pdev->dev);
pm_runtime_disable(mdwc->dev);
diff --git a/drivers/usb/gadget/function/f_ipc.c b/drivers/usb/gadget/function/f_ipc.c
index b6ce9c9..a79a559 100644
--- a/drivers/usb/gadget/function/f_ipc.c
+++ b/drivers/usb/gadget/function/f_ipc.c
@@ -407,7 +407,6 @@
break;
ctxt->current_state = IPC_CONNECTED;
- ctxt->online = 1;
ctxt->pdev = platform_device_alloc("ipc_bridge", -1);
if (!ctxt->pdev)
goto pdev_fail;
@@ -431,9 +430,9 @@
if (ctxt->connected)
break;
- platform_device_unregister(ctxt->pdev);
ctxt->current_state = IPC_DISCONNECTED;
wake_up(&ctxt->state_wq);
+ platform_device_unregister(ctxt->pdev);
break;
default:
pr_debug("%s: Unknown current state\n", __func__);
@@ -442,7 +441,6 @@
return;
pdev_fail:
- ctxt->online = 0;
ctxt->current_state = IPC_DISCONNECTED;
return;
}
@@ -591,6 +589,7 @@
spin_lock_irqsave(&ctxt->lock, flags);
ctxt->connected = 1;
+ ctxt->online = 1;
spin_unlock_irqrestore(&ctxt->lock, flags);
schedule_work(&ctxt->func_work);
@@ -604,6 +603,7 @@
pr_debug("%s: Disabling\n", __func__);
spin_lock_irqsave(&ctxt->lock, flags);
+ ctxt->online = 0;
ctxt->connected = 0;
spin_unlock_irqrestore(&ctxt->lock, flags);
schedule_work(&ctxt->func_work);
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c
index defec0b..70864c4 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.c
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.c
@@ -151,16 +151,9 @@
return blocking_notifier_call_chain(&ses->notifier_head, event, ses);
}
-static void mdp3_dispatch_dma_done(struct kthread_work *work)
+static void __mdp3_dispatch_dma_done(struct mdp3_session_data *session)
{
- struct mdp3_session_data *session;
- int cnt = 0;
-
- pr_debug("%s\n", __func__);
- session = container_of(work, struct mdp3_session_data,
- dma_done_work);
- if (!session)
- return;
+ int cnt;
cnt = atomic_read(&session->dma_done_cnt);
MDSS_XLOG(cnt);
@@ -171,6 +164,29 @@
}
}
+void mdp3_flush_dma_done(struct mdp3_session_data *session)
+{
+ if (!session)
+ return;
+
+ pr_debug("%s\n", __func__);
+
+ __mdp3_dispatch_dma_done(session);
+}
+
+static void mdp3_dispatch_dma_done(struct kthread_work *work)
+{
+ struct mdp3_session_data *session;
+
+ pr_debug("%s\n", __func__);
+ session = container_of(work, struct mdp3_session_data,
+ dma_done_work);
+ if (!session)
+ return;
+
+ __mdp3_dispatch_dma_done(session);
+}
+
static void mdp3_dispatch_clk_off(struct work_struct *work)
{
struct mdp3_session_data *session;
@@ -3060,6 +3076,7 @@
pr_err("fail to init dma\n");
goto init_done;
}
+ mdp3_session->dma->session = mdp3_session;
intf_type = mdp3_ctrl_get_intf_type(mfd);
mdp3_session->intf = mdp3_get_display_intf(intf_type);
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.h b/drivers/video/fbdev/msm/mdp3_ctrl.h
index 64be356..de90127 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.h
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.h
@@ -91,5 +91,6 @@
int mdp3_ctrl_get_pack_pattern(u32 imgType);
int mdp3_ctrl_reset(struct msm_fb_data_type *mfd);
int mdp3_get_ion_client(struct msm_fb_data_type *mfd);
+void mdp3_flush_dma_done(struct mdp3_session_data *mdp3_session);
#endif /* MDP3_CTRL_H */
diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c
index c9356bd..f37c378 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.c
+++ b/drivers/video/fbdev/msm/mdp3_dma.c
@@ -16,6 +16,7 @@
#include "mdp3_dma.h"
#include "mdp3_hwio.h"
#include "mdss_debug.h"
+#include "mdp3_ctrl.h"
#define DMA_STOP_POLL_SLEEP_US 1000
#define DMA_STOP_POLL_TIMEOUT_US 200000
@@ -1080,6 +1081,16 @@
reinit_completion(&dma->dma_comp);
dma->vsync_client.handler = NULL;
+
+ /*
+ * Interrupts are disabled.
+ * Check for blocked dma done interrupt.
+ * Flush items waiting for dma done interrupt.
+ */
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD &&
+ atomic_read(&dma->session->dma_done_cnt))
+ mdp3_flush_dma_done(dma->session);
+
return ret;
}
diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h
index e0458f8..03d3cf0 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.h
+++ b/drivers/video/fbdev/msm/mdp3_dma.h
@@ -293,6 +293,8 @@
struct fb_cmap *gc_cmap;
struct fb_cmap *hist_cmap;
+ struct mdp3_session_data *session;
+
bool (*busy)(void);
int (*dma_config)(struct mdp3_dma *dma,
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 63f8553..850b872 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1908,7 +1908,7 @@
ret = mfd->mdp.off_fnc(mfd);
if (ret)
mfd->panel_power_state = cur_power_state;
- else if (mdss_panel_is_power_off(req_power_state))
+ else if (!mdss_panel_is_power_on_interactive(req_power_state))
mdss_fb_release_fences(mfd);
mfd->op_enable = true;
complete(&mfd->power_off_comp);
diff --git a/include/dt-bindings/clock/mdss-10nm-pll-clk.h b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
index 8108c98..f9781b5 100644
--- a/include/dt-bindings/clock/mdss-10nm-pll-clk.h
+++ b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -26,16 +26,32 @@
#define PCLK_SRC_MUX_0_CLK 7
#define PCLK_SRC_0_CLK 8
#define PCLK_MUX_0_CLK 9
-#define VCO_CLK_1 10
-#define PLL_OUT_DIV_1_CLK 11
-#define BITCLK_SRC_1_CLK 12
-#define BYTECLK_SRC_1_CLK 13
-#define POST_BIT_DIV_1_CLK 14
-#define POST_VCO_DIV_1_CLK 15
-#define BYTECLK_MUX_1_CLK 16
-#define PCLK_SRC_MUX_1_CLK 17
-#define PCLK_SRC_1_CLK 18
-#define PCLK_MUX_1_CLK 19
+#define SHADOW_VCO_CLK_0 10
+#define SHADOW_PLL_OUT_DIV_0_CLK 11
+#define SHADOW_BITCLK_SRC_0_CLK 12
+#define SHADOW_BYTECLK_SRC_0_CLK 13
+#define SHADOW_POST_BIT_DIV_0_CLK 14
+#define SHADOW_POST_VCO_DIV_0_CLK 15
+#define SHADOW_PCLK_SRC_MUX_0_CLK 16
+#define SHADOW_PCLK_SRC_0_CLK 17
+#define VCO_CLK_1 18
+#define PLL_OUT_DIV_1_CLK 19
+#define BITCLK_SRC_1_CLK 20
+#define BYTECLK_SRC_1_CLK 21
+#define POST_BIT_DIV_1_CLK 22
+#define POST_VCO_DIV_1_CLK 23
+#define BYTECLK_MUX_1_CLK 24
+#define PCLK_SRC_MUX_1_CLK 25
+#define PCLK_SRC_1_CLK 26
+#define PCLK_MUX_1_CLK 27
+#define SHADOW_VCO_CLK_1 28
+#define SHADOW_PLL_OUT_DIV_1_CLK 29
+#define SHADOW_BITCLK_SRC_1_CLK 30
+#define SHADOW_BYTECLK_SRC_1_CLK 31
+#define SHADOW_POST_BIT_DIV_1_CLK 32
+#define SHADOW_POST_VCO_DIV_1_CLK 33
+#define SHADOW_PCLK_SRC_MUX_1_CLK 34
+#define SHADOW_PCLK_SRC_1_CLK 35
/* DP PLL clocks */
#define DP_VCO_CLK 0
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 0fbce32..48bc2b7 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -425,6 +425,7 @@
#define CPUFREQ_CREATE_POLICY (3)
#define CPUFREQ_REMOVE_POLICY (4)
#define CPUFREQ_STOP (5)
+#define CPUFREQ_INCOMPATIBLE (6)
/* Govinfo Notifiers */
#define CPUFREQ_LOAD_CHANGE (0)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 47c5b39..d32e7b8 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -266,7 +266,7 @@
int capabilities;
int * __percpu pmu_disable_count;
- struct perf_cpu_context * __percpu pmu_cpu_context;
+ struct perf_cpu_context __percpu *pmu_cpu_context;
atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */
int task_ctx_nr;
int hrtimer_interval_ms;
diff --git a/include/soc/qcom/sysmon.h b/include/soc/qcom/sysmon.h
index 2ad3a5e..cca1dcc 100644
--- a/include/soc/qcom/sysmon.h
+++ b/include/soc/qcom/sysmon.h
@@ -40,6 +40,7 @@
*/
enum ssctl_ssr_event_enum_type {
SSCTL_SSR_EVENT_ENUM_TYPE_MIN_ENUM_VAL = -2147483647,
+ SSCTL_SSR_EVENT_INVALID = -1,
SSCTL_SSR_EVENT_BEFORE_POWERUP = 0,
SSCTL_SSR_EVENT_AFTER_POWERUP = 1,
SSCTL_SSR_EVENT_BEFORE_SHUTDOWN = 2,
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 475ec4f..340eccd 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -11216,13 +11216,25 @@
static void perf_event_exit_cpu_context(int cpu)
{
+ struct perf_cpu_context *cpuctx;
struct perf_event_context *ctx;
+ unsigned long flags;
struct pmu *pmu;
int idx;
idx = srcu_read_lock(&pmus_srcu);
list_for_each_entry_rcu(pmu, &pmus, entry) {
- ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
+ cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
+ ctx = &cpuctx->ctx;
+
+ /* Cancel the mux hrtimer to avoid CPU migration */
+ if (pmu->task_ctx_nr != perf_sw_context) {
+ raw_spin_lock_irqsave(&cpuctx->hrtimer_lock, flags);
+ hrtimer_cancel(&cpuctx->hrtimer);
+ cpuctx->hrtimer_active = 0;
+ raw_spin_unlock_irqrestore(&cpuctx->hrtimer_lock,
+ flags);
+ }
mutex_lock(&ctx->mutex);
smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);