Merge "drm/msm/sde: add mutex to the sde resource manager"
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index d0d7fff..59fa6a0 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -16,7 +16,7 @@
"qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8",
"qcom,mdss_edp_pll_8996_v3", "qcom,mdss_edp_pll_8996_v3_1p8",
"qcom,mdss_dsi_pll_10nm", "qcom,mdss_dp_pll_8998",
- "qcom,mdss_hdmi_pll_8998"
+ "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dp_pll_10nm".
- cell-index: Specifies the controller used
- reg: offset and length of the register set for the device.
- reg-names : names to refer to register sets related to this device
diff --git a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi
new file mode 100644
index 0000000..61ef7ff
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi
@@ -0,0 +1,53 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ system_heap: qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@22 { /* ADSP HEAP */
+ reg = <22>;
+ memory-region = <&adsp_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ qcom,ion-heap@27 { /* QSEECOM HEAP */
+ reg = <27>;
+ memory-region = <&qseecom_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ qcom,ion-heap@13 { /* SPSS HEAP */
+ reg = <13>;
+ memory-region = <&sp_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */
+ reg = <10>;
+ memory-region = <&secure_display_memory>;
+ qcom,ion-heap-type = "HYP_CMA";
+ };
+
+ qcom,ion-heap@9 {
+ reg = <9>;
+ qcom,ion-heap-type = "SYSTEM_SECURE";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 2cbb990..7bef48d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -279,9 +279,113 @@
#address-cells = <2>;
#size-cells = <2>;
ranges;
+
+ removed_regions: removed_regions@85700000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x85700000 0 0x3800000>;
+ };
+
+ pil_camera_mem: camera_region@8ab00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x8ab00000 0 0x500000>;
+ };
+
+ pil_modem_mem: modem_region@8b000000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x8b000000 0 0x7e00000>;
+ };
+
+ pil_video_mem: pil_video_region@92e00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x92e00000 0 0x500000>;
+ };
+
+ pil_cdsp_mem: cdsp_regions@93300000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x93300000 0 0x600000>;
+ };
+
+ pil_mba_mem: pil_mba_region@0x93900000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x93900000 0 0x200000>;
+ };
+
+ pil_adsp_mem: pil_adsp_region@93b00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x93b00000 0 0x1e00000>;
+ };
+
+ pil_ipa_fw_mem: pil_ipa_fw_region@95900000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x95900000 0 0x10000>;
+ };
+
+ pil_ipa_gsi_mem: pil_ipa_gsi_region@95910000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x95910000 0 0x5000>;
+ };
+
+ pil_gpu_mem: pil_gpu_region@95915000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x95915000 0 0x1000>;
+ };
+
+ adsp_mem: adsp_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0xc00000>;
+ };
+
+ qseecom_mem: qseecom_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x1400000>;
+ };
+
+ sp_mem: sp_region { /* SPSS-HLOS ION shared mem */
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>; /* 32-bit */
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x800000>;
+ };
+
+ secure_display_memory: secure_display_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x5c00000>;
+ };
+
+ /* global autoconfigured region for contiguous allocations */
+ linux,cma {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x2000000>;
+ linux,cma-default;
+ };
};
};
+#include "sdm670-ion.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
index fff9160..ef964ae 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
@@ -13,8 +13,13 @@
/dts-v1/;
/plugin/;
-#include "sdm845.dtsi"
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
#include "sdm845-cdp.dtsi"
+#include "sdm845-qupv3.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
index 79fa580..548bd49 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
@@ -13,8 +13,13 @@
/dts-v1/;
/plugin/;
-#include "sdm845.dtsi"
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
#include "sdm845-mtp.dtsi"
+#include "sdm845-qupv3.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index bf58da6..1500bb5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -368,10 +368,106 @@
cell-index = <0>;
label = "wb_display";
};
+
+ sde_dp: qcom,dp_display@0{
+ cell-index = <0>;
+ compatible = "qcom,dp-display";
+
+ gdsc-supply = <&mdss_core_gdsc>;
+ vdda-1p2-supply = <&pm8998_l26>;
+ vdda-0p9-supply = <&pm8998_l1>;
+
+ reg = <0xae90000 0xa84>,
+ <0x88eaa00 0x200>,
+ <0x88ea200 0x200>,
+ <0x88ea600 0x200>,
+ <0xaf02000 0x1a0>,
+ <0x780000 0x621c>,
+ <0x88ea030 0x10>,
+ <0x0aee1000 0x034>;
+ reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+ "dp_mmss_cc", "qfprom_physical", "dp_pll",
+ "hdcp_physical";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <12 0>;
+
+ clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+ <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
+ <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
+ clock-names = "core_aux_clk", "core_usb_ref_clk_src",
+ "core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+ "core_usb_pipe_clk", "ctrl_link_clk",
+ "ctrl_link_iface_clk", "ctrl_crypto_clk",
+ "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
+
+ qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+
+ qcom,aux-cfg-settings = [00 13 04 00 0a 26 0a 03 bb 03];
+
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <21800>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <880000>;
+ qcom,supply-enable-load = <36000>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+ };
+};
+
+&sde_dp {
+ pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+ pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>;
+ pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>;
+ qcom,aux-en-gpio = <&tlmm 43 0>;
+ qcom,aux-sel-gpio = <&tlmm 51 0>;
+ qcom,usbplug-cc-gpio = <&tlmm 38 0>;
};
&mdss_mdp {
- connectors = <&sde_rscc &sde_wb>;
+ connectors = <&sde_rscc &sde_wb &sde_dp>;
};
&dsi_dual_nt35597_truly_video {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
index 168f2a9..b9eac3c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
@@ -64,4 +64,46 @@
};
};
};
+
+ mdss_dp_pll: qcom,mdss_dp_pll@c011000 {
+ compatible = "qcom,mdss_dp_pll_10nm";
+ label = "MDSS DP PLL";
+ cell-index = <0>;
+ #clock-cells = <1>;
+
+ reg = <0x088ea000 0x200>,
+ <0x088eaa00 0x200>,
+ <0x088ea200 0x200>,
+ <0x088ea600 0x200>,
+ <0xaf03000 0x8>;
+ reg-names = "pll_base", "phy_base", "ln_tx0_base",
+ "ln_tx1_base", "gdsc_base";
+
+ gdsc-supply = <&mdss_core_gdsc>;
+
+ clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+ clock-names = "iface_clk", "ref_clk_src", "ref_clk",
+ "cfg_ahb_clk", "pipe_clk";
+ clock-rate = <0>;
+
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+
+ };
+ };
+
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index 4fe9282..af12224 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -27,6 +27,10 @@
qcom,max-secure-instances = <5>;
qcom,max-hw-load = <2563200>; /* Full 4k @ 60 + 1080p @ 60 */
+ /* LLCC Info */
+ cache-slice-names = "vidsc0", "vidsc1";
+ cache-slices = <&llcc 2>, <&llcc 3>;
+
/* Supply */
venus-supply = <&venus_gdsc>;
venus-core0-supply = <&vcodec0_gdsc>;
@@ -91,6 +95,14 @@
qcom,bus-governor = "performance";
qcom,bus-range-kbps = <1000 1000>;
};
+ venus_bus_llcc {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-llcc";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_LLCC>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <17000 125700>;
+ };
/* MMUs */
non_secure_cb {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 16bd53a..c89a05e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -459,6 +459,22 @@
compatible = "simple-bus";
};
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ vendor {
+ compatible = "android,vendor";
+ dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,slotselect";
+ };
+ };
+ };
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
diff --git a/drivers/clk/qcom/mdss/Makefile b/drivers/clk/qcom/mdss/Makefile
index d183393..87feee6 100644
--- a/drivers/clk/qcom/mdss/Makefile
+++ b/drivers/clk/qcom/mdss/Makefile
@@ -1,3 +1,6 @@
obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll-util.o
obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll.o
obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-10nm.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-10nm.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-10nm-util.o
+
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c
new file mode 100644
index 0000000..eb2092a
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c
@@ -0,0 +1,766 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/usb/usbpd.h>
+
+#include "mdss-pll.h"
+#include "mdss-dp-pll.h"
+#include "mdss-dp-pll-10nm.h"
+
+#define DP_PHY_REVISION_ID0 0x0000
+#define DP_PHY_REVISION_ID1 0x0004
+#define DP_PHY_REVISION_ID2 0x0008
+#define DP_PHY_REVISION_ID3 0x000C
+
+#define DP_PHY_CFG 0x0010
+#define DP_PHY_PD_CTL 0x0018
+#define DP_PHY_MODE 0x001C
+
+#define DP_PHY_AUX_CFG0 0x0020
+#define DP_PHY_AUX_CFG1 0x0024
+#define DP_PHY_AUX_CFG2 0x0028
+#define DP_PHY_AUX_CFG3 0x002C
+#define DP_PHY_AUX_CFG4 0x0030
+#define DP_PHY_AUX_CFG5 0x0034
+#define DP_PHY_AUX_CFG6 0x0038
+#define DP_PHY_AUX_CFG7 0x003C
+#define DP_PHY_AUX_CFG8 0x0040
+#define DP_PHY_AUX_CFG9 0x0044
+#define DP_PHY_AUX_INTERRUPT_MASK 0x0048
+#define DP_PHY_AUX_INTERRUPT_CLEAR 0x004C
+#define DP_PHY_AUX_BIST_CFG 0x0050
+
+#define DP_PHY_VCO_DIV 0x0064
+#define DP_PHY_TX0_TX1_LANE_CTL 0x006C
+#define DP_PHY_TX2_TX3_LANE_CTL 0x0088
+
+#define DP_PHY_SPARE0 0x00AC
+#define DP_PHY_STATUS 0x00C0
+
+/* Tx registers */
+#define TXn_BIST_MODE_LANENO 0x0000
+#define TXn_CLKBUF_ENABLE 0x0008
+#define TXn_TX_EMP_POST1_LVL 0x000C
+
+#define TXn_TX_DRV_LVL 0x001C
+
+#define TXn_RESET_TSYNC_EN 0x0024
+#define TXn_PRE_STALL_LDO_BOOST_EN 0x0028
+#define TXn_TX_BAND 0x002C
+#define TXn_SLEW_CNTL 0x0030
+#define TXn_INTERFACE_SELECT 0x0034
+
+#define TXn_RES_CODE_LANE_TX 0x003C
+#define TXn_RES_CODE_LANE_RX 0x0040
+#define TXn_RES_CODE_LANE_OFFSET_TX 0x0044
+#define TXn_RES_CODE_LANE_OFFSET_RX 0x0048
+
+#define TXn_DEBUG_BUS_SEL 0x0058
+#define TXn_TRANSCEIVER_BIAS_EN 0x005C
+#define TXn_HIGHZ_DRVR_EN 0x0060
+#define TXn_TX_POL_INV 0x0064
+#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0068
+
+#define TXn_LANE_MODE_1 0x008C
+
+#define TXn_TRAN_DRVR_EMP_EN 0x00C0
+#define TXn_TX_INTERFACE_MODE 0x00C4
+
+#define TXn_VMODE_CTRL1 0x00F0
+
+/* PLL register offset */
+#define QSERDES_COM_ATB_SEL1 0x0000
+#define QSERDES_COM_ATB_SEL2 0x0004
+#define QSERDES_COM_FREQ_UPDATE 0x0008
+#define QSERDES_COM_BG_TIMER 0x000C
+#define QSERDES_COM_SSC_EN_CENTER 0x0010
+#define QSERDES_COM_SSC_ADJ_PER1 0x0014
+#define QSERDES_COM_SSC_ADJ_PER2 0x0018
+#define QSERDES_COM_SSC_PER1 0x001C
+#define QSERDES_COM_SSC_PER2 0x0020
+#define QSERDES_COM_SSC_STEP_SIZE1 0x0024
+#define QSERDES_COM_SSC_STEP_SIZE2 0x0028
+#define QSERDES_COM_POST_DIV 0x002C
+#define QSERDES_COM_POST_DIV_MUX 0x0030
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0034
+#define QSERDES_COM_CLK_ENABLE1 0x0038
+#define QSERDES_COM_SYS_CLK_CTRL 0x003C
+#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0040
+#define QSERDES_COM_PLL_EN 0x0044
+#define QSERDES_COM_PLL_IVCO 0x0048
+#define QSERDES_COM_CMN_IETRIM 0x004C
+#define QSERDES_COM_CMN_IPTRIM 0x0050
+
+#define QSERDES_COM_CP_CTRL_MODE0 0x0060
+#define QSERDES_COM_CP_CTRL_MODE1 0x0064
+#define QSERDES_COM_PLL_RCTRL_MODE0 0x0068
+#define QSERDES_COM_PLL_RCTRL_MODE1 0x006C
+#define QSERDES_COM_PLL_CCTRL_MODE0 0x0070
+#define QSERDES_COM_PLL_CCTRL_MODE1 0x0074
+#define QSERDES_COM_PLL_CNTRL 0x0078
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x007C
+#define QSERDES_COM_SYSCLK_EN_SEL 0x0080
+#define QSERDES_COM_CML_SYSCLK_SEL 0x0084
+#define QSERDES_COM_RESETSM_CNTRL 0x0088
+#define QSERDES_COM_RESETSM_CNTRL2 0x008C
+#define QSERDES_COM_LOCK_CMP_EN 0x0090
+#define QSERDES_COM_LOCK_CMP_CFG 0x0094
+#define QSERDES_COM_LOCK_CMP1_MODE0 0x0098
+#define QSERDES_COM_LOCK_CMP2_MODE0 0x009C
+#define QSERDES_COM_LOCK_CMP3_MODE0 0x00A0
+
+#define QSERDES_COM_DEC_START_MODE0 0x00B0
+#define QSERDES_COM_DEC_START_MODE1 0x00B4
+#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00B8
+#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00BC
+#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00C0
+#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x00C4
+#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x00C8
+#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x00CC
+#define QSERDES_COM_INTEGLOOP_INITVAL 0x00D0
+#define QSERDES_COM_INTEGLOOP_EN 0x00D4
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x00D8
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x00DC
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x00E0
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x00E4
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x00E8
+#define QSERDES_COM_VCO_TUNE_CTRL 0x00EC
+#define QSERDES_COM_VCO_TUNE_MAP 0x00F0
+
+#define QSERDES_COM_CMN_STATUS 0x0124
+#define QSERDES_COM_RESET_SM_STATUS 0x0128
+
+#define QSERDES_COM_CLK_SEL 0x0138
+#define QSERDES_COM_HSCLK_SEL 0x013C
+
+#define QSERDES_COM_CORECLK_DIV_MODE0 0x0148
+
+#define QSERDES_COM_SW_RESET 0x0150
+#define QSERDES_COM_CORE_CLK_EN 0x0154
+#define QSERDES_COM_C_READY_STATUS 0x0158
+#define QSERDES_COM_CMN_CONFIG 0x015C
+
+#define QSERDES_COM_SVS_MODE_CLK_SEL 0x0164
+
+#define DP_PHY_PLL_POLL_SLEEP_US 500
+#define DP_PHY_PLL_POLL_TIMEOUT_US 10000
+
+#define DP_VCO_RATE_8100MHZDIV1000 8100000UL
+#define DP_VCO_RATE_9720MHZDIV1000 9720000UL
+#define DP_VCO_RATE_10800MHZDIV1000 10800000UL
+
+int dp_mux_set_parent_10nm(void *context, unsigned int reg, unsigned int val)
+{
+ struct mdss_pll_resources *dp_res = context;
+ int rc;
+ u32 auxclk_div;
+
+ rc = mdss_pll_resource_enable(dp_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss DP PLL resources\n");
+ return rc;
+ }
+
+ auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
+ auxclk_div &= ~0x03; /* bits 0 to 1 */
+
+ if (val == 0) /* mux parent index = 0 */
+ auxclk_div |= 1;
+ else if (val == 1) /* mux parent index = 1 */
+ auxclk_div |= 2;
+ else if (val == 2) /* mux parent index = 2 */
+ auxclk_div |= 0;
+
+ MDSS_PLL_REG_W(dp_res->phy_base,
+ DP_PHY_VCO_DIV, auxclk_div);
+ /* Make sure the PHY registers writes are done */
+ wmb();
+ pr_debug("%s: mux=%d auxclk_div=%x\n", __func__, val, auxclk_div);
+
+ mdss_pll_resource_enable(dp_res, false);
+
+ return 0;
+}
+
+int dp_mux_get_parent_10nm(void *context, unsigned int reg, unsigned int *val)
+{
+ int rc;
+ u32 auxclk_div = 0;
+ struct mdss_pll_resources *dp_res = context;
+
+ rc = mdss_pll_resource_enable(dp_res, true);
+ if (rc) {
+ pr_err("Failed to enable dp_res resources\n");
+ return rc;
+ }
+
+ auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
+ auxclk_div &= 0x03;
+
+ if (auxclk_div == 1) /* Default divider */
+ *val = 0;
+ else if (auxclk_div == 2)
+ *val = 1;
+ else if (auxclk_div == 0)
+ *val = 2;
+
+ mdss_pll_resource_enable(dp_res, false);
+
+ pr_debug("%s: auxclk_div=%d, val=%d\n", __func__, auxclk_div, *val);
+
+ return 0;
+}
+
+static int dp_vco_pll_init_db_10nm(struct dp_pll_db *pdb,
+ unsigned long rate)
+{
+ struct mdss_pll_resources *dp_res = pdb->pll;
+ u32 spare_value = 0;
+
+ spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0);
+ pdb->lane_cnt = spare_value & 0x0F;
+ pdb->orientation = (spare_value & 0xF0) >> 4;
+
+ pr_debug("%s: spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n",
+ __func__, spare_value, pdb->lane_cnt, pdb->orientation);
+
+ switch (rate) {
+ case DP_VCO_HSCLK_RATE_1620MHZDIV1000:
+ pr_debug("%s: VCO rate: %ld\n", __func__,
+ DP_VCO_RATE_9720MHZDIV1000);
+ pdb->hsclk_sel = 0x0c;
+ pdb->dec_start_mode0 = 0x69;
+ pdb->div_frac_start1_mode0 = 0x00;
+ pdb->div_frac_start2_mode0 = 0x80;
+ pdb->div_frac_start3_mode0 = 0x07;
+ pdb->integloop_gain0_mode0 = 0x3f;
+ pdb->integloop_gain1_mode0 = 0x00;
+ pdb->vco_tune_map = 0x00;
+ pdb->lock_cmp1_mode0 = 0x6f;
+ pdb->lock_cmp2_mode0 = 0x08;
+ pdb->lock_cmp3_mode0 = 0x00;
+ pdb->phy_vco_div = 0x1;
+ pdb->lock_cmp_en = 0x00;
+ break;
+ case DP_VCO_HSCLK_RATE_2700MHZDIV1000:
+ pr_debug("%s: VCO rate: %ld\n", __func__,
+ DP_VCO_RATE_10800MHZDIV1000);
+ pdb->hsclk_sel = 0x04;
+ pdb->dec_start_mode0 = 0x69;
+ pdb->div_frac_start1_mode0 = 0x00;
+ pdb->div_frac_start2_mode0 = 0x80;
+ pdb->div_frac_start3_mode0 = 0x07;
+ pdb->integloop_gain0_mode0 = 0x3f;
+ pdb->integloop_gain1_mode0 = 0x00;
+ pdb->vco_tune_map = 0x00;
+ pdb->lock_cmp1_mode0 = 0x0f;
+ pdb->lock_cmp2_mode0 = 0x0e;
+ pdb->lock_cmp3_mode0 = 0x00;
+ pdb->phy_vco_div = 0x1;
+ pdb->lock_cmp_en = 0x00;
+ break;
+ case DP_VCO_HSCLK_RATE_5400MHZDIV1000:
+ pr_debug("%s: VCO rate: %ld\n", __func__,
+ DP_VCO_RATE_10800MHZDIV1000);
+ pdb->hsclk_sel = 0x00;
+ pdb->dec_start_mode0 = 0x8c;
+ pdb->div_frac_start1_mode0 = 0x00;
+ pdb->div_frac_start2_mode0 = 0x00;
+ pdb->div_frac_start3_mode0 = 0x0a;
+ pdb->integloop_gain0_mode0 = 0x3f;
+ pdb->integloop_gain1_mode0 = 0x00;
+ pdb->vco_tune_map = 0x00;
+ pdb->lock_cmp1_mode0 = 0x1f;
+ pdb->lock_cmp2_mode0 = 0x1c;
+ pdb->lock_cmp3_mode0 = 0x00;
+ pdb->phy_vco_div = 0x2;
+ pdb->lock_cmp_en = 0x00;
+ break;
+ case DP_VCO_HSCLK_RATE_8100MHZDIV1000:
+ pr_debug("%s: VCO rate: %ld\n", __func__,
+ DP_VCO_RATE_8100MHZDIV1000);
+ pdb->hsclk_sel = 0x03;
+ pdb->dec_start_mode0 = 0x69;
+ pdb->div_frac_start1_mode0 = 0x00;
+ pdb->div_frac_start2_mode0 = 0x80;
+ pdb->div_frac_start3_mode0 = 0x07;
+ pdb->integloop_gain0_mode0 = 0x3f;
+ pdb->integloop_gain1_mode0 = 0x00;
+ pdb->vco_tune_map = 0x00;
+ pdb->lock_cmp1_mode0 = 0x2f;
+ pdb->lock_cmp2_mode0 = 0x2a;
+ pdb->lock_cmp3_mode0 = 0x00;
+ pdb->phy_vco_div = 0x0;
+ pdb->lock_cmp_en = 0x08;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dp_config_vco_rate_10nm(struct dp_pll_vco_clk *vco,
+ unsigned long rate)
+{
+ u32 res = 0;
+ struct mdss_pll_resources *dp_res = vco->priv;
+ struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv;
+
+ res = dp_vco_pll_init_db_10nm(pdb, rate);
+ if (res) {
+ pr_err("VCO Init DB failed\n");
+ return res;
+ }
+
+ if (pdb->lane_cnt != 4) {
+ if (pdb->orientation == ORIENTATION_CC2)
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x6d);
+ else
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x75);
+ } else {
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x7d);
+ }
+
+ /* Make sure the PHY register writes are done */
+ wmb();
+
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, 0x01);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0e);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_SEL, 0x30);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CMN_CONFIG, 0x02);
+
+ /* Different for each clock rates */
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_HSCLK_SEL, pdb->hsclk_sel);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_INTEGLOOP_GAIN0_MODE0, pdb->integloop_gain0_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_INTEGLOOP_GAIN1_MODE0, pdb->integloop_gain1_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_VCO_TUNE_MAP, pdb->vco_tune_map);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_LOCK_CMP3_MODE0, pdb->lock_cmp3_mode0);
+ /* Make sure the PLL register writes are done */
+ wmb();
+
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BG_TIMER, 0x0a);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORECLK_DIV_MODE0, 0x0a);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_VCO_TUNE_CTRL, 0x00);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORE_CLK_EN, 0x1f);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_IVCO, 0x07);
+ MDSS_PLL_REG_W(dp_res->pll_base,
+ QSERDES_COM_LOCK_CMP_EN, pdb->lock_cmp_en);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_CCTRL_MODE0, 0x36);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_RCTRL_MODE0, 0x16);
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CP_CTRL_MODE0, 0x06);
+ /* Make sure the PHY register writes are done */
+ wmb();
+
+ if (pdb->orientation == ORIENTATION_CC2)
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x4c);
+ else
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x5c);
+ /* Make sure the PLL register writes are done */
+ wmb();
+
+ /* TX Lane configuration */
+ MDSS_PLL_REG_W(dp_res->phy_base,
+ DP_PHY_TX0_TX1_LANE_CTL, 0x05);
+ MDSS_PLL_REG_W(dp_res->phy_base,
+ DP_PHY_TX2_TX3_LANE_CTL, 0x05);
+
+ /* TX-0 register configuration */
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_VMODE_CTRL1, 0x40);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_INTERFACE_SELECT, 0x3d);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_CLKBUF_ENABLE, 0x0f);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RESET_TSYNC_EN, 0x03);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRAN_DRVR_EMP_EN, 0x03);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+ TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_INTERFACE_MODE, 0x00);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_BAND, 0x4);
+
+ /* TX-1 register configuration */
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_VMODE_CTRL1, 0x40);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_INTERFACE_SELECT, 0x3d);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_CLKBUF_ENABLE, 0x0f);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RESET_TSYNC_EN, 0x03);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRAN_DRVR_EMP_EN, 0x03);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+ TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_INTERFACE_MODE, 0x00);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_BAND, 0x4);
+ /* Make sure the PHY register writes are done */
+ wmb();
+
+ /* dependent on the vco frequency */
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_VCO_DIV, pdb->phy_vco_div);
+
+ return res;
+}
+
+static bool dp_10nm_pll_lock_status(struct mdss_pll_resources *dp_res)
+{
+ u32 status;
+ bool pll_locked;
+
+ /* poll for PLL lock status */
+ if (readl_poll_timeout_atomic((dp_res->pll_base +
+ QSERDES_COM_C_READY_STATUS),
+ status,
+ ((status & BIT(0)) > 0),
+ DP_PHY_PLL_POLL_SLEEP_US,
+ DP_PHY_PLL_POLL_TIMEOUT_US)) {
+ pr_err("%s: C_READY status is not high. Status=%x\n",
+ __func__, status);
+ pll_locked = false;
+ } else {
+ pll_locked = true;
+ }
+
+ return pll_locked;
+}
+
+static bool dp_10nm_phy_rdy_status(struct mdss_pll_resources *dp_res)
+{
+ u32 status;
+ bool phy_ready = true;
+
+ /* poll for PHY ready status */
+ if (readl_poll_timeout_atomic((dp_res->phy_base +
+ DP_PHY_STATUS),
+ status,
+ ((status & (BIT(1))) > 0),
+ DP_PHY_PLL_POLL_SLEEP_US,
+ DP_PHY_PLL_POLL_TIMEOUT_US)) {
+ pr_err("%s: Phy_ready is not high. Status=%x\n",
+ __func__, status);
+ phy_ready = false;
+ }
+
+ return phy_ready;
+}
+
+static int dp_pll_enable_10nm(struct clk_hw *hw)
+{
+ int rc = 0;
+ struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+ struct mdss_pll_resources *dp_res = vco->priv;
+ struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv;
+ u32 bias_en, drvr_en;
+
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_AUX_CFG2, 0x04);
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01);
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05);
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01);
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x09);
+ wmb(); /* Make sure the PHY register writes are done */
+
+ MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20);
+ wmb(); /* Make sure the PLL register writes are done */
+
+ if (!dp_10nm_pll_lock_status(dp_res)) {
+ rc = -EINVAL;
+ goto lock_err;
+ }
+
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19);
+ /* Make sure the PHY register writes are done */
+ wmb();
+ /* poll for PHY ready status */
+ if (!dp_10nm_phy_rdy_status(dp_res)) {
+ rc = -EINVAL;
+ goto lock_err;
+ }
+
+ pr_debug("%s: PLL is locked\n", __func__);
+
+ if (pdb->lane_cnt == 1) {
+ bias_en = 0x3e;
+ drvr_en = 0x13;
+ } else {
+ bias_en = 0x3f;
+ drvr_en = 0x10;
+ }
+
+ if (pdb->lane_cnt != 4) {
+ if (pdb->orientation == ORIENTATION_CC1) {
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+ TXn_HIGHZ_DRVR_EN, drvr_en);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+ TXn_TRANSCEIVER_BIAS_EN, bias_en);
+ } else {
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+ TXn_HIGHZ_DRVR_EN, drvr_en);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+ TXn_TRANSCEIVER_BIAS_EN, bias_en);
+ }
+ } else {
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_HIGHZ_DRVR_EN, drvr_en);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+ TXn_TRANSCEIVER_BIAS_EN, bias_en);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_HIGHZ_DRVR_EN, drvr_en);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+ TXn_TRANSCEIVER_BIAS_EN, bias_en);
+ }
+
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_POL_INV, 0x0a);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_POL_INV, 0x0a);
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x18);
+ udelay(2000);
+
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19);
+
+ /*
+ * Make sure all the register writes are completed before
+ * doing any other operation
+ */
+ wmb();
+
+ /* poll for PHY ready status */
+ if (!dp_10nm_phy_rdy_status(dp_res)) {
+ rc = -EINVAL;
+ goto lock_err;
+ }
+
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_DRV_LVL, 0x38);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_DRV_LVL, 0x38);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_EMP_POST1_LVL, 0x20);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_EMP_POST1_LVL, 0x20);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06);
+ MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07);
+ MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07);
+ /* Make sure the PHY register writes are done */
+ wmb();
+
+lock_err:
+ return rc;
+}
+
+static int dp_pll_disable_10nm(struct clk_hw *hw)
+{
+ int rc = 0;
+ struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+ struct mdss_pll_resources *dp_res = vco->priv;
+
+ /* Assert DP PHY power down */
+ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x2);
+ /*
+ * Make sure all the register writes to disable PLL are
+ * completed before doing any other operation
+ */
+ wmb();
+
+ return rc;
+}
+
+
+int dp_vco_prepare_10nm(struct clk_hw *hw)
+{
+ int rc = 0;
+ struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+ struct mdss_pll_resources *dp_res = vco->priv;
+
+ pr_debug("rate=%ld\n", vco->rate);
+ rc = mdss_pll_resource_enable(dp_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss DP pll resources\n");
+ goto error;
+ }
+
+ if ((dp_res->vco_cached_rate != 0)
+ && (dp_res->vco_cached_rate == vco->rate)) {
+ rc = vco->hw.init->ops->set_rate(hw,
+ dp_res->vco_cached_rate, dp_res->vco_cached_rate);
+ if (rc) {
+ pr_err("index=%d vco_set_rate failed. rc=%d\n",
+ rc, dp_res->index);
+ mdss_pll_resource_enable(dp_res, false);
+ goto error;
+ }
+ }
+
+ rc = dp_pll_enable_10nm(hw);
+ if (rc) {
+ mdss_pll_resource_enable(dp_res, false);
+ pr_err("ndx=%d failed to enable dp pll\n",
+ dp_res->index);
+ goto error;
+ }
+
+ mdss_pll_resource_enable(dp_res, false);
+error:
+ return rc;
+}
+
+void dp_vco_unprepare_10nm(struct clk_hw *hw)
+{
+ struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+ struct mdss_pll_resources *dp_res = vco->priv;
+
+ if (!dp_res) {
+ pr_err("Invalid input parameter\n");
+ return;
+ }
+
+ if (!dp_res->pll_on &&
+ mdss_pll_resource_enable(dp_res, true)) {
+ pr_err("pll resource can't be enabled\n");
+ return;
+ }
+ dp_res->vco_cached_rate = vco->rate;
+ dp_pll_disable_10nm(hw);
+
+ dp_res->handoff_resources = false;
+ mdss_pll_resource_enable(dp_res, false);
+ dp_res->pll_on = false;
+}
+
+int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+ struct mdss_pll_resources *dp_res = vco->priv;
+ int rc;
+
+ rc = mdss_pll_resource_enable(dp_res, true);
+ if (rc) {
+ pr_err("pll resource can't be enabled\n");
+ return rc;
+ }
+
+ pr_debug("DP lane CLK rate=%ld\n", rate);
+
+ rc = dp_config_vco_rate_10nm(vco, rate);
+ if (rc)
+ pr_err("%s: Failed to set clk rate\n", __func__);
+
+ mdss_pll_resource_enable(dp_res, false);
+
+ vco->rate = rate;
+
+ return 0;
+}
+
+unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+ int rc;
+ u32 div, hsclk_div, link_clk_div = 0;
+ u64 vco_rate;
+ struct mdss_pll_resources *dp_res = vco->priv;
+
+ rc = mdss_pll_resource_enable(dp_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss DP pll=%d\n", dp_res->index);
+ return rc;
+ }
+
+ div = MDSS_PLL_REG_R(dp_res->pll_base, QSERDES_COM_HSCLK_SEL);
+ div &= 0x0f;
+
+ if (div == 12)
+ hsclk_div = 6; /* Default */
+ else if (div == 4)
+ hsclk_div = 4;
+ else if (div == 0)
+ hsclk_div = 2;
+ else if (div == 3)
+ hsclk_div = 1;
+ else {
+ pr_debug("unknown divider. forcing to default\n");
+ hsclk_div = 5;
+ }
+
+ div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_AUX_CFG2);
+ div >>= 2;
+
+ if ((div & 0x3) == 0)
+ link_clk_div = 5;
+ else if ((div & 0x3) == 1)
+ link_clk_div = 10;
+ else if ((div & 0x3) == 2)
+ link_clk_div = 20;
+ else
+ pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div);
+
+ if (link_clk_div == 20) {
+ vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
+ } else {
+ if (hsclk_div == 6)
+ vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000;
+ else if (hsclk_div == 4)
+ vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
+ else if (hsclk_div == 2)
+ vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
+ else
+ vco_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000;
+ }
+
+ pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+ mdss_pll_resource_enable(dp_res, false);
+
+ dp_res->vco_cached_rate = vco->rate = vco_rate;
+ return (unsigned long)vco_rate;
+}
+
+long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned long rrate = rate;
+ struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+
+ if (rate <= vco->min_rate)
+ rrate = vco->min_rate;
+ else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000)
+ rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
+ else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000)
+ rrate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
+ else
+ rrate = vco->max_rate;
+
+ pr_debug("%s: rrate=%ld\n", __func__, rrate);
+
+ *parent_rate = rrate;
+ return rrate;
+}
+
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c
new file mode 100644
index 0000000..e30ef82
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c
@@ -0,0 +1,310 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * Display Port PLL driver block diagram for branch clocks
+ *
+ * +------------------------------+
+ * | DP_VCO_CLK |
+ * | |
+ * | +-------------------+ |
+ * | | (DP PLL/VCO) | |
+ * | +---------+---------+ |
+ * | v |
+ * | +----------+-----------+ |
+ * | | hsclk_divsel_clk_src | |
+ * | +----------+-----------+ |
+ * +------------------------------+
+ * |
+ * +------------<---------v------------>----------+
+ * | |
+ * +-----v------------+ |
+ * | dp_link_clk_src | |
+ * | divsel_ten | |
+ * +---------+--------+ |
+ * | |
+ * | |
+ * v v
+ * Input to DISPCC block |
+ * for link clk, crypto clk |
+ * and interface clock |
+ * |
+ * |
+ * +--------<------------+-----------------+---<---+
+ * | | |
+ * +-------v------+ +--------v-----+ +--------v------+
+ * | vco_divided | | vco_divided | | vco_divided |
+ * | _clk_src | | _clk_src | | _clk_src |
+ * | | | | | |
+ * |divsel_six | | divsel_two | | divsel_four |
+ * +-------+------+ +-----+--------+ +--------+------+
+ * | | |
+ * v------->----------v-------------<------v
+ * |
+ * +----------+---------+
+ * | vco_divided_clk |
+ * | _src_mux |
+ * +---------+----------+
+ * |
+ * v
+ * Input to DISPCC block
+ * for DP pixel clock
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+
+#include "mdss-pll.h"
+#include "mdss-dp-pll.h"
+#include "mdss-dp-pll-10nm.h"
+
+static struct dp_pll_db dp_pdb;
+static struct clk_ops mux_clk_ops;
+
+static struct regmap_config dp_pll_10nm_cfg = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x910,
+};
+
+static struct regmap_bus dp_pixel_mux_regmap_ops = {
+ .reg_write = dp_mux_set_parent_10nm,
+ .reg_read = dp_mux_get_parent_10nm,
+};
+
+/* Op structures */
+static const struct clk_ops dp_10nm_vco_clk_ops = {
+ .recalc_rate = dp_vco_recalc_rate_10nm,
+ .set_rate = dp_vco_set_rate_10nm,
+ .round_rate = dp_vco_round_rate_10nm,
+ .prepare = dp_vco_prepare_10nm,
+ .unprepare = dp_vco_unprepare_10nm,
+};
+
+static struct dp_pll_vco_clk dp_vco_clk = {
+ .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000,
+ .max_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000,
+ .hw.init = &(struct clk_init_data){
+ .name = "dp_vco_clk",
+ .parent_names = (const char *[]){ "xo_board" },
+ .num_parents = 1,
+ .ops = &dp_10nm_vco_clk_ops,
+ },
+};
+
+static struct clk_fixed_factor dp_link_clk_divsel_ten = {
+ .div = 10,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dp_link_clk_divsel_ten",
+ .parent_names =
+ (const char *[]){ "dp_vco_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dp_vco_divsel_two_clk_src = {
+ .div = 2,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dp_vco_divsel_two_clk_src",
+ .parent_names =
+ (const char *[]){ "dp_vco_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dp_vco_divsel_four_clk_src = {
+ .div = 4,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dp_vco_divsel_four_clk_src",
+ .parent_names =
+ (const char *[]){ "dp_vco_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dp_vco_divsel_six_clk_src = {
+ .div = 6,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dp_vco_divsel_six_clk_src",
+ .parent_names =
+ (const char *[]){ "dp_vco_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+
+static int clk_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ int ret = 0;
+
+ ret = __clk_mux_determine_rate_closest(hw, req);
+ if (ret)
+ return ret;
+
+ /* Set the new parent of mux if there is a new valid parent */
+ if (hw->clk && req->best_parent_hw->clk)
+ clk_set_parent(hw->clk, req->best_parent_hw->clk);
+
+ return 0;
+}
+
+static unsigned long mux_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk *div_clk = NULL, *vco_clk = NULL;
+ struct dp_pll_vco_clk *vco = NULL;
+
+ div_clk = clk_get_parent(hw->clk);
+ if (!div_clk)
+ return 0;
+
+ vco_clk = clk_get_parent(div_clk);
+ if (!vco_clk)
+ return 0;
+
+ vco = to_dp_vco_hw(__clk_get_hw(vco_clk));
+ if (!vco)
+ return 0;
+
+ if (vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000)
+ return (vco->rate / 6);
+ else if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000)
+ return (vco->rate / 4);
+ else
+ return (vco->rate / 2);
+}
+
+static struct clk_regmap_mux dp_vco_divided_clk_src_mux = {
+ .reg = 0x64,
+ .shift = 0,
+ .width = 2,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dp_vco_divided_clk_src_mux",
+ .parent_names =
+ (const char *[]){"dp_vco_divsel_two_clk_src",
+ "dp_vco_divsel_four_clk_src",
+ "dp_vco_divsel_six_clk_src"},
+ .num_parents = 3,
+ .ops = &mux_clk_ops,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ },
+ },
+};
+
+static struct clk_hw *mdss_dp_pllcc_10nm[] = {
+ [DP_VCO_CLK] = &dp_vco_clk.hw,
+ [DP_LINK_CLK_DIVSEL_TEN] = &dp_link_clk_divsel_ten.hw,
+ [DP_VCO_DIVIDED_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw,
+ [DP_VCO_DIVIDED_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw,
+ [DP_VCO_DIVIDED_SIX_CLK_SRC] = &dp_vco_divsel_six_clk_src.hw,
+ [DP_VCO_DIVIDED_CLK_SRC_MUX] = &dp_vco_divided_clk_src_mux.clkr.hw,
+};
+
+int dp_pll_clock_register_10nm(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res)
+{
+ int rc = -ENOTSUPP, i = 0;
+ struct clk_onecell_data *clk_data;
+ struct clk *clk;
+ struct regmap *regmap;
+ int num_clks = ARRAY_SIZE(mdss_dp_pllcc_10nm);
+
+ if (!pdev || !pdev->dev.of_node) {
+ pr_err("Invalid input parameters\n");
+ return -EINVAL;
+ }
+
+ if (!pll_res || !pll_res->pll_base || !pll_res->phy_base ||
+ !pll_res->ln_tx0_base || !pll_res->ln_tx1_base) {
+ pr_err("%s: Invalid input parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks *
+ sizeof(struct clk *)), GFP_KERNEL);
+ if (!clk_data->clks) {
+ devm_kfree(&pdev->dev, clk_data);
+ return -ENOMEM;
+ }
+ clk_data->clk_num = num_clks;
+
+ pll_res->priv = &dp_pdb;
+ dp_pdb.pll = pll_res;
+
+ /* Set client data for vco, mux and div clocks */
+ regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops,
+ pll_res, &dp_pll_10nm_cfg);
+ dp_vco_divided_clk_src_mux.clkr.regmap = regmap;
+ mux_clk_ops = clk_regmap_mux_closest_ops;
+ mux_clk_ops.determine_rate = clk_mux_determine_rate;
+ mux_clk_ops.recalc_rate = mux_recalc_rate;
+
+ dp_vco_clk.priv = pll_res;
+
+ for (i = DP_VCO_CLK; i <= DP_VCO_DIVIDED_CLK_SRC_MUX; i++) {
+ pr_debug("reg clk: %d index: %d\n", i, pll_res->index);
+ clk = devm_clk_register(&pdev->dev,
+ mdss_dp_pllcc_10nm[i]);
+ if (IS_ERR(clk)) {
+ pr_err("clk registration failed for DP: %d\n",
+ pll_res->index);
+ rc = -EINVAL;
+ goto clk_reg_fail;
+ }
+ clk_data->clks[i] = clk;
+ }
+
+ rc = of_clk_add_provider(pdev->dev.of_node,
+ of_clk_src_onecell_get, clk_data);
+ if (rc) {
+ pr_err("%s: Clock register failed rc=%d\n", __func__, rc);
+ rc = -EPROBE_DEFER;
+ } else {
+ pr_debug("%s SUCCESS\n", __func__);
+ }
+ return 0;
+clk_reg_fail:
+ devm_kfree(&pdev->dev, clk_data->clks);
+ devm_kfree(&pdev->dev, clk_data);
+ return rc;
+}
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h
new file mode 100644
index 0000000..c3b5635
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MDSS_DP_PLL_10NM_H
+#define __MDSS_DP_PLL_10NM_H
+
+#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL
+#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL
+#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL
+#define DP_VCO_HSCLK_RATE_8100MHZDIV1000 8100000UL
+
+struct dp_pll_db {
+ struct mdss_pll_resources *pll;
+
+ /* lane and orientation settings */
+ u8 lane_cnt;
+ u8 orientation;
+
+ /* COM PHY settings */
+ u32 hsclk_sel;
+ u32 dec_start_mode0;
+ u32 div_frac_start1_mode0;
+ u32 div_frac_start2_mode0;
+ u32 div_frac_start3_mode0;
+ u32 integloop_gain0_mode0;
+ u32 integloop_gain1_mode0;
+ u32 vco_tune_map;
+ u32 lock_cmp1_mode0;
+ u32 lock_cmp2_mode0;
+ u32 lock_cmp3_mode0;
+ u32 lock_cmp_en;
+
+ /* PHY vco divider */
+ u32 phy_vco_div;
+};
+
+int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw,
+ unsigned long parent_rate);
+long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate);
+int dp_vco_prepare_10nm(struct clk_hw *hw);
+void dp_vco_unprepare_10nm(struct clk_hw *hw);
+int dp_mux_set_parent_10nm(void *context,
+ unsigned int reg, unsigned int val);
+int dp_mux_get_parent_10nm(void *context,
+ unsigned int reg, unsigned int *val);
+#endif /* __MDSS_DP_PLL_10NM_H */
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c
deleted file mode 100644
index a3ed8a8..0000000
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/iopoll.h>
-#include <linux/delay.h>
-#include <linux/clk/msm-clock-generic.h>
-
-#include "mdss-pll.h"
-#include "mdss-dp-pll.h"
-#include "mdss-dp-pll-8998.h"
-
-int link2xclk_divsel_set_div(struct div_clk *clk, int div)
-{
- int rc;
- u32 link2xclk_div_tx0, link2xclk_div_tx1;
- u32 phy_mode;
- struct mdss_pll_resources *dp_res = clk->priv;
-
- rc = mdss_pll_resource_enable(dp_res, true);
- if (rc) {
- pr_err("Failed to enable mdss DP PLL resources\n");
- return rc;
- }
-
- link2xclk_div_tx0 = MDSS_PLL_REG_R(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TX_BAND);
- link2xclk_div_tx1 = MDSS_PLL_REG_R(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TX_BAND);
-
- link2xclk_div_tx0 &= ~0x07; /* bits 0 to 2 */
- link2xclk_div_tx1 &= ~0x07; /* bits 0 to 2 */
-
- /* Configure TX band Mux */
- link2xclk_div_tx0 |= 0x4;
- link2xclk_div_tx1 |= 0x4;
-
- /*configure DP PHY MODE */
- phy_mode = 0x58;
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TX_BAND,
- link2xclk_div_tx0);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TX_BAND,
- link2xclk_div_tx1);
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_MODE, phy_mode);
- /* Make sure the PHY register writes are done */
- wmb();
-
- pr_debug("%s: div=%d link2xclk_div_tx0=%x, link2xclk_div_tx1=%x\n",
- __func__, div, link2xclk_div_tx0, link2xclk_div_tx1);
-
- mdss_pll_resource_enable(dp_res, false);
-
- return rc;
-}
-
-int link2xclk_divsel_get_div(struct div_clk *clk)
-{
- int rc;
- u32 div = 0, phy_mode;
- struct mdss_pll_resources *dp_res = clk->priv;
-
- rc = mdss_pll_resource_enable(dp_res, true);
- if (rc) {
- pr_err("Failed to enable dp_res resources\n");
- return rc;
- }
-
- phy_mode = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_MODE);
-
- if (phy_mode & 0x48)
- pr_err("%s: DP PAR Rate not correct\n", __func__);
-
- if ((phy_mode & 0x3) == 1)
- div = 10;
- else if ((phy_mode & 0x3) == 0)
- div = 5;
- else
- pr_err("%s: unsupported div: %d\n", __func__, phy_mode);
-
- mdss_pll_resource_enable(dp_res, false);
- pr_debug("%s: phy_mode=%d, div=%d\n", __func__,
- phy_mode, div);
-
- return div;
-}
-
-int vco_divided_clk_set_div(struct div_clk *clk, int div)
-{
- int rc;
- u32 auxclk_div;
- struct mdss_pll_resources *dp_res = clk->priv;
-
- rc = mdss_pll_resource_enable(dp_res, true);
- if (rc) {
- pr_err("Failed to enable mdss DP PLL resources\n");
- return rc;
- }
-
- auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
- auxclk_div &= ~0x03; /* bits 0 to 1 */
-
- auxclk_div |= 1; /* Default divider */
-
- if (div == 4)
- auxclk_div |= 2;
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_VCO_DIV, auxclk_div);
- /* Make sure the PHY registers writes are done */
- wmb();
- pr_debug("%s: div=%d auxclk_div=%x\n", __func__, div, auxclk_div);
-
- mdss_pll_resource_enable(dp_res, false);
-
- return rc;
-}
-
-
-enum handoff vco_divided_clk_handoff(struct clk *c)
-{
- /*
- * Since cont-splash is not enabled, disable handoff
- * for vco_divider_clk.
- */
- return HANDOFF_DISABLED_CLK;
-}
-
-int vco_divided_clk_get_div(struct div_clk *clk)
-{
- int rc;
- u32 div, auxclk_div;
- struct mdss_pll_resources *dp_res = clk->priv;
-
- rc = mdss_pll_resource_enable(dp_res, true);
- if (rc) {
- pr_err("Failed to enable dp_res resources\n");
- return rc;
- }
-
- auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
- auxclk_div &= 0x03;
-
- div = 2; /* Default divider */
- if (auxclk_div == 2)
- div = 4;
-
- mdss_pll_resource_enable(dp_res, false);
-
- pr_debug("%s: auxclk_div=%d, div=%d\n", __func__, auxclk_div, div);
-
- return div;
-}
-
-int dp_config_vco_rate(struct dp_pll_vco_clk *vco, unsigned long rate)
-{
- u32 res = 0;
- struct mdss_pll_resources *dp_res = vco->priv;
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_PD_CTL, 0x3d);
- /* Make sure the PHY register writes are done */
- wmb();
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_SVS_MODE_CLK_SEL, 0x01);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_SYSCLK_EN_SEL, 0x37);
-
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CLK_ENABLE1, 0x0e);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CLK_SEL, 0x30);
-
- /* Different for each clock rates */
- if (rate == DP_VCO_HSCLK_RATE_1620MHZDIV1000) {
- pr_debug("%s: VCO rate: %ld\n", __func__,
- DP_VCO_RATE_8100MHZDIV1000);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_SYS_CLK_CTRL, 0x02);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_HSCLK_SEL, 0x2c);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP_EN, 0x04);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DEC_START_MODE0, 0x69);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CMN_CONFIG, 0x42);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP1_MODE0, 0xbf);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP2_MODE0, 0x21);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP3_MODE0, 0x00);
- } else if (rate == DP_VCO_HSCLK_RATE_2700MHZDIV1000) {
- pr_debug("%s: VCO rate: %ld\n", __func__,
- DP_VCO_RATE_8100MHZDIV1000);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_SYS_CLK_CTRL, 0x06);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_HSCLK_SEL, 0x84);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP_EN, 0x08);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DEC_START_MODE0, 0x69);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CMN_CONFIG, 0x02);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP1_MODE0, 0x3f);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP2_MODE0, 0x38);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP3_MODE0, 0x00);
- } else if (rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) {
- pr_debug("%s: VCO rate: %ld\n", __func__,
- DP_VCO_RATE_10800MHZDIV1000);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_SYS_CLK_CTRL, 0x06);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_HSCLK_SEL, 0x80);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP_EN, 0x08);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DEC_START_MODE0, 0x8c);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_DIV_FRAC_START3_MODE0, 0xa0);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CMN_CONFIG, 0x12);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP1_MODE0, 0x7f);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP2_MODE0, 0x70);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_LOCK_CMP3_MODE0, 0x00);
- } else {
- pr_err("%s: unsupported rate: %ld\n", __func__, rate);
- return -EINVAL;
- }
- /* Make sure the PLL register writes are done */
- wmb();
-
- if ((rate == DP_VCO_HSCLK_RATE_1620MHZDIV1000)
- || (rate == DP_VCO_HSCLK_RATE_2700MHZDIV1000)) {
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_VCO_DIV, 0x1);
- } else {
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_VCO_DIV, 0x2);
- }
- /* Make sure the PHY register writes are done */
- wmb();
-
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3f);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_VCO_TUNE_MAP, 0x00);
-
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_BG_TIMER, 0x00);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_BG_TIMER, 0x0a);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CORECLK_DIV_MODE0, 0x05);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_VCO_TUNE_CTRL, 0x00);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CP_CTRL_MODE0, 0x06);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_PLL_CCTRL_MODE0, 0x36);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_PLL_RCTRL_MODE0, 0x16);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_PLL_IVCO, 0x07);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x37);
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_CORE_CLK_EN, 0x0f);
-
- /* Make sure the PLL register writes are done */
- wmb();
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_MODE, 0x58);
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_TX0_TX1_LANE_CTL, 0x05);
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_TX2_TX3_LANE_CTL, 0x05);
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
- 0x1a);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
- 0x1a);
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_VMODE_CTRL1,
- 0x40);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_VMODE_CTRL1,
- 0x40);
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN,
- 0x30);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN,
- 0x30);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_INTERFACE_SELECT,
- 0x3d);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_INTERFACE_SELECT,
- 0x3d);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE,
- 0x0f);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE,
- 0x0f);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_RESET_TSYNC_EN,
- 0x03);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_RESET_TSYNC_EN,
- 0x03);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TRAN_DRVR_EMP_EN,
- 0x03);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TRAN_DRVR_EMP_EN,
- 0x03);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN,
- 0x00);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN,
- 0x00);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TX_INTERFACE_MODE,
- 0x00);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TX_INTERFACE_MODE,
- 0x00);
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TX_BAND,
- 0x4);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TX_BAND,
- 0x4);
- /* Make sure the PHY register writes are done */
- wmb();
- return res;
-}
-
-static bool dp_pll_lock_status(struct mdss_pll_resources *dp_res)
-{
- u32 status;
- bool pll_locked;
-
- /* poll for PLL ready status */
- if (readl_poll_timeout_atomic((dp_res->pll_base +
- QSERDES_COM_C_READY_STATUS),
- status,
- ((status & BIT(0)) > 0),
- DP_PLL_POLL_SLEEP_US,
- DP_PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: C_READY status is not high. Status=%x\n",
- __func__, status);
- pll_locked = false;
- } else if (readl_poll_timeout_atomic((dp_res->pll_base +
- DP_PHY_STATUS),
- status,
- ((status & BIT(1)) > 0),
- DP_PLL_POLL_SLEEP_US,
- DP_PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: Phy_ready is not high. Status=%x\n",
- __func__, status);
- pll_locked = false;
- } else {
- pll_locked = true;
- }
-
- return pll_locked;
-}
-
-
-static int dp_pll_enable(struct clk *c)
-{
- int rc = 0;
- u32 status;
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
- struct mdss_pll_resources *dp_res = vco->priv;
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x01);
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x05);
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x01);
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x09);
- /* Make sure the PHY register writes are done */
- wmb();
- MDSS_PLL_REG_W(dp_res->pll_base,
- QSERDES_COM_RESETSM_CNTRL, 0x20);
- /* Make sure the PLL register writes are done */
- wmb();
- /* poll for PLL ready status */
- if (readl_poll_timeout_atomic((dp_res->pll_base +
- QSERDES_COM_C_READY_STATUS),
- status,
- ((status & BIT(0)) > 0),
- DP_PLL_POLL_SLEEP_US,
- DP_PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: C_READY status is not high. Status=%x\n",
- __func__, status);
- rc = -EINVAL;
- goto lock_err;
- }
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x19);
- /* Make sure the PHY register writes are done */
- wmb();
- /* poll for PHY ready status */
- if (readl_poll_timeout_atomic((dp_res->phy_base +
- DP_PHY_STATUS),
- status,
- ((status & BIT(1)) > 0),
- DP_PLL_POLL_SLEEP_US,
- DP_PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: Phy_ready is not high. Status=%x\n",
- __func__, status);
- rc = -EINVAL;
- goto lock_err;
- }
-
- pr_debug("%s: PLL is locked\n", __func__);
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
- 0x3f);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN,
- 0x10);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
- 0x3f);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN,
- 0x10);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TX_POL_INV,
- 0x0a);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TX_POL_INV,
- 0x0a);
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x18);
- udelay(2000);
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x19);
-
- /*
- * Make sure all the register writes are completed before
- * doing any other operation
- */
- wmb();
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_LANE_MODE_1,
- 0xf6);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_LANE_MODE_1,
- 0xf6);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE,
- 0x1f);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE,
- 0x1f);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE,
- 0x0f);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE,
- 0x0f);
- /*
- * Make sure all the register writes are completed before
- * doing any other operation
- */
- wmb();
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x09);
- udelay(2000);
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_CFG, 0x19);
- udelay(2000);
- /* poll for PHY ready status */
- if (readl_poll_timeout_atomic((dp_res->phy_base +
- DP_PHY_STATUS),
- status,
- ((status & BIT(1)) > 0),
- DP_PLL_POLL_SLEEP_US,
- DP_PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: Lane_mode: Phy_ready is not high. Status=%x\n",
- __func__, status);
- rc = -EINVAL;
- goto lock_err;
- }
-
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TX_DRV_LVL,
- 0x2a);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TX_DRV_LVL,
- 0x2a);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_TX_EMP_POST1_LVL,
- 0x20);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_TX_EMP_POST1_LVL,
- 0x20);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX,
- 0x11);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX,
- 0x11);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX,
- 0x11);
- MDSS_PLL_REG_W(dp_res->phy_base,
- QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX,
- 0x11);
- /* Make sure the PHY register writes are done */
- wmb();
-
-lock_err:
- return rc;
-}
-
-static int dp_pll_disable(struct clk *c)
-{
- int rc = 0;
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
- struct mdss_pll_resources *dp_res = vco->priv;
-
- /* Assert DP PHY power down */
- MDSS_PLL_REG_W(dp_res->phy_base,
- DP_PHY_PD_CTL, 0x2);
- /*
- * Make sure all the register writes to disable PLL are
- * completed before doing any other operation
- */
- wmb();
-
- return rc;
-}
-
-
-int dp_vco_prepare(struct clk *c)
-{
- int rc = 0;
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
- struct mdss_pll_resources *dp_pll_res = vco->priv;
-
- DEV_DBG("rate=%ld\n", vco->rate);
- rc = mdss_pll_resource_enable(dp_pll_res, true);
- if (rc) {
- pr_err("Failed to enable mdss DP pll resources\n");
- goto error;
- }
-
- rc = dp_pll_enable(c);
- if (rc) {
- mdss_pll_resource_enable(dp_pll_res, false);
- pr_err("ndx=%d failed to enable dsi pll\n",
- dp_pll_res->index);
- goto error;
- }
-
- mdss_pll_resource_enable(dp_pll_res, false);
-error:
- return rc;
-}
-
-void dp_vco_unprepare(struct clk *c)
-{
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
- struct mdss_pll_resources *io = vco->priv;
-
- if (!io) {
- DEV_ERR("Invalid input parameter\n");
- return;
- }
-
- if (!io->pll_on &&
- mdss_pll_resource_enable(io, true)) {
- DEV_ERR("pll resource can't be enabled\n");
- return;
- }
- dp_pll_disable(c);
-
- io->handoff_resources = false;
- mdss_pll_resource_enable(io, false);
- io->pll_on = false;
-}
-
-int dp_vco_set_rate(struct clk *c, unsigned long rate)
-{
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
- struct mdss_pll_resources *io = vco->priv;
- int rc;
-
- rc = mdss_pll_resource_enable(io, true);
- if (rc) {
- DEV_ERR("pll resource can't be enabled\n");
- return rc;
- }
-
- DEV_DBG("DP lane CLK rate=%ld\n", rate);
-
- rc = dp_config_vco_rate(vco, rate);
- if (rc)
- DEV_ERR("%s: Failed to set clk rate\n", __func__);
-
- mdss_pll_resource_enable(io, false);
-
- vco->rate = rate;
-
- return 0;
-}
-
-unsigned long dp_vco_get_rate(struct clk *c)
-{
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
- int rc;
- u32 div, hsclk_div, link2xclk_div;
- u64 vco_rate;
- struct mdss_pll_resources *pll = vco->priv;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable mdss DP pll=%d\n", pll->index);
- return rc;
- }
-
- div = MDSS_PLL_REG_R(pll->pll_base, QSERDES_COM_HSCLK_SEL);
- div &= 0x0f;
-
- if (div == 12)
- hsclk_div = 5; /* Default */
- else if (div == 4)
- hsclk_div = 3;
- else if (div == 0)
- hsclk_div = 2;
- else {
- pr_debug("unknown divider. forcing to default\n");
- hsclk_div = 5;
- }
-
- div = MDSS_PLL_REG_R(pll->phy_base, DP_PHY_MODE);
-
- if (div & 0x58)
- pr_err("%s: DP PAR Rate not correct\n", __func__);
-
- if ((div & 0x3) == 1)
- link2xclk_div = 10;
- else if ((div & 0x3) == 0)
- link2xclk_div = 5;
- else
- pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div);
-
- if (link2xclk_div == 10) {
- vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
- } else {
- if (hsclk_div == 5)
- vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000;
- else if (hsclk_div == 3)
- vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
- else
- vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
- }
-
- pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
-
- mdss_pll_resource_enable(pll, false);
-
- return (unsigned long)vco_rate;
-}
-
-long dp_vco_round_rate(struct clk *c, unsigned long rate)
-{
- unsigned long rrate = rate;
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-
- if (rate <= vco->min_rate)
- rrate = vco->min_rate;
- else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000)
- rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
- else
- rrate = vco->max_rate;
-
- pr_debug("%s: rrate=%ld\n", __func__, rrate);
-
- return rrate;
-}
-
-enum handoff dp_vco_handoff(struct clk *c)
-{
- enum handoff ret = HANDOFF_DISABLED_CLK;
- struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
- struct mdss_pll_resources *io = vco->priv;
-
- if (mdss_pll_resource_enable(io, true)) {
- DEV_ERR("pll resource can't be enabled\n");
- return ret;
- }
-
- if (dp_pll_lock_status(io)) {
- io->pll_on = true;
- c->rate = dp_vco_get_rate(c);
- io->handoff_resources = true;
- ret = HANDOFF_ENABLED_CLK;
- } else {
- io->handoff_resources = false;
- mdss_pll_resource_enable(io, false);
- DEV_DBG("%s: PLL not locked\n", __func__);
- }
-
- DEV_DBG("done, ret=%d\n", ret);
- return ret;
-}
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c b/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c
deleted file mode 100644
index 6a49d15..0000000
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-/*
- ***************************************************************************
- ******** Display Port PLL driver block diagram for branch clocks **********
- ***************************************************************************
-
- +--------------------------+
- | DP_VCO_CLK |
- | |
- | +-------------------+ |
- | | (DP PLL/VCO) | |
- | +---------+---------+ |
- | v |
- | +----------+-----------+ |
- | | hsclk_divsel_clk_src | |
- | +----------+-----------+ |
- +--------------------------+
- |
- v
- +------------<------------|------------>-------------+
- | | |
-+----------v----------+ +----------v----------+ +----------v----------+
-| dp_link_2x_clk | | vco_divided_clk_src | | vco_divided_clk_src |
-| divsel_five | | | | |
-v----------+----------v | divsel_two | | divsel_four |
- | +----------+----------+ +----------+----------+
- | | |
- v v v
- | +---------------------+ |
- Input to MMSSCC block | | (aux_clk_ops) | |
- for link clk, crypto clk +--> vco_divided_clk <-+
- and interface clock | _src_mux |
- +----------+----------+
- |
- v
- Input to MMSSCC block
- for DP pixel clock
-
- ******************************************************************************
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/clk/msm-clk-provider.h>
-#include <linux/clk/msm-clk.h>
-#include <linux/clk/msm-clock-generic.h>
-#include <dt-bindings/clock/msm-clocks-8998.h>
-
-#include "mdss-pll.h"
-#include "mdss-dp-pll.h"
-#include "mdss-dp-pll-8998.h"
-
-static const struct clk_ops clk_ops_vco_divided_clk_src_c;
-static const struct clk_ops clk_ops_link_2x_clk_div_c;
-static const struct clk_ops clk_ops_gen_mux_dp;
-
-static struct clk_div_ops link2xclk_divsel_ops = {
- .set_div = link2xclk_divsel_set_div,
- .get_div = link2xclk_divsel_get_div,
-};
-
-static struct clk_div_ops vco_divided_clk_ops = {
- .set_div = vco_divided_clk_set_div,
- .get_div = vco_divided_clk_get_div,
-};
-
-static const struct clk_ops dp_8998_vco_clk_ops = {
- .set_rate = dp_vco_set_rate,
- .round_rate = dp_vco_round_rate,
- .prepare = dp_vco_prepare,
- .unprepare = dp_vco_unprepare,
- .handoff = dp_vco_handoff,
-};
-
-static struct clk_mux_ops mdss_mux_ops = {
- .set_mux_sel = mdss_set_mux_sel,
- .get_mux_sel = mdss_get_mux_sel,
-};
-
-static struct dp_pll_vco_clk dp_vco_clk = {
- .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000,
- .max_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000,
- .c = {
- .dbg_name = "dp_vco_clk",
- .ops = &dp_8998_vco_clk_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dp_vco_clk.c),
- },
-};
-
-static struct div_clk dp_link_2x_clk_divsel_five = {
- .data = {
- .div = 5,
- .min_div = 5,
- .max_div = 5,
- },
- .ops = &link2xclk_divsel_ops,
- .c = {
- .parent = &dp_vco_clk.c,
- .dbg_name = "dp_link_2x_clk_divsel_five",
- .ops = &clk_ops_link_2x_clk_div_c,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dp_link_2x_clk_divsel_five.c),
- },
-};
-
-static struct div_clk vco_divsel_four_clk_src = {
- .data = {
- .div = 4,
- .min_div = 4,
- .max_div = 4,
- },
- .ops = &vco_divided_clk_ops,
- .c = {
- .parent = &dp_vco_clk.c,
- .dbg_name = "vco_divsel_four_clk_src",
- .ops = &clk_ops_vco_divided_clk_src_c,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(vco_divsel_four_clk_src.c),
- },
-};
-
-static struct div_clk vco_divsel_two_clk_src = {
- .data = {
- .div = 2,
- .min_div = 2,
- .max_div = 2,
- },
- .ops = &vco_divided_clk_ops,
- .c = {
- .parent = &dp_vco_clk.c,
- .dbg_name = "vco_divsel_two_clk_src",
- .ops = &clk_ops_vco_divided_clk_src_c,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(vco_divsel_two_clk_src.c),
- },
-};
-
-static struct mux_clk vco_divided_clk_src_mux = {
- .num_parents = 2,
- .parents = (struct clk_src[]) {
- {&vco_divsel_two_clk_src.c, 0},
- {&vco_divsel_four_clk_src.c, 1},
- },
- .ops = &mdss_mux_ops,
- .c = {
- .parent = &vco_divsel_two_clk_src.c,
- .dbg_name = "vco_divided_clk_src_mux",
- .ops = &clk_ops_gen_mux_dp,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(vco_divided_clk_src_mux.c),
- }
-};
-
-static struct clk_lookup dp_pllcc_8998[] = {
- CLK_LIST(dp_vco_clk),
- CLK_LIST(dp_link_2x_clk_divsel_five),
- CLK_LIST(vco_divsel_four_clk_src),
- CLK_LIST(vco_divsel_two_clk_src),
- CLK_LIST(vco_divided_clk_src_mux),
-};
-
-int dp_pll_clock_register_8998(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res)
-{
- int rc = -ENOTSUPP;
-
- if (!pll_res || !pll_res->pll_base || !pll_res->phy_base) {
- DEV_ERR("%s: Invalid input parameters\n", __func__);
- return -EINVAL;
- }
-
- /* Set client data for vco, mux and div clocks */
- dp_vco_clk.priv = pll_res;
- vco_divided_clk_src_mux.priv = pll_res;
- vco_divsel_two_clk_src.priv = pll_res;
- vco_divsel_four_clk_src.priv = pll_res;
- dp_link_2x_clk_divsel_five.priv = pll_res;
-
- clk_ops_link_2x_clk_div_c = clk_ops_div;
- clk_ops_link_2x_clk_div_c.prepare = mdss_pll_div_prepare;
-
- /*
- * Set the ops for the divider in the pixel clock tree to the
- * slave_div to ensure that a set rate on this divider clock will not
- * be propagated to it's parent. This is needed ensure that when we set
- * the rate for pixel clock, the vco is not reconfigured
- */
- clk_ops_vco_divided_clk_src_c = clk_ops_slave_div;
- clk_ops_vco_divided_clk_src_c.prepare = mdss_pll_div_prepare;
- clk_ops_vco_divided_clk_src_c.handoff = vco_divided_clk_handoff;
-
- clk_ops_gen_mux_dp = clk_ops_gen_mux;
- clk_ops_gen_mux_dp.get_rate = parent_get_rate;
-
- /* We can select different clock ops for future versions */
- dp_vco_clk.c.ops = &dp_8998_vco_clk_ops;
-
- rc = of_msm_clock_register(pdev->dev.of_node, dp_pllcc_8998,
- ARRAY_SIZE(dp_pllcc_8998));
- if (rc) {
- DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc);
- rc = -EPROBE_DEFER;
- } else {
- DEV_DBG("%s SUCCESS\n", __func__);
- }
-
- return rc;
-}
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h b/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h
deleted file mode 100644
index 11d5ddc..0000000
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __MDSS_DP_PLL_8998_H
-#define __MDSS_DP_PLL_8998_H
-
-#define DP_PHY_REVISION_ID0 0x0000
-#define DP_PHY_REVISION_ID1 0x0004
-#define DP_PHY_REVISION_ID2 0x0008
-#define DP_PHY_REVISION_ID3 0x000C
-
-#define DP_PHY_CFG 0x0010
-#define DP_PHY_PD_CTL 0x0014
-#define DP_PHY_MODE 0x0018
-
-#define DP_PHY_AUX_CFG0 0x001C
-#define DP_PHY_AUX_CFG1 0x0020
-#define DP_PHY_AUX_CFG2 0x0024
-#define DP_PHY_AUX_CFG3 0x0028
-#define DP_PHY_AUX_CFG4 0x002C
-#define DP_PHY_AUX_CFG5 0x0030
-#define DP_PHY_AUX_CFG6 0x0034
-#define DP_PHY_AUX_CFG7 0x0038
-#define DP_PHY_AUX_CFG8 0x003C
-#define DP_PHY_AUX_CFG9 0x0040
-#define DP_PHY_AUX_INTERRUPT_MASK 0x0044
-#define DP_PHY_AUX_INTERRUPT_CLEAR 0x0048
-#define DP_PHY_AUX_BIST_CFG 0x004C
-
-#define DP_PHY_VCO_DIV 0x0064
-#define DP_PHY_TX0_TX1_LANE_CTL 0x0068
-
-#define DP_PHY_TX2_TX3_LANE_CTL 0x0084
-#define DP_PHY_STATUS 0x00BC
-
-/* Tx registers */
-#define QSERDES_TX0_OFFSET 0x0400
-#define QSERDES_TX1_OFFSET 0x0800
-
-#define TXn_BIST_MODE_LANENO 0x0000
-#define TXn_CLKBUF_ENABLE 0x0008
-#define TXn_TX_EMP_POST1_LVL 0x000C
-
-#define TXn_TX_DRV_LVL 0x001C
-
-#define TXn_RESET_TSYNC_EN 0x0024
-#define TXn_PRE_STALL_LDO_BOOST_EN 0x0028
-#define TXn_TX_BAND 0x002C
-#define TXn_SLEW_CNTL 0x0030
-#define TXn_INTERFACE_SELECT 0x0034
-
-#define TXn_RES_CODE_LANE_TX 0x003C
-#define TXn_RES_CODE_LANE_RX 0x0040
-#define TXn_RES_CODE_LANE_OFFSET_TX 0x0044
-#define TXn_RES_CODE_LANE_OFFSET_RX 0x0048
-
-#define TXn_DEBUG_BUS_SEL 0x0058
-#define TXn_TRANSCEIVER_BIAS_EN 0x005C
-#define TXn_HIGHZ_DRVR_EN 0x0060
-#define TXn_TX_POL_INV 0x0064
-#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0068
-
-#define TXn_LANE_MODE_1 0x008C
-
-#define TXn_TRAN_DRVR_EMP_EN 0x00C0
-#define TXn_TX_INTERFACE_MODE 0x00C4
-
-#define TXn_VMODE_CTRL1 0x00F0
-
-
-/* PLL register offset */
-#define QSERDES_COM_ATB_SEL1 0x0000
-#define QSERDES_COM_ATB_SEL2 0x0004
-#define QSERDES_COM_FREQ_UPDATE 0x0008
-#define QSERDES_COM_BG_TIMER 0x000C
-#define QSERDES_COM_SSC_EN_CENTER 0x0010
-#define QSERDES_COM_SSC_ADJ_PER1 0x0014
-#define QSERDES_COM_SSC_ADJ_PER2 0x0018
-#define QSERDES_COM_SSC_PER1 0x001C
-#define QSERDES_COM_SSC_PER2 0x0020
-#define QSERDES_COM_SSC_STEP_SIZE1 0x0024
-#define QSERDES_COM_SSC_STEP_SIZE2 0x0028
-#define QSERDES_COM_POST_DIV 0x002C
-#define QSERDES_COM_POST_DIV_MUX 0x0030
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0034
-#define QSERDES_COM_CLK_ENABLE1 0x0038
-#define QSERDES_COM_SYS_CLK_CTRL 0x003C
-#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0040
-#define QSERDES_COM_PLL_EN 0x0044
-#define QSERDES_COM_PLL_IVCO 0x0048
-#define QSERDES_COM_CMN_IETRIM 0x004C
-#define QSERDES_COM_CMN_IPTRIM 0x0050
-
-#define QSERDES_COM_CP_CTRL_MODE0 0x0060
-#define QSERDES_COM_CP_CTRL_MODE1 0x0064
-#define QSERDES_COM_PLL_RCTRL_MODE0 0x0068
-#define QSERDES_COM_PLL_RCTRL_MODE1 0x006C
-#define QSERDES_COM_PLL_CCTRL_MODE0 0x0070
-#define QSERDES_COM_PLL_CCTRL_MODE1 0x0074
-#define QSERDES_COM_PLL_CNTRL 0x0078
-#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x007C
-#define QSERDES_COM_SYSCLK_EN_SEL 0x0080
-#define QSERDES_COM_CML_SYSCLK_SEL 0x0084
-#define QSERDES_COM_RESETSM_CNTRL 0x0088
-#define QSERDES_COM_RESETSM_CNTRL2 0x008C
-#define QSERDES_COM_LOCK_CMP_EN 0x0090
-#define QSERDES_COM_LOCK_CMP_CFG 0x0094
-#define QSERDES_COM_LOCK_CMP1_MODE0 0x0098
-#define QSERDES_COM_LOCK_CMP2_MODE0 0x009C
-#define QSERDES_COM_LOCK_CMP3_MODE0 0x00A0
-
-#define QSERDES_COM_DEC_START_MODE0 0x00B0
-#define QSERDES_COM_DEC_START_MODE1 0x00B4
-#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00B8
-#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00BC
-#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00C0
-#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x00C4
-#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x00C8
-#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x00CC
-#define QSERDES_COM_INTEGLOOP_INITVAL 0x00D0
-#define QSERDES_COM_INTEGLOOP_EN 0x00D4
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x00D8
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x00DC
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x00E0
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x00E4
-#define QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x00E8
-#define QSERDES_COM_VCO_TUNE_CTRL 0x00EC
-#define QSERDES_COM_VCO_TUNE_MAP 0x00F0
-
-#define QSERDES_COM_CMN_STATUS 0x0124
-#define QSERDES_COM_RESET_SM_STATUS 0x0128
-
-#define QSERDES_COM_CLK_SEL 0x0138
-#define QSERDES_COM_HSCLK_SEL 0x013C
-
-#define QSERDES_COM_CORECLK_DIV_MODE0 0x0148
-
-#define QSERDES_COM_SW_RESET 0x0150
-#define QSERDES_COM_CORE_CLK_EN 0x0154
-#define QSERDES_COM_C_READY_STATUS 0x0158
-#define QSERDES_COM_CMN_CONFIG 0x015C
-
-#define QSERDES_COM_SVS_MODE_CLK_SEL 0x0164
-
-#define DP_PLL_POLL_SLEEP_US 500
-#define DP_PLL_POLL_TIMEOUT_US 10000
-
-#define DP_VCO_RATE_8100MHZDIV1000 8100000UL
-#define DP_VCO_RATE_10800MHZDIV1000 10800000UL
-
-#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL
-#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL
-#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL
-
-int dp_vco_set_rate(struct clk *c, unsigned long rate);
-unsigned long dp_vco_get_rate(struct clk *c);
-long dp_vco_round_rate(struct clk *c, unsigned long rate);
-enum handoff dp_vco_handoff(struct clk *c);
-enum handoff vco_divided_clk_handoff(struct clk *c);
-int dp_vco_prepare(struct clk *c);
-void dp_vco_unprepare(struct clk *c);
-int hsclk_divsel_set_div(struct div_clk *clk, int div);
-int hsclk_divsel_get_div(struct div_clk *clk);
-int link2xclk_divsel_set_div(struct div_clk *clk, int div);
-int link2xclk_divsel_get_div(struct div_clk *clk);
-int vco_divided_clk_set_div(struct div_clk *clk, int div);
-int vco_divided_clk_get_div(struct div_clk *clk);
-
-#endif /* __MDSS_DP_PLL_8998_H */
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll.h b/drivers/clk/qcom/mdss/mdss-dp-pll.h
index 2805ff9..2b1d70e 100644
--- a/drivers/clk/qcom/mdss/mdss-dp-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,21 +15,19 @@
#define __MDSS_DP_PLL_H
struct dp_pll_vco_clk {
+ struct clk_hw hw;
unsigned long rate; /* current vco rate */
u64 min_rate; /* min vco rate */
u64 max_rate; /* max vco rate */
void *priv;
-
- struct clk c;
};
-static inline struct dp_pll_vco_clk *mdss_dp_to_vco_clk(struct clk *clk)
+static inline struct dp_pll_vco_clk *to_dp_vco_hw(struct clk_hw *hw)
{
- return container_of(clk, struct dp_pll_vco_clk, c);
+ return container_of(hw, struct dp_pll_vco_clk, hw);
}
-int dp_pll_clock_register_8998(struct platform_device *pdev,
+int dp_pll_clock_register_10nm(struct platform_device *pdev,
struct mdss_pll_resources *pll_res);
-
#endif /* __MDSS_DP_PLL_H */
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 7f82fda..e292ef8 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -21,6 +21,7 @@
#include <linux/iopoll.h>
#include "mdss-pll.h"
#include "mdss-dsi-pll.h"
+#include "mdss-dp-pll.h"
int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable)
{
@@ -126,6 +127,8 @@
if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_10nm"))
pll_res->pll_interface_type = MDSS_DSI_PLL_10NM;
+ if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_10nm"))
+ pll_res->pll_interface_type = MDSS_DP_PLL_10NM;
else
goto err;
@@ -151,6 +154,9 @@
case MDSS_DSI_PLL_10NM:
rc = dsi_pll_clock_register_10nm(pdev, pll_res);
break;
+ case MDSS_DP_PLL_10NM:
+ rc = dp_pll_clock_register_10nm(pdev, pll_res);
+ break;
case MDSS_UNKNOWN_PLL:
default:
rc = -EINVAL;
@@ -171,6 +177,7 @@
const char *label;
struct resource *pll_base_reg;
struct resource *phy_base_reg;
+ struct resource *tx0_base_reg, *tx1_base_reg;
struct resource *dynamic_pll_base_reg;
struct resource *gdsc_base_reg;
struct mdss_pll_resources *pll_res;
@@ -272,6 +279,30 @@
}
}
+ tx0_base_reg = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "ln_tx0_base");
+ if (tx0_base_reg) {
+ pll_res->ln_tx0_base = ioremap(tx0_base_reg->start,
+ resource_size(tx0_base_reg));
+ if (!pll_res->ln_tx0_base) {
+ pr_err("Unable to remap Lane TX0 base resources\n");
+ rc = -ENOMEM;
+ goto tx0_io_error;
+ }
+ }
+
+ tx1_base_reg = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "ln_tx1_base");
+ if (tx1_base_reg) {
+ pll_res->ln_tx1_base = ioremap(tx1_base_reg->start,
+ resource_size(tx1_base_reg));
+ if (!pll_res->ln_tx1_base) {
+ pr_err("Unable to remap Lane TX1 base resources\n");
+ rc = -ENOMEM;
+ goto tx1_io_error;
+ }
+ }
+
gdsc_base_reg = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "gdsc_base");
if (!gdsc_base_reg) {
@@ -309,6 +340,12 @@
if (pll_res->gdsc_base)
iounmap(pll_res->gdsc_base);
gdsc_io_error:
+ if (pll_res->ln_tx1_base)
+ iounmap(pll_res->ln_tx1_base);
+tx1_io_error:
+ if (pll_res->ln_tx0_base)
+ iounmap(pll_res->ln_tx0_base);
+tx0_io_error:
if (pll_res->dyn_pll_base)
iounmap(pll_res->dyn_pll_base);
dyn_pll_io_error:
@@ -347,6 +384,7 @@
static const struct of_device_id mdss_pll_dt_match[] = {
{.compatible = "qcom,mdss_dsi_pll_10nm"},
+ {.compatible = "qcom,mdss_dp_pll_10nm"},
{}
};
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index ee91e11..033462d 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -37,6 +37,7 @@
enum {
MDSS_DSI_PLL_10NM,
+ MDSS_DP_PLL_10NM,
MDSS_UNKNOWN_PLL,
};
@@ -81,6 +82,8 @@
*/
void __iomem *pll_base;
void __iomem *phy_base;
+ void __iomem *ln_tx0_base;
+ void __iomem *ln_tx1_base;
void __iomem *gdsc_base;
void __iomem *dyn_pll_base;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 8af73ac..d9ebe113 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -4877,15 +4877,12 @@
if (handle == NULL)
return -ENODEV;
- qce_enable_clk(pce_dev);
-
sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe;
sps_disconnect(sps_pipe_info);
sps_pipe_info = pce_dev->ce_bam_info.producer.pipe;
sps_disconnect(sps_pipe_info);
- qce_disable_clk(pce_dev);
return 0;
}
@@ -4899,8 +4896,6 @@
if (handle == NULL)
return -ENODEV;
- qce_enable_clk(pce_dev);
-
sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe;
sps_connect_info = &pce_dev->ce_bam_info.consumer.connect;
memset(sps_connect_info->desc.base, 0x00, sps_connect_info->desc.size);
@@ -4923,7 +4918,6 @@
if (rc)
pr_err("Producer callback registration failed rc = %d\n", rc);
- qce_disable_clk(pce_dev);
return rc;
}
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index ff64631..56fbb94 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -5371,8 +5371,11 @@
spin_unlock_irqrestore(&cp->lock, flags);
if (ret)
return ret;
- if (qce_pm_table.suspend)
+ if (qce_pm_table.suspend) {
+ qcrypto_ce_set_bus(pengine, true);
qce_pm_table.suspend(pengine->qce);
+ qcrypto_ce_set_bus(pengine, false);
+ }
return 0;
}
@@ -5393,9 +5396,11 @@
spin_lock_irqsave(&cp->lock, flags);
if (pengine->bw_state == BUS_SUSPENDED) {
spin_unlock_irqrestore(&cp->lock, flags);
- if (qce_pm_table.resume)
+ if (qce_pm_table.resume) {
+ qcrypto_ce_set_bus(pengine, true);
qce_pm_table.resume(pengine->qce);
-
+ qcrypto_ce_set_bus(pengine, false);
+ }
spin_lock_irqsave(&cp->lock, flags);
pengine->bw_state = BUS_NO_BANDWIDTH;
pengine->active_seq++;
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index a79a9c9..70581e2 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -20,14 +20,8 @@
#define DP_AUX_ENUM_STR(x) #x
-struct aux_buf {
- u8 *start; /* buffer start addr */
- u8 *end; /* buffer end addr */
- u8 *data; /* data pou32er */
- u32 size; /* size of buffer */
- u32 len; /* dara length */
- u8 trans_num; /* transaction number */
- enum aux_tx_mode tx_mode;
+enum {
+ DP_AUX_DATA_INDEX_WRITE = BIT(31),
};
struct dp_aux_private {
@@ -38,15 +32,12 @@
struct mutex mutex;
struct completion comp;
- struct aux_cmd *cmds;
- struct aux_buf txp;
- struct aux_buf rxp;
-
u32 aux_error_num;
bool cmd_busy;
+ bool native;
+ bool read;
- u8 txbuf[256];
- u8 rxbuf[256];
+ struct drm_dp_aux drm_aux;
};
static char *dp_aux_get_error(u32 aux_error)
@@ -69,159 +60,104 @@
}
}
-static void dp_aux_buf_init(struct aux_buf *buf, u8 *data, u32 size)
+static u32 dp_aux_write(struct dp_aux_private *aux,
+ struct drm_dp_aux_msg *msg)
{
- buf->start = data;
- buf->size = size;
- buf->data = buf->start;
- buf->end = buf->start + buf->size;
- buf->len = 0;
- buf->trans_num = 0;
- buf->tx_mode = AUX_NATIVE;
-}
+ u32 data[4], reg, len;
+ u8 *msgdata = msg->buffer;
+ int const aux_cmd_fifo_len = 128;
+ int i = 0;
-static void dp_aux_buf_set(struct dp_aux_private *aux)
-{
- init_completion(&aux->comp);
- aux->cmd_busy = false;
- mutex_init(&aux->mutex);
-
- dp_aux_buf_init(&aux->txp, aux->txbuf, sizeof(aux->txbuf));
- dp_aux_buf_init(&aux->rxp, aux->rxbuf, sizeof(aux->rxbuf));
-}
-
-static void dp_aux_buf_reset(struct aux_buf *buf)
-{
- buf->data = buf->start;
- buf->len = 0;
- buf->trans_num = 0;
- buf->tx_mode = AUX_NATIVE;
-
- memset(buf->start, 0x0, 256);
-}
-
-static void dp_aux_buf_push(struct aux_buf *buf, u32 len)
-{
- buf->data += len;
- buf->len += len;
-}
-
-static u32 dp_aux_buf_trailing(struct aux_buf *buf)
-{
- return (u32)(buf->end - buf->data);
-}
-
-static u32 dp_aux_add_cmd(struct aux_buf *buf, struct aux_cmd *cmd)
-{
- u8 data;
- u8 *bp, *cp;
- u32 i, len;
-
- if (cmd->ex_mode == AUX_READ)
+ if (aux->read)
len = 4;
else
- len = cmd->len + 4;
-
- if (dp_aux_buf_trailing(buf) < len) {
- pr_err("buf trailing error\n");
- return 0;
- }
+ len = msg->size + 4;
/*
* cmd fifo only has depth of 144 bytes
* limit buf length to 128 bytes here
*/
- if ((buf->len + len) > 128) {
+ if (len > aux_cmd_fifo_len) {
pr_err("buf len error\n");
return 0;
}
- bp = buf->data;
- data = cmd->addr >> 16;
- data &= 0x0f; /* 4 addr bits */
+ /* Pack cmd and write to HW */
+ data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
+ if (aux->read)
+ data[0] |= BIT(4); /* R/W */
- if (cmd->ex_mode == AUX_READ)
- data |= BIT(4);
+ data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */
+ data[2] = msg->address & 0xff; /* addr[7:0] */
+ data[3] = (msg->size - 1) & 0xff; /* len[7:0] */
- *bp++ = data;
- *bp++ = cmd->addr >> 8;
- *bp++ = cmd->addr;
- *bp++ = cmd->len - 1;
-
- if (cmd->ex_mode == AUX_WRITE) {
- cp = cmd->buf;
-
- for (i = 0; i < cmd->len; i++)
- *bp++ = *cp++;
- }
-
- dp_aux_buf_push(buf, len);
-
- buf->tx_mode = cmd->tx_mode;
-
- buf->trans_num++;
-
- return cmd->len - 1;
-}
-
-static u32 dp_aux_cmd_fifo_tx(struct dp_aux_private *aux)
-{
- u8 *dp;
- u32 data, len, cnt;
- struct aux_buf *tp = &aux->txp;
-
- len = tp->len;
- if (len == 0) {
- pr_err("invalid len\n");
- return 0;
- }
-
- cnt = 0;
- dp = tp->start;
-
- while (cnt < len) {
- data = *dp;
- data <<= 8;
- data &= 0x00ff00;
- if (cnt == 0)
- data |= BIT(31);
-
- aux->catalog->data = data;
+ for (i = 0; i < len; i++) {
+ reg = (i < 4) ? data[i] : msgdata[i - 4];
+ reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */
+ if (i == 0)
+ reg |= DP_AUX_DATA_INDEX_WRITE;
+ aux->catalog->data = reg;
aux->catalog->write_data(aux->catalog);
-
- cnt++;
- dp++;
}
- data = (tp->trans_num - 1);
- if (tp->tx_mode == AUX_I2C) {
- data |= BIT(8); /* I2C */
- data |= BIT(10); /* NO SEND ADDR */
- data |= BIT(11); /* NO SEND STOP */
- }
+ reg = 0; /* Transaction number == 1 */
+ if (!aux->native) /* i2c */
+ reg |= (BIT(8) | BIT(10) | BIT(11));
- data |= BIT(9); /* GO */
- aux->catalog->data = data;
+ reg |= BIT(9);
+ aux->catalog->data = reg;
aux->catalog->write_trans(aux->catalog);
- return tp->len;
+ return len;
}
-static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len)
+static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
+ struct drm_dp_aux_msg *msg)
+{
+ u32 ret = 0, len = 0, timeout;
+ int const aux_timeout_ms = HZ/4;
+
+ reinit_completion(&aux->comp);
+
+ len = dp_aux_write(aux, msg);
+ if (len == 0) {
+ pr_err("DP AUX write failed\n");
+ return -EINVAL;
+ }
+
+ timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
+ if (!timeout) {
+ pr_err("aux write timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ pr_debug("aux status %s\n",
+ dp_aux_get_error(aux->aux_error_num));
+
+ if (aux->aux_error_num == DP_AUX_ERR_NONE)
+ ret = len;
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
+ struct drm_dp_aux_msg *msg)
{
u32 data;
u8 *dp;
u32 i;
- struct aux_buf *rp = &aux->rxp;
+ u32 len = msg->size;
data = 0;
- data |= BIT(31); /* INDEX_WRITE */
+ data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
data |= BIT(0); /* read */
aux->catalog->data = data;
aux->catalog->write_data(aux->catalog);
- dp = rp->data;
+ dp = msg->buffer;
/* discard first byte */
data = aux->catalog->read_data(aux->catalog);
@@ -230,9 +166,6 @@
data = aux->catalog->read_data(aux->catalog);
*dp++ = (u8)((data >> 8) & 0xff);
}
-
- rp->len = len;
- return len;
}
static void dp_aux_native_handler(struct dp_aux_private *aux)
@@ -292,219 +225,76 @@
if (!aux->cmd_busy)
return;
- if (aux->cmds->tx_mode == AUX_NATIVE)
+ if (aux->native)
dp_aux_native_handler(aux);
else
dp_aux_i2c_handler(aux);
}
-
-
-static int dp_aux_write(struct dp_aux_private *aux)
+/*
+ * This function does the real job to process an AUX transaction.
+ * It will call aux_reset() function to reset the AUX channel,
+ * if the waiting is timeout.
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
+ struct drm_dp_aux_msg *msg)
{
- struct aux_cmd *cm;
- struct aux_buf *tp;
- u32 len, ret, timeout;
+ ssize_t ret;
+ int const aux_cmd_native_max = 16;
+ int const aux_cmd_i2c_max = 128;
+ struct dp_aux_private *aux = container_of(drm_aux,
+ struct dp_aux_private, drm_aux);
mutex_lock(&aux->mutex);
- tp = &aux->txp;
- dp_aux_buf_reset(tp);
-
- cm = aux->cmds;
- while (cm) {
- ret = dp_aux_add_cmd(tp, cm);
- if (ret <= 0)
- break;
-
- if (!cm->next)
- break;
- cm++;
- }
-
- reinit_completion(&aux->comp);
+ aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+ aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
aux->cmd_busy = true;
- len = dp_aux_cmd_fifo_tx(aux);
-
- timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
- if (!timeout)
- pr_err("aux write timeout\n");
-
- pr_debug("aux status %s\n",
- dp_aux_get_error(aux->aux_error_num));
-
- if (aux->aux_error_num == DP_AUX_ERR_NONE)
- ret = len;
- else
- ret = aux->aux_error_num;
-
- aux->cmd_busy = false;
- mutex_unlock(&aux->mutex);
- return ret;
-}
-
-static int dp_aux_read(struct dp_aux_private *aux)
-{
- struct aux_cmd *cm;
- struct aux_buf *tp, *rp;
- u32 len, ret, timeout;
-
- mutex_lock(&aux->mutex);
-
- tp = &aux->txp;
- rp = &aux->rxp;
-
- dp_aux_buf_reset(tp);
- dp_aux_buf_reset(rp);
-
- cm = aux->cmds;
- len = 0;
-
- while (cm) {
- ret = dp_aux_add_cmd(tp, cm);
- len += cm->len;
-
- if (ret <= 0)
- break;
-
- if (!cm->next)
- break;
- cm++;
+ /* Ignore address only message */
+ if ((msg->size == 0) || (msg->buffer == NULL)) {
+ msg->reply = aux->native ?
+ DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+ ret = msg->size;
+ goto unlock_exit;
}
- reinit_completion(&aux->comp);
- aux->cmd_busy = true;
+ /* msg sanity check */
+ if ((aux->native && (msg->size > aux_cmd_native_max)) ||
+ (msg->size > aux_cmd_i2c_max)) {
+ pr_err("%s: invalid msg: size(%zu), request(%x)\n",
+ __func__, msg->size, msg->request);
+ ret = -EINVAL;
+ goto unlock_exit;
+ }
- dp_aux_cmd_fifo_tx(aux);
+ ret = dp_aux_cmd_fifo_tx(aux, msg);
+ if (ret < 0) {
+ aux->catalog->reset(aux->catalog); /* reset aux */
+ goto unlock_exit;
+ }
- timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
- if (!timeout)
- pr_err("aux read timeout\n");
+ if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+ if (aux->read)
+ dp_aux_cmd_fifo_rx(aux, msg);
- pr_debug("aux status %s\n",
- dp_aux_get_error(aux->aux_error_num));
+ msg->reply = aux->native ?
+ DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+ } else {
+ /* Reply defer to retry */
+ msg->reply = aux->native ?
+ DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+ }
- if (aux->aux_error_num == DP_AUX_ERR_NONE)
- ret = dp_cmd_fifo_rx(aux, len);
- else
- ret = aux->aux_error_num;
+ /* Return requested size for success or retry */
+ ret = msg->size;
- aux->cmds->buf = rp->data;
+unlock_exit:
aux->cmd_busy = false;
-
mutex_unlock(&aux->mutex);
-
return ret;
}
-static int dp_aux_write_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
- enum aux_tx_mode mode, u8 *buf)
-{
- struct aux_cmd cmd = {0};
- struct dp_aux_private *aux;
-
- if (!dp_aux || !len) {
- pr_err("invalid input\n");
- return -EINVAL;
- }
-
- aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
- cmd.ex_mode = AUX_WRITE;
- cmd.tx_mode = mode;
- cmd.addr = addr;
- cmd.len = len;
- cmd.buf = buf;
-
- aux->cmds = &cmd;
-
- return dp_aux_write(aux);
-}
-
-static int dp_aux_read_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
- enum aux_tx_mode mode, u8 **buf)
-{
- int rc = 0;
- struct aux_cmd cmd = {0};
- struct dp_aux_private *aux;
-
- if (!dp_aux || !len) {
- pr_err("invalid input\n");
- rc = -EINVAL;
- goto end;
- }
-
- aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
- cmd.ex_mode = AUX_READ;
- cmd.tx_mode = mode;
- cmd.addr = addr;
- cmd.len = len;
-
- aux->cmds = &cmd;
-
- rc = dp_aux_read(aux);
- if (rc <= 0) {
- rc = -EINVAL;
- goto end;
- }
-
- *buf = cmd.buf;
-end:
- return rc;
-}
-
-static int dp_aux_process(struct dp_aux *dp_aux, struct aux_cmd *cmds)
-{
- struct dp_aux_private *aux;
-
- if (!dp_aux || !cmds) {
- pr_err("invalid input\n");
- return -EINVAL;
- }
-
- aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
- aux->cmds = cmds;
-
- if (cmds->ex_mode == AUX_READ)
- return dp_aux_read(aux);
- else
- return dp_aux_write(aux);
-}
-
-static bool dp_aux_ready(struct dp_aux *dp_aux)
-{
- u8 data = 0;
- int count, ret;
- struct dp_aux_private *aux;
-
- if (!dp_aux) {
- pr_err("invalid input\n");
- goto error;
- }
-
- aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
- for (count = 5; count; count--) {
- ret = dp_aux_write_ex(dp_aux, 0x50, 1, AUX_I2C, &data);
- if (ret >= 0)
- break;
-
- msleep(100);
- }
-
- if (count <= 0) {
- pr_err("aux chan NOT ready\n");
- goto error;
- }
-
- return true;
-error:
- return false;
-}
-
static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg)
{
struct dp_aux_private *aux;
@@ -535,6 +325,45 @@
aux->catalog->enable(aux->catalog, false);
}
+static int dp_aux_register(struct dp_aux *dp_aux)
+{
+ struct dp_aux_private *aux;
+ int ret = 0;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ aux->drm_aux.name = "sde_dp_aux";
+ aux->drm_aux.dev = aux->dev;
+ aux->drm_aux.transfer = dp_aux_transfer;
+ ret = drm_dp_aux_register(&aux->drm_aux);
+ if (ret) {
+ pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
+ goto exit;
+ }
+ dp_aux->drm_aux = &aux->drm_aux;
+exit:
+ return ret;
+}
+
+static void dp_aux_deregister(struct dp_aux *dp_aux)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+ drm_dp_aux_unregister(&aux->drm_aux);
+}
+
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
{
int rc = 0;
@@ -553,21 +382,19 @@
goto error;
}
+ init_completion(&aux->comp);
+ aux->cmd_busy = false;
+ mutex_init(&aux->mutex);
+
aux->dev = dev;
-
- dp_aux_buf_set(aux);
-
aux->catalog = catalog;
-
dp_aux = &aux->dp_aux;
- dp_aux->process = dp_aux_process;
- dp_aux->read = dp_aux_read_ex;
- dp_aux->write = dp_aux_write_ex;
- dp_aux->ready = dp_aux_ready;
dp_aux->isr = dp_aux_isr;
dp_aux->init = dp_aux_init;
dp_aux->deinit = dp_aux_deinit;
+ dp_aux->drm_aux_register = dp_aux_register;
+ dp_aux->drm_aux_deregister = dp_aux_deregister;
return dp_aux;
error:
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index 0603c15..f08c12b 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -16,6 +16,7 @@
#define _DP_AUX_H_
#include "dp_catalog.h"
+#include "drm_dp_helper.h"
enum dp_aux_error {
DP_AUX_ERR_NONE = 0,
@@ -26,32 +27,10 @@
DP_AUX_ERR_NACK_DEFER = -5,
};
-enum aux_tx_mode {
- AUX_NATIVE,
- AUX_I2C,
-};
-
-enum aux_exe_mode {
- AUX_WRITE,
- AUX_READ,
-};
-
-struct aux_cmd {
- enum aux_exe_mode ex_mode;
- enum aux_tx_mode tx_mode;
- u32 addr;
- u32 len;
- u8 *buf;
- bool next;
-};
-
struct dp_aux {
- int (*process)(struct dp_aux *aux, struct aux_cmd *cmd);
- int (*write)(struct dp_aux *aux, u32 addr, u32 len,
- enum aux_tx_mode mode, u8 *buf);
- int (*read)(struct dp_aux *aux, u32 addr, u32 len,
- enum aux_tx_mode mode, u8 **buf);
- bool (*ready)(struct dp_aux *aux);
+ struct drm_dp_aux *drm_aux;
+ int (*drm_aux_register)(struct dp_aux *aux);
+ void (*drm_aux_deregister)(struct dp_aux *aux);
void (*isr)(struct dp_aux *aux);
void (*init)(struct dp_aux *aux, u32 *aux_cfg);
void (*deinit)(struct dp_aux *aux);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index ca55d16..9361b52 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -177,8 +177,6 @@
#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004)
-#define EDID_START_ADDRESS 0x50
-
/* DP MMSS_CC registers */
#define MMSS_DP_LINK_CMD_RCGR (0x0138)
#define MMSS_DP_LINK_CFG_RCGR (0x013C)
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 56f6052..888c511 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -20,14 +20,9 @@
#include "dp_ctrl.h"
-#define DP_LINK_RATE_MULTIPLIER 27000000
#define DP_KHZ_TO_HZ 1000
#define DP_CRYPTO_CLK_RATE_KHZ 180000
-/* sink power state */
-#define SINK_POWER_ON 1
-#define SINK_POWER_OFF 2
-
#define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0)
#define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3)
@@ -103,14 +98,6 @@
complete(&ctrl->video_comp);
}
-static void dp_ctrl_set_sink_power_state(struct dp_ctrl_private *ctrl,
- u8 power_state)
-{
- const int len = 1;
-
- ctrl->aux->write(ctrl->aux, 0x600, len, AUX_NATIVE, &power_state);
-}
-
static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
{
ctrl->catalog->state_ctrl(ctrl->catalog, state);
@@ -128,7 +115,7 @@
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
- dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_OFF);
+ drm_dp_link_power_down(ctrl->aux->drm_aux, &ctrl->panel->dp_link);
reinit_completion(&ctrl->idle_comp);
dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
@@ -143,12 +130,13 @@
static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
{
u32 config = 0, tbd;
+ u8 *dpcd = ctrl->panel->dpcd;
config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */
config |= (0 << 11); /* RGB */
/* Scrambler reset enable */
- if (ctrl->panel->dpcd.scrambler_reset)
+ if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
config |= (1 << 10);
tbd = ctrl->link->get_test_bits_depth(ctrl->link,
@@ -158,7 +146,7 @@
/* Num of Lanes */
config |= ((ctrl->link->lane_count - 1) << 4);
- if (ctrl->panel->dpcd.enhanced_frame)
+ if (drm_dp_enhanced_frame_cap(dpcd))
config |= 0x40;
config |= 0x04; /* progressive video */
@@ -327,7 +315,7 @@
even_distribution = 0;
min_hblank = 0;
- lclk = link_rate * DP_LINK_RATE_MULTIPLIER;
+ lclk = drm_dp_bw_code_to_link_rate(link_rate) * DP_KHZ_TO_HZ;
pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
pclk, lwidth, h_blank);
@@ -763,7 +751,7 @@
buf[i] = voltage_level | pre_emphasis_level | max_level_reached;
pr_debug("p|v=0x%x\n", voltage_level | pre_emphasis_level);
- return ctrl->aux->write(ctrl->aux, 0x103, 4, AUX_NATIVE, buf);
+ return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
}
static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
@@ -778,25 +766,6 @@
dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level);
}
-static void dp_ctrl_cap_lane_rate_set(struct dp_ctrl_private *ctrl)
-{
- u8 buf[4];
- struct dp_panel_dpcd *cap;
-
- cap = &ctrl->panel->dpcd;
-
- pr_debug("bw=%x lane=%d\n", ctrl->link->link_rate,
- ctrl->link->lane_count);
-
- buf[0] = ctrl->link->link_rate;
- buf[1] = ctrl->link->lane_count;
-
- if (cap->enhanced_frame)
- buf[1] |= 0x80;
-
- ctrl->aux->write(ctrl->aux, 0x100, 2, AUX_NATIVE, buf);
-}
-
static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
u8 pattern)
{
@@ -805,33 +774,39 @@
pr_debug("pattern=%x\n", pattern);
buf[0] = pattern;
- ctrl->aux->write(ctrl->aux, 0x102, 1, AUX_NATIVE, buf);
+ drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1);
}
static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
{
- int tries, old_v_level;
- int ret = 0;
- int usleep_time;
+ int tries, old_v_level, ret = 0, len = 0;
+ u8 link_status[DP_LINK_STATUS_SIZE];
int const maximum_retries = 5;
dp_ctrl_state_ctrl(ctrl, 0);
-
/* Make sure to clear the current pattern before starting a new one */
wmb();
ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
- dp_ctrl_cap_lane_rate_set(ctrl);
- dp_ctrl_train_pattern_set(ctrl, 0x21); /* train_1 */
+ dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
+ DP_RECOVERED_CLOCK_OUT_EN); /* train_1 */
dp_ctrl_update_vx_px(ctrl);
tries = 0;
old_v_level = ctrl->link->v_level;
while (1) {
- usleep_time = ctrl->panel->dpcd.training_read_interval;
- usleep_range(usleep_time, usleep_time * 2);
+ drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
- if (ctrl->link->clock_recovery(ctrl->link)) {
+ len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
+ link_status);
+ if (len < DP_LINK_STATUS_SIZE) {
+ pr_err("[%s]: DP link status read failed\n", __func__);
+ ret = -1;
+ break;
+ }
+
+ if (drm_dp_clock_recovery_ok(link_status,
+ ctrl->link->lane_count)) {
ret = 0;
break;
}
@@ -852,8 +827,7 @@
old_v_level = ctrl->link->v_level;
}
- ctrl->link->adjust_levels(ctrl->link);
-
+ ctrl->link->adjust_levels(ctrl->link, link_status);
dp_ctrl_update_vx_px(ctrl);
}
@@ -869,15 +843,15 @@
switch (ctrl->link->link_rate) {
case DP_LINK_RATE_810:
- ctrl->link->link_rate = DP_LINK_RATE_540;
+ ctrl->link->link_rate = DP_LINK_BW_5_4;
break;
- case DP_LINK_RATE_540:
- ctrl->link->link_rate = DP_LINK_RATE_270;
+ case DP_LINK_BW_5_4:
+ ctrl->link->link_rate = DP_LINK_BW_2_7;
break;
- case DP_LINK_RATE_270:
- ctrl->link->link_rate = DP_LINK_RATE_162;
+ case DP_LINK_BW_2_7:
+ ctrl->link->link_rate = DP_LINK_BW_1_62;
break;
- case DP_LINK_RATE_162:
+ case DP_LINK_BW_1_62:
default:
ret = -EINVAL;
break;
@@ -890,36 +864,38 @@
static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
{
- int usleep_time;
-
dp_ctrl_train_pattern_set(ctrl, 0);
-
- usleep_time = ctrl->panel->dpcd.training_read_interval;
- usleep_range(usleep_time, usleep_time * 2);
+ drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
}
static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
{
- int tries = 0;
- int ret = 0;
- int usleep_time;
+ int tries = 0, ret = 0, len = 0;
char pattern;
int const maximum_retries = 5;
+ u8 link_status[DP_LINK_STATUS_SIZE];
- if (ctrl->panel->dpcd.flags & DPCD_TPS3)
- pattern = 0x03;
+ if (drm_dp_tps3_supported(ctrl->panel->dpcd))
+ pattern = DP_TRAINING_PATTERN_3;
else
- pattern = 0x02;
+ pattern = DP_TRAINING_PATTERN_2;
dp_ctrl_update_vx_px(ctrl);
ctrl->catalog->set_pattern(ctrl->catalog, pattern);
- dp_ctrl_train_pattern_set(ctrl, pattern | 0x20);
+ dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);
do {
- usleep_time = ctrl->panel->dpcd.training_read_interval;
- usleep_range(usleep_time, usleep_time * 2);
+ drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
- if (ctrl->link->channel_equalization(ctrl->link)) {
+ len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
+ link_status);
+ if (len < DP_LINK_STATUS_SIZE) {
+ pr_err("[%s]: DP link status read failed\n", __func__);
+ ret = -1;
+ break;
+ }
+
+ if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count)) {
ret = 0;
break;
}
@@ -930,8 +906,7 @@
}
tries++;
- ctrl->link->adjust_levels(ctrl->link);
-
+ ctrl->link->adjust_levels(ctrl->link, link_status);
dp_ctrl_update_vx_px(ctrl);
} while (1);
@@ -941,12 +916,7 @@
static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
{
int ret = 0;
-
- ret = ctrl->aux->ready(ctrl->aux);
- if (!ret) {
- pr_err("aux chan NOT ready\n");
- return ret;
- }
+ struct drm_dp_link dp_link;
ctrl->link->p_level = 0;
ctrl->link->v_level = 0;
@@ -954,6 +924,11 @@
dp_ctrl_config_ctrl(ctrl);
dp_ctrl_state_ctrl(ctrl, 0);
+ dp_link.num_lanes = ctrl->link->lane_count;
+ dp_link.rate = ctrl->link->link_rate;
+ dp_link.capabilities = ctrl->panel->dp_link.capabilities;
+ drm_dp_link_configure(ctrl->aux->drm_aux, &dp_link);
+
ret = dp_ctrl_link_train_1(ctrl);
if (ret < 0) {
if (!dp_ctrl_link_rate_down_shift(ctrl)) {
@@ -1007,7 +982,7 @@
ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
- dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_ON);
+ drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->dp_link);
if (ctrl->link->phy_pattern_requested(ctrl->link))
goto end;
@@ -1065,8 +1040,7 @@
ctrl->power->set_pixel_clk_parent(ctrl->power);
dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
- (ctrl->link->link_rate * DP_LINK_RATE_MULTIPLIER) /
- DP_KHZ_TO_HZ);
+ drm_dp_bw_code_to_link_rate(ctrl->link->link_rate));
dp_ctrl_set_clock_rate(ctrl, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ);
@@ -1208,7 +1182,7 @@
ctrl->catalog->hpd_config(ctrl->catalog, true);
ctrl->link->link_rate = ctrl->panel->get_link_rate(ctrl->panel);
- ctrl->link->lane_count = ctrl->panel->dpcd.max_lane_count;
+ ctrl->link->lane_count = ctrl->panel->dp_link.num_lanes;
ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
pr_debug("link_rate=%d, lane_count=%d, pixel_rate=%d\n",
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 850acbf..d3f6bca 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -195,6 +195,18 @@
goto end;
}
+ rc = dp->aux->drm_aux_register(dp->aux);
+ if (rc) {
+ pr_err("DRM DP AUX register failed\n");
+ goto end;
+ }
+
+ rc = dp->panel->sde_edid_register(dp->panel);
+ if (rc) {
+ pr_err("DRM DP EDID register failed\n");
+ goto end;
+ }
+
rc = dp->power->power_client_init(dp->power, &priv->phandle);
if (rc) {
pr_err("Power client create failed\n");
@@ -227,6 +239,10 @@
(void)dp->power->power_client_deinit(dp->power);
+ (void) dp->panel->sde_edid_deregister(dp->panel);
+
+ (void) dp->aux->drm_aux_deregister(dp->aux);
+
(void)dp_display_debugfs_deinit(dp);
mutex_unlock(&dp->lock);
@@ -245,9 +261,8 @@
if (rc)
goto end;
- rc = dp->panel->read_edid(dp->panel);
- if (rc)
- goto end;
+ sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
+ (void **)&dp->panel->edid_ctrl);
return 0;
end:
@@ -256,6 +271,7 @@
static int dp_display_process_hpd_low(struct dp_display_private *dp)
{
+ dp->dp_display.is_connected = false;
return 0;
}
@@ -290,6 +306,7 @@
if (dp->usbpd->hpd_high)
dp_display_process_hpd_high(dp);
+ dp->dp_display.is_connected = true;
mutex_unlock(&dp->lock);
end:
@@ -315,6 +332,7 @@
}
mutex_lock(&dp->lock);
+ dp->dp_display.is_connected = false;
disable_irq(dp->irq);
mutex_unlock(&dp->lock);
@@ -573,33 +591,17 @@
return 0;
}
-static int dp_display_get_modes(struct dp_display *dp,
- struct dp_display_mode *modes, u32 *count)
+static int dp_display_get_modes(struct dp_display *dp)
{
- *count = 1;
+ int ret = 0;
+ struct dp_display_private *dp_display;
- if (modes) {
- modes->timing.h_active = 1920;
- modes->timing.v_active = 1080;
- modes->timing.h_back_porch = 148;
- modes->timing.h_front_porch = 88;
- modes->timing.h_sync_width = 44;
- modes->timing.h_active_low = 0;
- modes->timing.v_back_porch = 36;
- modes->timing.v_front_porch = 4;
- modes->timing.v_sync_width = 5;
- modes->timing.v_active_low = 0;
- modes->timing.h_skew = 0;
- modes->timing.refresh_rate = 60;
- modes->timing.pixel_clk_khz = 148500;
- }
+ dp_display = container_of(dp, struct dp_display_private, dp_display);
- return 0;
-}
+ ret = _sde_edid_update_modes(dp->connector,
+ dp_display->panel->edid_ctrl);
-static int dp_display_detect(struct dp_display *dp)
-{
- return 0;
+ return ret;
}
static int dp_display_probe(struct platform_device *pdev)
@@ -637,7 +639,6 @@
g_dp_display->set_mode = dp_display_set_mode;
g_dp_display->validate_mode = dp_display_validate_mode;
g_dp_display->get_modes = dp_display_get_modes;
- g_dp_display->detect = dp_display_detect;
g_dp_display->prepare = dp_display_prepare;
g_dp_display->unprepare = dp_display_unprepare;
g_dp_display->request_irq = dp_request_irq;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index e684854..877287a 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -27,6 +27,8 @@
struct dp_display {
struct drm_device *drm_dev;
struct dp_bridge *bridge;
+ struct drm_connector *connector;
+ bool is_connected;
int (*enable)(struct dp_display *dp_display);
int (*post_enable)(struct dp_display *dp_display);
@@ -38,11 +40,7 @@
struct dp_display_mode *mode);
int (*validate_mode)(struct dp_display *dp_display,
struct dp_display_mode *mode);
- int (*get_modes)(struct dp_display *dp_display,
- struct dp_display_mode *modes, u32 *count);
-
- int (*detect)(struct dp_display *dp_display);
-
+ int (*get_modes)(struct dp_display *dp_display);
int (*prepare)(struct dp_display *dp_display);
int (*unprepare)(struct dp_display *dp_display);
int (*request_irq)(struct dp_display *dp_display);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 0f6e36f..78c04c4 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -26,8 +26,10 @@
#define to_dp_bridge(x) container_of((x), struct dp_bridge, base)
static void convert_to_dp_mode(const struct drm_display_mode *drm_mode,
- struct dp_display_mode *dp_mode)
+ struct dp_display_mode *dp_mode, struct dp_display *dp)
{
+ const u32 num_components = 3;
+
memset(dp_mode, 0, sizeof(*dp_mode));
dp_mode->timing.h_active = drm_mode->hdisplay;
@@ -45,6 +47,7 @@
dp_mode->timing.v_front_porch = drm_mode->vsync_start -
drm_mode->vdisplay;
+ dp_mode->timing.bpp = dp->connector->display_info.bpc * num_components;
dp_mode->timing.refresh_rate = drm_mode->vrefresh;
@@ -235,7 +238,7 @@
dp = bridge->display;
memset(&bridge->dp_mode, 0x0, sizeof(struct dp_display_mode));
- convert_to_dp_mode(adjusted_mode, &bridge->dp_mode);
+ convert_to_dp_mode(adjusted_mode, &bridge->dp_mode, dp);
}
static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
@@ -257,7 +260,7 @@
bridge = to_dp_bridge(drm_bridge);
dp = bridge->display;
- convert_to_dp_mode(mode, &dp_mode);
+ convert_to_dp_mode(mode, &dp_mode, dp);
rc = dp->validate_mode(dp, &dp_mode);
if (rc) {
@@ -289,6 +292,7 @@
if (!info || !dp_display)
return -EINVAL;
+ dp_display->connector = connector;
return 0;
}
@@ -315,7 +319,7 @@
int dp_connector_get_info(struct msm_display_info *info, void *data)
{
- struct dsi_display *display = data;
+ struct dp_display *display = data;
if (!info || !display) {
pr_err("invalid params\n");
@@ -326,17 +330,10 @@
info->num_of_h_tiles = 1;
info->h_tile_instance[0] = 0;
-
- info->is_connected = true;
- info->frame_rate = 60;
- info->width_mm = 160;
- info->height_mm = 90;
- info->max_width = 1920;
- info->max_height = 1080;
- info->vtotal = 1125;
- info->is_primary = true;
+ info->is_connected = display->is_connected;
info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
- info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
+ info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID |
+ MSM_DISPLAY_CAP_HOT_PLUG;
return 0;
}
@@ -375,60 +372,23 @@
int dp_connector_get_modes(struct drm_connector *connector,
void *display)
{
- u32 count = 0;
- u32 size = 0;
- struct dp_display_mode *modes;
- struct drm_display_mode drm_mode;
+ int rc = 0;
struct dp_display *dp;
- int rc, i;
- if (!connector || !display || sde_connector_get_panel(connector))
- goto end;
+ if (!connector || !display)
+ return -EINVAL;
dp = display;
-
- rc = dp->get_modes(dp, NULL, &count);
- if (rc) {
- pr_err("failed to get num of modes, rc=%d\n", rc);
- goto end;
+ /* pluggable case assumes EDID is read when HPD */
+ if (dp->is_connected) {
+ rc = dp->get_modes(dp);
+ if (!rc)
+ pr_err("failed to get DP sink modes, rc=%d\n", rc);
+ } else {
+ pr_err("No sink connected\n");
}
- size = count * sizeof(*modes);
- modes = kzalloc(size, GFP_KERNEL);
- if (!modes) {
- count = 0;
- goto end;
- }
-
- rc = dp->get_modes(dp, modes, &count);
- if (rc) {
- pr_err("failed to get modes, rc=%d\n", rc);
- count = 0;
- goto error;
- }
-
- for (i = 0; i < count; i++) {
- struct drm_display_mode *m;
-
- memset(&drm_mode, 0x0, sizeof(drm_mode));
- convert_to_drm_mode(&modes[i], &drm_mode);
- m = drm_mode_duplicate(connector->dev, &drm_mode);
- if (!m) {
- pr_err("failed to add mode %ux%u\n",
- drm_mode.hdisplay,
- drm_mode.vdisplay);
- count = -ENOMEM;
- goto error;
- }
- m->width_mm = connector->display_info.width_mm;
- m->height_mm = connector->display_info.height_mm;
- drm_mode_probed_add(connector, m);
- }
-error:
- kfree(modes);
-end:
- pr_debug("MODE COUNT =%d\n\n", count);
- return count;
+ return 0;
}
int dp_drm_bridge_init(void *data, struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index e9955a9..741acfca 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -114,18 +114,6 @@
bool cp_ready;
};
-struct dp_link_status {
- u8 lane_01_status;
- u8 lane_23_status;
- u8 interlane_align_done;
- u8 downstream_port_status_changed;
- u8 link_status_updated;
- u8 port_0_in_sync;
- u8 port_1_in_sync;
- u8 req_voltage_swing[4];
- u8 req_pre_emphasis[4];
-};
-
struct dp_link_private {
struct device *dev;
struct dp_aux *aux;
@@ -133,7 +121,7 @@
struct dp_link_request request;
struct dp_link_sink_count sink_count;
- struct dp_link_status link_status;
+ u8 link_status[DP_LINK_STATUS_SIZE];
};
/**
@@ -232,13 +220,12 @@
int ret = 0;
u8 *bp;
u8 data;
- int rlen;
u32 const param_len = 0x1;
u32 const max_audio_period = 0xA;
/* TEST_AUDIO_PERIOD_CH_XX */
- rlen = link->aux->read(link->aux, addr, param_len, AUX_NATIVE, &bp);
- if (rlen < param_len) {
+ if (drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp,
+ param_len) < param_len) {
pr_err("failed to read test_audio_period (0x%x)\n", addr);
ret = -EINVAL;
goto exit;
@@ -350,8 +337,8 @@
int const max_audio_pattern_type = 0x1;
/* Read the requested audio pattern type (Byte 0x272). */
- rlen = link->aux->read(link->aux, test_audio_pattern_type_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux,
+ test_audio_pattern_type_addr, &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link audio mode data\n");
ret = -EINVAL;
@@ -387,8 +374,8 @@
int channel_count = 0x0;
/* Read the requested audio mode (Byte 0x271). */
- rlen = link->aux->read(link->aux, test_audio_mode_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_audio_mode_addr,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link audio mode data\n");
ret = -EINVAL;
@@ -555,7 +542,7 @@
return -EINVAL;
/* Read the requested video link pattern (Byte 0x221). */
- rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
if (rlen < len) {
pr_err("failed to read 0x%x\n", addr);
return -EINVAL;
@@ -576,7 +563,7 @@
return -EINVAL;
/* Read the requested video link pattern (Byte 0x221). */
- rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
if (rlen < len) {
pr_err("failed to read 0x%x\n", addr);
return -EINVAL;
@@ -596,7 +583,7 @@
int rlen;
/* Read the requested video link pattern (Byte 0x221). */
- rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
if (rlen < 1) {
pr_err("failed to read 0x%x\n", addr);
return -EINVAL;
@@ -625,8 +612,8 @@
int const test_misc_addr = 0x232;
/* Read the requested video link pattern (Byte 0x221). */
- rlen = link->aux->read(link->aux, test_video_pattern_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_video_pattern_addr,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link video pattern\n");
ret = -EINVAL;
@@ -647,8 +634,8 @@
link->request.test_video_pattern));
/* Read the requested color bit depth and dynamic range (Byte 0x232) */
- rlen = link->aux->read(link->aux, test_misc_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_misc_addr,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link bit depth\n");
ret = -EINVAL;
@@ -780,9 +767,9 @@
*/
static bool dp_link_is_link_rate_valid(u32 link_rate)
{
- return ((link_rate == DP_LINK_RATE_162) ||
- (link_rate == DP_LINK_RATE_270) ||
- (link_rate == DP_LINK_RATE_540) ||
+ return ((link_rate == DP_LINK_BW_1_62) ||
+ (link_rate == DP_LINK_BW_2_7) ||
+ (link_rate == DP_LINK_BW_5_4) ||
(link_rate == DP_LINK_RATE_810));
}
@@ -814,12 +801,10 @@
int ret = 0;
int rlen;
int const param_len = 0x1;
- int const test_link_rate_addr = 0x219;
- int const test_lane_count_addr = 0x220;
/* Read the requested link rate (Byte 0x219). */
- rlen = link->aux->read(link->aux, test_link_rate_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LINK_RATE,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link rate\n");
ret = -EINVAL;
@@ -837,8 +822,8 @@
pr_debug("link rate = 0x%x\n", link->request.test_link_rate);
/* Read the requested lane count (Byte 0x220). */
- rlen = link->aux->read(link->aux, test_lane_count_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LANE_COUNT,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read lane count\n");
ret = -EINVAL;
@@ -890,8 +875,8 @@
int const phy_test_pattern_addr = 0x248;
int ret = 0;
- rlen = link->aux->read(link->aux, phy_test_pattern_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, phy_test_pattern_addr,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read phy link pattern\n");
ret = -EINVAL;
@@ -965,16 +950,14 @@
u8 data;
int rlen;
u32 const param_len = 0x1;
- u32 const device_service_irq_addr = 0x201;
- u32 const test_request_addr = 0x218;
u8 buf[4];
/**
* Read the device service IRQ vector (Byte 0x201) to determine
* whether an automated link has been requested by the sink.
*/
- rlen = link->aux->read(link->aux, device_service_irq_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux,
+ DP_DEVICE_SERVICE_IRQ_VECTOR, &bp, param_len);
if (rlen < param_len) {
pr_err("aux read failed\n");
ret = -EINVAL;
@@ -994,8 +977,8 @@
* Read the link request byte (Byte 0x218) to determine what type
* of automated link has been requested by the sink.
*/
- rlen = link->aux->read(link->aux, test_request_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_REQUEST,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("aux read failed\n");
ret = -EINVAL;
@@ -1033,7 +1016,7 @@
end:
/* clear the link request IRQ */
buf[0] = 1;
- link->aux->write(link->aux, test_request_addr, 1, AUX_NATIVE, buf);
+ drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_REQUEST, buf, 1);
/**
* Send a TEST_ACK if all link parameters are valid, otherwise send
@@ -1060,10 +1043,9 @@
u8 data;
int rlen;
int const param_len = 0x1;
- int const sink_count_addr = 0x200;
- rlen = link->aux->read(link->aux, sink_count_addr,
- param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_SINK_COUNT,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read sink count\n");
return;
@@ -1080,67 +1062,16 @@
link->sink_count.count, link->sink_count.cp_ready);
}
-static int dp_link_link_status_read(struct dp_link_private *link)
-{
- u8 *bp;
- u8 data;
- int rlen, ret = 0;
- int const addr = 0x202;
- int const len = 6;
- struct dp_link_status *sp;
-
- rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
- if (rlen < len) {
- pr_err("edp aux read failed\n");
- ret = -EINVAL;
- goto error;
- }
-
- sp = &link->link_status;
-
- data = *bp++; /* byte 0x202 */
- sp->lane_01_status = data; /* lane 0, 1 */
-
- data = *bp++; /* byte 0x203 */
- sp->lane_23_status = data; /* lane 2, 3 */
-
- data = *bp++; /* byte 0x204 */
- sp->interlane_align_done = (data & BIT(0));
- sp->downstream_port_status_changed = (data & BIT(6));
- sp->link_status_updated = (data & BIT(7));
-
- data = *bp++; /* byte 0x205 */
- sp->port_0_in_sync = (data & BIT(0));
- sp->port_1_in_sync = (data & BIT(1));
-
- data = *bp++; /* byte 0x206 */
- sp->req_voltage_swing[0] = data & 0x03;
- data >>= 2;
- sp->req_pre_emphasis[0] = data & 0x03;
- data >>= 2;
- sp->req_voltage_swing[1] = data & 0x03;
- data >>= 2;
- sp->req_pre_emphasis[1] = data & 0x03;
-
- data = *bp++; /* byte 0x207 */
- sp->req_voltage_swing[2] = data & 0x03;
- data >>= 2;
- sp->req_pre_emphasis[2] = data & 0x03;
- data >>= 2;
- sp->req_voltage_swing[3] = data & 0x03;
- data >>= 2;
- sp->req_pre_emphasis[3] = data & 0x03;
-
- return 0;
-error:
- return ret;
-}
-
static void dp_link_parse_sink_status_field(struct dp_link_private *link)
{
+ int len = 0;
+
dp_link_parse_sink_count(link);
dp_link_parse_request(link);
- dp_link_link_status_read(link);
+ len = drm_dp_dpcd_read_link_status(link->aux->drm_aux,
+ link->link_status);
+ if (len < DP_LINK_STATUS_SIZE)
+ pr_err("DP link status read failed\n");
}
static bool dp_link_is_link_training_requested(struct dp_link_private *link)
@@ -1196,7 +1127,7 @@
pr_debug("\n");
- rlen = link->aux->read(link->aux, addr1, param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr1, &bp, param_len);
if (rlen < param_len) {
pr_err("failed reading lanes 0/1\n");
ret = -EINVAL;
@@ -1217,7 +1148,7 @@
p1 = data & 0x3;
data = data >> 2;
- rlen = link->aux->read(link->aux, addr2, param_len, AUX_NATIVE, &bp);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr2, &bp, param_len);
if (rlen < param_len) {
pr_err("failed reading lanes 2/3\n");
ret = -EINVAL;
@@ -1294,76 +1225,6 @@
return 0;
}
-static bool dp_link_is_link_status_updated(struct dp_link_private *link)
-{
- return link->link_status.link_status_updated;
-}
-
-static bool dp_link_channel_eq_done(struct dp_link_private *link)
-{
- u32 mask, data;
- struct dp_link *dp_link = &link->dp_link;
-
- pr_debug("\n");
-
- dp_link_link_status_read(link);
-
- if (!link->link_status.interlane_align_done) { /* not align */
- pr_err("interlane align failed\n");
- return 0;
- }
-
- if (dp_link->lane_count == 1) {
- mask = 0x7;
- data = link->link_status.lane_01_status;
- } else if (dp_link->lane_count == 2) {
- mask = 0x77;
- data = link->link_status.lane_01_status;
- } else {
- mask = 0x7777;
- data = link->link_status.lane_23_status;
- data <<= 8;
- data |= link->link_status.lane_01_status;
- }
-
- data &= mask;
- pr_debug("data=%x mask=%x\n", data, mask);
-
- if (data == mask)/* all done */
- return true;
-
- return false;
-}
-
-static bool dp_link_clock_recovery_done(struct dp_link_private *link)
-{
- u32 mask, data;
- struct dp_link *dp_link = &link->dp_link;
-
- dp_link_link_status_read(link);
-
- if (dp_link->lane_count == 1) {
- mask = 0x01; /* lane 0 */
- data = link->link_status.lane_01_status;
- } else if (dp_link->lane_count == 2) {
- mask = 0x011; /*B lane 0, 1 */
- data = link->link_status.lane_01_status;
- } else {
- mask = 0x01111; /*B lane 0, 1 */
- data = link->link_status.lane_23_status;
- data <<= 8;
- data |= link->link_status.lane_01_status;
- }
-
- data &= mask;
- pr_debug("data=%x mask=%x\n", data, mask);
-
- if (data == mask) /* all done */
- return true;
-
- return false;
-}
-
/**
* dp_link_process_link_status_update() - processes link status updates
* @link: Display Port link module data
@@ -1377,21 +1238,25 @@
*/
static int dp_link_process_link_status_update(struct dp_link_private *link)
{
- if (!dp_link_is_link_status_updated(link) ||
- (dp_link_channel_eq_done(link) &&
- dp_link_clock_recovery_done(link)))
+ if (!(link->link_status[2] & BIT(7)) || /* link status updated */
+ (drm_dp_clock_recovery_ok(link->link_status,
+ link->dp_link.lane_count) &&
+ drm_dp_channel_eq_ok(link->link_status,
+ link->dp_link.lane_count)))
return -EINVAL;
pr_debug("channel_eq_done = %d, clock_recovery_done = %d\n",
- dp_link_channel_eq_done(link),
- dp_link_clock_recovery_done(link));
+ drm_dp_clock_recovery_ok(link->link_status,
+ link->dp_link.lane_count),
+ drm_dp_clock_recovery_ok(link->link_status,
+ link->dp_link.lane_count));
return 0;
}
static bool dp_link_is_ds_port_status_changed(struct dp_link_private *link)
{
- return link->link_status.downstream_port_status_changed;
+ return (link->link_status[2] & BIT(6)); /* port status changed */
}
/**
@@ -1562,37 +1427,6 @@
return ret;
}
-static u8 *dp_link_get_voltage_swing(struct dp_link *dp_link)
-
-{
- struct dp_link_private *link;
-
- if (!dp_link) {
- pr_err("invalid input\n");
- return ERR_PTR(-EINVAL);
- }
-
- link = container_of(dp_link, struct dp_link_private, dp_link);
-
- return link->link_status.req_voltage_swing;
-}
-
-static u8 *dp_link_get_pre_emphasis(struct dp_link *dp_link)
-
-{
- struct dp_link_private *link;
-
-
- if (!dp_link) {
- pr_err("invalid input\n");
- return ERR_PTR(-EINVAL);
- }
-
- link = container_of(dp_link, struct dp_link_private, dp_link);
-
- return link->link_status.req_pre_emphasis;
-}
-
static int dp_link_get_colorimetry_config(struct dp_link *dp_link)
{
u32 cc;
@@ -1625,38 +1459,11 @@
return cc;
}
-static bool dp_link_clock_recovery(struct dp_link *dp_link)
-{
- struct dp_link_private *link;
-
- if (!dp_link) {
- pr_err("invalid input\n");
- return -EINVAL;
- }
-
- link = container_of(dp_link, struct dp_link_private, dp_link);
-
- return dp_link_clock_recovery_done(link);
-}
-
-static bool dp_link_channel_equalization(struct dp_link *dp_link)
-{
- struct dp_link_private *link;
-
- if (!dp_link) {
- pr_err("invalid input\n");
- return -EINVAL;
- }
-
- link = container_of(dp_link, struct dp_link_private, dp_link);
-
- return dp_link_channel_eq_done(link);
-}
-
-static int dp_link_adjust_levels(struct dp_link *dp_link)
+static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
{
int i;
int max = 0;
+ u8 data;
struct dp_link_private *link;
if (!dp_link) {
@@ -1668,24 +1475,24 @@
/* use the max level across lanes */
for (i = 0; i < dp_link->lane_count; i++) {
- pr_debug("lane=%d req_voltage_swing=%d\n",
- i, link->link_status.req_voltage_swing[i]);
- if (max < link->link_status.req_voltage_swing[i])
- max = link->link_status.req_voltage_swing[i];
+ data = drm_dp_get_adjust_request_voltage(link_status, i);
+ pr_debug("lane=%d req_voltage_swing=%d\n", i, data);
+ if (max < data)
+ max = data;
}
- dp_link->v_level = max;
+ dp_link->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
/* use the max level across lanes */
max = 0;
for (i = 0; i < dp_link->lane_count; i++) {
- pr_debug("lane=%d req_pre_emphasis=%d\n",
- i, link->link_status.req_pre_emphasis[i]);
- if (max < link->link_status.req_pre_emphasis[i])
- max = link->link_status.req_pre_emphasis[i];
+ data = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
+ pr_debug("lane=%d req_pre_emphasis=%d\n", i, data);
+ if (max < data)
+ max = data;
}
- dp_link->p_level = max;
+ dp_link->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
/**
* Adjust the voltage swing and pre-emphasis level combination to within
@@ -1781,12 +1588,8 @@
dp_link = &link->dp_link;
dp_link->process_request = dp_link_process_request;
- dp_link->get_voltage_swing = dp_link_get_voltage_swing;
dp_link->get_test_bits_depth = dp_link_get_test_bits_depth;
- dp_link->get_pre_emphasis = dp_link_get_pre_emphasis;
dp_link->get_colorimetry_config = dp_link_get_colorimetry_config;
- dp_link->clock_recovery = dp_link_clock_recovery;
- dp_link->channel_equalization = dp_link_channel_equalization;
dp_link->adjust_levels = dp_link_adjust_levels;
dp_link->send_psm_request = dp_link_send_psm_request;
dp_link->phy_pattern_requested = dp_link_phy_pattern_requested;
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index de10e9a..26249d6 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -54,15 +54,11 @@
u32 v_level;
u32 p_level;
- u8 *(*get_voltage_swing)(struct dp_link *dp_link);
- u8 *(*get_pre_emphasis)(struct dp_link *dp_link);
u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp);
int (*process_request)(struct dp_link *dp_link);
int (*get_colorimetry_config)(struct dp_link *dp_link);
- int (*adjust_levels)(struct dp_link *dp_link);
+ int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status);
int (*send_psm_request)(struct dp_link *dp_link, bool req);
- bool (*clock_recovery)(struct dp_link *dp_link);
- bool (*channel_equalization)(struct dp_link *dp_link);
bool (*phy_pattern_requested)(struct dp_link *dp_link);
};
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index f9616c4..fed1dbb 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -16,7 +16,9 @@
#include "dp_panel.h"
-#define DP_LINK_RATE_MULTIPLIER 27000000
+enum {
+ DP_LINK_RATE_MULTIPLIER = 27000000,
+};
struct dp_panel_private {
struct device *dev;
@@ -27,13 +29,10 @@
static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
{
- u8 *bp;
- u8 data;
- u32 const addr = 0x0;
- u32 const len = 16;
int rlen, rc = 0;
struct dp_panel_private *panel;
- struct dp_panel_dpcd *cap;
+ struct drm_dp_link *dp_link;
+ u8 major = 0, minor = 0;
if (!dp_panel) {
pr_err("invalid input\n");
@@ -41,236 +40,38 @@
goto end;
}
- cap = &dp_panel->dpcd;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+ dp_link = &dp_panel->dp_link;
- rlen = panel->aux->read(panel->aux, addr, len, AUX_NATIVE, &bp);
- if (rlen != len) {
+ rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV,
+ dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
+ if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
pr_err("dpcd read failed, rlen=%d\n", rlen);
rc = -EINVAL;
goto end;
}
- memset(cap, 0, sizeof(*cap));
+ dp_link->revision = dp_panel->dpcd[DP_DPCD_REV];
- data = *bp++; /* byte 0 */
- cap->major = (data >> 4) & 0x0f;
- cap->minor = data & 0x0f;
- pr_debug("version: %d.%d\n", cap->major, cap->minor);
+ major = (dp_link->revision >> 4) & 0x0f;
+ minor = dp_link->revision & 0x0f;
+ pr_debug("version: %d.%d\n", major, minor);
- data = *bp++; /* byte 1 */
- /* 162, 270, 540, 810 MB, symbol rate, NOT bit rate */
- cap->max_link_rate = data;
- pr_debug("link_rate=%d\n", cap->max_link_rate);
+ dp_link->rate =
+ drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]);
+ pr_debug("link_rate=%d\n", dp_link->rate);
- data = *bp++; /* byte 2 */
- if (data & BIT(7))
- cap->enhanced_frame++;
+ dp_link->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
+ DP_MAX_LANE_COUNT_MASK;
+ pr_debug("lane_count=%d\n", dp_link->num_lanes);
- if (data & 0x40) {
- cap->flags |= DPCD_TPS3;
- pr_debug("pattern 3 supported\n");
- } else {
- pr_debug("pattern 3 not supported\n");
- }
+ if (dp_panel->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)
+ dp_link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
- data &= 0x0f;
- cap->max_lane_count = data;
- pr_debug("lane_count=%d\n", cap->max_lane_count);
-
- data = *bp++; /* byte 3 */
- if (data & BIT(0)) {
- cap->flags |= DPCD_MAX_DOWNSPREAD_0_5;
- pr_debug("max_downspread\n");
- }
-
- if (data & BIT(6)) {
- cap->flags |= DPCD_NO_AUX_HANDSHAKE;
- pr_debug("NO Link Training\n");
- }
-
- data = *bp++; /* byte 4 */
- cap->num_rx_port = (data & BIT(0)) + 1;
- pr_debug("rx_ports=%d", cap->num_rx_port);
-
- data = *bp++; /* Byte 5: DOWN_STREAM_PORT_PRESENT */
- cap->downstream_port.dfp_present = data & BIT(0);
- cap->downstream_port.dfp_type = data & 0x6;
- cap->downstream_port.format_conversion = data & BIT(3);
- cap->downstream_port.detailed_cap_info_available = data & BIT(4);
- pr_debug("dfp_present = %d, dfp_type = %d\n",
- cap->downstream_port.dfp_present,
- cap->downstream_port.dfp_type);
- pr_debug("format_conversion = %d, detailed_cap_info_available = %d\n",
- cap->downstream_port.format_conversion,
- cap->downstream_port.detailed_cap_info_available);
-
- bp += 1; /* Skip Byte 6 */
- rlen -= 1;
-
- data = *bp++; /* Byte 7: DOWN_STREAM_PORT_COUNT */
- cap->downstream_port.dfp_count = data & 0x7;
- cap->downstream_port.msa_timing_par_ignored = data & BIT(6);
- cap->downstream_port.oui_support = data & BIT(7);
- pr_debug("dfp_count = %d, msa_timing_par_ignored = %d\n",
- cap->downstream_port.dfp_count,
- cap->downstream_port.msa_timing_par_ignored);
- pr_debug("oui_support = %d\n", cap->downstream_port.oui_support);
-
- data = *bp++; /* byte 8 */
- if (data & BIT(1)) {
- cap->flags |= DPCD_PORT_0_EDID_PRESENTED;
- pr_debug("edid presented\n");
- }
-
- data = *bp++; /* byte 9 */
- cap->rx_port0_buf_size = (data + 1) * 32;
- pr_debug("lane_buf_size=%d\n", cap->rx_port0_buf_size);
-
- bp += 2; /* skip 10, 11 port1 capability */
- rlen -= 2;
-
- data = *bp++; /* byte 12 */
- cap->i2c_speed_ctrl = data;
- if (cap->i2c_speed_ctrl > 0)
- pr_debug("i2c_rate=%d", cap->i2c_speed_ctrl);
-
- data = *bp++; /* byte 13 */
- cap->scrambler_reset = data & BIT(0);
- pr_debug("scrambler_reset=%d\n", cap->scrambler_reset);
-
- if (data & BIT(1))
- cap->enhanced_frame++;
-
- pr_debug("enhanced_framing=%d\n", cap->enhanced_frame);
-
- data = *bp++; /* byte 14 */
- if (data == 0)
- cap->training_read_interval = 4000; /* us */
- else
- cap->training_read_interval = 4000 * data; /* us */
- pr_debug("training_interval=%d\n", cap->training_read_interval);
end:
return rc;
}
-/*
- * edid standard header bytes
- */
-static u8 edid_hdr[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
-
-static bool dp_panel_is_edid_header_valid(u8 *buf)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(edid_hdr); i++) {
- if (buf[i] != edid_hdr[i])
- return false;
- }
-
- return true;
-}
-
-static int dp_panel_validate_edid(u8 *bp, int len)
-{
- int i;
- u8 csum = 0;
- u32 const size = 128;
-
- if (len < size) {
- pr_err("Error: len=%x\n", len);
- return -EINVAL;
- }
-
- for (i = 0; i < size; i++)
- csum += *bp++;
-
- if (csum != 0) {
- pr_err("error: csum=0x%x\n", csum);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int dp_panel_read_edid(struct dp_panel *dp_panel)
-{
- u8 *edid_buf;
- u32 checksum = 0;
- int rlen, ret = 0;
- int edid_blk = 0, blk_num = 0, retries = 10;
- u32 const segment_addr = 0x30;
- bool edid_parsing_done = false;
- struct dp_panel_private *panel;
-
- panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
-
- ret = panel->aux->ready(panel->aux);
- if (!ret) {
- pr_err("aux chan NOT ready\n");
- goto end;
- }
-
- do {
- u8 segment;
-
-
- /*
- * Write the segment first.
- * Segment = 0, for blocks 0 and 1
- * Segment = 1, for blocks 2 and 3
- * Segment = 2, for blocks 3 and 4
- * and so on ...
- */
- segment = blk_num >> 1;
-
- panel->aux->write(panel->aux, segment_addr, 1, AUX_I2C,
- &segment);
-
- rlen = panel->aux->read(panel->aux, EDID_START_ADDRESS +
- (blk_num * EDID_BLOCK_SIZE),
- EDID_BLOCK_SIZE, AUX_I2C, &edid_buf);
- if (rlen != EDID_BLOCK_SIZE) {
- pr_err("invalid edid len: %d\n", rlen);
- continue;
- }
-
- pr_debug("=== EDID data ===\n");
- print_hex_dump(KERN_DEBUG, "EDID: ", DUMP_PREFIX_NONE, 16, 1,
- edid_buf, EDID_BLOCK_SIZE, false);
-
- pr_debug("blk_num=%d, rlen=%d\n", blk_num, rlen);
-
- if (dp_panel_is_edid_header_valid(edid_buf)) {
- ret = dp_panel_validate_edid(edid_buf, rlen);
- if (ret) {
- pr_err("corrupt edid block detected\n");
- goto end;
- }
-
- if (edid_parsing_done) {
- blk_num++;
- continue;
- }
-
- dp_panel->edid.ext_block_cnt = edid_buf[0x7E];
- edid_parsing_done = true;
- checksum = edid_buf[rlen - 1];
- } else {
- edid_blk++;
- blk_num++;
- }
-
- memcpy(dp_panel->edid.buf + (edid_blk * EDID_BLOCK_SIZE),
- edid_buf, EDID_BLOCK_SIZE);
-
- if (edid_blk == dp_panel->edid.ext_block_cnt)
- goto end;
- } while (retries--);
-end:
- return ret;
-}
-
static int dp_panel_timing_cfg(struct dp_panel *dp_panel)
{
int rc = 0;
@@ -334,6 +135,36 @@
return rc;
}
+static int dp_panel_edid_register(struct dp_panel *dp_panel)
+{
+ int rc = 0;
+
+ if (!dp_panel) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ dp_panel->edid_ctrl = sde_edid_init();
+ if (!dp_panel->edid_ctrl) {
+ pr_err("sde edid init for DP failed\n");
+ rc = -ENOMEM;
+ goto end;
+ }
+end:
+ return rc;
+}
+
+static void dp_panel_edid_deregister(struct dp_panel *dp_panel)
+{
+ if (!dp_panel) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ sde_edid_deinit((void **)&dp_panel->edid_ctrl);
+}
+
static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
{
int rc = 0;
@@ -350,12 +181,12 @@
return rc;
}
-static u8 dp_panel_get_link_rate(struct dp_panel *dp_panel)
+static u32 dp_panel_get_link_rate(struct dp_panel *dp_panel)
{
const u32 encoding_factx10 = 8;
const u32 ln_to_link_ratio = 10;
u32 min_link_rate, reminder = 0;
- u8 calc_link_rate = 0, lane_cnt;
+ u32 calc_link_rate = 0, lane_cnt, max_rate = 0;
struct dp_panel_private *panel;
struct dp_panel_info *pinfo;
@@ -366,11 +197,10 @@
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
- lane_cnt = dp_panel->dpcd.max_lane_count;
+ lane_cnt = dp_panel->dp_link.num_lanes;
+ max_rate = drm_dp_link_rate_to_bw_code(dp_panel->dp_link.rate);
pinfo = &dp_panel->pinfo;
- pinfo->bpp = 24;
-
/*
* The max pixel clock supported is 675Mhz. The
* current calculations below will make sure
@@ -393,12 +223,12 @@
min_link_rate += 1;
pr_debug("min_link_rate = %d\n", min_link_rate);
- if (min_link_rate <= DP_LINK_RATE_162)
- calc_link_rate = DP_LINK_RATE_162;
- else if (min_link_rate <= DP_LINK_RATE_270)
- calc_link_rate = DP_LINK_RATE_270;
- else if (min_link_rate <= DP_LINK_RATE_540)
- calc_link_rate = DP_LINK_RATE_540;
+ if (min_link_rate <= DP_LINK_BW_1_62)
+ calc_link_rate = DP_LINK_BW_1_62;
+ else if (min_link_rate <= DP_LINK_BW_2_7)
+ calc_link_rate = DP_LINK_BW_2_7;
+ else if (min_link_rate <= DP_LINK_BW_5_4)
+ calc_link_rate = DP_LINK_BW_5_4;
else if (min_link_rate <= DP_LINK_RATE_810)
calc_link_rate = DP_LINK_RATE_810;
else {
@@ -407,8 +237,8 @@
calc_link_rate = DP_LINK_RATE_810;
}
- if (calc_link_rate > dp_panel->dpcd.max_link_rate)
- calc_link_rate = dp_panel->dpcd.max_link_rate;
+ if (calc_link_rate > max_rate)
+ calc_link_rate = max_rate;
pr_debug("calc_link_rate = 0x%x\n", calc_link_rate);
end:
@@ -440,12 +270,10 @@
dp_panel = &panel->dp_panel;
- dp_panel->edid.buf = devm_kzalloc(dev,
- sizeof(EDID_BLOCK_SIZE) * 4, GFP_KERNEL);
-
+ dp_panel->sde_edid_register = dp_panel_edid_register;
+ dp_panel->sde_edid_deregister = dp_panel_edid_deregister;
dp_panel->init_info = dp_panel_init_panel_info;
dp_panel->timing_cfg = dp_panel_timing_cfg;
- dp_panel->read_edid = dp_panel_read_edid;
dp_panel->read_dpcd = dp_panel_read_dpcd;
dp_panel->get_link_rate = dp_panel_get_link_rate;
@@ -463,6 +291,5 @@
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
- devm_kfree(panel->dev, dp_panel->edid.buf);
devm_kfree(panel->dev, panel);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 5c145eb..5852c70 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -16,66 +16,9 @@
#define _DP_PANEL_H_
#include "dp_aux.h"
+#include "sde_edid_parser.h"
-#define DPCD_ENHANCED_FRAME BIT(0)
-#define DPCD_TPS3 BIT(1)
-#define DPCD_MAX_DOWNSPREAD_0_5 BIT(2)
-#define DPCD_NO_AUX_HANDSHAKE BIT(3)
-#define DPCD_PORT_0_EDID_PRESENTED BIT(4)
-
-#define EDID_START_ADDRESS 0x50
-#define EDID_BLOCK_SIZE 0x80
-
-
-#define DP_LINK_RATE_162 6 /* 1.62G = 270M * 6 */
-#define DP_LINK_RATE_270 10 /* 2.70G = 270M * 10 */
-#define DP_LINK_RATE_540 20 /* 5.40G = 270M * 20 */
#define DP_LINK_RATE_810 30 /* 8.10G = 270M * 30 */
-#define DP_LINK_RATE_MAX DP_LINK_RATE_810
-
-struct downstream_port_config {
- /* Byte 02205h */
- bool dfp_present;
- u32 dfp_type;
- bool format_conversion;
- bool detailed_cap_info_available;
- /* Byte 02207h */
- u32 dfp_count;
- bool msa_timing_par_ignored;
- bool oui_support;
-};
-
-struct dp_panel_dpcd {
- u8 major;
- u8 minor;
- u8 max_lane_count;
- u8 num_rx_port;
- u8 i2c_speed_ctrl;
- u8 scrambler_reset;
- u8 enhanced_frame;
- u32 max_link_rate; /* 162, 270 and 540 Mb, divided by 10 */
- u32 flags;
- u32 rx_port0_buf_size;
- u32 training_read_interval;/* us */
- struct downstream_port_config downstream_port;
-};
-
-struct dp_panel_edid {
- u8 *buf;
- u8 id_name[4];
- u8 id_product;
- u8 version;
- u8 revision;
- u8 video_intf; /* dp == 0x5 */
- u8 color_depth; /* 6, 8, 10, 12 and 14 bits */
- u8 color_format; /* RGB 4:4:4, YCrCb 4:4:4, Ycrcb 4:2:2 */
- u8 dpm; /* display power management */
- u8 sync_digital; /* 1 = digital */
- u8 sync_separate; /* 1 = separate */
- u8 vsync_pol; /* 0 = negative, 1 = positive */
- u8 hsync_pol; /* 0 = negative, 1 = positive */
- u8 ext_block_cnt;
-};
struct dp_panel_info {
u32 h_active;
@@ -95,17 +38,21 @@
};
struct dp_panel {
- struct dp_panel_dpcd dpcd;
- struct dp_panel_edid edid;
+ /* dpcd raw data */
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+ struct drm_dp_link dp_link;
+
+ struct sde_edid_ctrl *edid_ctrl;
struct dp_panel_info pinfo;
u32 vic;
+ int (*sde_edid_register)(struct dp_panel *dp_panel);
+ void (*sde_edid_deregister)(struct dp_panel *dp_panel);
int (*init_info)(struct dp_panel *dp_panel);
int (*timing_cfg)(struct dp_panel *dp_panel);
- int (*read_edid)(struct dp_panel *dp_panel);
int (*read_dpcd)(struct dp_panel *dp_panel);
- u8 (*get_link_rate)(struct dp_panel *dp_panel);
+ u32 (*get_link_rate)(struct dp_panel *dp_panel);
};
struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index cf0cc56..23f23b0 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -1112,12 +1112,11 @@
struct sde_hw_stage_cfg *stage_cfg;
struct sde_rect plane_crtc_roi;
- u32 flush_mask = 0;
+ u32 flush_mask, flush_sbuf, flush_tmp;
uint32_t lm_idx = LEFT_MIXER, stage_idx;
bool bg_alpha_enable[CRTC_DUAL_MIXERS] = {false};
int zpos_cnt[CRTC_DUAL_MIXERS][SDE_STAGE_MAX + 1] = { {0} };
int i;
- bool sbuf_mode = false;
u32 prefill = 0;
if (!sde_crtc || !mixer) {
@@ -1129,6 +1128,10 @@
lm = mixer->hw_lm;
stage_cfg = &sde_crtc->stage_cfg;
cstate = to_sde_crtc_state(crtc->state);
+ flush_sbuf = 0x0;
+
+ cstate->sbuf_cfg.rot_op_mode = SDE_CTL_ROT_OP_MODE_OFFLINE;
+ cstate->sbuf_prefill_line = 0;
drm_atomic_crtc_for_each_plane(plane, crtc) {
state = plane->state;
@@ -1144,10 +1147,16 @@
fb = state->fb;
if (sde_plane_is_sbuf_mode(plane, &prefill))
- sbuf_mode = true;
+ cstate->sbuf_cfg.rot_op_mode =
+ SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
+ if (prefill > cstate->sbuf_prefill_line)
+ cstate->sbuf_prefill_line = prefill;
- sde_plane_get_ctl_flush(plane, ctl, &flush_mask);
+ sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_tmp);
+ /* persist rotator flush bit(s) for one more commit */
+ flush_mask |= cstate->sbuf_flush_mask | flush_tmp;
+ flush_sbuf |= flush_tmp;
SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
crtc->base.id,
@@ -1163,7 +1172,8 @@
state->src_x >> 16, state->src_y >> 16,
state->src_w >> 16, state->src_h >> 16,
state->crtc_x, state->crtc_y,
- state->crtc_w, state->crtc_h);
+ state->crtc_w, state->crtc_h,
+ cstate->sbuf_cfg.rot_op_mode);
for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
struct sde_rect intersect;
@@ -1208,6 +1218,8 @@
}
}
+ cstate->sbuf_flush_mask = flush_sbuf;
+
if (lm && lm->ops.setup_dim_layer) {
cstate = to_sde_crtc_state(crtc->state);
for (i = 0; i < cstate->num_dim_layers; i++)
@@ -1215,20 +1227,8 @@
mixer, &cstate->dim_layer[i]);
}
- if (ctl->ops.setup_sbuf_cfg) {
- cstate = to_sde_crtc_state(crtc->state);
- if (!sbuf_mode) {
- cstate->sbuf_cfg.rot_op_mode =
- SDE_CTL_ROT_OP_MODE_OFFLINE;
- cstate->sbuf_prefill_line = 0;
- } else {
- cstate->sbuf_cfg.rot_op_mode =
- SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
- cstate->sbuf_prefill_line = prefill;
- }
-
+ if (ctl->ops.setup_sbuf_cfg)
ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
- }
_sde_crtc_program_lm_output_roi(crtc);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 4b3c814..2cf30a9 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -272,6 +272,7 @@
* @new_perf: new performance state
* @sbuf_cfg: stream buffer configuration
* @sbuf_prefill_line: number of line for inline rotator prefetch
+ * @sbuf_flush_mask: flush mask for inline rotator
*/
struct sde_crtc_state {
struct drm_crtc_state base;
@@ -298,7 +299,8 @@
struct sde_core_perf_params cur_perf;
struct sde_core_perf_params new_perf;
struct sde_ctl_sbuf_cfg sbuf_cfg;
- u64 sbuf_prefill_line;
+ u32 sbuf_prefill_line;
+ u32 sbuf_flush_mask;
struct sde_crtc_respool rp;
};
@@ -433,10 +435,14 @@
*/
static inline u32 sde_crtc_get_inline_prefill(struct drm_crtc *crtc)
{
+ struct sde_crtc_state *cstate;
+
if (!crtc || !crtc->state)
return 0;
- return to_sde_crtc_state(crtc->state)->sbuf_prefill_line;
+ cstate = to_sde_crtc_state(crtc->state);
+ return cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE ?
+ cstate->sbuf_prefill_line : 0;
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 5cb84b4..488f5c0 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -222,7 +222,7 @@
* @rot_fetch_lines: number of line to prefill, or 0 to disable
*/
static void programmable_rot_fetch_config(struct sde_encoder_phys *phys_enc,
- u64 rot_fetch_lines)
+ u32 rot_fetch_lines)
{
struct sde_encoder_phys_vid *vid_enc =
to_sde_encoder_phys_vid(phys_enc);
@@ -232,9 +232,12 @@
u32 horiz_total = 0;
u32 vert_total = 0;
u32 rot_fetch_start_vsync_counter = 0;
+ u32 flush_mask = 0;
unsigned long lock_flags;
- if (!phys_enc || !vid_enc->hw_intf ||
+ if (!phys_enc || !vid_enc->hw_intf || !phys_enc->hw_ctl ||
+ !phys_enc->hw_ctl->ops.get_bitmask_intf ||
+ !phys_enc->hw_ctl->ops.update_pending_flush ||
!vid_enc->hw_intf->ops.setup_rot_start)
return;
@@ -253,9 +256,14 @@
}
SDE_DEBUG_VIDENC(vid_enc,
- "rot_fetch_lines %llu rot_fetch_start_vsync_counter %u\n",
+ "rot_fetch_lines %u rot_fetch_start_vsync_counter %u\n",
rot_fetch_lines, rot_fetch_start_vsync_counter);
+ phys_enc->hw_ctl->ops.get_bitmask_intf(
+ phys_enc->hw_ctl, &flush_mask, vid_enc->hw_intf->idx);
+ phys_enc->hw_ctl->ops.update_pending_flush(
+ phys_enc->hw_ctl, flush_mask);
+
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
vid_enc->hw_intf->ops.setup_rot_start(vid_enc->hw_intf, &f);
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 8941a54..d63fec1 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1368,33 +1368,31 @@
static u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
{
struct drm_plane_state *state;
- struct drm_crtc_state *cstate;
struct sde_plane_state *pstate;
struct sde_plane_rot_state *rstate;
struct sde_kms *sde_kms;
u32 blocksize = 128;
u32 prefill_line = 0;
- if (!plane || !plane->state || !plane->state->fb ||
- !plane->state->crtc || !plane->state->crtc->state) {
+ if (!plane || !plane->state || !plane->state->fb) {
SDE_ERROR("invalid parameters\n");
return 0;
}
sde_kms = _sde_plane_get_kms(plane);
state = plane->state;
- cstate = state->crtc->state;
pstate = to_sde_plane_state(state);
rstate = &pstate->rot;
- if (!rstate->rot_hw || !rstate->rot_hw->caps || !rstate->out_src_h ||
- !sde_kms || !sde_kms->catalog) {
- SDE_ERROR("invalid parameters\n");
+ if (!sde_kms || !sde_kms->catalog) {
+ SDE_ERROR("invalid kms\n");
return 0;
}
- sde_format_get_block_size(rstate->out_fb_format, &blocksize,
- &blocksize);
+ if (rstate->out_fb_format)
+ sde_format_get_block_size(rstate->out_fb_format,
+ &blocksize, &blocksize);
+
prefill_line = blocksize + sde_kms->catalog->sbuf_headroom;
SDE_DEBUG("plane%d prefill:%u\n", plane->base.id, prefill_line);
@@ -1416,7 +1414,7 @@
struct sde_plane_rot_state *rstate = pstate ? &pstate->rot : NULL;
bool sbuf_mode = rstate ? rstate->out_sbuf : false;
- if (prefill && sbuf_mode)
+ if (prefill)
*prefill = sde_plane_rot_calc_prefill(plane);
return sbuf_mode;
@@ -2447,16 +2445,16 @@
* sde_plane_get_ctl_flush - get control flush for the given plane
* @plane: Pointer to drm plane structure
* @ctl: Pointer to hardware control driver
- * @flush: Pointer to flush control word
+ * @flush_sspp: Pointer to sspp flush control word
+ * @flush_rot: Pointer to rotator flush control word
*/
void sde_plane_get_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl,
- u32 *flush)
+ u32 *flush_sspp, u32 *flush_rot)
{
struct sde_plane_state *pstate;
struct sde_plane_rot_state *rstate;
- u32 bitmask;
- if (!plane || !flush) {
+ if (!plane || !flush_sspp) {
SDE_ERROR("invalid parameters\n");
return;
}
@@ -2464,13 +2462,15 @@
pstate = to_sde_plane_state(plane->state);
rstate = &pstate->rot;
- bitmask = ctl->ops.get_bitmask_sspp(ctl, sde_plane_pipe(plane));
+ *flush_sspp = ctl->ops.get_bitmask_sspp(ctl, sde_plane_pipe(plane));
+ if (!flush_rot)
+ return;
+
+ *flush_rot = 0x0;
if (sde_plane_is_sbuf_mode(plane, NULL) && rstate->rot_hw &&
ctl->ops.get_bitmask_rot)
- ctl->ops.get_bitmask_rot(ctl, &bitmask, rstate->rot_hw->idx);
-
- *flush = bitmask;
+ ctl->ops.get_bitmask_rot(ctl, flush_rot, rstate->rot_hw->idx);
}
static int sde_plane_prepare_fb(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 92c077e..f83a891 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -172,10 +172,11 @@
* sde_plane_get_ctl_flush - get control flush mask
* @plane: Pointer to DRM plane object
* @ctl: Pointer to control hardware
- * @flush: Pointer to updated flush mask
+ * @flush_sspp: Pointer to sspp flush control word
+ * @flush_rot: Pointer to rotator flush control word
*/
void sde_plane_get_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl,
- u32 *flush);
+ u32 *flush_sspp, u32 *flush_rot);
/**
* sde_plane_is_sbuf_mode - return status of stream buffer mode
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 6c7f6c4..d2cb1e8 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -60,6 +60,7 @@
void *data;
int err = -EBUSY;
+again:
spin_lock_irqsave(&chan->lock, flags);
if (!chan->msg_count || chan->active_req)
@@ -85,6 +86,16 @@
exit:
spin_unlock_irqrestore(&chan->lock, flags);
+ /*
+ * If the controller returns -EAGAIN, then it means, our spinlock
+ * here is preventing the controller from receiving its interrupt,
+ * that would help clear the controller channels that are currently
+ * blocked waiting on the interrupt response.
+ * Unlock and retry again.
+ */
+ if (err == -EAGAIN)
+ goto again;
+
if (!err && (chan->txdone_method & TXDONE_BY_POLL))
/* kick start the timer immediately to avoid delays */
hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0),
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index b328a2a..1f649d6 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -28,7 +28,6 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
-#include <linux/workqueue.h>
#include <asm-generic/io.h>
@@ -95,10 +94,10 @@
struct mbox_chan *chan;
struct tcs_mbox_msg *msg;
u32 m; /* m-th TCS */
- struct tasklet_struct tasklet;
int err;
int idx;
bool in_use;
+ struct list_head list;
};
struct tcs_response_pool {
@@ -122,16 +121,18 @@
/* One per MBOX controller */
struct tcs_drv {
+ struct mbox_controller mbox;
const char *name;
- void *base; /* start address of the RSC's registers */
- void *reg_base; /* start address for DRV specific register */
+ void __iomem *base; /* start address of the RSC's registers */
+ void __iomem *reg_base; /* start address for DRV specific register */
int drv_id;
struct platform_device *pdev;
- struct mbox_controller mbox;
struct tcs_mbox tcs[TCS_TYPE_NR];
int num_assigned;
int num_tcs;
- struct workqueue_struct *wq;
+ struct tasklet_struct tasklet;
+ struct list_head response_pending;
+ spinlock_t drv_lock;
struct tcs_response_pool *resp_pool;
atomic_t tcs_in_use[MAX_POOL_SIZE];
/* Debug info */
@@ -141,8 +142,6 @@
atomic_t tcs_irq_count[MAX_POOL_SIZE];
};
-static void tcs_notify_tx_done(unsigned long data);
-
static int tcs_response_pool_init(struct tcs_drv *drv)
{
struct tcs_response_pool *pool;
@@ -153,11 +152,10 @@
return -ENOMEM;
for (i = 0; i < MAX_POOL_SIZE; i++) {
- tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done,
- (unsigned long) &pool->resp[i]);
pool->resp[i].drv = drv;
pool->resp[i].idx = i;
pool->resp[i].m = TCS_M_INIT;
+ INIT_LIST_HEAD(&pool->resp[i].list);
}
spin_lock_init(&pool->lock);
@@ -188,6 +186,9 @@
}
spin_unlock_irqrestore(&pool->lock, flags);
+ if (pos == MAX_POOL_SIZE)
+ pr_err("response pool is full\n");
+
return resp;
}
@@ -240,11 +241,11 @@
return;
msg = resp->msg;
- pr_info("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
+ pr_debug("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
resp->idx, resp->m, resp->in_use);
- pr_info("Msg: state=%d\n", msg->state);
+ pr_debug("Msg: state=%d\n", msg->state);
for (i = 0; i < msg->num_payload; i++)
- pr_info("addr=0x%x data=0x%x complete=0x%x\n",
+ pr_debug("addr=0x%x data=0x%x complete=0x%x\n",
msg->payload[i].addr,
msg->payload[i].data,
msg->payload[i].complete);
@@ -364,7 +365,15 @@
static inline void send_tcs_response(struct tcs_response *resp)
{
- tasklet_schedule(&resp->tasklet);
+ struct tcs_drv *drv = resp->drv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv->drv_lock, flags);
+ INIT_LIST_HEAD(&resp->list);
+ list_add_tail(&resp->list, &drv->response_pending);
+ spin_unlock_irqrestore(&drv->drv_lock, flags);
+
+ tasklet_schedule(&drv->tasklet);
}
static inline void enable_tcs_irq(struct tcs_drv *drv, int m, bool enable)
@@ -455,12 +464,12 @@
/* Clear the TCS IRQ status */
write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m));
+ /* Notify the client that this request is completed. */
+ atomic_set(&drv->tcs_in_use[m], 0);
+
/* Clean up response object and notify mbox in tasklet */
if (resp)
send_tcs_response(resp);
-
- /* Notify the client that this request is completed. */
- atomic_set(&drv->tcs_in_use[m], 0);
}
return IRQ_HANDLED;
@@ -475,19 +484,38 @@
mbox_chan_txdone(chan, err);
}
-/**
- * tcs_notify_tx_done: TX Done for requests that do not trigger TCS
- */
-static void tcs_notify_tx_done(unsigned long data)
+static void respond_tx_done(struct tcs_response *resp)
{
- struct tcs_response *resp = (struct tcs_response *) data;
struct mbox_chan *chan = resp->chan;
struct tcs_mbox_msg *msg = resp->msg;
int err = resp->err;
int m = resp->m;
- mbox_notify_tx_done(chan, msg, m, err);
free_response(resp);
+ mbox_notify_tx_done(chan, msg, m, err);
+}
+
+/**
+ * tcs_notify_tx_done: TX Done for requests that do not trigger TCS
+ */
+static void tcs_notify_tx_done(unsigned long data)
+{
+ struct tcs_drv *drv = (struct tcs_drv *)data;
+ struct tcs_response *resp;
+ unsigned long flags;
+
+ do {
+ spin_lock_irqsave(&drv->drv_lock, flags);
+ if (list_empty(&drv->response_pending)) {
+ spin_unlock_irqrestore(&drv->drv_lock, flags);
+ break;
+ }
+ resp = list_first_entry(&drv->response_pending,
+ struct tcs_response, list);
+ list_del(&resp->list);
+ spin_unlock_irqrestore(&drv->drv_lock, flags);
+ respond_tx_done(resp);
+ } while (1);
}
static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
@@ -673,8 +701,11 @@
if (IS_ERR(tcs))
return PTR_ERR(tcs);
- if (trigger)
+ if (trigger) {
resp = setup_response(drv, msg, chan, TCS_M_INIT, 0);
+ if (IS_ERR_OR_NULL(resp))
+ return -EBUSY;
+ }
/* Identify the sequential slots that we can write to */
spin_lock_irqsave(&tcs->tcs_lock, flags);
@@ -686,28 +717,21 @@
return slot;
}
- if (trigger) {
- ret = check_for_req_inflight(drv, tcs, msg);
- if (ret) {
- spin_unlock_irqrestore(&tcs->tcs_lock, flags);
- return ret;
- }
- }
-
- /* Mark the slots as in-use, before we unlock */
- if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
- bitmap_set(tcs->slots, slot, msg->num_payload);
-
- /* Copy the addresses of the resources over to the slots */
- for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
- tcs->cmd_addr[slot + i] = msg->payload[i].addr;
-
+ /* Figure out the TCS-m and CMD-n to write to */
offset = slot / tcs->ncpt;
m = offset + tcs->tcs_offset;
n = slot % tcs->ncpt;
- /* Block, if we have an address from the msg in flight */
if (trigger) {
+ /* Block, if we have an address from the msg in flight */
+ ret = check_for_req_inflight(drv, tcs, msg);
+ if (ret) {
+ spin_unlock_irqrestore(&tcs->tcs_lock, flags);
+ if (resp)
+ free_response(resp);
+ return ret;
+ }
+
resp->m = m;
/* Mark the TCS as busy */
atomic_set(&drv->tcs_in_use[m], 1);
@@ -716,6 +740,14 @@
if (tcs->type != ACTIVE_TCS)
enable_tcs_irq(drv, m, true);
drv->tcs_last_sent_ts[m] = arch_counter_get_cntvct();
+ } else {
+ /* Mark the slots as in-use, before we unlock */
+ if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
+ bitmap_set(tcs->slots, slot, msg->num_payload);
+
+ /* Copy the addresses of the resources over to the slots */
+ for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
+ tcs->cmd_addr[slot + i] = msg->payload[i].addr;
}
/* Write to the TCS or AMC */
@@ -758,6 +790,32 @@
return 0;
}
+static void print_tcs_regs(struct tcs_drv *drv, int m)
+{
+ int n;
+ struct tcs_mbox *tcs = get_tcs_from_index(drv, m);
+ void __iomem *base = drv->reg_base;
+ u32 enable, addr, data, msgid;
+
+ if (!tcs || tcs_is_free(drv, m))
+ return;
+
+ enable = read_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0);
+ if (!enable)
+ return;
+
+ pr_debug("TCS-%d contents:\n", m);
+ for (n = 0; n < tcs->ncpt; n++) {
+ if (!(enable & BIT(n)))
+ continue;
+ addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n);
+ data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n);
+ msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n);
+ pr_debug("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
+ n, addr, data, msgid);
+ }
+}
+
static void dump_tcs_stats(struct tcs_drv *drv)
{
int i;
@@ -766,12 +824,13 @@
for (i = 0; i < drv->num_tcs; i++) {
if (!atomic_read(&drv->tcs_in_use[i]))
continue;
- pr_info("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
+ pr_debug("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
curr, i,
atomic_read(&drv->tcs_send_count[i]),
drv->tcs_last_sent_ts[i],
atomic_read(&drv->tcs_irq_count[i]),
drv->tcs_last_recv_ts[i]);
+ print_tcs_regs(drv, i);
print_response(drv, i);
}
}
@@ -840,7 +899,7 @@
if (ret != -EBUSY)
break;
udelay(100);
- } while (++count < 10);
+ } while (++count < 100);
tx_fail:
/* If there was an error in the request, schedule a response */
@@ -849,7 +908,8 @@
drv, msg, chan, TCS_M_INIT, ret);
dev_err(dev, "Error sending RPMH message %d\n", ret);
- send_tcs_response(resp);
+ if (resp)
+ send_tcs_response(resp);
ret = 0;
}
@@ -857,6 +917,7 @@
if (ret == -EBUSY) {
dev_err(dev, "TCS Busy, retrying RPMH message send\n");
dump_tcs_stats(drv);
+ ret = -EAGAIN;
}
return ret;
@@ -967,6 +1028,7 @@
}
chan = &mbox->chans[drv->num_assigned++];
+ chan->con_priv = drv;
return chan;
}
@@ -1108,6 +1170,9 @@
drv->mbox.is_idle = tcs_drv_is_idle;
drv->num_tcs = st;
drv->pdev = pdev;
+ INIT_LIST_HEAD(&drv->response_pending);
+ spin_lock_init(&drv->drv_lock);
+ tasklet_init(&drv->tasklet, tcs_notify_tx_done, (unsigned long)drv);
drv->name = of_get_property(pdev->dev.of_node, "label", NULL);
if (!drv->name)
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
index fdebdc7..b774625 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
@@ -51,21 +51,23 @@
static struct cam_cpas_intf *g_cpas_intf;
int cam_cpas_get_hw_info(uint32_t *camera_family,
- struct cam_hw_version *camera_version)
+ struct cam_hw_version *camera_version,
+ struct cam_hw_version *cpas_version)
{
if (!CAM_CPAS_INTF_INITIALIZED()) {
pr_err("cpas intf not initialized\n");
return -ENODEV;
}
- if (!camera_family || !camera_version) {
- pr_err("invalid input %pK %pK\n", camera_family,
- camera_version);
+ if (!camera_family || !camera_version || !cpas_version) {
+ pr_err("invalid input %pK %pK %pK\n", camera_family,
+ camera_version, cpas_version);
return -EINVAL;
}
*camera_family = g_cpas_intf->hw_caps.camera_family;
*camera_version = g_cpas_intf->hw_caps.camera_version;
+ *cpas_version = g_cpas_intf->hw_caps.cpas_version;
return 0;
}
@@ -344,7 +346,7 @@
}
rc = cam_cpas_get_hw_info(&query.camera_family,
- &query.camera_version);
+ &query.camera_version, &query.cpas_version);
if (rc)
break;
@@ -428,6 +430,7 @@
static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
+ struct cam_control cmd_data;
int32_t rc;
struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
@@ -436,9 +439,16 @@
return -ENODEV;
}
+ if (copy_from_user(&cmd_data, (void __user *)arg,
+ sizeof(cmd_data))) {
+ pr_err("Failed to copy from user_ptr=%pK size=%zu\n",
+ (void __user *)arg, sizeof(cmd_data));
+ return -EFAULT;
+ }
+
switch (cmd) {
case VIDIOC_CAM_CONTROL:
- rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
+ rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data);
break;
default:
pr_err("Invalid command %d for CPAS!\n", cmd);
@@ -446,6 +456,15 @@
break;
}
+ if (!rc) {
+ if (copy_to_user((void __user *)arg, &cmd_data,
+ sizeof(cmd_data))) {
+ pr_err("Failed to copy to user_ptr=%pK size=%zu\n",
+ (void __user *)arg, sizeof(cmd_data));
+ rc = -EFAULT;
+ }
+ }
+
return rc;
}
#endif
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h
index 12c8e66..20ed1b6 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h
@@ -279,17 +279,16 @@
.value = 3,
},
.danger_lut = {
- .enable = false,
+ .enable = true,
.access_type = CAM_REG_TYPE_READ_WRITE,
- .masked_value = 0,
.offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */
- .value = 0x0,
+ .value = 0xFFFFFF00,
},
.safe_lut = {
- .enable = false,
+ .enable = true,
.access_type = CAM_REG_TYPE_READ_WRITE,
.offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */
- .value = 0x0,
+ .value = 0x3,
},
.ubwc_ctl = {
.enable = true,
@@ -328,18 +327,16 @@
.value = 3,
},
.danger_lut = {
- .enable = false,
+ .enable = true,
.access_type = CAM_REG_TYPE_READ_WRITE,
- .masked_value = 0,
.offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */
- .value = 0x0,
+ .value = 0xFFFFFF00,
},
.safe_lut = {
- .enable = false,
+ .enable = true,
.access_type = CAM_REG_TYPE_READ_WRITE,
- .masked_value = 0,
.offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */
- .value = 0x0,
+ .value = 0x3,
},
.ubwc_ctl = {
.enable = true,
diff --git a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
index f6b0729..27b8504 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
@@ -312,13 +312,15 @@
* @camera_family : Camera family type. One of
* CAM_FAMILY_CAMERA_SS
* CAM_FAMILY_CPAS_SS
- * @camera_version : Camera version
+ * @camera_version : Camera platform version
+ * @cpas_version : Camera cpas version
*
* @return 0 on success.
*
*/
int cam_cpas_get_hw_info(
uint32_t *camera_family,
- struct cam_hw_version *camera_version);
+ struct cam_hw_version *camera_version,
+ struct cam_hw_version *cpas_version);
#endif /* _CAM_CPAS_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index c837232..4888e5b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -531,7 +531,8 @@
rc = camera_io_dev_read(
&(s_ctrl->io_master_info),
slave_info->sensor_id_reg_addr,
- &chipid, CAMERA_SENSOR_I2C_TYPE_WORD);
+ &chipid, CAMERA_SENSOR_I2C_TYPE_WORD,
+ CAMERA_SENSOR_I2C_TYPE_WORD);
CDBG("%s:%d read id: 0x%x expected id 0x%x:\n",
__func__, __LINE__, chipid, slave_info->sensor_id);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index f889abc..13e115a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -38,6 +38,7 @@
int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
uint32_t addr, uint32_t *data,
+ enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type)
{
if (!io_master_info) {
@@ -47,7 +48,7 @@
if (io_master_info->master_type == CCI_MASTER) {
return cam_cci_i2c_read(io_master_info->cci_client,
- addr, data, data_type, data_type);
+ addr, data, addr_type, data_type);
} else {
pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
__LINE__, io_master_info->master_type);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
index 757ac17..27bbe6e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
@@ -38,12 +38,14 @@
* @io_master_info: I2C/SPI master information
* @addr: I2C address
* @data: I2C data
+ * @addr_type: I2C addr type
* @data_type: I2C data type
*
* This API abstracts read functionality based on master type
*/
int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
uint32_t addr, uint32_t *data,
+ enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type);
/**
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 901632a..96f40e1 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -82,7 +82,7 @@
sync_cb->sync_obj = sync_obj;
INIT_WORK(&sync_cb->cb_dispatch_work,
cam_sync_util_cb_dispatch);
-
+ list_add_tail(&sync_cb->list, &row->callback_list);
sync_cb->status = row->state;
queue_work(sync_dev->work_queue,
&sync_cb->cb_dispatch_work);
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
index 1e42f75..0ffea5b 100644
--- a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
@@ -44,6 +44,7 @@
struct hfi_mem msg_q;
struct hfi_mem dbg_q;
struct hfi_mem sec_heap;
+ struct hfi_mem shmem;
void __iomem *icp_base;
};
diff --git a/drivers/media/platform/msm/camera/icp/hfi.c b/drivers/media/platform/msm/camera/icp/hfi.c
index 4315865..15e0315 100644
--- a/drivers/media/platform/msm/camera/icp/hfi.c
+++ b/drivers/media/platform/msm/camera/icp/hfi.c
@@ -19,6 +19,8 @@
#include <asm/errno.h>
#include <linux/timer.h>
#include <media/cam_icp.h>
+#include <linux/iopoll.h>
+
#include "cam_io_util.h"
#include "hfi_reg.h"
#include "hfi_sys_defs.h"
@@ -336,7 +338,7 @@
icp_base + HFI_REG_A5_CSR_A5_CONTROL);
} else {
cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
- ICP_FLAG_CSR_WAKE_UP_EN,
+ ICP_FLAG_CSR_WAKE_UP_EN | ICP_CSR_EN_CLKGATE_WFI,
icp_base + HFI_REG_A5_CSR_A5_CONTROL);
}
@@ -460,8 +462,10 @@
}
cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
- cam_io_w((uint32_t)0x7400000, icp_base + HFI_REG_SHARED_MEM_PTR);
- cam_io_w((uint32_t)0x6400000, icp_base + HFI_REG_SHARED_MEM_SIZE);
+ cam_io_w((uint32_t)hfi_mem->shmem.iova,
+ icp_base + HFI_REG_SHARED_MEM_PTR);
+ cam_io_w((uint32_t)hfi_mem->shmem.len,
+ icp_base + HFI_REG_SHARED_MEM_SIZE);
cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
icp_base + HFI_REG_UNCACHED_HEAP_PTR);
cam_io_w((uint32_t)hfi_mem->sec_heap.len,
@@ -472,25 +476,17 @@
hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
pr_debug("hw version : %u[%x]\n", hw_version, hw_version);
- do {
- msleep(500);
- status = cam_io_r(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
- } while (status != ICP_INIT_RESP_SUCCESS);
-
- if (status == ICP_INIT_RESP_SUCCESS) {
- g_hfi->hfi_state = FW_RESP_DONE;
- rc = 0;
- } else {
- rc = -ENODEV;
- pr_err("FW initialization failed");
+ rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
+ status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
+ if (rc) {
+ pr_err("timed out , status = %u\n", status);
goto regions_fail;
}
fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
g_hfi->hfi_state = FW_START_SENT;
- pr_debug("fw version : %u[%x]\n", fw_version, fw_version);
- pr_debug("hfi init is successful\n");
+ HFI_DBG("fw version : %u[%x]\n", fw_version, fw_version);
cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
return rc;
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 140542b..43491a9 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -26,6 +26,8 @@
#include <linux/debugfs.h>
#include <media/cam_defs.h>
#include <media/cam_icp.h>
+#include <linux/debugfs.h>
+
#include "cam_sync_api.h"
#include "cam_packet_util.h"
#include "cam_hw.h"
@@ -55,6 +57,23 @@
static struct cam_icp_hw_mgr icp_hw_mgr;
+static int cam_icp_hw_mgr_create_debugfs_entry(void)
+{
+ icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL);
+ if (!icp_hw_mgr.dentry)
+ return -ENOMEM;
+
+ if (!debugfs_create_bool("a5_debug",
+ 0644,
+ icp_hw_mgr.dentry,
+ &icp_hw_mgr.a5_debug)) {
+ debugfs_remove_recursive(icp_hw_mgr.dentry);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static int cam_icp_stop_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
{
struct cam_hw_intf *a5_dev_intf = NULL;
@@ -568,7 +587,12 @@
uint64_t kvaddr;
size_t len;
- pr_err("Allocating FW for iommu handle: %x\n", icp_hw_mgr.iommu_hdl);
+ rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl,
+ CAM_MEM_MGR_REGION_SHARED,
+ &icp_hw_mgr.hfi_mem.shmem);
+ if (rc)
+ return -ENOMEM;
+
rc = cam_smmu_alloc_firmware(icp_hw_mgr.iommu_hdl,
&iova, &kvaddr, &len);
if (rc < 0) {
@@ -764,7 +788,7 @@
msecs_to_jiffies((timeout)));
if (!rem_jiffies) {
rc = -ETIMEDOUT;
- pr_err("timeout/err in iconfig command: %d\n", rc);
+ pr_err("FW response timeout: %d\n", rc);
}
return rc;
@@ -870,6 +894,7 @@
cam_icp_free_hfi_mem();
hw_mgr->fw_download = false;
+ debugfs_remove_recursive(icp_hw_mgr.dentry);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return 0;
@@ -886,6 +911,8 @@
struct cam_icp_a5_set_irq_cb irq_cb;
struct cam_icp_a5_set_fw_buf_info fw_buf_info;
struct hfi_mem_info hfi_mem;
+ unsigned long rem_jiffies;
+ int timeout = 5000;
int rc = 0;
if (!hw_mgr) {
@@ -1014,9 +1041,12 @@
hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova;
hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len;
+ hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start;
+ hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len;
+
rc = cam_hfi_init(0, &hfi_mem,
a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
- false);
+ hw_mgr->a5_debug);
if (rc < 0) {
pr_err("hfi_init is failed\n");
goto set_irq_failed;
@@ -1033,7 +1063,13 @@
NULL, 0);
ICP_DBG("Wait for INIT DONE Message\n");
- wait_for_completion(&hw_mgr->a5_complete);
+ rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete,
+ msecs_to_jiffies((timeout)));
+ if (!rem_jiffies) {
+ rc = -ETIMEDOUT;
+ pr_err("FW response timed out %d\n", rc);
+ goto set_irq_failed;
+ }
ICP_DBG("Done Waiting for INIT DONE Message\n");
@@ -1041,6 +1077,10 @@
a5_dev_intf->hw_priv,
CAM_ICP_A5_CMD_POWER_COLLAPSE,
NULL, 0);
+ if (rc) {
+ pr_err("icp power collapse failed\n");
+ goto set_irq_failed;
+ }
hw_mgr->fw_download = true;
@@ -1428,6 +1468,8 @@
int rc = 0;
struct hfi_cmd_work_data *task_data;
struct hfi_cmd_ipebps_async ioconfig_cmd;
+ unsigned long rem_jiffies;
+ int timeout = 5000;
ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
@@ -1451,7 +1493,13 @@
task->process_cb = cam_icp_mgr_process_cmd;
cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
ICP_DBG("fw_hdl = %x ctx_data = %pK\n", ctx_data->fw_handle, ctx_data);
- wait_for_completion(&ctx_data->wait_complete);
+
+ rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+ msecs_to_jiffies((timeout)));
+ if (!rem_jiffies) {
+ rc = -ETIMEDOUT;
+ pr_err("FW response timed out %d\n", rc);
+ }
return rc;
}
@@ -1462,6 +1510,8 @@
{
struct hfi_cmd_create_handle create_handle;
struct hfi_cmd_work_data *task_data;
+ unsigned long rem_jiffies;
+ int timeout = 5000;
int rc = 0;
create_handle.size = sizeof(struct hfi_cmd_create_handle);
@@ -1479,7 +1529,13 @@
task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
task->process_cb = cam_icp_mgr_process_cmd;
cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
- wait_for_completion(&ctx_data->wait_complete);
+
+ rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+ msecs_to_jiffies((timeout)));
+ if (!rem_jiffies) {
+ rc = -ETIMEDOUT;
+ pr_err("FW response timed out %d\n", rc);
+ }
return rc;
}
@@ -1489,6 +1545,8 @@
{
struct hfi_cmd_ping_pkt ping_pkt;
struct hfi_cmd_work_data *task_data;
+ unsigned long rem_jiffies;
+ int timeout = 5000;
int rc = 0;
ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt);
@@ -1505,7 +1563,14 @@
task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
task->process_cb = cam_icp_mgr_process_cmd;
cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
- wait_for_completion(&ctx_data->wait_complete);
+
+ rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+ msecs_to_jiffies((timeout)));
+ if (!rem_jiffies) {
+ rc = -ETIMEDOUT;
+ pr_err("FW response timed out %d\n", rc);
+ }
+
return rc;
}
@@ -1929,6 +1994,9 @@
if (!icp_hw_mgr.msg_work_data)
goto msg_work_data_failed;
+ rc = cam_icp_hw_mgr_create_debugfs_entry();
+ if (rc)
+ goto msg_work_data_failed;
for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
icp_hw_mgr.msg_work->task.pool[i].payload =
@@ -1940,7 +2008,6 @@
init_completion(&icp_hw_mgr.a5_complete);
- pr_err("Exit\n");
return rc;
msg_work_data_failed:
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index e5ffa7a..32d796a 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -23,6 +23,8 @@
#include "hfi_session_defs.h"
#include "cam_req_mgr_workq.h"
#include "cam_mem_mgr.h"
+#include "cam_smmu_api.h"
+
#define CAM_ICP_ROLE_PARENT 1
#define CAM_ICP_ROLE_CHILD 2
@@ -56,6 +58,7 @@
struct cam_mem_mgr_memory_desc dbg_q;
struct cam_mem_mgr_memory_desc sec_heap;
struct cam_mem_mgr_memory_desc fw_buf;
+ struct cam_smmu_region_info shmem;
};
/**
@@ -176,6 +179,8 @@
struct hfi_cmd_work_data *cmd_work_data;
struct hfi_msg_work_data *msg_work_data;
uint32_t ctxt_cnt;
+ struct dentry *dentry;
+ bool a5_debug;
};
#endif /* CAM_ICP_HW_MGR_H */
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 88250e1..8d54e20 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1369,13 +1369,13 @@
pkt->size += sizeof(u32) * 2;
break;
}
- case HAL_CONFIG_VPE_OPERATIONS:
+ case HAL_PARAM_VPE_ROTATION:
{
- struct hfi_operations_type *hfi;
- struct hal_operations *prop =
- (struct hal_operations *) pdata;
- pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VPE_OPERATIONS;
- hfi = (struct hfi_operations_type *) &pkt->rg_property_data[1];
+ struct hfi_vpe_rotation_type *hfi;
+ struct hal_vpe_rotation *prop =
+ (struct hal_vpe_rotation *) pdata;
+ pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VPE_ROTATION;
+ hfi = (struct hfi_vpe_rotation_type *)&pkt->rg_property_data[1];
switch (prop->rotate) {
case HAL_ROTATE_NONE:
hfi->rotation = HFI_ROTATE_NONE;
@@ -1411,7 +1411,7 @@
rc = -EINVAL;
break;
}
- pkt->size += sizeof(u32) + sizeof(struct hfi_operations_type);
+ pkt->size += sizeof(u32) + sizeof(struct hfi_vpe_rotation_type);
break;
}
case HAL_PARAM_VENC_INTRA_REFRESH:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 89e8356..f678f56 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -110,6 +110,8 @@
struct hfi_profile_level *profile_level;
struct hfi_bit_depth *pixel_depth;
struct hfi_pic_struct *pic_struct;
+ struct hfi_buffer_requirements *buf_req;
+ struct hfi_index_extradata_input_crop_payload *crop_info;
u32 entropy_mode = 0;
u8 *data_ptr;
int prop_id;
@@ -231,6 +233,41 @@
data_ptr +=
sizeof(u32);
break;
+ case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
+ data_ptr = data_ptr + sizeof(u32);
+ buf_req =
+ (struct hfi_buffer_requirements *)
+ data_ptr;
+ event_notify.capture_buf_count =
+ buf_req->buffer_count_min;
+ dprintk(VIDC_DBG,
+ "Capture Count : 0x%x\n",
+ event_notify.capture_buf_count);
+ data_ptr +=
+ sizeof(struct hfi_buffer_requirements);
+ break;
+ case HFI_INDEX_EXTRADATA_INPUT_CROP:
+ data_ptr = data_ptr + sizeof(u32);
+ crop_info = (struct
+ hfi_index_extradata_input_crop_payload *)
+ data_ptr;
+ event_notify.crop_data.left = crop_info->left;
+ event_notify.crop_data.top = crop_info->top;
+ event_notify.crop_data.width = crop_info->width;
+ event_notify.crop_data.height =
+ crop_info->height;
+ dprintk(VIDC_DBG,
+ "CROP info : Left = %d Top = %d\n",
+ crop_info->left,
+ crop_info->top);
+ dprintk(VIDC_DBG,
+ "CROP info : Width = %d Height = %d\n",
+ crop_info->width,
+ crop_info->height);
+ data_ptr +=
+ sizeof(struct
+ hfi_index_extradata_input_crop_payload);
+ break;
default:
dprintk(VIDC_ERR,
"%s cmd: %#x not supported\n",
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 074ea4fa..b116622 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -74,6 +74,14 @@
goto mem_map_failed;
}
+ /* Check if the dmabuf size matches expected size */
+ if (buf->size < *buffer_size) {
+ rc = -EINVAL;
+ dprintk(VIDC_ERR,
+ "Size mismatch! Dmabuf size: %zu Expected Size: %lu",
+ buf->size, *buffer_size);
+ goto mem_buf_size_mismatch;
+ }
/* Prepare a dma buf for dma on the given device */
attach = dma_buf_attach(buf, cb->dev);
if (IS_ERR_OR_NULL(attach)) {
@@ -151,6 +159,7 @@
dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
mem_map_table_failed:
dma_buf_detach(buf, attach);
+mem_buf_size_mismatch:
mem_buf_attach_failed:
dma_buf_put(buf);
mem_map_failed:
@@ -201,12 +210,12 @@
}
}
-static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 size,
struct msm_smem *mem, enum hal_buffer buffer_type)
{
struct ion_handle *hndl = NULL;
ion_phys_addr_t iova = 0;
- unsigned long buffer_size = 0;
+ unsigned long buffer_size = size;
int rc = 0;
unsigned long align = SZ_4K;
unsigned long ion_flags = 0;
@@ -217,10 +226,11 @@
dprintk(VIDC_DBG, "%s ion handle: %pK\n", __func__, hndl);
if (IS_ERR_OR_NULL(hndl)) {
dprintk(VIDC_ERR, "Failed to get handle: %pK, %d, %d, %pK\n",
- client, fd, offset, hndl);
+ client, fd, size, hndl);
rc = -ENOMEM;
goto fail_import_fd;
}
+
mem->kvaddr = NULL;
rc = ion_handle_get_flags(client->clnt, hndl, &ion_flags);
if (rc) {
@@ -441,7 +451,7 @@
ion_client_destroy(client->clnt);
}
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 size,
enum hal_buffer buffer_type)
{
struct smem_client *client = clt;
@@ -459,7 +469,7 @@
}
switch (client->mem_type) {
case SMEM_ION:
- rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
+ rc = ion_user_to_kernel(clt, fd, size, mem, buffer_type);
break;
default:
dprintk(VIDC_ERR, "Mem type not supported\n");
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 7802d31..5c34f28 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -225,6 +225,14 @@
return 0;
}
+static int msm_v4l2_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+ return msm_vidc_g_crop(vidc_inst, a);
+}
+
static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
@@ -265,6 +273,7 @@
.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
.vidioc_s_parm = msm_v4l2_s_parm,
.vidioc_g_parm = msm_v4l2_g_parm,
+ .vidioc_g_crop = msm_v4l2_g_crop,
.vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
};
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index aa5f18d..d44684e 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1117,7 +1117,7 @@
struct hal_h264_entropy_control h264_entropy_control;
struct hal_intra_period intra_period;
struct hal_idr_period idr_period;
- struct hal_operations operations;
+ struct hal_vpe_rotation vpe_rotation;
struct hal_intra_refresh intra_refresh;
struct hal_multi_slice_control multi_slice_control;
struct hal_h264_db_control h264_db_control;
@@ -1345,19 +1345,12 @@
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
{
- if (!(inst->capability.pixelprocess_capabilities &
- HAL_VIDEO_ENCODER_ROTATION_CAPABILITY)) {
- dprintk(VIDC_ERR, "Rotation not supported: %#x\n",
- ctrl->id);
- rc = -ENOTSUPP;
- break;
- }
- property_id = HAL_CONFIG_VPE_OPERATIONS;
- operations.rotate = msm_comm_v4l2_to_hal(
+ property_id = HAL_PARAM_VPE_ROTATION;
+ vpe_rotation.rotate = msm_comm_v4l2_to_hal(
V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
ctrl->val);
- operations.flip = HAL_FLIP_NONE;
- pdata = &operations;
+ vpe_rotation.flip = HAL_FLIP_NONE;
+ pdata = &vpe_rotation;
break;
}
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 6253632..2e952a3 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -265,6 +265,29 @@
}
EXPORT_SYMBOL(msm_vidc_s_ctrl);
+int msm_vidc_g_crop(void *instance, struct v4l2_crop *crop)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !crop)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_ENCODER) {
+ dprintk(VIDC_ERR,
+ "Session = %pK : Encoder Crop is not implemented yet\n",
+ inst);
+ return -EPERM;
+ }
+
+ crop->c.left = inst->prop.crop_info.left;
+ crop->c.top = inst->prop.crop_info.top;
+ crop->c.width = inst->prop.crop_info.width;
+ crop->c.height = inst->prop.crop_info.height;
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_vidc_g_crop);
+
int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
{
struct msm_vidc_inst *inst = instance;
@@ -534,7 +557,7 @@
handle = msm_comm_smem_user_to_kernel(inst,
p->reserved[0],
- p->reserved[1],
+ p->length,
buffer_type);
if (!handle) {
dprintk(VIDC_ERR,
@@ -605,8 +628,10 @@
goto exit;
}
- dprintk(VIDC_DBG, "[MAP] Create binfo = %pK fd = %d type = %d\n",
- binfo, b->m.planes[0].reserved[0], b->type);
+ dprintk(VIDC_DBG,
+ "[MAP] Create binfo = %pK fd = %d size = %d type = %d\n",
+ binfo, b->m.planes[0].reserved[0],
+ b->m.planes[0].length, b->type);
for (i = 0; i < b->length; ++i) {
rc = 0;
@@ -878,6 +903,7 @@
struct buffer_info *bi, *dummy;
int i, rc = 0;
int found_buf = 0;
+ struct vb2_buf_entry *temp, *next;
if (!inst)
return -EINVAL;
@@ -936,6 +962,16 @@
default:
break;
}
+
+ mutex_lock(&inst->pendingq.lock);
+ list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) {
+ if (temp->vb->type == buffer_type) {
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ mutex_unlock(&inst->pendingq.lock);
+
return rc;
}
EXPORT_SYMBOL(msm_vidc_release_buffer);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index b1a8e8b..fe61e6f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1166,12 +1166,12 @@
if (!rc) {
dprintk(VIDC_ERR, "Wait interrupted or timed out: %d\n",
SESSION_MSG_INDEX(cmd));
- msm_comm_kill_session(inst);
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
dprintk(VIDC_ERR,
"sess resp timeout can potentially crash the system\n");
msm_comm_print_debug_info(inst);
msm_vidc_handle_hw_error(inst->core);
+ msm_comm_kill_session(inst);
rc = -EIO;
} else {
rc = 0;
@@ -1554,6 +1554,14 @@
inst->entropy_mode = event_notify->entropy_mode;
inst->profile = event_notify->profile;
inst->level = event_notify->level;
+ inst->prop.crop_info.left =
+ event_notify->crop_data.left;
+ inst->prop.crop_info.top =
+ event_notify->crop_data.top;
+ inst->prop.crop_info.height =
+ event_notify->crop_data.height;
+ inst->prop.crop_info.width =
+ event_notify->crop_data.width;
ptr = (u32 *)seq_changed_event.u.data;
ptr[0] = event_notify->height;
@@ -1561,6 +1569,10 @@
ptr[2] = event_notify->bit_depth;
ptr[3] = event_notify->pic_struct;
ptr[4] = event_notify->colour_space;
+ ptr[5] = event_notify->crop_data.top;
+ ptr[6] = event_notify->crop_data.left;
+ ptr[7] = event_notify->crop_data.height;
+ ptr[8] = event_notify->crop_data.width;
dprintk(VIDC_DBG,
"Event payload: height = %d width = %d\n",
@@ -1571,6 +1583,13 @@
event_notify->bit_depth, event_notify->pic_struct,
event_notify->colour_space);
+ dprintk(VIDC_DBG,
+ "Event payload: CROP top = %d left = %d Height = %d Width = %d\n",
+ event_notify->crop_data.top,
+ event_notify->crop_data.left,
+ event_notify->crop_data.height,
+ event_notify->crop_data.width);
+
mutex_lock(&inst->lock);
inst->in_reconfig = true;
inst->reconfig_height = event_notify->height;
@@ -4245,14 +4264,13 @@
__func__, inst,
SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO));
inst->state = MSM_VIDC_CORE_INVALID;
- msm_comm_kill_session(inst);
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
dprintk(VIDC_ERR,
"SESS_PROP timeout can potentially crash the system\n");
- if (inst->core->resources.debug_timeout)
- msm_comm_print_debug_info(inst);
+ msm_comm_print_debug_info(inst);
msm_vidc_handle_hw_error(inst->core);
+ msm_comm_kill_session(inst);
rc = -ETIMEDOUT;
goto exit;
} else {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 8ffbf50..c197776 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -12,6 +12,7 @@
*/
#define CREATE_TRACE_POINTS
+#define MAX_SSR_STRING_LEN 10
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
@@ -134,21 +135,36 @@
static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos) {
- u32 ssr_trigger_val;
- int rc;
+ unsigned long ssr_trigger_val = 0;
+ int rc = 0;
struct msm_vidc_core *core = filp->private_data;
+ size_t size = MAX_SSR_STRING_LEN;
+ char kbuf[MAX_SSR_STRING_LEN + 1] = {0};
if (!buf)
return -EINVAL;
- rc = kstrtou32(buf, 0, &ssr_trigger_val);
- if (rc < 0) {
+ if (!count)
+ goto exit;
+
+ if (count < size)
+ size = count;
+
+ if (copy_from_user(kbuf, buf, size)) {
+ dprintk(VIDC_WARN, "%s User memory fault\n", __func__);
+ rc = -EFAULT;
+ goto exit;
+ }
+
+ rc = kstrtoul(kbuf, 0, &ssr_trigger_val);
+ if (rc) {
dprintk(VIDC_WARN, "returning error err %d\n", rc);
rc = -EINVAL;
} else {
msm_vidc_trigger_ssr(core, ssr_trigger_val);
rc = count;
}
+exit:
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 8fd895d..f4c851a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -186,7 +186,7 @@
{
bool enable_fatal;
- enable_fatal = core->resources.debug_timeout;
+ enable_fatal = msm_vidc_debug_timeout;
/* Video driver can decide FATAL handling of HW errors
* based on multiple factors. This condition check will
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 37bccbd..5edd3d5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -175,9 +175,17 @@
struct video_device vdev;
};
+struct session_crop {
+ u32 left;
+ u32 top;
+ u32 width;
+ u32 height;
+};
+
struct session_prop {
u32 width[MAX_PORT_NUM];
u32 height[MAX_PORT_NUM];
+ struct session_crop crop_info;
u32 fps;
u32 bitrate;
};
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index d259072..19ca561 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -969,7 +969,7 @@
res->debug_timeout = of_property_read_bool(pdev->dev.of_node,
"qcom,debug-timeout");
- res->debug_timeout |= msm_vidc_debug_timeout;
+ msm_vidc_debug_timeout |= res->debug_timeout;
of_property_read_u32(pdev->dev.of_node,
"qcom,pm-qos-latency-us", &res->pm_qos_latency_us);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 8968764..6139e46 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1049,8 +1049,12 @@
}
dprintk(VIDC_DBG, "Suspending Venus\n");
- rc = flush_delayed_work(&venus_hfi_pm_work);
+ flush_delayed_work(&venus_hfi_pm_work);
+ mutex_lock(&device->lock);
+ if (device->power_enabled)
+ rc = -EBUSY;
+ mutex_unlock(&device->lock);
return rc;
}
@@ -4168,7 +4172,7 @@
struct venus_hfi_device *device = dev;
u32 smem_block_size = 0;
u8 *smem_table_ptr;
- char version[VENUS_VERSION_LENGTH];
+ char version[VENUS_VERSION_LENGTH] = "";
const u32 smem_image_index_venus = 14 * 128;
if (!device || !fw_info) {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index a2f076b..86e4f42 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -154,7 +154,7 @@
HAL_PARAM_VENC_SESSION_QP_RANGE,
HAL_CONFIG_VENC_INTRA_PERIOD,
HAL_CONFIG_VENC_IDR_PERIOD,
- HAL_CONFIG_VPE_OPERATIONS,
+ HAL_PARAM_VPE_ROTATION,
HAL_PARAM_VENC_INTRA_REFRESH,
HAL_PARAM_VENC_MULTI_SLICE_CONTROL,
HAL_SYS_DEBUG_CONFIG,
@@ -634,7 +634,7 @@
HAL_UNUSED_FLIP = 0x10000000,
};
-struct hal_operations {
+struct hal_vpe_rotation {
enum hal_rotate rotate;
enum hal_flip flip;
};
@@ -1019,7 +1019,7 @@
struct hal_quantization_range quantization_range;
struct hal_intra_period intra_period;
struct hal_idr_period idr_period;
- struct hal_operations operations;
+ struct hal_vpe_rotation vpe_rotation;
struct hal_intra_refresh intra_refresh;
struct hal_multi_slice_control multi_slice_control;
struct hal_debug_config debug_config;
@@ -1212,6 +1212,16 @@
} data;
};
+struct hal_index_extradata_input_crop_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 left;
+ u32 top;
+ u32 width;
+ u32 height;
+};
+
struct msm_vidc_cb_event {
u32 device_id;
void *session_id;
@@ -1227,6 +1237,8 @@
u32 profile;
u32 level;
u32 entropy_mode;
+ u32 capture_buf_count;
+ struct hal_index_extradata_input_crop_payload crop_data;
};
struct msm_vidc_cb_data_done {
@@ -1314,16 +1326,6 @@
int num_sessions;
};
-struct hal_index_extradata_input_crop_payload {
- u32 size;
- u32 version;
- u32 port_index;
- u32 left;
- u32 top;
- u32 width;
- u32 height;
-};
-
struct hal_cmd_sys_get_property_packet {
u32 size;
u32 packet_type;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 2d4a573..616fc09 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -327,8 +327,6 @@
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004)
#define HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005)
-#define HFI_PROPERTY_PARAM_VPE_COMMON_START \
- (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
#define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008)
#define HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME \
@@ -344,13 +342,15 @@
#define HFI_PROPERTY_CONFIG_VENC_SESSION_QP \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x012)
+#define HFI_PROPERTY_PARAM_VPE_COMMON_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
+#define HFI_PROPERTY_PARAM_VPE_ROTATION \
+ (HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x001)
#define HFI_PROPERTY_CONFIG_VPE_COMMON_START \
(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
#define HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE \
(HFI_PROPERTY_CONFIG_COMMON_START + 0x010)
-#define HFI_PROPERTY_CONFIG_VPE_OPERATIONS \
- (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x002)
struct hfi_pic_struct {
u32 progressive_only;
@@ -472,7 +472,7 @@
u32 idr_period;
};
-struct hfi_operations_type {
+struct hfi_vpe_rotation_type {
u32 rotation;
u32 flip;
};
@@ -716,12 +716,7 @@
#define HFI_FLIP_NONE (HFI_COMMON_BASE + 0x1)
#define HFI_FLIP_HORIZONTAL (HFI_COMMON_BASE + 0x2)
-#define HFI_FLIP_VERTICAL (HFI_COMMON_BASE + 0x3)
-
-struct hfi_operations {
- u32 rotate;
- u32 flip;
-};
+#define HFI_FLIP_VERTICAL (HFI_COMMON_BASE + 0x4)
#define HFI_RESOURCE_SYSCACHE 0x00000002
diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c
index fbaf05e..e8ba149 100644
--- a/drivers/mfd/wcd934x-regmap.c
+++ b/drivers/mfd/wcd934x-regmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1926,6 +1926,19 @@
case WCD934X_ANA_MBHC_ELECT:
case WCD934X_ANA_MBHC_ZDET:
case WCD934X_ANA_MICB2:
+ case WCD934X_CODEC_RPM_CLK_MCLK_CFG:
+ case WCD934X_CLK_SYS_MCLK_PRG:
+ case WCD934X_CHIP_TIER_CTRL_EFUSE_CTL:
+ case WCD934X_ANA_BIAS:
+ case WCD934X_ANA_BUCK_CTL:
+ case WCD934X_ANA_RCO:
+ case WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL:
+ case WCD934X_CODEC_RPM_CLK_GATE:
+ case WCD934X_BIAS_VBG_FINE_ADJ:
+ case WCD934X_CODEC_CPR_SVS_CX_VDD:
+ case WCD934X_CODEC_CPR_SVS2_CX_VDD:
+ case WCD934X_CDC_TOP_TOP_CFG1:
+ case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
return true;
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 877c4d1..c1857c7 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1261,7 +1261,7 @@
atomic_read(&data->ioctl_count) <= 1)) {
pr_err("Interrupted from abort\n");
ret = -ERESTARTSYS;
- break;
+ return ret;
}
}
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 0d0d56f..0c8ff86 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -338,10 +338,15 @@
{
struct mmc_host *host = data;
- if (host && host->ops && host->ops->force_err_irq) {
- mmc_host_clk_hold(host);
+ if (host && host->card && host->ops &&
+ host->ops->force_err_irq) {
+ /*
+ * To access the force error irq reg, we need to make
+ * sure the host is powered up and host clock is ticking.
+ */
+ mmc_get_card(host->card);
host->ops->force_err_irq(host, val);
- mmc_host_clk_release(host);
+ mmc_put_card(host->card);
}
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index 293371b..c5aaac5 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -125,7 +125,6 @@
IPA_USB_CONNECTED,
IPA_USB_STOPPED,
IPA_USB_SUSPEND_REQUESTED,
- IPA_USB_SUSPEND_IN_PROGRESS,
IPA_USB_SUSPENDED,
IPA_USB_SUSPENDED_NO_RWAKEUP,
IPA_USB_RESUME_IN_PROGRESS
@@ -146,13 +145,6 @@
#define IPA3_USB_IS_TTYPE_DPL(__ttype) \
((__ttype) == IPA_USB_TRANSPORT_DPL)
-struct finish_suspend_work_context {
- struct work_struct work;
- enum ipa3_usb_transport_type ttype;
- u32 dl_clnt_hdl;
- u32 ul_clnt_hdl;
-};
-
struct ipa3_usb_teth_prot_conn_params {
u32 usb_to_ipa_clnt_hdl;
u32 ipa_to_usb_clnt_hdl;
@@ -168,7 +160,6 @@
int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data);
void *user_data;
enum ipa3_usb_state state;
- struct finish_suspend_work_context finish_suspend_work;
struct ipa_usb_xdci_chan_params ch_params;
struct ipa3_usb_teth_prot_conn_params teth_conn_params;
};
@@ -221,16 +212,10 @@
static void ipa3_usb_wq_notify_remote_wakeup(struct work_struct *work);
static void ipa3_usb_wq_dpl_notify_remote_wakeup(struct work_struct *work);
-static void ipa3_usb_wq_notify_suspend_completed(struct work_struct *work);
-static void ipa3_usb_wq_dpl_notify_suspend_completed(struct work_struct *work);
static DECLARE_WORK(ipa3_usb_notify_remote_wakeup_work,
ipa3_usb_wq_notify_remote_wakeup);
static DECLARE_WORK(ipa3_usb_dpl_notify_remote_wakeup_work,
ipa3_usb_wq_dpl_notify_remote_wakeup);
-static DECLARE_WORK(ipa3_usb_notify_suspend_completed_work,
- ipa3_usb_wq_notify_suspend_completed);
-static DECLARE_WORK(ipa3_usb_dpl_notify_suspend_completed_work,
- ipa3_usb_wq_dpl_notify_suspend_completed);
struct ipa3_usb_context *ipa3_usb_ctx;
@@ -273,8 +258,6 @@
return "IPA_USB_STOPPED";
case IPA_USB_SUSPEND_REQUESTED:
return "IPA_USB_SUSPEND_REQUESTED";
- case IPA_USB_SUSPEND_IN_PROGRESS:
- return "IPA_USB_SUSPEND_IN_PROGRESS";
case IPA_USB_SUSPENDED:
return "IPA_USB_SUSPENDED";
case IPA_USB_SUSPENDED_NO_RWAKEUP:
@@ -330,17 +313,11 @@
* In case of failure during suspend request
* handling, state is reverted to connected.
*/
- (err_permit && state == IPA_USB_SUSPEND_REQUESTED) ||
- /*
- * In case of failure during suspend completing
- * handling, state is reverted to connected.
- */
- (err_permit && state == IPA_USB_SUSPEND_IN_PROGRESS))
+ (err_permit && state == IPA_USB_SUSPEND_REQUESTED))
state_legal = true;
break;
case IPA_USB_STOPPED:
- if (state == IPA_USB_SUSPEND_IN_PROGRESS ||
- state == IPA_USB_CONNECTED ||
+ if (state == IPA_USB_CONNECTED ||
state == IPA_USB_SUSPENDED ||
state == IPA_USB_SUSPENDED_NO_RWAKEUP)
state_legal = true;
@@ -349,19 +326,8 @@
if (state == IPA_USB_CONNECTED)
state_legal = true;
break;
- case IPA_USB_SUSPEND_IN_PROGRESS:
- if (state == IPA_USB_SUSPEND_REQUESTED ||
- /*
- * In case of failure during resume, state is reverted
- * to original, which could be suspend_in_progress.
- * Allow it.
- */
- (err_permit && state == IPA_USB_RESUME_IN_PROGRESS))
- state_legal = true;
- break;
case IPA_USB_SUSPENDED:
if (state == IPA_USB_SUSPEND_REQUESTED ||
- state == IPA_USB_SUSPEND_IN_PROGRESS ||
/*
* In case of failure during resume, state is reverted
* to original, which could be suspended. Allow it
@@ -374,8 +340,7 @@
state_legal = true;
break;
case IPA_USB_RESUME_IN_PROGRESS:
- if (state == IPA_USB_SUSPEND_IN_PROGRESS ||
- state == IPA_USB_SUSPENDED)
+ if (state == IPA_USB_SUSPENDED)
state_legal = true;
break;
default:
@@ -452,7 +417,6 @@
break;
case IPA_USB_OP_DISCONNECT:
if (state == IPA_USB_CONNECTED ||
- state == IPA_USB_SUSPEND_IN_PROGRESS ||
state == IPA_USB_SUSPENDED ||
state == IPA_USB_SUSPENDED_NO_RWAKEUP)
is_legal = true;
@@ -483,7 +447,6 @@
break;
case IPA_USB_OP_RESUME:
if (state == IPA_USB_SUSPENDED ||
- state == IPA_USB_SUSPEND_IN_PROGRESS ||
state == IPA_USB_SUSPENDED_NO_RWAKEUP)
is_legal = true;
break;
@@ -582,71 +545,6 @@
ipa3_usb_notify_do(IPA_USB_TRANSPORT_DPL, IPA_USB_REMOTE_WAKEUP);
}
-static void ipa3_usb_wq_notify_suspend_completed(struct work_struct *work)
-{
- ipa3_usb_notify_do(IPA_USB_TRANSPORT_TETH, IPA_USB_SUSPEND_COMPLETED);
-}
-
-static void ipa3_usb_wq_dpl_notify_suspend_completed(struct work_struct *work)
-{
- ipa3_usb_notify_do(IPA_USB_TRANSPORT_DPL, IPA_USB_SUSPEND_COMPLETED);
-}
-
-static void ipa3_usb_wq_finish_suspend_work(struct work_struct *work)
-{
- struct finish_suspend_work_context *finish_suspend_work_ctx;
- unsigned long flags;
- int result = -EFAULT;
- struct ipa3_usb_transport_type_ctx *tctx;
-
- mutex_lock(&ipa3_usb_ctx->general_mutex);
- IPA_USB_DBG_LOW("entry\n");
- finish_suspend_work_ctx = container_of(work,
- struct finish_suspend_work_context, work);
- tctx = &ipa3_usb_ctx->ttype_ctx[finish_suspend_work_ctx->ttype];
-
- spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
- if (tctx->state != IPA_USB_SUSPEND_IN_PROGRESS) {
- spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
- mutex_unlock(&ipa3_usb_ctx->general_mutex);
- return;
- }
- spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
-
- /* Stop DL/DPL channel */
- result = ipa3_stop_gsi_channel(finish_suspend_work_ctx->dl_clnt_hdl);
- if (result) {
- IPAERR("Error stopping DL/DPL channel: %d, resuming channel\n",
- result);
- ipa3_xdci_resume(finish_suspend_work_ctx->ul_clnt_hdl,
- finish_suspend_work_ctx->dl_clnt_hdl,
- IPA3_USB_IS_TTYPE_DPL(finish_suspend_work_ctx->ttype));
- /* Change state back to CONNECTED */
- if (!ipa3_usb_set_state(IPA_USB_CONNECTED, true,
- finish_suspend_work_ctx->ttype))
- IPA_USB_ERR("failed to change state to connected\n");
- queue_work(ipa3_usb_ctx->wq,
- IPA3_USB_IS_TTYPE_DPL(finish_suspend_work_ctx->ttype) ?
- &ipa3_usb_dpl_notify_remote_wakeup_work :
- &ipa3_usb_notify_remote_wakeup_work);
- mutex_unlock(&ipa3_usb_ctx->general_mutex);
- return;
- }
-
- /* Change ipa_usb state to SUSPENDED */
- if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false,
- finish_suspend_work_ctx->ttype))
- IPA_USB_ERR("failed to change state to suspended\n");
-
- queue_work(ipa3_usb_ctx->wq,
- IPA3_USB_IS_TTYPE_DPL(finish_suspend_work_ctx->ttype) ?
- &ipa3_usb_dpl_notify_suspend_completed_work :
- &ipa3_usb_notify_suspend_completed_work);
-
- IPA_USB_DBG_LOW("exit\n");
- mutex_unlock(&ipa3_usb_ctx->general_mutex);
-}
-
static int ipa3_usb_cons_request_resource_cb_do(
enum ipa3_usb_transport_type ttype,
struct work_struct *remote_wakeup_work)
@@ -674,17 +572,6 @@
else
result = -EINPROGRESS;
break;
- case IPA_USB_SUSPEND_IN_PROGRESS:
- /*
- * This case happens due to suspend interrupt.
- * CONS is granted
- */
- if (!rm_ctx->cons_requested) {
- rm_ctx->cons_requested = true;
- queue_work(ipa3_usb_ctx->wq, remote_wakeup_work);
- }
- result = 0;
- break;
case IPA_USB_SUSPENDED:
if (!rm_ctx->cons_requested) {
rm_ctx->cons_requested = true;
@@ -727,15 +614,10 @@
ipa3_usb_state_to_string(
ipa3_usb_ctx->ttype_ctx[ttype].state));
switch (ipa3_usb_ctx->ttype_ctx[ttype].state) {
- case IPA_USB_SUSPEND_IN_PROGRESS:
+ case IPA_USB_SUSPENDED:
/* Proceed with the suspend if no DL/DPL data */
if (rm_ctx->cons_requested)
rm_ctx->cons_requested_released = true;
- else {
- queue_work(ipa3_usb_ctx->wq,
- &ipa3_usb_ctx->ttype_ctx[ttype].
- finish_suspend_work.work);
- }
break;
case IPA_USB_SUSPEND_REQUESTED:
if (rm_ctx->cons_requested)
@@ -2311,8 +2193,7 @@
spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
orig_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
- if (orig_state != IPA_USB_SUSPEND_IN_PROGRESS &&
- orig_state != IPA_USB_SUSPENDED) {
+ if (orig_state != IPA_USB_SUSPENDED) {
spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
flags);
/* Stop UL channel */
@@ -2340,8 +2221,7 @@
if (result)
goto bad_params;
- if (orig_state != IPA_USB_SUSPEND_IN_PROGRESS &&
- orig_state != IPA_USB_SUSPENDED) {
+ if (orig_state != IPA_USB_SUSPENDED) {
result = ipa3_usb_release_prod(ttype);
if (result) {
IPA_USB_ERR("failed to release PROD.\n");
@@ -2547,7 +2427,6 @@
{
int result = 0;
unsigned long flags;
- enum ipa3_usb_cons_state curr_cons_state;
enum ipa3_usb_transport_type ttype;
mutex_lock(&ipa3_usb_ctx->general_mutex);
@@ -2602,49 +2481,20 @@
goto release_prod_fail;
}
+ /* Check if DL/DPL data pending */
spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
- curr_cons_state = ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state;
+ if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state ==
+ IPA_USB_CONS_GRANTED &&
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
+
+ IPA_USB_DBG("DL/DPL data pending, invoke remote wakeup\n");
+ queue_work(ipa3_usb_ctx->wq,
+ IPA3_USB_IS_TTYPE_DPL(ttype) ?
+ &ipa3_usb_dpl_notify_remote_wakeup_work :
+ &ipa3_usb_notify_remote_wakeup_work);
+ }
spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
- if (curr_cons_state == IPA_USB_CONS_GRANTED) {
- /* Change state to SUSPEND_IN_PROGRESS */
- if (!ipa3_usb_set_state(IPA_USB_SUSPEND_IN_PROGRESS,
- false, ttype))
- IPA_USB_ERR("fail set state to suspend_in_progress\n");
- /* Check if DL/DPL data pending */
- spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
- if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
- IPA_USB_DBG(
- "DL/DPL data pending, invoke remote wakeup\n");
- queue_work(ipa3_usb_ctx->wq,
- IPA3_USB_IS_TTYPE_DPL(ttype) ?
- &ipa3_usb_dpl_notify_remote_wakeup_work :
- &ipa3_usb_notify_remote_wakeup_work);
- }
- spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
-
- ipa3_usb_ctx->ttype_ctx[ttype].finish_suspend_work.ttype =
- ttype;
- ipa3_usb_ctx->ttype_ctx[ttype].finish_suspend_work.dl_clnt_hdl =
- dl_clnt_hdl;
- ipa3_usb_ctx->ttype_ctx[ttype].finish_suspend_work.ul_clnt_hdl =
- ul_clnt_hdl;
- INIT_WORK(&ipa3_usb_ctx->ttype_ctx[ttype].
- finish_suspend_work.work,
- ipa3_usb_wq_finish_suspend_work);
-
- result = -EINPROGRESS;
- IPA_USB_DBG("exit with suspend_in_progress\n");
- goto bad_params;
- }
-
- /* Stop DL channel */
- result = ipa3_stop_gsi_channel(dl_clnt_hdl);
- if (result) {
- IPAERR("Error stopping DL/DPL channel: %d\n", result);
- result = -EFAULT;
- goto release_prod_fail;
- }
/* Change state to SUSPENDED */
if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false, ttype))
IPA_USB_ERR("failed to change state to suspended\n");
@@ -2803,13 +2653,11 @@
}
}
- if (prev_state != IPA_USB_SUSPEND_IN_PROGRESS) {
- /* Start DL/DPL channel */
- result = ipa3_start_gsi_channel(dl_clnt_hdl);
- if (result) {
- IPA_USB_ERR("failed to start DL/DPL channel.\n");
- goto start_dl_fail;
- }
+ /* Start DL/DPL channel */
+ result = ipa3_start_gsi_channel(dl_clnt_hdl);
+ if (result) {
+ IPA_USB_ERR("failed to start DL/DPL channel.\n");
+ goto start_dl_fail;
}
/* Change state to CONNECTED */
@@ -2824,12 +2672,10 @@
return 0;
state_change_connected_fail:
- if (prev_state != IPA_USB_SUSPEND_IN_PROGRESS) {
- result = ipa3_stop_gsi_channel(dl_clnt_hdl);
- if (result)
- IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
- result);
- }
+ result = ipa3_stop_gsi_channel(dl_clnt_hdl);
+ if (result)
+ IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
+ result);
start_dl_fail:
if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
result = ipa3_stop_gsi_channel(ul_clnt_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 31e530e..837bf38 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -232,6 +232,9 @@
ipa3_transport_release_resource);
static void ipa_gsi_notify_cb(struct gsi_per_notify *notify);
+static void ipa3_post_init_wq(struct work_struct *work);
+static DECLARE_WORK(ipa3_post_init_work, ipa3_post_init_wq);
+
static struct ipa3_plat_drv_res ipa3_res = {0, };
struct msm_bus_scale_pdata *ipa3_bus_scale_table;
@@ -495,63 +498,6 @@
return 0;
}
-/**
-* ipa3_flow_control() - Enable/Disable flow control on a particular client.
-* Return codes:
-* None
-*/
-void ipa3_flow_control(enum ipa_client_type ipa_client,
- bool enable, uint32_t qmap_id)
-{
- struct ipa_ep_cfg_ctrl ep_ctrl = {0};
- int ep_idx;
- struct ipa3_ep_context *ep;
-
- /* Check if tethered flow control is needed or not.*/
- if (!ipa3_ctx->tethered_flow_control) {
- IPADBG("Apps flow control is not needed\n");
- return;
- }
-
- /* Check if ep is valid. */
- ep_idx = ipa3_get_ep_mapping(ipa_client);
- if (ep_idx == -1) {
- IPADBG("Invalid IPA client\n");
- return;
- }
-
- ep = &ipa3_ctx->ep[ep_idx];
- if (!ep->valid || (ep->client != IPA_CLIENT_USB_PROD)) {
- IPADBG("EP not valid/Not applicable for client.\n");
- return;
- }
-
- spin_lock(&ipa3_ctx->disconnect_lock);
- /* Check if the QMAP_ID matches. */
- if (ep->cfg.meta.qmap_id != qmap_id) {
- IPADBG("Flow control ind not for same flow: %u %u\n",
- ep->cfg.meta.qmap_id, qmap_id);
- spin_unlock(&ipa3_ctx->disconnect_lock);
- return;
- }
- if (!ep->disconnect_in_progress) {
- if (enable) {
- IPADBG("Enabling Flow\n");
- ep_ctrl.ipa_ep_delay = false;
- IPA_STATS_INC_CNT(ipa3_ctx->stats.flow_enable);
- } else {
- IPADBG("Disabling Flow\n");
- ep_ctrl.ipa_ep_delay = true;
- IPA_STATS_INC_CNT(ipa3_ctx->stats.flow_disable);
- }
- ep_ctrl.ipa_ep_suspend = false;
- ipa3_cfg_ep_ctrl(ep_idx, &ep_ctrl);
- } else {
- IPADBG("EP disconnect is in progress\n");
- }
- spin_unlock(&ipa3_ctx->disconnect_lock);
-}
-
static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type)
{
if (!buff) {
@@ -1863,9 +1809,11 @@
IPA_ENDP_INIT_HOL_BLOCK_EN_n,
ep_idx, &ep_holb);
- ipahal_write_reg_n_fields(
- IPA_ENDP_INIT_CTRL_n,
- ep_idx, &ep_suspend);
+ /* from IPA 4.0 pipe suspend is not supported */
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
+ ipahal_write_reg_n_fields(
+ IPA_ENDP_INIT_CTRL_n,
+ ep_idx, &ep_suspend);
}
}
}
@@ -3979,6 +3927,15 @@
struct ipa3_flt_tbl *flt_tbl;
int i;
+ if (ipa3_ctx == NULL) {
+ IPADBG("IPA driver haven't initialized\n");
+ return -ENXIO;
+ }
+
+ /* Prevent consequent calls from trying to load the FW again. */
+ if (ipa3_ctx->ipa_initialization_complete)
+ return 0;
+
/*
* indication whether working in MHI config or non MHI config is given
* in ipa3_write which is launched before ipa3_post_init. i.e. from
@@ -4113,41 +4070,15 @@
fail_setup_apps_pipes:
gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
fail_register_device:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
- ipa_rm_exit();
- cdev_del(&ipa3_ctx->cdev);
- device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
- unregister_chrdev_region(ipa3_ctx->dev_num, 1);
- ipa3_free_dma_task_for_gsi();
ipa3_destroy_flt_tbl_idrs();
- idr_destroy(&ipa3_ctx->ipa_idr);
- kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
- kmem_cache_destroy(ipa3_ctx->tx_pkt_wrapper_cache);
- kmem_cache_destroy(ipa3_ctx->rt_tbl_cache);
- kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_offset_cache);
- kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache);
- kmem_cache_destroy(ipa3_ctx->hdr_offset_cache);
- kmem_cache_destroy(ipa3_ctx->hdr_cache);
- kmem_cache_destroy(ipa3_ctx->rt_rule_cache);
- kmem_cache_destroy(ipa3_ctx->flt_rule_cache);
- destroy_workqueue(ipa3_ctx->transport_power_mgmt_wq);
- destroy_workqueue(ipa3_ctx->power_mgmt_wq);
- iounmap(ipa3_ctx->mmio);
- ipa3_disable_clks();
- if (ipa3_clk)
- clk_put(ipa3_clk);
- ipa3_clk = NULL;
- msm_bus_scale_unregister_client(ipa3_ctx->ipa_bus_hdl);
- if (ipa3_bus_scale_table) {
- msm_bus_cl_clear_pdata(ipa3_bus_scale_table);
- ipa3_bus_scale_table = NULL;
- }
- kfree(ipa3_ctx->ctrl);
- kfree(ipa3_ctx);
- ipa3_ctx = NULL;
return result;
}
+static void ipa3_post_init_wq(struct work_struct *work)
+{
+ ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
+}
+
static int ipa3_trigger_fw_loading_mdms(void)
{
int result;
@@ -4249,9 +4180,10 @@
if (result) {
IPAERR("FW loading process has failed\n");
return result;
- } else
- ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
-
+ } else {
+ queue_work(ipa3_ctx->transport_power_mgmt_wq,
+ &ipa3_post_init_work);
+ }
return count;
}
@@ -4722,20 +4654,6 @@
goto fail_device_create;
}
- cdev_init(&ipa3_ctx->cdev, &ipa3_drv_fops);
- ipa3_ctx->cdev.owner = THIS_MODULE;
- ipa3_ctx->cdev.ops = &ipa3_drv_fops; /* from LDD3 */
-
- result = cdev_add(&ipa3_ctx->cdev, ipa3_ctx->dev_num, 1);
- if (result) {
- IPAERR(":cdev_add err=%d\n", -result);
- result = -ENODEV;
- goto fail_cdev_add;
- }
- IPADBG("ipa cdev added successful. major:%d minor:%d\n",
- MAJOR(ipa3_ctx->dev_num),
- MINOR(ipa3_ctx->dev_num));
-
if (ipa3_create_nat_device()) {
IPAERR("unable to create nat device\n");
result = -ENODEV;
@@ -4793,16 +4711,28 @@
}
}
+ cdev_init(&ipa3_ctx->cdev, &ipa3_drv_fops);
+ ipa3_ctx->cdev.owner = THIS_MODULE;
+ ipa3_ctx->cdev.ops = &ipa3_drv_fops; /* from LDD3 */
+
+ result = cdev_add(&ipa3_ctx->cdev, ipa3_ctx->dev_num, 1);
+ if (result) {
+ IPAERR(":cdev_add err=%d\n", -result);
+ result = -ENODEV;
+ goto fail_cdev_add;
+ }
+ IPADBG("ipa cdev added successful. major:%d minor:%d\n",
+ MAJOR(ipa3_ctx->dev_num),
+ MINOR(ipa3_ctx->dev_num));
return 0;
+fail_cdev_add:
fail_ipa_init_interrupts:
ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
fail_create_apps_resource:
ipa_rm_exit();
fail_ipa_rm_init:
fail_nat_dev_add:
- cdev_del(&ipa3_ctx->cdev);
-fail_cdev_add:
device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
fail_device_create:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 0b8115f..564397a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -69,13 +69,15 @@
}
/* Enable the pipe */
- if (IPA_CLIENT_IS_CONS(ep->client) &&
- (ep->keep_ipa_awake ||
- ipa3_ctx->resume_on_connect[ep->client] ||
- !ipa3_should_pipe_be_suspended(ep->client))) {
- memset(&ep_cfg_ctrl, 0, sizeof(ep_cfg_ctrl));
- ep_cfg_ctrl.ipa_ep_suspend = false;
- res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+ if (IPA_CLIENT_IS_CONS(ep->client) &&
+ (ep->keep_ipa_awake ||
+ ipa3_ctx->resume_on_connect[ep->client] ||
+ !ipa3_should_pipe_be_suspended(ep->client))) {
+ memset(&ep_cfg_ctrl, 0, sizeof(ep_cfg_ctrl));
+ ep_cfg_ctrl.ipa_ep_suspend = false;
+ res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+ }
}
return res;
@@ -97,33 +99,41 @@
res = ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg);
}
- /* Suspend the pipe */
- if (IPA_CLIENT_IS_CONS(ep->client)) {
- /*
- * for RG10 workaround uC needs to be loaded before pipe can
- * be suspended in this case.
- */
- if (ipa3_ctx->apply_rg10_wa && ipa3_uc_state_check()) {
- IPADBG("uC is not loaded yet, waiting...\n");
- res = wait_for_completion_timeout(
- &ipa3_ctx->uc_loaded_completion_obj, 60 * HZ);
- if (res == 0)
- IPADBG("timeout waiting for uC to load\n");
+ /*
+ * for IPA 4.0 and above aggregation frame is closed together with
+ * channel STOP
+ */
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+ /* Suspend the pipe */
+ if (IPA_CLIENT_IS_CONS(ep->client)) {
+ /*
+ * for RG10 workaround uC needs to be loaded before
+ * pipe can be suspended in this case.
+ */
+ if (ipa3_ctx->apply_rg10_wa && ipa3_uc_state_check()) {
+ IPADBG("uC is not loaded yet, waiting...\n");
+ res = wait_for_completion_timeout(
+ &ipa3_ctx->uc_loaded_completion_obj,
+ 60 * HZ);
+ if (res == 0)
+ IPADBG("timeout waiting for uC load\n");
+ }
+
+ memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+ ep_cfg_ctrl.ipa_ep_suspend = true;
+ res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
}
- memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
- ep_cfg_ctrl.ipa_ep_suspend = true;
- res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
- }
-
- udelay(IPA_PKT_FLUSH_TO_US);
- ipahal_read_reg_n_fields(IPA_ENDP_INIT_AGGR_n, clnt_hdl, &ep_aggr);
- if (ep_aggr.aggr_en) {
- res = ipa3_tag_aggr_force_close(clnt_hdl);
- if (res) {
- IPAERR("tag process timeout, client:%d err:%d\n",
- clnt_hdl, res);
- BUG();
+ udelay(IPA_PKT_FLUSH_TO_US);
+ ipahal_read_reg_n_fields(IPA_ENDP_INIT_AGGR_n, clnt_hdl,
+ &ep_aggr);
+ if (ep_aggr.aggr_en) {
+ res = ipa3_tag_aggr_force_close(clnt_hdl);
+ if (res) {
+ IPAERR("tag process timeout client:%d err:%d\n",
+ clnt_hdl, res);
+ ipa_assert();
+ }
}
}
@@ -1257,10 +1267,12 @@
goto disable_clk_and_exit;
}
- /* Suspend the DL/DPL EP */
- memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
- ep_cfg_ctrl.ipa_ep_suspend = true;
- ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+ /* Suspend the DL/DPL EP */
+ memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+ ep_cfg_ctrl.ipa_ep_suspend = true;
+ ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+ }
/*
* Check if DL/DPL channel is empty again, data could enter the channel
@@ -1275,6 +1287,14 @@
goto unsuspend_dl_and_exit;
}
+ /* Stop DL channel */
+ result = ipa3_stop_gsi_channel(dl_clnt_hdl);
+ if (result) {
+ IPAERR("Error stopping DL/DPL channel: %d\n", result);
+ result = -EFAULT;
+ goto unsuspend_dl_and_exit;
+ }
+
/* STOP UL channel */
if (!is_dpl) {
source_pipe_bitmask = 1 << ipa3_get_ep_mapping(ul_ep->client);
@@ -1283,7 +1303,7 @@
if (result) {
IPAERR("Error stopping UL channel: result = %d\n",
result);
- goto unsuspend_dl_and_exit;
+ goto start_dl_and_exit;
}
}
@@ -1292,11 +1312,15 @@
IPADBG("exit\n");
return 0;
+start_dl_and_exit:
+ gsi_start_channel(dl_ep->gsi_chan_hdl);
unsuspend_dl_and_exit:
- /* Unsuspend the DL EP */
- memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
- ep_cfg_ctrl.ipa_ep_suspend = false;
- ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+ /* Unsuspend the DL EP */
+ memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+ ep_cfg_ctrl.ipa_ep_suspend = false;
+ ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+ }
disable_clk_and_exit:
IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(dl_clnt_hdl));
return result;
@@ -1340,7 +1364,8 @@
int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl)
{
- struct ipa3_ep_context *ul_ep, *dl_ep;
+ struct ipa3_ep_context *ul_ep = NULL;
+ struct ipa3_ep_context *dl_ep = NULL;
enum gsi_status gsi_res;
struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
@@ -1360,10 +1385,17 @@
ul_ep = &ipa3_ctx->ep[ul_clnt_hdl];
IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(dl_clnt_hdl));
- /* Unsuspend the DL/DPL EP */
- memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
- ep_cfg_ctrl.ipa_ep_suspend = false;
- ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+ /* Unsuspend the DL/DPL EP */
+ memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+ ep_cfg_ctrl.ipa_ep_suspend = false;
+ ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+ }
+
+ /* Start DL channel */
+ gsi_res = gsi_start_channel(dl_ep->gsi_chan_hdl);
+ if (gsi_res != GSI_STATUS_SUCCESS)
+ IPAERR("Error starting DL channel: %d\n", gsi_res);
/* Start UL channel */
if (!is_dpl) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 04d807f..915f2b8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -267,7 +267,6 @@
int i = 0;
int j;
int result;
- int fail_dma_wrap = 0;
u32 mem_flag = GFP_ATOMIC;
const struct ipa_gsi_ep_config *gsi_ep_cfg;
@@ -298,7 +297,6 @@
spin_lock_bh(&sys->spinlock);
for (i = 0; i < num_desc; i++) {
- fail_dma_wrap = 0;
tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache,
mem_flag);
if (!tx_pkt) {
@@ -319,7 +317,7 @@
if (ipa_populate_tag_field(&desc[i], tx_pkt,
&tag_pyld_ret)) {
IPAERR("Failed to populate tag field\n");
- goto failure;
+ goto failure_dma_map;
}
}
@@ -335,11 +333,6 @@
tx_pkt->mem.base,
tx_pkt->mem.size,
DMA_TO_DEVICE);
- if (!tx_pkt->mem.phys_base) {
- IPAERR("failed to do dma map.\n");
- fail_dma_wrap = 1;
- goto failure;
- }
} else {
tx_pkt->mem.phys_base =
desc[i].dma_address;
@@ -355,17 +348,17 @@
desc[i].frag,
0, tx_pkt->mem.size,
DMA_TO_DEVICE);
- if (!tx_pkt->mem.phys_base) {
- IPAERR("dma map failed\n");
- fail_dma_wrap = 1;
- goto failure;
- }
} else {
tx_pkt->mem.phys_base =
desc[i].dma_address;
tx_pkt->no_unmap_dma = true;
}
}
+ if (dma_mapping_error(ipa3_ctx->pdev, tx_pkt->mem.phys_base)) {
+ IPAERR("failed to do dma map.\n");
+ goto failure_dma_map;
+ }
+
tx_pkt->sys = sys;
tx_pkt->callback = desc[i].callback;
tx_pkt->user1 = desc[i].user1;
@@ -426,28 +419,31 @@
return 0;
+failure_dma_map:
+ kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
+
failure:
ipahal_destroy_imm_cmd(tag_pyld_ret);
tx_pkt = tx_pkt_first;
for (j = 0; j < i; j++) {
next_pkt = list_next_entry(tx_pkt, link);
list_del(&tx_pkt->link);
- if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
- dma_unmap_single(ipa3_ctx->pdev, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
- } else {
- dma_unmap_page(ipa3_ctx->pdev, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
+
+ if (!tx_pkt->no_unmap_dma) {
+ if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
+ dma_unmap_single(ipa3_ctx->pdev,
+ tx_pkt->mem.phys_base,
+ tx_pkt->mem.size, DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(ipa3_ctx->pdev,
+ tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ }
}
kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
tx_pkt = next_pkt;
}
- if (j < num_desc)
- /* last desc failed */
- if (fail_dma_wrap)
- kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
kfree(gsi_xfer_elem_array);
@@ -1444,8 +1440,7 @@
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
sys->rx_buff_sz,
DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
pr_err_ratelimited("%s dma map fail %p for %p sys=%p\n",
__func__, (void *)rx_pkt->data.dma_addr,
ptr, sys);
@@ -1605,8 +1600,7 @@
ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
@@ -1676,8 +1670,7 @@
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
sys->rx_buff_sz,
DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
@@ -1764,8 +1757,8 @@
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev,
ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev,
+ rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
@@ -1780,8 +1773,8 @@
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev,
ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev,
+ rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 410b96a..593d4fc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -490,6 +490,10 @@
entry->hdr,
entry->hdr_len,
DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, entry->phys_base)) {
+ IPAERR("dma_map_single failure for entry\n");
+ goto fail_dma_mapping;
+ }
} else {
entry->is_hdr_proc_ctx = false;
if (list_empty(&htbl->head_free_offset_list[bin])) {
@@ -565,6 +569,9 @@
list_del(&entry->link);
dma_unmap_single(ipa3_ctx->pdev, entry->phys_base,
entry->hdr_len, DMA_TO_DEVICE);
+fail_dma_mapping:
+ entry->is_hdr_proc_ctx = false;
+
bad_hdr_len:
entry->cookie = 0;
kmem_cache_free(ipa3_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 86442b1..9a406d6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1970,8 +1970,6 @@
int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipahal_reg_hash_tuple *tuple);
void ipa3_set_resorce_groups_min_max_limits(void);
void ipa3_suspend_apps_pipes(bool suspend);
-void ipa3_flow_control(enum ipa_client_type ipa_client, bool enable,
- uint32_t qmap_id);
int ipa3_flt_read_tbl_from_hw(u32 pipe_idx,
enum ipa_ip_type ip_type,
bool hashable,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 799246b..60dc04f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1600,13 +1600,15 @@
memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
if (IPA_CLIENT_IS_CONS(ep->client)) {
- ep_cfg_ctrl.ipa_ep_suspend = true;
- result = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
- if (result)
- IPAERR("client (ep: %d) failed to suspend result=%d\n",
- clnt_hdl, result);
- else
- IPADBG("client (ep: %d) suspended\n", clnt_hdl);
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+ ep_cfg_ctrl.ipa_ep_suspend = true;
+ result = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+ if (result)
+ IPAERR("(ep: %d) failed to suspend result=%d\n",
+ clnt_hdl, result);
+ else
+ IPADBG("(ep: %d) suspended\n", clnt_hdl);
+ }
} else {
ep_cfg_ctrl.ipa_ep_delay = true;
result = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index ab26893..079481d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -1631,6 +1631,16 @@
ep = &ipa3_ctx->ep[ipa_ep_idx];
+ /*
+ * starting IPA 4.0 pipe no longer can be suspended. Instead,
+ * the corresponding GSI channel should be stopped. Usually client
+ * driver will take care of stopping the channel. For client drivers
+ * that are not stopping the channel, IPA RM will do that based on
+ * ipa3_should_pipe_channel_be_stopped().
+ */
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+ return false;
+
if (ep->keep_ipa_awake)
return false;
@@ -1651,6 +1661,41 @@
}
/**
+ * ipa3_should_pipe_channel_be_stopped() - returns true when the client's
+ * channel should be stopped during a power save scenario. False otherwise.
+ * Most client already stops the GSI channel on suspend, and are not included
+ * in the list below.
+ *
+ * @client: [IN] IPA client
+ */
+static bool ipa3_should_pipe_channel_be_stopped(enum ipa_client_type client)
+{
+ struct ipa3_ep_context *ep;
+ int ipa_ep_idx;
+
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
+ return false;
+
+ ipa_ep_idx = ipa3_get_ep_mapping(client);
+ if (ipa_ep_idx == -1) {
+ IPAERR("Invalid client.\n");
+ WARN_ON(1);
+ return false;
+ }
+
+ ep = &ipa3_ctx->ep[ipa_ep_idx];
+
+ if (ep->keep_ipa_awake)
+ return false;
+
+ if (client == IPA_CLIENT_ODU_EMB_CONS ||
+ client == IPA_CLIENT_ODU_TETH_CONS)
+ return true;
+
+ return false;
+}
+
+/**
* ipa3_suspend_resource_sync() - suspend client endpoints related to the IPA_RM
* resource and decrement active clients counter, which may result in clock
* gating of IPA clocks.
@@ -1695,6 +1740,19 @@
pipe_suspended = true;
}
}
+
+ if (ipa3_ctx->ep[ipa_ep_idx].client == client &&
+ ipa3_should_pipe_channel_be_stopped(client)) {
+ if (ipa3_ctx->ep[ipa_ep_idx].valid) {
+ /* Stop GSI channel */
+ res = ipa3_stop_gsi_channel(ipa_ep_idx);
+ if (res) {
+ IPAERR("failed stop gsi ch %lu\n",
+ ipa3_ctx->ep[ipa_ep_idx].gsi_chan_hdl);
+ return res;
+ }
+ }
+ }
}
/* Sleep ~1 msec */
if (pipe_suspended)
@@ -1761,6 +1819,12 @@
ipa3_cfg_ep_ctrl(ipa_ep_idx, &suspend);
}
}
+
+ if (ipa3_ctx->ep[ipa_ep_idx].client == client &&
+ ipa3_should_pipe_channel_be_stopped(client)) {
+ res = -EPERM;
+ goto bail;
+ }
}
if (res == 0) {
@@ -1824,6 +1888,19 @@
ipa3_cfg_ep_ctrl(ipa_ep_idx, &suspend);
}
}
+
+ if (ipa3_ctx->ep[ipa_ep_idx].client == client &&
+ ipa3_should_pipe_channel_be_stopped(client)) {
+ if (ipa3_ctx->ep[ipa_ep_idx].valid) {
+ res = gsi_start_channel(
+ ipa3_ctx->ep[ipa_ep_idx].gsi_chan_hdl);
+ if (res) {
+ IPAERR("failed to start gsi ch %lu\n",
+ ipa3_ctx->ep[ipa_ep_idx].gsi_chan_hdl);
+ return res;
+ }
+ }
+ }
}
return res;
@@ -2714,6 +2791,12 @@
return -EINVAL;
}
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0 && ep_ctrl->ipa_ep_suspend) {
+ IPAERR("pipe suspend is not supported\n");
+ WARN_ON(1);
+ return -EPERM;
+ }
+
IPADBG("pipe=%d ep_suspend=%d, ep_delay=%d\n",
clnt_hdl,
ep_ctrl->ipa_ep_suspend,
@@ -4674,6 +4757,7 @@
struct ipa_ep_cfg_ctrl cfg;
int ipa_ep_idx;
struct ipa3_ep_context *ep;
+ int res;
memset(&cfg, 0, sizeof(cfg));
cfg.ipa_ep_suspend = suspend;
@@ -4688,7 +4772,23 @@
if (ep->valid) {
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
ipa_ep_idx);
- ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+ if (suspend) {
+ res = ipa3_stop_gsi_channel(ipa_ep_idx);
+ if (res) {
+ IPAERR("failed to stop LAN channel\n");
+ ipa_assert();
+ }
+ } else {
+ res = gsi_start_channel(ep->gsi_chan_hdl);
+ if (res) {
+ IPAERR("failed to start LAN channel\n");
+ ipa_assert();
+ }
+ }
+ } else {
+ ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+ }
if (suspend)
ipa3_gsi_poll_after_suspend(ep);
else if (!atomic_read(&ep->sys->curr_polling_state))
@@ -4706,7 +4806,23 @@
if (ep->valid) {
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
ipa_ep_idx);
- ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+ if (suspend) {
+ res = ipa3_stop_gsi_channel(ipa_ep_idx);
+ if (res) {
+ IPAERR("failed to stop WAN channel\n");
+ ipa_assert();
+ }
+ } else {
+ res = gsi_start_channel(ep->gsi_chan_hdl);
+ if (res) {
+ IPAERR("failed to start WAN channel\n");
+ ipa_assert();
+ }
+ }
+ } else {
+ ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+ }
if (suspend)
ipa3_gsi_poll_after_suspend(ep);
else if (!atomic_read(&ep->sys->curr_polling_state))
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 1a119b9..3019e4d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -688,6 +688,19 @@
IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT);
}
+static void ipareg_construct_endp_init_ctrl_n_v4_0(enum ipahal_reg_name reg,
+ const void *fields, u32 *val)
+{
+ struct ipa_ep_cfg_ctrl *ep_ctrl =
+ (struct ipa_ep_cfg_ctrl *)fields;
+
+ WARN_ON(ep_ctrl->ipa_ep_suspend);
+
+ IPA_SETFIELD_IN_REG(*val, ep_ctrl->ipa_ep_delay,
+ IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT,
+ IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK);
+}
+
static void ipareg_construct_endp_init_ctrl_scnd_n(enum ipahal_reg_name reg,
const void *fields, u32 *val)
{
@@ -1444,6 +1457,9 @@
ipareg_parse_hps_queue_weights, 0x000005a4, 0},
/* IPAv4.0 */
+ [IPA_HW_v4_0][IPA_ENDP_INIT_CTRL_n] = {
+ ipareg_construct_endp_init_ctrl_n_v4_0, ipareg_parse_dummy,
+ 0x00000800, 0x70 },
[IPA_HW_v4_0][IPA_TX_CFG] = {
ipareg_construct_tx_cfg_v4_0, ipareg_parse_tx_cfg_v4_0,
0x000001FC, 0},
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index b198348..f408f23 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1507,25 +1507,13 @@
break;
/* Flow enable */
case RMNET_IOCTL_FLOW_ENABLE:
- IPAWANDBG("Received flow enable\n");
- if (copy_from_user(&ioctl_data, ifr->ifr_ifru.ifru_data,
- sizeof(struct rmnet_ioctl_data_s))) {
- rc = -EFAULT;
- break;
- }
- ipa3_flow_control(IPA_CLIENT_USB_PROD, true,
- ioctl_data.u.tcm_handle);
+ IPAWANERR("RMNET_IOCTL_FLOW_ENABLE not supported\n");
+ rc = -EFAULT;
break;
/* Flow disable */
case RMNET_IOCTL_FLOW_DISABLE:
- IPAWANDBG("Received flow disable\n");
- if (copy_from_user(&ioctl_data, ifr->ifr_ifru.ifru_data,
- sizeof(struct rmnet_ioctl_data_s))) {
- rc = -EFAULT;
- break;
- }
- ipa3_flow_control(IPA_CLIENT_USB_PROD, false,
- ioctl_data.u.tcm_handle);
+ IPAWANERR("RMNET_IOCTL_FLOW_DISABLE not supported\n");
+ rc = -EFAULT;
break;
/* Set flow handle */
case RMNET_IOCTL_FLOW_SET_HNDL:
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 5ca0fe5..306510f 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -34,17 +34,21 @@
#define RPMH_MAX_REQ_IN_BATCH 10
#define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name) \
- struct rpmh_msg name = { \
- .msg = { 0 }, \
- .msg.state = s, \
- .msg.is_complete = true, \
- .msg.payload = name.cmd, \
- .msg.num_payload = 0, \
- .cmd = { { 0 } }, \
- .waitq = q, \
- .wait_count = c, \
- .rc = rc, \
- .bit = -1, \
+ struct rpmh_msg name = { \
+ .msg = { \
+ .state = s, \
+ .payload = name.cmd, \
+ .num_payload = 0, \
+ .is_read = false, \
+ .is_control = false, \
+ .is_complete = true, \
+ .invalidate = false, \
+ }, \
+ .cmd = { { 0 } }, \
+ .completion = q, \
+ .wait_count = c, \
+ .rc = rc, \
+ .bit = -1, \
}
struct rpmh_req {
@@ -57,7 +61,7 @@
struct rpmh_msg {
struct tcs_mbox_msg msg;
struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
- wait_queue_head_t *waitq;
+ struct completion *completion;
atomic_t *wait_count;
struct rpmh_client *rc;
int bit;
@@ -106,21 +110,31 @@
return msg;
}
+static void free_msg_to_pool(struct rpmh_msg *rpm_msg)
+{
+ struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
+ unsigned long flags;
+
+ /* If we allocated the pool, set it as available */
+ if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
+ spin_lock_irqsave(&rpm->lock, flags);
+ bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
+ spin_unlock_irqrestore(&rpm->lock, flags);
+ }
+}
+
static void rpmh_rx_cb(struct mbox_client *cl, void *msg)
{
struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);
atomic_dec(rpm_msg->wait_count);
- wake_up(rpm_msg->waitq);
}
static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
{
struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);
- struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
atomic_t *wc = rpm_msg->wait_count;
- wait_queue_head_t *waitq = rpm_msg->waitq;
- unsigned long flags;
+ struct completion *compl = rpm_msg->completion;
rpm_msg->err = r;
@@ -144,18 +158,12 @@
* into an issue that the stack allocated parent object may be
* invalid before we can check the ->bit value.
*/
-
- /* If we allocated the pool, set it as available */
- if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
- spin_lock_irqsave(&rpm->lock, flags);
- bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
- spin_unlock_irqrestore(&rpm->lock, flags);
- }
+ free_msg_to_pool(rpm_msg);
/* Signal the blocking thread we are done */
if (wc && atomic_dec_and_test(wc))
- if (waitq)
- wake_up(waitq);
+ if (compl)
+ complete(compl);
}
static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr)
@@ -312,9 +320,9 @@
int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state,
u32 addr, u32 data)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+ DECLARE_COMPLETION_ONSTACK(compl);
atomic_t wait_count = ATOMIC_INIT(1);
- DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg);
+ DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg);
int ret;
if (IS_ERR_OR_NULL(rc))
@@ -333,7 +341,7 @@
if (ret < 0)
return ret;
- wait_event(waitq, atomic_read(&wait_count) == 0);
+ wait_for_completion(&compl);
return rpm_msg.err;
}
@@ -408,9 +416,9 @@
int rpmh_write(struct rpmh_client *rc, enum rpmh_state state,
struct tcs_cmd *cmd, int n)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+ DECLARE_COMPLETION_ONSTACK(compl);
atomic_t wait_count = ATOMIC_INIT(1);
- DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg);
+ DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg);
int ret;
if (IS_ERR_OR_NULL(rc) || !cmd || n <= 0 || n > MAX_RPMH_PAYLOAD)
@@ -428,7 +436,7 @@
if (ret)
return ret;
- wait_event(waitq, atomic_read(&wait_count) == 0);
+ wait_for_completion(&compl);
return rpm_msg.err;
}
@@ -454,7 +462,7 @@
struct tcs_cmd *cmd, int *n)
{
struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH];
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+ DECLARE_COMPLETION_ONSTACK(compl);
atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */
int count = 0;
int ret, i, j, k;
@@ -507,9 +515,8 @@
for (i = 0; i < count; i++) {
rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]);
if (IS_ERR_OR_NULL(rpm_msg[i])) {
- /* Clean up our call by spoofing tx_done */
for (j = 0 ; j < i; j++)
- rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, 0);
+ free_msg_to_pool(rpm_msg[j]);
return PTR_ERR(rpm_msg[i]);
}
cmd += n[i];
@@ -520,7 +527,7 @@
might_sleep();
atomic_set(&wait_count, count);
for (i = 0; i < count; i++) {
- rpm_msg[i]->waitq = &waitq;
+ rpm_msg[i]->completion = &compl;
rpm_msg[i]->wait_count = &wait_count;
/* Bypass caching and write to mailbox directly */
ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg);
@@ -530,15 +537,17 @@
break;
}
}
- wait_event(waitq, atomic_read(&wait_count) == (count - i));
+ /* For those unsent requests, spoof tx_done */
+ for (j = i; j < count; j++)
+ rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, ret);
+ wait_for_completion(&compl);
} else {
/* Send Sleep requests to the controller, expect no response */
for (i = 0; i < count; i++) {
- rpm_msg[i]->waitq = NULL;
+ rpm_msg[i]->completion = NULL;
ret = mbox_send_controller_data(rc->chan,
&rpm_msg[i]->msg);
- /* Clean up our call by spoofing tx_done */
- rpmh_tx_done(&rc->client, &rpm_msg[i]->msg, ret);
+ free_msg_to_pool(rpm_msg[i]);
}
return 0;
}
@@ -660,10 +669,10 @@
int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp)
{
int ret;
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+ DECLARE_COMPLETION_ONSTACK(compl);
atomic_t wait_count = ATOMIC_INIT(2); /* wait for rx_cb and tx_done */
DEFINE_RPMH_MSG_ONSTACK(rc, RPMH_ACTIVE_ONLY_STATE,
- &waitq, &wait_count, rpm_msg);
+ &compl, &wait_count, rpm_msg);
if (IS_ERR_OR_NULL(rc) || !resp)
return -EINVAL;
@@ -684,7 +693,7 @@
return ret;
/* Wait until the response is received from RPMH */
- wait_event(waitq, atomic_read(&wait_count) == 0);
+ wait_for_completion(&compl);
/* Read the data back from the tcs_mbox_msg structrure */
*resp = rpm_msg.cmd[0].data;
diff --git a/include/dt-bindings/clock/mdss-10nm-pll-clk.h b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
index c1350ce..75ddcfa 100644
--- a/include/dt-bindings/clock/mdss-10nm-pll-clk.h
+++ b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
@@ -34,4 +34,12 @@
#define PCLK_SRC_MUX_1_CLK 15
#define PCLK_SRC_1_CLK 16
#define PCLK_MUX_1_CLK 17
+
+/* DP PLL clocks */
+#define DP_VCO_CLK 0
+#define DP_LINK_CLK_DIVSEL_TEN 1
+#define DP_VCO_DIVIDED_TWO_CLK_SRC 2
+#define DP_VCO_DIVIDED_FOUR_CLK_SRC 3
+#define DP_VCO_DIVIDED_SIX_CLK_SRC 4
+#define DP_VCO_DIVIDED_CLK_SRC_MUX 5
#endif
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 0583431..8053c8a 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -121,5 +121,6 @@
int msm_vidc_unsubscribe_event(void *instance,
const struct v4l2_event_subscription *sub);
int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
+int msm_vidc_g_crop(void *instance, struct v4l2_crop *a);
int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
#endif
diff --git a/include/uapi/media/cam_cpas.h b/include/uapi/media/cam_cpas.h
index 300bd87..c5cbac8 100644
--- a/include/uapi/media/cam_cpas.h
+++ b/include/uapi/media/cam_cpas.h
@@ -11,13 +11,15 @@
*
* @camera_family : Camera family type
* @reserved : Reserved field for alignment
- * @camera_version : Camera version
+ * @camera_version : Camera platform version
+ * @cpas_version : Camera CPAS version within camera platform
*
*/
struct cam_cpas_query_cap {
uint32_t camera_family;
uint32_t reserved;
struct cam_hw_version camera_version;
+ struct cam_hw_version cpas_version;
};
#endif /* __UAPI_CAM_CPAS_H__ */
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index c0a32f3..3c026e64 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -795,11 +795,13 @@
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
+ /* Add 1msec delay for VOUT to settle */
+ usleep_range(1000, 1100);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
- regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
+ regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
return 0;
}
@@ -8274,6 +8276,9 @@
WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
ret = __tavil_cdc_mclk_enable_locked(tavil, enable);
+ if (enable)
+ wcd_resmgr_set_sido_input_src(tavil->resmgr,
+ SIDO_SOURCE_RCO_BG);
WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
return ret;
@@ -8411,6 +8416,8 @@
__func__, ret);
goto done;
}
+ wcd_resmgr_set_sido_input_src(tavil->resmgr,
+ SIDO_SOURCE_RCO_BG);
ret = wcd_resmgr_enable_clk_block(tavil->resmgr,
WCD_CLK_RCO);
ret |= tavil_cdc_req_mclk_enable(tavil, false);
@@ -9814,18 +9821,23 @@
{
int val, rc;
- __tavil_cdc_mclk_enable(tavil, true);
+ WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
+ __tavil_cdc_mclk_enable_locked(tavil, true);
regmap_update_bits(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10);
regmap_update_bits(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
-
/*
* 5ms sleep required after enabling efuse control
* before checking the status.
*/
usleep_range(5000, 5500);
+ wcd_resmgr_set_sido_input_src(tavil->resmgr,
+ SIDO_SOURCE_RCO_BG);
+
+ WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
+
rc = regmap_read(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
if (rc || (!(val & 0x01)))
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index 8780888..825aaee 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -25,8 +25,7 @@
#define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41
#define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42
-static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
- int sido_src);
+
static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type)
{
if (clk_type == WCD_CLK_OFF)
@@ -267,8 +266,6 @@
0x01, 0x01);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x00);
- wcd_resmgr_set_sido_input_src(resmgr,
- SIDO_SOURCE_RCO_BG);
} else {
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
@@ -515,7 +512,7 @@
return ret;
}
-static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
int sido_src)
{
if (!resmgr)
@@ -553,6 +550,7 @@
pr_debug("%s: sido input src to external\n", __func__);
}
}
+EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src);
/*
* wcd_resmgr_set_sido_input_src_locked:
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.h b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
index f605a24..e831ba6 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -87,4 +87,7 @@
void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr);
void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr,
int sido_src);
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+ int sido_src);
+
#endif