aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPawan Chilka <pchilka@codeaurora.org>2019-09-02 14:05:56 +0530
committerPawan Chilka <pchilka@codeaurora.org>2019-09-02 14:07:24 +0530
commit824a56366b5fd803dd4e4c230a6e788d34919d1b (patch)
tree5886f070e4eae166b945682370749f2bae60b9ad
parent3ad2c95a85f688455db07d1a4b248082d329a52a (diff)
parenta7395d9607aefeb12aba5bb66b3c71a24a2dc6ff (diff)
Merge commit 'a7395d9607aefeb12aba5bb66b3c71a24a2dc6ff' into HEADLA.UM.8.1.r1-08800-sm8150.0LA.UM.8.1.r1-08700-sm8150.0LA.UM.8.1.r1-08600-sm8150.0
Change-Id: I5de0582240dd8a5e2b05b0ac20851d84fb9e255b Signed-off-by: Pawan Chilka <pchilka@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/pci/msm_pcie.txt5
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt14
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-atp.dtsi64
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-camera.dtsi42
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-idp.dtsi29
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi92
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-qrd.dtsi116
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-sde-display.dtsi1
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-sde.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/atoll-usb.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/atoll.dtsi34
-rw-r--r--arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi6
-rw-r--r--arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi1
-rw-r--r--arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi1
-rw-r--r--arch/arm64/boot/dts/qcom/sa8155.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi123
-rw-r--r--arch/arm64/boot/dts/qcom/sdxprairie.dtsi6
-rw-r--r--arch/arm64/configs/vendor/trinket_defconfig1
-rw-r--r--drivers/char/diag/diag_dci.c5
-rw-r--r--drivers/gpu/drm/msm/dp/dp_debug.c18
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_drm.c6
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c26
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_trace.h45
-rw-r--r--drivers/gpu/drm/msm/sde_power_handle.c7
-rw-r--r--drivers/gpu/drm/msm/sde_rsc.c2
-rw-r--r--drivers/gpu/msm/kgsl_gmu.c7
-rw-r--r--drivers/iommu/arm-smmu-debug.c57
-rw-r--r--drivers/iommu/arm-smmu-debug.h47
-rw-r--r--drivers/iommu/arm-smmu.c288
-rw-r--r--drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h12
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c207
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h11
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c374
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h20
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h6
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h6
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h6
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c216
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h14
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h13
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h5
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h11
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c3
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c26
-rw-r--r--drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c20
-rw-r--r--drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c4
-rw-r--r--drivers/net/ethernet/aquantia/Kconfig16
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig21
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/Makefile2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h45
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c506
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h40
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c93
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.h52
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_hwmon.c136
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c283
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.c41
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.h31
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.c110
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.h13
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c107
-rw-r--r--drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt10
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c57
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c8
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pm.c4
-rwxr-xr-x[-rw-r--r--]drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c9
-rw-r--r--drivers/power/supply/qcom/qg-battery-profile.c18
-rw-r--r--drivers/power/supply/qcom/qg-core.h7
-rw-r--r--drivers/power/supply/qcom/qg-profile-lib.c34
-rw-r--r--drivers/power/supply/qcom/qg-profile-lib.h11
-rw-r--r--drivers/power/supply/qcom/qg-reg.h3
-rw-r--r--drivers/power/supply/qcom/qg-sdam.c24
-rw-r--r--drivers/power/supply/qcom/qg-sdam.h6
-rw-r--r--drivers/power/supply/qcom/qg-soc.c93
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen4.c2
-rw-r--r--drivers/power/supply/qcom/qpnp-qg.c62
-rw-r--r--drivers/usb/dwc3/gadget.c6
-rw-r--r--drivers/usb/gadget/function/f_fs.c1
-rw-r--r--include/linux/ipa_eth.h2
-rw-r--r--include/uapi/linux/qg-profile.h2
-rw-r--r--include/uapi/media/cam_isp.h57
89 files changed, 3429 insertions, 508 deletions
diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt
index 8c12600f65a9..52f9e5ade3ff 100644
--- a/Documentation/devicetree/bindings/pci/msm_pcie.txt
+++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt
@@ -74,6 +74,10 @@ Optional Properties:
is changed from L0s to L0.
- qcom,phy-power-down-offset: Offset from PCIe PHY base to control the power state
of the PHY.
+ - qcom,core-preset: Value for PCIe core preset. Determines how aggressive the
+ PCIe PHY equalization is. The following are recommended settings:
+ short channels: 0x55555555 (default)
+ long channels: 0x77777777
- qcom,pcie-phy-ver: version of PCIe PHY.
- qcom,phy-sequence: The initialization sequence to bring up the PCIe PHY.
Should be specified in groups (offset, value, delay).
@@ -288,6 +292,7 @@ Example:
qcom,phy-status-offset = <0x800>;
qcom,phy-status-status = <6>;
qcom,phy-power-down-offset = <0x840>;
+ qcom,core-preset = <0x55555555>; /* short channels */
qcom,cpl-timeout = <0x2>;
iommus = <&anoc0_smmu>;
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
index 3daca154bb52..cccb14dd2f66 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -404,6 +404,20 @@ First Level Node - QGAUGE device
'qcom,qg-fast-chg-config' is enabled. The
default value if not specified is 1.
+- qcom,fvss-enable
+ Usage: optional
+ Value type: bool
+ Definition: Enable Filtered Voltage based SOC scaling.
+ This logic enables SOC scaling to report
+ 0 at the cutoff voltage.
+
+- qcom,fvss-vbatt-mv
+ Usage: optional
+ Value type: <u32>
+ Definition: Battery voltage threshold at which FVSS is
+ enabled. Applicable only if 'qcom,fvss-enable'
+ is set.
+
==========================================================
Second Level Nodes - Peripherals managed by QGAUGE driver
==========================================================
diff --git a/arch/arm64/boot/dts/qcom/atoll-atp.dtsi b/arch/arm64/boot/dts/qcom/atoll-atp.dtsi
index a2bfa96448c0..5190bed198e0 100644
--- a/arch/arm64/boot/dts/qcom/atoll-atp.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-atp.dtsi
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/iio/qcom,spmi-vadc.h>
&soc {
@@ -65,6 +66,69 @@
extcon = <&pm6150_pdphy>;
};
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm6150_l4>; /* 0.9v */
+ vdda-pll-supply = <&pm6150l_l3>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm6150_l19>;
+ vcc-voltage-level = <2960000 2960000>;
+ vcc-max-microamp = <600000>;
+ vccq2-supply = <&pm6150_l12>;
+ vccq2-voltage-level = <1750000 1950000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm6150l_l3>; /* PX10 */
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm6150_l19>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
+ qcom,vdd-current-level = <0 570000>;
+
+ vdd-io-supply = <&pm6150_l12>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <0 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm6150l_l9>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
+ qcom,vdd-current-level = <0 800000>;
+
+ vdd-io-supply = <&pm6150l_l6>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <0 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+
+ cd-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>;
+
+ status = "ok";
+};
+
&spmi_bus {
qcom,pm6150l@4 {
pm6150l_adc_tm_iio: adc_tm@3400 {
diff --git a/arch/arm64/boot/dts/qcom/atoll-camera.dtsi b/arch/arm64/boot/dts/qcom/atoll-camera.dtsi
index 020032d19482..66f7212bd595 100644
--- a/arch/arm64/boot/dts/qcom/atoll-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-camera.dtsi
@@ -1243,4 +1243,46 @@
clock-rates = <0>;
status = "ok";
};
+
+ qcom,cam-lrme {
+ compatible = "qcom,cam-lrme";
+ arch-compat = "lrme";
+ status = "ok";
+ };
+
+ cam_lrme: qcom,lrme@ac6b000 {
+ cell-index = <0>;
+ compatible = "qcom,lrme";
+ reg-names = "lrme";
+ reg = <0xac6b000 0x1000>;
+ reg-cam-base = <0x6b000>;
+ interrupt-names = "lrme";
+ interrupts = <0 476 0>;
+ regulator-names = "camss";
+ camss-supply = <&titan_top_gdsc>;
+ clock-names = "camera_ahb",
+ "camera_axi",
+ "soc_ahb_clk",
+ "cpas_ahb_clk",
+ "camnoc_axi_clk",
+ "lrme_clk_src",
+ "lrme_clk";
+ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+ <&clock_gcc GCC_CAMERA_HF_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&clock_camcc CAM_CC_LRME_CLK_SRC>,
+ <&clock_camcc CAM_CC_LRME_CLK>;
+ clock-rates = <0 0 0 0 0 200000000 200000000>,
+ <0 0 0 0 0 216000000 216000000>,
+ <0 0 0 0 0 300000000 300000000>,
+ <0 0 0 0 0 404000000 404000000>,
+ <0 0 0 0 0 404000000 404000000>,
+ <0 0 0 0 0 404000000 404000000>;
+ clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal",
+ "nominal_l1", "turbo";
+ src-clock-name = "lrme_clk_src";
+ status = "ok";
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/atoll-idp.dtsi b/arch/arm64/boot/dts/qcom/atoll-idp.dtsi
index 56ae442900f0..649190984014 100644
--- a/arch/arm64/boot/dts/qcom/atoll-idp.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-idp.dtsi
@@ -89,7 +89,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm6150_l19>;
- vcc-voltage-level = <2950000 2960000>;
+ vcc-voltage-level = <2960000 2960000>;
vcc-max-microamp = <600000>;
vccq2-supply = <&pm6150_l12>;
vccq2-voltage-level = <1750000 1950000>;
@@ -103,7 +103,7 @@
&sdhc_1 {
vdd-supply = <&pm6150_l19>;
- qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
qcom,vdd-current-level = <0 570000>;
vdd-io-supply = <&pm6150_l12>;
@@ -121,7 +121,7 @@
&sdhc_2 {
vdd-supply = <&pm6150l_l9>;
- qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
qcom,vdd-current-level = <0 800000>;
vdd-io-supply = <&pm6150l_l6>;
@@ -295,3 +295,26 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&pm6150l_gpios 3 0>;
};
+
+&qupv3_se0_i2c {
+ status = "ok";
+ qcom,clk-freq-out = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nq@28 {
+ compatible = "qcom,nq-nci";
+ reg = <0x28>;
+ qcom,nq-irq = <&tlmm 37 0x00>;
+ qcom,nq-ven = <&tlmm 12 0x00>;
+ qcom,nq-firm = <&tlmm 36 0x00>;
+ qcom,nq-clkreq = <&tlmm 31 0x00>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <37 0>;
+ interrupt-names = "nfc_irq";
+ pinctrl-names = "nfc_active", "nfc_suspend";
+ pinctrl-0 = <&nfc_int_active &nfc_enable_active
+ &nfc_clk_req_active>;
+ pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend
+ &nfc_clk_req_suspend>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi
index 46589b2972c8..99472bb0be26 100644
--- a/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi
@@ -374,6 +374,98 @@
};
};
+ nfc {
+ nfc_int_active: nfc_int_active {
+ /* active state */
+ mux {
+ /* GPIO 37 NFC Read Interrupt */
+ pins = "gpio37";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio37";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up;
+ };
+ };
+
+ nfc_int_suspend: nfc_int_suspend {
+ /* sleep state */
+ mux {
+ /* GPIO 37 NFC Read Interrupt */
+ pins = "gpio37";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio37";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up;
+ };
+ };
+
+ nfc_enable_active: nfc_enable_active {
+ /* active state */
+ mux {
+ /* 12: Enable 36: Firmware */
+ pins = "gpio12", "gpio36";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12", "gpio36";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up;
+ };
+ };
+
+ nfc_enable_suspend: nfc_enable_suspend {
+ /* sleep state */
+ mux {
+ /* 12: Enable 36: Firmware */
+ pins = "gpio12", "gpio36";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12", "gpio36";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable;
+ };
+ };
+
+ nfc_clk_req_active: nfc_clk_req_active {
+ /* active state */
+ mux {
+ /* GPIO 31: NFC CLOCK REQUEST */
+ pins = "gpio31";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up;
+ };
+ };
+
+ nfc_clk_req_suspend: nfc_clk_req_suspend {
+ /* sleep state */
+ mux {
+ /* GPIO 31: NFC CLOCK REQUEST */
+ pins = "gpio31";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable;
+ };
+ };
+ };
+
qupv3_se1_i2c_pins: qupv3_se1_i2c_pins {
qupv3_se1_i2c_active: qupv3_se1_i2c_active {
mux {
diff --git a/arch/arm64/boot/dts/qcom/atoll-qrd.dtsi b/arch/arm64/boot/dts/qcom/atoll-qrd.dtsi
index b582b02da5a7..1f92d08e239a 100644
--- a/arch/arm64/boot/dts/qcom/atoll-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-qrd.dtsi
@@ -14,6 +14,7 @@
#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include <dt-bindings/input/input.h>
+#include "atoll-audio-overlay.dtsi"
#include "atoll-camera-sensor-qrd.dtsi"
@@ -141,7 +142,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm6150_l19>;
- vcc-voltage-level = <2950000 2960000>;
+ vcc-voltage-level = <2960000 2960000>;
vcc-max-microamp = <600000>;
vccq2-supply = <&pm6150_l12>;
vccq2-voltage-level = <1750000 1950000>;
@@ -155,7 +156,7 @@
&sdhc_1 {
vdd-supply = <&pm6150_l19>;
- qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
qcom,vdd-current-level = <0 570000>;
vdd-io-supply = <&pm6150_l12>;
@@ -173,7 +174,7 @@
&sdhc_2 {
vdd-supply = <&pm6150l_l9>;
- qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
qcom,vdd-current-level = <0 800000>;
vdd-io-supply = <&pm6150l_l6>;
@@ -188,3 +189,112 @@
status = "ok";
};
+
+&atoll_snd {
+ qcom,model = "atoll-qrd-snd-card";
+ qcom,audio-routing =
+ "AMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Analog Mic1",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Analog Mic2",
+ "AMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Analog Mic3",
+ "AMIC4", "MIC BIAS1",
+ "MIC BIAS1", "Analog Mic4",
+ "TX DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "TX DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "TX DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "TX DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "TX DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "IN1_HPHL", "HPHL_OUT",
+ "IN2_HPHR", "HPHR_OUT",
+ "IN3_AUX", "AUX_OUT",
+ "TX SWR_ADC0", "ADC1_OUTPUT",
+ "TX SWR_ADC1", "ADC2_OUTPUT",
+ "TX SWR_ADC2", "ADC3_OUTPUT",
+ "TX SWR_ADC3", "ADC4_OUTPUT",
+ "TX SWR_DMIC0", "DMIC1_OUTPUT",
+ "TX SWR_DMIC1", "DMIC2_OUTPUT",
+ "TX SWR_DMIC2", "DMIC3_OUTPUT",
+ "TX SWR_DMIC3", "DMIC4_OUTPUT",
+ "TX SWR_DMIC4", "DMIC5_OUTPUT",
+ "TX SWR_DMIC5", "DMIC6_OUTPUT",
+ "TX SWR_DMIC6", "DMIC7_OUTPUT",
+ "TX SWR_DMIC7", "DMIC8_OUTPUT",
+ "WSA SRC0_INP", "SRC0",
+ "WSA_TX DEC0_INP", "TX DEC0 MUX",
+ "WSA_TX DEC1_INP", "TX DEC1 MUX",
+ "RX_TX DEC0_INP", "TX DEC0 MUX",
+ "RX_TX DEC1_INP", "TX DEC1 MUX",
+ "RX_TX DEC2_INP", "TX DEC2 MUX",
+ "RX_TX DEC3_INP", "TX DEC3 MUX",
+ "SpkrLeft IN", "WSA_SPK1 OUT",
+ "SpkrRight IN", "WSA_SPK2 OUT",
+ "VA MIC BIAS3", "Digital Mic0",
+ "VA MIC BIAS3", "Digital Mic1",
+ "VA MIC BIAS1", "Digital Mic2",
+ "VA MIC BIAS1", "Digital Mic3",
+ "VA MIC BIAS4", "Digital Mic4",
+ "VA MIC BIAS4", "Digital Mic5",
+ "VA DMIC0", "VA MIC BIAS3",
+ "VA DMIC1", "VA MIC BIAS3",
+ "VA DMIC2", "VA MIC BIAS1",
+ "VA DMIC3", "VA MIC BIAS1",
+ "VA DMIC4", "VA MIC BIAS4",
+ "VA DMIC5", "VA MIC BIAS4",
+ "VA SWR_ADC0", "VA_SWR_CLK",
+ "VA SWR_ADC1", "VA_SWR_CLK",
+ "VA SWR_ADC2", "VA_SWR_CLK",
+ "VA SWR_ADC3", "VA_SWR_CLK",
+ "VA SWR_MIC0", "VA_SWR_CLK",
+ "VA SWR_MIC1", "VA_SWR_CLK",
+ "VA SWR_MIC2", "VA_SWR_CLK",
+ "VA SWR_MIC3", "VA_SWR_CLK",
+ "VA SWR_MIC4", "VA_SWR_CLK",
+ "VA SWR_MIC5", "VA_SWR_CLK",
+ "VA SWR_MIC6", "VA_SWR_CLK",
+ "VA SWR_MIC7", "VA_SWR_CLK",
+ "VA SWR_ADC0", "ADC1_OUTPUT",
+ "VA SWR_ADC1", "ADC2_OUTPUT",
+ "VA SWR_ADC2", "ADC3_OUTPUT",
+ "VA SWR_ADC3", "ADC4_OUTPUT",
+ "VA SWR_MIC0", "DMIC1_OUTPUT",
+ "VA SWR_MIC1", "DMIC2_OUTPUT",
+ "VA SWR_MIC2", "DMIC3_OUTPUT",
+ "VA SWR_MIC3", "DMIC4_OUTPUT",
+ "VA SWR_MIC4", "DMIC5_OUTPUT",
+ "VA SWR_MIC5", "DMIC6_OUTPUT",
+ "VA SWR_MIC6", "DMIC7_OUTPUT",
+ "VA SWR_MIC7", "DMIC8_OUTPUT";
+ qcom,wsa-max-devs = <1>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft";
+};
+
+&qupv3_se0_i2c {
+ status = "ok";
+ qcom,clk-freq-out = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nq@28 {
+ compatible = "qcom,nq-nci";
+ reg = <0x28>;
+ qcom,nq-irq = <&tlmm 37 0x00>;
+ qcom,nq-ven = <&tlmm 12 0x00>;
+ qcom,nq-firm = <&tlmm 36 0x00>;
+ qcom,nq-clkreq = <&tlmm 31 0x00>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <37 0>;
+ interrupt-names = "nfc_irq";
+ pinctrl-names = "nfc_active", "nfc_suspend";
+ pinctrl-0 = <&nfc_int_active &nfc_enable_active
+ &nfc_clk_req_active>;
+ pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend
+ &nfc_clk_req_suspend>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/atoll-sde-display.dtsi b/arch/arm64/boot/dts/qcom/atoll-sde-display.dtsi
index ee2bb89b1de9..1acc087214a0 100644
--- a/arch/arm64/boot/dts/qcom/atoll-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-sde-display.dtsi
@@ -147,6 +147,7 @@
qcom,mdss-dsi-panel-phy-timings = [00 20 08 08 24 23 08
08 05 02 04 00];
qcom,display-topology = <1 0 1>;
+ qcom,default-topology-index = <0>;
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/atoll-sde.dtsi b/arch/arm64/boot/dts/qcom/atoll-sde.dtsi
index 8a01f196c5e7..b469e5efe542 100644
--- a/arch/arm64/boot/dts/qcom/atoll-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-sde.dtsi
@@ -136,7 +136,7 @@
qcom,sde-highest-bank-bit = <0x1>;
qcom,sde-ubwc-version = <0x200>;
qcom,sde-ubwc-bw-calc-version = <0x1>;
- qcom,sde-ubwc-static = <0x18>;
+ qcom,sde-ubwc-static = <0x1E>;
qcom,sde-panic-per-pipe;
qcom,sde-smart-panel-align-mode = <0xc>;
qcom,sde-has-cdp;
diff --git a/arch/arm64/boot/dts/qcom/atoll-usb.dtsi b/arch/arm64/boot/dts/qcom/atoll-usb.dtsi
index 1552d109b652..61d831a75090 100644
--- a/arch/arm64/boot/dts/qcom/atoll-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll-usb.dtsi
@@ -133,9 +133,9 @@
};
/* Primary USB port related QUSB2 PHY */
- qusb_phy0: qusb@88e2000 {
+ qusb_phy0: qusb@88e3000 {
compatible = "qcom,qusb2phy-v2";
- reg = <0x088e2000 0x400>,
+ reg = <0x088e3000 0x400>,
<0x00780258 0x4>,
<0x088e7014 0x4>;
reg-names = "qusb_phy_base", "efuse_addr",
diff --git a/arch/arm64/boot/dts/qcom/atoll.dtsi b/arch/arm64/boot/dts/qcom/atoll.dtsi
index f570ca76490d..e47e22d70f77 100644
--- a/arch/arm64/boot/dts/qcom/atoll.dtsi
+++ b/arch/arm64/boot/dts/qcom/atoll.dtsi
@@ -484,7 +484,7 @@
compatible = "android,fstab";
vendor {
compatible = "android,vendor";
- dev = "/dev/block/platform/soc/7c4000.sdhci/by-name/vendor";
+ dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor";
type = "ext4";
mnt_flags = "ro,barrier=1,discard";
fsmgr_flags = "wait,slotselect,avb";
@@ -897,6 +897,12 @@
reg-names = "pshold-base", "tcsr-boot-misc-detect";
};
+ qcom,mpm2-sleep-counter@0xc221000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xc221000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
qcom_seecom: qseecom@82200000 {
compatible = "qcom,qseecom";
reg = <0x82200000 0x2200000>;
@@ -1377,6 +1383,12 @@
cap-based-alloc-and-pwr-collapse;
};
+ qcom,llcc-perfmon {
+ compatible = "qcom,llcc-perfmon";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "qdss_clk";
+ };
+
qcom,llcc-erp {
compatible = "qcom,llcc-erp";
};
@@ -2585,10 +2597,12 @@
};
icnss: qcom,icnss@18800000 {
- status = "disabled";
compatible = "qcom,icnss";
- reg = <0x18800000 0x800000>;
- reg-names = "membase";
+ reg = <0x18800000 0x800000>,
+ <0xa0000000 0x10000000>,
+ <0xb0000000 0x10000>;
+ reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
+ iommus = <&apps_smmu 0xC0 0x1>;
interrupts = <GIC_SPI 414 IRQ_TYPE_LEVEL_HIGH /* CE0 */ >,
<GIC_SPI 415 IRQ_TYPE_LEVEL_HIGH /* CE1 */ >,
<GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH /* CE2 */ >,
@@ -2601,8 +2615,18 @@
<GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH /* CE9 */ >,
<GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH /* CE10 */ >,
<GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH /* CE11 */ >;
- qcom,smmu-s1-bypass;
qcom,wlan-msa-fixed-region = <&wlan_fw_mem>;
+ vdd-cx-mx-supply = <&L9A>;
+ vdd-1.8-xo-supply = <&L1C>;
+ vdd-1.3-rfa-supply = <&L2C>;
+ vdd-3.3-ch0-supply = <&L10C>;
+ qcom,vdd-cx-mx-config = <640000 640000>;
+ qcom,smp2p_map_wlan_1_in {
+ interrupts-extended = <&smp2p_wlan_1_in 0 0>,
+ <&smp2p_wlan_1_in 1 0>;
+ interrupt-names = "qcom,smp2p-force-fatal-error",
+ "qcom,smp2p-early-crash-ind";
+ };
};
qcom,venus@aae0000 {
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi
index bd1f37554f7e..f9cb196a2c2f 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi
@@ -23,6 +23,7 @@
#iommu-cells = <2>;
qcom,dynamic;
qcom,skip-init;
+ qcom,testbus-version = <1>;
qcom,no-dynamic-asid;
qcom,use-3-lvl-tables;
#global-interrupts = <1>;
@@ -55,6 +56,7 @@
<0x59c2200 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x0 0x400>;
+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
};
};
@@ -153,6 +155,7 @@
<0xc782200 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x0 0x400>;
+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
qcom,msm-bus,name = "apps_smmu";
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,active-only;
@@ -178,6 +181,7 @@
<0xc782208 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x400 0x400>;
+ interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc>;
qcom,msm-bus,name = "apps_smmu";
@@ -205,6 +209,7 @@
<0xc782210 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x800 0x400>;
+ interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc>;
qcom,msm-bus,name = "apps_smmu";
@@ -232,6 +237,7 @@
<0xc782218 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0xc00 0x400>;
+ interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_turing_mmu_tbu0_gdsc>;
qcom,msm-bus,name = "apps_smmu";
diff --git a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi
index b8fbb572f023..9c5d1d796a7c 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi
@@ -81,6 +81,7 @@
qcom,phy-status-offset = <0x3c>;
qcom,phy-status-bit = <0>;
qcom,phy-power-down-offset = <0x98>;
+ qcom,core-preset = <0x77777777>;
qcom,boot-option = <0x1>;
qcom,keep-powerdown-phy;
qcom,no-l0s-supported;
diff --git a/arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi b/arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi
index d22818a1f459..c0c9ac316e4d 100644
--- a/arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi
@@ -151,6 +151,7 @@
qcom,phy-status-offset = <0x974>;
qcom,phy-status-bit = <6>;
qcom,phy-power-down-offset = <0x804>;
+ qcom,core-preset = <0x77777777>;
qcom,boot-option = <0x1>;
diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi
index 95fa47b280ac..0e7494be74ed 100644
--- a/arch/arm64/boot/dts/qcom/sa8155.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi
@@ -94,11 +94,13 @@
qcom,no-l1-supported;
qcom,no-l1ss-supported;
qcom,no-aux-clk-sync;
+ qcom,core-preset = <0x77777777>;
};
&pcie1 {
vreg-1.8-supply = <&pm8150_2_l8>;
vreg-0.9-supply = <&pm8150_2_l18>;
+ qcom,core-preset = <0x77777777>;
};
&pcie_ep {
diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi
index 24262a3a9614..b2eca5ab8c46 100644
--- a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi
@@ -302,5 +302,9 @@
};
&mdss_mdp {
+ qcom,sde-ctl-display-pref = "primary", "none", "none",
+ "none", "none";
+ qcom,sde-mixer-display-pref = "primary", "none", "none",
+ "none", "none", "none";
connectors = <&dsi_dp1 &dsi_dp2 &sde_dp &sde_wb>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi
index 2ba4e8fefb26..a5addb26df0e 100644
--- a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi
@@ -708,7 +708,7 @@
config {
pins = "gpio17";
drive-strength = <2>; /* 2 mA */
- bias-pull-down; /* PULL DOWN */
+ bias-disable; /* NO PULL */
input-enable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi
index a58b88f7b13d..68f2731612e2 100644
--- a/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi
@@ -26,6 +26,129 @@
status = "okay";
};
+&pcie0 {
+ qcom,pcie-phy-ver = <2100>;
+ qcom,phy-sequence = <0x1240 0x03 0x0
+ 0x1010 0x00 0x0
+ 0x101c 0x31 0x0
+ 0x1020 0x01 0x0
+ 0x1024 0xce 0x0
+ 0x1028 0x0b 0x0
+ 0x1030 0x97 0x0
+ 0x1034 0x0c 0x0
+ 0x1044 0x18 0x0
+ 0x1048 0x90 0x0
+ 0x1058 0x0f 0x0
+ 0x1074 0x06 0x0
+ 0x1078 0x06 0x0
+ 0x107c 0x16 0x0
+ 0x1080 0x16 0x0
+ 0x1084 0x36 0x0
+ 0x1088 0x36 0x0
+ 0x1094 0x08 0x0
+ 0x10a4 0x46 0x0
+ 0x10a8 0x04 0x0
+ 0x10ac 0x04 0x0
+ 0x10b0 0x0d 0x0
+ 0x10b4 0x0a 0x0
+ 0x10b8 0x1a 0x0
+ 0x10bc 0xc3 0x0
+ 0x10c4 0xd0 0x0
+ 0x10d4 0x05 0x0
+ 0x10d8 0x55 0x0
+ 0x10dc 0x55 0x0
+ 0x10e0 0x05 0x0
+ 0x110c 0x02 0x0
+ 0x1154 0x34 0x0
+ 0x1158 0x12 0x0
+ 0x115c 0x00 0x0
+ 0x1168 0x05 0x0
+ 0x116c 0x04 0x0
+ 0x119c 0x88 0x0
+ 0x11a0 0x03 0x0
+ 0x11ac 0xca 0x0
+ 0x11b0 0x1e 0x0
+ 0x11b4 0xd8 0x0
+ 0x11b8 0x20 0x0
+ 0x11bc 0x22 0x0
+ 0x106c 0x0a 0x0
+ 0x1070 0x10 0x0
+ 0x11a4 0x17 0x0
+ 0x11a8 0x0b 0x0
+ 0x0088 0x05 0x0
+ 0x008c 0xf6 0x0
+ 0x0090 0x13 0x0
+ 0x00e0 0x00 0x0
+ 0x00c4 0x00 0x0
+ 0x0208 0x0c 0x0
+ 0x0258 0x16 0x0
+ 0x0378 0x44 0x0
+ 0x03c8 0x1a 0x0
+ 0x03cc 0x5a 0x0
+ 0x03d0 0x09 0x0
+ 0x03d4 0x37 0x0
+ 0x03d8 0xbd 0x0
+ 0x03dc 0xf9 0x0
+ 0x03e0 0xbf 0x0
+ 0x03e4 0xce 0x0
+ 0x03e8 0x62 0x0
+ 0x03ec 0xbf 0x0
+ 0x03f0 0x7d 0x0
+ 0x03f4 0xbf 0x0
+ 0x03f8 0xcf 0x0
+ 0x03fc 0xd6 0x0
+ 0x02ac 0x7f 0x0
+ 0x0310 0x55 0x0
+ 0x0334 0x0c 0x0
+ 0x0338 0x00 0x0
+ 0x0350 0x08 0x0
+ 0x0400 0xa0 0x0
+ 0x043c 0x02 0x0
+ 0x0888 0x05 0x0
+ 0x088c 0xf6 0x0
+ 0x0890 0x13 0x0
+ 0x08e0 0x00 0x0
+ 0x08c4 0x00 0x0
+ 0x0a08 0x0c 0x0
+ 0x0a58 0x16 0x0
+ 0x0b78 0x44 0x0
+ 0x0bc8 0x1a 0x0
+ 0x0bcc 0x5a 0x0
+ 0x0bd0 0x09 0x0
+ 0x0bd4 0x37 0x0
+ 0x0bd8 0xbd 0x0
+ 0x0bdc 0xf9 0x0
+ 0x0be0 0xbf 0x0
+ 0x0be4 0xce 0x0
+ 0x0be8 0x62 0x0
+ 0x0bec 0xbf 0x0
+ 0x0bf0 0x7d 0x0
+ 0x0bf4 0xbf 0x0
+ 0x0bf8 0xcf 0x0
+ 0x0bfc 0xd6 0x0
+ 0x0aac 0x7f 0x0
+ 0x0b10 0x55 0x0
+ 0x0b34 0x0c 0x0
+ 0x0b38 0x00 0x0
+ 0x0b50 0x08 0x0
+ 0x0c00 0xa0 0x0
+ 0x0c3c 0x02 0x0
+ 0x161c 0xc1 0x0
+ 0x1690 0x00 0x0
+ 0x13e0 0x16 0x0
+ 0x13e4 0x02 0x0
+ 0x1708 0x02 0x0
+ 0x16a0 0x17 0x0
+ 0x13d8 0x01 0x0
+ 0x16fc 0x01 0x0
+ 0x16f0 0x13 0x0
+ 0x16f4 0x13 0x0
+ 0x1e24 0x00 0x0
+ 0x1e28 0x00 0x0
+ 0x1200 0x00 0x0
+ 0x1244 0x03 0x0>;
+};
+
&clock_gcc {
compatible = "qcom,gcc-sdxprairie-v2", "syscon";
};
diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi
index fdb7bca4eee6..9da6d91ab44f 100644
--- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi
@@ -1044,9 +1044,9 @@
qcom,cpulist = <&CPU0>;
qcom,target-dev = <&cpubw>;
qcom,core-dev-table =
- < 153600 MHZ_TO_MBPS( 300, 4) >,
- < 576000 MHZ_TO_MBPS(1017, 4) >,
- < 1497600 MHZ_TO_MBPS(1804, 4)>;
+ < 576000 MHZ_TO_MBPS( 300, 4) >,
+ < 1497600 MHZ_TO_MBPS(1017, 4) >,
+ < 1555200 MHZ_TO_MBPS(1804, 4)>;
};
cnss_qca6390: qcom,cnss-qca6390@a0000000 {
diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig
index b9019ce1f73d..523a2dd3b4be 100644
--- a/arch/arm64/configs/vendor/trinket_defconfig
+++ b/arch/arm64/configs/vendor/trinket_defconfig
@@ -570,6 +570,7 @@ CONFIG_MSM_QMP=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_TLBSYNC_DEBUG=y
+CONFIG_ARM_SMMU_TESTBUS_DUMP=y
CONFIG_QCOM_LAZY_MAPPING=y
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 366eaf277578..aec1fd692eb9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -2083,6 +2083,11 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
if ((ret == DIAG_DCI_NO_ERROR && !common_cmd) || ret < 0)
return ret;
+ reg_entry.cmd_code = 0;
+ reg_entry.subsys_id = 0;
+ reg_entry.cmd_code_hi = 0;
+ reg_entry.cmd_code_lo = 0;
+
if (header_len >= (sizeof(uint8_t)))
reg_entry.cmd_code = header->cmd_code;
if (header_len >= (2 * sizeof(uint8_t)))
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index cd57bb0202aa..acb205dec57b 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -200,8 +200,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
goto bail;
size = min_t(size_t, count, SZ_2K);
-
- if (size <= char_to_nib)
+ if (size < 4)
goto bail;
buf = kzalloc(size, GFP_KERNEL);
@@ -231,6 +230,8 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
}
size -= 4;
+ if (size == 0)
+ goto bail;
dpcd_size = size / char_to_nib;
data_len = dpcd_size;
@@ -316,6 +317,7 @@ static ssize_t dp_debug_read_dpcd(struct file *file,
debug->aux->dpcd_updated(debug->aux);
}
+ len = min_t(size_t, count, len);
if (!copy_to_user(user_buff, buf, len))
*ppos += len;
@@ -647,6 +649,7 @@ static ssize_t dp_debug_max_pclk_khz_read(struct file *file,
debug->dp_debug.max_pclk_khz,
debug->parser->max_pclk_khz);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
return -EFAULT;
@@ -808,6 +811,7 @@ static ssize_t dp_debug_read_connected(struct file *file,
len += snprintf(buf, SZ_8, "%d\n", debug->hpd->hpd_high);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len))
return -EFAULT;
@@ -858,6 +862,7 @@ static ssize_t dp_debug_read_hdcp(struct file *file,
len = sizeof(debug->dp_debug.hdcp_status);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, debug->dp_debug.hdcp_status, len))
return -EFAULT;
@@ -921,6 +926,7 @@ static ssize_t dp_debug_read_edid_modes(struct file *file,
}
mutex_unlock(&connector->dev->mode_config.mutex);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
rc = -EFAULT;
@@ -996,6 +1002,7 @@ static ssize_t dp_debug_read_edid_modes_mst(struct file *file,
}
mutex_unlock(&connector->dev->mode_config.mutex);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
rc = -EFAULT;
@@ -1036,6 +1043,7 @@ static ssize_t dp_debug_read_mst_con_id(struct file *file,
ret = snprintf(buf, max_size, "%u\n", debug->mst_con_id);
len += ret;
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
rc = -EFAULT;
@@ -1099,6 +1107,7 @@ static ssize_t dp_debug_read_mst_conn_info(struct file *file,
}
mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
rc = -EFAULT;
@@ -1188,6 +1197,7 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
goto error;
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len))
goto error;
@@ -1220,6 +1230,7 @@ static ssize_t dp_debug_bw_code_read(struct file *file,
len += snprintf(buf + len, (SZ_4K - len),
"max_bw_code = %d\n", debug->panel->max_bw_code);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
return -EFAULT;
@@ -1245,6 +1256,7 @@ static ssize_t dp_debug_tpg_read(struct file *file,
len += snprintf(buf, SZ_8, "%d\n", debug->dp_debug.tpg_state);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len))
return -EFAULT;
@@ -1435,6 +1447,7 @@ static ssize_t dp_debug_read_hdr(struct file *file,
goto error;
}
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
rc = -EFAULT;
@@ -1612,6 +1625,7 @@ static ssize_t dp_debug_read_dump(struct file *file,
print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_NONE,
16, 4, buf, len, false);
+ len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len))
return -EFAULT;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index a8395de6bb7a..0e58dd8ed4d9 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -186,14 +186,15 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
return;
}
- SDE_ATRACE_BEGIN("dsi_bridge_pre_enable");
+ SDE_ATRACE_BEGIN("dsi_display_prepare");
rc = dsi_display_prepare(c_bridge->display);
if (rc) {
pr_err("[%d] DSI display prepare failed, rc=%d\n",
c_bridge->id, rc);
- SDE_ATRACE_END("dsi_bridge_pre_enable");
+ SDE_ATRACE_END("dsi_display_prepare");
return;
}
+ SDE_ATRACE_END("dsi_display_prepare");
SDE_ATRACE_BEGIN("dsi_display_enable");
rc = dsi_display_enable(c_bridge->display);
@@ -203,7 +204,6 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
(void)dsi_display_unprepare(c_bridge->display);
}
SDE_ATRACE_END("dsi_display_enable");
- SDE_ATRACE_END("dsi_bridge_pre_enable");
rc = dsi_display_splash_res_cleanup(c_bridge->display);
if (rc)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index f369aba32b8a..be06c3c964ef 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -371,6 +371,24 @@ static int _sde_encoder_get_mode_info(struct drm_encoder *drm_enc,
return sde_connector_get_mode_info(conn_state, mode_info);
}
+static bool _sde_encoder_is_autorefresh_enabled(
+ struct sde_encoder_virt *sde_enc)
+{
+ struct drm_connector *drm_conn;
+
+ if (!sde_enc->cur_master ||
+ !(sde_enc->disp_info.capabilities & MSM_DISPLAY_CAP_CMD_MODE))
+ return false;
+
+ drm_conn = sde_enc->cur_master->connector;
+
+ if (!drm_conn || !drm_conn->state)
+ return false;
+
+ return sde_connector_get_property(drm_conn->state,
+ CONNECTOR_PROP_AUTOREFRESH) ? true : false;
+}
+
static bool _sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc)
{
struct msm_compression_info *comp_info;
@@ -3865,7 +3883,7 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
u32 pending_kickoff_cnt;
struct msm_drm_private *priv = NULL;
struct sde_kms *sde_kms = NULL;
- bool is_vid_mode = false;
+ bool is_regdma_blocking = false, is_vid_mode = false;
if (!sde_enc) {
SDE_ERROR("invalid encoder\n");
@@ -3874,6 +3892,8 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
is_vid_mode = sde_enc->disp_info.capabilities &
MSM_DISPLAY_CAP_VID_MODE;
+ is_regdma_blocking = (is_vid_mode ||
+ _sde_encoder_is_autorefresh_enabled(sde_enc));
/* don't perform flush/start operations for slave encoders */
for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -3902,7 +3922,7 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
if (!phys->ops.needs_single_flush ||
!phys->ops.needs_single_flush(phys)) {
if (ctl->ops.reg_dma_flush)
- ctl->ops.reg_dma_flush(ctl, is_vid_mode);
+ ctl->ops.reg_dma_flush(ctl, is_regdma_blocking);
_sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0);
} else if (ctl->ops.get_pending_flush) {
ctl->ops.get_pending_flush(ctl, &pending_flush);
@@ -3913,7 +3933,7 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
if (pending_flush.pending_flush_mask && sde_enc->cur_master) {
ctl = sde_enc->cur_master->hw_ctl;
if (ctl->ops.reg_dma_flush)
- ctl->ops.reg_dma_flush(ctl, is_vid_mode);
+ ctl->ops.reg_dma_flush(ctl, is_regdma_blocking);
_sde_encoder_trigger_flush(&sde_enc->base, sde_enc->cur_master,
&pending_flush);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 13fbac27e3fe..bcc5dd6bff03 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -1594,6 +1594,8 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
exit:
phys_enc->enable_state = SDE_ENC_DISABLED;
wb_enc->crtc = NULL;
+ phys_enc->hw_cdm = NULL;
+ phys_enc->hw_ctl = NULL;
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index 2909778f4e46..61807d572272 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2019, 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
@@ -145,38 +145,24 @@ TRACE_EVENT(sde_encoder_underrun,
);
TRACE_EVENT(tracing_mark_write,
- TP_PROTO(int pid, const char *name, bool trace_begin),
- TP_ARGS(pid, name, trace_begin),
+ TP_PROTO(char trace_type, const struct task_struct *task,
+ const char *name, int value),
+ TP_ARGS(trace_type, task, name, value),
TP_STRUCT__entry(
+ __field(char, trace_type)
__field(int, pid)
__string(trace_name, name)
- __field(bool, trace_begin)
- ),
- TP_fast_assign(
- __entry->pid = pid;
- __assign_str(trace_name, name);
- __entry->trace_begin = trace_begin;
- ),
- TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E",
- __entry->pid, __get_str(trace_name))
-)
-
-TRACE_EVENT(sde_trace_counter,
- TP_PROTO(int pid, char *name, int value),
- TP_ARGS(pid, name, value),
- TP_STRUCT__entry(
- __field(int, pid)
- __string(counter_name, name)
__field(int, value)
),
TP_fast_assign(
- __entry->pid = current->tgid;
- __assign_str(counter_name, name);
+ __entry->trace_type = trace_type;
+ __entry->pid = task ? task->tgid : 0;
+ __assign_str(trace_name, name);
__entry->value = value;
),
- TP_printk("%d|%s|%d", __entry->pid,
- __get_str(counter_name), __entry->value)
-)
+ TP_printk("%c|%d|%s|%d", __entry->trace_type,
+ __entry->pid, __get_str(trace_name), __entry->value)
+);
#define SDE_TRACE_EVTLOG_SIZE 15
TRACE_EVENT(sde_evtlog,
@@ -319,12 +305,13 @@ TRACE_EVENT(sde_perf_calc_crtc,
__entry->core_clk_rate)
);
-#define SDE_ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
-#define SDE_ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
+#define sde_atrace trace_tracing_mark_write
+
+#define SDE_ATRACE_END(name) sde_atrace('E', current, name, 0)
+#define SDE_ATRACE_BEGIN(name) sde_atrace('B', current, name, 0)
#define SDE_ATRACE_FUNC() SDE_ATRACE_BEGIN(__func__)
-#define SDE_ATRACE_INT(name, value) \
- trace_sde_trace_counter(current->tgid, name, value)
+#define SDE_ATRACE_INT(name, value) sde_atrace('C', current, name, value)
#endif /* _SDE_TRACE_H_ */
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 85bfa9ce4419..2e5f4179a70e 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -1046,10 +1046,9 @@ int sde_power_resource_enable(struct sde_power_handle *phandle,
SDE_POWER_EVENT_POST_DISABLE);
}
-end:
SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_EXIT);
- mutex_unlock(&phandle->phandle_lock);
SDE_ATRACE_END("sde_power_resource_enable");
+ mutex_unlock(&phandle->phandle_lock);
return rc;
clk_err:
@@ -1063,8 +1062,10 @@ vreg_err:
sde_power_data_bus_update(&phandle->data_bus_handle[i], 0);
data_bus_hdl_err:
phandle->current_usecase_ndx = prev_usecase_ndx;
- mutex_unlock(&phandle->phandle_lock);
SDE_ATRACE_END("sde_power_resource_enable");
+
+end:
+ mutex_unlock(&phandle->phandle_lock);
return rc;
}
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index f0944844a8f3..606f54052aa4 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -29,6 +29,7 @@
#include <drm/drm_irq.h>
#include "sde_rsc_priv.h"
#include "sde_dbg.h"
+#include "sde_trace.h"
#define SDE_RSC_DRV_DBG_NAME "sde_rsc_drv"
#define SDE_RSC_WRAPPER_DBG_NAME "sde_rsc_wrapper"
@@ -987,6 +988,7 @@ int sde_rsc_client_state_update(struct sde_rsc_client *caller_client,
}
pr_debug("state switch successfully complete: %d\n", state);
+ SDE_ATRACE_INT("rsc_state", state);
rsc->current_state = state;
SDE_EVT32(caller_client->id, caller_client->current_state,
state, rsc->current_state, SDE_EVTLOG_FUNC_EXIT);
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 11ec6fa448df..b54aed6971bd 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1293,6 +1293,9 @@ static int gmu_aop_mailbox_init(struct kgsl_device *device,
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_mailbox *mailbox = &gmu->mailbox;
+ if (adreno_is_a640v2(adreno_dev) && (!adreno_dev->speed_bin))
+ return 0;
+
mailbox->client = kzalloc(sizeof(*mailbox->client), GFP_KERNEL);
if (!mailbox->client)
return -ENOMEM;
@@ -1309,8 +1312,8 @@ static int gmu_aop_mailbox_init(struct kgsl_device *device,
return PTR_ERR(mailbox->channel);
}
- if (adreno_dev->speed_bin)
- set_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag);
+ set_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag);
+
return 0;
}
diff --git a/drivers/iommu/arm-smmu-debug.c b/drivers/iommu/arm-smmu-debug.c
index fde0710be8e2..ad0fbf0c98c6 100644
--- a/drivers/iommu/arm-smmu-debug.c
+++ b/drivers/iommu/arm-smmu-debug.c
@@ -231,3 +231,60 @@ void arm_smmu_debug_dump_tcu_testbus(struct device *dev, void __iomem *base,
arm_smmu_debug_tcu_testbus_select(base, tcu_base,
CLK_TESTBUS, READ, 0));
}
+
+void arm_smmu_debug_set_tnx_tcr_cntl(void __iomem *tbu_base, u64 val)
+{
+ writel_relaxed(val, tbu_base + ARM_SMMU_TNX_TCR_CNTL);
+}
+
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl(void __iomem *tbu_base)
+{
+ return readl_relaxed(tbu_base + ARM_SMMU_TNX_TCR_CNTL);
+}
+
+void arm_smmu_debug_set_mask_and_match(void __iomem *tbu_base, u64 sel,
+ u64 mask, u64 match)
+{
+ writeq_relaxed(mask, tbu_base + ARM_SMMU_CAPTURE1_MASK(sel));
+ writeq_relaxed(match, tbu_base + ARM_SMMU_CAPTURE1_MATCH(sel));
+}
+
+void arm_smmu_debug_get_mask_and_match(void __iomem *tbu_base, u64 *mask,
+ u64 *match)
+{
+ int i;
+
+ for (i = 0; i < NO_OF_MASK_AND_MATCH; ++i) {
+ mask[i] = readq_relaxed(tbu_base +
+ ARM_SMMU_CAPTURE1_MASK(i+1));
+ match[i] = readq_relaxed(tbu_base +
+ ARM_SMMU_CAPTURE1_MATCH(i+1));
+ }
+}
+
+void arm_smmu_debug_get_capture_snapshot(void __iomem *tbu_base,
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT])
+{
+ int valid, i, j;
+
+ valid = readl_relaxed(tbu_base + APPS_SMMU_TNX_TCR_CNTL_2);
+
+ for (i = 0; i < NO_OF_CAPTURE_POINTS ; ++i) {
+ if (valid & (1 << i))
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j)
+ snapshot[i][j] = readq_relaxed(tbu_base +
+ ARM_SMMU_CAPTURE_SNAPSHOT(i, j));
+ else
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j)
+ snapshot[i][j] = 0xdededede;
+ }
+}
+
+void arm_smmu_debug_clear_intr_and_validbits(void __iomem *tbu_base)
+{
+ int val = 0;
+
+ val |= INTR_CLR;
+ val |= RESET_VALID;
+ writel_relaxed(val, tbu_base + ARM_SMMU_TNX_TCR_CNTL);
+}
diff --git a/drivers/iommu/arm-smmu-debug.h b/drivers/iommu/arm-smmu-debug.h
index 6b7843a54892..399cab64c8bc 100644
--- a/drivers/iommu/arm-smmu-debug.h
+++ b/drivers/iommu/arm-smmu-debug.h
@@ -55,6 +55,18 @@ enum testbus_ops {
TESTBUS_OUTPUT,
};
+#define ARM_SMMU_TNX_TCR_CNTL 0x130
+#define ARM_SMMU_CAPTURE1_MASK(i) (0x100 + (0x8)*(i-1))
+#define ARM_SMMU_CAPTURE1_MATCH(i) (0x118 + (0x8)*(i-1))
+#define ARM_SMMU_CAPTURE_SNAPSHOT(i, j) ((0x138 + (0x10)*i) + j*0x8)
+#define APPS_SMMU_TNX_TCR_CNTL_2 0x178
+
+#define NO_OF_MASK_AND_MATCH 0x3
+#define NO_OF_CAPTURE_POINTS 0x4
+#define REGS_PER_CAPTURE_POINT 0x2
+#define INTR_CLR (1 << 0)
+#define RESET_VALID (1 << 7)
+
#ifdef CONFIG_ARM_SMMU
u32 arm_smmu_debug_tbu_testbus_select(void __iomem *tbu_base,
@@ -71,7 +83,16 @@ void arm_smmu_debug_dump_tbu_testbus(struct device *dev, void __iomem *tbu_base,
u32 testbus_version);
void arm_smmu_debug_dump_tcu_testbus(struct device *dev, void __iomem *base,
void __iomem *tcu_base, int tcu_testbus_sel);
-
+void arm_smmu_debug_set_tnx_tcr_cntl(void __iomem *tbu_base, u64 val);
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl(void __iomem *tbu_base);
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl_2(void __iomem *tbu_base);
+void arm_smmu_debug_set_mask_and_match(void __iomem *tbu_base, u64 sel,
+ u64 mask, u64 match);
+void arm_smmu_debug_get_mask_and_match(void __iomem *tbu_base,
+ u64 *mask, u64 *match);
+void arm_smmu_debug_get_capture_snapshot(void __iomem *tbu_base,
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT]);
+void arm_smmu_debug_clear_intr_and_validbits(void __iomem *tbu_base);
#else
static inline u32 arm_smmu_debug_tbu_testbus_select(void __iomem *tbu_base,
void __iomem *tcu_base, u32 testbus_version, bool write,
@@ -100,4 +121,28 @@ static inline void arm_smmu_debug_dump_tcu_testbus(struct device *dev,
int tcu_testbus_sel)
{
}
+void arm_smmu_debug_set_tnx_tcr_cntl(void __iomem *tbu_base, u64 val)
+{
+}
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl(void __iomem *tbu_base)
+{
+}
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl_2(void __iomem *tbu_base)
+{
+}
+void arm_smmu_debug_set_mask_and_match(void __iomem *tbu_base, u64 sel,
+ u64 mask, u64 match)
+{
+}
+void arm_smmu_debug_get_mask_and_match(void __iomem *tbu_base,
+ u64 *mask, u64 *match)
+{
+}
+void arm_smmu_debug_get_capture_snapshot(void __iomem *tbu_base,
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT])
+{
+}
+void arm_smmu_debug_clear_intr_and_validbits(void __iomem *tbu_base)
+{
+}
#endif
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 52eb755a5335..d69ac838de7a 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -353,6 +353,7 @@ static int tbu_testbus_sel = TBU_TESTBUS_SEL_ALL;
static int tcu_testbus_sel = TCU_TESTBUS_SEL_ALL;
static struct dentry *debugfs_testbus_dir;
static DEFINE_SPINLOCK(testbus_lock);
+static struct dentry *debugfs_capturebus_dir;
module_param_named(tcu_testbus_sel, tcu_testbus_sel, int, 0644);
module_param_named(tbu_testbus_sel, tbu_testbus_sel, int, 0644);
@@ -430,6 +431,7 @@ struct qsmmuv500_tbu_device {
/* Protects halt count */
spinlock_t halt_lock;
u32 halt_count;
+ unsigned int *irqs;
};
static atomic_t cavium_smmu_context_count = ATOMIC_INIT(0);
@@ -5971,6 +5973,260 @@ err:
return 0;
}
+static ssize_t arm_smmu_debug_capturebus_snapshot_read(struct file *file,
+ char __user *ubuf, size_t count, loff_t *offset)
+{
+ struct qsmmuv500_tbu_device *tbu = file->private_data;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT];
+ char buf[400];
+ ssize_t retval;
+ size_t buflen;
+ int buf_len = sizeof(buf);
+ int i, j;
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, buf_len);
+
+ arm_smmu_power_on(smmu->pwr);
+ arm_smmu_power_on(tbu->pwr);
+
+ arm_smmu_debug_get_capture_snapshot(tbu_base, snapshot);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+
+ for (i = 0; i < NO_OF_CAPTURE_POINTS ; ++i) {
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j) {
+ snprintf(buf + strlen(buf), buf_len - strlen(buf),
+ "Capture_%d_Snapshot_%d : 0x%0llx\n",
+ i+1, j+1, snapshot[i][j]);
+ }
+ }
+
+ buflen = min(count, strlen(buf));
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err_ratelimited("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1;
+ retval = buflen;
+ }
+
+ return retval;
+}
+static const struct file_operations arm_smmu_debug_capturebus_snapshot_fops = {
+ .open = simple_open,
+ .read = arm_smmu_debug_capturebus_snapshot_read,
+};
+
+static ssize_t arm_smmu_debug_capturebus_config_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *offset)
+{
+ struct qsmmuv500_tbu_device *tbu = file->private_data;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ char *comma1, *comma2;
+ char buf[100];
+ u64 sel, mask, match, val;
+
+ if (count >= 100) {
+ pr_err_ratelimited("Input too large\n");
+ goto invalid_format;
+ }
+
+ memset(buf, 0, 100);
+
+ if (copy_from_user(buf, ubuf, count)) {
+ pr_err_ratelimited("Couldn't copy from user\n");
+ return -EFAULT;
+ }
+
+ comma1 = strnchr(buf, count, ',');
+ if (!comma1)
+ goto invalid_format;
+
+ *comma1 = '\0';
+
+ if (kstrtou64(buf, 0, &sel))
+ goto invalid_format;
+
+ if (sel > 4) {
+ goto invalid_format;
+ } else if (sel == 4) {
+ if (kstrtou64(comma1 + 1, 0, &val))
+ goto invalid_format;
+ goto program_capturebus;
+ }
+
+ comma2 = strnchr(comma1 + 1, count, ',');
+ if (!comma2)
+ goto invalid_format;
+
+ /* split up the words */
+ *comma2 = '\0';
+
+ if (kstrtou64(comma1 + 1, 0, &mask))
+ goto invalid_format;
+
+ if (kstrtou64(comma2 + 1, 0, &match))
+ goto invalid_format;
+
+program_capturebus:
+ arm_smmu_power_on(smmu->pwr);
+ arm_smmu_power_on(tbu->pwr);
+
+ if (sel == 4)
+ arm_smmu_debug_set_tnx_tcr_cntl(tbu_base, val);
+ else
+ arm_smmu_debug_set_mask_and_match(tbu_base, sel, mask, match);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+ return count;
+
+invalid_format:
+ pr_err_ratelimited("Invalid format. Expected: <1/2/3,Mask,Match> (or) <4,TNX_TCR_CNTL>>\n");
+ return -EINVAL;
+}
+static ssize_t arm_smmu_debug_capturebus_config_read(struct file *file,
+ char __user *ubuf, size_t count, loff_t *offset)
+{
+ struct qsmmuv500_tbu_device *tbu = file->private_data;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ unsigned long val;
+ u64 mask[NO_OF_MASK_AND_MATCH], match[NO_OF_MASK_AND_MATCH];
+ char buf[400];
+ ssize_t retval;
+ size_t buflen;
+ int buf_len = sizeof(buf);
+ int i;
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, buf_len);
+
+ arm_smmu_power_on(smmu->pwr);
+ arm_smmu_power_on(tbu->pwr);
+
+ arm_smmu_debug_get_mask_and_match(tbu_base,
+ mask, match);
+ val = arm_smmu_debug_get_tnx_tcr_cntl(tbu_base);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+
+ for (i = 0; i < NO_OF_MASK_AND_MATCH; ++i) {
+ snprintf(buf + strlen(buf), buf_len - strlen(buf),
+ "Mask_%d : 0x%0llx\t", i+1, mask[i]);
+ snprintf(buf + strlen(buf), buf_len - strlen(buf),
+ "Match_%d : 0x%0llx\n", i+1, match[i]);
+ }
+ snprintf(buf + strlen(buf), buf_len - strlen(buf), "0x%0x\n", val);
+
+ buflen = min(count, strlen(buf));
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err_ratelimited("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1;
+ retval = buflen;
+ }
+
+ return retval;
+}
+
+static const struct file_operations arm_smmu_debug_capturebus_config_fops = {
+ .open = simple_open,
+ .write = arm_smmu_debug_capturebus_config_write,
+ .read = arm_smmu_debug_capturebus_config_read,
+};
+
+static int qsmmuv500_capturebus_init(struct qsmmuv500_tbu_device *tbu)
+{
+ struct dentry *capturebus_dir;
+
+ if (!debugfs_capturebus_dir) {
+ debugfs_capturebus_dir = debugfs_create_dir(
+ "capturebus", iommu_debugfs_top);
+ if (!debugfs_capturebus_dir) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus debugfs directory\n");
+ return -ENODEV;
+ }
+ }
+ capturebus_dir = debugfs_create_dir(dev_name(tbu->dev),
+ debugfs_capturebus_dir);
+ if (!capturebus_dir) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus/%s debugfs directory\n",
+ dev_name(tbu->dev));
+ goto err;
+ }
+
+ if (!debugfs_create_file("config", 0400, capturebus_dir, tbu,
+ &arm_smmu_debug_capturebus_config_fops)) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus/%s/config debugfs file\n",
+ dev_name(tbu->dev));
+ goto err_rmdir;
+ }
+
+ if (!debugfs_create_file("snapshot", 0400, capturebus_dir, tbu,
+ &arm_smmu_debug_capturebus_snapshot_fops)) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus/%s/snapshot debugfs file\n",
+ dev_name(tbu->dev));
+ goto err_rmdir;
+ }
+ return 0;
+err_rmdir:
+ debugfs_remove_recursive(capturebus_dir);
+err:
+ return 0;
+}
+
+static irqreturn_t arm_smmu_debug_capture_bus_match(int irq, void *dev)
+{
+ struct qsmmuv500_tbu_device *tbu = dev;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ u64 mask[NO_OF_MASK_AND_MATCH], match[NO_OF_MASK_AND_MATCH];
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT];
+ int i, j, val;
+
+ if (arm_smmu_power_on(smmu->pwr) || arm_smmu_power_on(tbu->pwr))
+ return IRQ_NONE;
+
+ val = arm_smmu_debug_get_tnx_tcr_cntl(tbu_base);
+ arm_smmu_debug_get_mask_and_match(tbu_base, mask, match);
+ arm_smmu_debug_get_capture_snapshot(tbu_base, snapshot);
+ arm_smmu_debug_clear_intr_and_validbits(tbu_base);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+
+ dev_info(tbu->dev, "TNX_TCR_CNTL : 0x%0llx\n", val);
+
+ for (i = 0; i < NO_OF_MASK_AND_MATCH; ++i) {
+ dev_info(tbu->dev,
+ "Mask_%d : 0x%0llx\n", i+1, mask[i]);
+ dev_info(tbu->dev,
+ "Match_%d : 0x%0llx\n", i+1, match[i]);
+ }
+
+ for (i = 0; i < NO_OF_CAPTURE_POINTS ; ++i) {
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j) {
+ dev_info(tbu->dev,
+ "Capture_%d_Snapshot_%d : 0x%0llx\n",
+ i+1, j+1, snapshot[i][j]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
{
struct resource *res;
@@ -6055,7 +6311,7 @@ static int qsmmuv500_tbu_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct qsmmuv500_tbu_device *tbu;
const __be32 *cell;
- int len;
+ int len, i, err, num_irqs = 0;
tbu = devm_kzalloc(dev, sizeof(*tbu), GFP_KERNEL);
if (!tbu)
@@ -6082,12 +6338,42 @@ static int qsmmuv500_tbu_probe(struct platform_device *pdev)
tbu->sid_start = of_read_number(cell, 1);
tbu->num_sids = of_read_number(cell + 1, 1);
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs)))
+ num_irqs++;
+
+ tbu->irqs = devm_kzalloc(dev, sizeof(*tbu->irqs) * num_irqs,
+ GFP_KERNEL);
+ if (!tbu->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < num_irqs; ++i) {
+ int irq = platform_get_irq(pdev, i);
+
+ if (irq < 0) {
+ dev_err(dev, "failed to get irq index %d\n", i);
+ return -ENODEV;
+ }
+ tbu->irqs[i] = irq;
+
+ err = devm_request_threaded_irq(tbu->dev, tbu->irqs[i],
+ NULL, arm_smmu_debug_capture_bus_match,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "capture bus", tbu);
+ if (err) {
+ dev_err(dev, "failed to request capture bus irq%d (%u)\n",
+ i, tbu->irqs[i]);
+ return err;
+ }
+ }
+
tbu->pwr = arm_smmu_init_power_resources(pdev);
if (IS_ERR(tbu->pwr))
return PTR_ERR(tbu->pwr);
dev_set_drvdata(dev, tbu);
+
qsmmuv500_tbu_testbus_init(tbu);
+ qsmmuv500_capturebus_init(tbu);
return 0;
}
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
index 6b7a9007cff9..2afdafb03184 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
@@ -262,6 +262,16 @@ struct cam_hw_dump_pf_args {
bool *mem_found;
};
+/**
+ * struct cam_hw_reset_args -hw reset arguments
+ *
+ * @ctxt_to_hw_map: HW context from the acquire
+ *
+ */
+struct cam_hw_reset_args {
+ void *ctxt_to_hw_map;
+};
+
/* enum cam_hw_mgr_command - Hardware manager command type */
enum cam_hw_mgr_command {
CAM_HW_MGR_CMD_INTERNAL,
@@ -313,6 +323,7 @@ struct cam_hw_cmd_args {
* @hw_open: Function pointer for HW init
* @hw_close: Function pointer for HW deinit
* @hw_flush: Function pointer for HW flush
+ * @hw_reset: Function pointer for HW reset
*
*/
struct cam_hw_mgr_intf {
@@ -333,6 +344,7 @@ struct cam_hw_mgr_intf {
int (*hw_open)(void *hw_priv, void *fw_download_args);
int (*hw_close)(void *hw_priv, void *hw_close_args);
int (*hw_flush)(void *hw_priv, void *hw_flush_args);
+ int (*hw_reset)(void *hw_priv, void *hw_reset_args);
};
#endif /* _CAM_HW_MGR_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 0d0ce4210ae4..52dd3196a339 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -452,6 +452,14 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
trace_cam_buf_done("ISP", ctx, req);
req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+ if (ctx_isp->frame_id == 1)
+ ctx_isp->irq_timestamps = done->irq_mono_boot_time;
+ else if (ctx_isp->fps && ((done->irq_mono_boot_time -
+ ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps)))
+ ctx_isp->irq_delay_detect = true;
+
+ ctx_isp->irq_timestamps = done->irq_mono_boot_time;
+
for (i = 0; i < done->num_handles; i++) {
for (j = 0; j < req_isp->num_fence_map_out; j++) {
if (done->resource_handle[i] ==
@@ -565,6 +573,26 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
ctx_isp->substate_activated);
}
+ if (ctx_isp->active_req_cnt && ctx_isp->irq_delay_detect) {
+ CAM_ERR(CAM_ISP, "isp req[%lld] IRQ buf done got delayed",
+ req->request_id);
+ req = list_first_entry(&ctx->active_req_list,
+ struct cam_ctx_request, list);
+ req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+
+ for (j = 0; j < req_isp->num_fence_map_out; j++) {
+ rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+ CAM_SYNC_STATE_SIGNALED_ERROR);
+ if (rc)
+ CAM_DBG(CAM_ISP, "Sync failed with rc = %d",
+ rc);
+ req_isp->fence_map_out[j].sync_id = -1;
+ }
+ list_del_init(&req->list);
+ list_add_tail(&req->list, &ctx->free_req_list);
+ ctx_isp->active_req_cnt--;
+ }
+ ctx_isp->irq_delay_detect = false;
end:
return rc;
}
@@ -643,12 +671,47 @@ static void __cam_isp_ctx_send_sof_timestamp(
static int __cam_isp_ctx_reg_upd_in_epoch_state(
struct cam_isp_context *ctx_isp, void *evt_data)
{
- if (ctx_isp->frame_id == 1)
+ struct cam_isp_hw_reg_update_event_data *rup_event_data = evt_data;
+
+ struct cam_context *ctx = ctx_isp->base;
+ struct cam_ctx_request *req = NULL;
+ struct cam_isp_ctx_req *req_isp = NULL;
+
+ if (ctx_isp->frame_id == 1) {
CAM_DBG(CAM_ISP, "Reg update for early PCR");
- else
+ if (!list_empty(&ctx->active_req_list)) {
+ req = list_first_entry(&ctx->active_req_list,
+ struct cam_ctx_request, list);
+ req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+ } else if (!list_empty(&ctx->wait_req_list)) {
+ req = list_first_entry(&ctx->active_req_list,
+ struct cam_ctx_request, list);
+ req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+ }
+ } else {
+ if (!list_empty(&ctx->wait_req_list)) {
+ req = list_first_entry(&ctx->active_req_list,
+ struct cam_ctx_request, list);
+ req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+ }
CAM_WARN(CAM_ISP,
"Unexpected reg update in activated substate:%d for frame_id:%lld",
ctx_isp->substate_activated, ctx_isp->frame_id);
+ }
+
+ if (req_isp && req_isp->hw_update_data.fps) {
+ ctx_isp->fps = req_isp->hw_update_data.fps;
+ CAM_DBG(CAM_ISP, "req_isp %pK, Upadting ctx_isp->fps %d",
+ req_isp, ctx_isp->fps);
+ }
+
+ if (ctx_isp->frame_id == 1)
+ ctx_isp->irq_timestamps = rup_event_data->irq_mono_boot_time;
+ else if (ctx_isp->fps && ((rup_event_data->irq_mono_boot_time -
+ ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps)))
+ ctx_isp->irq_delay_detect = true;
+
+ ctx_isp->irq_timestamps = rup_event_data->irq_mono_boot_time;
return 0;
}
@@ -658,7 +721,8 @@ static int __cam_isp_ctx_reg_upd_in_activated_state(
int rc = 0;
struct cam_ctx_request *req;
struct cam_context *ctx = ctx_isp->base;
- struct cam_isp_ctx_req *req_isp;
+ struct cam_isp_ctx_req *req_isp = NULL;
+ struct cam_isp_hw_reg_update_event_data *rup_event_data = evt_data;
if (list_empty(&ctx->wait_req_list)) {
CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request");
@@ -683,13 +747,22 @@ static int __cam_isp_ctx_reg_upd_in_activated_state(
req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
}
+ if (req_isp && req_isp->hw_update_data.fps)
+ ctx_isp->fps = req_isp->hw_update_data.fps;
+
/*
* This function only called directly from applied and bubble applied
* state so change substate here.
*/
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH;
CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
+ if (ctx_isp->frame_id == 1)
+ ctx_isp->irq_timestamps = rup_event_data->irq_mono_boot_time;
+ else if (ctx_isp->fps && ((rup_event_data->irq_mono_boot_time -
+ ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps)))
+ ctx_isp->irq_delay_detect = true;
+ ctx_isp->irq_timestamps = rup_event_data->irq_mono_boot_time;
end:
return rc;
}
@@ -817,6 +890,14 @@ static int __cam_isp_ctx_sof_in_activated_state(
ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
ctx_isp->boot_timestamp = sof_event_data->boot_time;
+ if (ctx_isp->frame_id == 1)
+ ctx_isp->irq_timestamps = sof_event_data->irq_mono_boot_time;
+ else if (ctx_isp->fps && ((sof_event_data->irq_mono_boot_time -
+ ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps)))
+ ctx_isp->irq_delay_detect = true;
+
+ ctx_isp->irq_timestamps = sof_event_data->irq_mono_boot_time;
+
CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u",
ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id);
@@ -828,8 +909,9 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
{
int rc = 0;
struct cam_ctx_request *req = NULL;
- struct cam_isp_ctx_req *req_isp;
+ struct cam_isp_ctx_req *req_isp = NULL;
struct cam_context *ctx = ctx_isp->base;
+ struct cam_isp_hw_reg_update_event_data *rup_event_data = evt_data;
if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) {
CAM_DBG(CAM_ISP, "invalid RUP");
@@ -852,6 +934,16 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
"receive rup in unexpected state");
}
+ if (req_isp && req_isp->hw_update_data.fps)
+ ctx_isp->fps = req_isp->hw_update_data.fps;
+
+ if (ctx_isp->frame_id == 1)
+ ctx_isp->irq_timestamps = rup_event_data->irq_mono_boot_time;
+ else if (ctx_isp->fps && ((rup_event_data->irq_mono_boot_time -
+ ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps)))
+ ctx_isp->irq_delay_detect = true;
+
+ ctx_isp->irq_timestamps = rup_event_data->irq_mono_boot_time;
end:
return rc;
}
@@ -860,9 +952,10 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
void *evt_data)
{
struct cam_ctx_request *req;
- struct cam_isp_ctx_req *req_isp;
+ struct cam_isp_ctx_req *req_isp = NULL;
struct cam_context *ctx = ctx_isp->base;
uint64_t request_id = 0;
+ struct cam_isp_hw_epoch_event_data *epoch_hw_event_data = evt_data;
if (list_empty(&ctx->wait_req_list)) {
/*
@@ -928,6 +1021,15 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
ctx_isp->substate_activated);
end:
+ if (ctx_isp->frame_id == 1)
+ ctx_isp->irq_timestamps =
+ epoch_hw_event_data->irq_mono_boot_time;
+ else if (ctx_isp->fps && ((epoch_hw_event_data->irq_mono_boot_time -
+ ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps)))
+ ctx_isp->irq_delay_detect = true;
+
+ ctx_isp->irq_timestamps = epoch_hw_event_data->irq_mono_boot_time;
+
return 0;
}
@@ -960,6 +1062,14 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp,
ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
ctx_isp->boot_timestamp = sof_event_data->boot_time;
+ if (ctx_isp->frame_id == 1)
+ ctx_isp->irq_timestamps = sof_event_data->irq_mono_boot_time;
+ else if (ctx_isp->fps && ((sof_event_data->irq_mono_boot_time -
+ ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps)))
+ ctx_isp->irq_delay_detect = true;
+
+ ctx_isp->irq_timestamps = sof_event_data->irq_mono_boot_time;
+
if (list_empty(&ctx->active_req_list))
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
else
@@ -1442,7 +1552,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
{
int rc = 0;
struct cam_ctx_request *req = NULL;
- struct cam_isp_ctx_req *req_isp;
+ struct cam_isp_ctx_req *req_isp = NULL;
struct cam_context *ctx = ctx_isp->base;
if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) {
@@ -1466,6 +1576,9 @@ static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
"receive rup in unexpected state");
}
+ if (req_isp && req_isp->hw_update_data.fps)
+ ctx_isp->fps = req_isp->hw_update_data.fps;
+
end:
return rc;
}
@@ -1476,7 +1589,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state(
int rc = 0;
struct cam_ctx_request *req = NULL;
struct cam_context *ctx = ctx_isp->base;
- struct cam_isp_ctx_req *req_isp;
+ struct cam_isp_ctx_req *req_isp = NULL;
struct cam_req_mgr_trigger_notify notify;
uint64_t request_id = 0;
@@ -1499,6 +1612,9 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state(
list_add_tail(&req->list, &ctx->free_req_list);
}
+ if (req_isp && req_isp->hw_update_data.fps)
+ ctx_isp->fps = req_isp->hw_update_data.fps;
+
/*
* This function only called directly from applied and bubble applied
* state so change substate here.
@@ -1922,16 +2038,19 @@ static int __cam_isp_ctx_flush_req_in_top_state(
struct cam_req_mgr_flush_request *flush_req)
{
int rc = 0;
- struct cam_isp_context *ctx_isp;
-
- ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
+ struct cam_isp_context *ctx_isp =
+ (struct cam_isp_context *) ctx->ctx_priv;
+ struct cam_isp_stop_args stop_isp;
+ struct cam_hw_stop_args stop_args;
+ struct cam_isp_start_args start_isp;
+ struct cam_hw_reset_args reset_args;
if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
- CAM_INFO(CAM_ISP, "Last request id to flush is %lld",
- flush_req->req_id);
+ CAM_INFO(CAM_ISP, "ctx id:%d Last request id to flush is %lld",
+ ctx->ctx_id, flush_req->req_id);
ctx->last_flush_req = flush_req->req_id;
}
- CAM_DBG(CAM_ISP, "try to flush pending list");
+ CAM_DBG(CAM_ISP, "ctx id:%d try to flush pending list", ctx->ctx_id);
spin_lock_bh(&ctx->lock);
rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
@@ -1954,6 +2073,57 @@ static int __cam_isp_ctx_flush_req_in_top_state(
spin_unlock_bh(&ctx->lock);
atomic_set(&ctx_isp->process_bubble, 0);
+ if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
+ /* if active and wait list are empty, return */
+ spin_lock_bh(&ctx->lock);
+ if ((list_empty(&ctx->wait_req_list)) &&
+ (list_empty(&ctx->active_req_list))) {
+ spin_unlock_bh(&ctx->lock);
+ CAM_DBG(CAM_ISP, "ctx id:%d active,wait list are empty",
+ ctx->ctx_id);
+ goto end;
+ }
+ spin_unlock_bh(&ctx->lock);
+
+ /* Stop hw first before active list flush */
+ CAM_DBG(CAM_ISP, "ctx id:%d try to stop hw", ctx->ctx_id);
+ stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+ stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY;
+ stop_isp.stop_only = true;
+ stop_args.args = (void *)&stop_isp;
+ ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
+ &stop_args);
+
+ spin_lock_bh(&ctx->lock);
+ CAM_DBG(CAM_ISP, "try to flush wait list");
+ rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list,
+ flush_req);
+ CAM_DBG(CAM_ISP, "try to flush active list");
+ rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list,
+ flush_req);
+ ctx_isp->active_req_cnt = 0;
+ spin_unlock_bh(&ctx->lock);
+
+ CAM_DBG(CAM_ISP, "try to reset hw");
+ /* Reset hw */
+ reset_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+ rc = ctx->hw_mgr_intf->hw_reset(ctx->hw_mgr_intf->hw_mgr_priv,
+ &reset_args);
+ if (rc)
+ goto end;
+
+ CAM_DBG(CAM_ISP, "ctx id%d try to start hw", ctx->ctx_id);
+ /* Start hw */
+ start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx;
+ start_isp.start_only = true;
+ start_isp.hw_config.priv = NULL;
+
+ rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
+ &start_isp);
+ }
+
+end:
+ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
return rc;
}
@@ -2339,7 +2509,7 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state(
{
struct cam_ctx_request *req;
struct cam_context *ctx = ctx_isp->base;
- struct cam_isp_ctx_req *req_isp;
+ struct cam_isp_ctx_req *req_isp = NULL;
struct cam_req_mgr_trigger_notify notify;
uint64_t request_id = 0;
@@ -2394,6 +2564,9 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state(
jiffies_to_msecs(jiffies);
}
+ if (req_isp && req_isp->hw_update_data.fps)
+ ctx_isp->fps = req_isp->hw_update_data.fps;
+
__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
CAM_REQ_MGR_SOF_EVENT_SUCCESS);
CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
@@ -2669,7 +2842,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
{
int rc = 0, i;
struct cam_ctx_request *req = NULL;
- struct cam_isp_ctx_req *req_isp;
+ struct cam_isp_ctx_req *req_isp = NULL;
uintptr_t packet_addr;
struct cam_packet *packet;
size_t len = 0;
@@ -2758,6 +2931,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
rc = -EFAULT;
goto free_cpu_buf;
}
+
req_isp->num_cfg = cfg.num_hw_update_entries;
req_isp->num_fence_map_out = cfg.num_out_map_entries;
req_isp->num_fence_map_in = cfg.num_in_map_entries;
@@ -2814,6 +2988,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
CAM_ERR(CAM_ISP, "Recevied Update in wrong state");
}
}
+
if (rc)
goto put_ref;
@@ -3595,8 +3770,6 @@ static int __cam_isp_ctx_apply_req(struct cam_context *ctx,
return rc;
}
-
-
static int __cam_isp_ctx_handle_irq_in_activated(void *context,
uint32_t evt_id, void *evt_data)
{
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
index a4f4e5ae0ee9..cb73252363db 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
@@ -35,6 +35,11 @@
#define CAM_ISP_CTX_CFG_MAX 22
/*
+ * Defalut fps value set to 30
+ */
+#define CAM_ISP_CTX_DEFAULT_FPS 30
+
+/*
* Maximum entries in state monitoring array for error logging
*/
#define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES 20
@@ -180,6 +185,9 @@ struct cam_isp_context_req_id_info {
* @hw_acquired: Indicate whether HW resources are acquired
* @init_received: Indicate whether init config packet is received
* @split_acquire: Indicate whether a separate acquire is expected
+ * @irq_delay_detect: Indicate whether a irq delay has detected or not
+ * @irq_timestamps: Timestamp from last handled IRQ
+ * @fps: Current FPS for the activated state.
*
*/
struct cam_isp_context {
@@ -209,6 +217,9 @@ struct cam_isp_context {
bool hw_acquired;
bool init_received;
bool split_acquire;
+ bool irq_delay_detect;
+ uint64_t irq_timestamps;
+ uint32_t fps;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 3b6d04a302ed..c0b8c66fad31 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -146,6 +146,74 @@ static int cam_ife_hw_mgr_is_rdi_res(uint32_t res_id)
return rc;
}
+static const char *cam_ife_hw_mgr_get_res_id(
+ enum cam_ife_pix_path_res_id csid_res_id)
+{
+ char *res_name = NULL;
+
+ switch (csid_res_id) {
+ case CAM_IFE_PIX_PATH_RES_RDI_0:
+ res_name = "RDI_0";
+ break;
+ case CAM_IFE_PIX_PATH_RES_RDI_1:
+ res_name = "RDI_1";
+ break;
+ case CAM_IFE_PIX_PATH_RES_RDI_2:
+ res_name = "RDI_2";
+ break;
+ case CAM_IFE_PIX_PATH_RES_RDI_3:
+ res_name = "RDI_3";
+ break;
+ case CAM_IFE_PIX_PATH_RES_IPP:
+ res_name = "IPP";
+ break;
+ case CAM_IFE_PIX_PATH_RES_PPP:
+ res_name = "PPP";
+ break;
+ case CAM_IFE_PIX_PATH_RES_MAX:
+ res_name = "Invalid Max res";
+ break;
+ default:
+ res_name = "Invalid";
+ break;
+ }
+ return res_name;
+}
+
+static const char *cam_ife_hw_mgr_get_res_type(
+ enum cam_isp_resource_type csid_res_type)
+{
+ char *res_type = NULL;
+
+ switch (csid_res_type) {
+ case CAM_ISP_RESOURCE_UNINT:
+ res_type = "Unint";
+ break;
+ case CAM_ISP_RESOURCE_SRC:
+ res_type = "Src";
+ break;
+ case CAM_ISP_RESOURCE_CID:
+ res_type = "Cid";
+ break;
+ case CAM_ISP_RESOURCE_PIX_PATH:
+ res_type = "Pix Path";
+ break;
+ case CAM_ISP_RESOURCE_VFE_IN:
+ res_type = "Vfe In";
+ break;
+ case CAM_ISP_RESOURCE_VFE_OUT:
+ res_type = "Vfe Out";
+ break;
+ case CAM_ISP_RESOURCE_MAX:
+ res_type = "Invalid Max res";
+ break;
+ default:
+ res_type = "Invalid";
+ break;
+ }
+ return res_type;
+}
+
static int cam_ife_hw_mgr_reset_csid_res(
struct cam_ife_hw_mgr_res *isp_hw_res)
{
@@ -599,6 +667,61 @@ static int cam_ife_hw_mgr_get_ctx(
return rc;
}
+static void cam_ife_hw_mgr_dump_all_ctx(
+ struct cam_ife_hw_mgr_ctx *ife_ctx)
+{
+ uint32_t i;
+ struct cam_ife_hw_mgr_ctx *ctx;
+ struct cam_ife_hw_mgr_res *hw_mgr;
+
+ mutex_lock(&g_ife_hw_mgr.ctx_mutex);
+ list_for_each_entry(ctx, &g_ife_hw_mgr.used_ctx_list, list) {
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "ctx id:%d dual:%d in src:%d num_base:%d rdi only:%d",
+ ctx->ctx_index,
+ ctx->res_list_ife_in.is_dual_vfe,
+ ctx->res_list_ife_in.res_id,
+ ctx->num_base, ctx->is_rdi_only_context);
+ list_for_each_entry(hw_mgr, &ctx->res_list_ife_csid,
+ list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!hw_mgr->hw_res[i])
+ continue;
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "csid:%d res_type:%s id:%s state:%d",
+ hw_mgr->hw_res[i]->hw_intf->hw_idx,
+ cam_ife_hw_mgr_get_res_type(
+ hw_mgr->hw_res[i]->res_type),
+ cam_ife_hw_mgr_get_res_id(
+ hw_mgr->hw_res[i]->res_id),
+ hw_mgr->hw_res[i]->res_state);
+ }
+ }
+ list_for_each_entry(hw_mgr, &ctx->res_list_ife_src,
+ list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!hw_mgr->hw_res[i])
+ continue;
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "Src IFE:%d res_type:%s id:%s state:%d",
+ hw_mgr->hw_res[i]->hw_intf->hw_idx,
+ cam_ife_hw_mgr_get_res_type(
+ hw_mgr->hw_res[i]->res_type),
+ cam_ife_hw_mgr_get_res_id(
+ hw_mgr->hw_res[i]->res_id),
+ hw_mgr->hw_res[i]->res_state);
+ }
+ }
+ }
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "Current ctx id:%d dual:%d in src:%d num_base:%d rdi only:%d",
+ ife_ctx->ctx_index,
+ ife_ctx->res_list_ife_in.is_dual_vfe,
+ ife_ctx->res_list_ife_in.res_id,
+ ife_ctx->num_base, ife_ctx->is_rdi_only_context);
+ mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
+}
+
static void cam_ife_mgr_add_base_info(
struct cam_ife_hw_mgr_ctx *ctx,
enum cam_isp_hw_split_id split_id,
@@ -1509,8 +1632,9 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl(
&csid_acquire, sizeof(csid_acquire));
if (rc) {
CAM_ERR(CAM_ISP,
- "Cannot acquire ife csid pxl path rsrc %s",
- (is_ipp) ? "IPP" : "PPP");
+ "Cannot acquire ife csid pxl path rsrc %s, hw=%d rc=%d",
+ (is_ipp) ? "IPP" : "PPP",
+ hw_intf->hw_idx, rc);
goto put_res;
}
@@ -1622,7 +1746,6 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
"CSID Path reserve failed hw=%d rc=%d cid=%d",
hw_intf->hw_idx, rc,
cid_res->hw_res[0]->res_id);
-
goto put_res;
}
@@ -2018,6 +2141,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
return 0;
free_res:
+ /*Dump all the current acquired resources */
+ cam_ife_hw_mgr_dump_all_ctx(ife_ctx);
cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx);
free_cdm:
cam_cdm_release(ife_ctx->cdm_handle);
@@ -2172,11 +2297,13 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args)
ife_ctx->ctx_in_use = 1;
cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx);
-
CAM_DBG(CAM_ISP, "Exit...(success)");
return 0;
+
free_res:
+ /*Dump all the current acquired resources */
+ cam_ife_hw_mgr_dump_all_ctx(ife_ctx);
cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx);
cam_cdm_release(ife_ctx->cdm_handle);
free_ctx:
@@ -2572,6 +2699,11 @@ static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE);
}
+static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
+{
+ return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE);
+}
+
/* entry function: stop_hw */
static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
{
@@ -2925,6 +3057,9 @@ start_only:
CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d",
ctx->ctx_index);
+ if (start_isp->start_only)
+ cam_ife_mgr_resume_hw(ctx);
+
/* start the IFE out devices */
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
rc = cam_ife_hw_mgr_start_hw_res(
@@ -3025,6 +3160,44 @@ static int cam_ife_mgr_write(void *hw_mgr_priv, void *write_args)
return -EPERM;
}
+static int cam_ife_mgr_reset(void *hw_mgr_priv, void *hw_reset_args)
+{
+ struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_hw_reset_args *reset_args = hw_reset_args;
+ struct cam_ife_hw_mgr_ctx *ctx;
+ struct cam_ife_hw_mgr_res *hw_mgr_res;
+ uint32_t i;
+ int rc = 0;
+
+ if (!hw_mgr_priv || !hw_reset_args) {
+ CAM_ERR(CAM_ISP, "Invalid arguments");
+ return -EINVAL;
+ }
+
+ ctx = (struct cam_ife_hw_mgr_ctx *)reset_args->ctxt_to_hw_map;
+ if (!ctx || !ctx->ctx_in_use) {
+ CAM_ERR(CAM_ISP, "Invalid context is used");
+ return -EPERM;
+ }
+
+ CAM_DBG(CAM_ISP, "reset csid and vfe hw");
+ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid,
+ list) {
+ rc = cam_ife_hw_mgr_reset_csid_res(hw_mgr_res);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "Failed RESET (%d) rc:%d",
+ hw_mgr_res->res_id, rc);
+ goto end;
+ }
+ }
+
+ for (i = 0; i < ctx->num_base; i++)
+ rc = cam_ife_mgr_reset_vfe_hw(hw_mgr, ctx->base[i].idx);
+
+end:
+ return rc;
+}
+
static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
void *release_hw_args)
{
@@ -3152,6 +3325,54 @@ static int cam_isp_blob_fe_update(
return rc;
}
+static int cam_isp_blob_fps_config(
+ uint32_t blob_type,
+ struct cam_isp_generic_blob_info *blob_info,
+ struct cam_fps_config *fps_config,
+ struct cam_hw_prepare_update_args *prepare)
+{
+ struct cam_ife_hw_mgr_ctx *ctx = NULL;
+ struct cam_ife_hw_mgr_res *hw_mgr_res;
+ struct cam_hw_intf *hw_intf;
+ struct cam_vfe_fps_config_args fps_config_args;
+ int rc = -EINVAL;
+ uint32_t i;
+
+ ctx = prepare->ctxt_to_hw_map;
+
+ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!hw_mgr_res->hw_res[i])
+ continue;
+
+ if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) {
+ hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+ if (hw_intf && hw_intf->hw_ops.process_cmd) {
+ fps_config_args.fps =
+ fps_config->fps;
+ fps_config_args.node_res =
+ hw_mgr_res->hw_res[i];
+
+ rc = hw_intf->hw_ops.process_cmd(
+ hw_intf->hw_priv,
+ CAM_ISP_HW_CMD_FPS_CONFIG,
+ &fps_config_args,
+ sizeof(
+ struct cam_vfe_fps_config_args)
+ );
+ if (rc)
+ CAM_ERR(CAM_ISP,
+ "Failed fps config:%d",
+ fps_config->fps);
+ } else
+ CAM_WARN(CAM_ISP, "NULL hw_intf!");
+ }
+ }
+ }
+
+ return rc;
+}
+
static int cam_isp_blob_ubwc_update(
uint32_t blob_type,
struct cam_isp_generic_blob_info *blob_info,
@@ -3528,6 +3749,75 @@ static int cam_isp_blob_clock_update(
return rc;
}
+static int cam_isp_blob_sensor_config(
+ uint32_t blob_type,
+ struct cam_isp_generic_blob_info *blob_info,
+ struct cam_isp_sensor_config *dim_config,
+ struct cam_hw_prepare_update_args *prepare)
+{
+ struct cam_ife_hw_mgr_ctx *ctx = NULL;
+ struct cam_ife_hw_mgr_res *hw_mgr_res;
+ struct cam_hw_intf *hw_intf;
+ struct cam_ife_sensor_dimension_update_args update_args;
+ int rc = -EINVAL, found = 0;
+ uint32_t i, j;
+ struct cam_isp_sensor_dimension *path_config;
+
+ ctx = prepare->ctxt_to_hw_map;
+
+ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!hw_mgr_res->hw_res[i])
+ continue;
+ found = 1;
+ hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+ if (hw_intf && hw_intf->hw_ops.process_cmd) {
+ path_config = &(dim_config->ipp_path);
+ update_args.ipp_path.width =
+ path_config->width;
+ update_args.ipp_path.height =
+ path_config->height;
+ update_args.ipp_path.measure_enabled =
+ path_config->measure_enabled;
+ path_config = &(dim_config->ppp_path);
+ update_args.ppp_path.width =
+ path_config->width;
+ update_args.ppp_path.height =
+ path_config->height;
+ update_args.ppp_path.measure_enabled =
+ path_config->measure_enabled;
+ for (j = 0; j < CAM_IFE_RDI_NUM_MAX; j++) {
+ path_config =
+ &(dim_config->rdi_path[j]);
+ update_args.rdi_path[j].width =
+ path_config->width;
+ update_args.rdi_path[j].height =
+ path_config->height;
+ update_args.rdi_path[j].measure_enabled =
+ path_config->measure_enabled;
+ }
+ rc = hw_intf->hw_ops.process_cmd(
+ hw_intf->hw_priv,
+ CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG,
+ &update_args,
+ sizeof(
+ struct
+ cam_ife_sensor_dimension_update_args)
+ );
+ if (rc)
+ CAM_ERR(CAM_ISP,
+ "Dimension Update failed");
+ } else
+ CAM_ERR(CAM_ISP, "hw_intf is NULL");
+ }
+ if (found)
+ break;
+ }
+
+ return rc;
+}
+
+
void fill_res_bitmap(uint32_t resource_type, unsigned long *res_bitmap)
{
@@ -3620,12 +3910,6 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
return -EINVAL;
}
- if (blob_type >= CAM_ISP_GENERIC_BLOB_TYPE_MAX) {
- CAM_WARN(CAM_ISP, "Invalid Blob Type %d Max %d", blob_type,
- CAM_ISP_GENERIC_BLOB_TYPE_MAX);
- return 0;
- }
-
prepare = blob_info->prepare;
if (!prepare) {
CAM_ERR(CAM_ISP, "Failed. prepare is NULL, blob_type %d",
@@ -3633,7 +3917,6 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
return -EINVAL;
}
- CAM_DBG(CAM_ISP, "FS2: BLOB Type: %d", blob_type);
switch (blob_type) {
case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: {
struct cam_isp_resource_hfr_config *hfr_config;
@@ -3868,6 +4151,49 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
CAM_ERR(CAM_ISP, "Init Frame drop Update Failed");
}
break;
+ case CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_DIMENSION_CONFIG: {
+ struct cam_isp_sensor_config *csid_dim_config;
+
+ if (blob_size < sizeof(struct cam_isp_sensor_config)) {
+ CAM_ERR(CAM_ISP, "Invalid blob size %u expected %u",
+ blob_size,
+ sizeof(struct cam_isp_sensor_config));
+ return -EINVAL;
+ }
+
+ csid_dim_config =
+ (struct cam_isp_sensor_config *)blob_data;
+
+ rc = cam_isp_blob_sensor_config(blob_type, blob_info,
+ csid_dim_config, prepare);
+ if (rc)
+ CAM_ERR(CAM_ISP,
+ "Sensor Dimension Update Failed rc: %d", rc);
+ }
+ break;
+ case CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG: {
+ struct cam_fps_config *fps_config;
+ struct cam_isp_prepare_hw_update_data *prepare_hw_data;
+
+ if (blob_size < sizeof(struct cam_fps_config)) {
+ CAM_ERR(CAM_ISP, "Invalid fps blob size %u expected %u",
+ blob_size, sizeof(struct cam_fps_config));
+ return -EINVAL;
+ }
+
+ fps_config = (struct cam_fps_config *)blob_data;
+ prepare_hw_data = (struct cam_isp_prepare_hw_update_data *)
+ prepare->priv;
+
+ prepare_hw_data->fps = fps_config->fps;
+
+ rc = cam_isp_blob_fps_config(blob_type, blob_info,
+ fps_config, prepare);
+ if (rc)
+ CAM_ERR(CAM_ISP, "FPS Update Failed rc: %d", rc);
+
+ }
+ break;
default:
CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
break;
@@ -4025,10 +4351,6 @@ end:
return rc;
}
-static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
-{
- return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE);
-}
static int cam_ife_mgr_sof_irq_debug(
struct cam_ife_hw_mgr_ctx *ctx,
@@ -4766,6 +5088,8 @@ static int cam_ife_hw_mgr_handle_reg_update(
break;
if (!rup_status) {
+ rup_event_data.irq_mono_boot_time =
+ evt_payload->ts.time_usecs;
ife_hwr_irq_rup_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_REG_UPDATE,
@@ -4795,6 +5119,8 @@ static int cam_ife_hw_mgr_handle_reg_update(
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!rup_status) {
+ rup_event_data.irq_mono_boot_time =
+ evt_payload->ts.time_usecs;
/* Send the Reg update hw event */
ife_hwr_irq_rup_cb(
ife_hwr_mgr_ctx->common.cb_priv,
@@ -5154,6 +5480,8 @@ static int cam_ife_hw_mgr_handle_sof(
ife_hw_mgr_ctx,
&sof_done_event_data.timestamp,
&sof_done_event_data.boot_time);
+ sof_done_event_data.irq_mono_boot_time =
+ evt_payload->ts.time_usecs;
ife_hw_irq_sof_cb(
ife_hw_mgr_ctx->common.cb_priv,
@@ -5177,6 +5505,8 @@ static int cam_ife_hw_mgr_handle_sof(
ife_hw_mgr_ctx,
&sof_done_event_data.timestamp,
&sof_done_event_data.boot_time);
+ sof_done_event_data.irq_mono_boot_time =
+ evt_payload->ts.time_usecs;
ife_hw_irq_sof_cb(
ife_hw_mgr_ctx->common.cb_priv,
@@ -5262,13 +5592,15 @@ static int cam_ife_hw_mgr_handle_eof_for_camif_hw_res(
if (atomic_read(
&ife_hwr_mgr_ctx->overflow_pending))
break;
- if (!eof_status)
+ if (!eof_status) {
+ eof_done_event_data.irq_mono_boot_time =
+ evt_payload->ts.time_usecs;
ife_hwr_irq_eof_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_EOF,
&eof_done_event_data);
+ }
}
-
break;
/* Handling dual VFE Scenario */
case 1:
@@ -5309,11 +5641,14 @@ static int cam_ife_hw_mgr_handle_eof_for_camif_hw_res(
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
- if (!rc)
+ if (!rc) {
+ eof_done_event_data.irq_mono_boot_time =
+ evt_payload->ts.time_usecs;
ife_hwr_irq_eof_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_EOF,
&eof_done_event_data);
+ }
break;
@@ -5413,6 +5748,8 @@ static int cam_ife_hw_mgr_handle_buf_done_for_hw_res(
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
+ buf_done_event_data.irq_mono_boot_time =
+ evt_payload->ts.time_usecs;
/* Report for Successful buf_done event if any */
if (buf_done_event_data.num_handles > 0 &&
ife_hwr_irq_wm_done_cb) {
@@ -5852,6 +6189,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update;
hw_mgr_intf->hw_config = cam_ife_mgr_config_hw;
hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd;
+ hw_mgr_intf->hw_reset = cam_ife_mgr_reset;
if (iommu_hdl)
*iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
index 096e0f186bbf..1ab9361af1d1 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
@@ -130,6 +130,7 @@ struct cam_isp_bw_config_internal {
* @bw_config: BW config information
* @bw_config_valid: Flag indicating whether the bw_config at the index
* is valid or not
+ * @fps: fps vaue which has been updated in hw
*
*/
struct cam_isp_prepare_hw_update_data {
@@ -137,40 +138,47 @@ struct cam_isp_prepare_hw_update_data {
struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX];
struct cam_isp_bw_config_internal_ab bw_config_ab[CAM_IFE_HW_NUM_MAX];
bool bw_config_valid[CAM_IFE_HW_NUM_MAX];
+ uint32_t fps;
};
/**
* struct cam_isp_hw_sof_event_data - Event payload for CAM_HW_EVENT_SOF
*
- * @timestamp: Time stamp for the sof event
- * @boot_time: Boot time stamp for the sof event
+ * @timestamp: Time stamp for the sof event
+ * @boot_time: Boot time stamp for the sof event
+ * @irq_mono_boot_time: Time stamp till the execution of IRQ wrt event started
*
*/
struct cam_isp_hw_sof_event_data {
uint64_t timestamp;
uint64_t boot_time;
+ uint64_t irq_mono_boot_time;
};
/**
* struct cam_isp_hw_reg_update_event_data - Event payload for
* CAM_HW_EVENT_REG_UPDATE
*
- * @timestamp: Time stamp for the reg update event
+ * @timestamp: Time stamp for the reg update event
+ * @irq_mono_boot_time: Time stamp till the execution of IRQ wrt event started
*
*/
struct cam_isp_hw_reg_update_event_data {
uint64_t timestamp;
+ uint64_t irq_mono_boot_time;
};
/**
* struct cam_isp_hw_epoch_event_data - Event payload for CAM_HW_EVENT_EPOCH
*
- * @timestamp: Time stamp for the epoch event
+ * @timestamp: Time stamp for the epoch event
+ * @irq_mono_boot_time: Time stamp till the execution of this event started
*
*/
struct cam_isp_hw_epoch_event_data {
uint64_t timestamp;
+ uint64_t irq_mono_boot_time;
};
/**
@@ -179,6 +187,7 @@ struct cam_isp_hw_epoch_event_data {
* @num_handles: Number of resource handeles
* @resource_handle: Resource handle array
* @timestamp: Timestamp for the buf done event
+ * @irq_mono_boot_time: Time stamp till the execution of this event started
*
*/
struct cam_isp_hw_done_event_data {
@@ -186,16 +195,19 @@ struct cam_isp_hw_done_event_data {
uint32_t resource_handle[
CAM_NUM_OUT_PER_COMP_IRQ_MAX];
uint64_t timestamp;
+ uint64_t irq_mono_boot_time;
};
/**
* struct cam_isp_hw_eof_event_data - Event payload for CAM_HW_EVENT_EOF
*
* @timestamp: Timestamp for the eof event
+ * @irq_mono_boot_time: Time stamp till the execution of this event started
*
*/
struct cam_isp_hw_eof_event_data {
uint64_t timestamp;
+ uint64_t irq_mono_boot_time;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h
index 0e58617e1956..6254b97c436a 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, 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
@@ -293,6 +293,10 @@ static struct cam_ife_csid_common_reg_offset
.ppp_irq_mask_all = 0x0,
.measure_en_hbi_vbi_cnt_mask = 0xC,
.format_measure_en_val = 1,
+ .format_measure_height_mask_val = 0xFFFF,
+ .format_measure_height_shift_val = 0x10,
+ .format_measure_width_mask_val = 0xFFFF,
+ .format_measure_width_shift_val = 0x0,
};
static struct cam_ife_csid_reg_offset cam_ife_csid_170_reg_offset = {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h
index 46dec6e4156a..680b641038cf 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, 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
@@ -334,6 +334,10 @@ static struct cam_ife_csid_common_reg_offset
.ppp_irq_mask_all = 0xFFFF,
.measure_en_hbi_vbi_cnt_mask = 0xC,
.format_measure_en_val = 1,
+ .format_measure_height_mask_val = 0xFFFF,
+ .format_measure_height_shift_val = 0x10,
+ .format_measure_width_mask_val = 0xFFFF,
+ .format_measure_width_shift_val = 0x0,
};
static struct cam_ife_csid_reg_offset cam_ife_csid_175_reg_offset = {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h
index 1d6f7715add6..48570dad5f37 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, 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
@@ -350,6 +350,10 @@ static struct cam_ife_csid_common_reg_offset
.ppp_irq_mask_all = 0xFFFF,
.measure_en_hbi_vbi_cnt_mask = 0xC,
.format_measure_en_val = 1,
+ .format_measure_height_mask_val = 0xFFFF,
+ .format_measure_height_shift_val = 0x10,
+ .format_measure_width_mask_val = 0xFFFF,
+ .format_measure_width_shift_val = 0x0,
};
static struct cam_ife_csid_reg_offset cam_ife_csid_175_200_reg_offset = {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 5ab397bb7bf8..a3fce7733503 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -79,7 +79,7 @@ static int cam_ife_csid_is_ipp_ppp_format_supported(
static int cam_ife_csid_get_format_rdi(
uint32_t in_format, uint32_t out_format,
- uint32_t *decode_fmt, uint32_t *plain_fmt)
+ uint32_t *decode_fmt, uint32_t *plain_fmt, uint32_t *in_bpp)
{
int rc = 0;
@@ -97,6 +97,7 @@ static int cam_ife_csid_get_format_rdi(
rc = -EINVAL;
break;
}
+ *in_bpp = 6;
break;
case CAM_FORMAT_MIPI_RAW_8:
switch (out_format) {
@@ -112,6 +113,7 @@ static int cam_ife_csid_get_format_rdi(
rc = -EINVAL;
break;
}
+ *in_bpp = 8;
break;
case CAM_FORMAT_MIPI_RAW_10:
switch (out_format) {
@@ -127,6 +129,7 @@ static int cam_ife_csid_get_format_rdi(
rc = -EINVAL;
break;
}
+ *in_bpp = 10;
break;
case CAM_FORMAT_MIPI_RAW_12:
switch (out_format) {
@@ -141,6 +144,7 @@ static int cam_ife_csid_get_format_rdi(
rc = -EINVAL;
break;
}
+ *in_bpp = 12;
break;
case CAM_FORMAT_MIPI_RAW_14:
switch (out_format) {
@@ -155,6 +159,7 @@ static int cam_ife_csid_get_format_rdi(
rc = -EINVAL;
break;
}
+ *in_bpp = 14;
break;
case CAM_FORMAT_MIPI_RAW_16:
switch (out_format) {
@@ -169,6 +174,7 @@ static int cam_ife_csid_get_format_rdi(
rc = -EINVAL;
break;
}
+ *in_bpp = 16;
break;
case CAM_FORMAT_MIPI_RAW_20:
switch (out_format) {
@@ -183,6 +189,7 @@ static int cam_ife_csid_get_format_rdi(
rc = -EINVAL;
break;
}
+ *in_bpp = 20;
break;
case CAM_FORMAT_DPCM_10_6_10:
*decode_fmt = 0x7;
@@ -567,10 +574,6 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw,
init_completion(complete);
reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all;
- /* Enable the Test gen before reset */
- cam_io_w_mb(1, csid_hw->hw_info->soc_info.reg_map[0].mem_base +
- csid_reg->tpg_reg->csid_tpg_ctrl_addr);
-
/* Reset the corresponding ife csid path */
cam_io_w_mb(reset_strb_val, soc_info->reg_map[0].mem_base +
reset_strb_addr);
@@ -585,10 +588,6 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw,
rc = -ETIMEDOUT;
}
- /* Disable Test Gen after reset*/
- cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
- csid_reg->tpg_reg->csid_tpg_ctrl_addr);
-
end:
return rc;
@@ -1168,6 +1167,11 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw)
for (i = 0; i < CAM_IFE_PIX_PATH_RES_MAX; i++)
csid_hw->res_sof_cnt[i] = 0;
+ csid_hw->ipp_path_config.measure_enabled = 0;
+ csid_hw->ppp_path_config.measure_enabled = 0;
+ for (i = 0; i <= CAM_IFE_PIX_PATH_RES_RDI_3; i++)
+ csid_hw->rdi_path_config[i].measure_enabled = 0;
+
csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN;
csid_hw->error_irq_count = 0;
csid_hw->first_sof_ts = 0;
@@ -1626,6 +1630,7 @@ static int cam_ife_csid_init_config_pxl_path(
const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL;
bool is_ipp;
uint32_t decode_format = 0, plain_format = 0, val = 0;
+ struct cam_isp_sensor_dimension *path_config;
path_data = (struct cam_ife_csid_path_cfg *) res->res_priv;
csid_reg = csid_hw->csid_info->csid_reg;
@@ -1634,9 +1639,11 @@ static int cam_ife_csid_init_config_pxl_path(
if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) {
is_ipp = true;
pxl_reg = csid_reg->ipp_reg;
+ path_config = &(csid_hw->ipp_path_config);
} else {
is_ipp = false;
pxl_reg = csid_reg->ppp_reg;
+ path_config = &(csid_hw->ppp_path_config);
}
if (!pxl_reg) {
@@ -1705,6 +1712,24 @@ static int cam_ife_csid_init_config_pxl_path(
}
}
+ /* configure pixel format measure */
+ if (path_config->measure_enabled) {
+ val = (((path_config->height &
+ csid_reg->cmn_reg->format_measure_height_mask_val) <<
+ csid_reg->cmn_reg->format_measure_height_shift_val) |
+ (path_config->width &
+ csid_reg->cmn_reg->format_measure_width_mask_val));
+ CAM_DBG(CAM_ISP, "CSID:%d format measure cfg1 value : 0x%x",
+ csid_hw->hw_intf->hw_idx, val);
+
+ cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+ pxl_reg->csid_pxl_format_measure_cfg1_addr);
+
+ /* enable pixel and line counter */
+ cam_io_w_mb(3, soc_info->reg_map[0].mem_base +
+ pxl_reg->csid_pxl_format_measure_cfg0_addr);
+ }
+
/* set frame drop pattern to 0 and period to 1 */
cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
pxl_reg->csid_pxl_frm_drop_period_addr);
@@ -1850,6 +1875,7 @@ static int cam_ife_csid_enable_pxl_path(
const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL;
bool is_ipp;
uint32_t val = 0, path_status;
+ struct cam_isp_sensor_dimension *path_config;
path_data = (struct cam_ife_csid_path_cfg *) res->res_priv;
csid_reg = csid_hw->csid_info->csid_reg;
@@ -1858,9 +1884,11 @@ static int cam_ife_csid_enable_pxl_path(
if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) {
is_ipp = true;
pxl_reg = csid_reg->ipp_reg;
+ path_config = &(csid_hw->ipp_path_config);
} else {
is_ipp = false;
pxl_reg = csid_reg->ppp_reg;
+ path_config = &(csid_hw->ppp_path_config);
}
if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) {
@@ -1921,6 +1949,10 @@ static int cam_ife_csid_enable_pxl_path(
if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)
val |= CSID_PATH_INFO_INPUT_EOF;
+ if (path_config->measure_enabled)
+ val |= (CSID_PATH_ERROR_PIX_COUNT |
+ CSID_PATH_ERROR_LINE_COUNT);
+
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
pxl_reg->csid_pxl_irq_mask_addr);
@@ -2021,7 +2053,7 @@ static int cam_ife_csid_init_config_rdi_path(
struct cam_ife_csid_path_cfg *path_data;
const struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
- uint32_t path_format = 0, plain_fmt = 0, val = 0, id;
+ uint32_t path_format = 0, plain_fmt = 0, val = 0, id, in_bpp = 0;
uint32_t format_measure_addr;
path_data = (struct cam_ife_csid_path_cfg *) res->res_priv;
@@ -2036,7 +2068,7 @@ static int cam_ife_csid_init_config_rdi_path(
}
rc = cam_ife_csid_get_format_rdi(path_data->in_format,
- path_data->out_format, &path_format, &plain_fmt);
+ path_data->out_format, &path_format, &plain_fmt, &in_bpp);
if (rc)
return rc;
@@ -2085,6 +2117,32 @@ static int cam_ife_csid_init_config_rdi_path(
CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x",
csid_hw->hw_intf->hw_idx, val);
}
+
+ /* configure pixel format measure */
+ if (csid_hw->rdi_path_config[id].measure_enabled) {
+ val = ((csid_hw->rdi_path_config[id].height &
+ csid_reg->cmn_reg->format_measure_height_mask_val) <<
+ csid_reg->cmn_reg->format_measure_height_shift_val);
+
+ if (path_format == 0xF)
+ val |= (((csid_hw->rdi_path_config[id].width *
+ in_bpp) / 8) &
+ csid_reg->cmn_reg->format_measure_width_mask_val);
+ else
+ val |= (csid_hw->rdi_path_config[id].width &
+ csid_reg->cmn_reg->format_measure_width_mask_val);
+
+ CAM_DBG(CAM_ISP, "CSID:%d format measure cfg1 value : 0x%x",
+ csid_hw->hw_intf->hw_idx, val);
+
+ cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg1_addr);
+
+ /* enable pixel and line counter */
+ cam_io_w_mb(3, soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg0_addr);
+ }
+
/* set frame drop pattern to 0 and period to 1 */
cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
csid_reg->rdi_reg[id]->csid_rdi_frm_drop_period_addr);
@@ -2257,6 +2315,10 @@ static int cam_ife_csid_enable_rdi_path(
if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)
val |= CSID_PATH_INFO_INPUT_EOF;
+ if (csid_hw->rdi_path_config[id].measure_enabled)
+ val |= (CSID_PATH_ERROR_PIX_COUNT |
+ CSID_PATH_ERROR_LINE_COUNT);
+
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
@@ -2710,6 +2772,13 @@ static int cam_ife_csid_release(void *hw_priv,
case CAM_ISP_RESOURCE_PIX_PATH:
res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
cam_ife_csid_reset_init_frame_drop(csid_hw);
+ if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP)
+ csid_hw->ipp_path_config.measure_enabled = 0;
+ else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP)
+ csid_hw->ppp_path_config.measure_enabled = 0;
+ else
+ csid_hw->rdi_path_config[res->res_id].measure_enabled
+ = 0;
break;
default:
CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d",
@@ -3141,6 +3210,57 @@ static int cam_ife_csid_set_csid_clock(
return 0;
}
+static int cam_ife_csid_set_sensor_dimension(
+ struct cam_ife_csid_hw *csid_hw, void *cmd_args)
+{
+ struct cam_ife_sensor_dimension_update_args *dimension_update = NULL;
+ uint32_t i;
+
+ if (!csid_hw)
+ return -EINVAL;
+
+ dimension_update =
+ (struct cam_ife_sensor_dimension_update_args *)cmd_args;
+ csid_hw->ipp_path_config.measure_enabled =
+ dimension_update->ipp_path.measure_enabled;
+ if (dimension_update->ipp_path.measure_enabled) {
+ csid_hw->ipp_path_config.width =
+ dimension_update->ipp_path.width;
+ csid_hw->ipp_path_config.height =
+ dimension_update->ipp_path.height;
+ CAM_DBG(CAM_ISP, "CSID ipp path width %d height %d",
+ csid_hw->ipp_path_config.width,
+ csid_hw->ipp_path_config.height);
+ }
+ csid_hw->ppp_path_config.measure_enabled =
+ dimension_update->ppp_path.measure_enabled;
+ if (dimension_update->ppp_path.measure_enabled) {
+ csid_hw->ppp_path_config.width =
+ dimension_update->ppp_path.width;
+ csid_hw->ppp_path_config.height =
+ dimension_update->ppp_path.height;
+ CAM_DBG(CAM_ISP, "CSID ppp path width %d height %d",
+ csid_hw->ppp_path_config.width,
+ csid_hw->ppp_path_config.height);
+ }
+ for (i = 0; i <= CAM_IFE_PIX_PATH_RES_RDI_3; i++) {
+ csid_hw->rdi_path_config[i].measure_enabled
+ = dimension_update->rdi_path[i].measure_enabled;
+ if (csid_hw->rdi_path_config[i].measure_enabled) {
+ csid_hw->rdi_path_config[i].width =
+ dimension_update->rdi_path[i].width;
+ csid_hw->rdi_path_config[i].height =
+ dimension_update->rdi_path[i].height;
+ CAM_DBG(CAM_ISP,
+ "CSID rdi path[%d] width %d height %d",
+ i, csid_hw->rdi_path_config[i].width,
+ csid_hw->rdi_path_config[i].height);
+ }
+ }
+
+ return 0;
+}
+
static int cam_ife_csid_process_cmd(void *hw_priv,
uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
{
@@ -3178,6 +3298,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv,
case CAM_IFE_CSID_SET_INIT_FRAME_DROP:
rc = cam_ife_csid_set_init_frame_drop(csid_hw, cmd_args);
break;
+ case CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG:
+ rc = cam_ife_csid_set_sensor_dimension(csid_hw, cmd_args);
+ break;
default:
CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
csid_hw->hw_intf->hw_idx, cmd_type);
@@ -3200,7 +3323,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data)
const struct cam_ife_csid_rdi_reg_offset *rdi_reg;
uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0;
uint32_t irq_status_rdi[4] = {0, 0, 0, 0};
- uint32_t val, irq_status_ppp = 0;
+ uint32_t val, val2, irq_status_ppp = 0;
bool fatal_err_detected = false;
uint32_t sof_irq_debug_en = 0;
unsigned long flags;
@@ -3255,7 +3378,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data)
cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
csid_reg->cmn_reg->csid_irq_cmd_addr);
- CAM_DBG(CAM_ISP,
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
"CSID %d irq status 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
csid_hw->hw_intf->hw_idx, irq_status_top,
irq_status_rx, irq_status_ipp, irq_status_ppp,
@@ -3492,6 +3615,25 @@ handle_fatal_error:
csid_reg->ipp_reg->csid_pxl_ctrl_addr);
}
}
+
+ if ((irq_status_ipp & CSID_PATH_ERROR_PIX_COUNT) ||
+ (irq_status_ipp & CSID_PATH_ERROR_LINE_COUNT)) {
+ val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ csid_reg->ipp_reg->csid_pxl_format_measure0_addr);
+
+ CAM_ERR(CAM_ISP,
+ "CSID:%d irq_status_ipp:0x%x",
+ csid_hw->hw_intf->hw_idx, irq_status_ipp);
+ CAM_ERR(CAM_ISP,
+ "Expected sz 0x%x*0x%x actual sz 0x%x*0x%x",
+ csid_hw->ipp_path_config.height,
+ csid_hw->ipp_path_config.width,
+ ((val >>
+ csid_reg->cmn_reg->format_measure_height_shift_val) &
+ csid_reg->cmn_reg->format_measure_height_mask_val),
+ val &
+ csid_reg->cmn_reg->format_measure_width_mask_val);
+ }
}
/*read PPP errors */
@@ -3573,6 +3715,25 @@ handle_fatal_error:
csid_reg->ppp_reg->csid_pxl_ctrl_addr);
}
}
+
+ if ((irq_status_ppp & CSID_PATH_ERROR_PIX_COUNT) ||
+ (irq_status_ppp & CSID_PATH_ERROR_LINE_COUNT)) {
+ val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ csid_reg->ppp_reg->csid_pxl_format_measure0_addr);
+
+ CAM_ERR(CAM_ISP,
+ "CSID:%d irq_status_ppp:0x%x",
+ csid_hw->hw_intf->hw_idx, irq_status_ppp);
+ CAM_ERR(CAM_ISP,
+ "Expected sz 0x%x*0x%x actual sz 0x%x*0x%x",
+ csid_hw->ppp_path_config.height,
+ csid_hw->ppp_path_config.width,
+ ((val >>
+ csid_reg->cmn_reg->format_measure_height_shift_val) &
+ csid_reg->cmn_reg->format_measure_height_mask_val),
+ val &
+ csid_reg->cmn_reg->format_measure_width_mask_val);
+ }
}
for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
@@ -3639,6 +3800,31 @@ handle_fatal_error:
soc_info->reg_map[0].mem_base +
csid_reg->rdi_reg[i]->csid_rdi_ctrl_addr);
}
+
+ if ((irq_status_rdi[i] & CSID_PATH_ERROR_PIX_COUNT) ||
+ (irq_status_rdi[i] & CSID_PATH_ERROR_LINE_COUNT)) {
+ val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[i]->csid_rdi_format_measure0_addr);
+ val2 = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[i]->csid_rdi_format_measure_cfg1_addr
+ );
+ CAM_ERR(CAM_ISP,
+ "CSID:%d irq_status_rdi[%d]:0x%x",
+ csid_hw->hw_intf->hw_idx, i,
+ irq_status_rdi[i]);
+ CAM_ERR(CAM_ISP,
+ "Expected sz 0x%x*0x%x actual sz 0x%x*0x%x",
+ ((val2 >>
+ csid_reg->cmn_reg->format_measure_height_shift_val) &
+ csid_reg->cmn_reg->format_measure_height_mask_val),
+ val2 &
+ csid_reg->cmn_reg->format_measure_width_mask_val,
+ ((val >>
+ csid_reg->cmn_reg->format_measure_height_shift_val) &
+ csid_reg->cmn_reg->format_measure_height_mask_val),
+ val &
+ csid_reg->cmn_reg->format_measure_width_mask_val);
+ }
}
if (csid_hw->irq_debug_cnt >= CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX) {
@@ -3782,6 +3968,10 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf,
ife_csid_hw->csid_debug = 0;
ife_csid_hw->error_irq_count = 0;
ife_csid_hw->first_sof_ts = 0;
+ ife_csid_hw->ipp_path_config.measure_enabled = 0;
+ ife_csid_hw->ppp_path_config.measure_enabled = 0;
+ for (i = 0; i <= CAM_IFE_PIX_PATH_RES_RDI_3; i++)
+ ife_csid_hw->rdi_path_config[i].measure_enabled = 0;
/* Check if ppi bridge is present or not? */
ife_csid_hw->ppi_enable = of_property_read_bool(
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index 26b6a7871845..f2173f13f0c4 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -310,6 +310,10 @@ struct cam_ife_csid_common_reg_offset {
uint32_t ppp_irq_mask_all;
uint32_t measure_en_hbi_vbi_cnt_mask;
uint32_t format_measure_en_val;
+ uint32_t format_measure_width_shift_val;
+ uint32_t format_measure_width_mask_val;
+ uint32_t format_measure_height_shift_val;
+ uint32_t format_measure_height_mask_val;
};
/**
@@ -469,6 +473,11 @@ struct cam_ife_csid_path_cfg {
* @csid_debug: csid debug information to enable the SOT, EOT,
* SOF, EOF, measure etc in the csid hw
* @clk_rate Clock rate
+ * @ipp_path ipp path configuration
+ * @ppp_path ppp path configuration
+ * @rdi_path RDI path configuration
+ * @hbi Horizontal blanking
+ * @vbi Vertical blanking
* @sof_irq_triggered: Flag is set on receiving event to enable sof irq
* incase of SOF freeze.
* @irq_debug_cnt: Counter to track sof irq's when above flag is set.
@@ -507,6 +516,11 @@ struct cam_ife_csid_hw {
struct completion csid_rdin_complete[CAM_IFE_CSID_RDI_MAX];
uint64_t csid_debug;
uint64_t clk_rate;
+ struct cam_isp_sensor_dimension ipp_path_config;
+ struct cam_isp_sensor_dimension ppp_path_config;
+ struct cam_isp_sensor_dimension rdi_path_config[4];
+ uint32_t hbi;
+ uint32_t vbi;
bool sof_irq_triggered;
uint32_t irq_debug_cnt;
uint32_t error_irq_count;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
index 0c45bd1268b9..8d340207a0a1 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
@@ -158,6 +158,7 @@ enum cam_ife_csid_cmd_type {
CAM_IFE_CSID_SET_CSID_DEBUG,
CAM_IFE_CSID_SOF_IRQ_DEBUG,
CAM_IFE_CSID_SET_INIT_FRAME_DROP,
+ CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG,
CAM_IFE_CSID_CMD_MAX,
};
@@ -181,5 +182,17 @@ struct cam_ife_csid_clock_update_args {
uint64_t clk_rate;
};
+/*
+ * struct cam_ife_sensor_dim_update_args:
+ *
+ * @ppp_path: expected ppp path configuration
+ * @ipp_path: expected ipp path configuration
+ * @rdi_path: expected rdi path configuration
+ */
+struct cam_ife_sensor_dimension_update_args {
+ struct cam_isp_sensor_dimension ppp_path;
+ struct cam_isp_sensor_dimension ipp_path;
+ struct cam_isp_sensor_dimension rdi_path[4];
+};
#endif /* _CAM_CSID_HW_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
index b23014773022..d90030d9ed16 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
@@ -20,17 +20,21 @@
#include "cam_irq_controller.h"
#include <uapi/media/cam_isp.h>
+#define CAM_ISP_FPS_60 60
+
/*
* struct cam_isp_timestamp:
*
* @mono_time: Monotonic boot time
* @vt_time: AV Timer time
* @ticks: Qtimer ticks
+ * @time_usecs: time in micro seconds
*/
struct cam_isp_timestamp {
struct timeval mono_time;
struct timeval vt_time;
uint64_t ticks;
+ uint64_t time_usecs;
};
/*
@@ -105,6 +109,7 @@ enum cam_isp_hw_cmd_type {
CAM_ISP_HW_CMD_FE_UPDATE_IN_RD,
CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD,
CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP,
+ CAM_ISP_HW_CMD_FPS_CONFIG,
CAM_ISP_HW_CMD_MAX,
};
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
index 9d6bcb71bb69..3bcedc948a18 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
@@ -178,6 +178,17 @@ struct cam_vfe_clock_update_args {
};
/*
+ * struct cam_vfe_fps_config_args:
+ *
+ * @node_res: Resource to get the fps value
+ * @fps: FPS value to configure EPOCH
+ */
+struct cam_vfe_fps_config_args {
+ struct cam_isp_resource_node *node_res;
+ uint32_t fps;
+};
+
+/*
* struct cam_vfe_bw_update_args:
*
* @node_res: Resource to get the BW
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index a26c11264d2c..162ddadd744f 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -444,6 +444,8 @@ void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp)
get_monotonic_boottime(&ts);
time_stamp->mono_time.tv_sec = ts.tv_sec;
time_stamp->mono_time.tv_usec = ts.tv_nsec/1000;
+ time_stamp->time_usecs = ts.tv_sec * 1000000 +
+ time_stamp->mono_time.tv_usec;
}
static int cam_vfe_irq_top_half(uint32_t evt_id,
@@ -761,6 +763,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
case CAM_ISP_HW_CMD_BW_UPDATE:
case CAM_ISP_HW_CMD_BW_CONTROL:
case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP:
+ case CAM_ISP_HW_CMD_FPS_CONFIG:
rc = core_info->vfe_top->hw_ops.process_cmd(
core_info->vfe_top->top_priv, cmd_type, cmd_args,
arg_size);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index 3ed45ee530e8..112a2d680c30 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -44,6 +44,7 @@ struct cam_vfe_mux_camif_data {
bool enable_sof_irq_debug;
uint32_t irq_debug_cnt;
uint32_t camif_debug;
+ uint32_t fps;
};
static int cam_vfe_camif_validate_pix_pattern(uint32_t pattern)
@@ -269,9 +270,15 @@ static int cam_vfe_camif_resource_start(
rsrc_data->camif_reg->epoch_irq);
break;
default:
- epoch0_irq_mask = ((rsrc_data->last_line -
+ if (rsrc_data->fps == CAM_ISP_FPS_60) {
+ epoch0_irq_mask = ((rsrc_data->last_line -
rsrc_data->first_line) / 2) +
rsrc_data->first_line;
+ } else {
+ epoch0_irq_mask = (((rsrc_data->last_line -
+ rsrc_data->first_line) * 2) / 3) +
+ rsrc_data->first_line;
+ }
epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg &
0xFFFF;
computed_epoch_line_cfg = (epoch0_irq_mask << 16) |
@@ -515,6 +522,20 @@ static int cam_vfe_camif_sof_irq_debug(
return 0;
}
+static int cam_vfe_camif_set_fps_config(
+ struct cam_isp_resource_node *rsrc_node, void *cmd_args)
+{
+ struct cam_vfe_mux_camif_data *camif_priv = NULL;
+ struct cam_vfe_fps_config_args *fps_args = cmd_args;
+
+ camif_priv =
+ (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv;
+
+ camif_priv->fps = fps_args->fps;
+
+ return 0;
+
+}
static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node,
uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
@@ -546,6 +567,9 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node,
case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP:
rc = cam_vfe_camif_irq_reg_dump(rsrc_node);
break;
+ case CAM_ISP_HW_CMD_FPS_CONFIG:
+ rc = cam_vfe_camif_set_fps_config(rsrc_node, cmd_args);
+ break;
default:
CAM_ERR(CAM_ISP,
"unsupported process command:%d", cmd_type);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index d512128b28e5..0461b0820b4f 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -283,6 +283,22 @@ static int cam_vfe_top_fs_update(
return 0;
}
+static int cam_vfe_top_fps_config(
+ struct cam_vfe_top_ver2_priv *top_priv,
+ void *cmd_args, uint32_t arg_size)
+{
+ struct cam_vfe_fps_config_args *cmd_update = NULL;
+
+ cmd_update =
+ (struct cam_vfe_fps_config_args *)cmd_args;
+
+ if (cmd_update->node_res->process_cmd)
+ return cmd_update->node_res->process_cmd(cmd_update->node_res,
+ CAM_ISP_HW_CMD_FPS_CONFIG, cmd_args, arg_size);
+
+ return 0;
+}
+
static int cam_vfe_top_clock_update(
struct cam_vfe_top_ver2_priv *top_priv,
void *cmd_args, uint32_t arg_size)
@@ -740,6 +756,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type,
rc = cam_vfe_get_irq_register_dump(top_priv,
cmd_args, arg_size);
break;
+ case CAM_ISP_HW_CMD_FPS_CONFIG:
+ rc = cam_vfe_top_fps_config(top_priv, cmd_args,
+ arg_size);
+ break;
default:
rc = -EINVAL;
CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
index c74be4cf4e45..b0901f83fa97 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
@@ -1015,7 +1015,7 @@ int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg)
&eeprom_cap,
sizeof(struct cam_eeprom_query_cap_t))) {
CAM_ERR(CAM_EEPROM, "Failed Copy to User");
- return -EFAULT;
+ rc = -EFAULT;
goto release_mutex;
}
CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 0ae7d0ac4186..88c5c88030dc 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -3663,6 +3663,8 @@ STREAM_BUFF_END:
} else {
ioctl_cmd = VIDIOC_MSM_BUF_MNGR_IOCTL_CMD;
idx = MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX;
+ buff_mgr_info.index =
+ frame_info.output_buffer_info[0].index;
}
rc = msm_cpp_buffer_ops(cpp_dev, ioctl_cmd, idx,
&buff_mgr_info);
@@ -4376,6 +4378,8 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
memset(&k64_frame_info, 0, sizeof(k64_frame_info));
k64_frame_info.identity = k32_frame_info.identity;
k64_frame_info.frame_id = k32_frame_info.frame_id;
+ k64_frame_info.output_buffer_info[0].index =
+ k32_frame_info.output_buffer_info[0].index;
kp_ioctl.ioctl_ptr = (__force void __user *)&k64_frame_info;
diff --git a/drivers/net/ethernet/aquantia/Kconfig b/drivers/net/ethernet/aquantia/Kconfig
index 1b35d4e5a4a2..a5311a0f2d03 100644
--- a/drivers/net/ethernet/aquantia/Kconfig
+++ b/drivers/net/ethernet/aquantia/Kconfig
@@ -29,20 +29,4 @@ config AQFWD
source "drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig"
-config AQFWD_QCOM
- bool "QTI MSM/MDM target support"
- depends on AQFWD
- depends on ARCH_QCOM
- help
- Enable support for integration with Qualcomm Technologies, Inc. chipsets.
-
-config AQFWD_QCOM_IPA
- bool "QTI IPA offload support"
- depends on IPA_ETH
- select AQFWD_QCOM
- select ATLFWD_FWD
- help
- Enable support for Qualcomm Technologies, Inc. IPA (Internet Protocol Accelerator).
- If unsure, say N.
-
endif # NET_VENDOR_AQUANTIA
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig b/drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig
index 4a60625404de..1e47b65b8d6b 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig
@@ -42,3 +42,24 @@ config ATLFWD_FWD_TXBUF
API enabled, 0 otherwise.
endif
+
+config AQFWD_QCOM
+ bool "QTI MSM/MDM target support"
+ depends on AQFWD
+ depends on ARCH_QCOM
+ help
+ Some older targets using Qualcomm Technologies, Inc. chipsets
+ require peripheral drivers to explicitly set IOMMU attributes
+ and perform IOMMU attach. Enable this option if your platform
+ is affected. Using this feature will also require the user to
+ provide SMMU configuration via PCI device tree.
+ If unsure, say N.
+
+config AQFWD_QCOM_IPA
+ bool "QTI IPA offload support"
+ depends on IPA_ETH
+ select AQFWD_QCOM
+ select ATLFWD_FWD
+ help
+ Enable support for Qualcomm Technologies, Inc. IPA (Internet Protocol Accelerator).
+ If unsure, say N.
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/Makefile b/drivers/net/ethernet/aquantia/atlantic-fwd/Makefile
index 52d9467d566e..f098674f7557 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/Makefile
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/Makefile
@@ -40,8 +40,6 @@ atlantic-fwd-objs := atl_fw.o \
atlantic-fwd-$(CONFIG_ATLFWD_FWD) += atl_fwd.o
-atlantic-fwd-$(CONFIG_OF) += atl_of.o
-
atlantic-fwd-$(CONFIG_AQFWD_QCOM) += atl_qcom.o
atlantic-fwd-$(CONFIG_AQFWD_QCOM_IPA) += atl_qcom_ipa.o
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h
index a3dfebf9c00c..1324486dba9c 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h
@@ -18,7 +18,7 @@
#include <linux/netdevice.h>
#include <linux/moduleparam.h>
-#define ATL_VERSION "1.0.19"
+#define ATL_VERSION "1.0.20"
struct atl_nic;
@@ -220,9 +220,8 @@ struct atl_nic {
int nvecs;
struct atl_hw hw;
unsigned flags;
- unsigned long state;
uint32_t priv_flags;
- struct timer_list link_timer;
+ struct timer_list work_timer;
int max_mtu;
int requested_nvecs;
int requested_rx_size;
@@ -249,13 +248,6 @@ enum atl_nic_flags {
ATL_FL_WOL = BIT(1),
};
-enum atl_nic_state {
- ATL_ST_UP,
- ATL_ST_CONFIGURED,
- ATL_ST_ENABLED,
- ATL_ST_WORK_SCHED,
-};
-
#define ATL_PF(_name) ATL_PF_ ## _name
#define ATL_PF_BIT(_name) ATL_PF_ ## _name ## _BIT
#define ATL_DEF_PF_BIT(_name) ATL_PF_BIT(_name) = BIT(ATL_PF(_name))
@@ -335,18 +327,37 @@ extern int atl_enable_msi;
#define atl_nic_err(fmt, args...) \
dev_err(&nic->hw.pdev->dev, fmt, ## args)
+#define atl_dev_init_warn(fmt, args...) \
+do { \
+ if (hw) \
+ atl_dev_warn(fmt, ## args); \
+ else \
+ printk(KERN_WARNING "%s: " fmt, atl_driver_name, ##args); \
+} while(0)
+
+#define atl_dev_init_err(fmt, args...) \
+do { \
+ if (hw) \
+ atl_dev_warn(fmt, ## args); \
+ else \
+ printk(KERN_ERR "%s: " fmt, atl_driver_name, ##args); \
+} while(0)
+
#define atl_module_param(_name, _type, _mode) \
module_param_named(_name, atl_ ## _name, _type, _mode)
static inline void atl_intr_enable_non_ring(struct atl_nic *nic)
{
struct atl_hw *hw = &nic->hw;
- uint32_t mask = hw->intr_mask;
-#ifdef CONFIG_ATLFWD_FWD
- mask |= (uint32_t)(nic->fwd.msi_map);
-#endif
- atl_intr_enable(hw, mask);
+ atl_intr_enable(hw, hw->non_ring_intr_mask);
+}
+
+static inline void atl_intr_disable_non_ring(struct atl_nic *nic)
+{
+ struct atl_hw *hw = &nic->hw;
+
+ atl_intr_disable(hw, hw->non_ring_intr_mask);
}
netdev_tx_t atl_start_xmit(struct sk_buff *skb, struct net_device *ndev);
@@ -360,6 +371,7 @@ int atl_setup_datapath(struct atl_nic *nic);
void atl_clear_datapath(struct atl_nic *nic);
int atl_start_rings(struct atl_nic *nic);
void atl_stop_rings(struct atl_nic *nic);
+void atl_clear_rdm_cache(struct atl_nic *nic);
int atl_alloc_rings(struct atl_nic *nic);
void atl_free_rings(struct atl_nic *nic);
irqreturn_t atl_ring_irq(int irq, void *priv);
@@ -403,5 +415,8 @@ int atl_mdio_write(struct atl_hw *hw, uint8_t prtad, uint8_t mmd,
void atl_refresh_rxfs(struct atl_nic *nic);
void atl_schedule_work(struct atl_nic *nic);
int atl_hwmon_init(struct atl_nic *nic);
+int atl_update_thermal(struct atl_hw *hw);
+int atl_update_thermal_flag(struct atl_hw *hw, int bit, bool val);
+int atl_verify_thermal_limits(struct atl_hw *hw, struct atl_thermal *thermal);
#endif
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c
index d481355291b3..c445f1b9b18a 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c
@@ -36,17 +36,8 @@ struct atl_link_type atl_link_types[] = {
const int atl_num_rates = ARRAY_SIZE(atl_link_types);
-static inline void atl_lock_fw(struct atl_hw *hw)
-{
- mutex_lock(&hw->mcp.lock);
-}
-
-static inline void atl_unlock_fw(struct atl_hw *hw)
-{
- mutex_unlock(&hw->mcp.lock);
-}
-
-static int atl_fw1_wait_fw_init(struct atl_hw *hw)
+/* fw lock must be held */
+static int __atl_fw1_wait_fw_init(struct atl_hw *hw)
{
uint32_t hostData_addr;
uint32_t id, new_id;
@@ -79,7 +70,8 @@ static int atl_fw1_wait_fw_init(struct atl_hw *hw)
return 0;
}
-static int atl_fw2_wait_fw_init(struct atl_hw *hw)
+/* fw lock must be held */
+static int __atl_fw2_wait_fw_init(struct atl_hw *hw)
{
uint32_t reg;
@@ -148,6 +140,8 @@ static struct atl_link_type *atl_fw1_check_link(struct atl_hw *hw)
return link;
}
+static void __atl_fw2_thermal_check(struct atl_hw *hw, uint32_t sts);
+
static struct atl_link_type *atl_fw2_check_link(struct atl_hw *hw)
{
struct atl_link_type *link;
@@ -162,58 +156,91 @@ static struct atl_link_type *atl_fw2_check_link(struct atl_hw *hw)
high = atl_read(hw, ATL_MCP_SCRATCH(FW2_LINK_RES_HIGH));
link = atl_parse_fw_bits(hw, low, high, 1);
- if (!link)
- goto unlock;
- if (high & atl_fw2_pause)
- fc |= atl_fc_rx;
- if (high & atl_fw2_asym_pause)
- fc |= atl_fc_tx;
+ __atl_fw2_thermal_check(hw, low);
+
+ /* Thermal check might have reset link due to throttling */
+ link = lstate->link;
+
+ if (link) {
+ if (high & atl_fw2_pause)
+ fc |= atl_fc_rx;
+ if (high & atl_fw2_asym_pause)
+ fc |= atl_fc_tx;
+ }
lstate->fc.cur = fc;
-unlock:
atl_unlock_fw(hw);
return link;
}
-static int atl_fw1_get_link_caps(struct atl_hw *hw)
+/* fw lock must be held */
+static int __atl_fw1_get_link_caps(struct atl_hw *hw)
{
return 0;
}
-static int atl_fw2_get_link_caps(struct atl_hw *hw)
+/* fw lock must be held */
+static int __atl_fw2_get_link_caps(struct atl_hw *hw)
{
- uint32_t fw_stat_addr = hw->mcp.fw_stat_addr;
+ struct atl_mcp *mcp = &hw->mcp;
+ uint32_t fw_stat_addr = mcp->fw_stat_addr;
+ struct atl_link_type *rate;
unsigned int supported = 0;
- uint32_t caps[2];
+ uint32_t caps[2], mask = atl_fw2_pause_mask | atl_fw2_link_drop;
int i, ret;
- atl_lock_fw(hw);
-
atl_dev_dbg("Host data struct addr: %#x\n", fw_stat_addr);
ret = atl_read_mcp_mem(hw, fw_stat_addr + atl_fw2_stat_lcaps,
caps, 8);
if (ret)
- goto unlock;
+ return ret;
+
+ mcp->caps_low = caps[0];
+ mcp->caps_high = caps[1];
+ atl_dev_dbg("Got link caps: %#x %#x\n", caps[0], caps[1]);
+
+ atl_for_each_rate(i, rate) {
+ uint32_t bit = rate->fw_bits[1];
- for (i = 0; i < atl_num_rates; i++)
- if (atl_link_types[i].fw_bits[1] & caps[0]) {
+ if (bit & caps[0]) {
supported |= BIT(i);
- if (atl_link_types[i].fw_bits[1] & caps[1])
+ if (bit & caps[1]) {
supported |= BIT(i + ATL_EEE_BIT_OFFT);
+ mask |= bit;
+ }
}
+ }
+ mcp->req_high_mask = ~mask;
hw->link_state.supported = supported;
+ hw->link_state.lp_lowest = fls(supported) - 1;
-unlock:
- atl_unlock_fw(hw);
return ret;
}
static inline unsigned int atl_link_adv(struct atl_link_state *lstate)
{
- return lstate->force_off ? 0 : lstate->advertized;
+ struct atl_hw *hw = container_of(lstate, struct atl_hw, link_state);
+
+ if (lstate->force_off)
+ return 0;
+
+ if (lstate->thermal_throttled
+ && hw->thermal.flags & atl_thermal_throttle)
+ /* FW doesn't provide raw LP's advertized rates, only
+ * the rates adverized both by us and LP. Here we
+ * advertize not just the throttled_to rate, but also
+ * all the lower rates as well. That way if LP changes
+ * or dynamically starts to adverize a lower rate than
+ * throttled_to, we will notice that in
+ * atl_fw2_thermal_check() and switch to that lower
+ * rate there.
+ */
+ return BIT(lstate->throttled_to + 1) - 1;
+
+ return lstate->advertized;
}
static inline bool atl_fw1_set_link_needed(struct atl_link_state *lstate)
@@ -276,16 +303,14 @@ static void atl_fw1_set_link(struct atl_hw *hw, bool force)
atl_unlock_fw(hw);
}
-static void atl_fw2_set_link(struct atl_hw *hw, bool force)
+/* fw lock must be held */
+static void __atl_fw2_set_link(struct atl_hw *hw)
{
struct atl_link_state *lstate = &hw->link_state;
- uint32_t hi_bits = 0;
+ uint32_t hi_bits;
uint64_t bits;
- if (!force && !atl_fw2_set_link_needed(lstate))
- return;
-
- atl_lock_fw(hw);
+ hi_bits = hw->mcp.req_high & hw->mcp.req_high_mask;
if (lstate->fc.req & atl_fc_rx)
hi_bits |= atl_fw2_pause | atl_fw2_asym_pause;
@@ -294,15 +319,26 @@ static void atl_fw2_set_link(struct atl_hw *hw, bool force)
hi_bits ^= atl_fw2_asym_pause;
bits = atl_set_fw_bits(hw, 1);
- hi_bits |= bits >> 32;
/* If no modes are advertized, put PHY into low-power */
if (!bits)
- hi_bits = atl_fw2_link_drop;
+ hi_bits |= atl_fw2_link_drop;
+ else
+ hi_bits |= bits >> 32;
+
+ hw->mcp.req_high = hi_bits;
atl_write(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_LOW), bits);
atl_write(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), hi_bits);
+}
+
+static void atl_fw2_set_link(struct atl_hw *hw, bool force)
+{
+ if (!force && !atl_fw2_set_link_needed(&hw->link_state))
+ return;
+ atl_lock_fw(hw);
+ __atl_fw2_set_link(hw);
atl_unlock_fw(hw);
}
@@ -314,6 +350,8 @@ static int atl_fw1_unsupported(struct atl_hw *hw)
static int atl_fw2_restart_aneg(struct atl_hw *hw)
{
atl_lock_fw(hw);
+ /* Autoneg restart is self-clearing, no need to track via
+ * mcp->req_high */
atl_set_bits(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), BIT(31));
atl_unlock_fw(hw);
return 0;
@@ -398,15 +436,17 @@ int atl_read_mcp_word(struct atl_hw *hw, uint32_t offt, uint32_t *val)
return 0;
}
-static int atl_fw2_get_phy_temperature(struct atl_hw *hw, int *temp)
+/* fw lock must be held */
+static int __atl_fw2_get_phy_temperature(struct atl_hw *hw, int *temp)
{
uint32_t req, res;
int ret = 0;
- atl_lock_fw(hw);
+ if (test_bit(ATL_ST_RESETTING, &hw->state))
+ return 0;
- req = atl_read(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH));
- req ^= atl_fw2_phy_temp;
+ hw->mcp.req_high ^= atl_fw2_phy_temp;
+ req = hw->mcp.req_high;
atl_write(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), req);
busy_wait(1000, udelay(10), res,
@@ -414,27 +454,95 @@ static int atl_fw2_get_phy_temperature(struct atl_hw *hw, int *temp)
((res ^ req) & atl_fw2_phy_temp) != 0);
if (((res ^ req) & atl_fw2_phy_temp) != 0) {
atl_dev_err("Timeout waiting for PHY temperature\n");
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
ret = atl_read_fwstat_word(hw, atl_fw2_stat_temp, &res);
if (ret)
- goto unlock;
+ return ret;
*temp = (res & 0xffff) * 1000 / 256;
-unlock:
+ return ret;
+}
+
+static int atl_fw2_get_phy_temperature(struct atl_hw *hw, int *temp)
+{
+ int ret;
+
+ atl_lock_fw(hw);
+ ret = __atl_fw2_get_phy_temperature(hw, temp);
atl_unlock_fw(hw);
return ret;
}
+/* fw lock must be held */
+static void __atl_fw2_thermal_check(struct atl_hw *hw, uint32_t sts)
+{
+ bool alarm;
+ int temp, ret;
+ struct atl_link_state *lstate = &hw->link_state;
+ struct atl_link_type *link = lstate->link;
+ int lowest;
+
+ alarm = !!(sts & atl_fw2_thermal_alarm);
+
+ if (link) {
+ /* ffs() / fls() number bits starting at 1 */
+ lowest = ffs(lstate->lp_advertized) - 1;
+ if (lowest < lstate->lp_lowest) {
+ lstate->lp_lowest = lowest;
+ if (lowest < lstate->throttled_to &&
+ lstate->thermal_throttled && alarm)
+ /* We're still thermal-throttled, and
+ * just found out we can lower the
+ * speed even more, so renegotiate. */
+ goto relink;
+ }
+ } else
+ lstate->lp_lowest = fls(lstate->supported) - 1;
+
+ if (alarm == lstate->thermal_throttled)
+ return;
+
+ lstate->thermal_throttled = alarm;
+
+ ret = __atl_fw2_get_phy_temperature(hw, &temp);
+ if (ret)
+ temp = 0;
+ else
+ /* Temperature is in millidegrees C */
+ temp = (temp + 50) / 100;
+
+ if (alarm) {
+ if (temp)
+ atl_dev_warn("PHY temperature above threshold: %d.%d\n",
+ temp / 10, temp % 10);
+ else
+ atl_dev_warn("PHY temperature above threshold\n");
+ } else {
+ if (temp)
+ atl_dev_warn("PHY temperature back in range: %d.%d\n",
+ temp / 10, temp % 10);
+ else
+ atl_dev_warn("PHY temperature back in range\n");
+ }
+
+relink:
+ if (hw->thermal.flags & atl_thermal_throttle) {
+ /* If throttling is enabled, renegotiate link */
+ lstate->link = 0;
+ lstate->throttled_to = lstate->lp_lowest;
+ __atl_fw2_set_link(hw);
+ }
+}
+
static struct atl_fw_ops atl_fw_ops[2] = {
[0] = {
- .wait_fw_init = atl_fw1_wait_fw_init,
+ .__wait_fw_init = __atl_fw1_wait_fw_init,
.set_link = atl_fw1_set_link,
.check_link = atl_fw1_check_link,
- .get_link_caps = atl_fw1_get_link_caps,
+ .__get_link_caps = __atl_fw1_get_link_caps,
.restart_aneg = atl_fw1_unsupported,
.set_default_link = atl_fw1_set_default_link,
.enable_wol = atl_fw1_unsupported,
@@ -442,10 +550,10 @@ static struct atl_fw_ops atl_fw_ops[2] = {
.efuse_shadow_addr_reg = ATL_MCP_SCRATCH(FW1_EFUSE_SHADOW),
},
[1] = {
- .wait_fw_init = atl_fw2_wait_fw_init,
+ .__wait_fw_init = __atl_fw2_wait_fw_init,
.set_link = atl_fw2_set_link,
.check_link = atl_fw2_check_link,
- .get_link_caps = atl_fw2_get_link_caps,
+ .__get_link_caps = __atl_fw2_get_link_caps,
.restart_aneg = atl_fw2_restart_aneg,
.set_default_link = atl_fw2_set_default_link,
.enable_wol = atl_fw2_enable_wol,
@@ -454,10 +562,225 @@ static struct atl_fw_ops atl_fw_ops[2] = {
},
};
+/* fw lock must be held */
+static int __atl_fw2_set_thermal_monitor(struct atl_hw *hw, bool enable)
+{
+ struct atl_mcp *mcp = &hw->mcp;
+ int ret;
+ uint32_t high;
+
+ if (enable) {
+ struct atl_fw2_thermal_cfg cfg __attribute__((__aligned__(4)));
+
+ cfg.msg_id = 0x17;
+ cfg.shutdown_temp = hw->thermal.crit;
+ cfg.high_temp = hw->thermal.high;
+ cfg.normal_temp = hw->thermal.low;
+
+ ret = atl_write_mcp_mem(hw, 0, &cfg, (sizeof(cfg) + 3) & ~3,
+ MCP_AREA_CONFIG);
+ if (ret) {
+ atl_dev_err("Failed to upload thermal thresholds to firmware: %d\n",
+ ret);
+ return ret;
+ }
+
+ mcp->req_high |= atl_fw2_set_thermal;
+ } else
+ mcp->req_high &= ~atl_fw2_set_thermal;
+
+ atl_write(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), mcp->req_high);
+ busy_wait(1000, udelay(10), high,
+ atl_read(hw, ATL_MCP_SCRATCH(FW2_LINK_RES_HIGH)),
+ !!(high & atl_fw2_set_thermal) != enable);
+ if (!!(high & atl_fw2_set_thermal) != enable) {
+ atl_dev_err("Timeout waiting for thermal monitoring FW request\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* fw lock must be held */
+static int __atl_fw2_update_thermal(struct atl_hw *hw)
+{
+ struct atl_mcp *mcp = &hw->mcp;
+ int ret = 0;
+ bool enable = !!(hw->thermal.flags & atl_thermal_monitor);
+
+ if (!enable || (mcp->req_high & atl_fw2_set_thermal)) {
+ /* If monitoring is on and we need to change the
+ * thresholds, we need to temporarily disable thermal
+ * monitoring first. */
+ ret = __atl_fw2_set_thermal_monitor(hw, false);
+ if (ret)
+ return ret;
+ }
+
+ if (enable)
+ ret = __atl_fw2_set_thermal_monitor(hw, true);
+
+ /* Thresholds might have changed, recheck state. */
+ __atl_fw2_thermal_check(hw,
+ atl_read(hw, ATL_MCP_SCRATCH(FW2_LINK_RES_LOW)));
+ return ret;
+}
+
+struct atl_thermal_limit {
+ uintptr_t offset;
+ const char *name;
+ unsigned min;
+ unsigned max;
+};
+#define atl_def_thermal_limit(_name, _field, _min, _max) \
+{ \
+ .offset = offsetof(struct atl_thermal, _field), \
+ .name = _name, \
+ .min = _min, \
+ .max = _max, \
+},
+
+static struct atl_thermal_limit atl_thermal_limits[] = {
+ atl_def_thermal_limit("Shutdown", crit, 108, 118)
+ atl_def_thermal_limit("High", high, 90, 107)
+ atl_def_thermal_limit("Normal", low, 50, 85)
+};
+
+int atl_verify_thermal_limits(struct atl_hw *hw, struct atl_thermal *thermal)
+{
+ int i;
+ bool ignore = !!(thermal->flags & atl_thermal_ignore_lims);
+
+ for (i = 0; i < ARRAY_SIZE(atl_thermal_limits); i++) {
+ struct atl_thermal_limit *lim = &atl_thermal_limits[i];
+ unsigned val = *((uint8_t *)thermal + lim->offset);
+
+ if (val >= lim->min && val <= lim->max)
+ continue;
+
+ if (ignore) {
+ atl_dev_init_warn("%s temperature threshold out of range (%d - %d): %d, allowing anyway\n",
+ lim->name, lim->min, lim->max, val);
+ continue;
+ } else {
+ atl_dev_init_err("%s temperature threshold out of range (%d - %d): %d\n",
+ lim->name, lim->min, lim->max, val);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int atl_update_thermal(struct atl_hw *hw)
+{
+ int ret;
+
+ ret = atl_verify_thermal_limits(hw, &hw->thermal);
+ if (ret)
+ return ret;
+
+ if (test_bit(ATL_ST_RESETTING, &hw->state))
+ /* After reset, atl_fw_init() will apply the settings
+ * skipped here */
+ return 0;
+
+ atl_lock_fw(hw);
+ ret = __atl_fw2_update_thermal(hw);
+ atl_unlock_fw(hw);
+
+ return ret;
+}
+
+int atl_update_thermal_flag(struct atl_hw *hw, int bit, bool val)
+{
+ struct atl_thermal *thermal = &hw->thermal;
+ unsigned flags, changed;
+ int ret = 0;
+
+ atl_lock_fw(hw);
+ flags = thermal->flags;
+
+ switch (bit) {
+ case atl_thermal_monitor_shift:
+ if (!val)
+ /* Disable throttling along with monitoring */
+ flags &= ~atl_thermal_throttle;
+ else
+ if (!(hw->mcp.caps_high & atl_fw2_set_thermal)) {
+ atl_dev_err("Thermal monitoring not supported by firmware\n");
+ ret = -EINVAL;
+ }
+ break;
+
+ case atl_thermal_throttle_shift:
+ if (val && !(flags & atl_thermal_monitor)) {
+ atl_dev_err("Thermal monitoring needs to be enabled before enabling throttling\n");
+ ret = -EINVAL;
+ }
+ break;
+
+ case atl_thermal_ignore_lims_shift:
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto unlock;
+
+ flags &= ~BIT(bit);
+ flags |= val << bit;
+
+ changed = flags ^ thermal->flags;
+ thermal->flags = flags;
+
+ if (test_bit(ATL_ST_RESETTING, &hw->state))
+ /* After reset, atl_fw_init() will apply the settings
+ * skipped here */
+ goto unlock;
+
+ if (changed & atl_thermal_monitor)
+ ret = __atl_fw2_update_thermal(hw);
+ else if (changed & atl_thermal_throttle &&
+ hw->link_state.thermal_throttled)
+ __atl_fw2_set_link(hw);
+
+ if (ret)
+ /* __atl_fw2_update_thermal() failed. Revert flag
+ * changes */
+ thermal->flags ^= changed;
+
+unlock:
+ atl_unlock_fw(hw);
+ return ret;
+}
+
+/* fw lock must be held */
+static int __atl_fw2_get_hbeat(struct atl_hw *hw, uint16_t *hbeat)
+{
+ int ret;
+ uint32_t val;
+
+ ret = atl_read_fwstat_word(hw, atl_fw2_stat_phy_hbeat, &val);
+ if (ret)
+ atl_dev_err("FW watchdog: failure reading PHY heartbeat: %d\n",
+ -ret);
+ else
+ *hbeat = val & 0xffff;
+
+ return ret;
+}
+
+static unsigned int atl_wdog_period = 1100;
+module_param_named(wdog_period, atl_wdog_period, uint, 0644);
+
int atl_fw_init(struct atl_hw *hw)
{
uint32_t tries, reg, major;
int ret;
+ struct atl_mcp *mcp = &hw->mcp;
tries = busy_wait(10000, mdelay(1), reg, atl_read(hw, 0x18), !reg);
if (!reg) {
@@ -473,22 +796,87 @@ int atl_fw_init(struct atl_hw *hw)
}
if (major > 2)
major--;
- hw->mcp.ops = &atl_fw_ops[major - 1];
- hw->mcp.poll_link = major == 1;
- hw->mcp.fw_rev = reg;
- hw->mcp.fw_stat_addr = atl_read(hw, ATL_MCP_SCRATCH(FW_STAT_STRUCT));
+ mcp->ops = &atl_fw_ops[major - 1];
+ mcp->fw_rev = reg;
+
+ ret = mcp->ops->__wait_fw_init(hw);
+ if (ret)
+ return ret;
+
+ mcp->fw_stat_addr = atl_read(hw, ATL_MCP_SCRATCH(FW_STAT_STRUCT));
+
+ ret = __atl_fw2_get_hbeat(hw, &mcp->phy_hbeat);
+ if (ret)
+ return ret;
+ mcp->next_wdog = jiffies + 2 * HZ;
if (major > 1) {
+ mcp->req_high = 0;
+
ret = atl_read_fwstat_word(hw, atl_fw2_stat_settings_addr,
- &hw->mcp.fw_settings_addr);
+ &mcp->fw_settings_addr);
if (ret)
return ret;
ret = atl_read_fwstat_word(hw, atl_fw2_stat_settings_len,
- &hw->mcp.fw_settings_len);
+ &mcp->fw_settings_len);
if (ret)
return ret;
+
+ }
+
+ ret = mcp->ops->__get_link_caps(hw);
+ if (ret)
+ return ret;
+
+ if (!(mcp->caps_high & atl_fw2_set_thermal)) {
+ if (hw->thermal.flags & atl_thermal_monitor)
+ atl_dev_warn("Thermal monitoring not supported by firmware\n");
+ hw->thermal.flags &=
+ ~(atl_thermal_monitor | atl_thermal_throttle);
+ } else
+ ret = __atl_fw2_update_thermal(hw);
+
+
+ return ret;
+}
+
+void atl_fw_watchdog(struct atl_hw *hw)
+{
+ struct atl_mcp *mcp = &hw->mcp;
+ int ret;
+ uint16_t hbeat;
+
+ if (mcp->wdog_disabled || !time_after(jiffies, mcp->next_wdog))
+ return;
+
+ if (test_bit(ATL_ST_RESETTING, &hw->state) ||
+ !test_bit(ATL_ST_ENABLED, &hw->state))
+ return;
+
+ atl_lock_fw(hw);
+
+ ret = __atl_fw2_get_hbeat(hw, &hbeat);
+ if (ret) {
+ atl_dev_err("FW watchdog: failure reading PHY heartbeat: %d\n",
+ -ret);
+ goto out;
}
- return hw->mcp.ops->wait_fw_init(hw);
+ if (hbeat == 0 && mcp->phy_hbeat == 0) {
+ atl_dev_warn("FW heartbeat stuck at 0, probably not provisioned. Disabling watchdog.\n");
+ mcp->wdog_disabled = true;
+ goto out;
+ }
+
+ if (hbeat == mcp->phy_hbeat) {
+ atl_dev_err("FW watchdog: FW hang (PHY heartbeat stuck at %hd), resetting\n", hbeat);
+ set_bit(ATL_ST_RESET_NEEDED, &hw->state);
+ }
+
+ mcp->phy_hbeat = hbeat;
+
+out:
+ mcp->next_wdog = jiffies + atl_wdog_period * HZ / 1000;
+ atl_unlock_fw(hw);
}
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h
index dc0aff8ca413..da00018b2190 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h
@@ -12,6 +12,22 @@
struct atl_hw;
+struct atl_mcp {
+ uint32_t fw_rev;
+ struct atl_fw_ops *ops;
+ uint32_t fw_stat_addr;
+ uint32_t fw_settings_addr;
+ uint32_t fw_settings_len;
+ uint32_t req_high;
+ uint32_t req_high_mask; /* Clears link rate-dependend bits */
+ uint32_t caps_low;
+ uint32_t caps_high;
+ struct mutex lock;
+ unsigned long next_wdog;
+ bool wdog_disabled;
+ uint16_t phy_hbeat;
+};
+
struct atl_link_type {
unsigned speed;
unsigned ethtool_idx;
@@ -22,6 +38,13 @@ struct atl_link_type {
extern struct atl_link_type atl_link_types[];
extern const int atl_num_rates;
+struct atl_fw2_thermal_cfg {
+ uint32_t msg_id;
+ uint8_t shutdown_temp;
+ uint8_t high_temp;
+ uint8_t normal_temp;
+};
+
#define atl_for_each_rate(idx, type) \
for (idx = 0, type = atl_link_types; \
idx < atl_num_rates; \
@@ -37,12 +60,15 @@ enum atl_fw2_opts {
atl_fw2_pause_mask = atl_fw2_pause | atl_fw2_asym_pause,
atl_define_bit(atl_fw2_wake_on_link, 16)
atl_define_bit(atl_fw2_phy_temp, 18)
+ atl_define_bit(atl_fw2_set_thermal, 21)
atl_define_bit(atl_fw2_link_drop, 22)
atl_define_bit(atl_fw2_nic_proxy, 0x17)
atl_define_bit(atl_fw2_wol, 0x18)
+ atl_define_bit(atl_fw2_thermal_alarm, 29)
};
enum atl_fw2_stat_offt {
+ atl_fw2_stat_phy_hbeat = 0x4c,
atl_fw2_stat_temp = 0x50,
atl_fw2_stat_lcaps = 0x84,
atl_fw2_stat_settings_addr = 0x110,
@@ -64,6 +90,12 @@ enum atl_fc_mode {
atl_fc_full = atl_fc_rx | atl_fc_tx,
};
+enum atl_thermal_flags {
+ atl_define_bit(atl_thermal_monitor, 0)
+ atl_define_bit(atl_thermal_throttle, 1)
+ atl_define_bit(atl_thermal_ignore_lims, 2)
+};
+
struct atl_fc_state {
enum atl_fc_mode req;
enum atl_fc_mode prev_req;
@@ -81,7 +113,11 @@ struct atl_link_state{
unsigned advertized;
unsigned lp_advertized;
unsigned prev_advertized;
+ int lp_lowest; /* Idx of lowest rate advertized by
+ * link partner in atl_link_types[] */
+ int throttled_to; /* Idx of the rate we're throttled to */
bool force_off;
+ bool thermal_throttled;
bool autoneg;
bool eee;
bool eee_enabled;
@@ -92,8 +128,8 @@ struct atl_link_state{
struct atl_fw_ops {
void (*set_link)(struct atl_hw *hw, bool force);
struct atl_link_type *(*check_link)(struct atl_hw *hw);
- int (*wait_fw_init)(struct atl_hw *hw);
- int (*get_link_caps)(struct atl_hw *hw);
+ int (*__wait_fw_init)(struct atl_hw *hw);
+ int (*__get_link_caps)(struct atl_hw *hw);
int (*restart_aneg)(struct atl_hw *hw);
void (*set_default_link)(struct atl_hw *hw);
int (*enable_wol)(struct atl_hw *hw);
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c
index bf04d22de15f..31c4d687bc57 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c
@@ -415,6 +415,8 @@ struct atl_fwd_ring *atl_fwd_request_ring(struct net_device *ndev,
goto free_ring;
}
+ memset(hwring->descs, 0, hwring->size * sizeof(*hwring->descs));
+
hwring->reg_base = dir_tx ? ATL_TX_RING(idx) : ATL_RX_RING(idx);
ret = atl_fwd_alloc_bufs(ring, page_order);
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c
index 5324fdb785ba..641e719ae6fd 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c
@@ -100,10 +100,12 @@ static inline void atl_glb_soft_reset_full(struct atl_hw *hw)
atl_glb_soft_reset(hw);
}
+/* entered with fw lock held */
static int atl_hw_reset_nonrbl(struct atl_hw *hw)
{
uint32_t tries;
uint32_t reg = atl_read(hw, ATL_GLOBAL_DAISY_CHAIN_STS1);
+ int ret;
bool daisychain_running = (reg & 0x30) != 0x30;
@@ -131,7 +133,8 @@ static int atl_hw_reset_nonrbl(struct atl_hw *hw)
!(reg & 0x10));
if (!(reg & 0x10)) {
atl_dev_err("FLB kickstart timed out: %#x\n", reg);
- return -EIO;
+ ret = -EIO;
+ goto unlock;
}
atl_dev_dbg("FLB kickstart took %d ms\n", tries);
@@ -141,15 +144,33 @@ static int atl_hw_reset_nonrbl(struct atl_hw *hw)
atl_glb_soft_reset_full(hw);
- return atl_fw_init(hw);
+ ret = atl_fw_init(hw);
+
+unlock:
+ atl_unlock_fw(hw);
+
+ if (ret)
+ set_bit(ATL_ST_RESET_NEEDED, &hw->state);
+ else
+ set_bit(ATL_ST_GLOBAL_CONF_NEEDED, &hw->state);
+
+ return ret;
}
+/* Must be called either during early init when netdev isn't yet
+ * registered, or with RTNL lock held */
int atl_hw_reset(struct atl_hw *hw)
{
- uint32_t reg = atl_read(hw, ATL_MCP_SCRATCH(RBL_STS));
- uint32_t flb_stat = atl_read(hw, ATL_GLOBAL_DAISY_CHAIN_STS1);
+ uint32_t reg;
+ uint32_t flb_stat;
int tries = 0;
/* bool host_load_done = false; */
+ int ret;
+
+ atl_lock_fw(hw);
+
+ reg = atl_read(hw, ATL_MCP_SCRATCH(RBL_STS));
+ flb_stat = atl_read(hw, ATL_GLOBAL_DAISY_CHAIN_STS1);
while (!reg && flb_stat == 0x6000000 && tries++ < 1000) {
mdelay(1);
@@ -160,10 +181,12 @@ int atl_hw_reset(struct atl_hw *hw)
atl_dev_dbg("0x388: %#x 0x704: %#x\n", reg, flb_stat);
if (tries >= 1000) {
atl_dev_err("Timeout waiting to choose RBL or FLB path\n");
- return -EIO;
+ ret = -EIO;
+ goto unlock;
}
if (!reg)
+ /* atl_hw_reset_nonrbl() releases the fw lock */
return atl_hw_reset_nonrbl(hw);
atl_write(hw, 0x404, 0x40e1);
@@ -199,11 +222,13 @@ int atl_hw_reset(struct atl_hw *hw)
if (reg == 0xf1a7) {
atl_dev_err("MAC FW Host load not supported yet\n");
- return -EIO;
+ ret = -EIO;
+ goto unlock;
}
if (!reg || reg == 0xdead) {
atl_dev_err("RBL restart timeout: %#x\n", reg);
- return -EIO;
+ ret = -EIO;
+ goto unlock;
}
atl_dev_dbg("RBL restart took %d ms result %#x\n", tries, reg);
@@ -220,7 +245,17 @@ int atl_hw_reset(struct atl_hw *hw)
/* } */
/* } */
- return atl_fw_init(hw);
+ ret = atl_fw_init(hw);
+
+unlock:
+ atl_unlock_fw(hw);
+
+ if (ret)
+ set_bit(ATL_ST_RESET_NEEDED, &hw->state);
+ else
+ set_bit(ATL_ST_GLOBAL_CONF_NEEDED, &hw->state);
+
+ return ret;
}
static int atl_get_mac_addr(struct atl_hw *hw, uint8_t *buf)
@@ -240,15 +275,16 @@ static int atl_get_mac_addr(struct atl_hw *hw, uint8_t *buf)
return ret;
}
-int atl_hwinit(struct atl_nic *nic, enum atl_board brd_id)
+int atl_hwinit(struct atl_hw *hw, enum atl_board brd_id)
{
- struct atl_hw *hw = &nic->hw;
struct atl_board_info *brd = &atl_boards[brd_id];
int ret;
/* Default supported speed set based on device id. */
hw->link_state.supported = brd->link_mask;
+ hw->thermal = atl_def_thermal;
+
ret = atl_hw_reset(hw);
atl_dev_info("rev 0x%x chip 0x%x FW img 0x%x\n",
@@ -260,18 +296,14 @@ int atl_hwinit(struct atl_nic *nic, enum atl_board brd_id)
return ret;
ret = atl_get_mac_addr(hw, hw->mac_addr);
- if (ret) {
+ if (ret)
atl_dev_err("couldn't read MAC address\n");
- return ret;
- }
- return hw->mcp.ops->get_link_caps(hw);
+ return ret;
}
-static void atl_rx_xoff_set(struct atl_nic *nic, bool fc)
+static void atl_rx_xoff_set(struct atl_hw *hw, bool fc)
{
- struct atl_hw *hw = &nic->hw;
-
atl_write_bit(hw, ATL_RX_PBUF_REG2(0), 31, fc);
}
@@ -280,6 +312,11 @@ void atl_refresh_link(struct atl_nic *nic)
struct atl_hw *hw = &nic->hw;
struct atl_link_type *link, *prev_link = hw->link_state.link;
+ if (test_bit(ATL_ST_RESETTING, &hw->state) ||
+ !test_bit(ATL_ST_ENABLED, &hw->state) ||
+ !test_and_clear_bit(ATL_ST_UPDATE_LINK, &hw->state))
+ return;
+
link = hw->mcp.ops->check_link(hw);
if (link) {
@@ -291,15 +328,17 @@ void atl_refresh_link(struct atl_nic *nic)
atl_nic_info("Link down\n");
netif_carrier_off(nic->ndev);
}
- atl_rx_xoff_set(nic, !!(hw->link_state.fc.cur & atl_fc_rx));
+ atl_rx_xoff_set(hw, !!(hw->link_state.fc.cur & atl_fc_rx));
+
+ atl_intr_enable_non_ring(nic);
}
static irqreturn_t atl_link_irq(int irq, void *priv)
{
struct atl_nic *nic = (struct atl_nic *)priv;
+ set_bit(ATL_ST_UPDATE_LINK, &nic->hw.state);
atl_schedule_work(nic);
- atl_intr_enable(&nic->hw, BIT(0));
return IRQ_HANDLED;
}
@@ -307,7 +346,7 @@ static irqreturn_t atl_legacy_irq(int irq, void *priv)
{
struct atl_nic *nic = priv;
struct atl_hw *hw = &nic->hw;
- uint32_t mask = hw->intr_mask | BIT(atl_qvec_intr(nic->qvecs));
+ uint32_t mask = hw->non_ring_intr_mask | BIT(atl_qvec_intr(nic->qvecs));
uint32_t stat;
@@ -441,10 +480,15 @@ unsigned int atl_fwd_tx_buf_reserve =
module_param_named(fwd_tx_buf_reserve, atl_fwd_tx_buf_reserve, uint, 0444);
module_param_named(fwd_rx_buf_reserve, atl_fwd_rx_buf_reserve, uint, 0444);
+/* Must be called either during early init when netdev isn't yet
+ * registered, or with RTNL lock held */
void atl_start_hw_global(struct atl_nic *nic)
{
struct atl_hw *hw = &nic->hw;
+ if (!test_and_clear_bit(ATL_ST_GLOBAL_CONF_NEEDED, &hw->state))
+ return;
+
/* Enable TPO2 */
atl_write(hw, 0x7040, 0x10000);
/* Enable RPF2, filter logic 3 */
@@ -540,9 +584,6 @@ void atl_start_hw_global(struct atl_nic *nic)
/* Reset Rx/Tx on unexpected PERST# */
atl_write_bit(hw, 0x1000, 29, 0);
atl_write(hw, 0x448, 3);
-
- /* Enable non-ring interrupts */
- atl_intr_enable_non_ring(nic);
}
#define atl_vlan_flt_val(vid) ((uint32_t)(vid) | 1 << 16 | 1 << 31)
@@ -938,9 +979,11 @@ int atl_update_eth_stats(struct atl_nic *nic)
uint32_t reg = 0, reg2 = 0;
int ret;
+ atl_lock_fw(hw);
+
ret = atl_hwsem_get(hw, ATL_MCP_SEM_MSM);
if (ret)
- return ret;
+ goto unlock_fw;
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM_CTR_TX_PAUSE, &reg, hwsem_put);
stats.tx_pause = reg;
@@ -990,6 +1033,8 @@ int atl_update_eth_stats(struct atl_nic *nic)
hwsem_put:
atl_hwsem_put(hw, ATL_MCP_SEM_MSM);
+unlock_fw:
+ atl_unlock_fw(hw);
return ret;
}
#undef __READ_MSM_OR_GOTO
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.h
index 16e1f618eda2..d7a512da60b7 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.h
@@ -42,27 +42,45 @@ enum atl_board {
ATL_AQC100,
};
+struct atl_thermal {
+ unsigned flags;
+ uint8_t crit;
+ uint8_t high;
+ uint8_t low;
+};
+
+extern struct atl_thermal atl_def_thermal;
+
+enum atl_nic_state {
+ ATL_ST_ENABLED,
+ ATL_ST_CONFIGURED,
+ ATL_ST_RINGS_RUNNING,
+ /* ATL_ST_FWD_RINGS_RUNNING, */
+ ATL_ST_UP,
+ ATL_ST_WORK_SCHED,
+ ATL_ST_UPDATE_LINK,
+ ATL_ST_RESETTING,
+ ATL_ST_RESET_NEEDED,
+ ATL_ST_GLOBAL_CONF_NEEDED,
+ ATL_ST_START_NEEDED,
+ ATL_ST_DETACHED,
+};
+
#define ATL_WAKE_SUPPORTED (WAKE_MAGIC | WAKE_PHY)
struct atl_hw {
uint8_t __iomem *regs;
struct pci_dev *pdev;
+ unsigned long state;
struct atl_link_state link_state;
unsigned wol_mode;
- struct {
- uint32_t fw_rev;
- bool poll_link;
- struct atl_fw_ops *ops;
- uint32_t fw_stat_addr;
- uint32_t fw_settings_addr;
- uint32_t fw_settings_len;
- struct mutex lock;
- } mcp;
- uint32_t intr_mask;
+ struct atl_mcp mcp;
+ uint32_t non_ring_intr_mask;
uint8_t mac_addr[ETH_ALEN];
#define ATL_RSS_KEY_SIZE 40
uint8_t rss_key[ATL_RSS_KEY_SIZE];
#define ATL_RSS_TBL_SIZE (1 << 6)
uint8_t rss_tbl[ATL_RSS_TBL_SIZE];
+ struct atl_thermal thermal;
};
union atl_desc;
@@ -178,7 +196,7 @@ static inline void atl_set_vlan_promisc(struct atl_hw *hw, int promisc)
int atl_read_mcp_mem(struct atl_hw *hw, uint32_t mcp_addr, void *host_addr,
unsigned size);
-int atl_hwinit(struct atl_nic *nic, enum atl_board brd_id);
+int atl_hwinit(struct atl_hw *hw, enum atl_board brd_id);
void atl_refresh_link(struct atl_nic *nic);
void atl_set_rss_key(struct atl_hw *hw);
void atl_set_rss_tbl(struct atl_hw *hw);
@@ -219,4 +237,16 @@ static inline int atl_read_fwsettings_word(struct atl_hw *hw, uint32_t offt,
return atl_read_mcp_word(hw, offt + hw->mcp.fw_settings_addr, val);
}
+static inline void atl_lock_fw(struct atl_hw *hw)
+{
+ mutex_lock(&hw->mcp.lock);
+}
+
+static inline void atl_unlock_fw(struct atl_hw *hw)
+{
+ mutex_unlock(&hw->mcp.lock);
+}
+
+void atl_fw_watchdog(struct atl_hw *hw);
+
#endif
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hwmon.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hwmon.c
index 684f0c57659b..b8b592ffabec 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hwmon.c
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hwmon.c
@@ -9,14 +9,59 @@
#include "atl_common.h"
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
#if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0)
+static ssize_t atl_hwmon_set_flag(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct atl_hw *hw = dev_get_drvdata(dev);
+ bool val;
+ int ret;
+
+ if (strtobool(buf, &val) < 0)
+ return -EINVAL;
+
+ ret = atl_update_thermal_flag(hw, sattr->index, val);
+
+ return ret ?: size;
+}
+
+static ssize_t atl_hwmon_show_flag(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct atl_hw *hw = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ !!(hw->thermal.flags & BIT(sattr->index)));
+}
+
+#define ATL_HWMON_BIT_ATTR(_name, _bit) \
+ SENSOR_DEVICE_ATTR(_name, S_IRUGO | S_IWUSR, atl_hwmon_show_flag, \
+ atl_hwmon_set_flag, _bit)
+
+static ATL_HWMON_BIT_ATTR(monitor, atl_thermal_monitor_shift);
+static ATL_HWMON_BIT_ATTR(throttle, atl_thermal_throttle_shift);
+static ATL_HWMON_BIT_ATTR(ignore_lims, atl_thermal_ignore_lims_shift);
+
+static struct attribute *atl_hwmon_attrs[] = {
+ &sensor_dev_attr_monitor.dev_attr.attr,
+ &sensor_dev_attr_throttle.dev_attr.attr,
+ &sensor_dev_attr_ignore_lims.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(atl_hwmon);
+
static char *atl_hwmon_labels[] = {
"PHY Temperature",
};
static const uint32_t atl_hwmon_temp_config[] = {
- HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT | HWMON_T_MAX |
+ HWMON_T_MAX_HYST | HWMON_T_MAX_ALARM,
0,
};
@@ -33,7 +78,18 @@ static const struct hwmon_channel_info *atl_hwmon_info[] = {
static umode_t atl_hwmon_is_visible(const void *p,
enum hwmon_sensor_types type, uint32_t attr, int channel)
{
- return type == hwmon_temp ? S_IRUGO : 0;
+ if (type != hwmon_temp)
+ return 0;
+
+ switch (attr) {
+ case hwmon_temp_input: case hwmon_temp_max_alarm: case hwmon_temp_label:
+ return S_IRUGO;
+
+ case hwmon_temp_crit: case hwmon_temp_max: case hwmon_temp_max_hyst:
+ return S_IRUGO | S_IWUSR;
+ }
+
+ return 0;
}
static int atl_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
@@ -42,17 +98,77 @@ static int atl_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
struct atl_hw *hw = dev_get_drvdata(dev);
int temp, ret;
- if (type != hwmon_temp || attr != hwmon_temp_input)
+ if (type != hwmon_temp)
return -EINVAL;
- ret = hw->mcp.ops->get_phy_temperature(hw, &temp);
- if (ret)
- return ret;
+ switch (attr) {
+ case hwmon_temp_input:
+ ret = hw->mcp.ops->get_phy_temperature(hw, &temp);
+ if (ret)
+ return ret;
+
+ *val = temp;
+ break;
+
+ case hwmon_temp_crit:
+ *val = hw->thermal.crit * 1000;
+ break;
+
+ case hwmon_temp_max:
+ *val = hw->thermal.high * 1000;
+ break;
+
+ case hwmon_temp_max_hyst:
+ *val = hw->thermal.low * 1000;
+ break;
+
+ case hwmon_temp_max_alarm:
+ *val = hw->link_state.thermal_throttled;
+ break;
- *val = temp;
+ default:
+ return -EINVAL;
+ }
return 0;
}
+static int atl_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+ uint32_t attr, int channel, long val)
+{
+ struct atl_hw *hw = dev_get_drvdata(dev);
+ uint8_t *ptr, old;
+ int ret;
+
+ if (type != hwmon_temp)
+ return -EINVAL;
+
+ switch (attr) {
+ case hwmon_temp_crit:
+ ptr = &hw->thermal.crit;
+ break;
+
+ case hwmon_temp_max:
+ ptr = &hw->thermal.high;
+ break;
+
+ case hwmon_temp_max_hyst:
+ ptr = &hw->thermal.low;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ old = *ptr;
+ *ptr = val / 1000;
+
+ ret = atl_update_thermal(hw);
+ if (ret)
+ *ptr = old;
+
+ return ret;
+}
+
static int atl_hwmon_read_string(struct device *dev,
enum hwmon_sensor_types type, u32 attr, int channel, const char **str)
{
@@ -67,6 +183,7 @@ static const struct hwmon_ops atl_hwmon_ops = {
.is_visible = atl_hwmon_is_visible,
.read = atl_hwmon_read,
.read_string = atl_hwmon_read_string,
+ .write = atl_hwmon_write,
};
static const struct hwmon_chip_info atl_hwmon = {
@@ -77,9 +194,10 @@ static const struct hwmon_chip_info atl_hwmon = {
int atl_hwmon_init(struct atl_nic *nic)
{
struct device *hwmon_dev;
+ struct atl_hw *hw = &nic->hw;
- hwmon_dev = devm_hwmon_device_register_with_info(&nic->hw.pdev->dev,
- nic->ndev->name, &nic->hw, &atl_hwmon, NULL);
+ hwmon_dev = devm_hwmon_device_register_with_info(&hw->pdev->dev,
+ nic->ndev->name, hw, &atl_hwmon, atl_hwmon_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c
index 531aa9d9b4fe..f47dfcd34582 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c
@@ -13,9 +13,7 @@
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
-#include "atl_qcom_ipa.h"
-
-#include "atl_of.h"
+#include "atl_qcom.h"
const char atl_driver_name[] = "atlantic-fwd";
@@ -29,29 +27,61 @@ module_param_named(tx_mod, atl_tx_mod, uint, 0444);
static unsigned int atl_keep_link = 0;
module_param_named(keep_link, atl_keep_link, uint, 0644);
-static void atl_link_up(struct atl_nic *nic)
+static void atl_start_link(struct atl_nic *nic)
{
struct atl_hw *hw = &nic->hw;
- if (hw->mcp.poll_link)
- mod_timer(&nic->link_timer, jiffies + HZ);
-
hw->link_state.force_off = 0;
hw->mcp.ops->set_link(hw, true);
+ set_bit(ATL_ST_UPDATE_LINK, &hw->state);
+ atl_schedule_work(nic);
}
-static int atl_do_open(struct atl_nic *nic)
+static void atl_stop_link(struct atl_nic *nic)
{
- int ret;
+ struct atl_hw *hw = &nic->hw;
- ret = atl_start_rings(nic);
+ hw->link_state.force_off = 1;
+ hw->mcp.ops->set_link(hw, true);
+ hw->link_state.link = 0;
+ netif_carrier_off(nic->ndev);
+}
+
+static int atl_start(struct atl_nic *nic)
+{
+ int ret = 0;
+
+ atl_start_hw_global(nic);
+
+ if (atl_keep_link || netif_running(nic->ndev))
+ atl_start_link(nic);
+
+ if (netif_running(nic->ndev))
+ ret = atl_start_rings(nic);
+
+ if (ret && !atl_keep_link)
+ atl_stop_link(nic);
+
+ /* if (ret) */
+ /* goto out; */
+ /* ret = atl_fwd_resume_rings(nic); */
+
+/* out: */
if (ret)
- return ret;
+ set_bit(ATL_ST_START_NEEDED, &nic->hw.state);
+ return ret;
+}
- if (!atl_keep_link)
- atl_link_up(nic);
+static void atl_stop(struct atl_nic *nic, bool full)
+{
+ atl_stop_rings(nic);
- return 0;
+ /* if (full) { */
+ /* atl_stop_fwd_rings(nic); */
+ /* } */
+
+ if (!atl_keep_link || full)
+ atl_stop_link(nic);
}
static int atl_open(struct net_device *ndev)
@@ -59,7 +89,7 @@ static int atl_open(struct net_device *ndev)
struct atl_nic *nic = netdev_priv(ndev);
int ret;
- if (!test_bit(ATL_ST_CONFIGURED, &nic->state)) {
+ if (!test_bit(ATL_ST_CONFIGURED, &nic->hw.state)) {
/* A previous atl_reconfigure() had failed. Try once more. */
ret = atl_setup_datapath(nic);
if (ret)
@@ -77,13 +107,11 @@ static int atl_open(struct net_device *ndev)
if (ret)
goto free_rings;
- ret = atl_do_open(nic);
+ ret = atl_start(nic);
if (ret)
goto free_rings;
- netif_tx_start_all_queues(ndev);
-
- set_bit(ATL_ST_UP, &nic->state);
+ set_bit(ATL_ST_UP, &nic->hw.state);
return 0;
free_rings:
@@ -91,25 +119,6 @@ free_rings:
return ret;
}
-static void atl_link_down(struct atl_nic *nic)
-{
- struct atl_hw *hw = &nic->hw;
-
- del_timer_sync(&nic->link_timer);
- hw->link_state.force_off = 1;
- hw->mcp.ops->set_link(hw, true);
- hw->link_state.link = 0;
- netif_carrier_off(nic->ndev);
-}
-
-static void atl_do_close(struct atl_nic *nic)
-{
- if (!atl_keep_link)
- atl_link_down(nic);
-
- atl_stop_rings(nic);
-}
-
static int atl_close(struct net_device *ndev)
{
struct atl_nic *nic = netdev_priv(ndev);
@@ -117,12 +126,10 @@ static int atl_close(struct net_device *ndev)
/* atl_close() can be called a second time if
* atl_reconfigure() fails. Just return
*/
- if (!test_and_clear_bit(ATL_ST_UP, &nic->state))
+ if (!test_and_clear_bit(ATL_ST_UP, &nic->hw.state))
return 0;
- netif_tx_stop_all_queues(ndev);
-
- atl_do_close(nic);
+ atl_stop(nic, false);
atl_free_rings(nic);
return 0;
@@ -197,7 +204,7 @@ int atl_reconfigure(struct atl_nic *nic)
goto err;
/* Re-enable link interrupts disabled in atl_clear_datapath() */
- atl_intr_enable(&nic->hw, BIT(0));
+ atl_intr_enable_non_ring(nic);
/* Number of rings might have changed, re-init RSS
* redirection table.
@@ -222,25 +229,83 @@ static struct workqueue_struct *atl_wq;
void atl_schedule_work(struct atl_nic *nic)
{
- if (!test_and_set_bit(ATL_ST_WORK_SCHED, &nic->state))
+ if (!test_and_set_bit(ATL_ST_WORK_SCHED, &nic->hw.state))
queue_work(atl_wq, &nic->work);
}
+static int atl_do_reset(struct atl_nic *nic)
+{
+ struct atl_hw *hw = &nic->hw;
+ int ret;
+ bool reset, start;
+
+ if (!test_bit(ATL_ST_ENABLED, &hw->state))
+ /* We're suspending, postpone resets till resume */
+ return 0;
+
+ reset = test_and_clear_bit(ATL_ST_RESET_NEEDED, &hw->state);
+ start = test_and_clear_bit(ATL_ST_START_NEEDED, &hw->state);
+
+ if (!reset && !start)
+ return 0;
+
+ if (reset)
+ set_bit(ATL_ST_RESETTING, &hw->state);
+ rtnl_lock();
+
+ if (reset) {
+ atl_stop(nic, true);
+
+ ret = atl_hw_reset(hw);
+ if (ret) {
+ atl_nic_err("HW reset failed, re-trying\n");
+ if (!test_and_set_bit(ATL_ST_DETACHED, &hw->state))
+ netif_device_detach(nic->ndev);
+ goto out;
+ }
+ start = true;
+ clear_bit(ATL_ST_RESETTING, &hw->state);
+ }
+
+ if (start) {
+ ret = atl_start(nic);
+ if (ret)
+ goto out;
+ }
+
+ if (test_and_clear_bit(ATL_ST_DETACHED, &hw->state))
+ netif_device_attach(nic->ndev);
+
+out:
+ rtnl_unlock();
+ return ret;
+}
+
static void atl_work(struct work_struct *work)
{
struct atl_nic *nic = container_of(work, struct atl_nic, work);
+ struct atl_hw *hw = &nic->hw;
+ int ret;
+ clear_bit(ATL_ST_WORK_SCHED, &hw->state);
+
+ atl_fw_watchdog(hw);
+ ret = atl_do_reset(nic);
+ if (ret)
+ goto out;
atl_refresh_link(nic);
- clear_bit(ATL_ST_WORK_SCHED, &nic->state);
+
+out:
+ if (test_bit(ATL_ST_ENABLED, &hw->state))
+ mod_timer(&nic->work_timer, jiffies + HZ);
}
-static void atl_link_timer(struct timer_list *timer)
+static void atl_work_timer(struct timer_list *timer)
{
struct atl_nic *nic =
- container_of(timer, struct atl_nic, link_timer);
+ container_of(timer, struct atl_nic, work_timer);
atl_schedule_work(nic);
- mod_timer(&nic->link_timer, jiffies + HZ);
}
static const struct pci_device_id atl_pci_tbl[] = {
@@ -291,16 +356,6 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct atl_hw *hw;
int disable_needed;
- if (atl_max_queues < 1 || atl_max_queues > ATL_MAX_QUEUES) {
- dev_err(&pdev->dev, "Bad atl_max_queues value %d, must be between 1 and %d inclusive\n",
- atl_max_queues, ATL_MAX_QUEUES);
- return -EINVAL;
- }
-
- ret = atl_parse_dt(&pdev->dev);
- if (ret)
- return ret;
-
ret = pci_enable_device_mem(pdev);
if (ret)
return ret;
@@ -334,9 +389,9 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&nic->stats_lock);
INIT_WORK(&nic->work, atl_work);
mutex_init(&nic->hw.mcp.lock);
- __set_bit(ATL_ST_ENABLED, &nic->state);
hw = &nic->hw;
+ __set_bit(ATL_ST_ENABLED, &hw->state);
hw->regs = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!hw->regs) {
@@ -344,10 +399,13 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_ioremap;
}
- ret = atl_hwinit(nic, id->driver_data);
+ ret = atl_hwinit(hw, id->driver_data);
if (ret)
goto err_hwinit;
+ hw->mcp.ops->set_default_link(hw);
+ hw->link_state.force_off = 1;
+
pci_set_master(pdev);
eth_platform_get_mac_address(&hw->pdev->dev, hw->mac_addr);
@@ -394,11 +452,9 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ndev->priv_flags |= IFF_UNICAST_FLT;
- timer_setup(&nic->link_timer, &atl_link_timer, 0);
+ timer_setup(&nic->work_timer, &atl_work_timer, 0);
- hw->mcp.ops->set_default_link(hw);
- hw->link_state.force_off = 1;
- hw->intr_mask = BIT(ATL_NUM_NON_RING_IRQS) - 1;
+ hw->non_ring_intr_mask = BIT(ATL_NUM_NON_RING_IRQS) - 1;
ndev->netdev_ops = &atl_ndev_ops;
ndev->mtu = 1500;
#ifdef ATL_HAVE_MINMAX_MTU
@@ -412,17 +468,27 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, nic);
netif_carrier_off(ndev);
+ /* Safe to ignore ret value here. atl_start() only returns
+ * errors when rings are started. We could race with someone
+ * doing ifup on newly created netdev, but either they will
+ * succeed with grabbing RTNL first and handle ring-related
+ * errors there, or we will be first and just bring the
+ * global HW up. */
+ rtnl_lock();
+ atl_start(nic);
+ rtnl_unlock();
+
ret = atl_hwmon_init(nic);
if (ret)
goto err_hwmon_init;
- atl_start_hw_global(nic);
- if (atl_keep_link)
- atl_link_up(nic);
+ atl_intr_enable_non_ring(nic);
+ mod_timer(&nic->work_timer, jiffies + HZ);
return 0;
err_hwmon_init:
+ atl_stop(nic, true);
unregister_netdev(nic->ndev);
err_register:
atl_clear_datapath(nic);
@@ -430,7 +496,7 @@ err_datapath:
err_hwinit:
iounmap(hw->regs);
err_ioremap:
- disable_needed = test_and_clear_bit(ATL_ST_ENABLED, &nic->state);
+ disable_needed = test_and_clear_bit(ATL_ST_ENABLED, &hw->state);
free_netdev(ndev);
err_alloc_ndev:
pci_release_regions(pdev);
@@ -450,8 +516,11 @@ static void atl_remove(struct pci_dev *pdev)
return;
netif_carrier_off(nic->ndev);
+ atl_stop(nic, true);
+ disable_needed = test_and_clear_bit(ATL_ST_ENABLED, &nic->hw.state);
+ del_timer_sync(&nic->work_timer);
+ cancel_work_sync(&nic->work);
atl_intr_disable_all(&nic->hw);
- /* atl_hw_reset(&nic->hw); */
unregister_netdev(nic->ndev);
#ifdef CONFIG_ATLFWD_FWD
@@ -460,8 +529,6 @@ static void atl_remove(struct pci_dev *pdev)
atl_clear_datapath(nic);
iounmap(nic->hw.regs);
- disable_needed = test_and_clear_bit(ATL_ST_ENABLED, &nic->state);
- cancel_work_sync(&nic->work);
free_netdev(nic->ndev);
pci_release_regions(pdev);
if (disable_needed)
@@ -476,13 +543,13 @@ static int atl_suspend_common(struct device *dev, bool deep)
int ret;
rtnl_lock();
- netif_device_detach(nic->ndev);
- if (netif_running(nic->ndev))
- atl_do_close(nic);
+ if (!test_and_set_bit(ATL_ST_DETACHED, &hw->state))
+ netif_device_detach(nic->ndev);
+
+ atl_stop(nic, true);
- if (deep && atl_keep_link)
- atl_link_down(nic);
+ atl_clear_rdm_cache(nic);
if (deep && nic->flags & ATL_FL_WOL) {
ret = hw->mcp.ops->enable_wol(hw);
@@ -490,11 +557,12 @@ static int atl_suspend_common(struct device *dev, bool deep)
atl_dev_err("Enable WoL failed: %d\n", -ret);
}
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
+ clear_bit(ATL_ST_ENABLED, &hw->state);
+ cancel_work_sync(&nic->work);
- __clear_bit(ATL_ST_ENABLED, &nic->state);
+ pci_disable_device(pdev);
+ pci_save_state(pdev);
+ pci_prepare_to_sleep(pdev);
rtnl_unlock();
@@ -526,23 +594,16 @@ static int atl_resume_common(struct device *dev, bool deep)
if (ret)
goto exit;
+ set_bit(ATL_ST_ENABLED, &nic->hw.state);
pci_set_master(pdev);
- __set_bit(ATL_ST_ENABLED, &nic->state);
if (deep) {
ret = atl_hw_reset(&nic->hw);
if (ret)
goto exit;
-
- atl_start_hw_global(nic);
}
- if (netif_running(nic->ndev))
- ret = atl_do_open(nic);
-
- if (deep && atl_keep_link)
- atl_link_up(nic);
-
+ ret = atl_start(nic);
if (ret)
goto exit;
@@ -550,7 +611,8 @@ static int atl_resume_common(struct device *dev, bool deep)
if (ret)
goto exit;
- netif_device_attach(nic->ndev);
+ if (test_and_clear_bit(ATL_ST_DETACHED, &nic->hw.state))
+ netif_device_attach(nic->ndev);
exit:
rtnl_unlock();
@@ -593,19 +655,52 @@ static struct pci_driver atl_pci_ops = {
#endif
};
+struct atl_thermal atl_def_thermal;
+
+static bool atl_def_thermal_monitor = true, atl_def_thermal_throttle = false,
+ atl_def_thermal_ignore_lims = false;
+module_param_named(thermal_monitor, atl_def_thermal_monitor, bool, 0444);
+module_param_named(thermal_throttle, atl_def_thermal_throttle, bool, 0444);
+module_param_named(thermal_ignore_limits, atl_def_thermal_ignore_lims, bool, 0444);
+
+static uint8_t atl_def_thermal_crit = 108, atl_def_thermal_high = 100,
+ atl_def_thermal_low = 80;
+module_param_named(thermal_crit, atl_def_thermal_crit, byte, 0444);
+module_param_named(thermal_high, atl_def_thermal_high, byte, 0444);
+module_param_named(thermal_low, atl_def_thermal_low, byte, 0444);
+
static int __init atl_module_init(void)
{
+ struct atl_hw *hw = NULL;
int ret;
+ atl_def_thermal.flags =
+ atl_def_thermal_monitor << atl_thermal_monitor_shift |
+ atl_def_thermal_throttle << atl_thermal_throttle_shift |
+ atl_def_thermal_ignore_lims << atl_thermal_ignore_lims_shift;
+ atl_def_thermal.crit = atl_def_thermal_crit;
+ atl_def_thermal.high = atl_def_thermal_high;
+ atl_def_thermal.low = atl_def_thermal_low;
+
+ ret = atl_verify_thermal_limits(hw, &atl_def_thermal);
+ if (ret)
+ return ret;
+
+ if (atl_max_queues < 1 || atl_max_queues > ATL_MAX_QUEUES) {
+ atl_dev_init_err("Bad atl_max_queues value %d, must be between 1 and %d inclusive\n",
+ atl_max_queues, ATL_MAX_QUEUES);
+ return -EINVAL;
+ }
+
atl_wq = create_singlethread_workqueue(atl_driver_name);
if (!atl_wq) {
pr_err("%s: Couldn't create workqueue\n", atl_driver_name);
return -ENOMEM;
}
- ret = atl_qcom_ipa_register(&atl_pci_ops);
+ ret = atl_qcom_register(&atl_pci_ops);
if (ret) {
- pr_err("%s: Failed to register driver with IPA\n",
+ pr_err("%s: Failed to register driver with platform\n",
atl_driver_name);
destroy_workqueue(atl_wq);
return ret;
@@ -613,7 +708,7 @@ static int __init atl_module_init(void)
ret = pci_register_driver(&atl_pci_ops);
if (ret) {
- atl_qcom_ipa_unregister(&atl_pci_ops);
+ atl_qcom_unregister(&atl_pci_ops);
destroy_workqueue(atl_wq);
return ret;
}
@@ -626,7 +721,7 @@ static void __exit atl_module_exit(void)
{
pci_unregister_driver(&atl_pci_ops);
- atl_qcom_ipa_unregister(&atl_pci_ops);
+ atl_qcom_unregister(&atl_pci_ops);
if (atl_wq) {
destroy_workqueue(atl_wq);
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.c
deleted file mode 100644
index ef3c68163384..000000000000
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/of.h>
-
-#include "atl_qcom.h"
-#include "atl_of.h"
-
-static const struct of_device_id aqc_matches[] = {
- { .compatible = "aquantia,aqc-107" },
- { .compatible = "aquantia,aqc-108" },
- { .compatible = "aquantia,aqc-109" },
-};
-
-int atl_parse_dt(struct device *dev)
-{
- if (!dev->of_node) {
- dev_dbg(dev, "device tree node is not present\n");
- return 0;
- }
-
- if (!of_match_node(aqc_matches, dev->of_node)) {
- dev_notice(dev, "device tree node is not compatible\n");
- return 0;
- }
-
- /* Aquantia properties go here */
-
- /* OEM properties go here */
-
- return atl_qcom_parse_dt(dev);
-}
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.h
deleted file mode 100644
index 7f857574216e..000000000000
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_of.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 _ATL_OF_H_
-#define _ATL_OF_H_
-
-#include <linux/device.h>
-
-#ifdef CONFIG_OF
-
-int atl_parse_dt(struct device *dev);
-
-#else
-
-static inline int atl_parse_dt(struct device *dev)
-{
- return 0;
-}
-
-#endif // CONFIG_OF
-
-#endif // _ATL_OF_H_
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.c
index 75132cb42076..56023aeeec0a 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.c
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 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
@@ -10,12 +10,18 @@
* GNU General Public License for more details.
*/
+#include <linux/of.h>
+
#include <linux/iommu.h>
#include <asm/dma-iommu.h>
#include <linux/platform_device.h>
+#include "atl_qcom_ipa.h"
#include "atl_qcom.h"
+static int (*atl_probe_real)(struct pci_dev *, const struct pci_device_id *);
+static void (*atl_remove_real)(struct pci_dev *);
+
static int atl_qcom_parse_smmu_attr(struct device *dev,
struct iommu_domain *domain,
const char *key,
@@ -60,7 +66,7 @@ static int atl_qcom_parse_smmu_attrs(struct device *dev,
return rc;
}
-static int atl_qcom_parse_smmu(struct device *dev)
+static int __atl_qcom_attach_smmu(struct device *dev)
{
int rc;
const char *key;
@@ -117,14 +123,110 @@ err_release_mapping:
return rc;
}
-int atl_qcom_parse_dt(struct device *dev)
+static int atl_qcom_attach_smmu(struct device *dev)
{
int rc = 0;
+ if (!dev->of_node) {
+ dev_dbg(dev, "device tree node is not present\n");
+ return 0;
+ }
+
if (of_find_property(dev->of_node, "qcom,smmu", NULL))
- rc = atl_qcom_parse_smmu(dev);
+ rc = __atl_qcom_attach_smmu(dev);
else
dev_dbg(dev, "SMMU config not present in DT\n");
return 0;
}
+
+static void atl_qcom_detach_smmu(struct device *dev)
+{
+ struct dma_iommu_mapping *mapping;
+
+ if (!dev->of_node || !of_find_property(dev->of_node, "qcom,smmu", NULL))
+ return;
+
+ mapping = to_dma_iommu_mapping(dev);
+ if (!mapping)
+ return;
+
+ arm_iommu_detach_device(dev);
+ arm_iommu_release_mapping(mapping);
+}
+
+static int atl_qcom_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int rc;
+
+ rc = atl_qcom_attach_smmu(&pdev->dev);
+ if (rc)
+ return rc;
+
+ rc = atl_probe_real(pdev, id);
+ if (rc) {
+ atl_qcom_detach_smmu(&pdev->dev);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void atl_qcom_remove(struct pci_dev *pdev)
+{
+ atl_remove_real(pdev);
+ atl_qcom_detach_smmu(&pdev->dev);
+}
+
+static int __atl_qcom_register(struct pci_driver *pdrv)
+{
+ if (atl_probe_real || atl_remove_real) {
+ pr_err("%s: Driver already registered\n", __func__);
+ return -EEXIST;
+ }
+
+ atl_probe_real = pdrv->probe;
+ pdrv->probe = atl_qcom_probe;
+
+ atl_remove_real = pdrv->remove;
+ pdrv->remove = atl_qcom_remove;
+
+ return 0;
+}
+
+static void __atl_qcom_unregister(struct pci_driver *pdrv)
+{
+ if (atl_probe_real) {
+ pdrv->probe = atl_probe_real;
+ atl_probe_real = NULL;
+ }
+
+ if (atl_remove_real) {
+ pdrv->remove = atl_remove_real;
+ atl_remove_real = NULL;
+ }
+}
+
+int atl_qcom_register(struct pci_driver *pdrv)
+{
+ int rc;
+
+ rc = __atl_qcom_register(pdrv);
+ if (rc)
+ return rc;
+
+ rc = atl_qcom_ipa_register(pdrv);
+ if (rc) {
+ pr_err("%s: Failed to register driver with IPA\n", __func__);
+ __atl_qcom_unregister(pdrv);
+ return rc;
+ }
+
+ return 0;
+}
+
+void atl_qcom_unregister(struct pci_driver *pdrv)
+{
+ atl_qcom_ipa_unregister(pdrv);
+ __atl_qcom_unregister(pdrv);
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.h
index 2730d048e47c..08bfffa722d4 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.h
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 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
@@ -13,16 +13,17 @@
#ifndef _ATL_QCOM_H_
#define _ATL_QCOM_H_
+#include <linux/pci.h>
+
#ifdef CONFIG_AQFWD_QCOM
-int atl_qcom_parse_dt(struct device *dev);
+int atl_qcom_register(struct pci_driver *pdrv);
+void atl_qcom_unregister(struct pci_driver *pdrv);
#else
-static inline int atl_qcom_parse_dt(struct device *dev)
-{
- return 0;
-}
+static inline int atl_qcom_register(struct pci_driver *pdrv) { return 0; }
+static inline void atl_qcom_unregister(struct pci_driver *pdrv) { return; }
#endif // CONFIG_AQFWD_QCOM
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c
index 5455aec58233..5ae31f627019 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c
@@ -16,6 +16,9 @@
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/cpu.h>
+#include <uapi/linux/ip.h>
+#include <uapi/linux/tcp.h>
+#include <uapi/linux/udp.h>
#include "atl_trace.h"
@@ -384,7 +387,7 @@ static bool atl_clean_tx(struct atl_desc_ring *ring)
smp_mb();
if (__netif_subqueue_stopped(ndev, ring->qvec->idx) &&
- test_bit(ATL_ST_UP, &nic->state)) {
+ test_bit(ATL_ST_RINGS_RUNNING, &nic->hw.state)) {
atl_nic_dbg("restarting tx queue\n");
netif_wake_subqueue(ndev, ring->qvec->idx);
atl_update_ring_stat(ring, tx.tx_restart, 1);
@@ -394,12 +397,72 @@ static bool atl_clean_tx(struct atl_desc_ring *ring)
return !!budget;
}
+/* work around HW bugs in checksum calculation:
+ * - packets less than 60 octets
+ * - ip, tcp or udp checksum is 0xFFFF
+ */
+static bool atl_checksum_workaround(struct sk_buff *skb,
+ struct atl_rx_desc_wb *desc)
+{
+ int ip_header_offset = 14;
+ int l4_header_offset = 0;
+ struct iphdr *ip;
+ struct tcphdr *tcp;
+ struct udphdr *udp;
+
+ if (desc->pkt_len <= 60)
+ return true;
+
+ if ((desc->pkt_type & atl_rx_pkt_type_vlan_msk) ==
+ atl_rx_pkt_type_vlan)
+ ip_header_offset += 4;
+
+ if ((desc->pkt_type & atl_rx_pkt_type_vlan_msk) ==
+ atl_rx_pkt_type_dbl_vlan)
+ ip_header_offset += 8;
+
+ switch (desc->pkt_type & atl_rx_pkt_type_l3_msk) {
+ case atl_rx_pkt_type_ipv4:
+ ip = (struct iphdr *) &skb->data[ip_header_offset];
+
+ if (ip->check == 0xFFFF)
+ return true;
+ l4_header_offset = ip->ihl << 2;
+ break;
+ case atl_rx_pkt_type_ipv6:
+ l4_header_offset = ip_header_offset + sizeof(struct ipv6hdr);
+ break;
+ default:
+ return false;
+ }
+
+ switch (desc->pkt_type & atl_rx_pkt_type_l4_msk) {
+ case atl_rx_pkt_type_tcp:
+ tcp = (struct tcphdr *) &skb->data[ip_header_offset +
+ l4_header_offset];
+
+ if (tcp->check == 0xFFFF)
+ return true;
+ break;
+ case atl_rx_pkt_type_udp:
+ udp = (struct udphdr *) &skb->data[ip_header_offset +
+ l4_header_offset];
+ if (udp->check == 0xFFFF)
+ return true;
+ break;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
static bool atl_rx_checksum(struct sk_buff *skb, struct atl_rx_desc_wb *desc,
struct atl_desc_ring *ring)
{
struct atl_nic *nic = ring->qvec->nic;
struct net_device *ndev = nic->ndev;
- int csum_ok = 1, recheck = 0;
+ int csum_ok = 1;
skb_checksum_none_assert(skb);
@@ -426,7 +489,6 @@ static bool atl_rx_checksum(struct sk_buff *skb, struct atl_rx_desc_wb *desc,
switch (desc->pkt_type & atl_rx_pkt_type_l4_msk) {
case atl_rx_pkt_type_tcp:
case atl_rx_pkt_type_udp:
- recheck = desc->pkt_len <= 60;
csum_ok &= !(desc->rx_stat & atl_rx_stat_l4_err);
break;
default:
@@ -436,8 +498,10 @@ static bool atl_rx_checksum(struct sk_buff *skb, struct atl_rx_desc_wb *desc,
if (csum_ok) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
return true;
- } else if (recheck)
- return true;
+ } else {
+ if (atl_checksum_workaround(skb, desc))
+ return true;
+ }
atl_update_ring_stat(ring, rx.csum_err, 1);
@@ -1135,7 +1199,7 @@ void atl_clear_datapath(struct atl_nic *nic)
* pci_ops->remove(), without an intervening
* atl_setup_datapath().
*/
- if (!test_and_clear_bit(ATL_ST_CONFIGURED, &nic->state))
+ if (!test_and_clear_bit(ATL_ST_CONFIGURED, &nic->hw.state))
return;
atl_free_link_intr(nic);
@@ -1229,7 +1293,7 @@ int atl_setup_datapath(struct atl_nic *nic)
nic->max_mtu = atl_rx_linear ? ATL_MAX_RX_LINEAR_MTU : ATL_MAX_MTU;
- set_bit(ATL_ST_CONFIGURED, &nic->state);
+ set_bit(ATL_ST_CONFIGURED, &nic->hw.state);
return 0;
err_link_intr:
@@ -1620,6 +1684,9 @@ int atl_start_rings(struct atl_nic *nic)
struct atl_queue_vec *qvec;
int ret;
+ if (test_bit(ATL_ST_RINGS_RUNNING, &hw->state))
+ return 0;
+
if (nic->flags & ATL_FL_MULTIPLE_VECTORS) {
mask = BIT(nic->nvecs + ATL_NUM_NON_RING_IRQS) -
BIT(ATL_NUM_NON_RING_IRQS);
@@ -1638,6 +1705,9 @@ int atl_start_rings(struct atl_nic *nic)
goto stop;
}
+ set_bit(ATL_ST_RINGS_RUNNING, &hw->state);
+ netif_tx_start_all_queues(nic->ndev);
+
return 0;
stop:
@@ -1647,17 +1717,28 @@ stop:
return ret;
}
+void atl_clear_rdm_cache(struct atl_nic *nic)
+{
+ struct atl_hw *hw = &nic->hw;
+
+ atl_write_bit(hw, 0x5a00, 0, 1);
+ udelay(10);
+ atl_write_bit(hw, 0x5a00, 0, 0);
+}
+
void atl_stop_rings(struct atl_nic *nic)
{
struct atl_queue_vec *qvec;
- struct atl_hw *hw = &nic->hw;
+
+ if (!test_and_clear_bit(ATL_ST_RINGS_RUNNING, &nic->hw.state))
+ return;
+
+ netif_tx_stop_all_queues(nic->ndev);
atl_for_each_qvec(nic, qvec)
atl_stop_qvec(qvec);
- atl_write_bit(hw, 0x5a00, 0, 1);
- udelay(10);
- atl_write_bit(hw, 0x5a00, 0, 0);
+ atl_clear_rdm_cache(nic);
}
int atl_set_features(struct net_device *ndev, netdev_features_t features)
@@ -1698,6 +1779,10 @@ void atl_update_global_stats(struct atl_nic *nic)
int i;
struct atl_ring_stats stats;
+ if (!test_bit(ATL_ST_ENABLED, &nic->hw.state) ||
+ test_bit(ATL_ST_RESETTING, &nic->hw.state))
+ return;
+
memset(&stats, 0, sizeof(stats));
atl_update_eth_stats(nic);
diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt
index 4b4c614d36a6..a9aef75a8a85 100644
--- a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt
+++ b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt
@@ -1,3 +1,13 @@
+Version 1.0.20
+==============
+net: aquantia: Re-initialize fwd rings on driver resume
+Do entire suspend from dev_pm_ops->suspend() (AQ052)
+Prevent atl_update_global_stats() calls when suspended (AQ056) (ATLDRV-1021)
+Implement thermal throttling (ATLDRV-1009)
+Add log message when high temperature treshold is reached (ATLDRV-998))
+Implement FW heartbeat watchdog (AQ010) (ATLDRV-502)
+Workaround checksum offload bugs (ATLDRV-1013)
+
Version 1.0.19
==============
Fix freeing of buf vaddr vector in FWD API (AQ050)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c
index 67eafb233d93..0e987a776be0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c
@@ -27,6 +27,11 @@ enum ipa_eth_states {
IPA_ETH_ST_MAX,
};
+enum ipa_eth_dev_states {
+ IPA_ETH_DEV_ST_UNPAIRING,
+ IPA_ETH_DEV_ST_MAX,
+};
+
static unsigned long ipa_eth_state;
static struct dentry *ipa_eth_debugfs;
@@ -56,12 +61,15 @@ static inline bool ipa_eth_ready(void)
static inline bool initable(struct ipa_eth_device *eth_dev)
{
- return eth_dev->init;
+ return !test_bit(IPA_ETH_DEV_ST_UNPAIRING, &eth_dev->state) &&
+ eth_dev->init;
}
static inline bool startable(struct ipa_eth_device *eth_dev)
{
- return eth_dev->init && eth_dev->start &&
+ return !test_bit(IPA_ETH_DEV_ST_UNPAIRING, &eth_dev->state) &&
+ eth_dev->init &&
+ eth_dev->start &&
test_bit(IPA_ETH_IF_ST_LOWER_UP, &eth_dev->if_state);
}
@@ -148,9 +156,13 @@ static int ipa_eth_deinit_device(struct ipa_eth_device *eth_dev)
return 0;
}
+static void ipa_eth_free_msg(void *buff, u32 len, u32 type) {}
+
static int ipa_eth_start_device(struct ipa_eth_device *eth_dev)
{
int rc;
+ struct ipa_msg_meta msg_meta;
+ struct ipa_ecm_msg ecm_msg;
if (eth_dev->of_state == IPA_ETH_OF_ST_STARTED)
return 0;
@@ -180,6 +192,16 @@ static int ipa_eth_start_device(struct ipa_eth_device *eth_dev)
return rc;
}
+ memset(&msg_meta, 0, sizeof(msg_meta));
+ memset(&ecm_msg, 0, sizeof(ecm_msg));
+
+ ecm_msg.ifindex = eth_dev->net_dev->ifindex;
+ strlcpy(ecm_msg.name, eth_dev->net_dev->name, IPA_RESOURCE_NAME_MAX);
+
+ msg_meta.msg_type = ECM_CONNECT;
+ msg_meta.msg_len = sizeof(struct ipa_ecm_msg);
+ (void) ipa_send_msg(&msg_meta, &ecm_msg, ipa_eth_free_msg);
+
ipa_eth_dev_log(eth_dev, "Started device");
eth_dev->of_state = IPA_ETH_OF_ST_STARTED;
@@ -190,6 +212,18 @@ static int ipa_eth_start_device(struct ipa_eth_device *eth_dev)
static int ipa_eth_stop_device(struct ipa_eth_device *eth_dev)
{
int rc;
+ struct ipa_msg_meta msg_meta;
+ struct ipa_ecm_msg ecm_msg;
+
+ memset(&msg_meta, 0, sizeof(msg_meta));
+ memset(&ecm_msg, 0, sizeof(ecm_msg));
+
+ ecm_msg.ifindex = eth_dev->net_dev->ifindex;
+ strlcpy(ecm_msg.name, eth_dev->net_dev->name, IPA_RESOURCE_NAME_MAX);
+
+ msg_meta.msg_type = ECM_DISCONNECT;
+ msg_meta.msg_len = sizeof(struct ipa_ecm_msg);
+ (void) ipa_send_msg(&msg_meta, &ecm_msg, ipa_eth_free_msg);
if (eth_dev->of_state == IPA_ETH_OF_ST_DEINITED)
return 0;
@@ -342,7 +376,7 @@ static void ipa_eth_dev_start_timer_cb(unsigned long data)
ipa_eth_refresh_device(eth_dev);
}
-static int ipa_eth_netdev_event_change(struct ipa_eth_device *eth_dev)
+static int __ipa_eth_netdev_event(struct ipa_eth_device *eth_dev)
{
bool refresh_needed = netif_carrier_ok(eth_dev->net_dev) ?
!test_and_set_bit(IPA_ETH_IF_ST_LOWER_UP, &eth_dev->if_state) :
@@ -365,17 +399,9 @@ static int ipa_eth_netdev_event(struct notifier_block *nb,
if (net_dev != eth_dev->net_dev)
return NOTIFY_DONE;
- ipa_eth_dev_log(eth_dev, "Received netdev event %lu", event);
-
- switch (event) {
- case NETDEV_CHANGE:
- return ipa_eth_netdev_event_change(eth_dev);
- default:
- /* Ignore other events */
- break;
- }
+ ipa_eth_dev_log(eth_dev, "Received netdev event 0x%04lx", event);
- return NOTIFY_DONE;
+ return __ipa_eth_netdev_event(eth_dev);
}
static int ipa_eth_uc_ready_cb(struct notifier_block *nb,
@@ -620,7 +646,7 @@ static void __ipa_eth_unpair_device(struct ipa_eth_device *eth_dev)
flush_work(&eth_dev->refresh);
- eth_dev->init = eth_dev->start = false;
+ set_bit(IPA_ETH_DEV_ST_UNPAIRING, &eth_dev->state);
ipa_eth_refresh_device(eth_dev);
flush_work(&eth_dev->refresh);
@@ -628,6 +654,8 @@ static void __ipa_eth_unpair_device(struct ipa_eth_device *eth_dev)
unregister_netdevice_notifier(&eth_dev->netdevice_nb);
ipa_eth_offload_unpair_device(eth_dev);
+
+ clear_bit(IPA_ETH_DEV_ST_UNPAIRING, &eth_dev->state);
}
static void ipa_eth_pair_devices(void)
@@ -904,6 +932,7 @@ int ipa_eth_register_offload_driver(struct ipa_eth_offload_driver *od)
ipa_eth_log("Registered offload driver %s", od->name);
ipa_eth_pair_devices();
+ ipa_eth_refresh_devices();
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c
index 8f3983dd7c7d..006953a825ce 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c
@@ -242,6 +242,14 @@ int ipa_eth_gsi_dealloc(struct ipa_eth_channel *ch)
}
if (ep_ctx->gsi_evt_ring_hdl != ~0) {
+ gsi_rc = gsi_reset_evt_ring(ep_ctx->gsi_evt_ring_hdl);
+ if (gsi_rc != GSI_STATUS_SUCCESS) {
+ ipa_eth_dev_err(ch->eth_dev,
+ "Failed to reset event ring %lu",
+ ep_ctx->gsi_evt_ring_hdl);
+ return gsi_rc;
+ }
+
gsi_rc = gsi_dealloc_evt_ring(ep_ctx->gsi_evt_ring_hdl);
if (gsi_rc != GSI_STATUS_SUCCESS) {
ipa_eth_dev_err(ch->eth_dev,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c
index 89acc788609c..77d92d9ae82f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c
@@ -207,6 +207,8 @@ int ipa_eth_offload_register_driver(struct ipa_eth_offload_driver *od)
void ipa_eth_offload_unregister_driver(struct ipa_eth_offload_driver *od)
{
+ debugfs_remove_recursive(od->debugfs);
+
mutex_lock(&ipa_eth_offload_drivers_lock);
list_del(&od->driver_list);
mutex_unlock(&ipa_eth_offload_drivers_lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pm.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pm.c
index d969bb56b834..a8d4c7b7b50b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pm.c
@@ -11,6 +11,7 @@
*/
#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
#include "ipa_eth_i.h"
@@ -100,7 +101,10 @@ static u32 __fetch_ethtool_link_speed(struct ipa_eth_device *eth_dev)
int rc;
struct ethtool_link_ksettings link_ksettings;
+ rtnl_lock();
rc = __ethtool_get_link_ksettings(eth_dev->net_dev, &link_ksettings);
+ rtnl_unlock();
+
if (rc) {
ipa_eth_dev_err(eth_dev,
"Failed to obtain link settings via ethtool");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c
index 94e1acde00f6..c71dcee6d586 100644..100755
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c
@@ -537,7 +537,7 @@ static dma_addr_t ipa_mpm_smmu_map(void *va_addr,
/* check cache coherent */
if (ipa_mpm_ctx->dev_info.is_cache_coherent) {
- IPA_MPM_DBG(" enable cache coherent\n");
+ IPA_MPM_DBG_LOW(" enable cache coherent\n");
prot |= IOMMU_CACHE;
}
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 4e44e94e4ac0..d5fcdc348730 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -3026,7 +3026,7 @@ int ipa3_create_wdi_mapping(u32 num_buffers, struct ipa_wdi_buffer_info *info)
}
for (i = 0; i < num_buffers; i++) {
- IPADBG("i=%d pa=0x%pa iova=0x%lx sz=0x%zx\n", i,
+ IPADBG_LOW("i=%d pa=0x%pa iova=0x%lx sz=0x%zx\n", i,
&info[i].pa, info[i].iova, info[i].size);
info[i].result = ipa3_iommu_map(cb->iommu,
rounddown(info[i].iova, PAGE_SIZE),
@@ -3056,7 +3056,7 @@ int ipa3_release_wdi_mapping(u32 num_buffers, struct ipa_wdi_buffer_info *info)
}
for (i = 0; i < num_buffers; i++) {
- IPADBG("i=%d pa=0x%pa iova=0x%lx sz=0x%zx\n", i,
+ IPADBG_LOW("i=%d pa=0x%pa iova=0x%lx sz=0x%zx\n", i,
&info[i].pa, info[i].iova, info[i].size);
info[i].result = iommu_unmap(cb->iommu,
rounddown(info[i].iova, PAGE_SIZE),
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
index 7ef12d8c54c7..3395f0b327ae 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
@@ -4088,6 +4088,7 @@ bdy_alloc_fail:
int ipahal_fltrt_allocate_hw_sys_tbl(struct ipa_mem_buffer *tbl_mem)
{
struct ipahal_fltrt_obj *obj;
+ gfp_t flag = GFP_KERNEL;
IPAHAL_DBG_LOW("Entry\n");
@@ -4105,10 +4106,14 @@ int ipahal_fltrt_allocate_hw_sys_tbl(struct ipa_mem_buffer *tbl_mem)
/* add word for rule-set terminator */
tbl_mem->size += obj->tbl_width;
-
+alloc:
tbl_mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, tbl_mem->size,
- &tbl_mem->phys_base, GFP_KERNEL);
+ &tbl_mem->phys_base, flag);
if (!tbl_mem->base) {
+ if (flag == GFP_KERNEL) {
+ flag = GFP_ATOMIC;
+ goto alloc;
+ }
IPAHAL_ERR("fail to alloc DMA buf of size %d\n",
tbl_mem->size);
return -ENOMEM;
diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c
index beb6f519539e..744f26dc7930 100644
--- a/drivers/power/supply/qcom/qg-battery-profile.c
+++ b/drivers/power/supply/qcom/qg-battery-profile.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 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
@@ -107,7 +107,8 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
rc = -EINVAL;
} else {
/* OCV is passed as deci-uV - 10^-4 V */
- soc = interpolate_soc(&battery->profile[bp.table_index],
+ soc = qg_interpolate_soc(
+ &battery->profile[bp.table_index],
bp.batt_temp, UV_TO_DECIUV(bp.ocv_uv));
soc = CAP(QG_MIN_SOC, QG_MAX_SOC, soc);
rc = put_user(soc, &bp_user->soc);
@@ -127,7 +128,7 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- ocv_uv = interpolate_var(
+ ocv_uv = qg_interpolate_var(
&battery->profile[bp.table_index],
bp.batt_temp, bp.soc);
ocv_uv = DECIUV_TO_UV(ocv_uv);
@@ -149,7 +150,7 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- fcc_mah = interpolate_single_row_lut(
+ fcc_mah = qg_interpolate_single_row_lut(
&battery->profile[bp.table_index],
bp.batt_temp, DEGC_SCALE);
fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
@@ -169,7 +170,8 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- var = interpolate_var(&battery->profile[bp.table_index],
+ var = qg_interpolate_var(
+ &battery->profile[bp.table_index],
bp.batt_temp, bp.soc);
var = CAP(QG_MIN_VAR, QG_MAX_VAR, var);
rc = put_user(var, &bp_user->var);
@@ -189,7 +191,7 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- slope = interpolate_slope(
+ slope = qg_interpolate_slope(
&battery->profile[bp.table_index],
bp.batt_temp, bp.soc);
slope = CAP(QG_MIN_SLOPE, QG_MAX_SLOPE, slope);
@@ -401,7 +403,7 @@ int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging)
if (!the_battery || !the_battery->profile_node)
return -ENODEV;
- *soc = interpolate_soc(&the_battery->profile[table_index],
+ *soc = qg_interpolate_soc(&the_battery->profile[table_index],
batt_temp, UV_TO_DECIUV(ocv_uv));
*soc = CAP(0, 100, DIV_ROUND_CLOSEST(*soc, 100));
@@ -417,7 +419,7 @@ int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging)
if (!the_battery || !the_battery->profile_node)
return -ENODEV;
- fcc_mah = interpolate_single_row_lut(
+ fcc_mah = qg_interpolate_single_row_lut(
&the_battery->profile[table_index],
batt_temp, DEGC_SCALE);
fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index eb85b4e1ee36..31404fd7189e 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -63,6 +63,7 @@ struct qg_dt {
int shutdown_soc_threshold;
int min_sleep_time_secs;
int sys_min_volt_mv;
+ int fvss_vbat_mv;
bool hold_soc_while_full;
bool linearize_soc;
bool cl_disable;
@@ -73,6 +74,7 @@ struct qg_dt {
bool use_s7_ocv;
bool qg_sleep_config;
bool qg_fast_chg_cfg;
+ bool fvss_enable;
};
struct qg_esr_data {
@@ -134,6 +136,7 @@ struct qpnp_qg {
bool dc_present;
bool charge_full;
bool force_soc;
+ bool fvss_active;
int charge_status;
int charge_type;
int chg_iterm_ma;
@@ -142,6 +145,8 @@ struct qpnp_qg {
int esr_nominal;
int soh;
int soc_reporting_ready;
+ int last_fifo_v_uv;
+ int last_fifo_i_ua;
u32 fifo_done_count;
u32 wa_flags;
u32 seq_no;
@@ -150,6 +155,8 @@ struct qpnp_qg {
u32 esr_last;
u32 s2_state;
u32 s2_state_mask;
+ u32 soc_fvss_entry;
+ u32 vbat_fvss_entry;
ktime_t last_user_update_time;
ktime_t last_fifo_update_time;
unsigned long last_maint_soc_update_time;
diff --git a/drivers/power/supply/qcom/qg-profile-lib.c b/drivers/power/supply/qcom/qg-profile-lib.c
index 2af997ecac0e..c506fea51cdb 100644
--- a/drivers/power/supply/qcom/qg-profile-lib.c
+++ b/drivers/power/supply/qcom/qg-profile-lib.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,7 +16,7 @@
#include "qg-profile-lib.h"
#include "qg-defs.h"
-static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+int qg_linear_interpolate(int y0, int x0, int y1, int x1, int x)
{
if (y0 == y1 || x == x0)
return y0;
@@ -26,7 +26,7 @@ static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
}
-int interpolate_single_row_lut(struct profile_table_data *lut,
+int qg_interpolate_single_row_lut(struct profile_table_data *lut,
int x, int scale)
{
int i, result;
@@ -52,7 +52,7 @@ int interpolate_single_row_lut(struct profile_table_data *lut,
if (x == lut->col_entries[i] * scale) {
result = lut->data[0][i];
} else {
- result = linear_interpolate(
+ result = qg_linear_interpolate(
lut->data[0][i-1],
lut->col_entries[i-1] * scale,
lut->data[0][i],
@@ -63,7 +63,7 @@ int interpolate_single_row_lut(struct profile_table_data *lut,
return result;
}
-int interpolate_soc(struct profile_table_data *lut,
+int qg_interpolate_soc(struct profile_table_data *lut,
int batt_temp, int ocv)
{
int i, j, soc_high, soc_low, soc;
@@ -94,7 +94,7 @@ int interpolate_soc(struct profile_table_data *lut,
if (ocv >= lut->data[i][j]) {
if (ocv == lut->data[i][j])
return lut->row_entries[i];
- soc = linear_interpolate(
+ soc = qg_linear_interpolate(
lut->row_entries[i],
lut->data[i][j],
lut->row_entries[i - 1],
@@ -115,7 +115,7 @@ int interpolate_soc(struct profile_table_data *lut,
for (i = 0; i < rows-1; i++) {
if (soc_high == 0 && is_between(lut->data[i][j],
lut->data[i+1][j], ocv)) {
- soc_high = linear_interpolate(
+ soc_high = qg_linear_interpolate(
lut->row_entries[i],
lut->data[i][j],
lut->row_entries[i + 1],
@@ -125,7 +125,7 @@ int interpolate_soc(struct profile_table_data *lut,
if (soc_low == 0 && is_between(lut->data[i][j-1],
lut->data[i+1][j-1], ocv)) {
- soc_low = linear_interpolate(
+ soc_low = qg_linear_interpolate(
lut->row_entries[i],
lut->data[i][j-1],
lut->row_entries[i + 1],
@@ -134,7 +134,7 @@ int interpolate_soc(struct profile_table_data *lut,
}
if (soc_high && soc_low) {
- soc = linear_interpolate(
+ soc = qg_linear_interpolate(
soc_low,
lut->col_entries[j-1] * DEGC_SCALE,
soc_high,
@@ -155,7 +155,7 @@ int interpolate_soc(struct profile_table_data *lut,
return 10000;
}
-int interpolate_var(struct profile_table_data *lut,
+int qg_interpolate_var(struct profile_table_data *lut,
int batt_temp, int soc)
{
int i, var1, var2, var, rows, cols;
@@ -199,7 +199,7 @@ int interpolate_var(struct profile_table_data *lut,
break;
if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
- var = linear_interpolate(
+ var = qg_linear_interpolate(
lut->data[row1][i],
lut->row_entries[row1],
lut->data[row2][i],
@@ -208,21 +208,21 @@ int interpolate_var(struct profile_table_data *lut,
return var;
}
- var1 = linear_interpolate(
+ var1 = qg_linear_interpolate(
lut->data[row1][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row1][i],
lut->col_entries[i] * DEGC_SCALE,
batt_temp);
- var2 = linear_interpolate(
+ var2 = qg_linear_interpolate(
lut->data[row2][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row2][i],
lut->col_entries[i] * DEGC_SCALE,
batt_temp);
- var = linear_interpolate(
+ var = qg_linear_interpolate(
var1,
lut->row_entries[row1],
var2,
@@ -232,7 +232,7 @@ int interpolate_var(struct profile_table_data *lut,
return var;
}
-int interpolate_slope(struct profile_table_data *lut,
+int qg_interpolate_slope(struct profile_table_data *lut,
int batt_temp, int soc)
{
int i, ocvrow1, ocvrow2, rows, cols;
@@ -284,14 +284,14 @@ int interpolate_slope(struct profile_table_data *lut,
lut->row_entries[row2]);
return slope;
}
- ocvrow1 = linear_interpolate(
+ ocvrow1 = qg_linear_interpolate(
lut->data[row1][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row1][i],
lut->col_entries[i] * DEGC_SCALE,
batt_temp);
- ocvrow2 = linear_interpolate(
+ ocvrow2 = qg_linear_interpolate(
lut->data[row2][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row2][i],
diff --git a/drivers/power/supply/qcom/qg-profile-lib.h b/drivers/power/supply/qcom/qg-profile-lib.h
index eb7263dd7395..48408e04ab42 100644
--- a/drivers/power/supply/qcom/qg-profile-lib.h
+++ b/drivers/power/supply/qcom/qg-profile-lib.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -22,13 +22,14 @@ struct profile_table_data {
int **data;
};
-int interpolate_single_row_lut(struct profile_table_data *lut,
+int qg_linear_interpolate(int y0, int x0, int y1, int x1, int x);
+int qg_interpolate_single_row_lut(struct profile_table_data *lut,
int x, int scale);
-int interpolate_soc(struct profile_table_data *lut,
+int qg_interpolate_soc(struct profile_table_data *lut,
int batt_temp, int ocv);
-int interpolate_var(struct profile_table_data *lut,
+int qg_interpolate_var(struct profile_table_data *lut,
int batt_temp, int soc);
-int interpolate_slope(struct profile_table_data *lut,
+int qg_interpolate_slope(struct profile_table_data *lut,
int batt_temp, int soc);
#endif /*__QG_PROFILE_LIB_H__ */
diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h
index 95276251ddd8..d2591280622b 100644
--- a/drivers/power/supply/qcom/qg-reg.h
+++ b/drivers/power/supply/qcom/qg-reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 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
@@ -128,6 +128,7 @@
#define QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET 0x6E /* 4-byte 0x6E-0x71 */
#define QG_SDAM_ESR_CHARGE_SF_OFFSET 0x72 /* 2-byte 0x72-0x73 */
#define QG_SDAM_ESR_DISCHARGE_SF_OFFSET 0x74 /* 2-byte 0x74-0x75 */
+#define QG_SDAM_MAGIC_OFFSET 0x80 /* 4-byte 0x80-0x83 */
#define QG_SDAM_MAX_OFFSET 0xA4
/* Below offset is used by PBS */
diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c
index a7cb97e0e53d..95ac8ecc61c9 100644
--- a/drivers/power/supply/qcom/qg-sdam.c
+++ b/drivers/power/supply/qcom/qg-sdam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -88,6 +88,11 @@ static struct qg_sdam_info sdam_info[] = {
.offset = QG_SDAM_ESR_DISCHARGE_SF_OFFSET,
.length = 2,
},
+ [SDAM_MAGIC] = {
+ .name = "SDAM_MAGIC_OFFSET",
+ .offset = QG_SDAM_MAGIC_OFFSET,
+ .length = 4,
+ },
};
int qg_sdam_write(u8 param, u32 data)
@@ -242,6 +247,23 @@ int qg_sdam_write_all(u32 *sdam_data)
return 0;
}
+int qg_sdam_clear(void)
+{
+ int i, rc = 0;
+ struct qg_sdam *chip = the_chip;
+ u8 data = 0;
+
+ if (!chip) {
+ pr_err("Invalid sdam-chip pointer\n");
+ return -EINVAL;
+ }
+
+ for (i = SDAM_MIN_OFFSET; i <= SDAM_MAX_OFFSET; i++)
+ rc |= qg_sdam_multibyte_write(i, &data, 1);
+
+ return rc;
+}
+
int qg_sdam_init(struct device *dev)
{
int rc;
diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h
index 45218a83776e..d365f25def7b 100644
--- a/drivers/power/supply/qcom/qg-sdam.h
+++ b/drivers/power/supply/qcom/qg-sdam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019 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
@@ -14,6 +14,8 @@
#define __QG_SDAM_H__
#define SDAM_TYPE 0x2E
+#define SDAM_MIN_OFFSET 0x45
+#define SDAM_MAX_OFFSET 0xB3
enum qg_sdam_param {
SDAM_VALID,
@@ -28,6 +30,7 @@ enum qg_sdam_param {
SDAM_ESR_DISCHARGE_DELTA,
SDAM_ESR_CHARGE_SF,
SDAM_ESR_DISCHARGE_SF,
+ SDAM_MAGIC,
SDAM_MAX,
};
@@ -43,5 +46,6 @@ int qg_sdam_write_all(u32 *sdam_data);
int qg_sdam_read_all(u32 *sdam_data);
int qg_sdam_multibyte_write(u32 offset, u8 *sdam_data, u32 length);
int qg_sdam_multibyte_read(u32 offset, u8 *sdam_data, u32 length);
+int qg_sdam_clear(void);
#endif
diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c
index 4c227af2665a..21e8171651fe 100644
--- a/drivers/power/supply/qcom/qg-soc.c
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -24,6 +24,7 @@
#include "qg-reg.h"
#include "qg-util.h"
#include "qg-defs.h"
+#include "qg-profile-lib.h"
#include "qg-soc.h"
#define DEFAULT_UPDATE_TIME_MS 64000
@@ -36,6 +37,11 @@ module_param_named(
soc_interval_ms, qg_delta_soc_interval_ms, int, 0600
);
+static int qg_fvss_delta_soc_interval_ms = 10000;
+module_param_named(
+ fvss_soc_interval_ms, qg_fvss_delta_soc_interval_ms, int, 0600
+);
+
static int qg_delta_soc_cold_interval_ms = 4000;
module_param_named(
soc_cold_interval_ms, qg_delta_soc_cold_interval_ms, int, 0600
@@ -46,6 +52,84 @@ module_param_named(
maint_soc_update_ms, qg_maint_soc_update_ms, int, 0600
);
+/* FVSS scaling only based on VBAT */
+static int qg_fvss_vbat_scaling = 1;
+module_param_named(
+ fvss_vbat_scaling, qg_fvss_vbat_scaling, int, 0600
+);
+
+static int qg_process_fvss_soc(struct qpnp_qg *chip, int sys_soc)
+{
+ int rc, vbat_uv = 0, vbat_cutoff_uv = chip->dt.vbatt_cutoff_mv * 1000;
+ int soc_vbat = 0, wt_vbat = 0, wt_sys = 0, soc_fvss = 0;
+
+ if (!chip->dt.fvss_enable)
+ return 0;
+
+ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING)
+ goto exit_soc_scale;
+
+ rc = qg_get_battery_voltage(chip, &vbat_uv);
+ if (rc < 0)
+ goto exit_soc_scale;
+
+ if (!chip->last_fifo_v_uv)
+ chip->last_fifo_v_uv = vbat_uv;
+
+ if (chip->last_fifo_v_uv > (chip->dt.fvss_vbat_mv * 1000)) {
+ qg_dbg(chip, QG_DEBUG_SOC, "FVSS: last_fifo_v=%d fvss_entry_uv=%d - exit\n",
+ chip->last_fifo_v_uv, chip->dt.fvss_vbat_mv * 1000);
+ goto exit_soc_scale;
+ }
+
+ /* Enter FVSS */
+ if (!chip->fvss_active) {
+ chip->vbat_fvss_entry = CAP(vbat_cutoff_uv,
+ chip->dt.fvss_vbat_mv * 1000,
+ chip->last_fifo_v_uv);
+ chip->soc_fvss_entry = sys_soc;
+ chip->fvss_active = true;
+ } else if (chip->last_fifo_v_uv > chip->vbat_fvss_entry) {
+ /* VBAT has gone beyond the entry voltage */
+ chip->vbat_fvss_entry = chip->last_fifo_v_uv;
+ chip->soc_fvss_entry = sys_soc;
+ }
+
+ soc_vbat = qg_linear_interpolate(chip->soc_fvss_entry,
+ chip->vbat_fvss_entry,
+ 0,
+ vbat_cutoff_uv,
+ chip->last_fifo_v_uv);
+ soc_vbat = CAP(0, 100, soc_vbat);
+
+ if (qg_fvss_vbat_scaling) {
+ wt_vbat = 100;
+ wt_sys = 0;
+ } else {
+ wt_sys = qg_linear_interpolate(100,
+ chip->soc_fvss_entry,
+ 0,
+ 0,
+ sys_soc);
+ wt_sys = CAP(0, 100, wt_sys);
+ wt_vbat = 100 - wt_sys;
+ }
+
+ soc_fvss = ((soc_vbat * wt_vbat) + (sys_soc * wt_sys)) / 100;
+ soc_fvss = CAP(0, 100, soc_fvss);
+
+ qg_dbg(chip, QG_DEBUG_SOC, "FVSS: vbat_fvss_entry=%d soc_fvss_entry=%d cutoff_uv=%d vbat_uv=%d fifo_avg_v=%d soc_vbat=%d sys_soc=%d wt_vbat=%d wt_sys=%d soc_fvss=%d\n",
+ chip->vbat_fvss_entry, chip->soc_fvss_entry,
+ vbat_cutoff_uv, vbat_uv, chip->last_fifo_v_uv,
+ soc_vbat, sys_soc, wt_vbat, wt_sys, soc_fvss);
+
+ return soc_fvss;
+
+exit_soc_scale:
+ chip->fvss_active = false;
+ return sys_soc;
+}
+
int qg_adjust_sys_soc(struct qpnp_qg *chip)
{
int soc, vbat_uv, rc;
@@ -72,8 +156,11 @@ int qg_adjust_sys_soc(struct qpnp_qg *chip)
soc = DIV_ROUND_CLOSEST(chip->sys_soc, 100);
}
- qg_dbg(chip, QG_DEBUG_SOC, "last_adj_sys_soc=%d adj_sys_soc=%d\n",
- chip->last_adj_ssoc, soc);
+ qg_dbg(chip, QG_DEBUG_SOC, "sys_soc=%d adjusted sys_soc=%d\n",
+ chip->sys_soc, soc);
+
+ soc = qg_process_fvss_soc(chip, soc);
+
chip->last_adj_ssoc = soc;
return soc;
@@ -103,6 +190,8 @@ static void get_next_update_time(struct qpnp_qg *chip)
else if (chip->maint_soc > 0 && chip->maint_soc >= chip->recharge_soc)
/* if in maintenance mode scale slower */
min_delta_soc_interval_ms = qg_maint_soc_update_ms;
+ else if (chip->fvss_active)
+ min_delta_soc_interval_ms = qg_fvss_delta_soc_interval_ms;
if (!min_delta_soc_interval_ms)
min_delta_soc_interval_ms = 1000; /* 1 second */
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c
index 0df0636a034d..53b7244c04f3 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen4.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c
@@ -2334,8 +2334,8 @@ done:
out:
if (!chip->esr_fast_calib || is_debug_batt_id(fg)) {
/* If it is debug battery, then disable ESR fast calibration */
- chip->esr_fast_calib = false;
fg_gen4_esr_fast_calib_config(chip, false);
+ chip->esr_fast_calib = false;
}
if (chip->dt.multi_profile_load && rc < 0)
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index e9030aa74a55..7afd45172d18 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -460,6 +460,9 @@ static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length)
chip->kdata.fifo[j].interval = sample_interval;
chip->kdata.fifo[j].count = sample_count;
+ chip->last_fifo_v_uv = chip->kdata.fifo[j].v;
+ chip->last_fifo_i_ua = chip->kdata.fifo[j].i;
+
qg_dbg(chip, QG_DEBUG_FIFO, "FIFO %d raw_v=%d uV=%d raw_i=%d uA=%d interval=%d count=%d\n",
j, fifo_v,
chip->kdata.fifo[j].v,
@@ -524,6 +527,9 @@ static int qg_process_accumulator(struct qpnp_qg *chip)
if (chip->kdata.fifo_length == MAX_FIFO_LENGTH)
chip->kdata.fifo_length = MAX_FIFO_LENGTH - 1;
+ chip->last_fifo_v_uv = chip->kdata.fifo[index].v;
+ chip->last_fifo_i_ua = chip->kdata.fifo[index].i;
+
if (chip->kdata.fifo_length == 1) /* Only accumulator data */
chip->kdata.seq_no = chip->seq_no++ % U32_MAX;
@@ -2068,6 +2074,9 @@ static int qg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_POWER_AVG:
rc = qg_get_power(chip, &pval->intval, true);
break;
+ case POWER_SUPPLY_PROP_SCALE_MODE_EN:
+ pval->intval = chip->fvss_active;
+ break;
default:
pr_debug("Unsupported property %d\n", psp);
break;
@@ -2126,6 +2135,7 @@ static enum power_supply_property qg_psy_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_AVG,
POWER_SUPPLY_PROP_POWER_AVG,
POWER_SUPPLY_PROP_POWER_NOW,
+ POWER_SUPPLY_PROP_SCALE_MODE_EN,
};
static const struct power_supply_desc qg_psy_desc = {
@@ -3147,6 +3157,39 @@ static int qg_set_wa_flags(struct qpnp_qg *chip)
return 0;
}
+#define SDAM_MAGIC_NUMBER 0x12345678
+static int qg_sanitize_sdam(struct qpnp_qg *chip)
+{
+ int rc = 0;
+ u32 data = 0;
+
+ rc = qg_sdam_read(SDAM_MAGIC, &data);
+ if (rc < 0) {
+ pr_err("Failed to read SDAM rc=%d\n", rc);
+ return rc;
+ }
+
+ if (data == SDAM_MAGIC_NUMBER) {
+ qg_dbg(chip, QG_DEBUG_PON, "SDAM valid\n");
+ } else if (data == 0) {
+ rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER);
+ if (!rc)
+ qg_dbg(chip, QG_DEBUG_PON, "First boot. SDAM initilized\n");
+ } else {
+ /* SDAM has invalid value */
+ rc = qg_sdam_clear();
+ if (!rc) {
+ pr_err("SDAM uninitialized, SDAM reset\n");
+ rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER);
+ }
+ }
+
+ if (rc < 0)
+ pr_err("Failed in SDAM operation, rc=%d\n", rc);
+
+ return rc;
+}
+
#define ADC_CONV_DLY_512MS 0xA
static int qg_hw_init(struct qpnp_qg *chip)
{
@@ -3568,6 +3611,7 @@ static int qg_alg_init(struct qpnp_qg *chip)
#define DEFAULT_SLEEP_TIME_SECS 1800 /* 30 mins */
#define DEFAULT_SYS_MIN_VOLT_MV 2800
#define DEFAULT_FAST_CHG_S2_FIFO_LENGTH 1
+#define DEFAULT_FVSS_VBAT_MV 3500
static int qg_parse_dt(struct qpnp_qg *chip)
{
int rc = 0;
@@ -3862,6 +3906,18 @@ static int qg_parse_dt(struct qpnp_qg *chip)
else
chip->dt.min_sleep_time_secs = temp;
+ if (of_property_read_bool(node, "qcom,fvss-enable")) {
+
+ chip->dt.fvss_enable = true;
+
+ rc = of_property_read_u32(node,
+ "qcom,fvss-vbatt-mv", &temp);
+ if (rc < 0)
+ chip->dt.fvss_vbat_mv = DEFAULT_FVSS_VBAT_MV;
+ else
+ chip->dt.fvss_vbat_mv = temp;
+ }
+
/* Capacity learning params*/
if (!chip->dt.cl_disable) {
chip->dt.cl_feedback_on = of_property_read_bool(node,
@@ -4268,6 +4324,12 @@ static int qpnp_qg_probe(struct platform_device *pdev)
return rc;
}
+ rc = qg_sanitize_sdam(chip);
+ if (rc < 0) {
+ pr_err("Failed to sanitize SDAM, rc=%d\n", rc);
+ return rc;
+ }
+
rc = qg_soc_init(chip);
if (rc < 0) {
pr_err("Failed to initialize SOC scaling init rc=%d\n", rc);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index ca9511afa3d3..d3b7bc626d69 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1139,6 +1139,12 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id);
+ /*
+ * Ensure that updates of buffer address and size happens
+ * before we set the DWC3_TRB_CTRL_HWO so that core
+ * does not process any stale TRB.
+ */
+ mb();
trb->ctrl |= DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_enq(dep);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 838e058a3eaf..332997abd098 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1392,6 +1392,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
struct usb_endpoint_descriptor desc1, *desc;
switch (epfile->ffs->gadget->speed) {
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
desc_idx = 2;
break;
diff --git a/include/linux/ipa_eth.h b/include/linux/ipa_eth.h
index 2e09ac2b3916..732cc199f5cc 100644
--- a/include/linux/ipa_eth.h
+++ b/include/linux/ipa_eth.h
@@ -440,6 +440,7 @@ struct ipa_eth_channel {
* @start_on_resume: Allow start upon driver resume
* @start_on_timeout: Timeout in milliseconds after which @start is enabled
* @start_timer: Timer associated with @start_on_timer
+ * @state: Device state
* @if_state: Interface state - one or more bit numbers IPA_ETH_IF_ST_*
* @pm_handle: IPA PM client handle for the device
* @bus_priv: Private field for use by offload subsystem bus layer
@@ -478,6 +479,7 @@ struct ipa_eth_device {
u32 start_on_timeout;
struct timer_list start_timer;
+ unsigned long state;
unsigned long if_state;
u32 pm_handle;
diff --git a/include/uapi/linux/qg-profile.h b/include/uapi/linux/qg-profile.h
index 0230b3227f78..e18844af5b79 100644
--- a/include/uapi/linux/qg-profile.h
+++ b/include/uapi/linux/qg-profile.h
@@ -47,7 +47,7 @@ struct battery_params {
/* Profile MIN / MAX values */
#define QG_MIN_SOC 0
#define QG_MAX_SOC 10000
-#define QG_MIN_OCV_UV 3000000
+#define QG_MIN_OCV_UV 2000000
#define QG_MAX_OCV_UV 5000000
#define QG_MIN_VAR 0
#define QG_MAX_VAR 65535
diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h
index 68e8446f1585..4dd315d90600 100644
--- a/include/uapi/media/cam_isp.h
+++ b/include/uapi/media/cam_isp.h
@@ -84,14 +84,16 @@
#define CAM_ISP_DSP_MODE_ROUND 2
/* ISP Generic Cmd Buffer Blob types */
-#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0
-#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1
-#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2
-#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3
-#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4
-#define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5
-#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 6
-#define CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP 10
+#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0
+#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1
+#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2
+#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3
+#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4
+#define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5
+#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 6
+#define CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP 10
+#define CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_DIMENSION_CONFIG 11
+#define CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG 12
/* Per Path Usage Data */
#define CAM_ISP_USAGE_INVALID 0
@@ -464,6 +466,36 @@ struct cam_fe_config {
uint32_t latency_buf_size;
} __attribute__((packed));
+/**
+ * struct cam_isp_sensor_path_dimension
+ *
+ * @width expected width
+ * @height expected height
+ * @measure_enabled flag to indicate if pixel measurement is to be enabled
+ */
+struct cam_isp_sensor_dimension {
+ uint32_t width;
+ uint32_t height;
+ uint32_t measure_enabled;
+} __attribute__((packed));
+
+/**
+ * struct cam_isp_sensor_config - Sensor Dimension configuration
+ *
+ * @pix_path: expected ppp path configuration
+ * @pix_path: expected ipp path configuration
+ * @rdi_path: expected rdi path configuration
+ * @hbi: HBI value
+ * @vbi: VBI value
+ */
+struct cam_isp_sensor_config {
+ struct cam_isp_sensor_dimension ppp_path;
+ struct cam_isp_sensor_dimension ipp_path;
+ struct cam_isp_sensor_dimension rdi_path[4];
+ uint32_t hbi;
+ uint32_t vbi;
+} __attribute__((packed));
+
/* Acquire Device/HW v2 */
/**
@@ -489,6 +521,15 @@ struct cam_isp_acquire_hw_info {
uint64_t data;
};
+/**
+ * struct cam_fps_config - FPS blob support
+ *
+ * @fps: FPS value
+ */
+struct cam_fps_config {
+ uint32_t fps;
+} __attribute__((packed));
+
#define CAM_ISP_ACQUIRE_COMMON_VER0 0x1000
#define CAM_ISP_ACQUIRE_COMMON_SIZE_VER0 0x0