diff options
134 files changed, 5437 insertions, 2146 deletions
diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 4914401f3fda..b1b28993e325 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -113,9 +113,11 @@ fi endef ifneq ($(KERNEL_LEGACY_DIR),true) -$(KERNEL_USR): $(TARGET_PREBUILT_INT_KERNEL) +$(KERNEL_USR): $(KERNEL_HEADERS_INSTALL) rm -rf $(KERNEL_SYMLINK) ln -s kernel/$(TARGET_KERNEL) $(KERNEL_SYMLINK) + +$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_USR) endif $(KERNEL_OUT): @@ -139,12 +141,12 @@ $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \ - $(hide) rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ + rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi $(hide) if [ "$(KERNEL_HEADER_DEFCONFIG)" != "$(KERNEL_DEFCONFIG)" ]; then \ echo "Used a different defconfig for header generation"; \ - $(hide) rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ + rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt index 4dac20bcda69..34001a9ef4e8 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt @@ -18,13 +18,13 @@ Required properties - qcom,sensor-id: The id of the TSENS sensor polled for temperature. Typically the sensor closest to CPU0. - qcom,poll-ms: Sampling interval to read sensor, in ms. -- qcom,limit-temp: Threshold temperature to start stepping CPU down, in degC. -- qcom,temp-hysteresis: Degrees C below threshold temperature to step CPU up. -- qcom,freq-step: Number of frequency steps to take on each CPU mitigation. Optional properties - reg: Physical address for uio mapping +- qcom,limit-temp: Threshold temperature to start stepping CPU down, in degC. +- qcom,temp-hysteresis: Degrees C below threshold temperature to step CPU up. +- qcom,freq-step: Number of frequency steps to take on each CPU mitigation. - qcom,core-limit-temp: Threshold temperature to start shutting down cores in degC - qcom,core-temp-hysteresis: Degrees C below which the cores will be brought diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt index 08fab81f3393..7857eeb963a6 100644 --- a/Documentation/devicetree/bindings/cnss/icnss.txt +++ b/Documentation/devicetree/bindings/cnss/icnss.txt @@ -12,6 +12,11 @@ Required properties: - reg-names: Names of the memory regions defined in reg entry - interrupts: Copy engine interrupt table - qcom,wlan-msa-memory: MSA memory size + - clocks: List of clock phandles + - clock-names: List of clock names corresponding to the "clocks" property + - iommus: SMMUs and corresponding Stream IDs needed by WLAN + - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length> + format to be used for allocations associated between WLAN and SMMU Optional properties: - qcom,skip-qmi: Boolean property to decide whether to use QMI or not @@ -22,6 +27,11 @@ Example: compatible = "qcom,icnss"; reg = <0x0a000000 0x1000000>; reg-names = "membase"; + clocks = <&clock_gcc clk_aggre2_noc_clk>; + clock-names = "smmu_aggre2_noc_clk"; + iommus = <&anoc2_smmu 0x1900>, + <&anoc2_smmu 0x1901>; + qcom,wlan-smmu-iova-address = <0 0x10000000>; interrupts = <0 130 0 /* CE0 */ >, <0 131 0 /* CE1 */ >, diff --git a/Documentation/devicetree/bindings/iommu/iommu-debug.txt b/Documentation/devicetree/bindings/iommu/iommu-debug.txt new file mode 100644 index 000000000000..1d79f1865aa5 --- /dev/null +++ b/Documentation/devicetree/bindings/iommu/iommu-debug.txt @@ -0,0 +1,27 @@ +This document describes the device tree binding for IOMMU test devices. + +The iommu-debug framework can optionally make use of some platform devices +for improved standalone testing and other features. + +- compatible: iommu-debug-test + + +Required properties +=================== + +- iommus: The IOMMU for the test device (see iommu.txt) + + +Example +======= + + iommu_test_device { + compatible = "iommu-debug-test"; + /* + * 42 shouldn't be used by anyone on the cpp_fd_smmu. We just + * need _something_ here to get this node recognized by the + * SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&cpp_fd_smmu 42>; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-jpegdma.txt b/Documentation/devicetree/bindings/media/video/msm-jpegdma.txt index 6b05e7fa3084..a1d604218219 100644 --- a/Documentation/devicetree/bindings/media/video/msm-jpegdma.txt +++ b/Documentation/devicetree/bindings/media/video/msm-jpegdma.txt @@ -19,6 +19,8 @@ Required properties: - clocks : clocks required for the device. - qcom,clock-rates: should specify clock rates in Hz to each clocks property defined. +- qcom,max-ds-factor: should specify the max dma downscale factor, + supported by HW. - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for below optional properties: - qcom,msm-bus,name @@ -67,5 +69,6 @@ Example: qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, <62 512 666675 666675>; + qcom,max-ds-factor = <128>; status = "ok"; }; diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt index fc17085f5539..88a1c7d478c7 100644 --- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt @@ -109,7 +109,8 @@ KBSS specific properties: Usage: optional Value type: <u32> The time in nanoseconds that the CPR controller must delay - to allow voltage settling after a corner change. + to allow voltage settling per 1 mV of voltage change after a + corner change. - qcom,cpr-hw-closed-loop Usage: optional diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6834ace0c778..8ec6be0dd1b1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -4118,6 +4118,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. or other driver-specific files in the Documentation/watchdog/ directory. + workqueue.watchdog_thresh= + If CONFIG_WQ_WATCHDOG is configured, workqueue can + warn stall conditions and dump internal state to + help debugging. 0 disables workqueue stall + detection; otherwise, it's the stall threshold + duration in seconds. The default value is 30 and + it can be updated at runtime by writing to the + corresponding sysfs file. + workqueue.disable_numa By default, all work items queued to unbound workqueues are affine to the NUMA nodes they're diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi index e1c2dd8bde6a..cbe65e266968 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi @@ -251,3 +251,16 @@ "gcc_mmss_bimc_gfx_clk", "gcc_bimc_gfx_clk"; #clock-cells = <1>; }; + +&soc { + iommu_test_device { + compatible = "iommu-debug-test"; + /* + * 42 shouldn't be used by anyone on the cpp_fd_smmu. We just + * need _something_ here to get this node recognized by the + * SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&cpp_fd_smmu 42>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi index f00395b081b8..41af9b66d3c9 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi @@ -182,4 +182,15 @@ "gcc_gpu_bimc_gfx_clk"; #clock-cells = <1>; }; + + iommu_test_device { + compatible = "iommu-debug-test"; + /* + * 42 shouldn't be used by anyone on the mmss_smmu. We just + * need _something_ here to get this node recognized by the + * SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&mmss_smmu 42>; + }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi index e68f746bda38..f5d55972f92f 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi @@ -61,6 +61,7 @@ &cam_actuator_vaf_suspend>; pinctrl-1 = <&cam_actuator_vaf_active &cam_actuator_vaf_suspend>; + status = "disabled"; }; eeprom0: qcom,eeprom@0 { @@ -118,9 +119,9 @@ qcom,cam-vreg-op-mode = <0 80000 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active + pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend + pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_front_suspend>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, @@ -139,8 +140,8 @@ qcom,sensor-mode = <0>; qcom,cci-master = <1>; status = "ok"; - clocks = <&clock_mmss clk_mclk2_clk_src>, - <&clock_mmss clk_mmss_camss_mclk2_clk>; + clocks = <&clock_mmss clk_mclk1_clk_src>, + <&clock_mmss clk_mmss_camss_mclk1_clk>; clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; @@ -207,9 +208,9 @@ qcom,cam-vreg-op-mode = <0 0 80000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_active + pinctrl-0 = <&cam_sensor_mclk2_active &cam_sensor_rear2_active>; - pinctrl-1 = <&cam_sensor_mclk1_suspend + pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 15 0>, <&tlmm 9 0>, @@ -225,8 +226,8 @@ qcom,sensor-mode = <0>; qcom,cci-master = <0>; status = "ok"; - clocks = <&clock_mmss clk_mclk1_clk_src>, - <&clock_mmss clk_mmss_camss_mclk1_clk>; + clocks = <&clock_mmss clk_mclk2_clk_src>, + <&clock_mmss clk_mmss_camss_mclk2_clk>; clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; @@ -251,9 +252,9 @@ qcom,cam-vreg-op-mode = <0 80000 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active + pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend + pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_front_suspend>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, @@ -272,8 +273,8 @@ qcom,sensor-mode = <0>; qcom,cci-master = <1>; status = "ok"; - clocks = <&clock_mmss clk_mclk2_clk_src>, - <&clock_mmss clk_mmss_camss_mclk2_clk>; + clocks = <&clock_mmss clk_mclk1_clk_src>, + <&clock_mmss clk_mmss_camss_mclk1_clk>; clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi index e68f746bda38..f5d55972f92f 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi @@ -61,6 +61,7 @@ &cam_actuator_vaf_suspend>; pinctrl-1 = <&cam_actuator_vaf_active &cam_actuator_vaf_suspend>; + status = "disabled"; }; eeprom0: qcom,eeprom@0 { @@ -118,9 +119,9 @@ qcom,cam-vreg-op-mode = <0 80000 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active + pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend + pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_front_suspend>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, @@ -139,8 +140,8 @@ qcom,sensor-mode = <0>; qcom,cci-master = <1>; status = "ok"; - clocks = <&clock_mmss clk_mclk2_clk_src>, - <&clock_mmss clk_mmss_camss_mclk2_clk>; + clocks = <&clock_mmss clk_mclk1_clk_src>, + <&clock_mmss clk_mmss_camss_mclk1_clk>; clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; @@ -207,9 +208,9 @@ qcom,cam-vreg-op-mode = <0 0 80000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_active + pinctrl-0 = <&cam_sensor_mclk2_active &cam_sensor_rear2_active>; - pinctrl-1 = <&cam_sensor_mclk1_suspend + pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 15 0>, <&tlmm 9 0>, @@ -225,8 +226,8 @@ qcom,sensor-mode = <0>; qcom,cci-master = <0>; status = "ok"; - clocks = <&clock_mmss clk_mclk1_clk_src>, - <&clock_mmss clk_mmss_camss_mclk1_clk>; + clocks = <&clock_mmss clk_mclk2_clk_src>, + <&clock_mmss clk_mmss_camss_mclk2_clk>; clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; @@ -251,9 +252,9 @@ qcom,cam-vreg-op-mode = <0 80000 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active + pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend + pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_front_suspend>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, @@ -272,8 +273,8 @@ qcom,sensor-mode = <0>; qcom,cci-master = <1>; status = "ok"; - clocks = <&clock_mmss clk_mclk2_clk_src>, - <&clock_mmss clk_mmss_camss_mclk2_clk>; + clocks = <&clock_mmss clk_mclk1_clk_src>, + <&clock_mmss clk_mmss_camss_mclk1_clk>; clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi index 4139bd1c70e0..c51069d1f571 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi @@ -16,7 +16,7 @@ compatible = "qcom,msm-cam"; reg = <0x8c0000 0x40000>; reg-names = "msm-cam"; - status = "disabled"; + status = "ok"; bus-vectors = "suspend", "svs", "nominal", "turbo"; qcom,bus-votes = <0 300000000 640000000 640000000>; }; @@ -28,19 +28,28 @@ reg-names = "csiphy"; interrupts = <0 78 0>; interrupt-names = "csiphy"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, - <&clock_mmss clk_csi0phytimer_clk_src>, - <&clock_mmss clk_mmss_camss_csi0phytimer_clk>, + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_csi0_clk_src>, <&clock_mmss clk_mmss_camss_csi0_clk>, - <&clock_mmss clk_mmss_camss_cphy_csid0_clk>; - clock-names = "camss_top_ahb_clk", - "camss_ispif_ahb_clk", "csiphy_timer_src_clk", - "csiphy_timer_clk", "camss_ahb_clk", - "csi_src_clk", "csi_clk", "cphy_csid_clk"; - qcom,clock-rates = <0 0 269333333 0 0 256000000 0 0>; + <&clock_mmss clk_mmss_camss_cphy_csid0_clk>, + <&clock_mmss clk_csi0phytimer_clk_src>, + <&clock_mmss clk_mmss_camss_csi0phytimer_clk>, + <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, + <&clock_mmss clk_csiphy_clk_src>, + <&clock_mmss clk_mmss_camss_csiphy0_clk>; + clock-names = "mnoc_maxi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "csi_src_clk", "csi_clk", "cphy_csid_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk"; + qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0 + 0 256000000 0>; }; qcom,csiphy@ca35000 { @@ -50,19 +59,28 @@ reg-names = "csiphy"; interrupts = <0 79 0>; interrupt-names = "csiphy"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, - <&clock_mmss clk_csi1phytimer_clk_src>, - <&clock_mmss clk_mmss_camss_csi1phytimer_clk>, + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_csi1_clk_src>, <&clock_mmss clk_mmss_camss_csi1_clk>, - <&clock_mmss clk_mmss_camss_cphy_csid1_clk>; - clock-names = "camss_top_ahb_clk", - "camss_ispif_ahb_clk", "csiphy_timer_src_clk", - "csiphy_timer_clk", "camss_ahb_clk", - "csi_src_clk", "csi_clk", "cphy_csid_clk"; - qcom,clock-rates = <0 0 269333333 0 0 256000000 0 0>; + <&clock_mmss clk_mmss_camss_cphy_csid1_clk>, + <&clock_mmss clk_csi1phytimer_clk_src>, + <&clock_mmss clk_mmss_camss_csi1phytimer_clk>, + <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, + <&clock_mmss clk_csiphy_clk_src>, + <&clock_mmss clk_mmss_camss_csiphy1_clk>; + clock-names = "mnoc_maxi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "csi_src_clk", "csi_clk", "cphy_csid_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk"; + qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0 + 0 256000000 0>; }; qcom,csiphy@ca36000 { @@ -72,19 +90,28 @@ reg-names = "csiphy"; interrupts = <0 80 0>; interrupt-names = "csiphy"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, - <&clock_mmss clk_csi2phytimer_clk_src>, - <&clock_mmss clk_mmss_camss_csi2phytimer_clk>, + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_csi2_clk_src>, <&clock_mmss clk_mmss_camss_csi2_clk>, - <&clock_mmss clk_mmss_camss_cphy_csid2_clk>; - clock-names = "camss_top_ahb_clk", - "camss_ispif_ahb_clk", "csiphy_timer_src_clk", - "csiphy_timer_clk", "camss_ahb_clk", - "csi_src_clk", "csi_clk", "cphy_csid_clk"; - qcom,clock-rates = <0 0 269333333 0 0 256000000 0 0>; + <&clock_mmss clk_mmss_camss_cphy_csid2_clk>, + <&clock_mmss clk_csi2phytimer_clk_src>, + <&clock_mmss clk_mmss_camss_csi2phytimer_clk>, + <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, + <&clock_mmss clk_csiphy_clk_src>, + <&clock_mmss clk_mmss_camss_csiphy2_clk>; + clock-names = "mnoc_maxi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "csi_src_clk", "csi_clk", "cphy_csid_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk"; + qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0 + 0 256000000 0>; }; qcom,csid@ca30000 { @@ -94,24 +121,31 @@ reg-names = "csid"; interrupts = <0 296 0>; interrupt-names = "csid"; - qcom,csi-vdd-voltage = <752000>; - qcom,mipi-csi-vdd-supply = <&pmcobalt_s1_level>; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pmcobalt_l2>; gdscr-supply = <&gdsc_camss_top>; - qcom,cam-vreg-name = "gdscr"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + vdd_sec-supply = <&pmcobalt_l1>; + qcom,cam-vreg-name = "vdd_sec", "gdscr"; + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, <&clock_mmss clk_csi0_clk_src>, <&clock_mmss clk_mmss_camss_csi0_clk>, <&clock_mmss clk_mmss_camss_csiphy0_clk>, <&clock_mmss clk_mmss_camss_csi0_ahb_clk>, <&clock_mmss clk_mmss_camss_csi0rdi_clk>, - <&clock_mmss clk_mmss_camss_csi0pix_clk>, - <&clock_mmss clk_mmss_camss_ahb_clk>; - clock-names = "camss_top_ahb_clk", + <&clock_mmss clk_mmss_camss_csi0pix_clk>; + clock-names = "mnoc_maxi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", "ispif_ahb_clk", "csi_src_clk", "csi_clk", "csi_phy_clk", "csi_ahb_clk", "csi_rdi_clk", - "csi_pix_clk", "camss_ahb_clk"; - qcom,clock-rates = <0 0 256000000 0 0 0 0 0 0>; + "csi_pix_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0 0>; status = "ok"; }; @@ -123,23 +157,30 @@ interrupts = <0 297 0>; interrupt-names = "csid"; qcom,csi-vdd-voltage = <1200000>; - qcom,mipi-csi-vdd-supply = <&pmcobalt_s1_level>; + qcom,mipi-csi-vdd-supply = <&pmcobalt_l2>; gdscr-supply = <&gdsc_camss_top>; - qcom,cam-vreg-name = "gdscr"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + vdd_sec-supply = <&pmcobalt_l1>; + qcom,cam-vreg-name = "vdd_sec", "gdscr"; + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, <&clock_mmss clk_csi1_clk_src>, <&clock_mmss clk_mmss_camss_csi1_clk>, <&clock_mmss clk_mmss_camss_csiphy1_clk>, <&clock_mmss clk_mmss_camss_csi1_ahb_clk>, <&clock_mmss clk_mmss_camss_csi1rdi_clk>, - <&clock_mmss clk_mmss_camss_csi1pix_clk>, - <&clock_mmss clk_mmss_camss_ahb_clk>; - clock-names = "camss_top_ahb_clk", + <&clock_mmss clk_mmss_camss_csi1pix_clk>; + clock-names = "mnoc_maxi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", "ispif_ahb_clk", "csi_src_clk", "csi_clk", "csi_phy_clk", "csi_ahb_clk", "csi_rdi_clk", - "csi_pix_clk", "camss_ahb_clk"; - qcom,clock-rates = <0 0 256000000 0 0 0 0 0 0>; + "csi_pix_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0 0>; }; qcom,csid@ca30800 { @@ -150,23 +191,30 @@ interrupts = <0 298 0>; interrupt-names = "csid"; qcom,csi-vdd-voltage = <1200000>; - qcom,mipi-csi-vdd-supply = <&pmcobalt_s1_level>; + qcom,mipi-csi-vdd-supply = <&pmcobalt_l2>; gdscr-supply = <&gdsc_camss_top>; - qcom,cam-vreg-name = "gdscr"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + vdd_sec-supply = <&pmcobalt_l1>; + qcom,cam-vreg-name = "vdd_sec", "gdscr"; + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, <&clock_mmss clk_csi2_clk_src>, <&clock_mmss clk_mmss_camss_csi2_clk>, <&clock_mmss clk_mmss_camss_csiphy2_clk>, <&clock_mmss clk_mmss_camss_csi2_ahb_clk>, <&clock_mmss clk_mmss_camss_csi2rdi_clk>, - <&clock_mmss clk_mmss_camss_csi2pix_clk>, - <&clock_mmss clk_mmss_camss_ahb_clk>; - clock-names = "camss_top_ahb_clk", + <&clock_mmss clk_mmss_camss_csi2pix_clk>; + clock-names = "mnoc_maxi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", "ispif_ahb_clk", "csi_src_clk", "csi_clk", "csi_phy_clk", "csi_ahb_clk", "csi_rdi_clk", - "csi_pix_clk", "camss_ahb_clk"; - qcom,clock-rates = <0 0 256000000 0 0 0 0 0 0>; + "csi_pix_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0 0>; }; qcom,csid@ca30c00 { @@ -177,27 +225,33 @@ interrupts = <0 299 0>; interrupt-names = "csid"; qcom,csi-vdd-voltage = <1200000>; - qcom,mipi-csi-vdd-supply = <&pmcobalt_s1_level>; + qcom,mipi-csi-vdd-supply = <&pmcobalt_l2>; gdscr-supply = <&gdsc_camss_top>; - qcom,cam-vreg-name = "gdscr"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + vdd_sec-supply = <&pmcobalt_l1>; + qcom,cam-vreg-name = "vdd_sec", "gdscr"; + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, - <&clock_mmss clk_csi0_clk_src>, - <&clock_mmss clk_mmss_camss_csi0_clk>, - <&clock_mmss clk_mmss_camss_csiphy0_clk>, - <&clock_mmss clk_mmss_camss_csi0_ahb_clk>, - <&clock_mmss clk_mmss_camss_csi0rdi_clk>, - <&clock_mmss clk_mmss_camss_csi0pix_clk>, - <&clock_mmss clk_mmss_camss_ahb_clk>; - clock-names = "camss_top_ahb_clk", + <&clock_mmss clk_csi3_clk_src>, + <&clock_mmss clk_mmss_camss_csi3_clk>, + <&clock_mmss clk_mmss_camss_csi3_ahb_clk>, + <&clock_mmss clk_mmss_camss_csi3rdi_clk>, + <&clock_mmss clk_mmss_camss_csi3pix_clk>; + clock-names = "mnoc_maxi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", "ispif_ahb_clk", "csi_src_clk", "csi_clk", - "csi_phy_clk", "csi_ahb_clk", "csi_rdi_clk", - "csi_pix_clk", "camss_ahb_clk"; - qcom,clock-rates = <0 0 256000000 0 0 0 0 0 0>; + "csi_ahb_clk", "csi_rdi_clk", + "csi_pix_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0>; }; qcom,cam_smmu { compatible = "qcom,msm-cam-smmu"; - status = "disabled"; + status = "ok"; msm_cam_smmu_cb1 { compatible = "qcom,msm-cam-smmu-cb"; @@ -605,16 +659,20 @@ mmagic-supply = <&gdsc_bimc_smmu>; gdscr-supply = <&gdsc_camss_top>; qcom,cam-vreg-name = "mmagic", "gdscr"; - clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_top_ahb_clk>, <&clock_mmss clk_cci_clk_src>, <&clock_mmss clk_mmss_camss_cci_ahb_clk>, - <&clock_mmss clk_mmss_camss_cci_clk>, - <&clock_mmss clk_mmss_camss_ahb_clk>; - clock-names = "camss_top_ahb_clk", - "cci_src_clk", "cci_ahb_clk", "camss_cci_clk", - "camss_ahb_clk"; - qcom,clock-rates = <0 19200000 0 0 0>, - <0 37500000 0 0 0>; + <&clock_mmss clk_mmss_camss_cci_clk>; + clock-names = "mnoc_axi", "mnoc_ahb", "smmu_ahb", "smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "cci_src_clk", "cci_ahb_clk", "camss_cci_clk"; + qcom,clock-rates = <0 0 0 0 0 0 19200000 0 0>, + <0 0 0 0 0 0 37500000 0 0>; pinctrl-names = "cci_default", "cci_suspend"; pinctrl-0 = <&cci0_active &cci1_active>; pinctrl-1 = <&cci0_suspend &cci1_suspend>; @@ -725,6 +783,7 @@ qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, <62 512 666675 666675>; + qcom,max-ds-factor = <128>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi index f72dfacbc70d..dcadd99e2f2e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi @@ -61,11 +61,6 @@ vcc-max-microamp = <750000>; vccq-max-microamp = <560000>; vccq2-max-microamp = <750000>; - - qcom,disable-lpm; - rpm-level = <0>; - spm-level = <0>; - status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi index 929c48c7346c..fd7e0404691c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi @@ -75,6 +75,8 @@ qcom,deep-nap-timeout = <2>; //<HZ/50> qcom,strtstp-sleepwake; + qcom,highest-bank-bit = <15>; + clocks = <&clock_gfx clk_gpucc_gfx3d_clk>, <&clock_gcc clk_gcc_gpu_cfg_ahb_clk>, <&clock_gpu clk_gpucc_rbbmtimer_clk>, diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi index 7bae6848c61c..d72a770d886e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi @@ -61,11 +61,6 @@ vcc-max-microamp = <750000>; vccq-max-microamp = <560000>; vccq2-max-microamp = <750000>; - - qcom,disable-lpm; - rpm-level = <0>; - spm-level = <0>; - status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi index 03b8aa094796..9acbeae79a28 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi @@ -746,12 +746,12 @@ cam_sensor_rear_active: cam_sensor_rear_active { /* RESET, STANDBY */ mux { - pins = "gpio30","gpio29","gpio27"; + pins = "gpio30","gpio29"; function = "gpio"; }; config { - pins = "gpio30","gpio29","gpio27"; + pins = "gpio30","gpio29"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; @@ -1011,12 +1011,12 @@ cam_sensor_rear_suspend: cam_sensor_rear_suspend { /* RESET, STANDBY */ mux { - pins = "gpio30","gpio29","gpio27"; + pins = "gpio30","gpio29"; function = "gpio"; }; config { - pins = "gpio30","gpio29","gpio27"; + pins = "gpio30","gpio29"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; @@ -1055,12 +1055,12 @@ cam_sensor_rear2_active: cam_sensor_rear2_active { /* RESET, STANDBY */ mux { - pins = "gpio63","gpio62"; + pins = "gpio9","gpio8"; function = "gpio"; }; config { - pins = "gpio63","gpio62"; + pins = "gpio9","gpio8"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; @@ -1118,19 +1118,16 @@ }; }; - cam_sensor_rear2_sus { - cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { - /* RESET, STANDBY */ - mux { - pins = "gpio63","gpio62"; - function = "gpio"; - }; - - config { - pins = "gpio63","gpio62"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio9","gpio8"; + function = "gpio"; + }; + config { + pins = "gpio9","gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ }; }; @@ -1167,12 +1164,12 @@ cam_sensor_front_active: cam_sensor_front_active { /* RESET, STANDBY */ mux { - pins = "gpio23","gpio26"; + pins = "gpio28","gpio27"; function = "gpio"; }; config { - pins = "gpio23","gpio26"; + pins = "gpio28","gpio27"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; @@ -1233,12 +1230,12 @@ cam_sensor_front_suspend: cam_sensor_front_suspend { /* RESET, STANDBY */ mux { - pins = "gpio23","gpio26"; + pins = "gpio28","gpio27"; function = "gpio"; }; config { - pins = "gpio23","gpio26"; + pins = "gpio28","gpio27"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 89134821899b..0490ce3854cd 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -599,11 +599,11 @@ qcom,cpr-up-down-delay-time = <3000>; qcom,cpr-step-quot-init-min = <11>; qcom,cpr-step-quot-init-max = <13>; - qcom,cpr-count-mode = <2>; /* Staggered */ + qcom,cpr-count-mode = <0>; /* All at once */ qcom,cpr-down-error-step-limit = <1>; qcom,cpr-up-error-step-limit = <1>; - qcom,cpr-corner-switch-delay-time = <1600>; - qcom,cpr-voltage-settling-time = <1600>; + qcom,cpr-corner-switch-delay-time = <209>; + qcom,cpr-voltage-settling-time = <1760>; qcom,apm-threshold-voltage = <832000>; qcom,apm-hysteresis-voltage = <32000>; @@ -611,11 +611,14 @@ qcom,voltage-base = <352000>; qcom,cpr-saw-use-unit-mV; + qcom,cpr-enable; + qcom,cpr-hw-closed-loop; + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; - qcom,cpr-consecutive-down = <2>; - qcom,cpr-up-threshold = <0>; + qcom,cpr-consecutive-down = <0>; + qcom,cpr-up-threshold = <2>; qcom,cpr-down-threshold = <2>; apc0_pwrcl_vreg: regulator-pwrcl { @@ -685,11 +688,11 @@ qcom,cpr-up-down-delay-time = <3000>; qcom,cpr-step-quot-init-min = <11>; qcom,cpr-step-quot-init-max = <13>; - qcom,cpr-count-mode = <2>; /* Staggered */ + qcom,cpr-count-mode = <0>; /* All at once */ qcom,cpr-down-error-step-limit = <1>; qcom,cpr-up-error-step-limit = <1>; - qcom,cpr-corner-switch-delay-time = <1600>; - qcom,cpr-voltage-settling-time = <1600>; + qcom,cpr-corner-switch-delay-time = <209>; + qcom,cpr-voltage-settling-time = <1760>; qcom,apm-threshold-voltage = <832000>; qcom,apm-hysteresis-voltage = <32000>; @@ -697,11 +700,14 @@ qcom,voltage-base = <352000>; qcom,cpr-saw-use-unit-mV; + qcom,cpr-enable; + qcom,cpr-hw-closed-loop; + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; - qcom,cpr-consecutive-down = <2>; - qcom,cpr-up-threshold = <0>; + qcom,cpr-consecutive-down = <0>; + qcom,cpr-up-threshold = <2>; qcom,cpr-down-threshold = <2>; apc1_perfcl_vreg: regulator-pwrcl { @@ -776,13 +782,15 @@ qcom,cpr-idle-cycles = <15>; qcom,cpr-step-quot-init-min = <10>; qcom,cpr-step-quot-init-max = <13>; - qcom,cpr-count-mode = <2>; /* Staggered */ + qcom,cpr-count-mode = <0>; /* All-at-once min */ vdd-supply = <&pm8005_s1>; qcom,voltage-step = <4000>; mem-acc-supply = <&gfx_mem_acc_vreg>; qcom,cpr-aging-ref-voltage = <1032000>; + qcom,cpr-enable; + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; @@ -842,11 +850,39 @@ <2389 2287 2985 3112 2873 2904 2159 2399 1580 1602 2158 3042 2780 2069 0 0>; + qcom,cpr-open-loop-voltage-fuse-adjustment = + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>; + + qcom,cpr-closed-loop-voltage-adjustment = + < 150000 150000 150000 150000 + 150000 150000>, + < 150000 150000 150000 150000 + 150000 150000>, + < 150000 150000 150000 150000 + 150000 150000>, + < 150000 150000 150000 150000 + 150000 150000>, + < 150000 150000 150000 150000 + 150000 150000>, + < 150000 150000 150000 150000 + 150000 150000>, + < 150000 150000 150000 150000 + 150000 150000>, + < 150000 150000 150000 150000 + 150000 150000>; + qcom,cpr-floor-to-ceiling-max-range = <50000 50000 50000 50000 50000 50000>; qcom,cpr-fused-closed-loop-voltage-adjustment-map = - <1 2 2 3 3 4>; + <0 0 1 2 3 4>; qcom,allow-voltage-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 78c99ee81a12..4e2c4b732c05 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -629,10 +629,16 @@ reg = <0xc8c0000 0x40000>; reg-names = "cc_base"; vdd_dig-supply = <&pmcobalt_s1_level>; - clock-names = "xo", "gpll0", "gpll0_div"; + clock-names = "xo", "gpll0", "gpll0_div", + "pclk0_src", "pclk1_src", + "byte0_src", "byte1_src"; clocks = <&clock_gcc clk_cxo_clk_src>, <&clock_gcc clk_gpll0_out_main>, - <&clock_gcc clk_gcc_mmss_gpll0_div_clk>; + <&clock_gcc clk_gcc_mmss_gpll0_div_clk>, + <&mdss_dsi0_pll clk_dsi0pll_pclk_mux>, + <&mdss_dsi1_pll clk_dsi1pll_pclk_mux>, + <&mdss_dsi0_pll clk_dsi0pll_byteclk_mux>, + <&mdss_dsi1_pll clk_dsi1pll_byteclk_mux>; #clock-cells = <1>; }; @@ -1927,16 +1933,18 @@ qcom,proxy-reg-names = "vdd"; clocks = <&clock_mmss clk_mmss_video_core_clk>, + <&clock_mmss clk_mmss_mnoc_ahb_clk>, <&clock_mmss clk_mmss_video_ahb_clk>, + <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_mmss clk_mmss_video_axi_clk>, <&clock_mmss clk_mmss_video_maxi_clk>; - clock-names = "core_clk", "iface_clk", - "bus_clk", "maxi_clk"; - qcom,proxy-clock-names = "core_clk", "iface_clk", - "bus_clk", "maxi_clk"; + clock-names = "core_clk", "mnoc_ahb_clk", "iface_clk", + "noc_axi_clk", "bus_clk", "maxi_clk"; + qcom,proxy-clock-names = "core_clk","mnoc_ahb_clk", + "iface_clk", "noc_axi_clk", "bus_clk", "maxi_clk"; qcom,pas-id = <9>; - qcom,proxy-timeout-ms = <100>; + qcom,proxy-timeout-ms = <10000>; qcom,firmware-name = "venus"; memory-region = <&peripheral_mem>; status = "ok"; @@ -1986,11 +1994,6 @@ qcom,rtb-size = <0x100000>; }; - qcom,msm-rtb { - compatible = "qcom,msm-rtb"; - qcom,rtb-size = <0x100000>; - }; - qcom,msm-imem@146bf000 { compatible = "qcom,msm-imem"; reg = <0x146bf000 0x1000>; @@ -2017,6 +2020,11 @@ compatible = "qcom,msm-imem-pil"; reg = <0x94c 200>; }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; + }; }; cpu_pmu: cpu-pmu { @@ -2144,6 +2152,11 @@ reg = <0x18800000 0x800000>, <0x10AC000 0x20>; reg-names = "membase", "mpm_config"; + clocks = <&clock_gcc clk_aggre2_noc_clk>; + clock-names = "smmu_aggre2_noc_clk"; + iommus = <&anoc2_smmu 0x1900>, + <&anoc2_smmu 0x1901>; + qcom,wlan-smmu-iova-address = <0xa0000000 0x10000000>; interrupts = <0 413 0 /* CE0 */ >, <0 414 0 /* CE1 */ >, <0 415 0 /* CE2 */ >, diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index d780a12b161c..6b3d8718fe50 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -523,6 +523,7 @@ CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_MSM_SMEM=y CONFIG_QPNP_HAPTIC=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 5134ffe9a6a0..7cc9914a671e 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -216,6 +216,7 @@ CONFIG_MSM_BT_POWER=y CONFIG_BTFM_SLIM=y CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NET_9P=y CONFIG_NET_9P_VIRTIO=y @@ -285,7 +286,6 @@ CONFIG_DIAG_CHAR=y CONFIG_VIRTIO_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS=y @@ -325,6 +325,9 @@ CONFIG_REGULATOR_CPRH_KBSS=y CONFIG_REGULATOR_MEM_ACC=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MSM_SDE_ROTATOR=y CONFIG_FB=y CONFIG_FB_ARMCLCD=y CONFIG_FB_MSM=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 4c851ce0168d..e14f310f7125 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -215,6 +215,8 @@ CONFIG_MSM_BT_POWER=y CONFIG_BTFM_SLIM=y CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y CONFIG_NET_9P=y CONFIG_NET_9P_VIRTIO=y @@ -298,7 +300,6 @@ CONFIG_DIAG_CHAR=y CONFIG_VIRTIO_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS=y @@ -338,6 +339,9 @@ CONFIG_REGULATOR_CPRH_KBSS=y CONFIG_REGULATOR_MEM_ACC=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MSM_SDE_ROTATOR=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_ARMCLCD=y @@ -461,6 +465,7 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_SYSMON_GLINK_COMM=y CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y @@ -484,6 +489,7 @@ CONFIG_TRACER_PKT=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_EXTCON=y CONFIG_PWM=y @@ -522,7 +528,9 @@ CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y CONFIG_SLUB_DEBUG_PANIC_ON=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_FREE=y @@ -537,6 +545,7 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_LOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y diff --git a/drivers/clk/msm/clock-gcc-cobalt.c b/drivers/clk/msm/clock-gcc-cobalt.c index 88d77977235d..ec06e6b9774f 100644 --- a/drivers/clk/msm/clock-gcc-cobalt.c +++ b/drivers/clk/msm/clock-gcc-cobalt.c @@ -261,6 +261,7 @@ static struct rcg_clk pcie_aux_clk_src = { }; static struct clk_freq_tbl ftbl_ufs_axi_clk_src[] = { + F( 50000000, gpll0_out_main, 12, 0, 0), F( 100000000, gpll0_out_main, 6, 0, 0), F( 200000000, gpll0_out_main, 3, 0, 0), F( 240000000, gpll0_out_main, 2.5, 0, 0), @@ -916,6 +917,7 @@ static struct rcg_clk tsif_ref_clk_src = { }; static struct clk_freq_tbl ftbl_ufs_ice_core_clk_src[] = { + F( 75000000, gpll0_out_main, 8, 0, 0), F( 150000000, gpll0_out_main, 4, 0, 0), F( 300000000, gpll0_out_main, 2, 0, 0), F_END @@ -1168,6 +1170,7 @@ static struct branch_clk gcc_bimc_mss_q6_axi_clk = { static struct local_vote_clk gcc_blsp1_ahb_clk = { .cbcr_reg = GCC_BLSP1_AHB_CBCR, + .bcr_reg = GCC_BLSP1_BCR, .vote_reg = GCC_APCS_CLOCK_BRANCH_ENA_VOTE, .en_mask = BIT(17), .base = &virt_base, @@ -1360,6 +1363,7 @@ static struct branch_clk gcc_blsp1_uart3_apps_clk = { static struct local_vote_clk gcc_blsp2_ahb_clk = { .cbcr_reg = GCC_BLSP2_AHB_CBCR, + .bcr_reg = GCC_BLSP2_BCR, .vote_reg = GCC_APCS_CLOCK_BRANCH_ENA_VOTE, .en_mask = BIT(15), .base = &virt_base, @@ -1958,6 +1962,7 @@ static struct branch_clk gcc_ufs_ahb_clk = { static struct branch_clk gcc_ufs_axi_clk = { .cbcr_reg = GCC_UFS_AXI_CBCR, + .bcr_reg = GCC_UFS_BCR, .has_sibling = 0, .base = &virt_base, .c = { diff --git a/drivers/edac/cortex_arm64_edac.c b/drivers/edac/cortex_arm64_edac.c index 2268bd3fa8f0..1fa8e9a62082 100644 --- a/drivers/edac/cortex_arm64_edac.c +++ b/drivers/edac/cortex_arm64_edac.c @@ -267,8 +267,10 @@ static void ca53_parse_cpumerrsr(struct erp_local_data *ed) if (A53_CPUMERRSR_FATAL(cpumerrsr)) ed->err = DBE; - edac_printk(KERN_CRIT, EDAC_CPU, "Cortex A53 CPU%d L1 %s Error detected\n", - smp_processor_id(), err_name[ed->err]); + edac_printk(KERN_CRIT, EDAC_CPU, + "Kryo2xx Silver CPU%d L1 %s Error detected\n", + smp_processor_id(), err_name[ed->err]); + ca53_ca57_print_error_state_regs(); if (ed->err == DBE) edac_printk(KERN_CRIT, EDAC_CPU, "Fatal error\n"); @@ -338,8 +340,8 @@ static void ca53_parse_l2merrsr(struct erp_local_data *ed) if (A53_L2MERRSR_FATAL(l2merrsr)) ed->err = DBE; - edac_printk(KERN_CRIT, EDAC_CPU, "CortexA53 L2 %s Error detected\n", - err_name[ed->err]); + edac_printk(KERN_CRIT, EDAC_CPU, "Kyro2xx Silver L2 %s Error detected\n", + err_name[ed->err]); ca53_ca57_print_error_state_regs(); if (ed->err == DBE) edac_printk(KERN_CRIT, EDAC_CPU, "Fatal error\n"); diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index 0ad87c609453..db5a9ca28408 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -10,7 +10,8 @@ msm_kgsl_core-y = \ kgsl_pwrscale.o \ kgsl_mmu.o \ kgsl_snapshot.o \ - kgsl_events.o + kgsl_events.o \ + kgsl_pool.o msm_kgsl_core-$(CONFIG_QCOM_KGSL_IOMMU) += kgsl_iommu.o msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h index d8f94757ba28..fd972dfd3862 100644 --- a/drivers/gpu/msm/a3xx_reg.h +++ b/drivers/gpu/msm/a3xx_reg.h @@ -44,35 +44,20 @@ /* CP_EVENT_WRITE events */ #define CACHE_FLUSH_TS 4 -/* CP_INTERRUPT masks */ - -#define CP_INTERRUPT_IB2 0x20000000 -#define CP_INTERRUPT_IB1 0x40000000 -#define CP_INTERRUPT_RB 0x80000000 - /* Register definitions */ -#define A3XX_RBBM_HW_VERSION 0x000 -#define A3XX_RBBM_HW_RELEASE 0x001 -#define A3XX_RBBM_HW_CONFIGURATION 0x002 #define A3XX_RBBM_CLOCK_CTL 0x010 #define A3XX_RBBM_SP_HYST_CNT 0x012 #define A3XX_RBBM_SW_RESET_CMD 0x018 #define A3XX_RBBM_AHB_CTL0 0x020 #define A3XX_RBBM_AHB_CTL1 0x021 #define A3XX_RBBM_AHB_CMD 0x022 -#define A3XX_RBBM_AHB_ME_SPLIT_STATUS 0x25 -#define A3XX_RBBM_AHB_PFP_SPLIT_STATUS 0x26 #define A3XX_RBBM_AHB_ERROR_STATUS 0x027 #define A3XX_RBBM_GPR0_CTL 0x02E /* This the same register as on A2XX, just in a different place */ #define A3XX_RBBM_STATUS 0x030 #define A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL 0x33 #define A3XX_RBBM_INTERFACE_HANG_INT_CTL 0x50 -#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL0 0x51 -#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL1 0x54 -#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL2 0x57 -#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL3 0x5A #define A3XX_RBBM_INT_CLEAR_CMD 0x061 #define A3XX_RBBM_INT_0_MASK 0x063 #define A3XX_RBBM_INT_0_STATUS 0x064 @@ -188,10 +173,8 @@ #define A3XX_RBBM_EXT_TRACE_CMD 0x122 #define A3XX_CP_RB_BASE 0x01C0 #define A3XX_CP_RB_CNTL 0x01C1 -#define A3XX_CP_RB_RPTR_ADDR 0x01C3 #define A3XX_CP_RB_RPTR 0x01C4 #define A3XX_CP_RB_WPTR 0x01C5 -#define A3XX_CP_RB_RPTR_WR 0x01C7 /* Following two are same as on A2XX, just in a different place */ #define A3XX_CP_PFP_UCODE_ADDR 0x1C9 #define A3XX_CP_PFP_UCODE_DATA 0x1CA @@ -203,8 +186,6 @@ #define A3XX_CP_QUEUE_THRESHOLDS 0x01D5 #define A3XX_CP_MEQ_ADDR 0x1DA #define A3XX_CP_MEQ_DATA 0x1DB -#define A3XX_CP_SCRATCH_UMSK 0x01DC -#define A3XX_CP_SCRATCH_ADDR 0x01DD #define A3XX_CP_STATE_DEBUG_INDEX 0x01EC #define A3XX_CP_STATE_DEBUG_DATA 0x01ED #define A3XX_CP_CNTL 0x01F4 @@ -225,53 +206,28 @@ #define A3XX_CP_IB2_BUFSZ 0x045B #define A3XX_CP_HW_FAULT 0x45C -#define A3XX_CP_AHB_FAULT 0x54D #define A3XX_CP_PROTECT_CTRL 0x45E #define A3XX_CP_PROTECT_STATUS 0x45F #define A3XX_CP_PROTECT_REG_0 0x460 -#define A3XX_CP_PROTECT_REG_1 0x461 -#define A3XX_CP_PROTECT_REG_2 0x462 -#define A3XX_CP_PROTECT_REG_3 0x463 -#define A3XX_CP_PROTECT_REG_4 0x464 -#define A3XX_CP_PROTECT_REG_5 0x465 -#define A3XX_CP_PROTECT_REG_6 0x466 -#define A3XX_CP_PROTECT_REG_7 0x467 -#define A3XX_CP_PROTECT_REG_8 0x468 -#define A3XX_CP_PROTECT_REG_9 0x469 -#define A3XX_CP_PROTECT_REG_A 0x46A -#define A3XX_CP_PROTECT_REG_B 0x46B -#define A3XX_CP_PROTECT_REG_C 0x46C -#define A3XX_CP_PROTECT_REG_D 0x46D -#define A3XX_CP_PROTECT_REG_E 0x46E -#define A3XX_CP_PROTECT_REG_F 0x46F #define A3XX_CP_STAT 0x047F #define A3XX_CP_SCRATCH_REG0 0x578 #define A3XX_CP_SCRATCH_REG6 0x57E #define A3XX_CP_SCRATCH_REG7 0x57F -#define A3XX_VSC_BIN_SIZE 0xC01 #define A3XX_VSC_SIZE_ADDRESS 0xC02 -#define A3XX_VSC_PIPE_CONFIG_0 0xC06 #define A3XX_VSC_PIPE_DATA_ADDRESS_0 0xC07 #define A3XX_VSC_PIPE_DATA_LENGTH_0 0xC08 -#define A3XX_VSC_PIPE_CONFIG_1 0xC09 #define A3XX_VSC_PIPE_DATA_ADDRESS_1 0xC0A #define A3XX_VSC_PIPE_DATA_LENGTH_1 0xC0B -#define A3XX_VSC_PIPE_CONFIG_2 0xC0C #define A3XX_VSC_PIPE_DATA_ADDRESS_2 0xC0D #define A3XX_VSC_PIPE_DATA_LENGTH_2 0xC0E -#define A3XX_VSC_PIPE_CONFIG_3 0xC0F #define A3XX_VSC_PIPE_DATA_ADDRESS_3 0xC10 #define A3XX_VSC_PIPE_DATA_LENGTH_3 0xC11 -#define A3XX_VSC_PIPE_CONFIG_4 0xC12 #define A3XX_VSC_PIPE_DATA_ADDRESS_4 0xC13 #define A3XX_VSC_PIPE_DATA_LENGTH_4 0xC14 -#define A3XX_VSC_PIPE_CONFIG_5 0xC15 #define A3XX_VSC_PIPE_DATA_ADDRESS_5 0xC16 #define A3XX_VSC_PIPE_DATA_LENGTH_5 0xC17 -#define A3XX_VSC_PIPE_CONFIG_6 0xC18 #define A3XX_VSC_PIPE_DATA_ADDRESS_6 0xC19 #define A3XX_VSC_PIPE_DATA_LENGTH_6 0xC1A -#define A3XX_VSC_PIPE_CONFIG_7 0xC1B #define A3XX_VSC_PIPE_DATA_ADDRESS_7 0xC1C #define A3XX_VSC_PIPE_DATA_LENGTH_7 0xC1D #define A3XX_PC_PERFCOUNTER0_SELECT 0xC48 @@ -417,10 +373,6 @@ #define A3XX_RB_SAMPLE_COUNT_ADDR 0x2111 #define A3XX_RB_Z_CLAMP_MIN 0x2114 #define A3XX_RB_Z_CLAMP_MAX 0x2115 -#define A3XX_PC_VSTREAM_CONTROL 0x21E4 -#define A3XX_PC_VERTEX_REUSE_BLOCK_CNTL 0x21EA -#define A3XX_PC_PRIM_VTX_CNTL 0x21EC -#define A3XX_PC_RESTART_INDEX 0x21ED #define A3XX_HLSQ_CONTROL_0_REG 0x2200 #define A3XX_HLSQ_CONTROL_1_REG 0x2201 #define A3XX_HLSQ_CONTROL_2_REG 0x2202 @@ -443,11 +395,6 @@ #define A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG 0x2216 #define A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG 0x2217 #define A3XX_HLSQ_CL_WG_OFFSET_REG 0x221A -#define A3XX_VFD_CONTROL_0 0x2240 -#define A3XX_VFD_INDEX_MIN 0x2242 -#define A3XX_VFD_INDEX_MAX 0x2243 -#define A3XX_VFD_FETCH_INSTR_0_0 0x2246 -#define A3XX_VFD_FETCH_INSTR_0_4 0x224E #define A3XX_VFD_FETCH_INSTR_1_0 0x2247 #define A3XX_VFD_FETCH_INSTR_1_1 0x2249 #define A3XX_VFD_FETCH_INSTR_1_2 0x224B @@ -464,10 +411,6 @@ #define A3XX_VFD_FETCH_INSTR_1_D 0x2261 #define A3XX_VFD_FETCH_INSTR_1_E 0x2263 #define A3XX_VFD_FETCH_INSTR_1_F 0x2265 -#define A3XX_VFD_DECODE_INSTR_0 0x2266 -#define A3XX_VFD_VS_THREADING_THRESHOLD 0x227E -#define A3XX_VPC_ATTR 0x2280 -#define A3XX_VPC_VARY_CYLWRAP_ENABLE_1 0x228B #define A3XX_SP_SP_CTRL_REG 0x22C0 #define A3XX_SP_VS_CTRL_REG0 0x22C4 #define A3XX_SP_VS_CTRL_REG1 0x22C5 @@ -510,13 +453,7 @@ #define A3XX_SP_FS_IMAGE_OUTPUT_REG_3 0x22F7 #define A3XX_SP_FS_LENGTH_REG 0x22FF #define A3XX_PA_SC_AA_CONFIG 0x2301 -#define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340 -#define A3XX_TPL1_TP_FS_TEX_OFFSET 0x2342 -#define A3XX_TPL1_TP_FS_BORDER_COLOR_BASE_ADDR 0x2343 #define A3XX_VBIF_CLKON 0x3001 -#define A3XX_VBIF_FIXED_SORT_EN 0x300C -#define A3XX_VBIF_FIXED_SORT_SEL0 0x300D -#define A3XX_VBIF_FIXED_SORT_SEL1 0x300E #define A3XX_VBIF_ABIT_SORT 0x301C #define A3XX_VBIF_ABIT_SORT_CONF 0x301D #define A3XX_VBIF_GATE_OFF_WRREQ_EN 0x302A @@ -529,12 +466,8 @@ #define A3XX_VBIF_DDR_OUT_MAX_BURST 0x3036 #define A3XX_VBIF_ARB_CTL 0x303C #define A3XX_VBIF_ROUND_ROBIN_QOS_ARB 0x3049 -#define A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x3058 #define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E #define A3XX_VBIF_OUT_AXI_AOOO 0x305F -#define A3XX_VBIF_PERF_CNT_EN 0x3070 -#define A3XX_VBIF_PERF_CNT_CLR 0x3071 -#define A3XX_VBIF_PERF_CNT_SEL 0x3072 #define A3XX_VBIF_PERF_CNT0_LO 0x3073 #define A3XX_VBIF_PERF_CNT0_HI 0x3074 #define A3XX_VBIF_PERF_CNT1_LO 0x3075 @@ -553,14 +486,6 @@ #define A3XX_VBIF_XIN_HALT_CTRL1 0x3081 /* VBIF register offsets for A306 */ -#define A3XX_VBIF2_PERF_CNT_EN0 0x30c0 -#define A3XX_VBIF2_PERF_CNT_EN1 0x30c1 -#define A3XX_VBIF2_PERF_CNT_EN2 0x30c2 -#define A3XX_VBIF2_PERF_CNT_EN3 0x30c3 -#define A3XX_VBIF2_PERF_CNT_CLR0 0x30c8 -#define A3XX_VBIF2_PERF_CNT_CLR1 0x30c9 -#define A3XX_VBIF2_PERF_CNT_CLR2 0x30ca -#define A3XX_VBIF2_PERF_CNT_CLR3 0x30cb #define A3XX_VBIF2_PERF_CNT_SEL0 0x30d0 #define A3XX_VBIF2_PERF_CNT_SEL1 0x30d1 #define A3XX_VBIF2_PERF_CNT_SEL2 0x30d2 @@ -577,9 +502,6 @@ #define A3XX_VBIF2_PERF_PWR_CNT_EN0 0x3100 #define A3XX_VBIF2_PERF_PWR_CNT_EN1 0x3101 #define A3XX_VBIF2_PERF_PWR_CNT_EN2 0x3102 -#define A3XX_VBIF2_PERF_PWR_CNT_CLR0 0x3108 -#define A3XX_VBIF2_PERF_PWR_CNT_CLR1 0x3109 -#define A3XX_VBIF2_PERF_PWR_CNT_CLR2 0x310A #define A3XX_VBIF2_PERF_PWR_CNT_LOW0 0x3110 #define A3XX_VBIF2_PERF_PWR_CNT_LOW1 0x3111 #define A3XX_VBIF2_PERF_PWR_CNT_LOW2 0x3112 @@ -590,240 +512,7 @@ #define A3XX_VBIF_DDR_OUTPUT_RECOVERABLE_HALT_CTRL0 0x3800 #define A3XX_VBIF_DDR_OUTPUT_RECOVERABLE_HALT_CTRL1 0x3801 -/* Various flags used by the context switch code */ - -#define SP_MULTI 0 -#define SP_BUFFER_MODE 1 -#define SP_TWO_VTX_QUADS 0 -#define SP_PIXEL_BASED 0 -#define SP_R8G8B8A8_UNORM 8 -#define SP_FOUR_PIX_QUADS 1 - -#define HLSQ_DIRECT 0 -#define HLSQ_BLOCK_ID_SP_VS 4 -#define HLSQ_SP_VS_INSTR 0 -#define HLSQ_SP_FS_INSTR 0 -#define HLSQ_BLOCK_ID_SP_FS 6 -#define HLSQ_TWO_PIX_QUADS 0 -#define HLSQ_TWO_VTX_QUADS 0 -#define HLSQ_BLOCK_ID_TP_TEX 2 -#define HLSQ_TP_TEX_SAMPLERS 0 -#define HLSQ_TP_TEX_MEMOBJ 1 -#define HLSQ_BLOCK_ID_TP_MIPMAP 3 -#define HLSQ_TP_MIPMAP_BASE 1 -#define HLSQ_FOUR_PIX_QUADS 1 - -#define RB_FACTOR_ONE 1 -#define RB_BLEND_OP_ADD 0 -#define RB_FACTOR_ZERO 0 -#define RB_DITHER_DISABLE 0 -#define RB_DITHER_ALWAYS 1 -#define RB_FRAG_NEVER 0 -#define RB_ENDIAN_NONE 0 -#define RB_R8G8B8A8_UNORM 8 -#define RB_RESOLVE_PASS 2 -#define RB_CLEAR_MODE_RESOLVE 1 -#define RB_TILINGMODE_LINEAR 0 -#define RB_REF_NEVER 0 -#define RB_FRAG_LESS 1 -#define RB_REF_ALWAYS 7 -#define RB_STENCIL_KEEP 0 -#define RB_RENDERING_PASS 0 -#define RB_TILINGMODE_32X32 2 - -#define PC_DRAW_TRIANGLES 2 -#define PC_DI_PT_RECTLIST 8 -#define PC_DI_SRC_SEL_AUTO_INDEX 2 -#define PC_DI_INDEX_SIZE_16_BIT 0 -#define PC_DI_IGNORE_VISIBILITY 0 -#define PC_DI_PT_TRILIST 4 -#define PC_DI_SRC_SEL_IMMEDIATE 1 -#define PC_DI_INDEX_SIZE_32_BIT 1 - -#define UCHE_ENTIRE_CACHE 1 -#define UCHE_OP_INVALIDATE 1 - -/* - * The following are bit field shifts within some of the registers defined - * above. These are used in the context switch code in conjunction with the - * _SET macro - */ - -#define GRAS_CL_CLIP_CNTL_CLIP_DISABLE 16 -#define GRAS_CL_CLIP_CNTL_IJ_PERSP_CENTER 12 -#define GRAS_CL_CLIP_CNTL_PERSP_DIVISION_DISABLE 21 -#define GRAS_CL_CLIP_CNTL_VP_CLIP_CODE_IGNORE 19 -#define GRAS_CL_CLIP_CNTL_VP_XFORM_DISABLE 20 -#define GRAS_CL_CLIP_CNTL_ZFAR_CLIP_DISABLE 17 -#define GRAS_CL_VPORT_XSCALE_VPORT_XSCALE 0 -#define GRAS_CL_VPORT_YSCALE_VPORT_YSCALE 0 -#define GRAS_CL_VPORT_ZSCALE_VPORT_ZSCALE 0 -#define GRAS_SC_CONTROL_RASTER_MODE 12 -#define GRAS_SC_CONTROL_RENDER_MODE 4 -#define GRAS_SC_SCREEN_SCISSOR_BR_BR_X 0 -#define GRAS_SC_SCREEN_SCISSOR_BR_BR_Y 16 -#define GRAS_SC_WINDOW_SCISSOR_BR_BR_X 0 -#define GRAS_SC_WINDOW_SCISSOR_BR_BR_Y 16 -#define GRAS_SU_CTRLMODE_LINEHALFWIDTH 03 -#define HLSQ_CONSTFSPRESERVEDRANGEREG_ENDENTRY 16 -#define HLSQ_CONSTFSPRESERVEDRANGEREG_STARTENTRY 0 -#define HLSQ_CTRL0REG_CHUNKDISABLE 26 -#define HLSQ_CTRL0REG_CONSTSWITCHMODE 27 -#define HLSQ_CTRL0REG_FSSUPERTHREADENABLE 6 -#define HLSQ_CTRL0REG_FSTHREADSIZE 4 -#define HLSQ_CTRL0REG_LAZYUPDATEDISABLE 28 -#define HLSQ_CTRL0REG_RESERVED2 10 -#define HLSQ_CTRL0REG_SPCONSTFULLUPDATE 29 -#define HLSQ_CTRL0REG_SPSHADERRESTART 9 -#define HLSQ_CTRL0REG_TPFULLUPDATE 30 -#define HLSQ_CTRL1REG_RESERVED1 9 -#define HLSQ_CTRL1REG_VSSUPERTHREADENABLE 8 -#define HLSQ_CTRL1REG_VSTHREADSIZE 6 -#define HLSQ_CTRL2REG_PRIMALLOCTHRESHOLD 26 -#define HLSQ_FSCTRLREG_FSCONSTLENGTH 0 -#define HLSQ_FSCTRLREG_FSCONSTSTARTOFFSET 12 -#define HLSQ_FSCTRLREG_FSINSTRLENGTH 24 -#define HLSQ_VSCTRLREG_VSINSTRLENGTH 24 -#define PC_PRIM_VTX_CONTROL_POLYMODE_BACK_PTYPE 8 -#define PC_PRIM_VTX_CONTROL_POLYMODE_FRONT_PTYPE 5 -#define PC_PRIM_VTX_CONTROL_PROVOKING_VTX_LAST 25 -#define PC_PRIM_VTX_CONTROL_STRIDE_IN_VPC 0 -#define PC_DRAW_INITIATOR_PRIM_TYPE 0 -#define PC_DRAW_INITIATOR_SOURCE_SELECT 6 -#define PC_DRAW_INITIATOR_VISIBILITY_CULLING_MODE 9 -#define PC_DRAW_INITIATOR_INDEX_SIZE 0x0B -#define PC_DRAW_INITIATOR_SMALL_INDEX 0x0D -#define PC_DRAW_INITIATOR_PRE_DRAW_INITIATOR_ENABLE 0x0E -#define RB_COPYCONTROL_COPY_GMEM_BASE 14 -#define RB_COPYCONTROL_RESOLVE_CLEAR_MODE 4 -#define RB_COPYDESTBASE_COPY_DEST_BASE 4 -#define RB_COPYDESTINFO_COPY_COMPONENT_ENABLE 14 -#define RB_COPYDESTINFO_COPY_DEST_ENDIAN 18 -#define RB_COPYDESTINFO_COPY_DEST_FORMAT 2 -#define RB_COPYDESTINFO_COPY_DEST_TILE 0 -#define RB_COPYDESTPITCH_COPY_DEST_PITCH 0 -#define RB_DEPTHCONTROL_Z_TEST_FUNC 4 -#define RB_MODECONTROL_RENDER_MODE 8 -#define RB_MODECONTROL_MARB_CACHE_SPLIT_MODE 15 -#define RB_MODECONTROL_PACKER_TIMER_ENABLE 16 -#define RB_MRTBLENDCONTROL_ALPHA_BLEND_OPCODE 21 -#define RB_MRTBLENDCONTROL_ALPHA_DEST_FACTOR 24 -#define RB_MRTBLENDCONTROL_ALPHA_SRC_FACTOR 16 -#define RB_MRTBLENDCONTROL_CLAMP_ENABLE 29 -#define RB_MRTBLENDCONTROL_RGB_BLEND_OPCODE 5 -#define RB_MRTBLENDCONTROL_RGB_DEST_FACTOR 8 -#define RB_MRTBLENDCONTROL_RGB_SRC_FACTOR 0 -#define RB_MRTBUFBASE_COLOR_BUF_BASE 4 -#define RB_MRTBUFINFO_COLOR_BUF_PITCH 17 -#define RB_MRTBUFINFO_COLOR_FORMAT 0 -#define RB_MRTBUFINFO_COLOR_TILE_MODE 6 -#define RB_MRTCONTROL_COMPONENT_ENABLE 24 -#define RB_MRTCONTROL_DITHER_MODE 12 -#define RB_MRTCONTROL_READ_DEST_ENABLE 3 -#define RB_MRTCONTROL_ROP_CODE 8 -#define RB_MSAACONTROL_MSAA_DISABLE 10 -#define RB_MSAACONTROL_SAMPLE_MASK 16 -#define RB_RENDERCONTROL_ALPHA_TEST_FUNC 24 -#define RB_RENDERCONTROL_BIN_WIDTH 4 -#define RB_RENDERCONTROL_DISABLE_COLOR_PIPE 12 -#define RB_STENCILCONTROL_STENCIL_FAIL 11 -#define RB_STENCILCONTROL_STENCIL_FAIL_BF 23 -#define RB_STENCILCONTROL_STENCIL_FUNC 8 -#define RB_STENCILCONTROL_STENCIL_FUNC_BF 20 -#define RB_STENCILCONTROL_STENCIL_ZFAIL 17 -#define RB_STENCILCONTROL_STENCIL_ZFAIL_BF 29 -#define RB_STENCILCONTROL_STENCIL_ZPASS 14 -#define RB_STENCILCONTROL_STENCIL_ZPASS_BF 26 -#define SP_FSCTRLREG0_FSFULLREGFOOTPRINT 10 -#define SP_FSCTRLREG0_FSHALFREGFOOTPRINT 4 -#define SP_FSCTRLREG0_FSICACHEINVALID 2 -#define SP_FSCTRLREG0_FSINOUTREGOVERLAP 18 -#define SP_FSCTRLREG0_FSINSTRBUFFERMODE 1 -#define SP_FSCTRLREG0_FSLENGTH 24 -#define SP_FSCTRLREG0_FSSUPERTHREADMODE 21 -#define SP_FSCTRLREG0_FSTHREADMODE 0 -#define SP_FSCTRLREG0_FSTHREADSIZE 20 -#define SP_FSCTRLREG0_PIXLODENABLE 22 -#define SP_FSCTRLREG1_FSCONSTLENGTH 0 -#define SP_FSCTRLREG1_FSINITIALOUTSTANDING 20 -#define SP_FSCTRLREG1_HALFPRECVAROFFSET 24 -#define SP_FSMRTREG_REGID 0 -#define SP_FSMRTREG_PRECISION 8 -#define SP_FSOUTREG_PAD0 2 -#define SP_IMAGEOUTPUTREG_MRTFORMAT 0 -#define SP_IMAGEOUTPUTREG_DEPTHOUTMODE 3 -#define SP_IMAGEOUTPUTREG_PAD0 6 -#define SP_OBJOFFSETREG_CONSTOBJECTSTARTOFFSET 16 -#define SP_OBJOFFSETREG_SHADEROBJOFFSETINIC 25 -#define SP_SHADERLENGTH_LEN 0 -#define SP_SPCTRLREG_CONSTMODE 18 -#define SP_SPCTRLREG_LOMODE 22 -#define SP_SPCTRLREG_SLEEPMODE 20 -#define SP_VSCTRLREG0_VSFULLREGFOOTPRINT 10 -#define SP_VSCTRLREG0_VSICACHEINVALID 2 -#define SP_VSCTRLREG0_VSINSTRBUFFERMODE 1 -#define SP_VSCTRLREG0_VSLENGTH 24 -#define SP_VSCTRLREG0_VSSUPERTHREADMODE 21 -#define SP_VSCTRLREG0_VSTHREADMODE 0 -#define SP_VSCTRLREG0_VSTHREADSIZE 20 -#define SP_VSCTRLREG1_VSINITIALOUTSTANDING 24 -#define SP_VSOUTREG_COMPMASK0 9 -#define SP_VSPARAMREG_POSREGID 0 -#define SP_VSPARAMREG_PSIZEREGID 8 -#define SP_VSPARAMREG_TOTALVSOUTVAR 20 -#define SP_VSVPCDSTREG_OUTLOC0 0 -#define TPL1_TPTEXOFFSETREG_BASETABLEPTR 16 -#define TPL1_TPTEXOFFSETREG_MEMOBJOFFSET 8 -#define TPL1_TPTEXOFFSETREG_SAMPLEROFFSET 0 -#define UCHE_INVALIDATE1REG_OPCODE 0x1C -#define UCHE_INVALIDATE1REG_ALLORPORTION 0x1F -#define VFD_BASEADDR_BASEADDR 0 -#define VFD_CTRLREG0_PACKETSIZE 18 -#define VFD_CTRLREG0_STRMDECINSTRCNT 22 -#define VFD_CTRLREG0_STRMFETCHINSTRCNT 27 -#define VFD_CTRLREG0_TOTALATTRTOVS 0 -#define VFD_CTRLREG1_MAXSTORAGE 0 -#define VFD_CTRLREG1_REGID4INST 24 -#define VFD_CTRLREG1_REGID4VTX 16 -#define VFD_DECODEINSTRUCTIONS_CONSTFILL 4 -#define VFD_DECODEINSTRUCTIONS_FORMAT 6 -#define VFD_DECODEINSTRUCTIONS_LASTCOMPVALID 29 -#define VFD_DECODEINSTRUCTIONS_REGID 12 -#define VFD_DECODEINSTRUCTIONS_SHIFTCNT 24 -#define VFD_DECODEINSTRUCTIONS_SWITCHNEXT 30 -#define VFD_DECODEINSTRUCTIONS_WRITEMASK 0 -#define VFD_FETCHINSTRUCTIONS_BUFSTRIDE 7 -#define VFD_FETCHINSTRUCTIONS_FETCHSIZE 0 -#define VFD_FETCHINSTRUCTIONS_INDEXDECODE 18 -#define VFD_FETCHINSTRUCTIONS_STEPRATE 24 -#define VFD_FETCHINSTRUCTIONS_SWITCHNEXT 17 -#define VFD_THREADINGTHRESHOLD_REGID_VTXCNT 8 -#define VFD_THREADINGTHRESHOLD_REGID_THRESHOLD 0 -#define VFD_THREADINGTHRESHOLD_RESERVED6 4 -#define VPC_VPCATTR_LMSIZE 28 -#define VPC_VPCATTR_THRHDASSIGN 12 -#define VPC_VPCATTR_TOTALATTR 0 -#define VPC_VPCPACK_NUMFPNONPOSVAR 8 -#define VPC_VPCPACK_NUMNONPOSVSVAR 16 -#define VPC_VPCVARPSREPLMODE_COMPONENT08 0 -#define VPC_VPCVARPSREPLMODE_COMPONENT09 2 -#define VPC_VPCVARPSREPLMODE_COMPONENT0A 4 -#define VPC_VPCVARPSREPLMODE_COMPONENT0B 6 -#define VPC_VPCVARPSREPLMODE_COMPONENT0C 8 -#define VPC_VPCVARPSREPLMODE_COMPONENT0D 10 -#define VPC_VPCVARPSREPLMODE_COMPONENT0E 12 -#define VPC_VPCVARPSREPLMODE_COMPONENT0F 14 -#define VPC_VPCVARPSREPLMODE_COMPONENT10 16 -#define VPC_VPCVARPSREPLMODE_COMPONENT11 18 -#define VPC_VPCVARPSREPLMODE_COMPONENT12 20 -#define VPC_VPCVARPSREPLMODE_COMPONENT13 22 -#define VPC_VPCVARPSREPLMODE_COMPONENT14 24 -#define VPC_VPCVARPSREPLMODE_COMPONENT15 26 -#define VPC_VPCVARPSREPLMODE_COMPONENT16 28 -#define VPC_VPCVARPSREPLMODE_COMPONENT17 30 - /* RBBM Debug bus block IDs */ -#define RBBM_BLOCK_ID_NONE 0x0 #define RBBM_BLOCK_ID_CP 0x1 #define RBBM_BLOCK_ID_RBBM 0x2 #define RBBM_BLOCK_ID_VBIF 0x3 @@ -871,7 +560,6 @@ /* VBIF countables */ #define VBIF_AXI_TOTAL_BEATS 85 -#define VBIF_DDR_TOTAL_CYCLES 110 /* VBIF Recoverable HALT bit value */ #define VBIF_RECOVERABLE_HALT_CTRL 0x1 diff --git a/drivers/gpu/msm/a4xx_reg.h b/drivers/gpu/msm/a4xx_reg.h index 78db8dd2da40..4b69583a6ce1 100644 --- a/drivers/gpu/msm/a4xx_reg.h +++ b/drivers/gpu/msm/a4xx_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -102,7 +102,6 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_RBBM_INTERFACE_HANG_INT_CTL 0x2f #define A4XX_RBBM_INT_CLEAR_CMD 0x36 #define A4XX_RBBM_INT_0_MASK 0x37 -#define A4XX_RBBM_ALWAYSON_COUNTER_CNTL 0x3d #define A4XX_RBBM_RBBM_CTL 0x3e #define A4XX_RBBM_CLOCK_CTL2 0x42 #define A4XX_RBBM_BLOCK_SW_RESET_CMD 0x45 @@ -113,13 +112,8 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_RBBM_CFG_DEBBUS_SEL_D 0x4d #define A4XX_RBBM_CFG_DEBBUS_SEL_PING_INDEX_SHIFT 0 #define A4XX_RBBM_CFG_DEBBUS_SEL_PING_BLK_SEL_SHIFT 8 -#define A4XX_RBBM_CFG_DEBBUS_SEL_PONG_INDEX_SHIFT 16 -#define A4XX_RBBM_CFG_DEBBUS_SEL_PONG_BLK_SEL_SHIFT 24 #define A4XX_RBBM_CFG_DEBBUS_CTLT 0x4e -#define A4XX_RBBM_CFG_DEBBUS_CTLT_ENT_SHIFT 0 -#define A4XX_RBBM_CFG_DEBBUS_CTLT_GRANU_SHIFT 12 -#define A4XX_RBBM_CFG_DEBBUS_CTLT_SEGT_SHIFT 28 #define A4XX_RBBM_CFG_DEBBUS_CTLM 0x4f #define A4XX_RBBM_CFG_DEBBUS_CTLT_ENABLE_SHIFT 24 @@ -138,24 +132,7 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_RBBM_CFG_DEBBUS_BYTEL_0 0x5a -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL0_SHIFT 0 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL1_SHIFT 4 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL2_SHIFT 8 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL3_SHIFT 12 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL4_SHIFT 16 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL5_SHIFT 20 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL6_SHIFT 24 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_0_BYTEL7_SHIFT 28 - -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1 0x5b -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL8_SHIFT 0 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL9_SHIFT 4 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL10_SHIFT 8 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL11_SHIFT 12 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL12_SHIFT 16 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL13_SHIFT 20 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL14_SHIFT 24 -#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1_BYTEL15_SHIFT 28 +#define A4XX_RBBM_CFG_DEBBUS_BYTEL_1 0x5b #define A4XX_RBBM_CFG_DEBBUS_IVTE_0 0x5c #define A4XX_RBBM_CFG_DEBBUS_IVTE_1 0x5d @@ -425,14 +402,7 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_RBBM_AHB_PFP_SPLIT_STATUS 0x18d #define A4XX_RBBM_AHB_ERROR_STATUS 0x18f #define A4XX_RBBM_STATUS 0x191 -#define A4XX_RBBM_CFG_COUNTER0 0x1a2 -#define A4XX_RBBM_CFG_DEBBUS_TRACE_BUF0 0x1a9 -#define A4XX_RBBM_CFG_DEBBUS_TRACE_BUF1 0x1aa -#define A4XX_RBBM_CFG_DEBBUS_TRACE_BUF2 0x1ab -#define A4XX_RBBM_CFG_DEBBUS_TRACE_BUF3 0x1ac #define A4XX_RBBM_CFG_DEBBUS_TRACE_BUF4 0x1ad -#define A4XX_RBBM_CFG_DEBBUS_MISR0 0x1ae -#define A4XX_RBBM_CFG_DEBBUS_MISR1 0x1af #define A4XX_RBBM_POWER_STATUS 0x1b0 #define A4XX_RBBM_PPD_V2_SP_PWR_WEIGHTS 0x1b2 #define A4XX_RBBM_PPD_V2_SP_RB_EPOCH_TH 0x1b3 @@ -440,8 +410,6 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_RBBM_PPD_RAMP_V2_CONTROL 0x1b5 #define A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL2 0x1b8 #define A4XX_RBBM_PPD_CTRL 0x1b9 -#define A4XX_RBBM_PPD_EPOCH_INTRA_TH_1 0x1ba -#define A4XX_RBBM_PPD_EPOCH_INTRA_TH_2 0x1bb #define A4XX_RBBM_PPD_EPOCH_INTER_TH_HIGH_CLEAR_THR 0x1bc #define A4XX_RBBM_PPD_EPOCH_INTER_TH_LOW 0x1bd /* SECVID registers */ @@ -473,13 +441,8 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_CP_ME_RAM_WADDR 0x225 #define A4XX_CP_ME_RAM_RADDR 0x226 #define A4XX_CP_ME_RAM_DATA 0x227 -#define A4XX_CP_SCRATCH_UMASK 0x228 -#define A4XX_CP_SCRATCH_ADDR 0x229 #define A4XX_CP_PREEMPT 0x22a -/* PREEMPT register bit shifts */ -#define A4XX_CP_PREEMPT_STOP_SHIFT 0 -#define A4XX_CP_PREEMPT_RESUME_SHIFT 1 #define A4XX_CP_PREEMPT_DISABLE 0x22b #define A4XX_CP_CNTL 0x22c @@ -513,7 +476,6 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_CP_PERFCTR_CP_SEL_6 0x506 #define A4XX_CP_PERFCTR_CP_SEL_7 0x507 -#define A4XX_CP_SCRATCH_REG0 0x578 #define A4XX_CP_SCRATCH_REG6 0x57e #define A4XX_CP_SCRATCH_REG7 0x57f #define A4XX_CP_SCRATCH_REG8 0x580 @@ -540,9 +502,6 @@ enum a4xx_rb_perfctr_rb_sel { #define A4XX_SP_CS_CTRL_0 0x2300 #define A4XX_SP_CS_OBJ_OFFSET 0x2301 #define A4XX_SP_CS_OBJ_START 0x2302 -#define A4XX_SP_CS_PVT_MEM_PARAM 0x2303 -#define A4XX_SP_CS_PVT_MEM_ADDR 0x2304 -#define A4XX_SP_CS_PVT_MEM_SIZE 0x2305 #define A4XX_SP_CS_LENGTH 0x2306 #define A4XX_SP_MODE_CONTROL 0xec3 #define A4XX_SP_PERFCTR_SP_SEL_0 0xec4 @@ -611,8 +570,6 @@ enum a4xx_sp_perfctr_sp_sel { #define A4XX_VSC_PERFCTR_VSC_SEL_1 0xc51 /* VFD registers */ -#define A4XX_VFD_CONTROL_0 0x2200 -#define A4XX_VFD_FETCH_INSTR_0_0 0x220a #define A4XX_VFD_FETCH_INSTR_1_31 0x2287 #define A4XX_VFD_PERFCTR_VFD_SEL_0 0xe43 #define A4XX_VFD_PERFCTR_VFD_SEL_1 0xe44 @@ -699,14 +656,6 @@ enum a4xx_vfd_perfctr_vfd_sel { #define A4XX_VBIF_TEST_BUS_OUT 0x308c -#define A4XX_VBIF_PERF_CNT_EN0 0x30c0 -#define A4XX_VBIF_PERF_CNT_EN1 0x30c1 -#define A4XX_VBIF_PERF_CNT_EN2 0x30c2 -#define A4XX_VBIF_PERF_CNT_EN3 0x30c3 -#define A4XX_VBIF_PERF_CNT_CLR0 0x30c8 -#define A4XX_VBIF_PERF_CNT_CLR1 0x30c9 -#define A4XX_VBIF_PERF_CNT_CLR2 0x30ca -#define A4XX_VBIF_PERF_CNT_CLR3 0x30cb #define A4XX_VBIF_PERF_CNT_SEL0 0x30d0 #define A4XX_VBIF_PERF_CNT_SEL1 0x30d1 #define A4XX_VBIF_PERF_CNT_SEL2 0x30d2 @@ -724,10 +673,6 @@ enum a4xx_vfd_perfctr_vfd_sel { #define A4XX_VBIF_PERF_PWR_CNT_EN1 0x3101 #define A4XX_VBIF_PERF_PWR_CNT_EN2 0x3102 #define A4XX_VBIF_PERF_PWR_CNT_EN3 0x3103 -#define A4XX_VBIF_PERF_PWR_CNT_CLR0 0x3108 -#define A4XX_VBIF_PERF_PWR_CNT_CLR1 0x3109 -#define A4XX_VBIF_PERF_PWR_CNT_CLR2 0x310A -#define A4XX_VBIF_PERF_PWR_CNT_CLR3 0x310B #define A4XX_VBIF_PERF_PWR_CNT_LOW0 0x3110 #define A4XX_VBIF_PERF_PWR_CNT_LOW1 0x3111 #define A4XX_VBIF_PERF_PWR_CNT_LOW2 0x3112 @@ -737,12 +682,6 @@ enum a4xx_vfd_perfctr_vfd_sel { #define A4XX_VBIF_PERF_PWR_CNT_HIGH2 0x311a #define A4XX_VBIF_PERF_PWR_CNT_HIGH3 0x311b -/* Bit flags for RBBM_CTL */ -#define A4XX_RBBM_RBBM_CTL_RESET_PWR_CTR0 0x00000001 -#define A4XX_RBBM_RBBM_CTL_RESET_PWR_CTR1 0x00000002 -#define A4XX_RBBM_RBBM_CTL_ENABLE_PWR_CTR0 0x00000010 -#define A4XX_RBBM_RBBM_CTL_ENABLE_PWR_CTR1 0x00000020 - /* GRAS registers */ #define A4XX_GRAS_PERFCTR_TSE_SEL_0 0xc88 #define A4XX_GRAS_PERFCTR_TSE_SEL_1 0xc89 @@ -772,7 +711,6 @@ enum a4xx_pc_perfctr_pc_sel { /* HLSQ registers */ #define A4XX_HLSQ_TIMEOUT_THRESHOLD 0xe00 -#define A4XX_HLSQ_STATE_RESTORE_TRIGGER 0xe01 #define A4XX_HLSQ_MODE_CONTROL 0xe05 #define A4XX_HLSQ_PERFCTR_HLSQ_SEL_0 0xe06 #define A4XX_HLSQ_PERFCTR_HLSQ_SEL_1 0xe07 @@ -784,24 +722,11 @@ enum a4xx_pc_perfctr_pc_sel { #define A4XX_HLSQ_PERFCTR_HLSQ_SEL_7 0xe0d #define A4XX_HLSQ_SPTP_RDSEL 0xe30 #define A4xx_HLSQ_CONTROL_0 0x23c0 -#define A4xx_HLSQ_CONTROL_1 0x23c1 -#define A4xx_HLSQ_CONTROL_2 0x23c2 -#define A4xx_HLSQ_CONTROL_3 0x23c3 -#define A4xx_HLSQ_CONTROL_4 0x23c4 #define A4XX_HLSQ_CS_CONTROL 0x23ca #define A4XX_HLSQ_CL_NDRANGE_0 0x23cd -#define A4XX_HLSQ_CL_NDRANGE_1 0x23ce -#define A4XX_HLSQ_CL_NDRANGE_2 0x23cf -#define A4XX_HLSQ_CL_NDRANGE_3 0x23d0 -#define A4XX_HLSQ_CL_NDRANGE_4 0x23d1 -#define A4XX_HLSQ_CL_NDRANGE_5 0x23d2 -#define A4XX_HLSQ_CL_NDRANGE_6 0x23d3 #define A4XX_HLSQ_CL_CONTROL_0 0x23d4 -#define A4XX_HLSQ_CL_CONTROL_1 0x23d5 #define A4XX_HLSQ_CL_KERNEL_CONST 0x23d6 #define A4XX_HLSQ_CL_KERNEL_GROUP_X 0x23d7 -#define A4XX_HLSQ_CL_KERNEL_GROUP_Y 0x23d8 -#define A4XX_HLSQ_CL_KERNEL_GROUP_Z 0x23d9 #define A4XX_HLSQ_CL_WG_OFFSET 0x23da #define A4XX_HLSQ_UPDATE_CONTROL 0x23db @@ -863,9 +788,6 @@ enum a4xx_uche_perfctr_uche_sel { #define A4XX_TPL1_PERFCTR_TP_SEL_6 0xf0a #define A4XX_TPL1_PERFCTR_TP_SEL_7 0xf0b #define A4XX_TPL1_TP_TEX_TSIZE_1 0x23a0 -#define A4XX_TPL1_TP_CS_BORDER_COLOR_BASE_ADDR 0x23A4 -#define A4XX_TPL1_TP_CS_SAMPLER_BASE_ADDR 0x23A5 -#define A4XX_TPL1_TP_CS_TEXMEMOBJ_BASE_ADDR 0x23A6 enum a4xx_tpl1_perfctr_tp_sel { TP_OUTPUT_TEXELS_POINT = 0x2, diff --git a/drivers/gpu/msm/a5xx_reg.h b/drivers/gpu/msm/a5xx_reg.h index da5412c309ad..372bfad48a09 100644 --- a/drivers/gpu/msm/a5xx_reg.h +++ b/drivers/gpu/msm/a5xx_reg.h @@ -131,9 +131,6 @@ #define A5XX_CP_POWERCTR_CP_SEL_2 0xBBC #define A5XX_CP_POWERCTR_CP_SEL_3 0xBBD -/* CP_EVENT_WRITE events */ -#define A5XX_CACHE_FLUSH_TS 0x4 - /* RBBM registers */ #define A5XX_RBBM_CFG_DBGBUS_SEL_A 0x4 #define A5XX_RBBM_CFG_DBGBUS_SEL_B 0x5 @@ -141,8 +138,6 @@ #define A5XX_RBBM_CFG_DBGBUS_SEL_D 0x7 #define A5XX_RBBM_CFG_DBGBUS_SEL_PING_INDEX_SHIFT 0x0 #define A5XX_RBBM_CFG_DBGBUS_SEL_PING_BLK_SEL_SHIFT 0x8 -#define A5XX_RBBM_CFG_DBGBUS_SEL_PONG_INDEX_SHIFT 0x10 -#define A5XX_RBBM_CFG_DBGBUS_SEL_PONG_BLK_SEL_SHIFT 0x18 #define A5XX_RBBM_CFG_DBGBUS_CNTLT 0x8 #define A5XX_RBBM_CFG_DBGBUS_CNTLM 0x9 @@ -536,10 +531,6 @@ #define A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI 0xF801 #define A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE 0xF802 #define A5XX_RBBM_SECVID_TSB_CNTL 0xF803 -#define A5XX_RBBM_SECVID_TSB_COMP_STATUS_LO 0xF804 -#define A5XX_RBBM_SECVID_TSB_COMP_STATUS_HI 0xF805 -#define A5XX_RBBM_SECVID_TSB_UCHE_STATUS_LO 0xF806 -#define A5XX_RBBM_SECVID_TSB_UCHE_STATUS_HI 0xF807 #define A5XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL 0xF810 /* VSC registers */ @@ -614,7 +605,6 @@ #define A5XX_PC_PERFCTR_PC_SEL_7 0xD17 /* HLSQ registers */ -#define A5XX_HLSQ_TIMEOUT_THRESHOLD 0xE00 #define A5XX_HLSQ_ADDR_MODE_CNTL 0xE05 #define A5XX_HLSQ_PERFCTR_HLSQ_SEL_0 0xE10 #define A5XX_HLSQ_PERFCTR_HLSQ_SEL_1 0xE11 @@ -624,7 +614,6 @@ #define A5XX_HLSQ_PERFCTR_HLSQ_SEL_5 0xE15 #define A5XX_HLSQ_PERFCTR_HLSQ_SEL_6 0xE16 #define A5XX_HLSQ_PERFCTR_HLSQ_SEL_7 0xE17 -#define A5XX_HLSQ_SPTP_RDSEL 0xF08 #define A5XX_HLSQ_DBG_READ_SEL 0xBC00 #define A5XX_HLSQ_DBG_AHB_READ_APERTURE 0xA000 @@ -648,7 +637,6 @@ /* UCHE registers */ #define A5XX_UCHE_ADDR_MODE_CNTL 0xE80 -#define A5XX_UCHE_SVM_CNTL 0xE82 #define A5XX_UCHE_WRITE_THRU_BASE_LO 0xE87 #define A5XX_UCHE_WRITE_THRU_BASE_HI 0xE88 #define A5XX_UCHE_TRAP_BASE_LO 0xE89 @@ -721,12 +709,8 @@ #define A5XX_VBIF_CLKON_FORCE_ON_TESTBUS_MASK 0x1 #define A5XX_VBIF_CLKON_FORCE_ON_TESTBUS_SHIFT 0x1 -#define A5XX_VBIF_ABIT_SORT 0x3028 -#define A5XX_VBIF_ABIT_SORT_CONF 0x3029 #define A5XX_VBIF_ROUND_ROBIN_QOS_ARB 0x3049 #define A5XX_VBIF_GATE_OFF_WRREQ_EN 0x302A -#define A5XX_VBIF_IN_RD_LIM_CONF0 0x302C -#define A5XX_VBIF_IN_RD_LIM_CONF1 0x302D #define A5XX_VBIF_XIN_HALT_CTRL0 0x3080 #define A5XX_VBIF_XIN_HALT_CTRL0_MASK 0xF @@ -877,9 +861,7 @@ #define A5XX_GPMU_TEMP_SENSOR_ID 0xAC00 #define A5XX_GPMU_TEMP_SENSOR_CONFIG 0xAC01 -#define A5XX_GPMU_TEMP_VAL 0xAC02 #define A5XX_GPMU_DELTA_TEMP_THRESHOLD 0xAC03 -#define A5XX_GPMU_TEMP_THRESHOLD_INTR_STATUS 0xAC05 #define A5XX_GPMU_TEMP_THRESHOLD_INTR_EN_MASK 0xAC06 #define A5XX_GPMU_LEAKAGE_TEMP_COEFF_0_1 0xAC40 @@ -894,9 +876,9 @@ #define A5XX_GPMU_GPMU_PWR_THRESHOLD 0xAC80 #define A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL 0xACC4 #define A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS 0xACC5 +#define A5XX_GPMU_GPMU_ISENSE_CTRL 0xACD0 #define A5XX_GDPM_CONFIG1 0xB80C -#define A5XX_GDPM_CONFIG2 0xB80D #define A5XX_GDPM_INT_EN 0xB80F #define A5XX_GDPM_INT_MASK 0xB811 #define A5XX_GPMU_BEC_ENABLE 0xB9A0 diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 24c5186340e5..fa981cf575a6 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2437,13 +2437,6 @@ int adreno_rb_readtimestamp(struct adreno_device *adreno_dev, int status = 0; struct adreno_ringbuffer *rb = priv; - /* - * If user passed in a NULL pointer for timestamp, return without - * doing anything. - */ - if (!timestamp) - return status; - if (KGSL_TIMESTAMP_QUEUED == type) *timestamp = rb->timestamp; else @@ -2474,19 +2467,12 @@ static int adreno_readtimestamp(struct kgsl_device *device, { int status = 0; struct kgsl_context *context = priv; - unsigned int id = KGSL_CONTEXT_ID(context); - BUG_ON(NULL == context || id >= KGSL_MEMSTORE_MAX); - /* - * If user passed in a NULL pointer for timestamp, return without - * doing anything. - */ - if (!timestamp) - return status; + if (type == KGSL_TIMESTAMP_QUEUED) { + struct adreno_context *ctxt = ADRENO_CONTEXT(context); - if (KGSL_TIMESTAMP_QUEUED == type) - *timestamp = adreno_context_timestamp(context); - else + *timestamp = ctxt->timestamp; + } else status = __adreno_readtimestamp(ADRENO_DEVICE(device), context->id, type, timestamp); diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 816185e9aad4..b8029178f932 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -55,9 +55,6 @@ /* ADRENO_GPUREV - Return the GPU ID for the given adreno_device */ #define ADRENO_GPUREV(_a) ((_a)->gpucore->gpurev) -/* ADRENO_GPUREV - Return the GPU patchid for the given adreno_device */ -#define ADRENO_PATCHID(_a) ((_a)->gpucore->patchid) - /* * ADRENO_FEATURE - return true if the specified feature is supported by the GPU * core @@ -132,7 +129,6 @@ #define KGSL_CMD_FLAGS_WFI BIT(2) #define KGSL_CMD_FLAGS_PROFILE BIT(3) #define KGSL_CMD_FLAGS_PWRON_FIXUP BIT(4) -#define KGSL_CMD_FLAGS_MEMLIST BIT(5) /* Command identifiers */ #define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF @@ -140,16 +136,10 @@ #define KGSL_CMD_INTERNAL_IDENTIFIER 0x2EEDD00D #define KGSL_START_OF_IB_IDENTIFIER 0x2EADEABE #define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD -#define KGSL_END_OF_FRAME_IDENTIFIER 0x2E0F2E0F -#define KGSL_NOP_IB_IDENTIFIER 0x20F20F20 #define KGSL_START_OF_PROFILE_IDENTIFIER 0x2DEFADE1 #define KGSL_END_OF_PROFILE_IDENTIFIER 0x2DEFADE2 #define KGSL_PWRON_FIXUP_IDENTIFIER 0x2AFAFAFA -#define ADRENO_ISTORE_START 0x5000 /* Istore offset */ - -#define ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW 50 - /* One cannot wait forever for the core to idle, so set an upper limit to the * amount of time to wait for the core to go idle */ @@ -734,11 +724,6 @@ struct adreno_gpudev { void (*pre_reset)(struct adreno_device *); }; -struct log_field { - bool show; - const char *display; -}; - /** * enum kgsl_ft_policy_bits - KGSL fault tolerance policy bits * @KGSL_FT_OFF: Disable fault detection (not used) @@ -983,18 +968,6 @@ static inline int adreno_is_a540v1(struct adreno_device *adreno_dev) return (ADRENO_GPUREV(adreno_dev) == ADRENO_REV_A540) && (ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 0); } -/** - * adreno_context_timestamp() - Return the last queued timestamp for the context - * @k_ctxt: Pointer to the KGSL context to query - * - * Return the last queued context for the given context. This is used to verify - * that incoming requests are not using an invalid (unsubmitted) timestamp - */ -static inline int adreno_context_timestamp(struct kgsl_context *k_ctxt) -{ - struct adreno_context *drawctxt = ADRENO_CONTEXT(k_ctxt); - return drawctxt->timestamp; -} /* * adreno_checkreg_off() - Checks the validity of a register enum diff --git a/drivers/gpu/msm/adreno_a3xx.h b/drivers/gpu/msm/adreno_a3xx.h index 4ab1236020e8..11596b8bf7aa 100644 --- a/drivers/gpu/msm/adreno_a3xx.h +++ b/drivers/gpu/msm/adreno_a3xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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,6 +13,34 @@ #ifndef __A3XX_H #define __A3XX_H +#include "a3xx_reg.h" + +#define A3XX_IRQ_FLAGS \ + { BIT(A3XX_INT_RBBM_GPU_IDLE), "RBBM_GPU_IDLE" }, \ + { BIT(A3XX_INT_RBBM_AHB_ERROR), "RBBM_AHB_ERR" }, \ + { BIT(A3XX_INT_RBBM_REG_TIMEOUT), "RBBM_REG_TIMEOUT" }, \ + { BIT(A3XX_INT_RBBM_ME_MS_TIMEOUT), "RBBM_ME_MS_TIMEOUT" }, \ + { BIT(A3XX_INT_RBBM_PFP_MS_TIMEOUT), "RBBM_PFP_MS_TIMEOUT" }, \ + { BIT(A3XX_INT_RBBM_ATB_BUS_OVERFLOW), "RBBM_ATB_BUS_OVERFLOW" }, \ + { BIT(A3XX_INT_VFD_ERROR), "RBBM_VFD_ERROR" }, \ + { BIT(A3XX_INT_CP_SW_INT), "CP_SW" }, \ + { BIT(A3XX_INT_CP_T0_PACKET_IN_IB), "CP_T0_PACKET_IN_IB" }, \ + { BIT(A3XX_INT_CP_OPCODE_ERROR), "CP_OPCODE_ERROR" }, \ + { BIT(A3XX_INT_CP_RESERVED_BIT_ERROR), "CP_RESERVED_BIT_ERROR" }, \ + { BIT(A3XX_INT_CP_HW_FAULT), "CP_HW_FAULT" }, \ + { BIT(A3XX_INT_CP_DMA), "CP_DMA" }, \ + { BIT(A3XX_INT_CP_IB2_INT), "CP_IB2_INT" }, \ + { BIT(A3XX_INT_CP_IB1_INT), "CP_IB1_INT" }, \ + { BIT(A3XX_INT_CP_RB_INT), "CP_RB_INT" }, \ + { BIT(A3XX_INT_CP_REG_PROTECT_FAULT), "CP_REG_PROTECT_FAULT" }, \ + { BIT(A3XX_INT_CP_RB_DONE_TS), "CP_RB_DONE_TS" }, \ + { BIT(A3XX_INT_CP_VS_DONE_TS), "CP_VS_DONE_TS" }, \ + { BIT(A3XX_INT_CP_PS_DONE_TS), "CP_PS_DONE_TS" }, \ + { BIT(A3XX_INT_CACHE_FLUSH_TS), "CACHE_FLUSH_TS" }, \ + { BIT(A3XX_INT_CP_AHB_ERROR_HALT), "CP_AHB_ERROR_HALT" }, \ + { BIT(A3XX_INT_MISC_HANG_DETECT), "MISC_HANG_DETECT" }, \ + { BIT(A3XX_INT_UCHE_OOB_ACCESS), "UCHE_OOB_ACCESS" } + unsigned int a3xx_irq_pending(struct adreno_device *adreno_dev); int a3xx_microcode_read(struct adreno_device *adreno_dev); diff --git a/drivers/gpu/msm/adreno_a4xx.h b/drivers/gpu/msm/adreno_a4xx.h index 93e54e82a48c..e425dc8e9f7b 100644 --- a/drivers/gpu/msm/adreno_a4xx.h +++ b/drivers/gpu/msm/adreno_a4xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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,39 @@ #ifndef _ADRENO_A4XX_H_ #define _ADRENO_A4XX_H_ +#include "a4xx_reg.h" + +#define A4XX_IRQ_FLAGS \ + { BIT(A4XX_INT_RBBM_GPU_IDLE), "RBBM_GPU_IDLE" }, \ + { BIT(A4XX_INT_RBBM_REG_TIMEOUT), "RBBM_REG_TIMEOUT" }, \ + { BIT(A4XX_INT_RBBM_ME_MS_TIMEOUT), "RBBM_ME_MS_TIMEOUT" }, \ + { BIT(A4XX_INT_RBBM_PFP_MS_TIMEOUT), "RBBM_PFP_MS_TIMEOUT" }, \ + { BIT(A4XX_INT_RBBM_ETS_MS_TIMEOUT), "RBBM_ETS_MS_TIMEOUT" }, \ + { BIT(A4XX_INT_RBBM_ASYNC_OVERFLOW), "RBBM_ASYNC_OVERFLOW" }, \ + { BIT(A4XX_INT_RBBM_GPC_ERR), "RBBM_GPC_ERR" }, \ + { BIT(A4XX_INT_CP_SW), "CP_SW" }, \ + { BIT(A4XX_INT_CP_OPCODE_ERROR), "CP_OPCODE_ERROR" }, \ + { BIT(A4XX_INT_CP_RESERVED_BIT_ERROR), "CP_RESERVED_BIT_ERROR" }, \ + { BIT(A4XX_INT_CP_HW_FAULT), "CP_HW_FAULT" }, \ + { BIT(A4XX_INT_CP_DMA), "CP_DMA" }, \ + { BIT(A4XX_INT_CP_IB2_INT), "CP_IB2_INT" }, \ + { BIT(A4XX_INT_CP_IB1_INT), "CP_IB1_INT" }, \ + { BIT(A4XX_INT_CP_RB_INT), "CP_RB_INT" }, \ + { BIT(A4XX_INT_CP_REG_PROTECT_FAULT), "CP_REG_PROTECT_FAULT" }, \ + { BIT(A4XX_INT_CP_RB_DONE_TS), "CP_RB_DONE_TS" }, \ + { BIT(A4XX_INT_CP_VS_DONE_TS), "CP_VS_DONE_TS" }, \ + { BIT(A4XX_INT_CP_PS_DONE_TS), "CP_PS_DONE_TS" }, \ + { BIT(A4XX_INT_CACHE_FLUSH_TS), "CACHE_FLUSH_TS" }, \ + { BIT(A4XX_INT_CP_AHB_ERROR_HALT), "CP_AHB_ERROR_HALT" }, \ + { BIT(A4XX_INT_RBBM_ATB_BUS_OVERFLOW), "RBBM_ATB_BUS_OVERFLOW" }, \ + { BIT(A4XX_INT_MISC_HANG_DETECT), "MISC_HANG_DETECT" }, \ + { BIT(A4XX_INT_UCHE_OOB_ACCESS), "UCHE_OOB_ACCESS" }, \ + { BIT(A4XX_INT_RBBM_DPM_CALC_ERR), "RBBM_DPM_CALC_ERR" }, \ + { BIT(A4XX_INT_RBBM_DPM_EPOCH_ERR), "RBBM_DPM_CALC_ERR" }, \ + { BIT(A4XX_INT_RBBM_DPM_THERMAL_YELLOW_ERR), \ + "RBBM_DPM_THERMAL_YELLOW_ERR" }, \ + { BIT(A4XX_INT_RBBM_DPM_THERMAL_RED_ERR), "RBBM_DPM_THERMAL_RED_ERR" } + void a4xx_snapshot(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot); diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index f1fc3bdede00..e173dc594789 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -1713,6 +1713,9 @@ static int isense_enable(struct adreno_device *adreno_dev) unsigned int r; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + kgsl_regrmw(device, A5XX_GPMU_GPMU_ISENSE_CTRL, 0, + ISENSE_CGC_EN_DISABLE); + kgsl_regwrite(device, A5XX_GPU_CS_ENABLE_REG, adreno_is_a540v1(adreno_dev) ? 7 : 6); udelay(2); diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h index e41b5b9cce0c..e4b099aa30d1 100644 --- a/drivers/gpu/msm/adreno_a5xx.h +++ b/drivers/gpu/msm/adreno_a5xx.h @@ -14,6 +14,42 @@ #ifndef _ADRENO_A5XX_H_ #define _ADRENO_A5XX_H_ +#include "a5xx_reg.h" + +#define A5XX_IRQ_FLAGS \ + { BIT(A5XX_INT_RBBM_GPU_IDLE), "RBBM_GPU_IDLE" }, \ + { BIT(A5XX_INT_RBBM_AHB_ERROR), "RBBM_AHB_ERR" }, \ + { BIT(A5XX_INT_RBBM_TRANSFER_TIMEOUT), "RBBM_TRANSFER_TIMEOUT" }, \ + { BIT(A5XX_INT_RBBM_ME_MS_TIMEOUT), "RBBM_ME_MS_TIMEOUT" }, \ + { BIT(A5XX_INT_RBBM_PFP_MS_TIMEOUT), "RBBM_PFP_MS_TIMEOUT" }, \ + { BIT(A5XX_INT_RBBM_ETS_MS_TIMEOUT), "RBBM_ETS_MS_TIMEOUT" }, \ + { BIT(A5XX_INT_RBBM_ATB_ASYNC_OVERFLOW), "RBBM_ATB_ASYNC_OVERFLOW" }, \ + { BIT(A5XX_INT_RBBM_GPC_ERROR), "RBBM_GPC_ERR" }, \ + { BIT(A5XX_INT_CP_SW), "CP_SW" }, \ + { BIT(A5XX_INT_CP_HW_ERROR), "CP_OPCODE_ERROR" }, \ + { BIT(A5XX_INT_CP_CCU_FLUSH_DEPTH_TS), "CP_CCU_FLUSH_DEPTH_TS" }, \ + { BIT(A5XX_INT_CP_CCU_FLUSH_COLOR_TS), "CP_CCU_FLUSH_COLOR_TS" }, \ + { BIT(A5XX_INT_CP_CCU_RESOLVE_TS), "CP_CCU_RESOLVE_TS" }, \ + { BIT(A5XX_INT_CP_IB2), "CP_IB2_INT" }, \ + { BIT(A5XX_INT_CP_IB1), "CP_IB1_INT" }, \ + { BIT(A5XX_INT_CP_RB), "CP_RB_INT" }, \ + { BIT(A5XX_INT_CP_UNUSED_1), "CP_UNUSED_1" }, \ + { BIT(A5XX_INT_CP_RB_DONE_TS), "CP_RB_DONE_TS" }, \ + { BIT(A5XX_INT_CP_WT_DONE_TS), "CP_WT_DONE_TS" }, \ + { BIT(A5XX_INT_UNKNOWN_1), "UNKNOWN_1" }, \ + { BIT(A5XX_INT_CP_CACHE_FLUSH_TS), "CP_CACHE_FLUSH_TS" }, \ + { BIT(A5XX_INT_UNUSED_2), "UNUSED_2" }, \ + { BIT(A5XX_INT_RBBM_ATB_BUS_OVERFLOW), "RBBM_ATB_BUS_OVERFLOW" }, \ + { BIT(A5XX_INT_MISC_HANG_DETECT), "MISC_HANG_DETECT" }, \ + { BIT(A5XX_INT_UCHE_OOB_ACCESS), "UCHE_OOB_ACCESS" }, \ + { BIT(A5XX_INT_UCHE_TRAP_INTR), "UCHE_TRAP_INTR" }, \ + { BIT(A5XX_INT_DEBBUS_INTR_0), "DEBBUS_INTR_0" }, \ + { BIT(A5XX_INT_DEBBUS_INTR_1), "DEBBUS_INTR_1" }, \ + { BIT(A5XX_INT_GPMU_VOLTAGE_DROOP), "GPMU_VOLTAGE_DROOP" }, \ + { BIT(A5XX_INT_GPMU_FIRMWARE), "GPMU_FIRMWARE" }, \ + { BIT(A5XX_INT_ISDB_CPU_IRQ), "ISDB_CPU_IRQ" }, \ + { BIT(A5XX_INT_ISDB_UNDER_DEBUG), "ISDB_UNDER_DEBUG" } + #define A5XX_CP_CTXRECORD_MAGIC_REF 0x27C4BAFCUL /* Size of each CP preemption record */ #define A5XX_CP_CTXRECORD_SIZE_IN_BYTES 0x100000 @@ -97,16 +133,19 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); /* A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL */ #define STATE_OF_CHILD GENMASK(5, 4) #define STATE_OF_CHILD_01 BIT(4) +#define STATE_OF_CHILD_11 (BIT(4) | BIT(5)) #define IDLE_FULL_LM_SLEEP BIT(0) /* A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS */ #define WAKEUP_ACK BIT(1) #define IDLE_FULL_ACK BIT(0) +/* A5XX_GPMU_GPMU_ISENSE_CTRL */ +#define ISENSE_CGC_EN_DISABLE BIT(0) + /* A5XX_GPMU_TEMP_SENSOR_CONFIG */ #define GPMU_BCL_ENABLED BIT(4) #define GPMU_LLM_ENABLED BIT(9) -#define GPMU_LMH_ENABLED BIT(8) #define GPMU_ISENSE_STATUS GENMASK(3, 0) #define GPMU_ISENSE_END_POINT_CAL_ERR BIT(0) @@ -119,7 +158,6 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); /* A5XX_GPU_CS_AMP_CALIBRATION_STATUS*_* */ #define AMP_OUT_OF_RANGE_ERR BIT(4) -#define AMP_CHECK_TIMEOUT_ERR BIT(3) #define AMP_OFFSET_CHECK_MAX_ERR BIT(2) #define AMP_OFFSET_CHECK_MIN_ERR BIT(1) @@ -139,20 +177,12 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); #define PWR_THRESHOLD_VALID 0x80000000 /* AGC */ #define AGC_INIT_BASE A5XX_GPMU_DATA_RAM_BASE -#define AGC_RVOUS_MAGIC (AGC_INIT_BASE + 0) -#define AGC_KMD_GPMU_ADDR (AGC_INIT_BASE + 1) -#define AGC_KMD_GPMU_BYTES (AGC_INIT_BASE + 2) -#define AGC_GPMU_KMD_ADDR (AGC_INIT_BASE + 3) -#define AGC_GPMU_KMD_BYTES (AGC_INIT_BASE + 4) #define AGC_INIT_MSG_MAGIC (AGC_INIT_BASE + 5) -#define AGC_RESERVED (AGC_INIT_BASE + 6) #define AGC_MSG_BASE (AGC_INIT_BASE + 7) #define AGC_MSG_STATE (AGC_MSG_BASE + 0) #define AGC_MSG_COMMAND (AGC_MSG_BASE + 1) -#define AGC_MSG_RETURN (AGC_MSG_BASE + 2) #define AGC_MSG_PAYLOAD_SIZE (AGC_MSG_BASE + 3) -#define AGC_MSG_MAX_RETURN_SIZE (AGC_MSG_BASE + 4) #define AGC_MSG_PAYLOAD (AGC_MSG_BASE + 5) #define AGC_INIT_MSG_VALUE 0xBABEFACE @@ -160,14 +190,9 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); #define AGC_LM_CONFIG (136/4) #define AGC_LM_CONFIG_ENABLE_GPMU_ADAPTIVE (1) -#define AGC_LM_CONFIG_ENABLE_GPMU_LEGACY (2) -#define AGC_LM_CONFIG_ENABLE_GPMU_LLM (3) -#define AGC_LM_CONFIG_ENABLE_ISENSE (1 << 4) -#define AGC_LM_CONFIG_ENABLE_DPM (2 << 4) #define AGC_LM_CONFIG_ENABLE_ERROR (3 << 4) -#define AGC_THROTTLE_SEL_CRC (0 << 8) #define AGC_THROTTLE_SEL_DCS (1 << 8) #define AGC_LLM_ENABLED (1 << 16) @@ -177,12 +202,9 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); #define AGC_LEVEL_CONFIG (140/4) -#define AGC_LEVEL_CONFIG_SENSOR_DISABLE GENMASK(15, 0) -#define AGC_LEVEL_CONFIG_LMDISABLE GENMASK(31, 16) #define LM_DCVS_LIMIT 2 /* FW file tages */ -#define GPMU_HEADER_ID 1 #define GPMU_FIRMWARE_ID 2 #define GPMU_SEQUENCE_ID 3 #define GPMU_INST_RAM_SIZE 0xFFF @@ -196,7 +218,6 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); #define MAX_HEADER_SIZE 10 #define LM_SEQUENCE_ID 1 -#define HWCG_SEQUENCE_ID 2 #define MAX_SEQUENCE_ID 3 /* LM defaults */ diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c index 3d1f81fb01f7..154f5af99ffe 100644 --- a/drivers/gpu/msm/adreno_a5xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c @@ -783,6 +783,33 @@ static size_t a5xx_snapshot_registers(struct kgsl_device *device, u8 *buf, return (header->count * 8) + sizeof(*header); } +/* Snapshot a preemption record buffer */ +static size_t snapshot_preemption_record(struct kgsl_device *device, u8 *buf, + size_t remain, void *priv) +{ + struct kgsl_memdesc *memdesc = priv; + + struct kgsl_snapshot_gpu_object_v2 *header = + (struct kgsl_snapshot_gpu_object_v2 *)buf; + + u8 *ptr = buf + sizeof(*header); + + if (remain < (SZ_64K + sizeof(*header))) { + SNAPSHOT_ERR_NOMEM(device, "PREEMPTION RECORD"); + return 0; + } + + header->size = SZ_64K >> 2; + header->gpuaddr = memdesc->gpuaddr; + header->ptbase = + kgsl_mmu_pagetable_get_ttbr0(device->mmu.defaultpagetable); + header->type = SNAPSHOT_GPU_OBJECT_GLOBAL; + + memcpy(ptr, memdesc->hostptr, SZ_64K); + + return SZ_64K + sizeof(*header); +} + /* * a5xx_snapshot() - A5XX GPU snapshot function * @adreno_dev: Device being snapshotted @@ -797,7 +824,8 @@ void a5xx_snapshot(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_snapshot_data *snap_data = gpudev->snapshot_data; - unsigned int reg; + unsigned int reg, i; + struct adreno_ringbuffer *rb; /* Disable Clock gating temporarily for the debug bus to work */ a5xx_hwcg_set(adreno_dev, false); @@ -874,6 +902,15 @@ void a5xx_snapshot(struct adreno_device *adreno_dev, /* Debug bus */ a5xx_snapshot_debugbus(device, snapshot); + + /* Preemption record */ + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + kgsl_snapshot_add_section(device, + KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, + snapshot, snapshot_preemption_record, + &rb->preemption_desc); + } + } void a5xx_crashdump_init(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c index 9825797039cc..02a39278ccb3 100644 --- a/drivers/gpu/msm/adreno_coresight.c +++ b/drivers/gpu/msm/adreno_coresight.c @@ -313,8 +313,9 @@ int adreno_coresight_init(struct adreno_device *adreno_dev) desc.pdata = of_get_coresight_platform_data(&device->pdev->dev, device->pdev->dev.of_node); - if (desc.pdata == NULL) - return -ENODEV; + if (IS_ERR_OR_NULL(desc.pdata)) + return (desc.pdata == NULL) ? -ENODEV : + PTR_ERR(desc.pdata); desc.type = CORESIGHT_DEV_TYPE_SOURCE; desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS; diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 19928686eaf2..3f36a93ea110 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -2579,12 +2579,11 @@ void adreno_dispatcher_preempt_callback(struct adreno_device *adreno_dev, int bit) { struct adreno_dispatcher *dispatcher = &(adreno_dev->dispatcher); + if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED != - atomic_read(&dispatcher->preemption_state)) { - KGSL_DRV_CRIT_RATELIMIT(KGSL_DEVICE(adreno_dev), - "Preemption interrupt generated w/o trigger!\n"); + atomic_read(&dispatcher->preemption_state)) return; - } + trace_adreno_hw_preempt_trig_to_comp_int(adreno_dev->cur_rb, adreno_dev->next_rb); atomic_set(&dispatcher->preemption_state, diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index cef4bb4db3a0..d8498d938b6a 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -21,8 +21,6 @@ #include "adreno.h" #include "adreno_trace.h" -#define KGSL_INIT_REFTIMESTAMP 0x7FFFFFFF - static void wait_callback(struct kgsl_device *device, struct kgsl_event_group *group, void *priv, int result) { diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h index 09683b1bb2ba..7e80247e9322 100644 --- a/drivers/gpu/msm/adreno_drawctxt.h +++ b/drivers/gpu/msm/adreno_drawctxt.h @@ -83,9 +83,6 @@ struct adreno_context { /* Flag definitions for flag field in adreno_context */ -/* Set when sync timer of cmdbatch belonging to the context times out */ -#define ADRENO_CONTEXT_CMDBATCH_FLAG_FENCE_LOG BIT(0) - /** * enum adreno_context_priv - Private flags for an adreno draw context * @ADRENO_CONTEXT_FAULT - set if the context has faulted (and recovered) diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c index 1779e8e7c0b7..96922972200f 100644 --- a/drivers/gpu/msm/adreno_perfcounter.c +++ b/drivers/gpu/msm/adreno_perfcounter.c @@ -27,13 +27,9 @@ #define VBIF2_PERF_CLR_REG_SEL_OFF 8 /* offset of enable register from select register */ #define VBIF2_PERF_EN_REG_SEL_OFF 16 -/* offset of high counter from low counter value */ -#define VBIF2_PERF_HIGH_REG_LOW_OFF 8 /* offset of clear register from the enable register */ #define VBIF2_PERF_PWR_CLR_REG_EN_OFF 8 -/* offset of high counter from low counter value */ -#define VBIF2_PERF_PWR_HIGH_REG_LOW_OFF 8 #define REG_64BIT_VAL(hi, lo, val) (((((uint64_t) hi) << 32) | lo) + val) /* diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h index f81c0f20e10b..ec2c29b929c1 100644 --- a/drivers/gpu/msm/adreno_pm4types.h +++ b/drivers/gpu/msm/adreno_pm4types.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,8 +15,6 @@ #include "adreno.h" -#define CP_PKT_MASK 0xc0000000 - #define CP_TYPE0_PKT ((unsigned int)0 << 30) #define CP_TYPE3_PKT ((unsigned int)3 << 30) #define CP_TYPE4_PKT ((unsigned int)4 << 28) @@ -32,21 +30,10 @@ #define CP_PREEMPT_TOKEN 0x1E /* Bit to set in CP_PREEMPT_TOKEN ordinal for interrupt on preemption */ #define CP_PREEMPT_ORDINAL_INTERRUPT 24 -/* copy from ME scratch RAM to a register */ -#define CP_SCRATCH_TO_REG 0x4d - -/* Copy from REG to ME scratch RAM */ -#define CP_REG_TO_SCRATCH 0x4a /* Wait for memory writes to complete */ #define CP_WAIT_MEM_WRITES 0x12 -/* Conditional execution based on register comparison */ -#define CP_COND_REG_EXEC 0x47 - -/* Memory to REG copy */ -#define CP_MEM_TO_REG 0x42 - /* initialize CP's micro-engine */ #define CP_ME_INIT 0x48 @@ -68,12 +55,6 @@ /* switches SMMU pagetable, used on a5xx only */ #define CP_SMMU_TABLE_UPDATE 0x53 -/* wait until a read completes */ -#define CP_WAIT_UNTIL_READ 0x5c - -/* wait until all base/size writes from an IB_PFD packet have completed */ -#define CP_WAIT_IB_PFD_COMPLETE 0x5d - /* register read/modify/write */ #define CP_REG_RMW 0x21 @@ -86,9 +67,6 @@ /* write N 32-bit words to memory */ #define CP_MEM_WRITE 0x3d -/* write CP_PROG_COUNTER value to memory */ -#define CP_MEM_WRITE_CNTR 0x4f - /* conditional execution of a sequence of packets */ #define CP_COND_EXEC 0x44 @@ -98,69 +76,21 @@ /* generate an event that creates a write to memory when completed */ #define CP_EVENT_WRITE 0x46 -/* generate a VS|PS_done event */ -#define CP_EVENT_WRITE_SHD 0x58 - -/* generate a cache flush done event */ -#define CP_EVENT_WRITE_CFL 0x59 - -/* generate a z_pass done event */ -#define CP_EVENT_WRITE_ZPD 0x5b - - /* initiate fetch of index buffer and draw */ #define CP_DRAW_INDX 0x22 -/* draw using supplied indices in packet */ -#define CP_DRAW_INDX_2 0x36 - -/* initiate fetch of index buffer and binIDs and draw */ -#define CP_DRAW_INDX_BIN 0x34 - -/* initiate fetch of bin IDs and draw using supplied indices */ -#define CP_DRAW_INDX_2_BIN 0x35 - /* New draw packets defined for A4XX */ #define CP_DRAW_INDX_OFFSET 0x38 #define CP_DRAW_INDIRECT 0x28 #define CP_DRAW_INDX_INDIRECT 0x29 #define CP_DRAW_AUTO 0x24 -/* begin/end initiator for viz query extent processing */ -#define CP_VIZ_QUERY 0x23 - -/* fetch state sub-blocks and initiate shader code DMAs */ -#define CP_SET_STATE 0x25 - /* load constant into chip and to memory */ #define CP_SET_CONSTANT 0x2d -/* load sequencer instruction memory (pointer-based) */ -#define CP_IM_LOAD 0x27 - -/* load sequencer instruction memory (code embedded in packet) */ -#define CP_IM_LOAD_IMMEDIATE 0x2b - -/* load constants from a location in memory */ -#define CP_LOAD_CONSTANT_CONTEXT 0x2e - /* selective invalidation of state pointers */ #define CP_INVALIDATE_STATE 0x3b - -/* dynamically changes shader instruction memory partition */ -#define CP_SET_SHADER_BASES 0x4A - -/* sets the 64-bit BIN_MASK register in the PFP */ -#define CP_SET_BIN_MASK 0x50 - -/* sets the 64-bit BIN_SELECT register in the PFP */ -#define CP_SET_BIN_SELECT 0x51 - - -/* updates the current context, if needed */ -#define CP_CONTEXT_UPDATE 0x5e - /* generate interrupt from the command stream */ #define CP_INTERRUPT 0x40 @@ -179,12 +109,6 @@ /* Inform CP about current render mode (needed for a5xx preemption) */ #define CP_SET_RENDER_MODE 0x6C -/* copy sequencer instruction memory to system memory */ -#define CP_IM_STORE 0x2c - -/* test 2 memory locations to dword values specified */ -#define CP_TEST_TWO_MEMS 0x71 - /* Write register, ignoring context state for context sensitive registers */ #define CP_REG_WR_NO_CTXT 0x78 @@ -198,9 +122,6 @@ /* PFP waits until the FIFO between the PFP and the ME is empty */ #define CP_WAIT_FOR_ME 0x13 -/* Record the real-time when this packet is processed by PFP */ -#define CP_RECORD_PFP_TIMESTAMP 0x11 - #define CP_SET_PROTECTED_MODE 0x5f /* sets the register protection mode */ /* Used to switch GPU between secure and non-secure modes */ diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index e433a2f275e2..f1980fd92961 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -105,7 +105,6 @@ struct adreno_ringbuffer_pagetable_info { struct adreno_ringbuffer { uint32_t flags; struct kgsl_memdesc buffer_desc; - unsigned int sizedwords; unsigned int wptr; unsigned int rptr; unsigned int last_wptr; @@ -125,16 +124,6 @@ struct adreno_ringbuffer { enum adreno_dispatcher_starve_timer_states starve_timer_state; }; -/* enable timestamp (...scratch0) memory shadowing */ -#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1 - -/* - * protected mode error checking below register address 0x800 - * note: if CP_INTERRUPT packet is used then checking needs - * to change to below register address 0x7C8 - */ -#define GSL_RB_PROTECTED_MODE_CONTROL 0x200001F2 - /* Returns the current ringbuffer */ #define ADRENO_CURRENT_RINGBUFFER(a) ((a)->cur_rb) diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index f9834b973a4e..ca61d36a1384 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -21,9 +21,6 @@ #include "adreno_snapshot.h" #include "adreno_a5xx.h" -/* Number of dwords of ringbuffer history to record */ -#define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100 - #define VPC_MEMORY_BANKS 4 /* Maintain a list of the objects we see during parsing */ @@ -753,46 +750,6 @@ static size_t snapshot_global(struct kgsl_device *device, u8 *buf, return memdesc->size + sizeof(*header); } -/* Snapshot a preemption record buffer */ -static size_t snapshot_preemption_record(struct kgsl_device *device, u8 *buf, - size_t remain, void *priv) -{ - struct kgsl_memdesc *memdesc = priv; - struct a5xx_cp_preemption_record record; - int size = sizeof(record); - - struct kgsl_snapshot_gpu_object_v2 *header = - (struct kgsl_snapshot_gpu_object_v2 *)buf; - - u8 *ptr = buf + sizeof(*header); - - if (size == 0) - return 0; - - if (remain < (size + sizeof(*header))) { - KGSL_CORE_ERR( - "snapshot: Not enough memory for preemption record\n"); - return 0; - } - - if (memdesc->hostptr == NULL) { - KGSL_CORE_ERR( - "snapshot: no kernel mapping for preemption record 0x%016llX\n", - memdesc->gpuaddr); - return 0; - } - - header->size = size >> 2; - header->gpuaddr = memdesc->gpuaddr; - header->ptbase = - kgsl_mmu_pagetable_get_ttbr0(device->mmu.defaultpagetable); - header->type = SNAPSHOT_GPU_OBJECT_GLOBAL; - - memcpy(ptr, memdesc->hostptr, size); - - return size + sizeof(*header); -} - /* Snapshot IOMMU specific buffers */ static void adreno_snapshot_iommu(struct kgsl_device *device, struct kgsl_snapshot *snapshot) @@ -840,7 +797,6 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot, unsigned int ib1size, ib2size; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - struct adreno_ringbuffer *rb; ib_max_objs = 0; /* Reset the list of objects */ @@ -885,15 +841,6 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot, if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_IOMMU) adreno_snapshot_iommu(device, snapshot); - if (ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) { - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, - snapshot, snapshot_preemption_record, - &rb->preemption_desc); - } - } - /* * Add a section that lists (gpuaddr, size, memtype) tuples of the * hanging process diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h index c0926cbb6a85..5f1bbb9a83b3 100644 --- a/drivers/gpu/msm/adreno_trace.h +++ b/drivers/gpu/msm/adreno_trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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,6 +22,9 @@ #define TRACE_INCLUDE_FILE adreno_trace #include <linux/tracepoint.h> +#include "adreno_a3xx.h" +#include "adreno_a4xx.h" +#include "adreno_a5xx.h" TRACE_EVENT(adreno_cmdbatch_queued, TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int queued), @@ -364,38 +367,7 @@ TRACE_EVENT(kgsl_a3xx_irq_status, "d_name=%s status=%s", __get_str(device_name), __entry->status ? __print_flags(__entry->status, "|", - { 1 << A3XX_INT_RBBM_GPU_IDLE, "RBBM_GPU_IDLE" }, - { 1 << A3XX_INT_RBBM_AHB_ERROR, "RBBM_AHB_ERR" }, - { 1 << A3XX_INT_RBBM_REG_TIMEOUT, "RBBM_REG_TIMEOUT" }, - { 1 << A3XX_INT_RBBM_ME_MS_TIMEOUT, - "RBBM_ME_MS_TIMEOUT" }, - { 1 << A3XX_INT_RBBM_PFP_MS_TIMEOUT, - "RBBM_PFP_MS_TIMEOUT" }, - { 1 << A3XX_INT_RBBM_ATB_BUS_OVERFLOW, - "RBBM_ATB_BUS_OVERFLOW" }, - { 1 << A3XX_INT_VFD_ERROR, "RBBM_VFD_ERROR" }, - { 1 << A3XX_INT_CP_SW_INT, "CP_SW" }, - { 1 << A3XX_INT_CP_T0_PACKET_IN_IB, - "CP_T0_PACKET_IN_IB" }, - { 1 << A3XX_INT_CP_OPCODE_ERROR, "CP_OPCODE_ERROR" }, - { 1 << A3XX_INT_CP_RESERVED_BIT_ERROR, - "CP_RESERVED_BIT_ERROR" }, - { 1 << A3XX_INT_CP_HW_FAULT, "CP_HW_FAULT" }, - { 1 << A3XX_INT_CP_DMA, "CP_DMA" }, - { 1 << A3XX_INT_CP_IB2_INT, "CP_IB2_INT" }, - { 1 << A3XX_INT_CP_IB1_INT, "CP_IB1_INT" }, - { 1 << A3XX_INT_CP_RB_INT, "CP_RB_INT" }, - { 1 << A3XX_INT_CP_REG_PROTECT_FAULT, - "CP_REG_PROTECT_FAULT" }, - { 1 << A3XX_INT_CP_RB_DONE_TS, "CP_RB_DONE_TS" }, - { 1 << A3XX_INT_CP_VS_DONE_TS, "CP_VS_DONE_TS" }, - { 1 << A3XX_INT_CP_PS_DONE_TS, "CP_PS_DONE_TS" }, - { 1 << A3XX_INT_CACHE_FLUSH_TS, "CACHE_FLUSH_TS" }, - { 1 << A3XX_INT_CP_AHB_ERROR_HALT, - "CP_AHB_ERROR_HALT" }, - { 1 << A3XX_INT_MISC_HANG_DETECT, "MISC_HANG_DETECT" }, - { 1 << A3XX_INT_UCHE_OOB_ACCESS, "UCHE_OOB_ACCESS" }) - : "None" + A3XX_IRQ_FLAGS) : "None" ) ); @@ -422,49 +394,34 @@ TRACE_EVENT(kgsl_a4xx_irq_status, "d_name=%s status=%s", __get_str(device_name), __entry->status ? __print_flags(__entry->status, "|", - { 1 << A4XX_INT_RBBM_GPU_IDLE, "RBBM_GPU_IDLE" }, - { 1 << A4XX_INT_RBBM_AHB_ERROR, "RBBM_AHB_ERR" }, - { 1 << A4XX_INT_RBBM_REG_TIMEOUT, "RBBM_REG_TIMEOUT" }, - { 1 << A4XX_INT_RBBM_ME_MS_TIMEOUT, - "RBBM_ME_MS_TIMEOUT" }, - { 1 << A4XX_INT_RBBM_PFP_MS_TIMEOUT, - "RBBM_PFP_MS_TIMEOUT" }, - { 1 << A4XX_INT_RBBM_ETS_MS_TIMEOUT, - "RBBM_ETS_MS_TIMEOUT" }, - { 1 << A4XX_INT_RBBM_ASYNC_OVERFLOW, - "RBBM_ASYNC_OVERFLOW" }, - { 1 << A4XX_INT_RBBM_GPC_ERR, - "RBBM_GPC_ERR" }, - { 1 << A4XX_INT_CP_SW, "CP_SW" }, - { 1 << A4XX_INT_CP_OPCODE_ERROR, "CP_OPCODE_ERROR" }, - { 1 << A4XX_INT_CP_RESERVED_BIT_ERROR, - "CP_RESERVED_BIT_ERROR" }, - { 1 << A4XX_INT_CP_HW_FAULT, "CP_HW_FAULT" }, - { 1 << A4XX_INT_CP_DMA, "CP_DMA" }, - { 1 << A4XX_INT_CP_IB2_INT, "CP_IB2_INT" }, - { 1 << A4XX_INT_CP_IB1_INT, "CP_IB1_INT" }, - { 1 << A4XX_INT_CP_RB_INT, "CP_RB_INT" }, - { 1 << A4XX_INT_CP_REG_PROTECT_FAULT, - "CP_REG_PROTECT_FAULT" }, - { 1 << A4XX_INT_CP_RB_DONE_TS, "CP_RB_DONE_TS" }, - { 1 << A4XX_INT_CP_VS_DONE_TS, "CP_VS_DONE_TS" }, - { 1 << A4XX_INT_CP_PS_DONE_TS, "CP_PS_DONE_TS" }, - { 1 << A4XX_INT_CACHE_FLUSH_TS, "CACHE_FLUSH_TS" }, - { 1 << A4XX_INT_CP_AHB_ERROR_HALT, - "CP_AHB_ERROR_HALT" }, - { 1 << A4XX_INT_RBBM_ATB_BUS_OVERFLOW, - "RBBM_ATB_BUS_OVERFLOW" }, - { 1 << A4XX_INT_MISC_HANG_DETECT, "MISC_HANG_DETECT" }, - { 1 << A4XX_INT_UCHE_OOB_ACCESS, "UCHE_OOB_ACCESS" }, - { 1 << A4XX_INT_RBBM_DPM_CALC_ERR, - "RBBM_DPM_CALC_ERR" }, - { 1 << A4XX_INT_RBBM_DPM_EPOCH_ERR, - "RBBM_DPM_CALC_ERR" }, - { 1 << A4XX_INT_RBBM_DPM_THERMAL_YELLOW_ERR, - "RBBM_DPM_THERMAL_YELLOW_ERR" }, - { 1 << A4XX_INT_RBBM_DPM_THERMAL_RED_ERR, - "RBBM_DPM_THERMAL_RED_ERR" }) - : "None" + A4XX_IRQ_FLAGS) : "None" + ) +); + +/* + * Tracepoint for a5xx irq. Includes status info + */ +TRACE_EVENT(kgsl_a5xx_irq_status, + + TP_PROTO(struct adreno_device *adreno_dev, unsigned int status), + + TP_ARGS(adreno_dev, status), + + TP_STRUCT__entry( + __string(device_name, adreno_dev->dev.name) + __field(unsigned int, status) + ), + + TP_fast_assign( + __assign_str(device_name, adreno_dev->dev.name); + __entry->status = status; + ), + + TP_printk( + "d_name=%s status=%s", + __get_str(device_name), + __entry->status ? __print_flags(__entry->status, "|", + A5XX_IRQ_FLAGS) : "None" ) ); @@ -601,86 +558,6 @@ TRACE_EVENT(adreno_rb_starve, ) ); -/* - * Tracepoint for a5xx irq. Includes status info - */ -TRACE_EVENT(kgsl_a5xx_irq_status, - - TP_PROTO(struct adreno_device *adreno_dev, unsigned int status), - - TP_ARGS(adreno_dev, status), - - TP_STRUCT__entry( - __string(device_name, adreno_dev->dev.name) - __field(unsigned int, status) - ), - - TP_fast_assign( - __assign_str(device_name, adreno_dev->dev.name); - __entry->status = status; - ), - - TP_printk( - "d_name=%s status=%s", - __get_str(device_name), - __entry->status ? __print_flags(__entry->status, "|", - { 1 << A5XX_INT_RBBM_GPU_IDLE, "RBBM_GPU_IDLE" }, - { 1 << A5XX_INT_RBBM_AHB_ERROR, "RBBM_AHB_ERR" }, - { 1 << A5XX_INT_RBBM_TRANSFER_TIMEOUT, - "RBBM_TRANSFER_TIMEOUT" }, - { 1 << A5XX_INT_RBBM_ME_MS_TIMEOUT, - "RBBM_ME_MS_TIMEOUT" }, - { 1 << A5XX_INT_RBBM_PFP_MS_TIMEOUT, - "RBBM_PFP_MS_TIMEOUT" }, - { 1 << A5XX_INT_RBBM_ETS_MS_TIMEOUT, - "RBBM_ETS_MS_TIMEOUT" }, - { 1 << A5XX_INT_RBBM_ATB_ASYNC_OVERFLOW, - "RBBM_ATB_ASYNC_OVERFLOW" }, - { 1 << A5XX_INT_RBBM_GPC_ERROR, - "RBBM_GPC_ERR" }, - { 1 << A5XX_INT_CP_SW, "CP_SW" }, - { 1 << A5XX_INT_CP_HW_ERROR, "CP_OPCODE_ERROR" }, - { 1 << A5XX_INT_CP_CCU_FLUSH_DEPTH_TS, - "CP_CCU_FLUSH_DEPTH_TS" }, - { 1 << A5XX_INT_CP_CCU_FLUSH_COLOR_TS, - "CP_CCU_FLUSH_COLOR_TS" }, - { 1 << A5XX_INT_CP_CCU_RESOLVE_TS, - "CP_CCU_RESOLVE_TS" }, - { 1 << A5XX_INT_CP_IB2, "CP_IB2_INT" }, - { 1 << A5XX_INT_CP_IB1, "CP_IB1_INT" }, - { 1 << A5XX_INT_CP_RB, "CP_RB_INT" }, - { 1 << A5XX_INT_CP_UNUSED_1, "CP_UNUSED_1" }, - { 1 << A5XX_INT_CP_RB_DONE_TS, "CP_RB_DONE_TS" }, - { 1 << A5XX_INT_CP_WT_DONE_TS, "CP_WT_DONE_TS" }, - { 1 << A5XX_INT_UNKNOWN_1, "UNKNOWN_1" }, - { 1 << A5XX_INT_CP_CACHE_FLUSH_TS, - "CP_CACHE_FLUSH_TS" }, - { 1 << A5XX_INT_UNUSED_2, - "UNUSED_2" }, - { 1 << A5XX_INT_RBBM_ATB_BUS_OVERFLOW, - "RBBM_ATB_BUS_OVERFLOW" }, - { 1 << A5XX_INT_MISC_HANG_DETECT, - "MISC_HANG_DETECT" }, - { 1 << A5XX_INT_UCHE_OOB_ACCESS, - "UCHE_OOB_ACCESS" }, - { 1 << A5XX_INT_UCHE_TRAP_INTR, - "UCHE_TRAP_INTR" }, - { 1 << A5XX_INT_DEBBUS_INTR_0, - "DEBBUS_INTR_0" }, - { 1 << A5XX_INT_DEBBUS_INTR_1, - "DEBBUS_INTR_1" }, - { 1 << A5XX_INT_GPMU_VOLTAGE_DROOP, - "GPMU_VOLTAGE_DROOP" }, - { 1 << A5XX_INT_GPMU_FIRMWARE, - "GPMU_FIRMWARE" }, - { 1 << A5XX_INT_ISDB_CPU_IRQ, - "ISDB_CPU_IRQ" }, - { 1 << A5XX_INT_ISDB_UNDER_DEBUG, - "ISDB_UNDER_DEBUG" }) - : "None" - ) -); - #endif /* _ADRENO_TRACE_H */ /* This part must be outside protection */ diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 77494ebb2c92..51dc781b2bd4 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -41,6 +41,7 @@ #include "kgsl_trace.h" #include "kgsl_sync.h" #include "kgsl_compat.h" +#include "kgsl_pool.h" #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "kgsl." @@ -1785,12 +1786,8 @@ long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv, long ret; entry = kgsl_sharedmem_find(private, (uint64_t) param->gpuaddr); - if (entry == NULL) { - KGSL_MEM_INFO(dev_priv->device, - "Invalid GPU address 0x%016llx\n", - (uint64_t) param->gpuaddr); + if (entry == NULL) return -EINVAL; - } ret = gpumem_free_entry(entry); kgsl_mem_entry_put(entry); @@ -1807,11 +1804,8 @@ long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv, long ret; entry = kgsl_sharedmem_find_id(private, param->id); - if (entry == NULL) { - KGSL_MEM_INFO(dev_priv->device, - "Invalid GPU memory object ID %d\n", param->id); + if (entry == NULL) return -EINVAL; - } ret = gpumem_free_entry(entry); kgsl_mem_entry_put(entry); @@ -1900,11 +1894,8 @@ long kgsl_ioctl_gpuobj_free(struct kgsl_device_private *dev_priv, long ret; entry = kgsl_sharedmem_find_id(private, param->id); - if (entry == NULL) { - KGSL_MEM_ERR(dev_priv->device, - "Invalid GPU memory object ID %d\n", param->id); + if (entry == NULL) return -EINVAL; - } /* If no event is specified then free immediately */ if (!(param->flags & KGSL_GPUOBJ_FREE_ON_EVENT)) @@ -1939,17 +1930,14 @@ long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid( entry = kgsl_sharedmem_find(dev_priv->process_priv, (uint64_t) param->gpuaddr); if (entry == NULL) { - KGSL_MEM_ERR(dev_priv->device, - "Invalid GPU address 0x%016llx\n", - (uint64_t) param->gpuaddr); - goto out; + kgsl_context_put(context); + return -EINVAL; } ret = gpumem_free_entry_on_timestamp(dev_priv->device, entry, context, param->timestamp); kgsl_mem_entry_put(entry); -out: kgsl_context_put(context); return ret; @@ -2553,7 +2541,6 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, private->pagetable, entry, param->fd); break; default: - KGSL_CORE_ERR("Invalid memory type: %x\n", memtype); result = -EOPNOTSUPP; break; } @@ -2563,10 +2550,6 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, if ((param->flags & KGSL_MEMFLAGS_SECURE) && (entry->memdesc.size & mmu->secure_align_mask)) { - KGSL_DRV_ERR(dev_priv->device, - "Secure buffer size %lld not aligned to %x alignment", - entry->memdesc.size, - mmu->secure_align_mask + 1); result = -EINVAL; goto error_attach; } @@ -2668,24 +2651,13 @@ long kgsl_ioctl_gpumem_sync_cache(struct kgsl_device_private *dev_priv, struct kgsl_mem_entry *entry = NULL; long ret; - if (param->id != 0) { + if (param->id != 0) entry = kgsl_sharedmem_find_id(private, param->id); - if (entry == NULL) { - KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n", - param->id); - return -EINVAL; - } - } else if (param->gpuaddr != 0) { + else if (param->gpuaddr != 0) entry = kgsl_sharedmem_find(private, (uint64_t) param->gpuaddr); - if (entry == NULL) { - KGSL_MEM_INFO(dev_priv->device, - "can't find gpuaddr 0x%08lX\n", - param->gpuaddr); - return -EINVAL; - } - } else { + + if (entry == NULL) return -EINVAL; - } ret = _kgsl_gpumem_sync_cache(entry, (uint64_t) param->offset, (uint64_t) param->length, param->op); @@ -2813,12 +2785,8 @@ long kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv, long ret; entry = kgsl_sharedmem_find(private, (uint64_t) param->gpuaddr); - if (entry == NULL) { - KGSL_MEM_INFO(dev_priv->device, - "can't find gpuaddr 0x%08lX\n", - param->gpuaddr); + if (entry == NULL) return -EINVAL; - } ret = _kgsl_gpumem_sync_cache(entry, 0, entry->memdesc.size, KGSL_GPUMEM_CACHE_FLUSH); @@ -3106,15 +3074,12 @@ long kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv, struct kgsl_mem_entry *entry = NULL; int result = 0; - if (param->id != 0) { + if (param->id != 0) entry = kgsl_sharedmem_find_id(private, param->id); - if (entry == NULL) - return -EINVAL; - } else if (param->gpuaddr != 0) { + else if (param->gpuaddr != 0) entry = kgsl_sharedmem_find(private, (uint64_t) param->gpuaddr); - if (entry == NULL) - return -EINVAL; - } else + + if (entry == NULL) return -EINVAL; /* @@ -3979,6 +3944,9 @@ int kgsl_device_platform_probe(struct kgsl_device *device) /* Initialize common sysfs entries */ kgsl_pwrctrl_init_sysfs(device); + /* Initialize the memory pools */ + kgsl_init_page_pools(); + return 0; error_close_mmu: @@ -3997,6 +3965,8 @@ void kgsl_device_platform_remove(struct kgsl_device *device) kgsl_device_snapshot_close(device); + kgsl_exit_page_pools(); + kgsl_pwrctrl_uninit_sysfs(device); pm_qos_remove_request(&device->pwrctrl.pm_qos_req_dma); diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c index 1f10a333adf7..2e90f78a303c 100644 --- a/drivers/gpu/msm/kgsl_cffdump.c +++ b/drivers/gpu/msm/kgsl_cffdump.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2016, 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 @@ -72,8 +72,6 @@ struct cff_op_wait_irq { unsigned char op; } __packed; -#define CFF_OP_RMW 0x0000000a - struct cff_op_write_mem { unsigned char op; uint addr; diff --git a/drivers/gpu/msm/kgsl_compat.h b/drivers/gpu/msm/kgsl_compat.h index b7a1eb174baf..ca1685e5fcf5 100644 --- a/drivers/gpu/msm/kgsl_compat.h +++ b/drivers/gpu/msm/kgsl_compat.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -92,16 +92,6 @@ struct kgsl_ringbuffer_issueibcmds_compat { #define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS_COMPAT \ _IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds_compat) -struct kgsl_cmdstream_freememontimestamp_compat { - compat_ulong_t gpuaddr; - unsigned int type; - unsigned int timestamp; -}; - -#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_COMPAT \ - _IOW(KGSL_IOC_TYPE, 0x12, \ - struct kgsl_cmdstream_freememontimestamp_compat) - struct kgsl_cmdstream_freememontimestamp_ctxtid_compat { unsigned int context_id; compat_ulong_t gpuaddr; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index b0540a3830ee..c3fb2b81fcbd 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -27,10 +27,6 @@ #include "kgsl_sharedmem.h" #include "kgsl_cmdbatch.h" -#define KGSL_TIMEOUT_NONE 0 -#define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF -#define KGSL_TIMEOUT_PART 50 /* 50 msec */ - #define KGSL_IOCTL_FUNC(_cmd, _func) \ [_IOC_NR((_cmd))] = \ { .cmd = (_cmd), .func = (_func) } @@ -53,10 +49,6 @@ #define KGSL_STATE_SLUMBER 0x00000080 #define KGSL_STATE_DEEP_NAP 0x00000100 -#define KGSL_GRAPHICS_MEMORY_LOW_WATERMARK 0x1000000 - -#define KGSL_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK))) - /** * enum kgsl_event_results - result codes passed to an event callback when the * event is retired or cancelled @@ -342,14 +334,10 @@ struct kgsl_process_private; * @priv: in-kernel context flags, use KGSL_CONTEXT_* values * @reset_status: status indication whether a gpu reset occured and whether * this context was responsible for causing it - * @wait_on_invalid_ts: flag indicating if this context has tried to wait on a - * bad timestamp * @timeline: sync timeline used to create fences that can be signaled when a * sync_pt timestamp expires * @events: A kgsl_event_group for this context - contains the list of GPU * events - * @pagefault_ts: global timestamp of the pagefault, if KGSL_CONTEXT_PAGEFAULT - * is set. * @flags: flags from userspace controlling the behavior of this context * @pwr_constraint: power constraint from userspace for this context * @fault_count: number of times gpu hanged in last _context_throttle_time ms @@ -365,10 +353,8 @@ struct kgsl_context { unsigned long priv; struct kgsl_device *device; unsigned int reset_status; - bool wait_on_invalid_ts; struct sync_timeline *timeline; struct kgsl_event_group events; - unsigned int pagefault_ts; unsigned int flags; struct kgsl_pwr_constraint pwr_constraint; unsigned int fault_count; diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index aecb62cd1543..a338559ac0bb 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -227,9 +227,11 @@ static int _attach_pt(struct kgsl_iommu_pt *iommu_pt, return ret; } -static int _lock_if_secure_mmu(struct kgsl_device *device, - struct kgsl_memdesc *memdesc, struct kgsl_mmu *mmu) +static int _lock_if_secure_mmu(struct kgsl_memdesc *memdesc, + struct kgsl_mmu *mmu) { + struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); + if (!kgsl_memdesc_is_secured(memdesc)) return 0; @@ -245,9 +247,11 @@ static int _lock_if_secure_mmu(struct kgsl_device *device, return 0; } -static void _unlock_if_secure_mmu(struct kgsl_device *device, - struct kgsl_memdesc *memdesc, struct kgsl_mmu *mmu) +static void _unlock_if_secure_mmu(struct kgsl_memdesc *memdesc, + struct kgsl_mmu *mmu) { + struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); + if (!kgsl_memdesc_is_secured(memdesc) || !kgsl_mmu_is_secured(mmu)) return; @@ -260,11 +264,10 @@ static int _iommu_map_sync_pc(struct kgsl_pagetable *pt, uint64_t gpuaddr, phys_addr_t physaddr, uint64_t size, unsigned int flags) { - struct kgsl_device *device = KGSL_MMU_DEVICE(pt->mmu); struct kgsl_iommu_pt *iommu_pt = pt->priv; int ret; - ret = _lock_if_secure_mmu(device, memdesc, pt->mmu); + ret = _lock_if_secure_mmu(memdesc, pt->mmu); if (ret) return ret; @@ -274,7 +277,7 @@ static int _iommu_map_sync_pc(struct kgsl_pagetable *pt, _iommu_sync_mmu_pc(false); - _unlock_if_secure_mmu(device, memdesc, pt->mmu); + _unlock_if_secure_mmu(memdesc, pt->mmu); if (ret) { KGSL_CORE_ERR("map err: %p, 0x%016llX, 0x%llx, 0x%x, %d\n", @@ -288,12 +291,11 @@ static int _iommu_map_sync_pc(struct kgsl_pagetable *pt, static int _iommu_unmap_sync_pc(struct kgsl_pagetable *pt, struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t size) { - struct kgsl_device *device = KGSL_MMU_DEVICE(pt->mmu); struct kgsl_iommu_pt *iommu_pt = pt->priv; - size_t unmapped; + size_t unmapped = 0; int ret; - ret = _lock_if_secure_mmu(device, memdesc, pt->mmu); + ret = _lock_if_secure_mmu(memdesc, pt->mmu); if (ret) return ret; @@ -303,7 +305,7 @@ static int _iommu_unmap_sync_pc(struct kgsl_pagetable *pt, _iommu_sync_mmu_pc(false); - _unlock_if_secure_mmu(device, memdesc, pt->mmu); + _unlock_if_secure_mmu(memdesc, pt->mmu); if (unmapped != size) { KGSL_CORE_ERR("unmap err: %p, 0x%016llx, 0x%llx, %zd\n", @@ -314,32 +316,100 @@ static int _iommu_unmap_sync_pc(struct kgsl_pagetable *pt, return 0; } +static int _iommu_map_sg_offset_sync_pc(struct kgsl_pagetable *pt, + uint64_t addr, struct kgsl_memdesc *memdesc, + struct scatterlist *sg, int nents, + uint64_t offset, uint64_t size, unsigned int flags) +{ + struct kgsl_iommu_pt *iommu_pt = pt->priv; + uint64_t offset_tmp = offset; + uint64_t size_tmp = size; + size_t mapped = 0; + unsigned int i; + struct scatterlist *s; + phys_addr_t physaddr; + int ret; + + ret = _lock_if_secure_mmu(memdesc, pt->mmu); + if (ret) + return ret; + + _iommu_sync_mmu_pc(true); + + for_each_sg(sg, s, nents, i) { + /* Iterate until we find the offset */ + if (offset_tmp >= s->length) { + offset_tmp -= s->length; + continue; + } + + /* How much mapping is needed in this sg? */ + if (size < s->length - offset_tmp) + size_tmp = size; + else + size_tmp = s->length - offset_tmp; + + /* Get the phys addr for the offset page */ + if (offset_tmp != 0) { + physaddr = page_to_phys(nth_page(sg_page(s), + offset_tmp >> PAGE_SHIFT)); + /* Reset offset_tmp */ + offset_tmp = 0; + } else + physaddr = page_to_phys(sg_page(s)); + + /* Do the map for this sg */ + ret = iommu_map(iommu_pt->domain, addr + mapped, + physaddr, size_tmp, flags); + if (ret) + break; + + mapped += size_tmp; + size -= size_tmp; + + if (size == 0) + break; + } + + _iommu_sync_mmu_pc(false); + + _unlock_if_secure_mmu(memdesc, pt->mmu); + + if (size != 0) { + /* Cleanup on error */ + _iommu_unmap_sync_pc(pt, memdesc, addr, mapped); + KGSL_CORE_ERR("map err: %p, 0x%016llX, %d, %x, %zd\n", + iommu_pt->domain, addr, nents, flags, mapped); + return -ENODEV; + } + + return 0; +} + static int _iommu_map_sg_sync_pc(struct kgsl_pagetable *pt, uint64_t addr, struct kgsl_memdesc *memdesc, + struct scatterlist *sg, int nents, unsigned int flags) { - struct kgsl_device *device = KGSL_MMU_DEVICE(pt->mmu); struct kgsl_iommu_pt *iommu_pt = pt->priv; size_t mapped; int ret; - ret = _lock_if_secure_mmu(device, memdesc, pt->mmu); + ret = _lock_if_secure_mmu(memdesc, pt->mmu); if (ret) return ret; _iommu_sync_mmu_pc(true); - mapped = iommu_map_sg(iommu_pt->domain, addr, memdesc->sgt->sgl, - memdesc->sgt->nents, flags); + mapped = iommu_map_sg(iommu_pt->domain, addr, sg, nents, flags); _iommu_sync_mmu_pc(false); - _unlock_if_secure_mmu(device, memdesc, pt->mmu); + _unlock_if_secure_mmu(memdesc, pt->mmu); if (mapped == 0) { KGSL_CORE_ERR("map err: %p, 0x%016llX, %d, %x, %zd\n", - iommu_pt->domain, addr, memdesc->sgt->nents, - flags, mapped); + iommu_pt->domain, addr, nents, flags, mapped); return -ENODEV; } @@ -1404,15 +1474,34 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) } static int -kgsl_iommu_unmap(struct kgsl_pagetable *pt, - struct kgsl_memdesc *memdesc) +kgsl_iommu_unmap_offset(struct kgsl_pagetable *pt, + struct kgsl_memdesc *memdesc, uint64_t addr, + uint64_t offset, uint64_t size) +{ + /* + * All GPU addresses as assigned are page aligned, but some + * functions perturb the gpuaddr with an offset, so apply the + * mask here to make sure we have the right address. + */ + + addr = PAGE_ALIGN(addr); + + if (size == 0 || addr == 0) + return 0; + + return _iommu_unmap_sync_pc(pt, memdesc, addr + offset, size); +} + +static int +kgsl_iommu_unmap(struct kgsl_pagetable *pt, struct kgsl_memdesc *memdesc) { uint64_t size = memdesc->size; if (kgsl_memdesc_has_guard_page(memdesc)) size += kgsl_memdesc_guard_page_size(pt->mmu, memdesc); - return _iommu_unmap_sync_pc(pt, memdesc, memdesc->gpuaddr, size); + return kgsl_iommu_unmap_offset(pt, memdesc, memdesc->gpuaddr, 0, + size); } /** @@ -1472,27 +1561,30 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, protflags & ~IOMMU_WRITE); } -static int -kgsl_iommu_map(struct kgsl_pagetable *pt, - struct kgsl_memdesc *memdesc) +static unsigned int _get_protection_flags(struct kgsl_memdesc *memdesc) { - int ret; - uint64_t addr = memdesc->gpuaddr; - uint64_t size = memdesc->size; - unsigned int flags; - - BUG_ON(NULL == pt->priv); - - flags = IOMMU_READ | IOMMU_WRITE | IOMMU_NOEXEC; + unsigned int flags = IOMMU_READ | IOMMU_WRITE | IOMMU_NOEXEC; - /* Set up the protection for the page(s) */ if (memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) flags &= ~IOMMU_WRITE; if (memdesc->priv & KGSL_MEMDESC_PRIVILEGED) flags |= IOMMU_PRIV; - ret = _iommu_map_sg_sync_pc(pt, addr, memdesc, flags); + return flags; +} + +static int +kgsl_iommu_map(struct kgsl_pagetable *pt, + struct kgsl_memdesc *memdesc) +{ + int ret; + uint64_t addr = memdesc->gpuaddr; + uint64_t size = memdesc->size; + unsigned int flags = _get_protection_flags(memdesc); + + ret = _iommu_map_sg_sync_pc(pt, addr, memdesc, memdesc->sgt->sgl, + memdesc->sgt->nents, flags); if (ret) return ret; @@ -1503,6 +1595,26 @@ kgsl_iommu_map(struct kgsl_pagetable *pt, return ret; } +static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt, + uint64_t virtaddr, uint64_t virtoffset, + struct kgsl_memdesc *memdesc, uint64_t physoffset, + uint64_t size, uint64_t feature_flag) +{ + int pg_sz; + unsigned int protflags = _get_protection_flags(memdesc); + + pg_sz = (1 << kgsl_memdesc_get_align(memdesc)); + if (!IS_ALIGNED(virtaddr | virtoffset | physoffset | size, pg_sz)) + return -EINVAL; + + if (size == 0) + return -EINVAL; + + return _iommu_map_sg_offset_sync_pc(pt, virtaddr + virtoffset, + memdesc, memdesc->sgt->sgl, memdesc->sgt->nents, + physoffset, size, protflags); +} + /* This function must be called with context bank attached */ static void kgsl_iommu_clear_fsr(struct kgsl_mmu *mmu) { @@ -2270,4 +2382,6 @@ static struct kgsl_mmu_pt_ops iommu_pt_ops = { .find_svm_region = kgsl_iommu_find_svm_region, .svm_range = kgsl_iommu_svm_range, .addr_in_range = kgsl_iommu_addr_in_range, + .mmu_map_offset = kgsl_iommu_map_offset, + .mmu_unmap_offset = kgsl_iommu_unmap_offset, }; diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h index f82452dd6080..06f6d65effad 100644 --- a/drivers/gpu/msm/kgsl_iommu.h +++ b/drivers/gpu/msm/kgsl_iommu.h @@ -45,20 +45,6 @@ #define KGSL_IOMMU_SVM_BASE64 0x700000000ULL #define KGSL_IOMMU_SVM_END64 0x800000000ULL -/* Pagetable virtual base */ -#define KGSL_IOMMU_CTX_OFFSET_V1 0x8000 -#define KGSL_IOMMU_CTX_OFFSET_V2 0x9000 -#define KGSL_IOMMU_CTX_OFFSET_V2_A530 0x8000 -#define KGSL_IOMMU_CTX_OFFSET_A405V2 0x8000 -#define KGSL_IOMMU_CTX_SHIFT 12 - -/* FSYNR1 V0 fields */ -#define KGSL_IOMMU_FSYNR1_AWRITE_MASK 0x00000001 -#define KGSL_IOMMU_FSYNR1_AWRITE_SHIFT 8 -/* FSYNR0 V1 fields */ -#define KGSL_IOMMU_V1_FSYNR0_WNR_MASK 0x00000001 -#define KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT 4 - /* TLBSTATUS register fields */ #define KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE BIT(0) diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h index 70480f8e9189..51baabefb6d3 100644 --- a/drivers/gpu/msm/kgsl_log.h +++ b/drivers/gpu/msm/kgsl_log.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2008-2011,2013-2014 The Linux Foundation. +/* Copyright (c) 2002,2008-2011,2013-2014,2016 The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -48,9 +48,6 @@ BUG(); \ } while (0) -#define KGSL_LOG_POSTMORTEM_WRITE(_dev, fmt, args...) \ - do { dev_crit(_dev->dev, fmt, ##args); } while (0) - #define KGSL_LOG_DUMP(_dev, fmt, args...) dev_err(_dev->dev, fmt, ##args) #define KGSL_DEV_ERR_ONCE(_dev, fmt, args...) \ @@ -83,24 +80,6 @@ KGSL_LOG_CRIT_RATELIMITED(_dev->dev, _dev->drv_log, fmt, ##args) #define KGSL_DRV_FATAL(_dev, fmt, args...) \ KGSL_LOG_FATAL((_dev)->dev, (_dev)->drv_log, fmt, ##args) -#define KGSL_CMD_INFO(_dev, fmt, args...) \ -KGSL_LOG_INFO(_dev->dev, _dev->cmd_log, fmt, ##args) -#define KGSL_CMD_WARN(_dev, fmt, args...) \ -KGSL_LOG_WARN(_dev->dev, _dev->cmd_log, fmt, ##args) -#define KGSL_CMD_ERR(_dev, fmt, args...) \ -KGSL_LOG_ERR(_dev->dev, _dev->cmd_log, fmt, ##args) -#define KGSL_CMD_CRIT(_dev, fmt, args...) \ -KGSL_LOG_CRIT(_dev->dev, _dev->cmd_log, fmt, ##args) - -#define KGSL_CTXT_INFO(_dev, fmt, args...) \ -KGSL_LOG_INFO(_dev->dev, _dev->ctxt_log, fmt, ##args) -#define KGSL_CTXT_WARN(_dev, fmt, args...) \ -KGSL_LOG_WARN(_dev->dev, _dev->ctxt_log, fmt, ##args) -#define KGSL_CTXT_ERR(_dev, fmt, args...) \ -KGSL_LOG_ERR(_dev->dev, _dev->ctxt_log, fmt, ##args) -#define KGSL_CTXT_CRIT(_dev, fmt, args...) \ -KGSL_LOG_CRIT(_dev->dev, _dev->ctxt_log, fmt, ##args) - #define KGSL_MEM_INFO(_dev, fmt, args...) \ KGSL_LOG_INFO(_dev->dev, _dev->mem_log, fmt, ##args) #define KGSL_MEM_WARN(_dev, fmt, args...) \ @@ -125,13 +104,4 @@ KGSL_LOG_CRIT(_dev->dev, _dev->pwr_log, fmt, ##args) #define KGSL_CORE_ERR(fmt, args...) \ pr_err("kgsl: %s: " fmt, __func__, ##args) -#define KGSL_CORE_ERR_ONCE(fmt, args...) \ -({ \ - static bool kgsl_core_err_once; \ - if (!kgsl_core_err_once) { \ - kgsl_core_err_once = true; \ - pr_err("kgsl: %s: " fmt, __func__, ##args); \ - } \ -}) - #endif /* __KGSL_LOG_H */ diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 82150fbe9ac1..f8315090ff06 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -476,6 +476,31 @@ kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, } EXPORT_SYMBOL(kgsl_mmu_unmap); +int kgsl_mmu_map_offset(struct kgsl_pagetable *pagetable, + uint64_t virtaddr, uint64_t virtoffset, + struct kgsl_memdesc *memdesc, uint64_t physoffset, + uint64_t size, uint64_t flags) +{ + if (PT_OP_VALID(pagetable, mmu_map_offset)) + return pagetable->pt_ops->mmu_map_offset(pagetable, virtaddr, + virtoffset, memdesc, physoffset, size, flags); + + return -EINVAL; +} +EXPORT_SYMBOL(kgsl_mmu_map_offset); + +int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t offset, + uint64_t size) +{ + if (PT_OP_VALID(pagetable, mmu_unmap_offset)) + return pagetable->pt_ops->mmu_unmap_offset(pagetable, memdesc, + addr, offset, size); + + return -EINVAL; +} +EXPORT_SYMBOL(kgsl_mmu_unmap_offset); + void kgsl_mmu_remove_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc) { diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 576a6acd4538..3652aa2e6ec4 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -92,6 +92,13 @@ struct kgsl_mmu_pt_ops { int (*svm_range)(struct kgsl_pagetable *, uint64_t *, uint64_t *, uint64_t); bool (*addr_in_range)(struct kgsl_pagetable *pagetable, uint64_t); + int (*mmu_map_offset)(struct kgsl_pagetable *pt, + uint64_t virtaddr, uint64_t virtoffset, + struct kgsl_memdesc *memdesc, uint64_t physoffset, + uint64_t size, uint64_t flags); + int (*mmu_unmap_offset)(struct kgsl_pagetable *pt, + struct kgsl_memdesc *memdesc, uint64_t addr, + uint64_t offset, uint64_t size); }; /* @@ -206,6 +213,14 @@ struct kgsl_pagetable *kgsl_get_pagetable(unsigned long name); struct kgsl_pagetable * kgsl_mmu_createpagetableobject(struct kgsl_mmu *mmu, unsigned int name); +int kgsl_mmu_map_offset(struct kgsl_pagetable *pagetable, + uint64_t virtaddr, uint64_t virtoffset, + struct kgsl_memdesc *memdesc, uint64_t physoffset, + uint64_t size, uint64_t flags); +int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t offset, + uint64_t size); + /* * Static inline functions of MMU that simply call the SMMU specific * function using a function pointer. These functions can be thought diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c new file mode 100644 index 000000000000..497cfdaae2ec --- /dev/null +++ b/drivers/gpu/msm/kgsl_pool.c @@ -0,0 +1,341 @@ +/* Copyright (c) 2016, 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/vmalloc.h> +#include <asm/cacheflush.h> +#include <linux/slab.h> +#include <linux/highmem.h> +#include <linux/version.h> + +#include "kgsl.h" +#include "kgsl_device.h" +#include "kgsl_pool.h" + +/* + * Maximum pool size in terms of pages + * = (Number of pools * Max size per pool) + */ +#define KGSL_POOL_MAX_PAGES (2 * 4096) + +/* Set the max pool size to 8192 pages */ +static unsigned int kgsl_pool_max_pages = KGSL_POOL_MAX_PAGES; + +struct kgsl_page_pool { + unsigned int pool_order; + int page_count; + spinlock_t list_lock; + struct list_head page_list; +}; + +static struct kgsl_page_pool kgsl_pools[] = { + { + .pool_order = 0, + .list_lock = __SPIN_LOCK_UNLOCKED(kgsl_pools[0].list_lock), + .page_list = LIST_HEAD_INIT(kgsl_pools[0].page_list), + }, +#ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS + { + .pool_order = 4, + .list_lock = __SPIN_LOCK_UNLOCKED(kgsl_pools[1].list_lock), + .page_list = LIST_HEAD_INIT(kgsl_pools[1].page_list), + }, +#endif +}; + +#define KGSL_NUM_POOLS ARRAY_SIZE(kgsl_pools) + +/* Returns KGSL pool corresponding to input page order*/ +static struct kgsl_page_pool * +_kgsl_get_pool_from_order(unsigned int order) +{ + int i; + + for (i = 0; i < KGSL_NUM_POOLS; i++) { + if (kgsl_pools[i].pool_order == order) + return &kgsl_pools[i]; + } + + return NULL; +} + +/* Add a page to specified pool */ +static void +_kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p) +{ + spin_lock(&pool->list_lock); + list_add_tail(&p->lru, &pool->page_list); + pool->page_count++; + spin_unlock(&pool->list_lock); +} + +/* Returns a page from specified pool */ +static struct page * +_kgsl_pool_get_page(struct kgsl_page_pool *pool) +{ + struct page *p = NULL; + + spin_lock(&pool->list_lock); + if (pool->page_count) { + p = list_first_entry(&pool->page_list, struct page, lru); + pool->page_count--; + list_del(&p->lru); + } + spin_unlock(&pool->list_lock); + + return p; +} + +/* Returns the number of pages in specified pool */ +static int +kgsl_pool_size(struct kgsl_page_pool *kgsl_pool) +{ + int size; + + spin_lock(&kgsl_pool->list_lock); + size = kgsl_pool->page_count * (1 << kgsl_pool->pool_order); + spin_unlock(&kgsl_pool->list_lock); + + return size; +} + +/* Returns the number of pages in all kgsl page pools */ +static int kgsl_pool_size_total(void) +{ + int i; + int total = 0; + + for (i = 0; i < KGSL_NUM_POOLS; i++) + total += kgsl_pool_size(&kgsl_pools[i]); + return total; +} + +/* + * This will shrink the specified pool by num_pages or its pool_size, + * whichever is smaller. + */ +static unsigned int +_kgsl_pool_shrink(struct kgsl_page_pool *pool, int num_pages) +{ + int j; + unsigned int pcount = 0; + + if (pool == NULL || num_pages <= 0) + return pcount; + + for (j = 0; j < num_pages >> pool->pool_order; j++) { + struct page *page = _kgsl_pool_get_page(pool); + + if (page != NULL) { + __free_pages(page, pool->pool_order); + pcount += (1 << pool->pool_order); + } else { + /* Break as this pool is empty */ + break; + } + } + + return pcount; +} + +/* + * This function reduces the total pool size + * to number of pages specified by target_pages. + * + * If target_pages are greater than current pool size + * nothing needs to be done otherwise remove + * (current_pool_size - target_pages) pages from pool + * starting from higher order pool. + */ +static int +kgsl_pool_reduce(unsigned int target_pages) +{ + int total_pages = 0; + int i; + int nr_removed; + struct kgsl_page_pool *pool; + unsigned int pcount = 0; + + total_pages = kgsl_pool_size_total(); + + for (i = (KGSL_NUM_POOLS - 1); i >= 0; i--) { + pool = &kgsl_pools[i]; + + total_pages -= pcount; + + nr_removed = total_pages - target_pages; + if (nr_removed <= 0) + return pcount; + + /* Round up to integral number of pages in this pool */ + nr_removed = ALIGN(nr_removed, 1 << pool->pool_order); + + /* Remove nr_removed pages from this pool*/ + pcount += _kgsl_pool_shrink(pool, nr_removed); + } + + return pcount; +} + +/** + * kgsl_pool_free_sgt() - Free scatter-gather list + * @sgt: pointer of the sg list + * + * Free the sg list by collapsing any physical adjacent pages. + * Pages are added back to the pool, if pool has sufficient space + * otherwise they are given back to system. + */ + +void kgsl_pool_free_sgt(struct sg_table *sgt) +{ + int i; + struct scatterlist *sg; + + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + /* + * sg_alloc_table_from_pages() will collapse any physically + * adjacent pages into a single scatterlist entry. We cannot + * just call __free_pages() on the entire set since we cannot + * ensure that the size is a whole order. Instead, free each + * page or compound page group individually. + */ + struct page *p = sg_page(sg), *next; + unsigned int count; + unsigned int j = 0; + + while (j < (sg->length/PAGE_SIZE)) { + count = 1 << compound_order(p); + next = nth_page(p, count); + kgsl_pool_free_page(p); + + p = next; + j += count; + } + } +} + +/** + * kgsl_pool_alloc_page() - Allocate a page of requested size + * @page_size: Size of the page to be allocated + * @pages: pointer to hold list of pages, should be big enough to hold + * requested page + * @len: Length of array pages. + * + * Return total page count on success and negative value on failure + */ +int kgsl_pool_alloc_page(int page_size, struct page **pages, + unsigned int pages_len) +{ + int j; + int pcount = 0; + struct kgsl_page_pool *pool; + struct page *page = NULL; + struct page *p = NULL; + + if ((pages == NULL) || pages_len < (page_size >> PAGE_SHIFT)) + return -EINVAL; + + pool = _kgsl_get_pool_from_order(get_order(page_size)); + + if (pool != NULL) + page = _kgsl_pool_get_page(pool); + + /* Allocate a new page if not allocated from pool */ + if (page == NULL) { + gfp_t gfp_mask = kgsl_gfp_mask(get_order(page_size)); + + page = alloc_pages(gfp_mask, + get_order(page_size)); + + if (!page) + return -ENOMEM; + } + + for (j = 0; j < (page_size >> PAGE_SHIFT); j++) { + p = nth_page(page, j); + pages[pcount] = p; + pcount++; + } + + return pcount; +} + +void kgsl_pool_free_page(struct page *page) +{ + struct kgsl_page_pool *pool; + int page_order; + + if (page == NULL) + return; + + page_order = compound_order(page); + + if (kgsl_pool_size_total() < kgsl_pool_max_pages) { + pool = _kgsl_get_pool_from_order(page_order); + if (pool != NULL) { + _kgsl_pool_add_page(pool, page); + return; + } + } + + /* Give back to system as not added to pool */ + __free_pages(page, page_order); +} + +/* Functions for the shrinker */ + +static unsigned long +kgsl_pool_shrink_scan_objects(struct shrinker *shrinker, + struct shrink_control *sc) +{ + /* nr represents number of pages to be removed*/ + int nr = sc->nr_to_scan; + int total_pages = kgsl_pool_size_total(); + + /* Target pages represents new pool size */ + int target_pages = (nr > total_pages) ? 0 : (total_pages - nr); + + /* Reduce pool size to target_pages */ + return kgsl_pool_reduce(target_pages); +} + +static unsigned long +kgsl_pool_shrink_count_objects(struct shrinker *shrinker, + struct shrink_control *sc) +{ + /* Return total pool size as everything in pool can be freed */ + return kgsl_pool_size_total(); +} + +/* Shrinker callback data*/ +static struct shrinker kgsl_pool_shrinker = { + .count_objects = kgsl_pool_shrink_count_objects, + .scan_objects = kgsl_pool_shrink_scan_objects, + .seeks = DEFAULT_SEEKS, + .batch = 0, +}; + +void kgsl_init_page_pools(void) +{ + /* Initialize shrinker */ + register_shrinker(&kgsl_pool_shrinker); +} + +void kgsl_exit_page_pools(void) +{ + /* Release all pages in pools, if any.*/ + kgsl_pool_reduce(0); + + /* Unregister shrinker */ + unregister_shrinker(&kgsl_pool_shrinker); +} + diff --git a/drivers/gpu/msm/kgsl_pool.h b/drivers/gpu/msm/kgsl_pool.h new file mode 100644 index 000000000000..f76c8aadbf30 --- /dev/null +++ b/drivers/gpu/msm/kgsl_pool.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2016, 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 __KGSL_POOL_H +#define __KGSL_POOL_H + +#include <linux/mm_types.h> +#include "kgsl_sharedmem.h" + +static inline unsigned int +kgsl_gfp_mask(unsigned int page_order) +{ + unsigned int gfp_mask = __GFP_HIGHMEM; + + if (page_order > 0) { + gfp_mask |= __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN; + gfp_mask &= ~__GFP_RECLAIM; + } else + gfp_mask |= GFP_KERNEL; + + if (kgsl_sharedmem_get_noretry() == true) + gfp_mask |= __GFP_NORETRY | __GFP_NOWARN; + + return gfp_mask; +} + +void kgsl_pool_free_sgt(struct sg_table *sgt); +void kgsl_init_page_pools(void); +void kgsl_exit_page_pools(void); +int kgsl_pool_alloc_page(int page_size, struct page **pages, + unsigned int pages_len); +void kgsl_pool_free_page(struct page *p); +#endif /* __KGSL_POOL_H */ + diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index f9b5545519cb..927841a7ad3b 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -35,23 +35,12 @@ #define UPDATE_BUSY_VAL 1000000 -/* - * Expected delay for post-interrupt processing on A3xx. - * The delay may be longer, gradually increase the delay - * to compensate. If the GPU isn't done by max delay, - * it's working on something other than just the final - * command sequence so stop waiting for it to be idle. - */ -#define INIT_UDELAY 200 -#define MAX_UDELAY 2000 - /* Number of jiffies for a full thermal cycle */ #define TH_HZ (HZ/5) #define KGSL_MAX_BUSLEVELS 20 #define DEFAULT_BUS_P 25 -#define DEFAULT_BUS_DIV (100 / DEFAULT_BUS_P) /* * The effective duration of qos request in usecs. After diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 7ed76760c043..9fcea11c805b 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -22,8 +22,6 @@ #define KGSL_PWRFLAGS_OFF 0 #define KGSL_PWRLEVEL_TURBO 0 -#define KGSL_PWRLEVEL_NOMINAL 1 -#define KGSL_PWRLEVEL_LAST_OFFSET 2 #define KGSL_PWR_ON 0xFFFF diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 4ee1816a66f0..4f6677d9a1de 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -19,9 +19,6 @@ #include "kgsl_device.h" #include "kgsl_trace.h" -#define FAST_BUS 1 -#define SLOW_BUS -1 - /* * "SLEEP" is generic counting both NAP & SLUMBER * PERIODS generally won't exceed 9 for the relavent 150msec diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 893e31852ccb..4cb9bc5d1651 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -27,6 +27,7 @@ #include "kgsl_device.h" #include "kgsl_log.h" #include "kgsl_mmu.h" +#include "kgsl_pool.h" /* * The user can set this from debugfs to force failed memory allocations to @@ -424,9 +425,6 @@ done: static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc) { - unsigned int i = 0; - struct scatterlist *sg; - kgsl_page_alloc_unmap_kernel(memdesc); /* we certainly do not expect the hostptr to still be mapped */ BUG_ON(memdesc->hostptr); @@ -451,28 +449,15 @@ static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc) atomic_long_sub(memdesc->size, &kgsl_driver.stats.page_alloc); } - for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) { - /* - * sg_alloc_table_from_pages() will collapse any physically - * adjacent pages into a single scatterlist entry. We cannot - * just call __free_pages() on the entire set since we cannot - * ensure that the size is a whole order. Instead, free each - * page or compound page group individually. - */ - struct page *p = sg_page(sg), *next; - unsigned int j = 0, count; - while (j < (sg->length/PAGE_SIZE)) { - if (memdesc->priv & KGSL_MEMDESC_TZ_LOCKED) - ClearPagePrivate(p); - - count = 1 << compound_order(p); - next = nth_page(p, count); - __free_pages(p, compound_order(p)); - p = next; - j += count; + if (memdesc->priv & KGSL_MEMDESC_TZ_LOCKED) { + struct sg_page_iter sg_iter; - } + for_each_sg_page(memdesc->sgt->sgl, &sg_iter, + memdesc->sgt->nents, 0) + ClearPagePrivate(sg_page_iter_page(&sg_iter)); } + + kgsl_pool_free_sgt(memdesc->sgt); } /* @@ -681,19 +666,67 @@ static inline int get_page_size(size_t size, unsigned int align) } #endif +static void kgsl_zero_pages(struct page **pages, unsigned int pcount) +{ + unsigned int j; + unsigned int step = ((VMALLOC_END - VMALLOC_START)/8) >> PAGE_SHIFT; + pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL); + void *ptr; + + /* + * All memory that goes to the user has to be zeroed out before it gets + * exposed to userspace. This means that the memory has to be mapped in + * the kernel, zeroed (memset) and then unmapped. This also means that + * the dcache has to be flushed to ensure coherency between the kernel + * and user pages. We used to pass __GFP_ZERO to alloc_page which mapped + * zeroed and unmaped each individual page, and then we had to turn + * around and call flush_dcache_page() on that page to clear the caches. + * This was killing us for performance. Instead, we found it is much + * faster to allocate the pages without GFP_ZERO, map a chunk of the + * range ('step' pages), memset it, flush it and then unmap + * - this results in a factor of 4 improvement for speed for large + * buffers. There is a small decrease in speed for small buffers, + * but only on the order of a few microseconds at best. The 'step' + * size is based on a guess at the amount of free vmalloc space, but + * will scale down if there's not enough free space. + */ + for (j = 0; j < pcount; j += step) { + step = min(step, pcount - j); + + ptr = vmap(&pages[j], step, VM_IOREMAP, page_prot); + + if (ptr != NULL) { + memset(ptr, 0, step * PAGE_SIZE); + dmac_flush_range(ptr, ptr + step * PAGE_SIZE); + vunmap(ptr); + } else { + int k; + /* Very, very, very slow path */ + + for (k = j; k < j + step; k++) { + ptr = kmap_atomic(pages[k]); + memset(ptr, 0, PAGE_SIZE); + dmac_flush_range(ptr, ptr + PAGE_SIZE); + kunmap_atomic(ptr); + } + /* scale down the step size to avoid this path */ + if (step > 1) + step >>= 1; + } + } +} + static int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, uint64_t size) { int ret = 0; - unsigned int j, pcount = 0, page_size, len_alloc; + unsigned int j, page_size, len_alloc; + unsigned int pcount = 0; size_t len; struct page **pages = NULL; - pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL); - void *ptr; unsigned int align; - unsigned int step = ((VMALLOC_END - VMALLOC_START)/8) >> PAGE_SHIFT; size = PAGE_ALIGN(size); if (size == 0 || size > UINT_MAX) @@ -740,30 +773,16 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, len = size; while (len > 0) { - struct page *page; - gfp_t gfp_mask = __GFP_HIGHMEM; - int j; + int page_count; /* don't waste space at the end of the allocation*/ if (len < page_size) page_size = PAGE_SIZE; - /* - * Don't do some of the more aggressive memory recovery - * techniques for large order allocations - */ - if (page_size != PAGE_SIZE) { - gfp_mask |= __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN; - gfp_mask &= ~__GFP_RECLAIM; - } else - gfp_mask |= GFP_KERNEL; - - if (sharedmem_noretry_flag == true) - gfp_mask |= __GFP_NORETRY | __GFP_NOWARN; + page_count = kgsl_pool_alloc_page(page_size, + pages + pcount, len_alloc - pcount); - page = alloc_pages(gfp_mask, get_order(page_size)); - - if (page == NULL) { + if (page_count <= 0) { if (page_size != PAGE_SIZE) { page_size = PAGE_SIZE; continue; @@ -785,9 +804,7 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, goto done; } - for (j = 0; j < page_size >> PAGE_SHIFT; j++) - pages[pcount++] = nth_page(page, j); - + pcount += page_count; len -= page_size; memdesc->size += page_size; } @@ -824,57 +841,23 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, goto done; } - /* - * All memory that goes to the user has to be zeroed out before it gets - * exposed to userspace. This means that the memory has to be mapped in - * the kernel, zeroed (memset) and then unmapped. This also means that - * the dcache has to be flushed to ensure coherency between the kernel - * and user pages. We used to pass __GFP_ZERO to alloc_page which mapped - * zeroed and unmaped each individual page, and then we had to turn - * around and call flush_dcache_page() on that page to clear the caches. - * This was killing us for performance. Instead, we found it is much - * faster to allocate the pages without GFP_ZERO, map a chunk of the - * range ('step' pages), memset it, flush it and then unmap - * - this results in a factor of 4 improvement for speed for large - * buffers. There is a small decrease in speed for small buffers, - * but only on the order of a few microseconds at best. The 'step' - * size is based on a guess at the amount of free vmalloc space, but - * will scale down if there's not enough free space. - */ - for (j = 0; j < pcount; j += step) { - step = min(step, pcount - j); - - ptr = vmap(&pages[j], step, VM_IOREMAP, page_prot); - - if (ptr != NULL) { - memset(ptr, 0, step * PAGE_SIZE); - dmac_flush_range(ptr, ptr + step * PAGE_SIZE); - vunmap(ptr); - } else { - int k; - /* Very, very, very slow path */ - - for (k = j; k < j + step; k++) { - ptr = kmap_atomic(pages[k]); - memset(ptr, 0, PAGE_SIZE); - dmac_flush_range(ptr, ptr + PAGE_SIZE); - kunmap_atomic(ptr); - } - /* scale down the step size to avoid this path */ - if (step > 1) - step >>= 1; - } - } - KGSL_STATS_ADD(memdesc->size, &kgsl_driver.stats.page_alloc, &kgsl_driver.stats.page_alloc_max); + /* + * Zero out the pages. + */ + kgsl_zero_pages(pages, pcount); + done: if (ret) { - unsigned int count = 1; - for (j = 0; j < pcount; j += count) { - count = 1 << compound_order(pages[j]); - __free_pages(pages[j], compound_order(pages[j])); + if (pages) { + unsigned int count = 1; + + for (j = 0; j < pcount; j += count) { + count = 1 << compound_order(pages[j]); + kgsl_pool_free_page(pages[j]); + } } kfree(memdesc->sgt); @@ -918,8 +901,8 @@ kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc, if (offsetbytes % sizeof(uint32_t) != 0) return -EINVAL; - WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size); - if (offsetbytes + sizeof(uint32_t) > memdesc->size) + WARN_ON(offsetbytes > (memdesc->size - sizeof(uint32_t))); + if (offsetbytes > (memdesc->size - sizeof(uint32_t))) return -ERANGE; rmb(); @@ -941,8 +924,8 @@ kgsl_sharedmem_writel(struct kgsl_device *device, if (offsetbytes % sizeof(uint32_t) != 0) return -EINVAL; - WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size); - if (offsetbytes + sizeof(uint32_t) > memdesc->size) + WARN_ON(offsetbytes > (memdesc->size - sizeof(uint32_t))); + if (offsetbytes > (memdesc->size - sizeof(uint32_t))) return -ERANGE; kgsl_cffdump_write(device, memdesc->gpuaddr + offsetbytes, @@ -967,8 +950,8 @@ kgsl_sharedmem_readq(const struct kgsl_memdesc *memdesc, if (offsetbytes % sizeof(uint32_t) != 0) return -EINVAL; - WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size); - if (offsetbytes + sizeof(uint32_t) > memdesc->size) + WARN_ON(offsetbytes > (memdesc->size - sizeof(uint32_t))); + if (offsetbytes > (memdesc->size - sizeof(uint32_t))) return -ERANGE; /* @@ -994,8 +977,8 @@ kgsl_sharedmem_writeq(struct kgsl_device *device, if (offsetbytes % sizeof(uint32_t) != 0) return -EINVAL; - WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size); - if (offsetbytes + sizeof(uint32_t) > memdesc->size) + WARN_ON(offsetbytes > (memdesc->size - sizeof(uint32_t))); + if (offsetbytes > (memdesc->size - sizeof(uint32_t))) return -ERANGE; kgsl_cffdump_write(device, lower_32_bits(memdesc->gpuaddr + offsetbytes), src); diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index dece6cbb9441..6772868d1c9b 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 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 @@ -1143,6 +1143,30 @@ static inline int iommu_debug_init_tests(void) { return 0; } static inline void iommu_debug_destroy_tests(void) { } #endif +/* + * This isn't really a "driver", we just need something in the device tree + * so that our tests can run without any client drivers, and our tests rely + * on parsing the device tree for nodes with the `iommus' property. + */ +static int iommu_debug_pass(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id iommu_debug_of_match[] = { + { .compatible = "iommu-debug-test" }, + { }, +}; + +static struct platform_driver iommu_debug_driver = { + .probe = iommu_debug_pass, + .remove = iommu_debug_pass, + .driver = { + .name = "iommu-debug", + .of_match_table = iommu_debug_of_match, + }, +}; + static int iommu_debug_init(void) { if (iommu_debug_init_tracking()) @@ -1151,11 +1175,12 @@ static int iommu_debug_init(void) if (iommu_debug_init_tests()) return -ENODEV; - return 0; + return platform_driver_register(&iommu_debug_driver); } static void iommu_debug_exit(void) { + platform_driver_unregister(&iommu_debug_driver); iommu_debug_destroy_tracking(); iommu_debug_destroy_tests(); } diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 305f110447a3..53f9b902e695 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -55,5 +55,4 @@ obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o -obj-$(CONFIG_MSM_IRQ) += irq-msm.o obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o diff --git a/drivers/irqchip/irq-msm.c b/drivers/irqchip/irq-msm.c deleted file mode 100644 index 31597484df53..000000000000 --- a/drivers/irqchip/irq-msm.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (c) 2014-2016, 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/irqchip.h> -#include <linux/irqchip/msm-gpio-irq.h> -#include <linux/irqchip/msm-mpm-irq.h> - -static int __init irq_msm_gpio_init(struct device_node *node, - struct device_node *parent) -{ - int rc; - -#ifdef CONFIG_USE_PINCTRL_IRQ - rc = msm_tlmm_of_irq_init(node, parent); -#else - rc = msm_gpio_of_init(node, parent); -#endif - if (rc) { - pr_err("Couldn't initlialize gpio irq rc = %d\n", rc); - return rc; - } - - /* - * Initialize the mpm after gpio (and gic) are initialized. Note that - * gpio irq controller is the child of gic irq controller, hence gic's - * init function will be called prior to gpio. - */ - of_mpm_init(); - - return 0; -} - -static int __init pinctrl_irq_dummy(struct device_node *node, - struct device_node *parent) -{ - /* - * Initialize the mpm after gpio (and gic) are initialized. Note that - * gpio irq controller is the child of gic irq controller, hence gic's - * init function will be called prior to gpio. - */ - of_mpm_init(); - return 0; -} -#ifdef CONFIG_USE_PINCTRL_IRQ -IRQCHIP_DECLARE(tlmmv3_irq, "qcom,msm-tlmm-gp", irq_msm_gpio_init); -#else -IRQCHIP_DECLARE(tlmm_irq, "qcom,msm-gpio", irq_msm_gpio_init); -#endif -IRQCHIP_DECLARE(8996_pinctrl, "qcom,msm8996-pinctrl", pinctrl_irq_dummy); diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c index 2f84ff95a38a..57e389b4c497 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c @@ -1075,6 +1075,30 @@ static int msm_jpegdma_s_parm(struct file *file, void *fh, return 0; } +/* + * msm_fd_g_ctrl - V4l2 ioctl get control. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @sub: Pointer to v4l2_control struct need to be filled. + */ +static int msm_jpegdma_g_ctrl(struct file *file, void *fh, + struct v4l2_control *a) +{ + struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh); + + switch (a->id) { + case V4L2_CID_JPEG_DMA_MAX_DOWN_SCALE: + a->value = msm_jpegdma_hw_get_max_downscale(ctx->jdma_device); + if (a->value < 0) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + /* V4l2 ioctl handlers */ static const struct v4l2_ioctl_ops fd_ioctl_ops = { .vidioc_querycap = msm_jpegdma_querycap, @@ -1096,6 +1120,7 @@ static const struct v4l2_ioctl_ops fd_ioctl_ops = { .vidioc_s_crop = msm_jpegdma_s_crop, .vidioc_g_parm = msm_jpegdma_g_parm, .vidioc_s_parm = msm_jpegdma_s_parm, + .vidioc_g_ctrl = msm_jpegdma_g_ctrl, }; /* diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c index e994ce1b8b32..0a871c342fb4 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c @@ -1366,6 +1366,25 @@ int msm_jpegdma_hw_get_mem_resources(struct platform_device *pdev, } /* + * msm_jpegdma_hw_get_max_downscale - Get max downscale factor from dtsi. + * @dma: Pointer to dma device. + */ +int msm_jpegdma_hw_get_max_downscale(struct msm_jpegdma_device *dma) +{ + int ret; + int max_ds_factor; + + ret = of_property_read_u32(dma->dev->of_node, + "qcom,max-ds-factor", &max_ds_factor); + if (ret < 0) { + dev_err(dma->dev, "cannot read qcom,max-ds-factor from dtsi\n"); + return ret; + } + dev_dbg(dma->dev, "max_ds_factor is %d\n", max_ds_factor); + return max_ds_factor; +} + +/* * msm_jpegdma_hw_get_qos - Get dma qos settings from device-tree. * @dma: Pointer to dma device. */ diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.h b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.h index b7ff3b53aeb0..a29f3323500d 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.h +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -52,6 +52,8 @@ int msm_jpegdma_hw_get_clocks(struct msm_jpegdma_device *dma); int msm_jpegdma_hw_put_clocks(struct msm_jpegdma_device *dma); +int msm_jpegdma_hw_get_max_downscale(struct msm_jpegdma_device *dma); + int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma); void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma); 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 e6eb22a60d3a..99f29bd0556f 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 @@ -2541,6 +2541,8 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, { switch (cmd) { case MSM_SD_SHUTDOWN: + case MSM_SD_NOTIFY_FREEZE: + case MSM_SD_UNNOTIFY_FREEZE: break; default: { if (ioctl_ptr == NULL) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h index 169f6b5f130a..c1102c866ccf 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h @@ -63,7 +63,7 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_3ph = { {0x180, 0x0}, {0x184, 0x7F}, {0x1cc, 0x41}, - {0x81c, 0x1}, + {0x81c, 0x2}, {0x82c, 0xFF}, {0x830, 0xFF}, {0x834, 0xFB}, diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index d690200b3c57..c9912f979b0a 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -633,10 +633,12 @@ static int msm_csiphy_2phase_lane_config_v50( mipi_csiphy_2ph_lnn_cfg5.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg5.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl10.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl10.addr); + if (clk_lane == 1) + msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl10.data, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl10.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_ctrl15.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. @@ -649,14 +651,14 @@ static int msm_csiphy_2phase_lane_config_v50( mipi_csiphy_2ph_lnn_cfg1.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg1.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg2.data, + msm_camera_io_w((csiphy_params->settle_cnt & 0xFF), csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg2.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl3.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl3.addr); + if (clk_lane == 1) + msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl3.data, csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl3.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg4.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c index 7315327e6d12..4a31b93ec37f 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c @@ -78,6 +78,7 @@ int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; + cci_ctrl.status = -EFAULT; rc = v4l2_subdev_call(client->cci_client->cci_subdev, core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); @@ -168,6 +169,7 @@ int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA; cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte; + cci_ctrl.status = -EFAULT; rc = v4l2_subdev_call(client->cci_client->cci_subdev, core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); @@ -382,7 +384,7 @@ int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, uint32_t addr, uint16_t data, enum msm_camera_i2c_data_type data_type, uint32_t delay_ms) { - int32_t rc; + int32_t rc = -EFAULT; int32_t i = 0; S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", __func__, addr, data, data_type); @@ -415,7 +417,7 @@ static int32_t msm_camera_cci_i2c_set_mask(struct msm_camera_i2c_client *client, uint32_t addr, uint16_t mask, enum msm_camera_i2c_data_type data_type, uint16_t set_mask) { - int32_t rc; + int32_t rc = -EFAULT; uint16_t reg_data; rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_type); diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index 1504356e685f..5216fd9c7b4a 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -2076,6 +2076,14 @@ int create_pkt_cmd_session_set_property( pkt->size += sizeof(u32) + sizeof(struct hfi_enable); break; } + case HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32) + sizeof(struct hfi_enable); + break; + } /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ case HAL_CONFIG_BUFFER_REQUIREMENTS: case HAL_CONFIG_PRIORITY: diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 09bd865f3463..8c0df7ce08e1 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -2636,10 +2636,33 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: { struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs; + bool is_cont_intra_supported = false; + air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS); air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF); cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS); + is_cont_intra_supported = + (inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_H264) || + (inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_HEVC); + + if (is_cont_intra_supported) { + if (air_mbs || air_ref || cir_mbs) + enable.enable = true; + else + enable.enable = false; + + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED, &enable); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set constrained intra\n"); + rc = -EINVAL; + break; + } + } + property_id = HAL_PARAM_VENC_INTRA_REFRESH; intra_refresh.mode = ctrl->val; diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index bd33a95aad20..561c6c39358d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1051,6 +1051,7 @@ static inline int vb2_bufq_init(struct msm_vidc_inst *inst, q->ops = msm_venc_get_vb2q_ops(); q->mem_ops = &msm_vidc_vb2_mem_ops; q->drv_priv = inst; + q->allow_zero_bytesused = 1; return vb2_queue_init(q); } diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 56f6f6152845..dcaf9ce8d1bb 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -232,6 +232,7 @@ enum hal_property { HAL_PARAM_VENC_BITRATE_TYPE, HAL_PARAM_VENC_H264_PIC_ORDER_CNT, HAL_PARAM_VENC_LOW_LATENCY, + HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED, }; enum hal_domain { diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 385f99fe530d..04f006c50f27 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -369,6 +369,8 @@ struct hfi_buffer_info { (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x028) #define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x029) +#define HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02B) #define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02C) #define HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE \ diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c index c100c47d7641..5432ce83c9a2 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c +++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -164,7 +164,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, pr_debug("%s: dec buf size: %d, num_buf: %d, enc buf size: %d, num_buf: %d\n", __func__, effects->config.output.buf_size, - effects->config.output.buf_size, + effects->config.output.num_buf, effects->config.input.buf_size, effects->config.input.num_buf); rc = q6asm_audio_client_buf_alloc_contiguous(IN, effects->ac, @@ -252,7 +252,8 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, bufptr = q6asm_is_cpu_buf_avail(IN, effects->ac, &size, &idx); if (bufptr) { - if (copy_from_user(bufptr, (void *)arg, + if ((effects->config.buf_cfg.output_len > size) || + copy_from_user(bufptr, (void *)arg, effects->config.buf_cfg.output_len)) { rc = -EFAULT; goto ioctl_fail; @@ -308,7 +309,8 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, rc = -EFAULT; goto ioctl_fail; } - if (copy_to_user((void *)arg, bufptr, + if ((effects->config.buf_cfg.input_len > size) || + copy_to_user((void *)arg, bufptr, effects->config.buf_cfg.input_len)) { rc = -EFAULT; goto ioctl_fail; diff --git a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c index c388925f4679..521bdafab76f 100644 --- a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c +++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c @@ -23,49 +23,37 @@ #include <linux/types.h> #include <linux/ipv6.h> #include <net/addrconf.h> -#include <linux/ipc_logging.h> #include <linux/ipa.h> #include <linux/cdev.h> #include <linux/ipa_odu_bridge.h> +#include "../ipa_common_i.h" #define ODU_BRIDGE_DRV_NAME "odu_ipa_bridge" -#define ODU_IPC_LOG_PAGES 10 -#define ODU_IPC_LOG(buf, fmt, args...) \ - ipc_log_string((buf), \ - ODU_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) - #define ODU_BRIDGE_DBG(fmt, args...) \ do { \ pr_debug(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ __func__, __LINE__, ## args); \ - if (odu_bridge_ctx) { \ - ODU_IPC_LOG(odu_bridge_ctx->logbuf, \ - fmt, ## args); \ - ODU_IPC_LOG(odu_bridge_ctx->logbuf_low, \ - fmt, ## args); \ - } \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + ODU_BRIDGE_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + ODU_BRIDGE_DRV_NAME " %s:%d " fmt, ## args); \ } while (0) #define ODU_BRIDGE_DBG_LOW(fmt, args...) \ do { \ pr_debug(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ __func__, __LINE__, ## args); \ - if (odu_bridge_ctx && \ - odu_bridge_ctx->enable_low_prio_print) { \ - ODU_IPC_LOG(odu_bridge_ctx->logbuf_low, \ - fmt, ## args); \ - } \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + ODU_BRIDGE_DRV_NAME " %s:%d " fmt, ## args); \ } while (0) #define ODU_BRIDGE_ERR(fmt, args...) \ do { \ pr_err(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ __func__, __LINE__, ## args); \ - if (odu_bridge_ctx) { \ - ODU_IPC_LOG(odu_bridge_ctx->logbuf, \ - fmt, ## args); \ - ODU_IPC_LOG(odu_bridge_ctx->logbuf_low, \ - fmt, ## args); \ - } \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + ODU_BRIDGE_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + ODU_BRIDGE_DRV_NAME " %s:%d " fmt, ## args); \ } while (0) #define ODU_BRIDGE_FUNC_ENTRY() \ @@ -158,7 +146,6 @@ struct odu_bridge_ctx { u32 ipa_sys_desc_size; void *logbuf; void *logbuf_low; - u32 enable_low_prio_print; }; static struct odu_bridge_ctx *odu_bridge_ctx; @@ -683,7 +670,6 @@ static long compat_odu_bridge_ioctl(struct file *file, static struct dentry *dent; static struct dentry *dfile_stats; static struct dentry *dfile_mode; -static struct dentry *dfile_low_prio; static ssize_t odu_debugfs_stats(struct file *file, char __user *ubuf, @@ -806,15 +792,6 @@ static void odu_debugfs_init(void) goto fail; } - dfile_low_prio = debugfs_create_u32("enable_low_prio_print", - read_write_mode, - dent, &odu_bridge_ctx->enable_low_prio_print); - if (!dfile_low_prio) { - ODU_BRIDGE_ERR("could not create enable_low_prio_print file\n"); - goto fail; - } - - return; fail: debugfs_remove_recursive(dent); } @@ -1104,34 +1081,6 @@ static void odu_bridge_deregister_properties(void) ODU_BRIDGE_FUNC_EXIT(); } -static int odu_bridge_ipc_logging_init(void) -{ - int result; - - odu_bridge_ctx->logbuf = ipc_log_context_create(ODU_IPC_LOG_PAGES, - "ipa_odu_bridge", 0); - if (odu_bridge_ctx->logbuf == NULL) { - /* we can't use odu_bridge print macros on failures */ - pr_err("odu_bridge: failed to get logbuf\n"); - return -ENOMEM; - } - - odu_bridge_ctx->logbuf_low = - ipc_log_context_create(ODU_IPC_LOG_PAGES, - "ipa_odu_bridge_low", 0); - if (odu_bridge_ctx->logbuf_low == NULL) { - pr_err("odu_bridge: failed to get logbuf_low\n"); - result = -ENOMEM; - goto fail_logbuf_low; - } - - return 0; - -fail_logbuf_low: - ipc_log_context_destroy(odu_bridge_ctx->logbuf); - return result; -} - /** * odu_bridge_init() - Initialize the ODU bridge driver * @params: initialization parameters @@ -1183,13 +1132,6 @@ int odu_bridge_init(struct odu_bridge_params *params) return -ENOMEM; } - res = odu_bridge_ipc_logging_init(); - if (res) { - /* ODU_BRIDGE_ERR will crash on NULL if we use it here*/ - pr_err("odu_bridge: failed to initialize ipc logging\n"); - res = -EFAULT; - goto fail_ipc_create; - } odu_bridge_ctx->class = class_create(THIS_MODULE, ODU_BRIDGE_DRV_NAME); if (!odu_bridge_ctx->class) { ODU_BRIDGE_ERR("Class_create err.\n"); @@ -1264,9 +1206,6 @@ fail_device_create: fail_alloc_chrdev_region: class_destroy(odu_bridge_ctx->class); fail_class_create: - ipc_log_context_destroy(odu_bridge_ctx->logbuf); - ipc_log_context_destroy(odu_bridge_ctx->logbuf_low); -fail_ipc_create: kfree(odu_bridge_ctx); odu_bridge_ctx = NULL; return res; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 06f8ab6e3e94..feb6225470ab 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -3473,6 +3473,7 @@ static int apps_cons_request_resource(void) static void ipa_sps_release_resource(struct work_struct *work) { + mutex_lock(&ipa_ctx->sps_pm.sps_pm_lock); /* check whether still need to decrease client usage */ if (atomic_read(&ipa_ctx->sps_pm.dec_clients)) { if (atomic_read(&ipa_ctx->sps_pm.eot_activity)) { @@ -3484,6 +3485,7 @@ static void ipa_sps_release_resource(struct work_struct *work) } } atomic_set(&ipa_ctx->sps_pm.eot_activity, 0); + mutex_unlock(&ipa_ctx->sps_pm.sps_pm_lock); } int ipa_create_apps_resource(void) @@ -3946,6 +3948,9 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, wakeup_source_init(&ipa_ctx->w_lock, "IPA_WS"); spin_lock_init(&ipa_ctx->wakelock_ref_cnt.spinlock); + /* Initialize the SPS PM lock. */ + mutex_init(&ipa_ctx->sps_pm.sps_pm_lock); + /* Initialize IPA RM (resource manager) */ result = ipa_rm_initialize(); if (result) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index 35157f961231..2255a74331cb 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -497,7 +497,7 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, } } else { tx_pkt->mem.base = desc[i].frag; - tx_pkt->mem.size = skb_frag_size(desc[i].frag); + tx_pkt->mem.size = desc[i].len; if (!desc[i].dma_address_valid) { tx_pkt->mem.phys_base = @@ -815,6 +815,11 @@ static void ipa_rx_switch_to_intr_mode(struct ipa_sys_context *sys) { int ret; + if (!sys->ep || !sys->ep->valid) { + IPAERR("EP Not Valid, no need to cleanup.\n"); + return; + } + if (!atomic_read(&sys->curr_polling_state)) { IPAERR("already in intr mode\n"); goto fail; @@ -1427,8 +1432,11 @@ int ipa2_teardown_sys_pipe(u32 clnt_hdl) } while (1); } - if (IPA_CLIENT_IS_CONS(ep->client)) + if (IPA_CLIENT_IS_CONS(ep->client)) { cancel_delayed_work_sync(&ep->sys->replenish_rx_work); + cancel_delayed_work_sync(&ep->sys->switch_to_intr_work); + } + flush_workqueue(ep->sys->wq); sps_disconnect(ep->ep_hdl); dma_free_coherent(ipa_ctx->pdev, ep->connect.desc.size, @@ -1626,6 +1634,7 @@ int ipa2_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, for (f = 0; f < num_frags; f++) { desc[2+f].frag = &skb_shinfo(skb)->frags[f]; desc[2+f].type = IPA_DATA_DESC_SKB_PAGED; + desc[2+f].len = skb_frag_size(desc[2+f].frag); } /* don't free skb till frag mappings are released */ @@ -1665,6 +1674,7 @@ int ipa2_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, for (f = 0; f < num_frags; f++) { desc[1+f].frag = &skb_shinfo(skb)->frags[f]; desc[1+f].type = IPA_DATA_DESC_SKB_PAGED; + desc[1+f].len = skb_frag_size(desc[1+f].frag); } /* don't free skb till frag mappings are released */ diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index ce2ffc8f1cee..7d5daf202112 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -1111,10 +1111,12 @@ struct ipa_uc_wdi_ctx { * @dec_clients: true if need to decrease active clients count * @eot_activity: represent EOT interrupt activity to determine to reset * the inactivity timer + * @sps_pm_lock: Lock to protect the sps_pm functionality. */ struct ipa_sps_pm { atomic_t dec_clients; atomic_t eot_activity; + struct mutex sps_pm_lock; }; /** diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c index 70e0db98e948..00f18333587b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c @@ -46,7 +46,6 @@ static struct workqueue_struct *ipa_clnt_req_workqueue; static struct workqueue_struct *ipa_clnt_resp_workqueue; static void *curr_conn; static bool qmi_modem_init_fin, qmi_indication_fin; -static struct work_struct ipa_qmi_service_init_work; static uint32_t ipa_wan_platform; struct ipa_qmi_context *ipa_qmi_ctx; static bool first_time_handshake; @@ -855,11 +854,6 @@ static int ipa_q6_clnt_svc_event_notify(struct notifier_block *this, queue_delayed_work(ipa_clnt_req_workqueue, &work_svc_arrive, 0); break; - case QMI_SERVER_EXIT: - if (!atomic_read(&workqueues_stopped)) - queue_delayed_work(ipa_clnt_req_workqueue, - &work_svc_exit, 0); - break; default: break; } @@ -871,7 +865,7 @@ static struct notifier_block ipa_q6_clnt_nb = { .notifier_call = ipa_q6_clnt_svc_event_notify, }; -static void ipa_qmi_service_init_worker(struct work_struct *work) +static void ipa_qmi_service_init_worker(void) { int rc; @@ -968,9 +962,7 @@ int ipa_qmi_service_init(uint32_t wan_platform_type) atomic_set(&workqueues_stopped, 0); if (0 == atomic_read(&ipa_qmi_initialized)) { - INIT_WORK(&ipa_qmi_service_init_work, - ipa_qmi_service_init_worker); - schedule_work(&ipa_qmi_service_init_work); + ipa_qmi_service_init_worker(); } return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index 449e9a1890b2..9d4704ded0c3 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -660,7 +660,9 @@ static int ipa_generate_rt_hw_tbl_v2(enum ipa_ip_type ip, return 0; proc_err: - dma_free_coherent(ipa_ctx->pdev, mem->size, mem->base, mem->phys_base); + if (mem->size) + dma_free_coherent(ipa_ctx->pdev, mem->size, mem->base, + mem->phys_base); base_err: dma_free_coherent(ipa_ctx->pdev, head->size, head->base, head->phys_base); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c index b49815b24bc2..d529622f1e19 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c @@ -17,7 +17,9 @@ #define IPA_PKT_FLUSH_TO_US 100 #define IPA_UC_POLL_SLEEP_USEC 100 #define IPA_UC_POLL_MAX_RETRY 10000 +#define HOLB_WORKQUEUE_NAME "ipa_holb_wq" +static struct workqueue_struct *ipa_holb_wq; static void ipa_start_monitor_holb(struct work_struct *work); static DECLARE_WORK(ipa_holb_work, ipa_start_monitor_holb); @@ -470,7 +472,7 @@ static void ipa_uc_response_hdlr(enum ipa_irq_type interrupt, * pipe if valid. */ if (ipa_ctx->ipa_hw_type == IPA_HW_v2_6L) - queue_work(ipa_ctx->power_mgmt_wq, &ipa_holb_work); + queue_work(ipa_holb_wq, &ipa_holb_work); } else if (ipa_ctx->uc_ctx.uc_sram_mmio->responseOp == IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED) { uc_rsp.raw32b = ipa_ctx->uc_ctx.uc_sram_mmio->responseParams; @@ -508,6 +510,13 @@ int ipa_uc_interface_init(void) return 0; } + ipa_holb_wq = create_singlethread_workqueue( + HOLB_WORKQUEUE_NAME); + if (!ipa_holb_wq) { + IPAERR("HOLB workqueue creation failed\n"); + return -ENOMEM; + } + mutex_init(&ipa_ctx->uc_ctx.uc_lock); if (ipa_ctx->ipa_hw_type >= IPA_HW_v2_5) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 672568468c47..6fd9b4e61e02 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -662,11 +662,14 @@ int ipa2_resume_resource(enum ipa_rm_resource_name resource) IPADBG("%d will be resumed on connect.\n", client); if (ipa_ctx->ep[ipa_ep_idx].client == client && ipa_should_pipe_be_suspended(client)) { - if (ipa_ctx->ep[ipa_ep_idx].valid) { + spin_lock(&ipa_ctx->disconnect_lock); + if (ipa_ctx->ep[ipa_ep_idx].valid && + !ipa_ctx->ep[ipa_ep_idx].disconnect_in_progress) { memset(&suspend, 0, sizeof(suspend)); suspend.ipa_ep_suspend = false; ipa2_cfg_ep_ctrl(ipa_ep_idx, &suspend); } + spin_unlock(&ipa_ctx->disconnect_lock); } } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c index 966f279d863b..9d1ff18d7ed0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -33,16 +33,38 @@ #define IPADMA_DRV_NAME "ipa_dma" #define IPADMA_DBG(fmt, args...) \ - pr_debug(IPADMA_DRV_NAME " %s:%d " fmt, \ - __func__, __LINE__, ## args) + do { \ + pr_debug(IPADMA_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPADMA_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPADMA_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPADMA_DBG_LOW(fmt, args...) \ + do { \ + pr_debug(IPADMA_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPADMA_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + #define IPADMA_ERR(fmt, args...) \ - pr_err(IPADMA_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_err(IPADMA_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPADMA_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPADMA_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) #define IPADMA_FUNC_ENTRY() \ - IPADMA_DBG("ENTRY\n") + IPADMA_DBG_LOW("ENTRY\n") #define IPADMA_FUNC_EXIT() \ - IPADMA_DBG("EXIT\n") + IPADMA_DBG_LOW("EXIT\n") #ifdef CONFIG_DEBUG_FS #define IPADMA_MAX_MSG_LEN 1024 @@ -255,7 +277,7 @@ int ipa3_dma_enable(void) } mutex_lock(&ipa3_dma_ctx->enable_lock); if (ipa3_dma_ctx->is_enabled) { - IPADMA_DBG("Already enabled.\n"); + IPADMA_ERR("Already enabled.\n"); mutex_unlock(&ipa3_dma_ctx->enable_lock); return -EPERM; } @@ -281,7 +303,7 @@ static bool ipa3_dma_work_pending(void) IPADMA_DBG("pending uc\n"); return true; } - IPADMA_DBG("no pending work\n"); + IPADMA_DBG_LOW("no pending work\n"); return false; } @@ -309,7 +331,7 @@ int ipa3_dma_disable(void) mutex_lock(&ipa3_dma_ctx->enable_lock); spin_lock_irqsave(&ipa3_dma_ctx->pending_lock, flags); if (!ipa3_dma_ctx->is_enabled) { - IPADMA_DBG("Already disabled.\n"); + IPADMA_ERR("Already disabled.\n"); spin_unlock_irqrestore(&ipa3_dma_ctx->pending_lock, flags); mutex_unlock(&ipa3_dma_ctx->enable_lock); return -EPERM; @@ -358,7 +380,7 @@ int ipa3_dma_sync_memcpy(u64 dest, u64 src, int len) bool stop_polling = false; IPADMA_FUNC_ENTRY(); - IPADMA_DBG("input parameters: dest = 0x%llx, src = 0x%llx, len = %d\n", + IPADMA_DBG_LOW("dest = 0x%llx, src = 0x%llx, len = %d\n", dest, src, len); if (ipa3_dma_ctx == NULL) { IPADMA_ERR("IPADMA isn't initialized, can't memcpy\n"); @@ -390,7 +412,7 @@ int ipa3_dma_sync_memcpy(u64 dest, u64 src, int len) if (atomic_read(&ipa3_dma_ctx->sync_memcpy_pending_cnt) >= IPA_DMA_MAX_PENDING_SYNC) { atomic_dec(&ipa3_dma_ctx->sync_memcpy_pending_cnt); - IPADMA_DBG("Reached pending requests limit\n"); + IPADMA_ERR("Reached pending requests limit\n"); return -EFAULT; } } @@ -575,7 +597,7 @@ int ipa3_dma_async_memcpy(u64 dest, u64 src, int len, unsigned long flags; IPADMA_FUNC_ENTRY(); - IPADMA_DBG("input parameters: dest = 0x%llx, src = 0x%llx, len = %d\n", + IPADMA_DBG_LOW("dest = 0x%llx, src = 0x%llx, len = %d\n", dest, src, len); if (ipa3_dma_ctx == NULL) { IPADMA_ERR("IPADMA isn't initialized, can't memcpy\n"); @@ -612,7 +634,7 @@ int ipa3_dma_async_memcpy(u64 dest, u64 src, int len, if (atomic_read(&ipa3_dma_ctx->async_memcpy_pending_cnt) >= IPA_DMA_MAX_PENDING_ASYNC) { atomic_dec(&ipa3_dma_ctx->async_memcpy_pending_cnt); - IPADMA_DBG("Reached pending requests limit\n"); + IPADMA_ERR("Reached pending requests limit\n"); return -EFAULT; } } @@ -774,7 +796,7 @@ void ipa3_dma_destroy(void) IPADMA_FUNC_ENTRY(); if (!ipa3_dma_ctx) { - IPADMA_DBG("IPADMA isn't initialized\n"); + IPADMA_ERR("IPADMA isn't initialized\n"); return; } @@ -919,7 +941,7 @@ static ssize_t ipa3_dma_debugfs_reset_statistics(struct file *file, switch (in_num) { case 0: if (ipa3_dma_work_pending()) - IPADMA_DBG("Note, there are pending memcpy\n"); + IPADMA_ERR("Note, there are pending memcpy\n"); atomic_set(&ipa3_dma_ctx->total_async_memcpy, 0); atomic_set(&ipa3_dma_ctx->total_sync_memcpy, 0); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index f58751d4c0d3..f0f79d066f0b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -22,12 +22,6 @@ static const u32 ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN_MAX] = { 32, 64}; #define HDR_PROC_TYPE_IS_VALID(type) \ ((type) >= 0 && (type) < IPA_HDR_PROC_MAX) -/* uCP command numbers */ -#define IPA_HDR_UCP_802_3_TO_802_3 6 -#define IPA_HDR_UCP_802_3_TO_ETHII 7 -#define IPA_HDR_UCP_ETHII_TO_802_3 8 -#define IPA_HDR_UCP_ETHII_TO_ETHII 9 - /** * ipa3_generate_hdr_hw_tbl() - generates the headers table * @mem: [out] buffer to put the header table @@ -60,70 +54,36 @@ static int ipa3_generate_hdr_hw_tbl(struct ipa3_mem_buffer *mem) continue; IPADBG_LOW("hdr of len %d ofst=%d\n", entry->hdr_len, entry->offset_entry->offset); - memcpy(mem->base + entry->offset_entry->offset, entry->hdr, - entry->hdr_len); + ipahal_cp_hdr_to_hw_buff(mem->base, entry->offset_entry->offset, + entry->hdr, entry->hdr_len); } return 0; } -static void ipa3_hdr_proc_ctx_to_hw_format(struct ipa3_mem_buffer *mem, +static int ipa3_hdr_proc_ctx_to_hw_format(struct ipa3_mem_buffer *mem, u32 hdr_base_addr) { struct ipa3_hdr_proc_ctx_entry *entry; + int ret; list_for_each_entry(entry, &ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list, link) { IPADBG_LOW("processing type %d ofst=%d\n", entry->type, entry->offset_entry->offset); - if (entry->type == IPA_HDR_PROC_NONE) { - struct ipa3_hdr_proc_ctx_add_hdr_seq *ctx; - - ctx = (struct ipa3_hdr_proc_ctx_add_hdr_seq *) - (mem->base + entry->offset_entry->offset); - ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD; - ctx->hdr_add.tlv.length = 1; - ctx->hdr_add.tlv.value = entry->hdr->hdr_len; - ctx->hdr_add.hdr_addr = (entry->hdr->is_hdr_proc_ctx) ? - entry->hdr->phys_base : - hdr_base_addr + - entry->hdr->offset_entry->offset; - IPADBG_LOW("header address 0x%x\n", - ctx->hdr_add.hdr_addr); - ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END; - ctx->end.length = 0; - ctx->end.value = 0; - } else { - struct ipa3_hdr_proc_ctx_add_hdr_cmd_seq *ctx; - - ctx = (struct ipa3_hdr_proc_ctx_add_hdr_cmd_seq *) - (mem->base + entry->offset_entry->offset); - ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD; - ctx->hdr_add.tlv.length = 1; - ctx->hdr_add.tlv.value = entry->hdr->hdr_len; - ctx->hdr_add.hdr_addr = (entry->hdr->is_hdr_proc_ctx) ? - entry->hdr->phys_base : - hdr_base_addr + - entry->hdr->offset_entry->offset; - IPADBG_LOW("header address 0x%x\n", - ctx->hdr_add.hdr_addr); - ctx->cmd.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD; - ctx->cmd.length = 0; - if (entry->type == IPA_HDR_PROC_ETHII_TO_ETHII) - ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_ETHII; - else if (entry->type == IPA_HDR_PROC_ETHII_TO_802_3) - ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_802_3; - else if (entry->type == IPA_HDR_PROC_802_3_TO_ETHII) - ctx->cmd.value = IPA_HDR_UCP_802_3_TO_ETHII; - else if (entry->type == IPA_HDR_PROC_802_3_TO_802_3) - ctx->cmd.value = IPA_HDR_UCP_802_3_TO_802_3; - IPADBG_LOW("command id %d\n", ctx->cmd.value); - ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END; - ctx->end.length = 0; - ctx->end.value = 0; - } + ret = ipahal_cp_proc_ctx_to_hw_buff(entry->type, mem->base, + entry->offset_entry->offset, + entry->hdr->hdr_len, + entry->hdr->is_hdr_proc_ctx, + entry->hdr->phys_base, + hdr_base_addr, + entry->hdr->offset_entry->offset); + if (ret) + return ret; } + + return 0; } /** @@ -162,9 +122,7 @@ static int ipa3_generate_hdr_proc_ctx_hw_tbl(u32 hdr_sys_addr, memset(aligned_mem->base, 0, aligned_mem->size); hdr_base_addr = (ipa3_ctx->hdr_tbl_lcl) ? IPA_MEM_PART(apps_hdr_ofst) : hdr_sys_addr; - ipa3_hdr_proc_ctx_to_hw_format(aligned_mem, hdr_base_addr); - - return 0; + return ipa3_hdr_proc_ctx_to_hw_format(aligned_mem, hdr_base_addr); } /** @@ -395,9 +353,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, hdr_entry->ref_cnt++; entry->cookie = IPA_COOKIE; - needed_len = (proc_ctx->type == IPA_HDR_PROC_NONE) ? - sizeof(struct ipa3_hdr_proc_ctx_add_hdr_seq) : - sizeof(struct ipa3_hdr_proc_ctx_add_hdr_cmd_seq); + needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type); if (needed_len <= ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN0]) { bin = IPA_HDR_PROC_CTX_BIN0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_defs.h b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_defs.h index 1b732efe2b2c..38a63f8a67ba 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_defs.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_defs.h @@ -16,11 +16,6 @@ /* This header defines various HW related data types */ -/* Processing context TLV type */ -#define IPA_PROC_CTX_TLV_TYPE_END 0 -#define IPA_PROC_CTX_TLV_TYPE_HDR_ADD 1 -#define IPA_PROC_CTX_TLV_TYPE_PROC_CMD 3 - #define IPA_RULE_ID_INVALID 0x3FF /** @@ -94,40 +89,6 @@ struct ipa3_rt_rule_hw_hdr { } u; }; -/** - * struct ipa3_hdr_proc_ctx_tlv - - * HW structure of IPA processing context header - TLV part - * @type: 0 - end type - * 1 - header addition type - * 3 - processing command type - * @length: number of bytes after tlv - * for type: - * 0 - needs to be 0 - * 1 - header addition length - * 3 - number of 32B including type and length. - * @value: specific value for type - * for type: - * 0 - needs to be 0 - * 1 - header length - * 3 - command ID (see IPA_HDR_UCP_* definitions) - */ -struct ipa3_hdr_proc_ctx_tlv { - u32 type:8; - u32 length:8; - u32 value:16; -}; - -/** - * struct ipa3_hdr_proc_ctx_hdr_add - - * HW structure of IPA processing context - add header tlv - * @tlv: IPA processing context TLV - * @hdr_addr: processing context header address - */ -struct ipa3_hdr_proc_ctx_hdr_add { - struct ipa3_hdr_proc_ctx_tlv tlv; - u32 hdr_addr; -}; - #define IPA_A5_MUX_HDR_EXCP_FLAG_IP BIT(7) #define IPA_A5_MUX_HDR_EXCP_FLAG_NAT BIT(6) #define IPA_A5_MUX_HDR_EXCP_FLAG_SW_FLT BIT(5) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index a21df09b7059..cec83ef7a202 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -396,30 +396,6 @@ struct ipa3_hdr_proc_ctx_offset_entry { }; /** - * struct ipa3_hdr_proc_ctx_add_hdr_seq - - * IPA processing context header - add header sequence - * @hdr_add: add header command - * @end: tlv end command (cmd.type must be 0) - */ -struct ipa3_hdr_proc_ctx_add_hdr_seq { - struct ipa3_hdr_proc_ctx_hdr_add hdr_add; - struct ipa3_hdr_proc_ctx_tlv end; -}; - -/** - * struct ipa3_hdr_proc_ctx_add_hdr_cmd_seq - - * IPA processing context header - process command sequence - * @hdr_add: add header command - * @cmd: tlv processing command (cmd.type must be 3) - * @end: tlv end command (cmd.type must be 0) - */ -struct ipa3_hdr_proc_ctx_add_hdr_cmd_seq { - struct ipa3_hdr_proc_ctx_hdr_add hdr_add; - struct ipa3_hdr_proc_ctx_tlv cmd; - struct ipa3_hdr_proc_ctx_tlv end; -}; - -/** struct ipa3_hdr_proc_ctx_entry - IPA processing context header table entry * @link: entry's link in global header table entries list * @type: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 401bb0f61ee8..517093adbe81 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -21,15 +21,42 @@ #include "ipa_qmi_service.h" #define IPA_MHI_DRV_NAME "ipa_mhi" + + #define IPA_MHI_DBG(fmt, args...) \ - pr_debug(IPA_MHI_DRV_NAME " %s:%d " fmt, \ - __func__, __LINE__, ## args) + do { \ + pr_debug(IPA_MHI_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_MHI_DBG_LOW(fmt, args...) \ + do { \ + pr_debug(IPA_MHI_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + + #define IPA_MHI_ERR(fmt, args...) \ - pr_err(IPA_MHI_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_err(IPA_MHI_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + + #define IPA_MHI_FUNC_ENTRY() \ - IPA_MHI_DBG("ENTRY\n") + IPA_MHI_DBG_LOW("ENTRY\n") #define IPA_MHI_FUNC_EXIT() \ - IPA_MHI_DBG("EXIT\n") + IPA_MHI_DBG_LOW("EXIT\n") #define IPA_MHI_GSI_ER_START 10 #define IPA_MHI_GSI_ER_END 16 @@ -756,12 +783,12 @@ static void ipa3_mhi_rm_prod_notify(void *user_data, enum ipa_rm_event event, switch (event) { case IPA_RM_RESOURCE_GRANTED: - IPA_MHI_DBG("IPA_RM_RESOURCE_GRANTED\n"); + IPA_MHI_DBG_LOW("IPA_RM_RESOURCE_GRANTED\n"); complete_all(&ipa3_mhi_ctx->rm_prod_granted_comp); break; case IPA_RM_RESOURCE_RELEASED: - IPA_MHI_DBG("IPA_RM_RESOURCE_RELEASED\n"); + IPA_MHI_DBG_LOW("IPA_RM_RESOURCE_RELEASED\n"); break; default: @@ -828,7 +855,7 @@ static int ipa3_mhi_rm_cons_request(void) } spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags); - IPA_MHI_DBG("EXIT with %d\n", res); + IPA_MHI_DBG_LOW("EXIT with %d\n", res); return res; } @@ -878,7 +905,7 @@ static int ipa3_mhi_request_prod(void) IPA_MHI_FUNC_ENTRY(); reinit_completion(&ipa3_mhi_ctx->rm_prod_granted_comp); - IPA_MHI_DBG("requesting mhi prod\n"); + IPA_MHI_DBG_LOW("requesting mhi prod\n"); res = ipa_rm_request_resource(IPA_RM_RESOURCE_MHI_PROD); if (res) { if (res != -EINPROGRESS) { @@ -894,7 +921,7 @@ static int ipa3_mhi_request_prod(void) } } - IPA_MHI_DBG("mhi prod granted\n"); + IPA_MHI_DBG_LOW("mhi prod granted\n"); IPA_MHI_FUNC_EXIT(); return 0; @@ -1071,11 +1098,12 @@ static bool ipa3_mhi_gsi_channel_empty(struct ipa3_mhi_channel_ctx *channel) IPA_MHI_FUNC_ENTRY(); if (!channel->stop_in_proc) { - IPA_MHI_DBG("Channel is not in STOP_IN_PROC\n"); + IPA_MHI_DBG_LOW("Channel is not in STOP_IN_PROC\n"); return true; } - IPA_MHI_DBG("Stopping GSI channel %ld\n", channel->ep->gsi_chan_hdl); + IPA_MHI_DBG_LOW("Stopping GSI channel %ld\n", + channel->ep->gsi_chan_hdl); res = gsi_stop_channel(channel->ep->gsi_chan_hdl); if (res != 0 && res != -GSI_STATUS_AGAIN && @@ -1087,7 +1115,7 @@ static bool ipa3_mhi_gsi_channel_empty(struct ipa3_mhi_channel_ctx *channel) } if (res == 0) { - IPA_MHI_DBG("GSI channel %ld STOP\n", + IPA_MHI_DBG_LOW("GSI channel %ld STOP\n", channel->ep->gsi_chan_hdl); channel->stop_in_proc = false; return true; @@ -1129,7 +1157,7 @@ static bool ipa3_mhi_wait_for_ul_empty_timeout(unsigned int msecs) } if (time_after(jiffies, jiffies_start + jiffies_timeout)) { - IPA_MHI_DBG("timeout waiting for UL empty\n"); + IPA_MHI_DBG_LOW("timeout waiting for UL empty\n"); break; } @@ -1441,31 +1469,31 @@ static int ipa_mhi_start_uc_channel(struct ipa3_mhi_channel_ctx *channel, static void ipa_mhi_dump_ch_ctx(struct ipa3_mhi_channel_ctx *channel) { - IPA_MHI_DBG("ch_id %d\n", channel->id); - IPA_MHI_DBG("chstate 0x%x\n", channel->ch_ctx_host.chstate); - IPA_MHI_DBG("brstmode 0x%x\n", channel->ch_ctx_host.brstmode); - IPA_MHI_DBG("pollcfg 0x%x\n", channel->ch_ctx_host.pollcfg); - IPA_MHI_DBG("chtype 0x%x\n", channel->ch_ctx_host.chtype); - IPA_MHI_DBG("erindex 0x%x\n", channel->ch_ctx_host.erindex); - IPA_MHI_DBG("rbase 0x%llx\n", channel->ch_ctx_host.rbase); - IPA_MHI_DBG("rlen 0x%llx\n", channel->ch_ctx_host.rlen); - IPA_MHI_DBG("rp 0x%llx\n", channel->ch_ctx_host.rp); - IPA_MHI_DBG("wp 0x%llx\n", channel->ch_ctx_host.wp); + IPA_MHI_DBG_LOW("ch_id %d\n", channel->id); + IPA_MHI_DBG_LOW("chstate 0x%x\n", channel->ch_ctx_host.chstate); + IPA_MHI_DBG_LOW("brstmode 0x%x\n", channel->ch_ctx_host.brstmode); + IPA_MHI_DBG_LOW("pollcfg 0x%x\n", channel->ch_ctx_host.pollcfg); + IPA_MHI_DBG_LOW("chtype 0x%x\n", channel->ch_ctx_host.chtype); + IPA_MHI_DBG_LOW("erindex 0x%x\n", channel->ch_ctx_host.erindex); + IPA_MHI_DBG_LOW("rbase 0x%llx\n", channel->ch_ctx_host.rbase); + IPA_MHI_DBG_LOW("rlen 0x%llx\n", channel->ch_ctx_host.rlen); + IPA_MHI_DBG_LOW("rp 0x%llx\n", channel->ch_ctx_host.rp); + IPA_MHI_DBG_LOW("wp 0x%llx\n", channel->ch_ctx_host.wp); } static void ipa_mhi_dump_ev_ctx(struct ipa3_mhi_channel_ctx *channel) { - IPA_MHI_DBG("ch_id %d event id %d\n", channel->id, + IPA_MHI_DBG_LOW("ch_id %d event id %d\n", channel->id, channel->ch_ctx_host.erindex); - IPA_MHI_DBG("intmodc 0x%x\n", channel->ev_ctx_host.intmodc); - IPA_MHI_DBG("intmodt 0x%x\n", channel->ev_ctx_host.intmodt); - IPA_MHI_DBG("ertype 0x%x\n", channel->ev_ctx_host.ertype); - IPA_MHI_DBG("msivec 0x%x\n", channel->ev_ctx_host.msivec); - IPA_MHI_DBG("rbase 0x%llx\n", channel->ev_ctx_host.rbase); - IPA_MHI_DBG("rlen 0x%llx\n", channel->ev_ctx_host.rlen); - IPA_MHI_DBG("rp 0x%llx\n", channel->ev_ctx_host.rp); - IPA_MHI_DBG("wp 0x%llx\n", channel->ev_ctx_host.wp); + IPA_MHI_DBG_LOW("intmodc 0x%x\n", channel->ev_ctx_host.intmodc); + IPA_MHI_DBG_LOW("intmodt 0x%x\n", channel->ev_ctx_host.intmodt); + IPA_MHI_DBG_LOW("ertype 0x%x\n", channel->ev_ctx_host.ertype); + IPA_MHI_DBG_LOW("msivec 0x%x\n", channel->ev_ctx_host.msivec); + IPA_MHI_DBG_LOW("rbase 0x%llx\n", channel->ev_ctx_host.rbase); + IPA_MHI_DBG_LOW("rlen 0x%llx\n", channel->ev_ctx_host.rlen); + IPA_MHI_DBG_LOW("rp 0x%llx\n", channel->ev_ctx_host.rp); + IPA_MHI_DBG_LOW("wp 0x%llx\n", channel->ev_ctx_host.wp); } static int ipa_mhi_read_ch_ctx(struct ipa3_mhi_channel_ctx *channel) @@ -2235,7 +2263,7 @@ static int ipa3_mhi_suspend_ul_channels(void) if (ipa3_mhi_ctx->ul_channels[i].state != IPA_HW_MHI_CHANNEL_STATE_RUN) continue; - IPA_MHI_DBG("suspending channel %d\n", + IPA_MHI_DBG_LOW("suspending channel %d\n", ipa3_mhi_ctx->ul_channels[i].id); if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) @@ -2271,7 +2299,7 @@ static int ipa3_mhi_resume_ul_channels(bool LPTransitionRejected) IPA_HW_MHI_CHANNEL_STATE_SUSPEND) continue; channel = &ipa3_mhi_ctx->ul_channels[i]; - IPA_MHI_DBG("resuming channel %d\n", channel->id); + IPA_MHI_DBG_LOW("resuming channel %d\n", channel->id); if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) { if (channel->brstmode_enabled && @@ -2324,7 +2352,7 @@ static int ipa3_mhi_stop_event_update_ul_channels(void) if (ipa3_mhi_ctx->ul_channels[i].state != IPA_HW_MHI_CHANNEL_STATE_SUSPEND) continue; - IPA_MHI_DBG("stop update event channel %d\n", + IPA_MHI_DBG_LOW("stop update event channel %d\n", ipa3_mhi_ctx->ul_channels[i].id); res = ipa3_uc_mhi_stop_event_update_channel( ipa3_mhi_ctx->ul_channels[i].index); @@ -2351,7 +2379,7 @@ static int ipa3_mhi_suspend_dl_channels(void) if (ipa3_mhi_ctx->dl_channels[i].state != IPA_HW_MHI_CHANNEL_STATE_RUN) continue; - IPA_MHI_DBG("suspending channel %d\n", + IPA_MHI_DBG_LOW("suspending channel %d\n", ipa3_mhi_ctx->dl_channels[i].id); if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) res = ipa3_mhi_suspend_gsi_channel( @@ -2386,7 +2414,7 @@ static int ipa3_mhi_resume_dl_channels(bool LPTransitionRejected) IPA_HW_MHI_CHANNEL_STATE_SUSPEND) continue; channel = &ipa3_mhi_ctx->dl_channels[i]; - IPA_MHI_DBG("resuming channel %d\n", channel->id); + IPA_MHI_DBG_LOW("resuming channel %d\n", channel->id); if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) { if (channel->brstmode_enabled && @@ -2437,7 +2465,7 @@ static int ipa3_mhi_stop_event_update_dl_channels(void) if (ipa3_mhi_ctx->dl_channels[i].state != IPA_HW_MHI_CHANNEL_STATE_SUSPEND) continue; - IPA_MHI_DBG("stop update event channel %d\n", + IPA_MHI_DBG_LOW("stop update event channel %d\n", ipa3_mhi_ctx->dl_channels[i].id); res = ipa3_uc_mhi_stop_event_update_channel( ipa3_mhi_ctx->dl_channels[i].index); @@ -2577,7 +2605,7 @@ static bool ipa3_mhi_has_open_aggr_frame(void) int ipa_ep_idx; aggr_state_active = ipahal_read_reg(IPA_STATE_AGGR_ACTIVE); - IPA_MHI_DBG("IPA_STATE_AGGR_ACTIVE_OFST 0x%x\n", aggr_state_active); + IPA_MHI_DBG_LOW("IPA_STATE_AGGR_ACTIVE_OFST 0x%x\n", aggr_state_active); for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) { channel = &ipa3_mhi_ctx->dl_channels[i]; @@ -2647,7 +2675,7 @@ int ipa3_mhi_suspend(bool force) return res; } force_clear = true; - IPA_MHI_DBG("force clear datapath enabled\n"); + IPA_MHI_DBG_LOW("force clear datapath enabled\n"); empty = ipa3_mhi_wait_for_ul_empty_timeout( IPA_MHI_CH_EMPTY_TIMEOUT_MSEC); @@ -2676,7 +2704,7 @@ int ipa3_mhi_suspend(bool force) BUG(); return res; } - IPA_MHI_DBG("force clear datapath disabled\n"); + IPA_MHI_DBG_LOW("force clear datapath disabled\n"); ipa3_mhi_ctx->qmi_req_id++; } @@ -2701,14 +2729,14 @@ int ipa3_mhi_suspend(bool force) */ IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - IPA_MHI_DBG("release prod\n"); + IPA_MHI_DBG_LOW("release prod\n"); res = ipa3_mhi_release_prod(); if (res) { IPA_MHI_ERR("ipa3_mhi_release_prod failed %d\n", res); goto fail_release_prod; } - IPA_MHI_DBG("wait for cons release\n"); + IPA_MHI_DBG_LOW("wait for cons release\n"); res = ipa3_mhi_wait_for_cons_release(); if (res) { IPA_MHI_ERR("ipa3_mhi_wait_for_cons_release failed %d\n", res); @@ -2772,7 +2800,7 @@ fail_suspend_ul_channel: IPA_MHI_ERR("failed to disable force clear\n"); BUG(); } - IPA_MHI_DBG("force clear datapath disabled\n"); + IPA_MHI_DBG_LOW("force clear datapath disabled\n"); ipa3_mhi_ctx->qmi_req_id++; } return res; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 4cd655aa8124..6444dcf3cfdc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -356,7 +356,7 @@ static void ipa3_a5_svc_recv_msg(struct work_struct *work) int rc; do { - IPAWANDBG("Notified about a Receive Event"); + IPAWANDBG_LOW("Notified about a Receive Event"); rc = qmi_recv_msg(ipa3_svc_handle); } while (rc == 0); if (rc != -ENOMSG) @@ -430,7 +430,7 @@ static int ipa3_check_qmi_response(int rc, req_id, result, error); return result; } - IPAWANDBG("Received %s successfully\n", resp_type); + IPAWANDBG_LOW("Received %s successfully\n", resp_type); return 0; } @@ -762,7 +762,7 @@ static void ipa3_q6_clnt_recv_msg(struct work_struct *work) int rc; do { - IPAWANDBG("Notified about a Receive Event"); + IPAWANDBG_LOW("Notified about a Receive Event"); rc = qmi_recv_msg(ipa_q6_clnt); } while (rc == 0); if (rc != -ENOMSG) @@ -774,7 +774,7 @@ static void ipa3_q6_clnt_notify(struct qmi_handle *handle, { switch (event) { case QMI_RECV_MSG: - IPAWANDBG("client qmi recv message called"); + IPAWANDBG_LOW("client qmi recv message called"); if (!workqueues_stopped) queue_delayed_work(ipa_clnt_resp_workqueue, &ipa3_work_recv_msg_client, 0); @@ -1154,7 +1154,7 @@ int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req, resp_desc.msg_id = QMI_IPA_GET_DATA_STATS_RESP_V01; resp_desc.ei_array = ipa3_get_data_stats_resp_msg_data_v01_ei; - IPAWANDBG("Sending QMI_IPA_GET_DATA_STATS_REQ_V01\n"); + IPAWANDBG_LOW("Sending QMI_IPA_GET_DATA_STATS_REQ_V01\n"); rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req, sizeof(struct ipa_get_data_stats_req_msg_v01), @@ -1162,7 +1162,7 @@ int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req, sizeof(struct ipa_get_data_stats_resp_msg_v01), QMI_SEND_STATS_REQ_TIMEOUT_MS); - IPAWANDBG("QMI_IPA_GET_DATA_STATS_RESP_V01 received\n"); + IPAWANDBG_LOW("QMI_IPA_GET_DATA_STATS_RESP_V01 received\n"); return ipa3_check_qmi_response(rc, QMI_IPA_GET_DATA_STATS_REQ_V01, resp->resp.result, @@ -1183,7 +1183,7 @@ int ipa3_qmi_get_network_stats(struct ipa_get_apn_data_stats_req_msg_v01 *req, resp_desc.msg_id = QMI_IPA_GET_APN_DATA_STATS_RESP_V01; resp_desc.ei_array = ipa3_get_apn_data_stats_resp_msg_data_v01_ei; - IPAWANDBG("Sending QMI_IPA_GET_APN_DATA_STATS_REQ_V01\n"); + IPAWANDBG_LOW("Sending QMI_IPA_GET_APN_DATA_STATS_REQ_V01\n"); rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req, sizeof(struct ipa_get_apn_data_stats_req_msg_v01), @@ -1191,7 +1191,7 @@ int ipa3_qmi_get_network_stats(struct ipa_get_apn_data_stats_req_msg_v01 *req, sizeof(struct ipa_get_apn_data_stats_resp_msg_v01), QMI_SEND_STATS_REQ_TIMEOUT_MS); - IPAWANDBG("QMI_IPA_GET_APN_DATA_STATS_RESP_V01 received\n"); + IPAWANDBG_LOW("QMI_IPA_GET_APN_DATA_STATS_RESP_V01 received\n"); return ipa3_check_qmi_response(rc, QMI_IPA_GET_APN_DATA_STATS_REQ_V01, resp->resp.result, @@ -1215,14 +1215,14 @@ int ipa3_qmi_set_data_quota(struct ipa_set_data_usage_quota_req_msg_v01 *req) resp_desc.msg_id = QMI_IPA_SET_DATA_USAGE_QUOTA_RESP_V01; resp_desc.ei_array = ipa3_set_data_usage_quota_resp_msg_data_v01_ei; - IPAWANDBG("Sending QMI_IPA_SET_DATA_USAGE_QUOTA_REQ_V01\n"); + IPAWANDBG_LOW("Sending QMI_IPA_SET_DATA_USAGE_QUOTA_REQ_V01\n"); rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req, sizeof(struct ipa_set_data_usage_quota_req_msg_v01), &resp_desc, &resp, sizeof(resp), QMI_SEND_STATS_REQ_TIMEOUT_MS); - IPAWANDBG("QMI_IPA_SET_DATA_USAGE_QUOTA_RESP_V01 received\n"); + IPAWANDBG_LOW("QMI_IPA_SET_DATA_USAGE_QUOTA_RESP_V01 received\n"); return ipa3_check_qmi_response(rc, QMI_IPA_SET_DATA_USAGE_QUOTA_REQ_V01, resp.resp.result, @@ -1249,13 +1249,13 @@ int ipa3_qmi_stop_data_qouta(void) resp_desc.msg_id = QMI_IPA_STOP_DATA_USAGE_QUOTA_RESP_V01; resp_desc.ei_array = ipa3_stop_data_usage_quota_resp_msg_data_v01_ei; - IPAWANDBG("Sending QMI_IPA_STOP_DATA_USAGE_QUOTA_REQ_V01\n"); + IPAWANDBG_LOW("Sending QMI_IPA_STOP_DATA_USAGE_QUOTA_REQ_V01\n"); rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), QMI_SEND_STATS_REQ_TIMEOUT_MS); - IPAWANDBG("QMI_IPA_STOP_DATA_USAGE_QUOTA_RESP_V01 received\n"); + IPAWANDBG_LOW("QMI_IPA_STOP_DATA_USAGE_QUOTA_RESP_V01 received\n"); return ipa3_check_qmi_response(rc, QMI_IPA_STOP_DATA_USAGE_QUOTA_REQ_V01, resp.resp.result, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h index 5f6722d3fbac..0f641204cc77 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h @@ -31,11 +31,39 @@ #define SUBSYS_MODEM "modem" #define IPAWANDBG(fmt, args...) \ - pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + DEV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + DEV_NAME " %s:%d " fmt, ## args); \ + } while (0) + + +#define IPAWANDBG_LOW(fmt, args...) \ + do { \ + pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + DEV_NAME " %s:%d " fmt, ## args); \ + } while (0) + #define IPAWANERR(fmt, args...) \ - pr_err(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_err(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + DEV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + DEV_NAME " %s:%d " fmt, ## args); \ + } while (0) + #define IPAWANINFO(fmt, args...) \ - pr_info(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_info(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + DEV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + DEV_NAME " %s:%d " fmt, ## args); \ + } while (0) extern struct ipa3_qmi_context *ipa3_qmi_ctx; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index 9f98d3ffef30..d0b1b525d95a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -1018,6 +1018,229 @@ static void ipahal_debugfs_init(void) {} static void ipahal_debugfs_remove(void) {} #endif /* CONFIG_DEBUG_FS */ +/* + * ipahal_cp_hdr_to_hw_buff_v3() - copy header to hardware buffer according to + * base address and offset given. + * @base: dma base address + * @offset: offset from base address where the data will be copied + * @hdr: the header to be copied + * @hdr_len: the length of the header + */ +static void ipahal_cp_hdr_to_hw_buff_v3(void *const base, u32 offset, + u8 *const hdr, u32 hdr_len) +{ + memcpy(base + offset, hdr, hdr_len); +} + +/* + * ipahal_cp_proc_ctx_to_hw_buff_v3() - copy processing context to + * base address and offset given. + * @type: header processing context type (no processing context, + * IPA_HDR_PROC_ETHII_TO_ETHII etc.) + * @base: dma base address + * @offset: offset from base address where the data will be copied + * @hdr_len: the length of the header + * @is_hdr_proc_ctx: header is located in phys_base (true) or hdr_base_addr + * @phys_base: memory location in DDR + * @hdr_base_addr: base address in table + * @hdr_offset_entry: offset from hdr_base_addr in table + */ +static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type, + void *const base, u32 offset, + u32 hdr_len, bool is_hdr_proc_ctx, + dma_addr_t phys_base, u32 hdr_base_addr, + u32 hdr_offset_entry){ + if (type == IPA_HDR_PROC_NONE) { + struct ipa_hw_hdr_proc_ctx_add_hdr_seq *ctx; + + ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_seq *) + (base + offset); + ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD; + ctx->hdr_add.tlv.length = 1; + ctx->hdr_add.tlv.value = hdr_len; + ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base : + hdr_base_addr + hdr_offset_entry; + IPAHAL_DBG("header address 0x%x\n", + ctx->hdr_add.hdr_addr); + ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END; + ctx->end.length = 0; + ctx->end.value = 0; + } else { + struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *ctx; + + ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *) + (base + offset); + ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD; + ctx->hdr_add.tlv.length = 1; + ctx->hdr_add.tlv.value = hdr_len; + ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base : + hdr_base_addr + hdr_offset_entry; + IPAHAL_DBG("header address 0x%x\n", + ctx->hdr_add.hdr_addr); + ctx->cmd.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD; + ctx->cmd.length = 0; + switch (type) { + case IPA_HDR_PROC_ETHII_TO_ETHII: + ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_ETHII; + break; + case IPA_HDR_PROC_ETHII_TO_802_3: + ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_802_3; + break; + case IPA_HDR_PROC_802_3_TO_ETHII: + ctx->cmd.value = IPA_HDR_UCP_802_3_TO_ETHII; + break; + case IPA_HDR_PROC_802_3_TO_802_3: + ctx->cmd.value = IPA_HDR_UCP_802_3_TO_802_3; + break; + default: + IPAHAL_ERR("unknown ipa_hdr_proc_type %d", type); + WARN_ON(1); + return -EINVAL; + } + IPAHAL_DBG("command id %d\n", ctx->cmd.value); + ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END; + ctx->end.length = 0; + ctx->end.value = 0; + } + + return 0; +} + +/* + * ipahal_get_proc_ctx_needed_len_v3() - calculates the needed length for + * addition of header processing context according to the type of processing + * context. + * @type: header processing context type (no processing context, + * IPA_HDR_PROC_ETHII_TO_ETHII etc.) + */ +static int ipahal_get_proc_ctx_needed_len_v3(enum ipa_hdr_proc_type type) +{ + return (type == IPA_HDR_PROC_NONE) ? + sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_seq) : + sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq); +} + +/* + * struct ipahal_hdr_funcs - headers handling functions for specific IPA + * version + * @ipahal_cp_hdr_to_hw_buff - copy function for regular headers + */ +struct ipahal_hdr_funcs { + void (*ipahal_cp_hdr_to_hw_buff)(void *const base, u32 offset, + u8 *const hdr, u32 hdr_len); + + int (*ipahal_cp_proc_ctx_to_hw_buff)(enum ipa_hdr_proc_type type, + void *const base, u32 offset, u32 hdr_len, + bool is_hdr_proc_ctx, dma_addr_t phys_base, + u32 hdr_base_addr, u32 hdr_offset_entry); + + int (*ipahal_get_proc_ctx_needed_len)(enum ipa_hdr_proc_type type); +}; + +static struct ipahal_hdr_funcs hdr_funcs; + +static void ipahal_hdr_init(enum ipa_hw_type ipa_hw_type) +{ + + IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type); + + /* + * once there are changes in HW and need to use different case, insert + * new case for the new h/w. put the default always for the latest HW + * and make sure all previous supported versions have their cases. + */ + switch (ipa_hw_type) { + case IPA_HW_v3_0: + default: + hdr_funcs.ipahal_cp_hdr_to_hw_buff = + ipahal_cp_hdr_to_hw_buff_v3; + hdr_funcs.ipahal_cp_proc_ctx_to_hw_buff = + ipahal_cp_proc_ctx_to_hw_buff_v3; + hdr_funcs.ipahal_get_proc_ctx_needed_len = + ipahal_get_proc_ctx_needed_len_v3; + } + IPAHAL_DBG("Exit\n"); +} + +/* + * ipahal_cp_hdr_to_hw_buff() - copy header to hardware buffer according to + * base address and offset given. + * @base: dma base address + * @offset: offset from base address where the data will be copied + * @hdr: the header to be copied + * @hdr_len: the length of the header + */ +void ipahal_cp_hdr_to_hw_buff(void *base, u32 offset, u8 *const hdr, + u32 hdr_len) +{ + IPAHAL_DBG_LOW("Entry\n"); + IPAHAL_DBG("base %p, offset %d, hdr %p, hdr_len %d\n", base, + offset, hdr, hdr_len); + if (!base || !hdr_len || !hdr) { + IPAHAL_ERR("failed on validating params"); + return; + } + + hdr_funcs.ipahal_cp_hdr_to_hw_buff(base, offset, hdr, hdr_len); + + IPAHAL_DBG_LOW("Exit\n"); +} + +/* + * ipahal_cp_proc_ctx_to_hw_buff() - copy processing context to + * base address and offset given. + * @type: type of header processing context + * @base: dma base address + * @offset: offset from base address where the data will be copied + * @hdr_len: the length of the header + * @is_hdr_proc_ctx: header is located in phys_base (true) or hdr_base_addr + * @phys_base: memory location in DDR + * @hdr_base_addr: base address in table + * @hdr_offset_entry: offset from hdr_base_addr in table + */ +int ipahal_cp_proc_ctx_to_hw_buff(enum ipa_hdr_proc_type type, + void *const base, u32 offset, u32 hdr_len, + bool is_hdr_proc_ctx, dma_addr_t phys_base, + u32 hdr_base_addr, u32 hdr_offset_entry) +{ + IPAHAL_DBG( + "type %d, base %p, offset %d, hdr_len %d, is_hdr_proc_ctx %d, hdr_base_addr %d, hdr_offset_entry %d\n" + , type, base, offset, hdr_len, is_hdr_proc_ctx, + hdr_base_addr, hdr_offset_entry); + + if (!base || + !hdr_len || + (!phys_base && !hdr_base_addr) || + !hdr_base_addr) { + IPAHAL_ERR("failed on validating params"); + return -EINVAL; + } + + return hdr_funcs.ipahal_cp_proc_ctx_to_hw_buff(type, base, offset, + hdr_len, is_hdr_proc_ctx, phys_base, + hdr_base_addr, hdr_offset_entry); +} + +/* + * ipahal_get_proc_ctx_needed_len() - calculates the needed length for + * addition of header processing context according to the type of processing + * context + * @type: header processing context type (no processing context, + * IPA_HDR_PROC_ETHII_TO_ETHII etc.) + */ +int ipahal_get_proc_ctx_needed_len(enum ipa_hdr_proc_type type) +{ + int res; + + IPAHAL_DBG("entry\n"); + + res = hdr_funcs.ipahal_get_proc_ctx_needed_len(type); + + IPAHAL_DBG("Exit\n"); + + return res; +} + int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base) { int result; @@ -1065,6 +1288,8 @@ int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base) goto bail_free_ctx; } + ipahal_hdr_init(ipa_hw_type); + ipahal_debugfs_init(); return 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h index 8591ff046624..13812585ff6f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h @@ -597,6 +597,41 @@ void ipahal_pkt_status_parse(const void *unparsed_status, const char *ipahal_pkt_status_exception_str( enum ipahal_pkt_status_exception exception); +/* + * ipahal_cp_hdr_to_hw_buff() - copy header to hardware buffer according to + * base address and offset given. + * @base: dma base address + * @offset: offset from base address where the data will be copied + * @hdr: the header to be copied + * @hdr_len: the length of the header + */ +void ipahal_cp_hdr_to_hw_buff(void *base, u32 offset, u8 *hdr, u32 hdr_len); + +/* + * ipahal_cp_proc_ctx_to_hw_buff() - copy processing context to + * base address and offset given. + * @type: type of header processing context + * @base: dma base address + * @offset: offset from base address where the data will be copied + * @hdr_len: the length of the header + * @is_hdr_proc_ctx: header is located in phys_base (true) or hdr_base_addr + * @phys_base: memory location in DDR + * @hdr_base_addr: base address in table + * @hdr_offset_entry: offset from hdr_base_addr in table + */ +int ipahal_cp_proc_ctx_to_hw_buff(enum ipa_hdr_proc_type type, + void *base, u32 offset, u32 hdr_len, + bool is_hdr_proc_ctx, dma_addr_t phys_base, + u32 hdr_base_addr, u32 hdr_offset_entry); + +/* + * ipahal_get_proc_ctx_needed_len() - calculates the needed length for addition + * of header processing context according to the type of processing context + * @type: header processing context type (no processing context, + * IPA_HDR_PROC_ETHII_TO_ETHII etc.) + */ +int ipahal_get_proc_ctx_needed_len(enum ipa_hdr_proc_type type); + int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base); void ipahal_destroy(void); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h index 9b348d6f969e..6a22240e951b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h @@ -471,4 +471,75 @@ struct ipa_pkt_status_hw { /* Size of H/W Packet Status */ #define IPA3_0_PKT_STATUS_SIZE 32 +/* Headers and processing context H/W structures and definitions */ + +/* uCP command numbers */ +#define IPA_HDR_UCP_802_3_TO_802_3 6 +#define IPA_HDR_UCP_802_3_TO_ETHII 7 +#define IPA_HDR_UCP_ETHII_TO_802_3 8 +#define IPA_HDR_UCP_ETHII_TO_ETHII 9 + +/* Processing context TLV type */ +#define IPA_PROC_CTX_TLV_TYPE_END 0 +#define IPA_PROC_CTX_TLV_TYPE_HDR_ADD 1 +#define IPA_PROC_CTX_TLV_TYPE_PROC_CMD 3 + +/** + * struct ipa_hw_hdr_proc_ctx_tlv - + * HW structure of IPA processing context header - TLV part + * @type: 0 - end type + * 1 - header addition type + * 3 - processing command type + * @length: number of bytes after tlv + * for type: + * 0 - needs to be 0 + * 1 - header addition length + * 3 - number of 32B including type and length. + * @value: specific value for type + * for type: + * 0 - needs to be 0 + * 1 - header length + * 3 - command ID (see IPA_HDR_UCP_* definitions) + */ +struct ipa_hw_hdr_proc_ctx_tlv { + u32 type:8; + u32 length:8; + u32 value:16; +}; + +/** + * struct ipa_hw_hdr_proc_ctx_hdr_add - + * HW structure of IPA processing context - add header tlv + * @tlv: IPA processing context TLV + * @hdr_addr: processing context header address + */ +struct ipa_hw_hdr_proc_ctx_hdr_add { + struct ipa_hw_hdr_proc_ctx_tlv tlv; + u32 hdr_addr; +}; + +/** + * struct ipa_hw_hdr_proc_ctx_add_hdr_seq - + * IPA processing context header - add header sequence + * @hdr_add: add header command + * @end: tlv end command (cmd.type must be 0) + */ +struct ipa_hw_hdr_proc_ctx_add_hdr_seq { + struct ipa_hw_hdr_proc_ctx_hdr_add hdr_add; + struct ipa_hw_hdr_proc_ctx_tlv end; +}; + +/** + * struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq - + * IPA processing context header - process command sequence + * @hdr_add: add header command + * @cmd: tlv processing command (cmd.type must be 3) + * @end: tlv end command (cmd.type must be 0) + */ +struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq { + struct ipa_hw_hdr_proc_ctx_hdr_add hdr_add; + struct ipa_hw_hdr_proc_ctx_tlv cmd; + struct ipa_hw_hdr_proc_ctx_tlv end; +}; + #endif /* _IPAHAL_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 8a34f006d3ee..928856f7f38b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1051,7 +1051,7 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev) struct ipa_tx_meta meta; if (skb->protocol != htons(ETH_P_MAP)) { - IPAWANDBG + IPAWANDBG_LOW ("SW filtering out none QMAP packet received from %s", current->comm); return NETDEV_TX_OK; @@ -1074,11 +1074,11 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev) if (atomic_read(&wwan_ptr->outstanding_pkts) >= wwan_ptr->outstanding_high) { if (!qmap_check) { - IPAWANDBG("pending(%d)/(%d)- stop(%d), qmap_chk(%d)\n", + IPAWANDBG_LOW("pending(%d)/(%d)- stop(%d)\n", atomic_read(&wwan_ptr->outstanding_pkts), wwan_ptr->outstanding_high, - netif_queue_stopped(dev), - qmap_check); + netif_queue_stopped(dev)); + IPAWANDBG_LOW("qmap_chk(%d)\n", qmap_check); netif_stop_queue(dev); return NETDEV_TX_BUSY; } @@ -1165,7 +1165,7 @@ static void apps_ipa_tx_complete_notify(void *priv, netif_queue_stopped(wwan_ptr->net) && atomic_read(&wwan_ptr->outstanding_pkts) < (wwan_ptr->outstanding_low)) { - IPAWANDBG("Outstanding low (%d) - waking up queue\n", + IPAWANDBG_LOW("Outstanding low (%d) - waking up queue\n", wwan_ptr->outstanding_low); netif_wake_queue(wwan_ptr->net); } @@ -1193,7 +1193,7 @@ static void apps_ipa_packet_receive_notify(void *priv, int result; unsigned int packet_len = skb->len; - IPAWANDBG("Rx packet was received"); + IPAWANDBG_LOW("Rx packet was received"); if (evt != IPA_RECEIVE) { IPAWANERR("A none IPA_RECEIVE event in wan_ipa_receive\n"); return; @@ -1733,10 +1733,10 @@ static void ipa3_q6_rm_notify_cb(void *user_data, { switch (event) { case IPA_RM_RESOURCE_GRANTED: - IPAWANDBG("%s: Q6_PROD GRANTED CB\n", __func__); + IPAWANDBG_LOW("%s: Q6_PROD GRANTED CB\n", __func__); break; case IPA_RM_RESOURCE_RELEASED: - IPAWANDBG("%s: Q6_PROD RELEASED CB\n", __func__); + IPAWANDBG_LOW("%s: Q6_PROD RELEASED CB\n", __func__); break; default: return; @@ -1843,7 +1843,7 @@ static void ipa3_wake_tx_queue(struct work_struct *work) */ static void ipa3_rm_resource_granted(void *dev) { - IPAWANDBG("Resource Granted - starting queue\n"); + IPAWANDBG_LOW("Resource Granted - starting queue\n"); schedule_work(&ipa3_tx_wakequeue_work); } @@ -2209,7 +2209,7 @@ static int rmnet_ipa_ap_suspend(struct device *dev) struct net_device *netdev = IPA_NETDEV(); struct ipa3_wwan_private *wwan_ptr; - IPAWANDBG("Enter...\n"); + IPAWANDBG_LOW("Enter...\n"); if (netdev == NULL) { IPAWANERR("netdev is NULL.\n"); return 0; @@ -2231,7 +2231,7 @@ static int rmnet_ipa_ap_suspend(struct device *dev) netif_tx_lock_bh(netdev); ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD); netif_tx_unlock_bh(netdev); - IPAWANDBG("Exit\n"); + IPAWANDBG_LOW("Exit\n"); return 0; } @@ -2250,10 +2250,10 @@ static int rmnet_ipa_ap_resume(struct device *dev) { struct net_device *netdev = IPA_NETDEV(); - IPAWANDBG("Enter...\n"); + IPAWANDBG_LOW("Enter...\n"); if (netdev) netif_wake_queue(netdev); - IPAWANDBG("Exit\n"); + IPAWANDBG_LOW("Exit\n"); return 0; } @@ -2337,7 +2337,7 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, break; } - IPAWANDBG("Exit\n"); + IPAWANDBG_LOW("Exit\n"); return NOTIFY_DONE; } @@ -2614,7 +2614,7 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, IPAWANERR("reset the pipe stats\n"); } else { /* print tethered-client enum */ - IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client); + IPAWANDBG_LOW("Tethered-client enum(%d)\n", data->ipa_client); } rc = ipa3_qmi_get_data_stats(req, resp); @@ -2632,16 +2632,17 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, if (resp->dl_dst_pipe_stats_list_valid) { for (pipe_len = 0; pipe_len < resp->dl_dst_pipe_stats_list_len; pipe_len++) { - IPAWANDBG("Check entry(%d) dl_dst_pipe(%d)\n", + IPAWANDBG_LOW("Check entry(%d) dl_dst_pipe(%d)\n", pipe_len, resp->dl_dst_pipe_stats_list [pipe_len].pipe_index); - IPAWANDBG("dl_p_v4(%lu)v6(%lu) dl_b_v4(%lu)v6(%lu)\n", + IPAWANDBG_LOW("dl_p_v4(%lu)v6(%lu)\n", (unsigned long int) resp-> dl_dst_pipe_stats_list[pipe_len]. num_ipv4_packets, (unsigned long int) resp-> dl_dst_pipe_stats_list[pipe_len]. - num_ipv6_packets, + num_ipv6_packets); + IPAWANDBG_LOW("dl_b_v4(%lu)v6(%lu)\n", (unsigned long int) resp-> dl_dst_pipe_stats_list[pipe_len]. num_ipv4_bytes, @@ -2671,7 +2672,7 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, } } } - IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n", + IPAWANDBG_LOW("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n", (unsigned long int) data->ipv4_rx_packets, (unsigned long int) data->ipv6_rx_packets, (unsigned long int) data->ipv4_rx_bytes, @@ -2680,17 +2681,18 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, if (resp->ul_src_pipe_stats_list_valid) { for (pipe_len = 0; pipe_len < resp->ul_src_pipe_stats_list_len; pipe_len++) { - IPAWANDBG("Check entry(%d) ul_dst_pipe(%d)\n", + IPAWANDBG_LOW("Check entry(%d) ul_dst_pipe(%d)\n", pipe_len, resp->ul_src_pipe_stats_list[pipe_len]. pipe_index); - IPAWANDBG("ul_p_v4(%lu)v6(%lu)ul_b_v4(%lu)v6(%lu)\n", + IPAWANDBG_LOW("ul_p_v4(%lu)v6(%lu)\n", (unsigned long int) resp-> ul_src_pipe_stats_list[pipe_len]. num_ipv4_packets, (unsigned long int) resp-> ul_src_pipe_stats_list[pipe_len]. - num_ipv6_packets, + num_ipv6_packets); + IPAWANDBG_LOW("ul_b_v4(%lu)v6(%lu)\n", (unsigned long int) resp-> ul_src_pipe_stats_list[pipe_len]. num_ipv4_bytes, @@ -2720,7 +2722,7 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, } } } - IPAWANDBG("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n", + IPAWANDBG_LOW("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n", (unsigned long int) data->ipv4_tx_packets, (unsigned long int) data->ipv6_tx_packets, (unsigned long int) data->ipv4_tx_bytes, diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c index 608e6f23435e..80b07ab79163 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -147,8 +147,7 @@ static long ipa3_wan_ioctl(struct file *filp, break; case WAN_IOC_POLL_TETHERING_STATS: - IPAWANDBG("device %s got WAN_IOCTL_POLL_TETHERING_STATS :>>>\n", - DRIVER_NAME); + IPAWANDBG_LOW("got WAN_IOCTL_POLL_TETHERING_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_poll_tethering_stats); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -172,8 +171,7 @@ static long ipa3_wan_ioctl(struct file *filp, break; case WAN_IOC_SET_DATA_QUOTA: - IPAWANDBG("device %s got WAN_IOCTL_SET_DATA_QUOTA :>>>\n", - DRIVER_NAME); + IPAWANDBG_LOW("got WAN_IOCTL_SET_DATA_QUOTA :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_set_data_quota); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -197,8 +195,7 @@ static long ipa3_wan_ioctl(struct file *filp, break; case WAN_IOC_SET_TETHER_CLIENT_PIPE: - IPAWANDBG("device %s got WAN_IOC_SET_TETHER_CLIENT_PIPE :>>>\n", - DRIVER_NAME); + IPAWANDBG_LOW("got WAN_IOC_SET_TETHER_CLIENT_PIPE :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_set_tether_client_pipe); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -218,8 +215,7 @@ static long ipa3_wan_ioctl(struct file *filp, break; case WAN_IOC_QUERY_TETHER_STATS: - IPAWANDBG("device %s got WAN_IOC_QUERY_TETHER_STATS :>>>\n", - DRIVER_NAME); + IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_query_tether_stats); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -245,7 +241,7 @@ static long ipa3_wan_ioctl(struct file *filp, break; case WAN_IOC_RESET_TETHER_STATS: - IPAWANDBG("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n", + IPAWANDBG_LOW("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct wan_ioctl_reset_tether_stats); param = kzalloc(pyld_sz, GFP_KERNEL); diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index a8adc2401dbf..6d826590cabc 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.c @@ -1102,17 +1102,15 @@ static int ops_notify(void *handle, enum wil_platform_event evt) break; case WIL_PLATFORM_EVT_PRE_RESET: /* - * Enable rf_clk3 clock before resetting the device to ensure - * stable ref clock during the device reset + * TODO: Enable rf_clk3 clock before resetting the device to + * ensure stable ref clock during the device reset */ - rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3); break; case WIL_PLATFORM_EVT_FW_RDY: /* - * Disable rf_clk3 clock after the device is up to allow + * TODO: Disable rf_clk3 clock after the device is up to allow * the device to control it via its GPIO for power saving */ - msm_11ad_disable_clk(ctx, &ctx->rf_clk3); break; default: pr_debug("%s: Unhandled event %d\n", __func__, evt); diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c index d32db884989e..c80b6b703e26 100644 --- a/drivers/regulator/cpr3-mmss-regulator.c +++ b/drivers/regulator/cpr3-mmss-regulator.c @@ -191,6 +191,14 @@ static const int msm8996pro_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = { }; static const int msmcobalt_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = { + 528000, + 656000, + 812000, + 932000, +}; + +static const int +msmcobalt_rev0_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = { 632000, 768000, 896000, @@ -694,7 +702,10 @@ static int cpr3_msm8996_mmss_calculate_open_loop_voltages( goto done; } - if (vreg->thread->ctrl->soc_revision == MSMCOBALT_SOC_ID) + if (vreg->thread->ctrl->soc_revision == MSMCOBALT_SOC_ID + && fuse->cpr_fusing_rev == 0) + ref_volt = msmcobalt_rev0_mmss_fuse_ref_volt; + else if (vreg->thread->ctrl->soc_revision == MSMCOBALT_SOC_ID) ref_volt = msmcobalt_mmss_fuse_ref_volt; else if (vreg->thread->ctrl->soc_revision == MSM8996PRO_SOC_ID) ref_volt = msm8996pro_mmss_fuse_ref_volt; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 5cd1a519693f..3fa75cc19a4f 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -668,4 +668,35 @@ config MSM_SERVICE_NOTIFIER like audio, the identifier for which is provided by the service locator. +config MSM_RPM_RBCPR_STATS_V2_LOG + tristate "MSM Resource Power Manager RPBCPR Stat Driver" + depends on DEBUG_FS + help + This option enables v2 of the rpmrbcpr_stats driver which reads RPM + memory for statistics pertaining to RPM's RBCPR(Rapid Bridge Core + Power Reduction) driver. The drivers outputs the message via a + debugfs node. + +config MSM_RPM_LOG + tristate "MSM Resource Power Manager Log Driver" + depends on DEBUG_FS + depends on MSM_RPM_SMD + default n + help + This option enables a driver which can read from a circular buffer + of messages produced by the RPM. These messages provide diagnostic + information about RPM operation. The driver outputs the messages + via a debugfs node. + +config MSM_RPM_STATS_LOG + tristate "MSM Resource Power Manager Stat Driver" + depends on DEBUG_FS + depends on MSM_RPM_SMD + default n + help + This option enables a driver which reads RPM messages from a shared + memory location. These messages provide statistical information about + the low power modes that RPM enters. The drivers outputs the message + via a debugfs node. + source "drivers/soc/qcom/memshare/Kconfig" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 2433e81a831b..2cb810465002 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -85,3 +85,6 @@ obj-$(CONFIG_MSM_KERNEL_PROTECT) += kernel_protect.o obj-$(CONFIG_MSM_RTB) += msm_rtb-hotplug.o obj-$(CONFIG_QCOM_REMOTEQDSS) += remoteqdss.o obj-$(CONFIG_MSM_SERVICE_LOCATOR) += service-locator.o +obj-$(CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG) += rpm_rbcpr_stats_v2.o +obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o +obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 887e49e3beb6..a64fdac00ff4 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -9,6 +9,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include <asm/dma-iommu.h> +#include <linux/clk.h> +#include <linux/iommu.h> #include <linux/export.h> #include <linux/err.h> #include <linux/of.h> @@ -45,6 +48,7 @@ struct icnss_qmi_event { #define WLFW_SERVICE_INS_ID_V01 0 #define ICNSS_WLFW_QMI_CONNECTED BIT(0) #define ICNSS_FW_READY BIT(1) +#define SMMU_CLOCK_NAME "smmu_aggre2_noc_clk" #define ICNSS_IS_WLFW_QMI_CONNECTED(_state) \ ((_state) & ICNSS_WLFW_QMI_CONNECTED) @@ -84,6 +88,10 @@ static struct { void __iomem *mem_base_va; phys_addr_t mpm_config_pa; void __iomem *mpm_config_va; + struct dma_iommu_mapping *smmu_mapping; + dma_addr_t smmu_iova_start; + size_t smmu_iova_len; + struct clk *smmu_clk; struct qmi_handle *wlfw_clnt; struct list_head qmi_event_list; spinlock_t qmi_event_lock; @@ -1170,9 +1178,120 @@ static ssize_t icnss_wlan_mode_store(struct device *dev, static DEVICE_ATTR(icnss_wlan_mode, S_IWUSR, NULL, icnss_wlan_mode_store); +static struct clk *icnss_clock_init(struct device *dev, const char *cname) +{ + struct clk *c; + long rate; + + if (of_property_match_string(dev->of_node, "clock-names", cname) < 0) { + pr_err("%s: clock %s is not found!", __func__, cname); + return NULL; + } + + c = devm_clk_get(dev, cname); + if (IS_ERR(c)) { + pr_err("%s: couldn't get clock %s!", __func__, cname); + return NULL; + } + + if (clk_get_rate(c) == 0) { + rate = clk_round_rate(c, 1000); + clk_set_rate(c, rate); + } + + return c; +} + +static int icnss_clock_enable(struct clk *c) +{ + int ret = 0; + + ret = clk_prepare_enable(c); + + if (ret < 0) + pr_err("%s: couldn't enable clock!\n", __func__); + + return ret; +} + +static void icnss_clock_disable(struct clk *c) +{ + clk_disable_unprepare(c); +} + +static int icnss_smmu_init(struct device *dev) +{ + struct dma_iommu_mapping *mapping; + int disable_htw = 1; + int atomic_ctx = 1; + int s1_bypass = 1; + int ret = 0; + + mapping = arm_iommu_create_mapping(&platform_bus_type, + penv->smmu_iova_start, + penv->smmu_iova_len); + if (IS_ERR(mapping)) { + pr_err("%s: create mapping failed, err = %d\n", __func__, ret); + ret = PTR_ERR(mapping); + goto map_fail; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_COHERENT_HTW_DISABLE, + &disable_htw); + if (ret < 0) { + pr_err("%s: set disable_htw attribute failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_ATOMIC, + &atomic_ctx); + if (ret < 0) { + pr_err("%s: set atomic_ctx attribute failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + if (ret < 0) { + pr_err("%s: set s1_bypass attribute failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + + ret = arm_iommu_attach_device(dev, mapping); + if (ret < 0) { + pr_err("%s: attach device failed, err = %d\n", __func__, ret); + goto attach_fail; + } + + penv->smmu_mapping = mapping; + + return ret; + +attach_fail: +set_attr_fail: + arm_iommu_release_mapping(mapping); +map_fail: + return ret; +} + +static void icnss_smmu_remove(struct device *dev) +{ + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(penv->smmu_mapping); + + penv->smmu_mapping = NULL; +} + static int icnss_probe(struct platform_device *pdev) { int ret = 0; + u32 smmu_iova_address[2]; struct resource *res; int i; struct device *dev = &pdev->dev; @@ -1247,6 +1366,30 @@ static int icnss_probe(struct platform_device *pdev) goto unmap_mpm_config; } + if (of_property_read_u32_array(pdev->dev.of_node, + "qcom,wlan-smmu-iova-address", + smmu_iova_address, 2) == 0) { + penv->smmu_iova_start = smmu_iova_address[0]; + penv->smmu_iova_len = smmu_iova_address[1]; + + ret = icnss_smmu_init(&pdev->dev); + if (ret < 0) { + pr_err("%s: SMMU init failed, err = %d\n", + __func__, ret); + goto err_smmu_init; + } + + penv->smmu_clk = icnss_clock_init(&pdev->dev, SMMU_CLOCK_NAME); + if (penv->smmu_clk) { + ret = icnss_clock_enable(penv->smmu_clk); + if (ret < 0) { + pr_err("%s: SMMU clock enable failed!\n", + __func__); + goto err_smmu_clock_enable; + } + } + } + penv->skip_qmi = of_property_read_bool(dev->of_node, "qcom,skip-qmi"); @@ -1289,6 +1432,12 @@ err_qmi: err_workqueue: device_remove_file(&pdev->dev, &dev_attr_icnss_wlan_mode); err_wlan_mode: + if (penv->smmu_clk) + icnss_clock_disable(penv->smmu_clk); +err_smmu_clock_enable: + if (penv->smmu_mapping) + icnss_smmu_remove(&pdev->dev); +err_smmu_init: if (penv->msa_va) dma_free_coherent(&pdev->dev, penv->msa_mem_size, penv->msa_va, penv->msa_pa); @@ -1311,6 +1460,13 @@ static int icnss_remove(struct platform_device *pdev) if (penv->qmi_event_wq) destroy_workqueue(penv->qmi_event_wq); device_remove_file(&pdev->dev, &dev_attr_icnss_wlan_mode); + + if (penv->smmu_mapping) { + if (penv->smmu_clk) + icnss_clock_disable(penv->smmu_clk); + icnss_smmu_remove(&pdev->dev); + } + if (penv->msa_va) dma_free_coherent(&pdev->dev, penv->msa_mem_size, penv->msa_va, penv->msa_pa); diff --git a/drivers/soc/qcom/rpm_log.c b/drivers/soc/qcom/rpm_log.c new file mode 100644 index 000000000000..deea77c6b0a9 --- /dev/null +++ b/drivers/soc/qcom/rpm_log.c @@ -0,0 +1,549 @@ +/* Copyright (c) 2010-2011, 2013-2014, 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/debugfs.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/uaccess.h> + +#include "rpm_log.h" + +/* registers in MSM_RPM_LOG_PAGE_INDICES */ +enum { + MSM_RPM_LOG_TAIL, + MSM_RPM_LOG_HEAD +}; + +/* used to 4 byte align message lengths */ +#define PADDED_LENGTH(x) (0xFFFFFFFC & ((x) + 3)) + +/* calculates the character string length of a message of byte length x */ +#define PRINTED_LENGTH(x) ((x) * 6 + 3) + +/* number of ms to wait between checking for new messages in the RPM log */ +#define RECHECK_TIME (50) + +#define VERSION_8974 0x1000 +#define RPM_ULOG_LENGTH_SHIFT 16 +#define RPM_ULOG_LENGTH_MASK 0xFFFF0000 + +struct msm_rpm_log_buffer { + char *data; + u32 len; + u32 pos; + struct mutex mutex; + u32 max_len; + u32 read_idx; + struct msm_rpm_log_platform_data *pdata; +}; + +/****************************************************************************** + * Internal functions + *****************************************************************************/ + +static inline u32 +msm_rpm_log_read(const struct msm_rpm_log_platform_data *pdata, u32 page, + u32 reg) +{ + return readl_relaxed(pdata->reg_base + pdata->reg_offsets[page] + + reg * 4); +} + +/* + * msm_rpm_log_copy() - Copies messages from a volatile circular buffer in + * the RPM's shared memory into a private local buffer + * msg_buffer: pointer to local buffer (string) + * buf_len: length of local buffer in bytes + * read_start_idx: index into shared memory buffer + * + * Return value: number of bytes written to the local buffer + * + * Copies messages stored in a circular buffer in the RPM Message Memory into + * a specified local buffer. The RPM processor is unaware of these reading + * efforts, so care is taken to make sure that messages are valid both before + * and after reading. The RPM processor utilizes a ULog driver to write the + * log. The RPM processor maintains tail and head indices. These correspond + * to the next byte to write into, and the first valid byte, respectively. + * Both indices increase monotonically (except for rollover). + * + * Messages take the form of [(u32)length] [(char)data0,1,...] in which the + * length specifies the number of payload bytes. Messages must be 4 byte + * aligned, so padding is added at the end of a message as needed. + * + * Print format: + * - 0xXX, 0xXX, 0xXX + * - 0xXX + * etc... + */ +static u32 msm_rpm_log_copy(const struct msm_rpm_log_platform_data *pdata, + char *msg_buffer, u32 buf_len, u32 *read_idx) +{ + u32 head_idx, tail_idx; + u32 pos = 0; + u32 i = 0; + u32 msg_len; + u32 pos_start; + char temp[4]; + + tail_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_TAIL); + head_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_HEAD); + + /* loop while the remote buffer has valid messages left to read */ + while (tail_idx - head_idx > 0 && tail_idx - *read_idx > 0) { + head_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_HEAD); + tail_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_TAIL); + /* check if the message to be read is valid */ + if (tail_idx - *read_idx > tail_idx - head_idx) { + *read_idx = head_idx; + continue; + } + + /* + * Ensure that all indices are 4 byte aligned. + * This conditions is required to interact with a ULog buffer + * properly. + */ + if (!IS_ALIGNED((tail_idx | head_idx | *read_idx), 4)) + break; + + msg_len = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_BUFFER, + ((*read_idx) & pdata->log_len_mask) >> 2); + + /* Message length for 8974 is first 2 bytes. + * Exclude message length and format from message length. + */ + if (pdata->version == VERSION_8974) { + msg_len = (msg_len & RPM_ULOG_LENGTH_MASK) >> + RPM_ULOG_LENGTH_SHIFT; + msg_len -= 4; + } + + /* handle messages that claim to be longer than the log */ + if (PADDED_LENGTH(msg_len) > tail_idx - *read_idx - 4) + msg_len = tail_idx - *read_idx - 4; + + /* check that the local buffer has enough space for this msg */ + if (pos + PRINTED_LENGTH(msg_len) > buf_len) + break; + + pos_start = pos; + pos += scnprintf(msg_buffer + pos, buf_len - pos, "- "); + + /* copy message payload to local buffer */ + for (i = 0; i < msg_len; i++) { + /* read from shared memory 4 bytes at a time */ + if (IS_ALIGNED(i, 4)) + *((u32 *)temp) = msm_rpm_log_read(pdata, + MSM_RPM_LOG_PAGE_BUFFER, + ((*read_idx + 4 + i) & + pdata->log_len_mask) >> 2); + + pos += scnprintf(msg_buffer + pos, buf_len - pos, + "0x%02X, ", temp[i & 0x03]); + } + + pos += scnprintf(msg_buffer + pos, buf_len - pos, "\n"); + + head_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_HEAD); + tail_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_TAIL); + + /* roll back if message that was read is not still valid */ + if (tail_idx - *read_idx > tail_idx - head_idx) + pos = pos_start; + + *read_idx += PADDED_LENGTH(msg_len) + 4; + } + + return pos; +} + + +/* + * msm_rpm_log_file_read() - Reads in log buffer messages then outputs them to a + * user buffer + * + * Return value: + * 0: success + * -ENOMEM: no memory available + * -EINVAL: user buffer null or requested bytes 0 + * -EFAULT: user buffer not writeable + * -EAGAIN: no bytes available at the moment + */ +static ssize_t msm_rpm_log_file_read(struct file *file, char __user *bufu, + size_t count, loff_t *ppos) +{ + u32 out_len, remaining; + struct msm_rpm_log_platform_data *pdata; + struct msm_rpm_log_buffer *buf; + + buf = file->private_data; + + if (!buf) + return -ENOMEM; + + pdata = buf->pdata; + + if (!pdata) + return -EINVAL; + if (!buf->data) + return -ENOMEM; + if (!bufu || count == 0) + return -EINVAL; + if (!access_ok(VERIFY_WRITE, bufu, count)) + return -EFAULT; + + mutex_lock(&buf->mutex); + /* check for more messages if local buffer empty */ + if (buf->pos == buf->len) { + buf->pos = 0; + buf->len = msm_rpm_log_copy(pdata, buf->data, buf->max_len, + &(buf->read_idx)); + } + + if ((file->f_flags & O_NONBLOCK) && buf->len == 0) { + mutex_unlock(&buf->mutex); + return -EAGAIN; + } + + /* loop until new messages arrive */ + while (buf->len == 0) { + cond_resched(); + if (msleep_interruptible(RECHECK_TIME)) + break; + buf->len = msm_rpm_log_copy(pdata, buf->data, buf->max_len, + &(buf->read_idx)); + } + + out_len = ((buf->len - buf->pos) < count ? buf->len - buf->pos : count); + + remaining = __copy_to_user(bufu, &(buf->data[buf->pos]), out_len); + buf->pos += out_len - remaining; + mutex_unlock(&buf->mutex); + + return out_len - remaining; +} + + +/* + * msm_rpm_log_file_open() - Allows a new reader to open the RPM log virtual + * file + * + * One local buffer is kmalloc'ed for each reader, so no resource sharing has + * to take place (besides the read only access to the RPM log buffer). + * + * Return value: + * 0: success + * -ENOMEM: no memory available + */ +static int msm_rpm_log_file_open(struct inode *inode, struct file *file) +{ + struct msm_rpm_log_buffer *buf; + struct msm_rpm_log_platform_data *pdata; + + pdata = inode->i_private; + if (!pdata) + return -EINVAL; + + file->private_data = + kmalloc(sizeof(struct msm_rpm_log_buffer), GFP_KERNEL); + if (!file->private_data) { + pr_err("%s: ERROR kmalloc failed to allocate %zu bytes\n", + __func__, sizeof(struct msm_rpm_log_buffer)); + return -ENOMEM; + } + buf = file->private_data; + + buf->data = kmalloc(PRINTED_LENGTH(pdata->log_len), GFP_KERNEL); + if (!buf->data) { + kfree(file->private_data); + file->private_data = NULL; + pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n", + __func__, PRINTED_LENGTH(pdata->log_len)); + return -ENOMEM; + } + + buf->pdata = pdata; + buf->len = 0; + buf->pos = 0; + mutex_init(&buf->mutex); + buf->max_len = PRINTED_LENGTH(pdata->log_len); + buf->read_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_HEAD); + return 0; +} + +static int msm_rpm_log_file_close(struct inode *inode, struct file *file) +{ + kfree(((struct msm_rpm_log_buffer *)file->private_data)->data); + kfree(file->private_data); + return 0; +} + + +static const struct file_operations msm_rpm_log_file_fops = { + .owner = THIS_MODULE, + .open = msm_rpm_log_file_open, + .read = msm_rpm_log_file_read, + .release = msm_rpm_log_file_close, +}; + +static int msm_rpm_log_probe(struct platform_device *pdev) +{ + struct dentry *dent; + struct msm_rpm_log_platform_data *pdata; + struct resource *res = NULL, *offset = NULL; + struct device_node *node = NULL; + phys_addr_t page_buffer_address, rpm_addr_phys; + int ret = 0; + char *key = NULL; + uint32_t val = 0; + uint32_t offset_addr = 0; + void __iomem *phys_ptr = NULL; + + node = pdev->dev.of_node; + + if (node) { + pdata = kzalloc(sizeof(struct msm_rpm_log_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + pr_err("%s: could not get resource\n", __func__); + kfree(pdata); + return -EINVAL; + } + + offset = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (offset) { + /* Remap the rpm-log pointer */ + phys_ptr = ioremap_nocache(offset->start, SZ_4); + if (!phys_ptr) { + pr_err("%s: Failed to ioremap address: %x\n", + __func__, offset_addr); + return -ENODEV; + } + offset_addr = readl_relaxed(phys_ptr); + iounmap(phys_ptr); + } + + pdata->phys_addr_base = res->start + offset_addr; + pdata->phys_size = resource_size(res); + + pdata->reg_base = ioremap_nocache(pdata->phys_addr_base, + pdata->phys_size); + if (!pdata->reg_base) { + pr_err("%s: ERROR could not ioremap: start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + kfree(pdata); + return -EBUSY; + } + /* Read various parameters from the header if the + * version of the RPM Ulog is 0x1000. This version + * corresponds to the node in the rpm header which + * holds RPM log on 8974. + * + * offset-page-buffer-addr: At this offset header + * contains address of the location where raw log + * starts + * offset-log-len: At this offset header contains + * the length of the log buffer. + * offset-log-len-mask: At this offset header contains + * the log length mask for the buffer. + * offset-page-indices: At this offset header contains + * the index for writer. + */ + + key = "qcom,offset-version"; + ret = of_property_read_u32(node, key, &val); + if (ret) { + pr_err("%s: Error in name %s key %s\n", + __func__, node->full_name, key); + ret = -EFAULT; + goto fail; + } + + pdata->version = readl_relaxed(pdata->reg_base + val); + if (pdata->version == VERSION_8974) { + key = "qcom,rpm-addr-phys"; + ret = of_property_read_u32(node, key, &val); + if (ret) { + pr_err("%s: Error in name %s key %s\n", + __func__, node->full_name, key); + ret = -EFAULT; + goto fail; + } + + rpm_addr_phys = val; + + key = "qcom,offset-page-buffer-addr"; + ret = of_property_read_u32(node, key, &val); + if (ret) { + pr_err("%s: Error in name %s key %s\n", + __func__, node->full_name, key); + ret = -EFAULT; + goto fail; + } + + page_buffer_address = rpm_addr_phys + + readl_relaxed(pdata->reg_base + val); + pdata->reg_offsets[MSM_RPM_LOG_PAGE_BUFFER] = + page_buffer_address - pdata->phys_addr_base; + + key = "qcom,offset-log-len"; + ret = of_property_read_u32(node, key, &val); + if (ret) { + pr_err("%s: Error in name %s key %s\n", + __func__, node->full_name, key); + ret = -EFAULT; + goto fail; + } + pdata->log_len = readl_relaxed(pdata->reg_base + val); + + if (pdata->log_len > pdata->phys_size) { + pr_err("%s: Error phy size: %d should be atleast log length: %d\n", + __func__, pdata->phys_size, + pdata->log_len); + + ret = -EINVAL; + goto fail; + } + + key = "qcom,offset-log-len-mask"; + ret = of_property_read_u32(node, key, &val); + if (ret) { + pr_err("%s: Error in name %s key %s\n", + __func__, node->full_name, key); + ret = -EFAULT; + goto fail; + } + pdata->log_len_mask = readl_relaxed(pdata->reg_base + + val); + + key = "qcom,offset-page-indices"; + ret = of_property_read_u32(node, key, &val); + if (ret) { + pr_err("%s: Error in name %s key %s\n", + __func__, node->full_name, key); + ret = -EFAULT; + goto fail; + } + pdata->reg_offsets[MSM_RPM_LOG_PAGE_INDICES] = + val; + } else{ + ret = -EINVAL; + goto fail; + } + + } else{ + pdata = pdev->dev.platform_data; + if (!pdata) + return -EINVAL; + + pdata->reg_base = ioremap(pdata->phys_addr_base, + pdata->phys_size); + if (!pdata->reg_base) { + pr_err("%s: ERROR could not ioremap: start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + return -EBUSY; + } + } + + dent = debugfs_create_file("rpm_log", S_IRUGO, NULL, + pdata, &msm_rpm_log_file_fops); + if (!dent) { + pr_err("%s: ERROR debugfs_create_file failed\n", __func__); + if (pdata->version == VERSION_8974) { + ret = -ENOMEM; + goto fail; + } + return -ENOMEM; + } + + platform_set_drvdata(pdev, dent); + + pr_notice("%s: OK\n", __func__); + return 0; + +fail: + iounmap(pdata->reg_base); + kfree(pdata); + return ret; +} + +static int msm_rpm_log_remove(struct platform_device *pdev) +{ + struct dentry *dent; + struct msm_rpm_log_platform_data *pdata; + + pdata = pdev->dev.platform_data; + + iounmap(pdata->reg_base); + + dent = platform_get_drvdata(pdev); + debugfs_remove(dent); + platform_set_drvdata(pdev, NULL); + + pr_notice("%s: OK\n", __func__); + return 0; +} + +static const struct of_device_id rpm_log_table[] = { + {.compatible = "qcom,rpm-log"}, + {}, +}; + +static struct platform_driver msm_rpm_log_driver = { + .probe = msm_rpm_log_probe, + .remove = msm_rpm_log_remove, + .driver = { + .name = "msm_rpm_log", + .owner = THIS_MODULE, + .of_match_table = rpm_log_table, + }, +}; + +static int __init msm_rpm_log_init(void) +{ + return platform_driver_register(&msm_rpm_log_driver); +} + +static void __exit msm_rpm_log_exit(void) +{ + platform_driver_unregister(&msm_rpm_log_driver); +} + +module_init(msm_rpm_log_init); +module_exit(msm_rpm_log_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM RPM Log driver"); +MODULE_ALIAS("platform:msm_rpm_log"); diff --git a/drivers/soc/qcom/rpm_log.h b/drivers/soc/qcom/rpm_log.h new file mode 100644 index 000000000000..1f1a9f78f37f --- /dev/null +++ b/drivers/soc/qcom/rpm_log.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2010, 2013, 2016 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 __ARCH_ARM_MACH_MSM_RPM_LOG_H +#define __ARCH_ARM_MACH_MSM_RPM_LOG_H + +#include <linux/types.h> + +enum { + MSM_RPM_LOG_PAGE_INDICES, + MSM_RPM_LOG_PAGE_BUFFER, + MSM_RPM_LOG_PAGE_COUNT +}; + +struct msm_rpm_log_platform_data { + u32 reg_offsets[MSM_RPM_LOG_PAGE_COUNT]; + u32 log_len; + u32 log_len_mask; + phys_addr_t phys_addr_base; + u32 phys_size; + u32 version; + void __iomem *reg_base; +}; + +#endif /* __ARCH_ARM_MACH_MSM_RPM_LOG_H */ diff --git a/drivers/soc/qcom/rpm_master_stat.c b/drivers/soc/qcom/rpm_master_stat.c new file mode 100644 index 000000000000..14004a2b721e --- /dev/null +++ b/drivers/soc/qcom/rpm_master_stat.c @@ -0,0 +1,473 @@ +/* Copyright (c) 2012-2016, 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/debugfs.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/of.h> +#include <linux/uaccess.h> + +#include "rpm_stats.h" + +#define RPM_MASTERS_BUF_LEN 400 + +#define SNPRINTF(buf, size, format, ...) \ + do { \ + if (size > 0) { \ + int ret; \ + ret = snprintf(buf, size, format, ## __VA_ARGS__); \ + if (ret > size) { \ + buf += size; \ + size = 0; \ + } else { \ + buf += ret; \ + size -= ret; \ + } \ + } \ + } while (0) + +#define GET_MASTER_NAME(a, prvdata) \ + ((a >= prvdata->num_masters) ? "Invalid Master Name" : \ + prvdata->master_names[a]) + +#define GET_FIELD(a) ((strnstr(#a, ".", 80) + 1)) + +struct msm_rpm_master_stats { + uint32_t active_cores; + uint32_t numshutdowns; + uint64_t shutdown_req; + uint64_t wakeup_ind; + uint64_t bringup_req; + uint64_t bringup_ack; + uint32_t wakeup_reason; /* 0 = rude wakeup, 1 = scheduled wakeup */ + uint32_t last_sleep_transition_duration; + uint32_t last_wake_transition_duration; + uint32_t xo_count; + uint64_t xo_last_entered_at; + uint64_t xo_last_exited_at; + uint64_t xo_accumulated_duration; +}; + +struct msm_rpm_master_stats_private_data { + void __iomem *reg_base; + u32 len; + char **master_names; + u32 num_masters; + char buf[RPM_MASTERS_BUF_LEN]; + struct msm_rpm_master_stats_platform_data *platform_data; +}; + +int msm_rpm_master_stats_file_close(struct inode *inode, + struct file *file) +{ + struct msm_rpm_master_stats_private_data *private = file->private_data; + + if (private->reg_base) + iounmap(private->reg_base); + kfree(file->private_data); + + return 0; +} + +static int msm_rpm_master_copy_stats( + struct msm_rpm_master_stats_private_data *prvdata) +{ + struct msm_rpm_master_stats record; + struct msm_rpm_master_stats_platform_data *pdata; + static int master_cnt; + int count, j = 0; + char *buf; + static DEFINE_MUTEX(msm_rpm_master_stats_mutex); + + mutex_lock(&msm_rpm_master_stats_mutex); + + /* Iterate possible number of masters */ + if (master_cnt > prvdata->num_masters - 1) { + master_cnt = 0; + mutex_unlock(&msm_rpm_master_stats_mutex); + return 0; + } + + pdata = prvdata->platform_data; + count = RPM_MASTERS_BUF_LEN; + buf = prvdata->buf; + + if (prvdata->platform_data->version == 2) { + SNPRINTF(buf, count, "%s\n", + GET_MASTER_NAME(master_cnt, prvdata)); + + record.shutdown_req = readq_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, shutdown_req))); + + SNPRINTF(buf, count, "\t%s:0x%llX\n", + GET_FIELD(record.shutdown_req), + record.shutdown_req); + + record.wakeup_ind = readq_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, wakeup_ind))); + + SNPRINTF(buf, count, "\t%s:0x%llX\n", + GET_FIELD(record.wakeup_ind), + record.wakeup_ind); + + record.bringup_req = readq_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, bringup_req))); + + SNPRINTF(buf, count, "\t%s:0x%llX\n", + GET_FIELD(record.bringup_req), + record.bringup_req); + + record.bringup_ack = readq_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, bringup_ack))); + + SNPRINTF(buf, count, "\t%s:0x%llX\n", + GET_FIELD(record.bringup_ack), + record.bringup_ack); + + record.xo_last_entered_at = readq_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, + xo_last_entered_at))); + + SNPRINTF(buf, count, "\t%s:0x%llX\n", + GET_FIELD(record.xo_last_entered_at), + record.xo_last_entered_at); + + record.xo_last_exited_at = readq_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, + xo_last_exited_at))); + + SNPRINTF(buf, count, "\t%s:0x%llX\n", + GET_FIELD(record.xo_last_exited_at), + record.xo_last_exited_at); + + record.xo_accumulated_duration = + readq_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, + xo_accumulated_duration))); + + SNPRINTF(buf, count, "\t%s:0x%llX\n", + GET_FIELD(record.xo_accumulated_duration), + record.xo_accumulated_duration); + + record.last_sleep_transition_duration = + readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, + last_sleep_transition_duration))); + + SNPRINTF(buf, count, "\t%s:0x%x\n", + GET_FIELD(record.last_sleep_transition_duration), + record.last_sleep_transition_duration); + + record.last_wake_transition_duration = + readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, + last_wake_transition_duration))); + + SNPRINTF(buf, count, "\t%s:0x%x\n", + GET_FIELD(record.last_wake_transition_duration), + record.last_wake_transition_duration); + + record.xo_count = + readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, + xo_count))); + + SNPRINTF(buf, count, "\t%s:0x%x\n", + GET_FIELD(record.xo_count), + record.xo_count); + + record.wakeup_reason = readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, + wakeup_reason))); + + SNPRINTF(buf, count, "\t%s:0x%x\n", + GET_FIELD(record.wakeup_reason), + record.wakeup_reason); + + record.numshutdowns = readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset + + offsetof(struct msm_rpm_master_stats, numshutdowns))); + + SNPRINTF(buf, count, "\t%s:0x%x\n", + GET_FIELD(record.numshutdowns), + record.numshutdowns); + + record.active_cores = readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset) + + offsetof(struct msm_rpm_master_stats, active_cores)); + + SNPRINTF(buf, count, "\t%s:0x%x\n", + GET_FIELD(record.active_cores), + record.active_cores); + } else { + SNPRINTF(buf, count, "%s\n", + GET_MASTER_NAME(master_cnt, prvdata)); + + record.numshutdowns = readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset) + 0x0); + + SNPRINTF(buf, count, "\t%s:0x%0x\n", + GET_FIELD(record.numshutdowns), + record.numshutdowns); + + record.active_cores = readl_relaxed(prvdata->reg_base + + (master_cnt * pdata->master_offset) + 0x4); + + SNPRINTF(buf, count, "\t%s:0x%0x\n", + GET_FIELD(record.active_cores), + record.active_cores); + } + + j = find_first_bit((unsigned long *)&record.active_cores, + BITS_PER_LONG); + while (j < BITS_PER_LONG) { + SNPRINTF(buf, count, "\t\tcore%d\n", j); + j = find_next_bit((unsigned long *)&record.active_cores, + BITS_PER_LONG, j + 1); + } + + master_cnt++; + mutex_unlock(&msm_rpm_master_stats_mutex); + return RPM_MASTERS_BUF_LEN - count; +} + +static ssize_t msm_rpm_master_stats_file_read(struct file *file, + char __user *bufu, size_t count, loff_t *ppos) +{ + struct msm_rpm_master_stats_private_data *prvdata; + struct msm_rpm_master_stats_platform_data *pdata; + + prvdata = file->private_data; + if (!prvdata) + return -EINVAL; + + pdata = prvdata->platform_data; + if (!pdata) + return -EINVAL; + + if (!bufu || count == 0) + return -EINVAL; + + if (*ppos <= pdata->phys_size) { + prvdata->len = msm_rpm_master_copy_stats(prvdata); + *ppos = 0; + } + + return simple_read_from_buffer(bufu, count, ppos, + prvdata->buf, prvdata->len); +} + +static int msm_rpm_master_stats_file_open(struct inode *inode, + struct file *file) +{ + struct msm_rpm_master_stats_private_data *prvdata; + struct msm_rpm_master_stats_platform_data *pdata; + + pdata = inode->i_private; + + file->private_data = + kzalloc(sizeof(struct msm_rpm_master_stats_private_data), + GFP_KERNEL); + + if (!file->private_data) + return -ENOMEM; + prvdata = file->private_data; + + prvdata->reg_base = ioremap(pdata->phys_addr_base, + pdata->phys_size); + if (!prvdata->reg_base) { + kfree(file->private_data); + prvdata = NULL; + pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + return -EBUSY; + } + + prvdata->len = 0; + prvdata->num_masters = pdata->num_masters; + prvdata->master_names = pdata->masters; + prvdata->platform_data = pdata; + return 0; +} + +static const struct file_operations msm_rpm_master_stats_fops = { + .owner = THIS_MODULE, + .open = msm_rpm_master_stats_file_open, + .read = msm_rpm_master_stats_file_read, + .release = msm_rpm_master_stats_file_close, + .llseek = no_llseek, +}; + +static struct msm_rpm_master_stats_platform_data + *msm_rpm_master_populate_pdata(struct device *dev) +{ + struct msm_rpm_master_stats_platform_data *pdata; + struct device_node *node = dev->of_node; + int rc = 0, i; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto err; + + rc = of_property_read_u32(node, "qcom,master-stats-version", + &pdata->version); + if (rc) { + dev_err(dev, "master-stats-version missing rc=%d\n", rc); + goto err; + } + + rc = of_property_read_u32(node, "qcom,master-offset", + &pdata->master_offset); + if (rc) { + dev_err(dev, "master-offset missing rc=%d\n", rc); + goto err; + } + + pdata->num_masters = of_property_count_strings(node, "qcom,masters"); + if (pdata->num_masters < 0) { + dev_err(dev, "Failed to get number of masters =%d\n", + pdata->num_masters); + goto err; + } + + pdata->masters = devm_kzalloc(dev, sizeof(char *) * pdata->num_masters, + GFP_KERNEL); + if (!pdata->masters) + goto err; + + /* + * Read master names from DT + */ + for (i = 0; i < pdata->num_masters; i++) { + const char *master_name; + + of_property_read_string_index(node, "qcom,masters", + i, &master_name); + pdata->masters[i] = devm_kzalloc(dev, sizeof(char) * + strlen(master_name) + 1, GFP_KERNEL); + if (!pdata->masters[i]) + goto err; + + strlcpy(pdata->masters[i], master_name, + strlen(master_name) + 1); + } + return pdata; +err: + return NULL; +} + +static int msm_rpm_master_stats_probe(struct platform_device *pdev) +{ + struct dentry *dent; + struct msm_rpm_master_stats_platform_data *pdata; + struct resource *res = NULL; + + if (!pdev) + return -EINVAL; + + if (pdev->dev.of_node) + pdata = msm_rpm_master_populate_pdata(&pdev->dev); + else + pdata = pdev->dev.platform_data; + + if (!pdata) { + dev_err(&pdev->dev, "%s: Unable to get pdata\n", __func__); + return -ENOMEM; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_err(&pdev->dev, + "%s: Failed to get IO resource from platform device", + __func__); + return -ENXIO; + } + + pdata->phys_addr_base = res->start; + pdata->phys_size = resource_size(res); + + dent = debugfs_create_file("rpm_master_stats", S_IRUGO, NULL, + pdata, &msm_rpm_master_stats_fops); + + if (!dent) { + dev_err(&pdev->dev, "%s: ERROR debugfs_create_file failed\n", + __func__); + return -ENOMEM; + } + + platform_set_drvdata(pdev, dent); + return 0; +} + +static int msm_rpm_master_stats_remove(struct platform_device *pdev) +{ + struct dentry *dent; + + dent = platform_get_drvdata(pdev); + debugfs_remove(dent); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static const struct of_device_id rpm_master_table[] = { + {.compatible = "qcom,rpm-master-stats"}, + {}, +}; + +static struct platform_driver msm_rpm_master_stats_driver = { + .probe = msm_rpm_master_stats_probe, + .remove = msm_rpm_master_stats_remove, + .driver = { + .name = "msm_rpm_master_stats", + .owner = THIS_MODULE, + .of_match_table = rpm_master_table, + }, +}; + +static int __init msm_rpm_master_stats_init(void) +{ + return platform_driver_register(&msm_rpm_master_stats_driver); +} + +static void __exit msm_rpm_master_stats_exit(void) +{ + platform_driver_unregister(&msm_rpm_master_stats_driver); +} + +module_init(msm_rpm_master_stats_init); +module_exit(msm_rpm_master_stats_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM RPM Master Statistics driver"); +MODULE_ALIAS("platform:msm_master_stat_log"); diff --git a/drivers/soc/qcom/rpm_rbcpr_stats_v2.c b/drivers/soc/qcom/rpm_rbcpr_stats_v2.c new file mode 100644 index 000000000000..2a8d0e5fe095 --- /dev/null +++ b/drivers/soc/qcom/rpm_rbcpr_stats_v2.c @@ -0,0 +1,421 @@ +/* Copyright (c) 2013-2016, 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/debugfs.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/mutex.h> +#include <linux/sort.h> +#include <linux/uaccess.h> + +#define RBCPR_BUF_LEN 8000 +#define RBCPR_STATS_MAX_SIZE SZ_2K +#define RBCPR_MAX_RAILS 4 +#define RBCPR_NUM_RECMNDS 3 +#define RBCPR_NUM_CORNERS 3 + +#define FIELD(a) ((strnstr(#a, "->", 80) + 2)) +#define PRINT(buf, pos, format, ...) \ + ((pos < RBCPR_BUF_LEN) ? snprintf((buf + pos), (RBCPR_BUF_LEN - pos),\ + format, ## __VA_ARGS__) : 0) + +enum { + CORNER_OFF, + CORNER_RETENTION, + CORNER_SVS_KRAIT, + CORNER_SVS_SOC, + CORNER_NOMINAL, + CORNER_TURBO, + CORNER_SUPER_TURBO, + CORNER_MAX, +}; + +struct rbcpr_recmnd_data_type { + uint32_t microvolts; + uint64_t timestamp; +}; + +struct rbcpr_corners_data_type { + int32_t efuse_adjustment; + uint32_t programmed_voltage; + uint32_t isr_count; + uint32_t min_count; + uint32_t max_count; + struct rbcpr_recmnd_data_type rbcpr_recmnd[RBCPR_NUM_RECMNDS]; +}; + +struct rbcpr_rail_stats_header_type { + uint32_t num_corners; + uint32_t num_latest_recommends; +}; + +struct rbcpr_rail_stats_footer_type { + uint32_t current_corner; + uint32_t railway_voltage; + uint32_t off_corner; + uint32_t margin; +}; + +struct rbcpr_stats_type { + uint32_t num_rails; + uint32_t status; +}; + +struct rbcpr_data_type { + void __iomem *start; + uint32_t len; + char buf[RBCPR_BUF_LEN]; +}; + +static char *rbcpr_rail_labels[] = { + [0] = "VDD-CX", + [1] = "VDD-GFX", +}; + +static char *rbcpr_corner_string[] = { + [CORNER_OFF] = "CORNERS_OFF", + [CORNER_RETENTION] = "RETENTION", + [CORNER_SVS_KRAIT] = "SVS", + [CORNER_SVS_SOC] = "SVS_SOC", + [CORNER_NOMINAL] = "NOMINAL", + [CORNER_TURBO] = "TURBO", + [CORNER_SUPER_TURBO] = "SUPER_TURBO", +}; + +#define CORNER_STRING(a) \ + ((a >= CORNER_MAX) ? "INVALID Corner" : rbcpr_corner_string[a]) + +static struct rbcpr_data_type *rbcpr_data; + +static void msm_rpmrbcpr_print_stats_header( + struct rbcpr_stats_type *rbcpr_stats, char *buf, + uint32_t *pos) +{ + *pos += PRINT(buf, *pos, "\n:RBCPR STATS "); + *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rbcpr_stats->num_rails), + rbcpr_stats->num_rails); + *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rbcpr_stats->status), + rbcpr_stats->status); +} + +static void msm_rpmrbcpr_print_rail_header( + struct rbcpr_rail_stats_header_type *rail_header, char *buf, + uint32_t *pos) +{ + *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail_header->num_corners), + rail_header->num_corners); + *pos += PRINT(buf, *pos, "(%s: %d)", + FIELD(rail_header->num_latest_recommends), + rail_header->num_latest_recommends); +} + +static void msm_rpmrbcpr_print_corner_recmnds( + struct rbcpr_recmnd_data_type *rbcpr_recmnd, char *buf, + uint32_t *pos) +{ + *pos += PRINT(buf, *pos, "\n\t\t\t :(%s: %d) ", + FIELD(rbcpr_recmd->microvolts), + rbcpr_recmnd->microvolts); + *pos += PRINT(buf, *pos, " (%s: %lld)", FIELD(rbcpr_recmd->timestamp), + rbcpr_recmnd->timestamp); +} + +static void msm_rpmrbcpr_print_corner_data( + struct rbcpr_corners_data_type *corner, char *buf, + uint32_t num_corners, uint32_t *pos) +{ + int i; + + *pos += PRINT(buf, *pos, "(%s: %d)", + FIELD(corner->efuse_adjustment), + corner->efuse_adjustment); + *pos += PRINT(buf, *pos, "(%s: %d)", + FIELD(corner->programmed_voltage), + corner->programmed_voltage); + *pos += PRINT(buf, *pos, "(%s: %d)", + FIELD(corner->isr_count), corner->isr_count); + *pos += PRINT(buf, *pos, "(%s: %d)", + FIELD(corner->min_count), corner->min_count); + *pos += PRINT(buf, *pos, "(%s: %d)\n", + FIELD(corner->max_count), corner->max_count); + *pos += PRINT(buf, *pos, "\t\t\t:Latest Recommends"); + for (i = 0; i < num_corners; i++) + msm_rpmrbcpr_print_corner_recmnds(&corner->rbcpr_recmnd[i], buf, + pos); +} + +static void msm_rpmrbcpr_print_rail_footer( + struct rbcpr_rail_stats_footer_type *rail, char *buf, + uint32_t *pos) +{ + *pos += PRINT(buf, *pos, "(%s: %s)", FIELD(rail->current_corner), + CORNER_STRING(rail->current_corner)); + *pos += PRINT(buf, *pos, "(%s: %d)", + FIELD(rail->railway_voltage), rail->railway_voltage); + *pos += PRINT(buf, *pos, "(%s: %d)", + FIELD(rail->off_corner), rail->off_corner); + *pos += PRINT(buf, *pos, "(%s: %d)\n", + FIELD(rail->margin), rail->margin); +} + +static uint32_t msm_rpmrbcpr_read_rpm_data(void) +{ + uint32_t read_offset = 0; + static struct rbcpr_stats_type rbcpr_stats_header; + uint32_t buffer_offset = 0; + char *buf = rbcpr_data->buf; + int i, j; + + memcpy_fromio(&rbcpr_stats_header, rbcpr_data->start, + sizeof(rbcpr_stats_header)); + read_offset += sizeof(rbcpr_stats_header); + msm_rpmrbcpr_print_stats_header(&rbcpr_stats_header, buf, + &buffer_offset); + + for (i = 0; i < rbcpr_stats_header.num_rails; i++) { + static struct rbcpr_rail_stats_header_type rail_header; + static struct rbcpr_rail_stats_footer_type rail_footer; + + memcpy_fromio(&rail_header, (rbcpr_data->start + read_offset), + sizeof(rail_header)); + read_offset += sizeof(rail_header); + buffer_offset += PRINT(buf, buffer_offset, "\n:%s Rail Data ", + rbcpr_rail_labels[i]); + msm_rpmrbcpr_print_rail_header(&rail_header, buf, + &buffer_offset); + + for (j = 0; j < rail_header.num_corners; j++) { + static struct rbcpr_corners_data_type corner; + uint32_t corner_index; + + memcpy_fromio(&corner, + (rbcpr_data->start + read_offset), + sizeof(corner)); + read_offset += sizeof(corner); + + /* + * RPM doesn't include corner type in the data for the + * corner. For now add this hack to know which corners + * are used based on number of corners for the rail. + */ + corner_index = j + 3; + if (rail_header.num_corners == 3 && j == 2) + corner_index++; + + buffer_offset += PRINT(buf, buffer_offset, + "\n\t\t:Corner Data: %s ", + CORNER_STRING(corner_index)); + msm_rpmrbcpr_print_corner_data(&corner, buf, + rail_header.num_latest_recommends, + &buffer_offset); + } + buffer_offset += PRINT(buf, buffer_offset, + "\n\t\t"); + memcpy_fromio(&rail_footer, (rbcpr_data->start + read_offset), + sizeof(rail_footer)); + read_offset += sizeof(rail_footer); + msm_rpmrbcpr_print_rail_footer(&rail_footer, buf, + &buffer_offset); + } + return buffer_offset; +} + +static int msm_rpmrbcpr_file_read(struct seq_file *m, void *data) +{ + struct rbcpr_data_type *pdata = m->private; + int ret = 0; + int curr_status_counter; + static int prev_status_counter; + static DEFINE_MUTEX(rbcpr_lock); + + mutex_lock(&rbcpr_lock); + if (!pdata) { + pr_err("%s pdata is null", __func__); + ret = -EINVAL; + goto exit_rpmrbcpr_file_read; + } + + /* Read RPM stats */ + curr_status_counter = readl_relaxed(pdata->start + + offsetof(struct rbcpr_stats_type, status)); + if (curr_status_counter != prev_status_counter) { + pdata->len = msm_rpmrbcpr_read_rpm_data(); + pdata->len = 0; + prev_status_counter = curr_status_counter; + } + + seq_printf(m, "%s", pdata->buf); + +exit_rpmrbcpr_file_read: + mutex_unlock(&rbcpr_lock); + return ret; +} + +static int msm_rpmrbcpr_file_open(struct inode *inode, struct file *file) +{ + if (!rbcpr_data->start) + return -ENODEV; + return single_open(file, msm_rpmrbcpr_file_read, inode->i_private); +} + +static const struct file_operations msm_rpmrbcpr_fops = { + .open = msm_rpmrbcpr_file_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int msm_rpmrbcpr_validate(struct platform_device *pdev) +{ + int ret = 0; + uint32_t num_rails; + + num_rails = readl_relaxed(rbcpr_data->start); + + if (num_rails > RBCPR_MAX_RAILS) { + pr_err("%s: Invalid number of RPM RBCPR rails %d", + __func__, num_rails); + ret = -EFAULT; + } + + return ret; +} + +static int msm_rpmrbcpr_probe(struct platform_device *pdev) +{ + struct dentry *dent; + int ret = 0; + struct resource *res = NULL; + void __iomem *start_ptr = NULL; + uint32_t rbcpr_start_addr = 0; + char *key = NULL; + uint32_t start_addr; + + rbcpr_data = devm_kzalloc(&pdev->dev, + sizeof(struct rbcpr_data_type), GFP_KERNEL); + + if (!rbcpr_data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + pr_err("%s: Failed to get IO resource from platform device", + __func__); + ret = -ENXIO; + goto rbcpr_probe_fail; + } + + key = "qcom,start-offset"; + ret = of_property_read_u32(pdev->dev.of_node, key, &start_addr); + + if (ret) { + pr_err("%s: Failed to get start offset", __func__); + goto rbcpr_probe_fail; + } + + start_addr += res->start; + start_ptr = ioremap_nocache(start_addr, 4); + + if (!start_ptr) { + pr_err("%s: Failed to remap RBCPR start pointer", + __func__); + goto rbcpr_probe_fail; + } + + rbcpr_start_addr = res->start + readl_relaxed(start_ptr); + res->end = rbcpr_start_addr + RBCPR_STATS_MAX_SIZE; + + if ((rbcpr_start_addr > (res->end - RBCPR_STATS_MAX_SIZE)) || + (rbcpr_start_addr < start_addr)) { + pr_err("%s: Invalid start address for rbcpr stats 0x%x", + __func__, rbcpr_start_addr); + goto rbcpr_probe_fail; + } + + rbcpr_data->start = devm_ioremap_nocache(&pdev->dev, rbcpr_start_addr, + RBCPR_STATS_MAX_SIZE); + + if (!rbcpr_data->start) { + pr_err("%s: Failed to remap RBCPR start address", + __func__); + goto rbcpr_probe_fail; + } + + ret = msm_rpmrbcpr_validate(pdev); + + if (ret) + goto rbcpr_probe_fail; + + dent = debugfs_create_file("rpm_rbcpr", S_IRUGO, NULL, + rbcpr_data, &msm_rpmrbcpr_fops); + + if (!dent) { + pr_err("%s: error debugfs_create_file failed\n", __func__); + ret = -ENOMEM; + goto rbcpr_probe_fail; + } + + platform_set_drvdata(pdev, dent); +rbcpr_probe_fail: + iounmap(start_ptr); + return ret; +} + +static int msm_rpmrbcpr_remove(struct platform_device *pdev) +{ + struct dentry *dent; + + dent = platform_get_drvdata(pdev); + debugfs_remove(dent); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static const struct of_device_id rpmrbcpr_stats_table[] = { + {.compatible = "qcom,rpmrbcpr-stats"}, + {}, +}; + +static struct platform_driver msm_rpmrbcpr_driver = { + .probe = msm_rpmrbcpr_probe, + .remove = msm_rpmrbcpr_remove, + .driver = { + .name = "msm_rpmrbcpr_stats", + .owner = THIS_MODULE, + .of_match_table = rpmrbcpr_stats_table, + }, +}; + +static int __init msm_rpmrbcpr_init(void) +{ + return platform_driver_register(&msm_rpmrbcpr_driver); +} + +static void __exit msm_rpmrbcpr_exit(void) +{ + platform_driver_unregister(&msm_rpmrbcpr_driver); +} + +module_init(msm_rpmrbcpr_init); +module_exit(msm_rpmrbcpr_exit); diff --git a/drivers/soc/qcom/rpm_stats.c b/drivers/soc/qcom/rpm_stats.c new file mode 100644 index 000000000000..dacca0efe231 --- /dev/null +++ b/drivers/soc/qcom/rpm_stats.c @@ -0,0 +1,570 @@ +/* Copyright (c) 2011-2016, 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/debugfs.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/types.h> +#include <linux/of.h> +#include <linux/uaccess.h> +#include <asm/arch_timer.h> +#include "rpm_stats.h" + +#define GET_PDATA_OF_ATTR(attr) \ + (container_of(attr, struct msm_rpmstats_kobj_attr, ka)->pd) + +enum { + ID_COUNTER, + ID_ACCUM_TIME_SCLK, + ID_MAX, +}; + +static char *msm_rpmstats_id_labels[ID_MAX] = { + [ID_COUNTER] = "Count", + [ID_ACCUM_TIME_SCLK] = "Total time(uSec)", +}; + +#define SCLK_HZ 32768 +#define MSM_ARCH_TIMER_FREQ 19200000 + +struct msm_rpmstats_record { + char name[32]; + uint32_t id; + uint32_t val; +}; + +struct msm_rpmstats_private_data { + void __iomem *reg_base; + u32 num_records; + u32 read_idx; + u32 len; + char buf[320]; + struct msm_rpmstats_platform_data *platform_data; +}; + +struct msm_rpm_stats_data_v2 { + u32 stat_type; + u32 count; + u64 last_entered_at; + u64 last_exited_at; + u64 accumulated; + u32 client_votes; + u32 reserved[3]; +}; + +struct msm_rpmstats_kobj_attr { + struct kobj_attribute ka; + struct msm_rpmstats_platform_data *pd; +}; + +static struct dentry *heap_dent; + +static inline u64 get_time_in_sec(u64 counter) +{ + do_div(counter, MSM_ARCH_TIMER_FREQ); + return counter; +} + +static inline u64 get_time_in_msec(u64 counter) +{ + do_div(counter, MSM_ARCH_TIMER_FREQ); + counter *= MSEC_PER_SEC; + return counter; +} + +static inline int msm_rpmstats_append_data_to_buf(char *buf, + struct msm_rpm_stats_data_v2 *data, int buflength) +{ + char stat_type[5]; + u64 time_in_last_mode; + u64 time_since_last_mode; + u64 actual_last_sleep; + + stat_type[4] = 0; + memcpy(stat_type, &data->stat_type, sizeof(u32)); + + time_in_last_mode = data->last_exited_at - data->last_entered_at; + time_in_last_mode = get_time_in_msec(time_in_last_mode); + time_since_last_mode = arch_counter_get_cntvct() - data->last_exited_at; + time_since_last_mode = get_time_in_sec(time_since_last_mode); + actual_last_sleep = get_time_in_msec(data->accumulated); + + return snprintf(buf, buflength, + "RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n" + "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n" + "client votes: %#010x\n\n", + stat_type, data->count, time_in_last_mode, + time_since_last_mode, actual_last_sleep, + data->client_votes); +} + +static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase, + int index, int offset) +{ + return readl_relaxed(regbase + offset + + index * sizeof(struct msm_rpm_stats_data_v2)); +} + +static inline u64 msm_rpmstats_read_quad_register_v2(void __iomem *regbase, + int index, int offset) +{ + u64 dst; + + memcpy_fromio(&dst, + regbase + offset + index * sizeof(struct msm_rpm_stats_data_v2), + 8); + return dst; +} + +static inline int msm_rpmstats_copy_stats_v2( + struct msm_rpmstats_private_data *prvdata) +{ + void __iomem *reg; + struct msm_rpm_stats_data_v2 data; + int i, length; + + reg = prvdata->reg_base; + + for (i = 0, length = 0; i < prvdata->num_records; i++) { + + data.stat_type = msm_rpmstats_read_long_register_v2(reg, i, + offsetof(struct msm_rpm_stats_data_v2, + stat_type)); + data.count = msm_rpmstats_read_long_register_v2(reg, i, + offsetof(struct msm_rpm_stats_data_v2, count)); + data.last_entered_at = msm_rpmstats_read_quad_register_v2(reg, + i, offsetof(struct msm_rpm_stats_data_v2, + last_entered_at)); + data.last_exited_at = msm_rpmstats_read_quad_register_v2(reg, + i, offsetof(struct msm_rpm_stats_data_v2, + last_exited_at)); + + data.accumulated = msm_rpmstats_read_quad_register_v2(reg, + i, offsetof(struct msm_rpm_stats_data_v2, + accumulated)); + data.client_votes = msm_rpmstats_read_long_register_v2(reg, + i, offsetof(struct msm_rpm_stats_data_v2, + client_votes)); + length += msm_rpmstats_append_data_to_buf(prvdata->buf + length, + &data, sizeof(prvdata->buf) - length); + prvdata->read_idx++; + } + return length; +} + +static inline unsigned long msm_rpmstats_read_register(void __iomem *regbase, + int index, int offset) +{ + return readl_relaxed(regbase + index * 12 + (offset + 1) * 4); +} +static void msm_rpmstats_strcpy(char *dest, char *src) +{ + union { + char ch[4]; + unsigned long word; + } string; + int index = 0; + + do { + int i; + + string.word = readl_relaxed(src + 4 * index); + for (i = 0; i < 4; i++) { + *dest++ = string.ch[i]; + if (!string.ch[i]) + break; + } + index++; + } while (*(dest-1)); + +} +static int msm_rpmstats_copy_stats(struct msm_rpmstats_private_data *pdata) +{ + + struct msm_rpmstats_record record; + unsigned long ptr; + unsigned long offset; + char *str; + uint64_t usec; + + ptr = msm_rpmstats_read_register(pdata->reg_base, pdata->read_idx, 0); + offset = (ptr - (unsigned long)pdata->platform_data->phys_addr_base); + + if (offset > pdata->platform_data->phys_size) + str = (char *)ioremap(ptr, SZ_256); + else + str = (char *) pdata->reg_base + offset; + + msm_rpmstats_strcpy(record.name, str); + + if (offset > pdata->platform_data->phys_size) + iounmap(str); + + record.id = msm_rpmstats_read_register(pdata->reg_base, + pdata->read_idx, 1); + record.val = msm_rpmstats_read_register(pdata->reg_base, + pdata->read_idx, 2); + + if (record.id == ID_ACCUM_TIME_SCLK) { + usec = record.val * USEC_PER_SEC; + do_div(usec, SCLK_HZ); + } else + usec = (unsigned long)record.val; + + pdata->read_idx++; + + return snprintf(pdata->buf, sizeof(pdata->buf), + "RPM Mode:%s\n\t%s:%llu\n", + record.name, + msm_rpmstats_id_labels[record.id], + usec); +} + +static ssize_t msm_rpmstats_file_read(struct file *file, char __user *bufu, + size_t count, loff_t *ppos) +{ + struct msm_rpmstats_private_data *prvdata; + + prvdata = file->private_data; + if (!prvdata) + return -EINVAL; + + if (!bufu || count == 0) + return -EINVAL; + + if (prvdata->platform_data->version == 1) { + if (!prvdata->num_records) + prvdata->num_records = readl_relaxed(prvdata->reg_base); + } + + if ((*ppos >= prvdata->len) && + (prvdata->read_idx < prvdata->num_records)) { + if (prvdata->platform_data->version == 1) + prvdata->len = msm_rpmstats_copy_stats(prvdata); + else if (prvdata->platform_data->version == 2) + prvdata->len = msm_rpmstats_copy_stats_v2(prvdata); + *ppos = 0; + } + return simple_read_from_buffer(bufu, count, ppos, + prvdata->buf, prvdata->len); +} + +static int msm_rpmstats_file_open(struct inode *inode, struct file *file) +{ + struct msm_rpmstats_private_data *prvdata; + struct msm_rpmstats_platform_data *pdata; + + pdata = inode->i_private; + + file->private_data = + kmalloc(sizeof(struct msm_rpmstats_private_data), GFP_KERNEL); + + if (!file->private_data) + return -ENOMEM; + prvdata = file->private_data; + + prvdata->reg_base = ioremap_nocache(pdata->phys_addr_base, + pdata->phys_size); + if (!prvdata->reg_base) { + kfree(file->private_data); + prvdata = NULL; + pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + return -EBUSY; + } + + prvdata->read_idx = prvdata->num_records = prvdata->len = 0; + prvdata->platform_data = pdata; + if (pdata->version == 2) + prvdata->num_records = 2; + + return 0; +} + +static int msm_rpmstats_file_close(struct inode *inode, struct file *file) +{ + struct msm_rpmstats_private_data *private = file->private_data; + + if (private->reg_base) + iounmap(private->reg_base); + kfree(file->private_data); + + return 0; +} + +static const struct file_operations msm_rpmstats_fops = { + .owner = THIS_MODULE, + .open = msm_rpmstats_file_open, + .read = msm_rpmstats_file_read, + .release = msm_rpmstats_file_close, + .llseek = no_llseek, +}; + +static int msm_rpmheap_file_show(struct seq_file *m, void *v) +{ + struct msm_rpmstats_platform_data *pdata; + void __iomem *reg_base; + uint32_t rpmheap_free; + + if (!m->private) + return -EINVAL; + + pdata = m->private; + + reg_base = ioremap_nocache(pdata->heap_phys_addrbase, SZ_4); + if (!reg_base) { + pr_err("%s: ERROR could not ioremap start=%p\n", + __func__, &pdata->heap_phys_addrbase); + return -EBUSY; + } + + rpmheap_free = readl_relaxed(reg_base); + iounmap(reg_base); + + seq_printf(m, "RPM FREE HEAP SPACE is 0x%x Bytes\n", rpmheap_free); + return 0; +} + +static int msm_rpmheap_file_open(struct inode *inode, struct file *file) +{ + return single_open(file, msm_rpmheap_file_show, inode->i_private); +} + +static const struct file_operations msm_rpmheap_fops = { + .owner = THIS_MODULE, + .open = msm_rpmheap_file_open, + .read = seq_read, + .release = single_release, + .llseek = no_llseek, +}; + +static ssize_t rpmstats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct msm_rpmstats_private_data *prvdata = NULL; + struct msm_rpmstats_platform_data *pdata = NULL; + + pdata = GET_PDATA_OF_ATTR(attr); + + prvdata = + kmalloc(sizeof(*prvdata), GFP_KERNEL); + if (!prvdata) + return -ENOMEM; + + prvdata->reg_base = ioremap_nocache(pdata->phys_addr_base, + pdata->phys_size); + if (!prvdata->reg_base) { + kfree(prvdata); + pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + return -EBUSY; + } + + prvdata->read_idx = prvdata->num_records = prvdata->len = 0; + prvdata->platform_data = pdata; + if (pdata->version == 2) + prvdata->num_records = 2; + + if (prvdata->platform_data->version == 1) { + if (!prvdata->num_records) + prvdata->num_records = + readl_relaxed(prvdata->reg_base); + } + + if (prvdata->read_idx < prvdata->num_records) { + if (prvdata->platform_data->version == 1) + prvdata->len = msm_rpmstats_copy_stats(prvdata); + else if (prvdata->platform_data->version == 2) + prvdata->len = msm_rpmstats_copy_stats_v2( + prvdata); + } + + return snprintf(buf, prvdata->len, prvdata->buf); +} + +static int msm_rpmstats_create_sysfs(struct msm_rpmstats_platform_data *pd) +{ + struct kobject *module_kobj = NULL; + struct kobject *rpmstats_kobj = NULL; + struct msm_rpmstats_kobj_attr *rpms_ka = NULL; + int ret = 0; + + module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME); + if (!module_kobj) { + pr_err("%s: Cannot find module_kset\n", __func__); + return -ENODEV; + } + + rpmstats_kobj = kobject_create_and_add("rpmstats", module_kobj); + if (!rpmstats_kobj) { + pr_err("%s: Cannot create rpmstats kobject\n", __func__); + ret = -ENOMEM; + goto fail; + } + + rpms_ka = kzalloc(sizeof(*rpms_ka), GFP_KERNEL); + if (!rpms_ka) { + kobject_put(rpmstats_kobj); + ret = -ENOMEM; + goto fail; + } + + sysfs_attr_init(&rpms_ka->ka.attr); + rpms_ka->pd = pd; + rpms_ka->ka.attr.mode = 0444; + rpms_ka->ka.attr.name = "stats"; + rpms_ka->ka.show = rpmstats_show; + rpms_ka->ka.store = NULL; + + ret = sysfs_create_file(rpmstats_kobj, &rpms_ka->ka.attr); + +fail: + return ret; +} + +static int msm_rpmstats_probe(struct platform_device *pdev) +{ + struct dentry *dent = NULL; + struct msm_rpmstats_platform_data *pdata; + struct msm_rpmstats_platform_data *pd; + struct resource *res = NULL, *offset = NULL; + struct device_node *node = NULL; + uint32_t offset_addr = 0; + void __iomem *phys_ptr = NULL; + int ret = 0; + + if (!pdev) + return -EINVAL; + + pdata = kzalloc(sizeof(struct msm_rpmstats_platform_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "phys_addr_base"); + if (!res) + return -EINVAL; + + offset = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "offset_addr"); + if (offset) { + /* Remap the rpm-stats pointer */ + phys_ptr = ioremap_nocache(offset->start, SZ_4); + if (!phys_ptr) { + pr_err("%s: Failed to ioremap address: %x\n", + __func__, offset_addr); + return -ENODEV; + } + offset_addr = readl_relaxed(phys_ptr); + iounmap(phys_ptr); + } + + pdata->phys_addr_base = res->start + offset_addr; + + pdata->phys_size = resource_size(res); + node = pdev->dev.of_node; + if (pdev->dev.platform_data) { + pd = pdev->dev.platform_data; + pdata->version = pd->version; + + } else if (node) + ret = of_property_read_u32(node, + "qcom,sleep-stats-version", &pdata->version); + + if (!ret) { + + dent = debugfs_create_file("rpm_stats", S_IRUGO, NULL, + pdata, &msm_rpmstats_fops); + + if (!dent) { + pr_err("%s: ERROR rpm_stats debugfs_create_file fail\n", + __func__); + kfree(pdata); + return -ENOMEM; + } + + } else { + kfree(pdata); + return -EINVAL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "heap_phys_addrbase"); + if (res) { + heap_dent = debugfs_create_file("rpm_heap", S_IRUGO, NULL, + pdata, &msm_rpmheap_fops); + + if (!heap_dent) { + pr_err("%s: ERROR rpm_heap debugfs_create_file fail\n", + __func__); + kfree(pdata); + return -ENOMEM; + } + pdata->heap_phys_addrbase = res->start; + } + + msm_rpmstats_create_sysfs(pdata); + + platform_set_drvdata(pdev, dent); + return 0; +} + +static int msm_rpmstats_remove(struct platform_device *pdev) +{ + struct dentry *dent; + + dent = platform_get_drvdata(pdev); + debugfs_remove(dent); + debugfs_remove(heap_dent); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static const struct of_device_id rpm_stats_table[] = { + {.compatible = "qcom,rpm-stats"}, + {}, +}; + +static struct platform_driver msm_rpmstats_driver = { + .probe = msm_rpmstats_probe, + .remove = msm_rpmstats_remove, + .driver = { + .name = "msm_rpm_stat", + .owner = THIS_MODULE, + .of_match_table = rpm_stats_table, + }, +}; +static int __init msm_rpmstats_init(void) +{ + return platform_driver_register(&msm_rpmstats_driver); +} +static void __exit msm_rpmstats_exit(void) +{ + platform_driver_unregister(&msm_rpmstats_driver); +} +module_init(msm_rpmstats_init); +module_exit(msm_rpmstats_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM RPM Statistics driver"); +MODULE_ALIAS("platform:msm_stat_log"); diff --git a/drivers/soc/qcom/rpm_stats.h b/drivers/soc/qcom/rpm_stats.h new file mode 100644 index 000000000000..7b61cd4da1f8 --- /dev/null +++ b/drivers/soc/qcom/rpm_stats.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2011-2016, 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 __ARCH_ARM_MACH_MSM_RPM_STATS_H +#define __ARCH_ARM_MACH_MSM_RPM_STATS_H + +#include <linux/types.h> + +struct msm_rpmstats_platform_data { + phys_addr_t phys_addr_base; + phys_addr_t heap_phys_addrbase; + u32 phys_size; + u32 version; +}; + +struct msm_rpm_master_stats_platform_data { + phys_addr_t phys_addr_base; + u32 phys_size; + char **masters; + /* + * RPM maintains PC stats for each master in MSG RAM, + * it allocates 256 bytes for this use. + * No of masters differs for different targets. + * Based on the number of masters, linux rpm stat + * driver reads (32 * num_masters) bytes to display + * master stats. + */ + s32 num_masters; + u32 master_offset; + u32 version; +}; +#endif diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 6e11f9ca5ce2..2d480f1af11f 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -649,15 +649,14 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, } static struct irq_chip pmic_arb_irqchip = { - .name = "pmic_arb", - .irq_ack = qpnpint_irq_ack, - .irq_eoi = qpnpint_irq_ack, - .irq_mask = qpnpint_irq_mask, - .irq_unmask = qpnpint_irq_unmask, - .irq_set_type = qpnpint_irq_set_type, + .name = "pmic_arb", + .irq_ack = qpnpint_irq_ack, + .irq_mask = qpnpint_irq_mask, + .irq_unmask = qpnpint_irq_unmask, + .irq_set_type = qpnpint_irq_set_type, .irq_get_irqchip_state = qpnpint_get_irqchip_state, - .flags = IRQCHIP_MASK_ON_SUSPEND - | IRQCHIP_SKIP_SET_WAKE, + .flags = IRQCHIP_MASK_ON_SUSPEND + | IRQCHIP_SKIP_SET_WAKE, }; static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, @@ -716,7 +715,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq); - irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_fasteoi_irq); + irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq); irq_set_chip_data(virq, d->host_data); irq_set_noprobe(virq); return 0; diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 743a2a5922dc..f2a21697d431 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -166,12 +166,12 @@ static bool psm_enabled; static bool psm_nodes_called; static bool psm_probed; static bool freq_mitigation_enabled; +static bool boot_freq_mitig_enabled; static bool ocr_enabled; static bool ocr_nodes_called; static bool ocr_probed; static bool ocr_reg_init_defer; static bool hotplug_enabled; -static bool interrupt_mode_enable; static bool msm_thermal_probed; static bool gfx_crit_phase_ctrl_enabled; static bool gfx_warm_phase_ctrl_enabled; @@ -3521,6 +3521,8 @@ static void do_freq_control(int temp) uint32_t cpu = 0; uint32_t max_freq = cpus[cpu].limited_max_freq; + if (!boot_freq_mitig_enabled) + return; if (core_ptr) return do_cluster_freq_ctrl(temp); if (!freq_table_get) @@ -4858,10 +4860,9 @@ static void __ref disable_msm_thermal(void) static void interrupt_mode_init(void) { - if (!msm_thermal_probed) { - interrupt_mode_enable = true; + if (!msm_thermal_probed) return; - } + if (polling_enabled) { polling_enabled = 0; create_sensor_zone_id_map(); @@ -5151,7 +5152,7 @@ static void msm_thermal_panic_notifier_init(struct device *dev) &msm_thermal_panic_notifier); } -int msm_thermal_pre_init(struct device *dev) +static int msm_thermal_pre_init(struct device *dev) { int ret = 0; @@ -5298,6 +5299,7 @@ int msm_thermal_init(struct msm_thermal_data *pdata) { int ret = 0; + msm_thermal_ioctl_init(); ret = devmgr_devices_init(pdata->pdev); if (ret) pr_err("cannot initialize devm devices. err:%d\n", ret); @@ -5319,16 +5321,19 @@ int msm_thermal_init(struct msm_thermal_data *pdata) if (ret) pr_err("cannot register cpufreq notifier. err:%d\n", ret); - register_reboot_notifier(&msm_thermal_reboot_notifier); - pm_notifier(msm_thermal_suspend_callback, 0); + if (!lmh_dcvs_available) { + register_reboot_notifier(&msm_thermal_reboot_notifier); + pm_notifier(msm_thermal_suspend_callback, 0); + } INIT_DELAYED_WORK(&retry_hotplug_work, retry_hotplug); - INIT_DELAYED_WORK(&check_temp_work, check_temp); - schedule_delayed_work(&check_temp_work, 0); if (num_possible_cpus() > 1) { cpus_previously_online_update(); register_cpu_notifier(&msm_thermal_cpu_notifier); } + + INIT_DELAYED_WORK(&check_temp_work, check_temp); + schedule_delayed_work(&check_temp_work, 0); msm_thermal_panic_notifier_init(&pdata->pdev->dev); return ret; @@ -5378,15 +5383,6 @@ static int vdd_restriction_reg_init(struct platform_device *pdev) for (i = 0; i < rails_cnt; i++) { if (rails[i].freq_req == 1) { usefreq |= BIT(i); - check_freq_table(); - /* - * Restrict frequency by default until we have made - * our first temp reading - */ - if (freq_table_get) - ret = vdd_restriction_apply_freq(&rails[i], 0); - else - pr_info("Defer vdd rstr freq init.\n"); } else { rails[i].reg = devm_regulator_get(&pdev->dev, rails[i].name); @@ -5404,11 +5400,6 @@ static int vdd_restriction_reg_init(struct platform_device *pdev) rails[i].name); return ret; } - /* - * Restrict votlage by default until we have made - * our first temp reading - */ - ret = vdd_restriction_apply_voltage(&rails[i], 0); } } @@ -6215,6 +6206,18 @@ static int fetch_cpu_mitigaiton_info(struct msm_thermal_data *data, int _cpu = 0, err = 0; struct device_node *cpu_node = NULL, *limits = NULL, *tsens = NULL; + char *key = NULL; + struct device_node *node = pdev->dev.of_node; + + key = "qcom,sensor-id"; + err = of_property_read_u32(node, key, &data->sensor_id); + if (err) + goto fetch_mitig_exit; + + key = "qcom,poll-ms"; + err = of_property_read_u32(node, key, &data->poll_ms); + if (err) + goto fetch_mitig_exit; for_each_possible_cpu(_cpu) { const char *sensor_name = NULL; @@ -6556,6 +6559,12 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data, hotplug_enabled = 1; } + key = "qcom,online-hotplug-core"; + if (of_property_read_bool(node, key)) + online_core = true; + else + online_core = false; + key = "qcom,core-limit-temp"; ret = of_property_read_u32(node, key, &data->core_limit_temp_degC); if (ret) @@ -6824,6 +6833,22 @@ static int probe_freq_mitigation(struct device_node *node, char *key = NULL; int ret = 0; + key = "qcom,limit-temp"; + ret = of_property_read_u32(node, key, &data->limit_temp_degC); + if (ret) + goto PROBE_FREQ_EXIT; + + key = "qcom,temp-hysteresis"; + ret = of_property_read_u32(node, key, &data->temp_hysteresis_degC); + if (ret) + goto PROBE_FREQ_EXIT; + + key = "qcom,freq-step"; + ret = of_property_read_u32(node, key, &data->bootup_freq_step); + if (ret) + goto PROBE_FREQ_EXIT; + boot_freq_mitig_enabled = true; + key = "qcom,freq-mitigation-temp"; ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc); if (ret) @@ -7156,92 +7181,8 @@ static int thermal_config_debugfs_read(struct seq_file *m, void *data) return 0; } -static int msm_thermal_dev_probe(struct platform_device *pdev) +static void msm_thermal_late_sysfs_init(void) { - int ret = 0; - char *key = NULL; - struct device_node *node = pdev->dev.of_node; - struct msm_thermal_data data; - - if (!mitigation) - return ret; - - memset(&data, 0, sizeof(struct msm_thermal_data)); - data.pdev = pdev; - - ret = msm_thermal_pre_init(&pdev->dev); - if (ret) { - pr_err("thermal pre init failed. err:%d\n", ret); - goto fail; - } - - key = "qcom,sensor-id"; - ret = of_property_read_u32(node, key, &data.sensor_id); - if (ret) - goto fail; - - key = "qcom,poll-ms"; - ret = of_property_read_u32(node, key, &data.poll_ms); - if (ret) - goto fail; - - key = "qcom,limit-temp"; - ret = of_property_read_u32(node, key, &data.limit_temp_degC); - if (ret) - goto fail; - - key = "qcom,temp-hysteresis"; - ret = of_property_read_u32(node, key, &data.temp_hysteresis_degC); - if (ret) - goto fail; - - key = "qcom,freq-step"; - ret = of_property_read_u32(node, key, &data.bootup_freq_step); - if (ret) - goto fail; - - key = "qcom,online-hotplug-core"; - if (of_property_read_bool(node, key)) - online_core = true; - else - online_core = false; - - probe_sensor_info(node, &data, pdev); - ret = probe_cc(node, &data, pdev); - - ret = probe_freq_mitigation(node, &data, pdev); - ret = probe_cx_phase_ctrl(node, &data, pdev); - ret = probe_gfx_phase_ctrl(node, &data, pdev); - ret = probe_therm_reset(node, &data, pdev); - - ret = probe_vdd_mx(node, &data, pdev); - if (ret == -EPROBE_DEFER) - goto fail; - /* - * Probe optional properties below. Call probe_psm before - * probe_vdd_rstr because rpm_regulator_get has to be called - * before devm_regulator_get - * probe_ocr should be called after probe_vdd_rstr to reuse the - * regualtor handle. calling devm_regulator_get more than once - * will fail. - */ - ret = probe_psm(node, &data, pdev); - if (ret == -EPROBE_DEFER) - goto fail; - - update_cpu_topology(&pdev->dev); - ret = probe_vdd_rstr(node, &data, pdev); - if (ret == -EPROBE_DEFER) - goto fail; - ret = probe_ocr(node, &data, pdev); - - ret = fetch_cpu_mitigaiton_info(&data, pdev); - if (ret) { - pr_err("Error fetching CPU mitigation information. err:%d\n", - ret); - goto probe_exit; - } - /* * In case sysfs add nodes get called before probe function. * Need to make sure sysfs node is created again @@ -7266,20 +7207,77 @@ static int msm_thermal_dev_probe(struct platform_device *pdev) create_cpu_topology_sysfs(); cluster_info_nodes_called = false; } - msm_thermal_ioctl_init(); - ret = msm_thermal_init(&data); - msm_thermal_probed = true; +} - if (interrupt_mode_enable) { - interrupt_mode_init(); - interrupt_mode_enable = false; +static int probe_deferrable_properties(struct device_node *node, + struct msm_thermal_data *data, struct platform_device *pdev) +{ + int ret = 0; + + /* + * Probe optional properties below. Call probe_psm before + * probe_vdd_rstr because rpm_regulator_get has to be called + * before devm_regulator_get + * probe_ocr should be called after probe_vdd_rstr to reuse the + * regualtor handle. calling devm_regulator_get more than once + * will fail. + */ + ret = probe_psm(node, data, pdev); + if (ret == -EPROBE_DEFER) + return ret; + + ret = probe_vdd_rstr(node, data, pdev); + if (ret == -EPROBE_DEFER) + return ret; + + probe_ocr(node, data, pdev); + ret = probe_vdd_mx(node, data, pdev); + if (ret == -EPROBE_DEFER) + return ret; + + return 0; +} + +static int msm_thermal_dev_probe(struct platform_device *pdev) +{ + int ret = 0; + struct device_node *node = pdev->dev.of_node; + struct msm_thermal_data data; + + if (!mitigation) + return ret; + + memset(&data, 0, sizeof(struct msm_thermal_data)); + data.pdev = pdev; + + ret = msm_thermal_pre_init(&pdev->dev); + if (ret) { + pr_err("thermal pre init failed. err:%d\n", ret); + goto probe_exit; } + ret = probe_deferrable_properties(node, &data, pdev); + if (ret) + goto probe_exit; - return ret; -fail: + probe_sensor_info(node, &data, pdev); + probe_cc(node, &data, pdev); + probe_freq_mitigation(node, &data, pdev); + probe_cx_phase_ctrl(node, &data, pdev); + probe_gfx_phase_ctrl(node, &data, pdev); + probe_therm_reset(node, &data, pdev); + update_cpu_topology(&pdev->dev); + ret = fetch_cpu_mitigaiton_info(&data, pdev); + if (ret) { + pr_err("Error fetching CPU mitigation information. err:%d\n", + ret); + goto probe_exit; + } + msm_thermal_late_sysfs_init(); + ret = msm_thermal_init(&data); if (ret) - pr_err("Failed reading node=%s, key=%s. err:%d\n", - node->full_name, key, ret); + goto probe_exit; + msm_thermal_probed = true; + probe_exit: return ret; } @@ -7410,7 +7408,6 @@ int __init msm_thermal_late_init(void) } } msm_thermal_add_mx_nodes(); - interrupt_mode_init(); create_cpu_topology_sysfs(); create_thermal_debugfs(); msm_thermal_add_bucket_info_nodes(); diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c index 87939140f82e..bddee84d81e0 100644 --- a/drivers/usb/gadget/function/f_diag.c +++ b/drivers/usb/gadget/function/f_diag.c @@ -204,8 +204,9 @@ static void diag_context_release(struct kref *kref) static void diag_update_pid_and_serial_num(struct diag_context *ctxt) { struct usb_composite_dev *cdev = ctxt->cdev; - struct usb_gadget_strings *table; + struct usb_gadget_strings **table; struct usb_string *s; + struct usb_gadget_string_container *uc; struct dload_struct local_diag_dload = { 0 }; /* @@ -223,30 +224,26 @@ static void diag_update_pid_and_serial_num(struct diag_context *ctxt) /* update pid */ local_diag_dload.magic_struct.pid = PID_MAGIC_ID; local_diag_dload.pid = cdev->desc.idProduct; + local_diag_dload.magic_struct.serial_num = SERIAL_NUM_MAGIC_ID; - /* pass on product id and serial number to dload */ - if (!cdev->desc.iSerialNumber) { - /* - * Serial number is filled by the composite driver. So - * it is fair enough to assume that it will always be - * found at first table of strings. - */ - table = *(cdev->driver->strings); + list_for_each_entry(uc, &cdev->gstrings, list) { + table = (struct usb_gadget_strings **)uc->stash; if (!table) { pr_err("%s: can't update dload cookie\n", __func__); - return; + break; } - for (s = table->strings; s && s->s; s++) { + + for (s = (*table)->strings; s && s->s; s++) { if (s->id == cdev->desc.iSerialNumber) { - local_diag_dload.magic_struct.serial_num = - SERIAL_NUM_MAGIC_ID; strlcpy(local_diag_dload.serial_number, s->s, SERIAL_NUMBER_LENGTH); - break; + goto update_dload; } } + } +update_dload: pr_debug("%s: dload:%p pid:%x serial_num:%s\n", __func__, diag_dload, local_diag_dload.pid, local_diag_dload.serial_number); diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 4a7be5416acb..15d85b40388f 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -3704,7 +3704,7 @@ static int mdss_fb_set_par(struct fb_info *info) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; struct fb_var_screeninfo *var = &info->var; - int old_imgType; + int old_imgType, old_format; int ret = 0; ret = mdss_fb_pan_idle(mfd); @@ -3787,6 +3787,12 @@ static int mdss_fb_set_par(struct fb_info *info) mfd->fbi->fix.smem_len = PAGE_ALIGN(mfd->fbi->fix.line_length * mfd->fbi->var.yres) * mfd->fb_page; + old_format = mdss_grayscale_to_mdp_format(var->grayscale); + if (!IS_ERR_VALUE(old_format)) { + if (old_format != mfd->panel_info->out_format) + mfd->panel_reconfig = true; + } + if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) { mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); mdss_fb_var_to_panelinfo(var, mfd->panel_info); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 018d7519bf8f..ab2c9c0e501f 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -2346,6 +2346,24 @@ bool hdmi_edid_get_scdc_support(void *input) return scdc_present; } +/** + * hdmi_edid_sink_scramble_override() - check if override has been enabled + * @input: edid data + * + * Return true if scrambling override is enabled false otherwise. + */ +bool hdmi_edid_sink_scramble_override(void *input) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + + if (edid_ctrl->edid_override && + (edid_ctrl->override_data.scramble != -1)) + return true; + + return false; + +} + bool hdmi_edid_get_sink_scrambler_support(void *input) { struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index 6cf0f1240f8a..4dd92ed32364 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -32,6 +32,7 @@ int hdmi_edid_parser(void *edid_ctrl); u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size); u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution); u32 hdmi_edid_get_sink_mode(void *edid_ctrl); +bool hdmi_edid_sink_scramble_override(void *input); bool hdmi_edid_get_sink_scrambler_support(void *input); bool hdmi_edid_get_scdc_support(void *input); int hdmi_edid_get_audio_blk(void *edid_ctrl, diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 94b7bf02ccd0..4f266fffadfb 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -77,6 +77,10 @@ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 #define HDMI_TX_3_MAX_PCLK_RATE 297000 #define HDMI_TX_4_MAX_PCLK_RATE 600000 +#define HDMI_TX_KHZ_TO_HZ 1000U + +#define hdmi_tx_get_fd(x) (x ? hdmi_ctrl->feature_data[ffs(x) - 1] : 0) +#define hdmi_tx_set_fd(x, y) {if (x) hdmi_ctrl->feature_data[ffs(x) - 1] = y; } /* Enable HDCP by default */ static bool hdcp_feature_on = true; @@ -90,6 +94,9 @@ static bool hdcp_feature_on = true; #define VENDOR_IFRAME_LINE_NUMBER 3 #define MAX_EDID_READ_RETRY 5 +#define HDMI_TX_MIN_FPS 20000 +#define HDMI_TX_MAX_FPS 120000 + enum { DATA_BYTE_1, DATA_BYTE_2, @@ -162,6 +169,7 @@ static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl); static void hdmi_tx_set_vendor_specific_infoframe( struct hdmi_tx_ctrl *hdmi_ctrl); +static void hdmi_tx_fps_work(struct work_struct *work); static struct mdss_hw hdmi_tx_hw = { .hw_ndx = MDSS_HW_HDMI, @@ -390,12 +398,15 @@ static int hdmi_tx_get_vic_from_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl, new_vic = pinfo->vic; DEV_DBG("%s: %s is supported\n", __func__, msm_hdmi_mode_2string(new_vic)); + pinfo->lcdc.frame_rate = info.refresh_rate; } else { DEV_ERR("%s: invalid or not supported vic %d\n", __func__, pinfo->vic); return -EPERM; } } else { + u64 pclk; + timing.active_h = pinfo->xres; timing.back_porch_h = pinfo->lcdc.h_back_porch; timing.front_porch_h = pinfo->lcdc.h_front_porch; @@ -416,7 +427,10 @@ static int hdmi_tx_get_vic_from_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl, timing.active_v, timing.back_porch_v, timing.front_porch_v, timing.pulse_width_v, v_total); - timing.pixel_freq = ((unsigned long int)pinfo->clk_rate / 1000); + pclk = pinfo->clk_rate; + do_div(pclk, HDMI_TX_KHZ_TO_HZ); + + timing.pixel_freq = (unsigned long) pclk; if (h_total && v_total) { timing.refresh_rate = ((timing.pixel_freq * 1000) / (h_total * v_total)) * 1000; @@ -436,7 +450,7 @@ static int hdmi_tx_get_vic_from_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl, static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) { return hdmi_edid_get_sink_mode( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1; + hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)) ? 0 : 1; } /* hdmi_tx_is_dvi_mode */ static inline bool hdmi_tx_is_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) @@ -446,21 +460,22 @@ static inline bool hdmi_tx_is_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) static inline bool hdmi_tx_is_cec_wakeup_en(struct hdmi_tx_ctrl *hdmi_ctrl) { - if (!hdmi_ctrl || !hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]) + void *fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW); + + if (!hdmi_ctrl || !fd) return false; - return hdmi_cec_is_wakeup_en( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]); + return hdmi_cec_is_wakeup_en(fd); } -static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl, - bool suspend) +static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl) { - if (!hdmi_ctrl || !hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]) + void *fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW); + + if (!hdmi_ctrl || !fd) return; - hdmi_cec_device_suspend(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW], - suspend); + hdmi_cec_device_suspend(fd, hdmi_ctrl->panel_suspend); } @@ -580,7 +595,7 @@ void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(device); if (hdmi_ctrl) - return hdmi_ctrl->feature_data[feature_type]; + return hdmi_tx_get_fd(feature_type); else return NULL; @@ -742,6 +757,41 @@ end: return ret; } +static int hdmi_tx_update_pixel_clk(struct hdmi_tx_ctrl *hdmi_ctrl, int fps) +{ + struct dss_module_power *power_data = NULL; + struct mdss_panel_info *pinfo; + int rc = 0; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + rc = -EINVAL; + goto end; + } + + pinfo = &hdmi_ctrl->panel_data.panel_info; + + power_data = &hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM]; + if (!power_data) { + DEV_ERR("%s: Error: invalid power data\n", __func__); + rc = -EINVAL; + goto end; + } + + if (power_data->clk_config->rate == pinfo->clk_rate) { + rc = -EINVAL; + goto end; + } + + power_data->clk_config->rate = pinfo->clk_rate; + + DEV_DBG("%s: rate %ld\n", __func__, power_data->clk_config->rate); + + msm_dss_clk_set_rate(power_data->clk_config, power_data->num_clk); +end: + return rc; +} + static ssize_t hdmi_tx_sysfs_wta_hot_plug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -935,6 +985,9 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, hdmi_tx_config_5v(hdmi_ctrl, false); } else { hdmi_tx_hpd_off(hdmi_ctrl); + + hdmi_ctrl->sdev.state = 0; + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); } break; @@ -1231,7 +1284,7 @@ static ssize_t hdmi_tx_sysfs_wta_s3d_mode(struct device *dev, if (s3d_mode > HDMI_S3D_NONE && !hdmi_edid_is_s3d_mode_supported( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], + hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), hdmi_ctrl->vid_cfg.vic, s3d_mode)) { DEV_ERR("%s: s3d mode not supported in current video mode\n", @@ -1723,58 +1776,50 @@ end: } /* Enable HDMI features */ -static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, - struct fb_info *fbi) +static int hdmi_tx_init_edid(struct hdmi_tx_ctrl *hdmi_ctrl) { struct hdmi_edid_init_data edid_init_data = {0}; - struct hdmi_hdcp_init_data hdcp_init_data = {0}; - struct hdmi_cec_init_data cec_init_data = {0}; - struct cec_abstract_init_data cec_abst_init_data = {0}; - struct hdmi_audio_init_data audio_init_data = {0}; - struct resource *res = NULL; - void *fd = NULL; - int ret = 0; - void *cec_hw_data, *cec_abst_data; - - if (!hdmi_ctrl || !fbi) { - DEV_ERR("%s: invalid input\n", __func__); - ret = -EINVAL; - goto end; - } + void *edid_data; + int rc = 0; - /* Initialize EDID feature */ edid_init_data.kobj = hdmi_ctrl->kobj; edid_init_data.ds_data = hdmi_ctrl->ds_data; edid_init_data.max_pclk_khz = hdmi_ctrl->max_pclk_khz; - fd = hdmi_edid_init(&edid_init_data); - if (!fd) { - DEV_ERR("%s: hdmi_edid_init failed\n", __func__); - ret = -ENODEV; + edid_data = hdmi_edid_init(&edid_init_data); + if (!edid_data) { + DEV_ERR("%s: edid init failed\n", __func__); + rc = -ENODEV; goto end; } - hdmi_ctrl->panel_data.panel_info.edid_data = fd; - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] = fd; + hdmi_ctrl->panel_data.panel_info.edid_data = edid_data; + hdmi_tx_set_fd(HDMI_TX_FEAT_EDID, edid_data); /* get edid buffer from edid parser */ hdmi_ctrl->edid_buf = edid_init_data.buf; hdmi_ctrl->edid_buf_size = edid_init_data.buf_size; - hdmi_edid_set_video_resolution(fd, hdmi_ctrl->vid_cfg.vic, true); + hdmi_edid_set_video_resolution(edid_data, hdmi_ctrl->vid_cfg.vic, true); +end: + return rc; +} - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] = fd; +static int hdmi_tx_init_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct hdmi_hdcp_init_data hdcp_init_data = {0}; + struct resource *res; + void *hdcp_data; + int rc = 0; res = platform_get_resource_byname(hdmi_ctrl->pdev, IORESOURCE_MEM, hdmi_tx_io_name(HDMI_TX_CORE_IO)); if (!res) { - DEV_ERR("%s: Error getting HDMI tx core resource\n", - __func__); - ret = -ENODEV; - goto err_res; + DEV_ERR("%s: Error getting HDMI tx core resource\n", __func__); + rc = -EINVAL; + goto end; } - /* Initialize HDCP features */ hdcp_init_data.phy_addr = res->start; hdcp_init_data.core_io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; hdcp_init_data.qfprom_io = &hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO]; @@ -1789,30 +1834,38 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, hdcp_init_data.timing = &hdmi_ctrl->vid_cfg.timing; if (hdmi_ctrl->hdcp14_present) { - fd = hdmi_hdcp_init(&hdcp_init_data); + hdcp_data = hdmi_hdcp_init(&hdcp_init_data); - if (IS_ERR_OR_NULL(fd)) { - DEV_WARN("%s: hdmi_hdcp_init failed\n", __func__); - ret = -ENODEV; - goto err_res; + if (IS_ERR_OR_NULL(hdcp_data)) { + DEV_ERR("%s: hdcp 1.4 init failed\n", __func__); + rc = -EINVAL; + goto end; } else { - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] = fd; - DEV_DBG("%s: HDCP 1.4 configured\n", __func__); + hdmi_tx_set_fd(HDMI_TX_FEAT_HDCP, hdcp_data); + DEV_DBG("%s: HDCP 1.4 initialized\n", __func__); } } - fd = hdmi_hdcp2p2_init(&hdcp_init_data); + hdcp_data = hdmi_hdcp2p2_init(&hdcp_init_data); - if (IS_ERR_OR_NULL(fd)) { - DEV_WARN("%s: hdmi_hdcp2p2_init failed\n", __func__); - ret = -ENODEV; - goto err_hdcp; + if (IS_ERR_OR_NULL(hdcp_data)) { + DEV_ERR("%s: hdcp 2.2 init failed\n", __func__); + rc = -EINVAL; + goto end; } else { - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2] = fd; - DEV_DBG("%s: HDCP 2.2 configured\n", __func__); + hdmi_tx_set_fd(HDMI_TX_FEAT_HDCP2P2, hdcp_data); + DEV_DBG("%s: HDCP 2.2 initialized\n", __func__); } +end: + return rc; +} + +static int hdmi_tx_init_cec_hw(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct hdmi_cec_init_data cec_init_data = {0}; + void *cec_hw_data; + int rc = 0; - /* initialize cec hw feature and get ops */ cec_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; cec_init_data.workq = hdmi_ctrl->workq; cec_init_data.pinfo = &hdmi_ctrl->panel_data.panel_info; @@ -1821,53 +1874,153 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, cec_hw_data = hdmi_cec_init(&cec_init_data); if (IS_ERR_OR_NULL(cec_hw_data)) { - DEV_ERR("%s: error cec init\n", __func__); - goto err_cec_hw; + DEV_ERR("%s: cec init failed\n", __func__); + rc = -EINVAL; + } else { + hdmi_ctrl->panel_data.panel_info.is_cec_supported = true; + hdmi_tx_set_fd(HDMI_TX_FEAT_CEC_HW, cec_hw_data); + DEV_DBG("%s: cec hw initialized\n", __func__); } - hdmi_ctrl->panel_data.panel_info.is_cec_supported = true; - hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW] = cec_hw_data; + return rc; +} + +static int hdmi_tx_init_cec_abst(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct cec_abstract_init_data cec_abst_init_data = {0}; + void *cec_abst_data; + int rc = 0; - /* initialize cec abstract layer and get callbacks */ cec_abst_init_data.kobj = hdmi_ctrl->kobj; cec_abst_init_data.ops = &hdmi_ctrl->hdmi_cec_ops; cec_abst_init_data.cbs = &hdmi_ctrl->hdmi_cec_cbs; cec_abst_data = cec_abstract_init(&cec_abst_init_data); if (IS_ERR_OR_NULL(cec_abst_data)) { - DEV_ERR("%s: error cec init\n", __func__); - goto err_cec_abst; + DEV_ERR("%s: cec abst init failed\n", __func__); + rc = -EINVAL; + } else { + hdmi_tx_set_fd(HDMI_TX_FEAT_CEC_ABST, cec_abst_data); + hdmi_ctrl->panel_data.panel_info.cec_data = cec_abst_data; + DEV_DBG("%s: cec abst initialized\n", __func__); } - /* keep cec abstract data */ - hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_ABST] = cec_abst_data; - hdmi_ctrl->panel_data.panel_info.cec_data = cec_abst_data; + return rc; +} + +static int hdmi_tx_init_audio(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct hdmi_audio_init_data audio_init_data = {0}; + void *audio_data; + int rc = 0; audio_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; audio_init_data.ops = &hdmi_ctrl->audio_ops; - hdmi_ctrl->audio_data = hdmi_audio_register(&audio_init_data); - return 0; + audio_data = hdmi_audio_register(&audio_init_data); + if (!audio_data) { + rc = -EINVAL; + DEV_ERR("%s: audio init failed\n", __func__); + } else { + hdmi_ctrl->audio_data = audio_data; + DEV_DBG("%s: audio initialized\n", __func__); + } -err_cec_abst: - hdmi_cec_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]); - hdmi_ctrl->panel_data.panel_info.is_cec_supported = false; -err_cec_hw: - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]) { - hdmi_hdcp2p2_deinit( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]); - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2] = NULL; - } -err_hdcp: - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) { - hdmi_hdcp_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]); - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] = NULL; - } -err_res: - hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]); + return rc; +} + +static void hdmi_tx_deinit_features(struct hdmi_tx_ctrl *hdmi_ctrl, + u32 features) +{ + void *fd; + + if (features & HDMI_TX_FEAT_CEC_ABST) { + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_ABST); + + cec_abstract_deinit(fd); + + hdmi_ctrl->panel_data.panel_info.cec_data = NULL; + hdmi_tx_set_fd(HDMI_TX_FEAT_CEC_ABST, 0); + } + + if (features & HDMI_TX_FEAT_CEC_HW) { + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW); + + hdmi_cec_deinit(fd); + hdmi_ctrl->panel_data.panel_info.is_cec_supported = false; + hdmi_tx_set_fd(HDMI_TX_FEAT_CEC_HW, 0); + } + + if (features & HDMI_TX_FEAT_HDCP2P2) { + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_HDCP2P2); + + hdmi_hdcp2p2_deinit(fd); + hdmi_tx_set_fd(HDMI_TX_FEAT_HDCP2P2, 0); + } + + if (features & HDMI_TX_FEAT_HDCP) { + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_HDCP); + + hdmi_hdcp_deinit(fd); + hdmi_tx_set_fd(HDMI_TX_FEAT_HDCP, 0); + } + + if (features & HDMI_TX_FEAT_EDID) { + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); + + hdmi_edid_deinit(fd); + hdmi_ctrl->edid_buf = NULL; + hdmi_ctrl->edid_buf_size = 0; + hdmi_tx_set_fd(HDMI_TX_FEAT_EDID, 0); + } +} /* hdmi_tx_init_features */ + +static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, + struct fb_info *fbi) +{ + int ret = 0; + u32 deinit_features = 0; + + if (!hdmi_ctrl || !fbi) { + DEV_ERR("%s: invalid input\n", __func__); + ret = -EINVAL; + goto end; + } + + ret = hdmi_tx_init_edid(hdmi_ctrl); + if (ret) + goto end; + + ret = hdmi_tx_init_hdcp(hdmi_ctrl); + if (ret) { + deinit_features |= HDMI_TX_FEAT_EDID; + goto err; + } + + ret = hdmi_tx_init_cec_hw(hdmi_ctrl); + if (ret) { + deinit_features |= HDMI_TX_FEAT_HDCP; + goto err; + } + + ret = hdmi_tx_init_cec_abst(hdmi_ctrl); + if (ret) { + deinit_features |= HDMI_TX_FEAT_CEC_HW; + goto err; + } + + ret = hdmi_tx_init_audio(hdmi_ctrl); + if (ret) { + deinit_features |= HDMI_TX_FEAT_CEC_ABST; + goto err; + } + + return 0; +err: + hdmi_tx_deinit_features(hdmi_ctrl, deinit_features); end: return ret; -} /* hdmi_tx_init_features */ +} static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl) { @@ -1905,6 +2058,7 @@ static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl) pinfo->lcdc.v_back_porch = timing.back_porch_v; pinfo->lcdc.v_front_porch = timing.front_porch_v; pinfo->lcdc.v_pulse_width = timing.pulse_width_v; + pinfo->lcdc.frame_rate = timing.refresh_rate; pinfo->type = DTV_PANEL; pinfo->pdest = DISPLAY_3; @@ -1912,6 +2066,9 @@ static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl) pinfo->bpp = 24; pinfo->fb_num = 1; + pinfo->min_fps = HDMI_TX_MIN_FPS; + pinfo->max_fps = HDMI_TX_MAX_FPS; + pinfo->lcdc.border_clr = 0; /* blk */ pinfo->lcdc.underflow_clr = 0xff; /* blue */ pinfo->lcdc.hsync_skew = 0; @@ -1932,7 +2089,7 @@ static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl) return -EINVAL; } - data = hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]; + data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); if (!hdmi_tx_is_controller_on(hdmi_ctrl)) { DEV_ERR("%s: failed: HDMI controller is off", __func__); @@ -1972,7 +2129,7 @@ static void hdmi_tx_update_hdcp_info(struct hdmi_tx_ctrl *hdmi_ctrl) } /* check first if hdcp2p2 is supported */ - fd = hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]; + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_HDCP2P2); if (fd) ops = hdmi_hdcp2p2_start(fd); @@ -1987,7 +2144,7 @@ static void hdmi_tx_update_hdcp_info(struct hdmi_tx_ctrl *hdmi_ctrl) hdcp1_check_if_supported_load_app(); if (hdmi_ctrl->hdcp14_present) { - fd = hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]; + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_HDCP); ops = hdmi_hdcp_start(fd); } } @@ -2105,6 +2262,18 @@ end: return ret; } /* hdmi_tx_check_capability */ +static void hdmi_tx_update_panel_data(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct mdss_panel_info *pinfo = &hdmi_ctrl->panel_data.panel_info; + + pinfo->saved_total = mdss_panel_get_htotal(pinfo, true); + pinfo->saved_fporch = hdmi_ctrl->vid_cfg.timing.front_porch_h; + + pinfo->current_fps = hdmi_ctrl->vid_cfg.timing.refresh_rate; + pinfo->default_fps = hdmi_ctrl->vid_cfg.timing.refresh_rate; + pinfo->lcdc.frame_rate = hdmi_ctrl->vid_cfg.timing.refresh_rate; +} + static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl, struct mdss_panel_info *pinfo) { @@ -2146,7 +2315,7 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl, vid_cfg->vic = new_vic; vid_cfg->avi_iframe.pixel_format = pinfo->out_format; vid_cfg->avi_iframe.scan_info = hdmi_edid_get_sink_scaninfo( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], + hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), hdmi_ctrl->vid_cfg.vic); vid_cfg->avi_iframe.bar_info.end_of_top_bar = 0x0; @@ -2180,12 +2349,30 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl, (vid_cfg->timing.pixel_freq * 1000) >> div; hdmi_edid_set_video_resolution( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], + hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), vid_cfg->vic, false); + hdmi_tx_update_panel_data(hdmi_ctrl); + return res_changed; } /* hdmi_tx_set_video_fmt */ +static bool hdmi_tx_check_for_video_update(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct msm_hdmi_mode_timing_info *timing = &hdmi_ctrl->vid_cfg.timing; + struct mdss_panel_info *pinfo = &hdmi_ctrl->panel_data.panel_info; + + if (timing->back_porch_h != pinfo->lcdc.h_back_porch || + timing->front_porch_h != pinfo->lcdc.h_front_porch || + timing->pulse_width_h != pinfo->lcdc.h_pulse_width || + timing->back_porch_v != pinfo->lcdc.v_back_porch || + timing->front_porch_v != pinfo->lcdc.v_front_porch || + timing->pulse_width_v != pinfo->lcdc.v_pulse_width) + return true; + + return false; +} + static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl) { u32 total_v = 0; @@ -2197,6 +2384,7 @@ static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl) u32 div = 0; struct dss_io_data *io = NULL; struct msm_hdmi_mode_timing_info *timing = NULL; + struct mdss_panel_info *pinfo; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); @@ -2214,6 +2402,9 @@ static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl) DEV_ERR("%s: Core io is not initialized\n", __func__); return -EPERM; } + + pinfo = &hdmi_ctrl->panel_data.panel_info; + /* * In case of YUV420 output, Horizontal timing parameters should be * reduced by half @@ -2221,6 +2412,35 @@ static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl) if (hdmi_ctrl->vid_cfg.avi_iframe.pixel_format == MDP_Y_CBCR_H2V2) div = 1; + if (pinfo->dynamic_fps) { + if (!hdmi_tx_check_for_video_update(hdmi_ctrl)) + return -EINVAL; + + if (pinfo->dfps_update == + DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP || + pinfo->dfps_update == + DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) { + DEV_DBG("%s: hfp=%d, hbp=%d, hpw=%d\n", __func__, + pinfo->lcdc.h_front_porch, + pinfo->lcdc.h_back_porch, + pinfo->lcdc.h_pulse_width); + + timing->back_porch_h = pinfo->lcdc.h_back_porch; + timing->front_porch_h = pinfo->lcdc.h_front_porch; + timing->pulse_width_h = pinfo->lcdc.h_pulse_width; + } else if (pinfo->dfps_update == + DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP) { + DEV_DBG("%s: vfp=%d, vbp=%d, vpw=%d\n", __func__, + pinfo->lcdc.v_front_porch, + pinfo->lcdc.v_back_porch, + pinfo->lcdc.v_pulse_width); + + timing->back_porch_v = pinfo->lcdc.v_back_porch; + timing->front_porch_v = pinfo->lcdc.v_front_porch; + timing->pulse_width_v = pinfo->lcdc.v_pulse_width; + } + } + total_h = (hdmi_tx_get_h_total(timing) >> div) - 1; total_v = hdmi_tx_get_v_total(timing) - 1; @@ -2446,7 +2666,7 @@ static void hdmi_tx_set_vendor_specific_infoframe( if ((hdmi_ctrl->s3d_mode != HDMI_S3D_NONE) && hdmi_edid_is_s3d_mode_supported( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], + hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), hdmi_ctrl->vid_cfg.vic, hdmi_ctrl->s3d_mode)) { switch (hdmi_ctrl->s3d_mode) { @@ -2650,8 +2870,7 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) reg_val |= BIT(2); /* Set transmission mode to DVI based in EDID info */ - if (hdmi_edid_get_sink_mode( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) == 0) + if (!hdmi_edid_get_sink_mode(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID))) reg_val &= ~BIT(1); /* DVI mode */ /* @@ -3113,7 +3332,7 @@ static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev, } return hdmi_edid_get_audio_blk( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], blk); + hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), blk); } /* hdmi_tx_get_audio_edid_blk */ static u8 hdmi_tx_tmds_enabled(struct platform_device *pdev) @@ -3292,7 +3511,7 @@ int hdmi_tx_setup_scrambler(struct hdmi_tx_ctrl *hdmi_ctrl) return -EINVAL; } - edid_data = hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]; + edid_data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); timing = &hdmi_ctrl->vid_cfg.timing; if (!timing) { @@ -3308,15 +3527,17 @@ int hdmi_tx_setup_scrambler(struct hdmi_tx_ctrl *hdmi_ctrl) rate = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl); - if (rate > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { - scrambler_on = true; - tmds_clock_ratio = 1; - } else { - if (hdmi_edid_get_sink_scrambler_support(edid_data)) + scrambler_on = hdmi_edid_get_sink_scrambler_support(edid_data); + + if (!hdmi_edid_sink_scramble_override(edid_data)) { + if (rate > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) scrambler_on = true; } if (scrambler_on) { + if (rate > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) + tmds_clock_ratio = 1; + rc = hdmi_scdc_write(&hdmi_ctrl->ddc_ctrl, HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE, tmds_clock_ratio); @@ -3476,17 +3697,18 @@ static inline void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl) sizeof(struct msm_ext_disp_audio_setup_params)); } -static int hdmi_tx_power_off(struct mdss_panel_data *panel_data) +static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl) { struct dss_io_data *io = NULL; - struct hdmi_tx_ctrl *hdmi_ctrl = - hdmi_tx_get_drvdata_from_panel_data(panel_data); + struct mdss_panel_data *panel_data; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return -EINVAL; } + panel_data = &hdmi_ctrl->panel_data; + io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; if (!io->base) { DEV_ERR("%s: Core io is not initialized\n", __func__); @@ -3522,14 +3744,13 @@ end: return 0; } /* hdmi_tx_power_off */ -static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) +static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) { int rc = 0; int res_changed = RESOLUTION_UNCHANGED; struct dss_io_data *io = NULL; struct mdss_panel_info *panel_info = NULL; - struct hdmi_tx_ctrl *hdmi_ctrl = - hdmi_tx_get_drvdata_from_panel_data(panel_data); + struct mdss_panel_data *panel_data; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); @@ -3548,6 +3769,8 @@ static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) goto end; } + panel_data = &hdmi_ctrl->panel_data; + rc = hdmi_tx_check_clk_state(hdmi_ctrl, HDMI_TX_HPD_PM); if (rc) goto end; @@ -3849,9 +4072,10 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data) hdmi_ctrl->hdmi_tx_ver)) DEV_ERR("%s: hdmi_ddc_isr failed\n", __func__); - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]) - if (hdmi_cec_isr(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW])) + if (hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW)) { + if (hdmi_cec_isr(hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW))) DEV_ERR("%s: hdmi_cec_isr failed\n", __func__); + } if (hdmi_ctrl->hdcp_ops && hdmi_ctrl->hdcp_data) { if (hdmi_ctrl->hdcp_ops->hdmi_hdcp_isr) { @@ -3872,37 +4096,11 @@ static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl) return; } - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_ABST]) { - cec_abstract_deinit( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_ABST]); - hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_ABST] = NULL; - } - - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]) { - hdmi_cec_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]); - hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW] = NULL; - hdmi_ctrl->panel_data.panel_info.is_cec_supported = false; - } - - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) { - hdmi_hdcp_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]); - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] = NULL; - } - - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]) { - hdmi_hdcp2p2_deinit( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]); - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2] = NULL; - } + hdmi_tx_deinit_features(hdmi_ctrl, HDMI_TX_FEAT_MAX); hdmi_ctrl->hdcp_ops = NULL; hdmi_ctrl->hdcp_data = NULL; - if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) { - hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]); - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] = NULL; - } - switch_dev_unregister(&hdmi_ctrl->sdev); if (hdmi_ctrl->workq) destroy_workqueue(hdmi_ctrl->workq); @@ -3957,6 +4155,7 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl) init_completion(&hdmi_ctrl->hpd_int_done); INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work); + INIT_WORK(&hdmi_ctrl->fps_work, hdmi_tx_fps_work); INIT_WORK(&hdmi_ctrl->cable_notify_work, hdmi_tx_cable_notify_work); INIT_DELAYED_WORK(&hdmi_ctrl->hdcp_cb_work, hdmi_tx_hdcp_cb_work); @@ -4088,212 +4287,379 @@ static char *hdmi_tx_get_event_name(int event) } } -static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, - int event, void *arg) +static void hdmi_tx_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl) { - int rc = 0, new_vic = -1; - struct hdmi_tx_ctrl *hdmi_ctrl = - hdmi_tx_get_drvdata_from_panel_data(panel_data); + int rc = 0, vic = 0; + u64 pclk; + struct mdss_panel_data *pdata; + struct mdss_panel_info *pinfo; + struct msm_hdmi_mode_timing_info timing = {0}; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); - return -EINVAL; + return; } - mutex_lock(&hdmi_ctrl->tx_lock); + pdata = &hdmi_ctrl->panel_data; + pinfo = &pdata->panel_info; - DEV_DBG("%s: event = %s suspend=%d, hpd_feature=%d\n", __func__, - hdmi_tx_get_event_name(event), hdmi_ctrl->panel_suspend, - hdmi_ctrl->hpd_feature_on); + if (!pinfo->dynamic_fps) { + DEV_DBG("%s: Dynamic fps not enabled\n", __func__); + return; + } - switch (event) { - case MDSS_EVENT_FB_REGISTERED: - rc = hdmi_tx_sysfs_create(hdmi_ctrl, arg); - if (rc) { - DEV_ERR("%s: hdmi_tx_sysfs_create failed.rc=%d\n", - __func__, rc); - goto end; - } - rc = hdmi_tx_init_features(hdmi_ctrl, arg); - if (rc) { - DEV_ERR("%s: init_features failed.rc=%d\n", - __func__, rc); - hdmi_tx_sysfs_remove(hdmi_ctrl); - goto end; + if (hdmi_ctrl->dynamic_fps == pinfo->current_fps) { + DEV_DBG("%s: Panel is already at this FPS: %d\n", + __func__, hdmi_ctrl->dynamic_fps); + return; + } + + if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) + hdmi_tx_hdcp_off(hdmi_ctrl); + + if (pinfo->dfps_update == DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) { + if (hdmi_tx_video_setup(hdmi_ctrl)) { + DEV_DBG("%s: no change in video timing\n", __func__); + return; } - rc = hdmi_tx_init_switch_dev(hdmi_ctrl); - if (rc) { - DEV_ERR("%s: init switch dev failed.rc=%d\n", - __func__, rc); - hdmi_tx_sysfs_remove(hdmi_ctrl); - goto end; + if (hdmi_tx_update_pixel_clk(hdmi_ctrl, + hdmi_ctrl->dynamic_fps)) { + DEV_DBG("%s: no change in clk\n", __func__); + return; } - if (hdmi_ctrl->pdata.primary || !hdmi_ctrl->pdata.pluggable) { - reinit_completion(&hdmi_ctrl->hpd_int_done); - rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true); - if (rc) { - DEV_ERR("%s: hpd_enable failed. rc=%d\n", - __func__, rc); - hdmi_tx_sysfs_remove(hdmi_ctrl); - goto end; - } else { - hdmi_ctrl->hpd_feature_on = true; - } + pinfo->saved_total = mdss_panel_get_htotal(pinfo, true); + pinfo->saved_fporch = pinfo->lcdc.h_front_porch; + } else if (pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP) { + if (hdmi_tx_video_setup(hdmi_ctrl)) { + DEV_DBG("%s: no change in video timing\n", __func__); + return; } - break; + pinfo->saved_total = mdss_panel_get_htotal(pinfo, true); + pinfo->saved_fporch = pinfo->lcdc.h_front_porch; + } else if (pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP) { + if (hdmi_tx_video_setup(hdmi_ctrl)) { + DEV_DBG("%s: no change in video timing\n", __func__); + return; + } - case MDSS_EVENT_CHECK_PARAMS: - new_vic = hdmi_tx_get_vic_from_panel_info(hdmi_ctrl, - (struct mdss_panel_info *)arg); - if ((new_vic < 0) || (new_vic > HDMI_VFRMT_MAX)) { - DEV_ERR("%s: invalid or not supported vic\n", __func__); - goto end; + pinfo->saved_total = mdss_panel_get_vtotal(pinfo); + pinfo->saved_fporch = pinfo->lcdc.v_front_porch; + } else if (pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { + if (hdmi_tx_update_pixel_clk(hdmi_ctrl, + hdmi_ctrl->dynamic_fps)) { + DEV_DBG("%s: no change in clk\n", __func__); + return; } + } - /* - * return value of 1 lets mdss know that panel - * needs a reconfig due to new resolution and - * it will issue close and open subsequently. - */ - if (new_vic != hdmi_ctrl->vid_cfg.vic) - rc = 1; - else - DEV_DBG("%s: no res change.\n", __func__); - break; + pinfo->current_fps = hdmi_ctrl->dynamic_fps; + pinfo->default_fps = hdmi_ctrl->dynamic_fps; + pinfo->lcdc.frame_rate = hdmi_ctrl->dynamic_fps; + pinfo->dynamic_fps = false; - case MDSS_EVENT_RESUME: - hdmi_ctrl->panel_suspend = false; - hdmi_tx_cec_device_suspend(hdmi_ctrl, hdmi_ctrl->panel_suspend); + rc = hdmi_get_supported_mode(&timing, &hdmi_ctrl->ds_data, + hdmi_ctrl->vid_cfg.vic); - if (!hdmi_ctrl->hpd_feature_on) - goto end; + if (rc || !timing.supported) { + DEV_ERR("%s: timing details\n", __func__); + return; + } - rc = hdmi_tx_hpd_on(hdmi_ctrl); - if (rc) { - DEV_ERR("%s: hpd_on failed. rc=%d\n", __func__, rc); - goto end; - } + timing.back_porch_h = pinfo->lcdc.h_back_porch; + timing.front_porch_h = pinfo->lcdc.h_front_porch; + timing.pulse_width_h = pinfo->lcdc.h_pulse_width; - if (hdmi_ctrl->sdev.state && - !hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) { - u32 timeout; - - reinit_completion(&hdmi_ctrl->hpd_int_done); - timeout = wait_for_completion_timeout( - &hdmi_ctrl->hpd_int_done, HZ/10); - if (!timeout && !hdmi_ctrl->hpd_state) { - DEV_DBG("%s: cable removed during suspend\n", - __func__); - hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); - hdmi_tx_wait_for_audio_engine(hdmi_ctrl); - hdmi_tx_send_cable_notification(hdmi_ctrl, 0); - } - } + timing.back_porch_v = pinfo->lcdc.v_back_porch; + timing.front_porch_v = pinfo->lcdc.v_front_porch; + timing.pulse_width_v = pinfo->lcdc.v_pulse_width; - break; + timing.refresh_rate = hdmi_ctrl->dynamic_fps; - case MDSS_EVENT_RESET: - if (!hdmi_ctrl->pdata.cont_splash_enabled && - hdmi_ctrl->hpd_initialized) { - hdmi_tx_set_mode(hdmi_ctrl, false); - hdmi_tx_phy_reset(hdmi_ctrl); - hdmi_tx_set_mode(hdmi_ctrl, true); - } + pclk = pinfo->clk_rate; + do_div(pclk, HDMI_TX_KHZ_TO_HZ); + timing.pixel_freq = (unsigned long) pclk; - break; + hdmi_ctrl->vid_cfg.timing = timing; - case MDSS_EVENT_UNBLANK: - rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true); + vic = hdmi_get_video_id_code(&timing, &hdmi_ctrl->ds_data); + + if (vic > 0 && hdmi_ctrl->vid_cfg.vic != vic) { + hdmi_ctrl->vid_cfg.vic = vic; + DEV_DBG("%s: switched to new resolution id %d\n", + __func__, vic); + } + + hdmi_tx_start_hdcp(hdmi_ctrl); +} + +static void hdmi_tx_fps_work(struct work_struct *work) +{ + struct hdmi_tx_ctrl *hdmi_ctrl = NULL; + + hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, fps_work); + if (!hdmi_ctrl) { + DEV_DBG("%s: invalid input\n", __func__); + return; + } + + hdmi_tx_update_fps(hdmi_ctrl); +} + +static int hdmi_tx_evt_handle_register(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc = 0; + + rc = hdmi_tx_sysfs_create(hdmi_ctrl, hdmi_ctrl->evt_arg); + if (rc) { + DEV_ERR("%s: hdmi_tx_sysfs_create failed.rc=%d\n", + __func__, rc); + goto sysfs_err; + } + rc = hdmi_tx_init_features(hdmi_ctrl, hdmi_ctrl->evt_arg); + if (rc) { + DEV_ERR("%s: init_features failed.rc=%d\n", __func__, rc); + goto init_err; + } + + rc = hdmi_tx_init_switch_dev(hdmi_ctrl); + if (rc) { + DEV_ERR("%s: init switch dev failed.rc=%d\n", __func__, rc); + goto switch_err; + } + + if (hdmi_ctrl->pdata.primary || !hdmi_ctrl->pdata.pluggable) { + reinit_completion(&hdmi_ctrl->hpd_int_done); + rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true); if (rc) { - DEV_ERR("%s: ddc power on failed. rc=%d\n", - __func__, rc); + DEV_ERR("%s: hpd_enable failed. rc=%d\n", __func__, rc); + goto primary_err; } else { - rc = hdmi_tx_power_on(panel_data); - if (rc) - DEV_ERR("%s: hdmi_tx_power_on failed. rc=%d\n", - __func__, rc); + hdmi_ctrl->hpd_feature_on = true; } - break; + } - case MDSS_EVENT_PANEL_ON: - if (!hdmi_ctrl->sim_mode) { - hdmi_tx_update_hdcp_info(hdmi_ctrl); + return 0; - rc = hdmi_tx_start_hdcp(hdmi_ctrl); - if (rc) - DEV_ERR("%s: hdcp start failed rc=%d\n", - __func__, rc); - } +primary_err: + switch_dev_unregister(&hdmi_ctrl->sdev); +switch_err: + hdmi_tx_deinit_features(hdmi_ctrl, HDMI_TX_FEAT_MAX); +init_err: + hdmi_tx_sysfs_remove(hdmi_ctrl); +sysfs_err: + return rc; +} - hdmi_ctrl->timing_gen_on = true; +static int hdmi_tx_evt_handle_check_param(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int new_vic = -1; + int rc = 0; - if (hdmi_ctrl->panel_suspend) { - DEV_DBG("%s: panel suspend has triggered\n", __func__); + new_vic = hdmi_tx_get_vic_from_panel_info(hdmi_ctrl, + hdmi_ctrl->evt_arg); + if ((new_vic < 0) || (new_vic > HDMI_VFRMT_MAX)) { + DEV_ERR("%s: invalid or not supported vic\n", __func__); + goto end; + } + /* + * return value of 1 lets mdss know that panel + * needs a reconfig due to new resolution and + * it will issue close and open subsequently. + */ + if (new_vic != hdmi_ctrl->vid_cfg.vic) { + rc = 1; + DEV_DBG("%s: res change %d ==> %d\n", __func__, + hdmi_ctrl->vid_cfg.vic, new_vic); + } +end: + return rc; +} + +static int hdmi_tx_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc = 0; + + hdmi_ctrl->panel_suspend = false; + hdmi_tx_cec_device_suspend(hdmi_ctrl); + + if (!hdmi_ctrl->hpd_feature_on) + goto end; + + rc = hdmi_tx_hpd_on(hdmi_ctrl); + if (rc) { + DEV_ERR("%s: hpd_on failed. rc=%d\n", __func__, rc); + goto end; + } + + if (hdmi_ctrl->sdev.state && + !hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) { + u32 timeout; + + reinit_completion(&hdmi_ctrl->hpd_int_done); + timeout = wait_for_completion_timeout( + &hdmi_ctrl->hpd_int_done, HZ/10); + if (!timeout && !hdmi_ctrl->hpd_state) { + DEV_DBG("%s: cable removed during suspend\n", __func__); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } - break; + } +end: + return rc; +} - case MDSS_EVENT_SUSPEND: - if (!hdmi_ctrl->hpd_feature_on) - goto end; +static int hdmi_tx_evt_handle_reset(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + if (!hdmi_ctrl->panel_data.panel_info.cont_splash_enabled && + hdmi_ctrl->hpd_initialized) { + hdmi_tx_set_mode(hdmi_ctrl, false); + hdmi_tx_phy_reset(hdmi_ctrl); + hdmi_tx_set_mode(hdmi_ctrl, true); + } - if (!hdmi_ctrl->hpd_state && !hdmi_ctrl->panel_power_on) - hdmi_tx_hpd_off(hdmi_ctrl); + return 0; +} - hdmi_ctrl->panel_suspend = true; - hdmi_tx_cec_device_suspend(hdmi_ctrl, hdmi_ctrl->panel_suspend); - break; +static int hdmi_tx_evt_handle_unblank(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc; - case MDSS_EVENT_BLANK: - if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) - hdmi_tx_hdcp_off(hdmi_ctrl); + rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true); + if (rc) { + DEV_ERR("%s: ddc power on failed. rc=%d\n", __func__, rc); + goto end; + } - break; + rc = hdmi_tx_power_on(hdmi_ctrl); + if (rc) + DEV_ERR("%s: hdmi_tx_power_on failed. rc=%d\n", __func__, rc); +end: + return rc; +} - case MDSS_EVENT_PANEL_OFF: - rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false); - if (rc) { - DEV_ERR("%s: Failed to disable ddc power\n", __func__); - return rc; - } +static int hdmi_tx_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc = 0; - if (hdmi_ctrl->panel_power_on) { - hdmi_tx_config_avmute(hdmi_ctrl, 1); - rc = hdmi_tx_power_off(panel_data); - if (rc) - DEV_ERR("%s: hdmi_tx_power_off failed.rc=%d\n", - __func__, rc); - } else { - DEV_DBG("%s: hdmi is already powered off\n", __func__); - } + if (!hdmi_ctrl->sim_mode) { + hdmi_tx_update_hdcp_info(hdmi_ctrl); - hdmi_ctrl->timing_gen_on = false; - break; + rc = hdmi_tx_start_hdcp(hdmi_ctrl); + if (rc) + DEV_ERR("%s: hdcp start failed rc=%d\n", __func__, rc); + } - case MDSS_EVENT_CLOSE: - if (panel_data->panel_info.cont_splash_enabled) { - hdmi_tx_power_off(panel_data); - panel_data->panel_info.cont_splash_enabled = false; + hdmi_ctrl->timing_gen_on = true; - goto end; - } + if (hdmi_ctrl->panel_suspend) { + DEV_DBG("%s: panel suspend has triggered\n", __func__); - if (hdmi_ctrl->hpd_feature_on && hdmi_ctrl->hpd_initialized && - !hdmi_ctrl->hpd_state) - hdmi_tx_hpd_polarity_setup(hdmi_ctrl, - HPD_CONNECT_POLARITY); - break; + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); + hdmi_tx_wait_for_audio_engine(hdmi_ctrl); + hdmi_tx_send_cable_notification(hdmi_ctrl, 0); + } + + return rc; +} + +static int hdmi_tx_evt_handle_suspend(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + if (!hdmi_ctrl->hpd_feature_on) + goto end; + + if (!hdmi_ctrl->hpd_state && !hdmi_ctrl->panel_power_on) + hdmi_tx_hpd_off(hdmi_ctrl); + + hdmi_ctrl->panel_suspend = true; + hdmi_tx_cec_device_suspend(hdmi_ctrl); +end: + return 0; +} + +static int hdmi_tx_evt_handle_blank(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) + hdmi_tx_hdcp_off(hdmi_ctrl); + + return 0; +} + +static int hdmi_tx_evt_handle_panel_off(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc; + + rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false); + if (rc) { + DEV_ERR("%s: Failed to disable ddc power\n", __func__); + goto end; } + + if (hdmi_ctrl->panel_power_on) { + hdmi_tx_config_avmute(hdmi_ctrl, 1); + rc = hdmi_tx_power_off(hdmi_ctrl); + if (rc) + DEV_ERR("%s: hdmi_tx_power_off failed.rc=%d\n", + __func__, rc); + } else { + DEV_DBG("%s: hdmi_ctrl is already powered off\n", __func__); + } + + hdmi_ctrl->timing_gen_on = false; end: + return rc; +} + +static int hdmi_tx_evt_handle_close(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + if (hdmi_ctrl->hpd_feature_on && hdmi_ctrl->hpd_initialized && + !hdmi_ctrl->hpd_state) + hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY); + + return 0; +} + +static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data, + int event, void *arg) +{ + int rc = 0; + hdmi_tx_evt_handler handler; + struct hdmi_tx_ctrl *hdmi_ctrl = + hdmi_tx_get_drvdata_from_panel_data(panel_data); + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + rc = -EINVAL; + goto end; + } + + /* UPDATE FPS is called from atomic context */ + if (event == MDSS_EVENT_PANEL_UPDATE_FPS) { + hdmi_ctrl->dynamic_fps = (u32) (unsigned long)arg; + queue_work(hdmi_ctrl->workq, &hdmi_ctrl->fps_work); + return rc; + } + + mutex_lock(&hdmi_ctrl->tx_lock); + + hdmi_ctrl->evt_arg = arg; + + DEV_DBG("%s: event = %s suspend=%d, hpd_feature=%d\n", __func__, + hdmi_tx_get_event_name(event), hdmi_ctrl->panel_suspend, + hdmi_ctrl->hpd_feature_on); + + handler = hdmi_ctrl->evt_handler[event]; + if (handler) + rc = handler(hdmi_ctrl); + mutex_unlock(&hdmi_ctrl->tx_lock); +end: return rc; -} /* hdmi_tx_panel_event_handler */ +} static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl) { @@ -4304,7 +4670,7 @@ static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl) return -EINVAL; } - hdmi_ctrl->panel_data.event_handler = hdmi_tx_panel_event_handler; + hdmi_ctrl->panel_data.event_handler = hdmi_tx_event_handler; if (!hdmi_ctrl->pdata.primary) hdmi_ctrl->vid_cfg.vic = DEFAULT_VIDEO_RESOLUTION; @@ -4894,6 +5260,29 @@ error: return rc; } /* hdmi_tx_get_dt_data */ +static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + hdmi_tx_evt_handler *handler; + + if (!hdmi_ctrl) + return -EINVAL; + + handler = hdmi_ctrl->evt_handler; + + handler[MDSS_EVENT_FB_REGISTERED] = hdmi_tx_evt_handle_register; + handler[MDSS_EVENT_CHECK_PARAMS] = hdmi_tx_evt_handle_check_param; + handler[MDSS_EVENT_RESUME] = hdmi_tx_evt_handle_resume; + handler[MDSS_EVENT_RESET] = hdmi_tx_evt_handle_reset; + handler[MDSS_EVENT_UNBLANK] = hdmi_tx_evt_handle_unblank; + handler[MDSS_EVENT_PANEL_ON] = hdmi_tx_evt_handle_panel_on; + handler[MDSS_EVENT_SUSPEND] = hdmi_tx_evt_handle_suspend; + handler[MDSS_EVENT_BLANK] = hdmi_tx_evt_handle_blank; + handler[MDSS_EVENT_PANEL_OFF] = hdmi_tx_evt_handle_panel_off; + handler[MDSS_EVENT_CLOSE] = hdmi_tx_evt_handle_close; + + return 0; +} + static int hdmi_tx_probe(struct platform_device *pdev) { int rc = 0, i; @@ -4975,6 +5364,13 @@ static int hdmi_tx_probe(struct platform_device *pdev) goto failed_dev_init; } + rc = hdmi_tx_init_event_handler(hdmi_ctrl); + if (rc) { + DEV_ERR("%s: FAILED: hdmi_tx_init_event_handler. rc=%d\n", + __func__, rc); + goto failed_dev_init; + } + rc = hdmi_tx_register_panel(hdmi_ctrl); if (rc) { DEV_ERR("%s: FAILED: register_panel. rc=%d\n", __func__, rc); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index a33ed2d4a3d1..f348bfba6929 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -121,6 +121,9 @@ struct hdmi_video_config { struct hdmi_avi_infoframe_config avi_iframe; }; +struct hdmi_tx_ctrl; +typedef int (*hdmi_tx_evt_handler) (struct hdmi_tx_ctrl *); + struct hdmi_tx_ctrl { struct platform_device *pdev; u32 hdmi_tx_ver; @@ -150,6 +153,7 @@ struct hdmi_tx_ctrl { u32 hpd_feature_on; u32 hpd_initialized; u32 vote_hdmi_core_on; + u32 dynamic_fps; u8 timing_gen_on; u8 mhl_hpd_on; u8 hdcp_status; @@ -157,6 +161,7 @@ struct hdmi_tx_ctrl { struct hdmi_util_ds_data ds_data; struct completion hpd_int_done; struct work_struct hpd_int_work; + struct work_struct fps_work; struct delayed_work hdcp_cb_work; struct work_struct cable_notify_work; @@ -182,7 +187,7 @@ struct hdmi_tx_ctrl { void *downstream_data; void *audio_data; - void *feature_data[HDMI_TX_FEAT_MAX]; + void *feature_data[hweight8(HDMI_TX_FEAT_MAX)]; struct hdmi_hdcp_ops *hdcp_ops; void *hdcp_data; bool hdcp22_present; @@ -198,6 +203,9 @@ struct hdmi_tx_ctrl { char disp_switch_name[MAX_SWITCH_NAME_SIZE]; bool power_data_enable[HDMI_TX_MAX_PM]; + + hdmi_tx_evt_handler evt_handler[MDSS_EVENT_MAX]; + void *evt_arg; }; #endif /* __MDSS_HDMI_TX_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index 4640c3f505b6..555ba1ba5b1c 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -595,29 +595,13 @@ int hdmi_get_video_id_code(struct msm_hdmi_mode_timing_info *timing_in, break; } - if (vic < 0) { - for (i = 0; i < HDMI_VFRMT_MAX; i++) { - ret = hdmi_get_supported_mode(&supported_timing, - ds_data, i); - if (ret || !supported_timing.supported) - continue; - if (timing_in->active_h != supported_timing.active_h) - continue; - if (timing_in->active_v != supported_timing.active_v) - continue; - vic = (int)supported_timing.video_format; - break; - } - } - - if (vic < 0) { + if (vic < 0) pr_err("timing is not supported h=%d v=%d\n", timing_in->active_h, timing_in->active_v); - } - + else + pr_debug("vic = %d timing = %s\n", vic, + msm_hdmi_mode_2string((u32)vic)); exit: - pr_debug("vic = %d timing = %s\n", vic, - msm_hdmi_mode_2string((u32)vic)); return vic; } /* hdmi_get_video_id_code */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index cb459ab17bd7..cbe22b751e77 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -368,12 +368,14 @@ #define HDMI_DEFAULT_TIMEOUT_HSYNC 28571 enum hdmi_tx_feature_type { - HDMI_TX_FEAT_EDID, - HDMI_TX_FEAT_HDCP, - HDMI_TX_FEAT_HDCP2P2, - HDMI_TX_FEAT_CEC_HW, - HDMI_TX_FEAT_CEC_ABST, - HDMI_TX_FEAT_MAX, + HDMI_TX_FEAT_EDID = BIT(0), + HDMI_TX_FEAT_HDCP = BIT(1), + HDMI_TX_FEAT_HDCP2P2 = BIT(2), + HDMI_TX_FEAT_CEC_HW = BIT(3), + HDMI_TX_FEAT_CEC_ABST = BIT(4), + HDMI_TX_FEAT_MAX = HDMI_TX_FEAT_EDID | HDMI_TX_FEAT_HDCP | + HDMI_TX_FEAT_HDCP2P2 | HDMI_TX_FEAT_CEC_HW | + HDMI_TX_FEAT_CEC_ABST }; enum hdmi_tx_scdc_access_type { diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 8e51aaf31b93..e2743353acd1 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -114,7 +114,7 @@ struct mdss_hw mdss_misc_hw = { .irq_handler = NULL, }; -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef CONFIG_QCOM_BUS_SCALING #define MDP_REG_BUS_VECTOR_ENTRY(ab_val, ib_val) \ { \ .src = MSM_BUS_MASTER_AMPSS_M0, \ @@ -387,7 +387,7 @@ static irqreturn_t mdss_irq_handler(int irq, void *ptr) return IRQ_HANDLED; } -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef CONFIG_QCOM_BUS_SCALING static int mdss_mdp_bus_scale_register(struct mdss_data_type *mdata) { struct msm_bus_scale_pdata *reg_bus_pdata; @@ -2275,6 +2275,9 @@ ssize_t mdss_mdp_show_capabilities(struct device *dev, SPRINT("max_downscale_ratio=%d\n", MAX_DOWNSCALE_RATIO); SPRINT("max_upscale_ratio=%d\n", MAX_UPSCALE_RATIO); + if (mdata->nwb) + SPRINT("wb_intf_index=%d\n", mdata->nwb - 1); + if (test_bit(MDSS_QOS_SIMPLIFIED_PREFILL, mdata->mdss_qos_map)) { SPRINT("fmt_mt_nv12_factor=%d\n", mdata->prefill_data.prefill_factors.fmt_mt_nv12_factor); @@ -4122,7 +4125,7 @@ static int mdss_mdp_parse_dt_ppb_off(struct platform_device *pdev) return 0; } -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef CONFIG_QCOM_BUS_SCALING static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev) { int rc, paths; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 180730d48c57..d409618ae6c0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -5656,7 +5656,7 @@ static int mdss_mdp_scaler_lut_init(struct mdss_data_type *mdata, struct mdp_scale_luts_info *lut_tbl) { struct mdss_mdp_qseed3_lut_tbl *qseed3_lut_tbl; - int ret; + int ret = 0; if (!mdata->scaler_off) return -EFAULT; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index a87e5d11b4a6..9c8b6684e1b3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -1626,6 +1626,11 @@ int mdss_mdp_qseed3_setup(struct mdss_mdp_pipe *pipe, return -EINVAL; } + if (!scaler) { + pr_debug("scaler pointer is NULL\n"); + return 0; + } + pr_debug("scaler->enable=%d", scaler->enable); op_mode = readl_relaxed(MDSS_MDP_REG_SCALER_OP_MODE + offset); @@ -1742,17 +1747,21 @@ int mdss_mdp_qseed3_setup(struct mdss_mdp_pipe *pipe, return rc; } -static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe) +static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe, + enum pp_config_block pp_blk) { struct mdss_data_type *mdata; int rc = 0; mdata = mdss_mdp_get_mdata(); if (test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map)) - rc = mdss_mdp_qseed3_setup(pipe, SSPP_VIG, 0); + rc = mdss_mdp_qseed3_setup(pipe, pp_blk, 0); else rc = mdss_mdp_qseed2_setup(pipe); + if (rc) + pr_err("scale setup on pipe %d type %d failed ret %d\n", + pipe->num, pipe->type, rc); return rc; } @@ -1762,18 +1771,17 @@ int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op) if (!pipe) return -ENODEV; - ret = mdss_mdp_scale_setup(pipe); - if (ret) { - pr_err("scale setup on pipe %d type %d failed ret %d\n", - pipe->num, pipe->type, ret); - return -EINVAL; - } - switch (pipe->type) { case MDSS_MDP_PIPE_TYPE_VIG: + ret = mdss_mdp_scale_setup(pipe, SSPP_VIG); + if (ret) + return -EINVAL; ret = pp_vig_pipe_setup(pipe, op); break; case MDSS_MDP_PIPE_TYPE_RGB: + ret = mdss_mdp_scale_setup(pipe, SSPP_RGB); + if (ret) + return -EINVAL; ret = pp_rgb_pipe_setup(pipe, op); break; case MDSS_MDP_PIPE_TYPE_DMA: diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 7528f642149b..d3f836032bb6 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -262,6 +262,7 @@ enum mdss_intf_events { MDSS_EVENT_DSI_RECONFIG_CMD, MDSS_EVENT_DSI_RESET_WRITE_PTR, MDSS_EVENT_PANEL_TIMING_SWITCH, + MDSS_EVENT_MAX, }; struct lcd_panel_info { diff --git a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h index 2c92246827b6..d637d123e714 100644 --- a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h @@ -125,6 +125,7 @@ #define GCC_AGGRE1_USB3_AXI_CBCR 0x82024 #define GCC_BIMC_MSS_Q6_AXI_CBCR 0x4401C #define GCC_BLSP1_AHB_CBCR 0x17004 +#define GCC_BLSP1_BCR 0x17000 #define GCC_BLSP1_QUP1_SPI_APPS_CBCR 0x19004 #define GCC_BLSP1_QUP1_I2C_APPS_CBCR 0x19008 #define GCC_BLSP1_QUP2_SPI_APPS_CBCR 0x1B004 @@ -141,6 +142,7 @@ #define GCC_BLSP1_UART2_APPS_CBCR 0x1C004 #define GCC_BLSP1_UART3_APPS_CBCR 0x1E004 #define GCC_BLSP2_AHB_CBCR 0x25004 +#define GCC_BLSP2_BCR 0x25000 #define GCC_BLSP2_QUP1_SPI_APPS_CBCR 0x26004 #define GCC_BLSP2_QUP1_I2C_APPS_CBCR 0x26008 #define GCC_BLSP2_QUP2_I2C_APPS_CBCR 0x28008 @@ -195,6 +197,7 @@ #define GCC_TSIF_AHB_CBCR 0x36004 #define GCC_TSIF_REF_CBCR 0x36008 #define GCC_UFS_AXI_CBCR 0x75008 +#define GCC_UFS_BCR 0x75000 #define GCC_UFS_AHB_CBCR 0x7500C #define GCC_UFS_TX_SYMBOL_0_CBCR 0x75010 #define GCC_UFS_RX_SYMBOL_0_CBCR 0x75014 diff --git a/include/linux/sched.h b/include/linux/sched.h index 5ad9cf84a581..bc7ad2e61018 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -391,6 +391,7 @@ extern void scheduler_tick(void); extern void sched_show_task(struct task_struct *p); #ifdef CONFIG_LOCKUP_DETECTOR +extern void touch_softlockup_watchdog_sched(void); extern void touch_softlockup_watchdog(void); extern void touch_softlockup_watchdog_sync(void); extern void touch_all_softlockup_watchdogs(void); @@ -401,6 +402,9 @@ extern unsigned int softlockup_panic; extern unsigned int hardlockup_panic; void lockup_detector_init(void); #else +static inline void touch_softlockup_watchdog_sched(void) +{ +} static inline void touch_softlockup_watchdog(void) { } diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 0197358f1e81..0e32bc71245e 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -618,4 +618,10 @@ static inline int workqueue_sysfs_register(struct workqueue_struct *wq) { return 0; } #endif /* CONFIG_SYSFS */ +#ifdef CONFIG_WQ_WATCHDOG +void wq_watchdog_touch(int cpu); +#else /* CONFIG_WQ_WATCHDOG */ +static inline void wq_watchdog_touch(int cpu) { } +#endif /* CONFIG_WQ_WATCHDOG */ + #endif diff --git a/include/uapi/media/msm_jpeg_dma.h b/include/uapi/media/msm_jpeg_dma.h index df3c7ee5b7cf..6b664566cb4c 100644 --- a/include/uapi/media/msm_jpeg_dma.h +++ b/include/uapi/media/msm_jpeg_dma.h @@ -17,6 +17,7 @@ /* msm jpeg dma control ID's */ #define V4L2_CID_JPEG_DMA_SPEED (V4L2_CID_PRIVATE_BASE) +#define V4L2_CID_JPEG_DMA_MAX_DOWN_SCALE (V4L2_CID_PRIVATE_BASE + 1) /* msm_jpeg_dma_buf */ struct msm_jpeg_dma_buff { diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c index caf4041f5b0a..bc54e84675da 100644 --- a/kernel/sched/clock.c +++ b/kernel/sched/clock.c @@ -354,7 +354,7 @@ void sched_clock_idle_wakeup_event(u64 delta_ns) return; sched_clock_tick(); - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); } EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 89dcc6cafa07..7f0f1d8d46b0 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -163,7 +163,7 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs) * when we go busy again does not account too much ticks. */ if (ts->tick_stopped) { - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); if (is_idle_task(current)) ts->idle_jiffies++; } @@ -450,7 +450,7 @@ static void tick_nohz_update_jiffies(ktime_t now) tick_do_update_jiffies64(now); local_irq_restore(flags); - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); } /* @@ -721,7 +721,7 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) update_cpu_load_nohz(); calc_load_exit_idle(); - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); /* * Cancel the scheduled timer and restore the tick */ diff --git a/kernel/watchdog.c b/kernel/watchdog.c index d12d5b86a555..b40f7f35413d 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -20,6 +20,7 @@ #include <linux/smpboot.h> #include <linux/sched/rt.h> #include <linux/tick.h> +#include <linux/workqueue.h> #include <asm/irq_regs.h> #include <linux/kvm_para.h> @@ -232,7 +233,15 @@ static void __touch_watchdog(void) __this_cpu_write(watchdog_touch_ts, get_timestamp()); } -void touch_softlockup_watchdog(void) +/** + * touch_softlockup_watchdog_sched - touch watchdog on scheduler stalls + * + * Call when the scheduler may have stalled for legitimate reasons + * preventing the watchdog task from executing - e.g. the scheduler + * entering idle state. This should only be used for scheduler events. + * Use touch_softlockup_watchdog() for everything else. + */ +void touch_softlockup_watchdog_sched(void) { /* * Preemption can be enabled. It doesn't matter which CPU's timestamp @@ -240,6 +249,12 @@ void touch_softlockup_watchdog(void) */ raw_cpu_write(watchdog_touch_ts, 0); } + +void touch_softlockup_watchdog(void) +{ + touch_softlockup_watchdog_sched(); + wq_watchdog_touch(raw_smp_processor_id()); +} EXPORT_SYMBOL(touch_softlockup_watchdog); void touch_all_softlockup_watchdogs(void) @@ -253,6 +268,7 @@ void touch_all_softlockup_watchdogs(void) */ for_each_watchdog_cpu(cpu) per_cpu(watchdog_touch_ts, cpu) = 0; + wq_watchdog_touch(-1); } #ifdef CONFIG_HARDLOCKUP_DETECTOR diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 15dacf9590cb..58fe79122a61 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -149,6 +149,8 @@ struct worker_pool { int id; /* I: pool ID */ unsigned int flags; /* X: flags */ + unsigned long watchdog_ts; /* L: watchdog timestamp */ + struct list_head worklist; /* L: list of pending works */ int nr_workers; /* L: total number of workers */ @@ -1084,6 +1086,8 @@ static void pwq_activate_delayed_work(struct work_struct *work) struct pool_workqueue *pwq = get_work_pwq(work); trace_workqueue_activate_work(work); + if (list_empty(&pwq->pool->worklist)) + pwq->pool->watchdog_ts = jiffies; move_linked_works(work, &pwq->pool->worklist, NULL); __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work)); pwq->nr_active++; @@ -1386,6 +1390,8 @@ retry: trace_workqueue_activate_work(work); pwq->nr_active++; worklist = &pwq->pool->worklist; + if (list_empty(worklist)) + pwq->pool->watchdog_ts = jiffies; } else { work_flags |= WORK_STRUCT_DELAYED; worklist = &pwq->delayed_works; @@ -2159,6 +2165,8 @@ recheck: list_first_entry(&pool->worklist, struct work_struct, entry); + pool->watchdog_ts = jiffies; + if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) { /* optimization path, not strictly necessary */ process_one_work(worker, work); @@ -2242,6 +2250,7 @@ repeat: struct pool_workqueue, mayday_node); struct worker_pool *pool = pwq->pool; struct work_struct *work, *n; + bool first = true; __set_current_state(TASK_RUNNING); list_del_init(&pwq->mayday_node); @@ -2258,9 +2267,14 @@ repeat: * process'em. */ WARN_ON_ONCE(!list_empty(scheduled)); - list_for_each_entry_safe(work, n, &pool->worklist, entry) - if (get_work_pwq(work) == pwq) + list_for_each_entry_safe(work, n, &pool->worklist, entry) { + if (get_work_pwq(work) == pwq) { + if (first) + pool->watchdog_ts = jiffies; move_linked_works(work, scheduled, &n); + } + first = false; + } if (!list_empty(scheduled)) { process_scheduled_works(rescuer); @@ -3071,6 +3085,7 @@ static int init_worker_pool(struct worker_pool *pool) pool->cpu = -1; pool->node = NUMA_NO_NODE; pool->flags |= POOL_DISASSOCIATED; + pool->watchdog_ts = jiffies; INIT_LIST_HEAD(&pool->worklist); INIT_LIST_HEAD(&pool->idle_list); hash_init(pool->busy_hash); @@ -4310,7 +4325,9 @@ void show_workqueue_state(void) pr_info("pool %d:", pool->id); pr_cont_pool_info(pool); - pr_cont(" workers=%d", pool->nr_workers); + pr_cont(" hung=%us workers=%d", + jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000, + pool->nr_workers); if (pool->manager) pr_cont(" manager: %d", task_pid_nr(pool->manager->task)); @@ -5169,6 +5186,154 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq) static void workqueue_sysfs_unregister(struct workqueue_struct *wq) { } #endif /* CONFIG_SYSFS */ +/* + * Workqueue watchdog. + * + * Stall may be caused by various bugs - missing WQ_MEM_RECLAIM, illegal + * flush dependency, a concurrency managed work item which stays RUNNING + * indefinitely. Workqueue stalls can be very difficult to debug as the + * usual warning mechanisms don't trigger and internal workqueue state is + * largely opaque. + * + * Workqueue watchdog monitors all worker pools periodically and dumps + * state if some pools failed to make forward progress for a while where + * forward progress is defined as the first item on ->worklist changing. + * + * This mechanism is controlled through the kernel parameter + * "workqueue.watchdog_thresh" which can be updated at runtime through the + * corresponding sysfs parameter file. + */ +#ifdef CONFIG_WQ_WATCHDOG + +static void wq_watchdog_timer_fn(unsigned long data); + +static unsigned long wq_watchdog_thresh = 30; +static struct timer_list wq_watchdog_timer = + TIMER_DEFERRED_INITIALIZER(wq_watchdog_timer_fn, 0, 0); + +static unsigned long wq_watchdog_touched = INITIAL_JIFFIES; +static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES; + +static void wq_watchdog_reset_touched(void) +{ + int cpu; + + wq_watchdog_touched = jiffies; + for_each_possible_cpu(cpu) + per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies; +} + +static void wq_watchdog_timer_fn(unsigned long data) +{ + unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ; + bool lockup_detected = false; + struct worker_pool *pool; + int pi; + + if (!thresh) + return; + + rcu_read_lock(); + + for_each_pool(pool, pi) { + unsigned long pool_ts, touched, ts; + + if (list_empty(&pool->worklist)) + continue; + + /* get the latest of pool and touched timestamps */ + pool_ts = READ_ONCE(pool->watchdog_ts); + touched = READ_ONCE(wq_watchdog_touched); + + if (time_after(pool_ts, touched)) + ts = pool_ts; + else + ts = touched; + + if (pool->cpu >= 0) { + unsigned long cpu_touched = + READ_ONCE(per_cpu(wq_watchdog_touched_cpu, + pool->cpu)); + if (time_after(cpu_touched, ts)) + ts = cpu_touched; + } + + /* did we stall? */ + if (time_after(jiffies, ts + thresh)) { + lockup_detected = true; + pr_emerg("BUG: workqueue lockup - pool"); + pr_cont_pool_info(pool); + pr_cont(" stuck for %us!\n", + jiffies_to_msecs(jiffies - pool_ts) / 1000); + } + } + + rcu_read_unlock(); + + if (lockup_detected) + show_workqueue_state(); + + wq_watchdog_reset_touched(); + mod_timer(&wq_watchdog_timer, jiffies + thresh); +} + +void wq_watchdog_touch(int cpu) +{ + if (cpu >= 0) + per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies; + else + wq_watchdog_touched = jiffies; +} + +static void wq_watchdog_set_thresh(unsigned long thresh) +{ + wq_watchdog_thresh = 0; + del_timer_sync(&wq_watchdog_timer); + + if (thresh) { + wq_watchdog_thresh = thresh; + wq_watchdog_reset_touched(); + mod_timer(&wq_watchdog_timer, jiffies + thresh * HZ); + } +} + +static int wq_watchdog_param_set_thresh(const char *val, + const struct kernel_param *kp) +{ + unsigned long thresh; + int ret; + + ret = kstrtoul(val, 0, &thresh); + if (ret) + return ret; + + if (system_wq) + wq_watchdog_set_thresh(thresh); + else + wq_watchdog_thresh = thresh; + + return 0; +} + +static const struct kernel_param_ops wq_watchdog_thresh_ops = { + .set = wq_watchdog_param_set_thresh, + .get = param_get_ulong, +}; + +module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh, + 0644); + +static void wq_watchdog_init(void) +{ + wq_watchdog_set_thresh(wq_watchdog_thresh); +} + +#else /* CONFIG_WQ_WATCHDOG */ + +static inline void wq_watchdog_init(void) { } + +#endif /* CONFIG_WQ_WATCHDOG */ + static void __init wq_numa_init(void) { cpumask_var_t *tbl; @@ -5292,6 +5457,9 @@ static int __init init_workqueues(void) !system_unbound_wq || !system_freezable_wq || !system_power_efficient_wq || !system_freezable_power_efficient_wq); + + wq_watchdog_init(); + return 0; } early_initcall(init_workqueues); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 9e27a3c3aeb4..36ea0d54e05b 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -255,6 +255,13 @@ config PAGE_OWNER If unsure, say N. +config PAGE_OWNER_ENABLE_DEFAULT + bool "Enable Track page owner by default" + depends on PAGE_OWNER + ---help--- + Enable track page owner by default? This value + can be overridden by page_owner_disabled=off|on. + config DEBUG_FS bool "Debug Filesystem" help @@ -824,6 +831,17 @@ config BOOTPARAM_HUNG_TASK_PANIC_VALUE default 0 if !BOOTPARAM_HUNG_TASK_PANIC default 1 if BOOTPARAM_HUNG_TASK_PANIC +config WQ_WATCHDOG + bool "Detect Workqueue Stalls" + depends on DEBUG_KERNEL + help + Say Y here to enable stall detection on workqueues. If a + worker pool doesn't make forward progress on a pending work + item for over a given amount of time, 30s by default, a + warning message is printed along with dump of workqueue + state. This can be configured through kernel parameter + "workqueue.watchdog_thresh" and its sysfs counterpart. + endmenu # "Debug lockups and hangs" config PANIC_ON_OOPS @@ -1934,6 +1952,19 @@ config MEMTEST memtest=17, mean do 17 test patterns. If you are unsure how to answer this question, answer N. +config MEMTEST_ENABLE_DEFAULT + int "Enable Memtest pattern test by default? (0-17)" + range 0 17 + default "0" + depends on MEMTEST + help + This option helps to select Memtest to be enabled through + kernel defconfig options. Alternatively it can be enabled + using memtest=<patterns> kernel command line. + + Default value is kept as "0" so that it is kept as disabled. + To enable enter any value between 1-17 range. + config TEST_STATIC_KEYS tristate "Test static keys" default n diff --git a/lib/Makefile b/lib/Makefile index 79599c7b9828..03a447a234cc 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -22,8 +22,7 @@ lib-$(CONFIG_SMP) += cpumask.o lib-y += kobject.o klist.o obj-y += lockref.o -KASAN_SANITIZE_find_next_bit.o := n -KASAN_SANITIZE_find_last_bit.o := n +KASAN_SANITIZE_find_bit.o := n obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \ diff --git a/mm/memtest.c b/mm/memtest.c index 8eaa4c3a5f65..15a423eb0c29 100644 --- a/mm/memtest.c +++ b/mm/memtest.c @@ -80,8 +80,8 @@ static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end) } /* default is disabled */ -static unsigned int memtest_pattern __initdata; - +static unsigned int memtest_pattern __initdata = + CONFIG_MEMTEST_ENABLE_DEFAULT; static int __init parse_memtest(char *arg) { int ret = 0; diff --git a/mm/page_owner.c b/mm/page_owner.c index 983c3a10fa07..45cccaa1ce32 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -7,7 +7,8 @@ #include <linux/page_owner.h> #include "internal.h" -static bool page_owner_disabled = true; +static bool page_owner_disabled = + !IS_ENABLED(CONFIG_PAGE_OWNER_ENABLE_DEFAULT); bool page_owner_inited __read_mostly; static void init_early_allocated_pages(void); @@ -20,6 +21,9 @@ static int early_page_owner_param(char *buf) if (strcmp(buf, "on") == 0) page_owner_disabled = false; + if (strcmp(buf, "off") == 0) + page_owner_disabled = true; + return 0; } early_param("page_owner", early_page_owner_param); diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index 4f1ce53f7efa..ee4a8733b3e1 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -198,6 +198,8 @@ static int process_resume_tx_msg(union rr_control_msg *msg, static void ipc_router_reset_conn(struct msm_ipc_router_remote_port *rport_ptr); static int ipc_router_get_xprt_info_ref( struct msm_ipc_router_xprt_info *xprt_info); +static void ipc_router_put_xprt_info_ref( + struct msm_ipc_router_xprt_info *xprt_info); static void ipc_router_release_xprt_info_ref(struct kref *ref); struct pil_vote_info { @@ -2081,7 +2083,7 @@ static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info, fm_error3: mutex_unlock(&fwd_xprt_info->tx_lock_lhb2); fm_error2: - kref_put(&fwd_xprt_info->ref, ipc_router_release_xprt_info_ref); + ipc_router_put_xprt_info_ref(fwd_xprt_info); fm_error_xprt: up_read(&rt_entry->lock_lha4); fm_error1: @@ -3084,7 +3086,7 @@ out_write_pkt: ipc_router_log_msg(xprt_info->log_ctx, IPC_ROUTER_LOG_EVENT_TX_ERR, pkt, hdr, src, rport_ptr); - kref_put(&xprt_info->ref, ipc_router_release_xprt_info_ref); + ipc_router_put_xprt_info_ref(xprt_info); return ret; } update_comm_mode_info(&src->mode_info, xprt_info); @@ -3102,7 +3104,7 @@ out_write_pkt: (hdr->size & 0xffff)); } - kref_put(&xprt_info->ref, ipc_router_release_xprt_info_ref); + ipc_router_put_xprt_info_ref(xprt_info); return hdr->size; } @@ -3254,8 +3256,8 @@ static int msm_ipc_router_send_resume_tx(void *data) } ret = ipc_router_send_ctl_msg(rt_entry->xprt_info, &msg, hdr->src_node_id); + ipc_router_put_xprt_info_ref(rt_entry->xprt_info); kref_put(&rt_entry->ref, ipc_router_release_rtentry); - kref_put(&rt_entry->xprt_info->ref, ipc_router_release_xprt_info_ref); if (ret < 0) IPC_RTR_ERR( "%s: Send Resume_Tx Failed SRC_NODE: %d SRC_PORT: %d DEST_NODE: %d", @@ -3982,6 +3984,9 @@ static int ipc_router_get_xprt_info_ref( int ret = -ENODEV; struct msm_ipc_router_xprt_info *tmp_xprt_info; + if (!xprt_info) + return 0; + down_read(&xprt_info_list_lock_lha5); list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) { if (tmp_xprt_info == xprt_info) { @@ -3996,6 +4001,20 @@ static int ipc_router_get_xprt_info_ref( } /** + * ipc_router_put_xprt_info_ref() - Put a reference to the xprt_info structure + * @xprt_info: pointer to the xprt_info. + * + * This function is used to put the reference to the xprt_info structure + * corresponding to the requested @xprt_info pointer. + */ +static void ipc_router_put_xprt_info_ref( + struct msm_ipc_router_xprt_info *xprt_info) +{ + if (xprt_info) + kref_put(&xprt_info->ref, ipc_router_release_xprt_info_ref); +} + +/** * ipc_router_release_xprt_info_ref() - release the xprt_info last reference * @ref: Reference to the xprt_info structure. * @@ -4095,8 +4114,7 @@ static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt) wakeup_source_trash(&xprt_info->ws); - kref_put(&xprt_info->ref, - ipc_router_release_xprt_info_ref); + ipc_router_put_xprt_info_ref(xprt_info); wait_for_completion(&xprt_info->ref_complete); xprt->priv = 0; diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index 9d4961aa8330..2f09d8801a96 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -103,8 +103,16 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; + ret = qcom_ice_setup_ice_hw("ufs", true); + if (ret) { + pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); + return ret; + } + + ret = scm_call2(smc_id, &desc); + + qcom_ice_setup_ice_hw("ufs", false); - ret = scm_call2_atomic(smc_id, &desc); pr_debug(" %s , ret = %d\n", __func__, ret); if (ret) { pr_err("%s: Error: 0x%x\n", __func__, ret); @@ -112,7 +120,7 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; desc.args[0] = index; - scm_call2_atomic(smc_id, &desc); + scm_call2(smc_id, &desc); } return ret; @@ -136,10 +144,12 @@ int qti_pfk_ice_invalidate_key(uint32_t index) desc.args[0] = index; ret = qcom_ice_setup_ice_hw("ufs", true); - if (ret) + if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); + return ret; + } - ret = scm_call2_atomic(smc_id, &desc); + ret = scm_call2(smc_id, &desc); qcom_ice_setup_ice_hw("ufs", false); diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index dad53baec605..23261271bec8 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1322,6 +1322,12 @@ int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir, ac->port[dir].buf = buf; + /* check for integer overflow */ + if ((bufcnt > 0) && ((INT_MAX / bufcnt) < bufsz)) { + pr_err("%s: integer overflow\n", __func__); + mutex_unlock(&ac->cmd_lock); + goto fail; + } bytes_to_alloc = bufsz * bufcnt; /* The size to allocate should be multiple of 4K bytes */ |
