summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/imem.txt6
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,gpucc.txt23
-rw-r--r--Documentation/devicetree/bindings/gpu/adreno.txt4
-rw-r--r--Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt4
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi80
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-qrd.dtsi356
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi71
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi7
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi67
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi524
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-v2-camera.dtsi27
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-bus.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi96
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi37
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton.dtsi35
-rw-r--r--arch/arm/configs/msmfalcon_defconfig10
-rw-r--r--arch/arm64/configs/msm-perf_defconfig3
-rw-r--r--arch/arm64/configs/msm_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex_defconfig3
-rw-r--r--arch/arm64/mm/dma-mapping.c265
-rw-r--r--drivers/char/diag/diag_dci.c4
-rw-r--r--drivers/char/diag/diagfwd_glink.c23
-rw-r--r--drivers/char/diag/diagfwd_peripheral.c4
-rw-r--r--drivers/clk/msm/clock-osm.c39
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c4
-rw-r--r--drivers/clk/msm/mdss/mdss-hdmi-pll-cobalt.c4
-rw-r--r--drivers/clk/qcom/Kconfig11
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-rcg2.c1
-rw-r--r--drivers/clk/qcom/gpucc-msmfalcon.c482
-rw-r--r--drivers/cpuidle/lpm-levels-of.c210
-rw-r--r--drivers/cpuidle/lpm-levels.c355
-rw-r--r--drivers/cpuidle/lpm-levels.h9
-rw-r--r--drivers/gpu/msm/a5xx_reg.h1
-rw-r--r--drivers/gpu/msm/adreno-gpulist.h22
-rw-r--r--drivers/gpu/msm/adreno.c15
-rw-r--r--drivers/gpu/msm/adreno.h6
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c11
-rw-r--r--drivers/gpu/msm/adreno_drawctxt.c19
-rw-r--r--drivers/gpu/msm/kgsl.h15
-rw-r--r--drivers/gpu/msm/kgsl_device.h4
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c349
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.h2
-rw-r--r--drivers/gpu/msm/kgsl_pwrscale.c8
-rw-r--r--drivers/gpu/msm/kgsl_snapshot.c38
-rw-r--r--drivers/iommu/io-pgtable-arm.c11
-rw-r--r--drivers/iommu/msm_dma_iommu_mapping.c1
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c13
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c12
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c1
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c14
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_util.c7
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c72
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c58
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c4
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c39
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_dcvs.c8
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c8
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_internal.h2
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c6
-rw-r--r--drivers/platform/msm/qpnp-revid.c9
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c15
-rw-r--r--drivers/power/qcom-charger/smb-lib.c114
-rw-r--r--drivers/power/qcom-charger/smb-lib.h1
-rw-r--r--drivers/power/qcom-charger/smb-reg.h3
-rw-r--r--drivers/power/qcom/msm-core.c10
-rw-r--r--drivers/power/reset/msm-poweroff.c197
-rw-r--r--drivers/regulator/cpr3-regulator.c156
-rw-r--r--drivers/regulator/cpr3-regulator.h5
-rw-r--r--drivers/regulator/cpr3-util.c101
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c194
-rw-r--r--drivers/scsi/ufs/ufs_test.c20
-rw-r--r--drivers/soc/qcom/common_log.c2
-rw-r--r--drivers/soc/qcom/icnss.c177
-rw-r--r--drivers/soc/qcom/rpm-smd-debug.c2
-rw-r--r--drivers/soc/qcom/system_stats.c2
-rwxr-xr-xdrivers/staging/android/ion/ion.c4
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c6
-rw-r--r--drivers/staging/android/ion/ion_cma_secure_heap.c12
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c13
-rw-r--r--drivers/staging/android/ion/msm/msm_ion.c6
-rw-r--r--drivers/thermal/lmh_lite.c15
-rw-r--r--drivers/usb/core/hcd.c3
-rw-r--r--drivers/usb/core/hub.c6
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c9
-rw-r--r--drivers/usb/gadget/function/f_gsi.h15
-rw-r--r--drivers/usb/gadget/function/f_mtp.c3
-rw-r--r--drivers/usb/host/xhci.c21
-rw-r--r--drivers/usb/pd/policy_engine.c12
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c23
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_status.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c87
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c107
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c14
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h9
-rw-r--r--fs/fuse/passthrough.c4
-rw-r--r--include/dt-bindings/clock/qcom,gcc-msmfalcon.h48
-rw-r--r--include/dt-bindings/clock/qcom,gpu-msmfalcon.h47
-rw-r--r--include/linux/dma-mapping-fast.h2
-rw-r--r--include/linux/iommu.h4
-rw-r--r--include/linux/msm_dma_iommu_mapping.h2
-rw-r--r--include/linux/qpnp/qpnp-revid.h1
-rw-r--r--include/linux/sched/sysctl.h16
-rw-r--r--include/linux/usb/hcd.h2
-rw-r--r--include/soc/qcom/icnss.h3
-rw-r--r--include/sound/apr_audio-v2.h135
-rw-r--r--include/sound/q6afe-v2.h2
-rw-r--r--include/sound/q6asm-v2.h62
-rw-r--r--include/sound/wcd-dsp-mgr.h14
-rw-r--r--include/trace/events/trace_msm_low_power.h50
-rw-r--r--include/uapi/linux/msm_vidc_dec.h6
-rw-r--r--include/uapi/sound/wcd-dsp-glink.h2
-rw-r--r--init/Kconfig26
-rw-r--r--kernel/sched/Makefile1
-rw-r--r--kernel/sched/fair.c4
-rw-r--r--kernel/sched/tune.c17
-rw-r--r--kernel/sysctl.c11
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--sound/soc/codecs/wcd-dsp-mgr.c388
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c2
-rw-r--r--sound/soc/codecs/wcd-spi.c31
-rw-r--r--sound/soc/codecs/wcd9330.c12
-rw-r--r--sound/soc/codecs/wcd9335.c6
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c203
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h12
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-routing.h4
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c92
-rw-r--r--sound/soc/codecs/wcd9xxx-mbhc.c4
-rw-r--r--sound/soc/codecs/wcd_cpe_core.c2
-rw-r--r--sound/soc/codecs/wsa881x.c2
-rw-r--r--sound/soc/msm/msm-dai-fe.c68
-rw-r--r--sound/soc/msm/msmcobalt.c827
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c14
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c95
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c41
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h4
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c29
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c471
153 files changed, 6545 insertions, 1202 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt
index d1f8ce1e5ac8..a9d2a2456cfd 100644
--- a/Documentation/devicetree/bindings/arm/msm/imem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/imem.txt
@@ -46,6 +46,12 @@ Required properties:
-compatible: "qcom,msm-imem-restart_reason
-reg: start address and size of restart_reason region in imem
+Download Mode Type:
+-------------------
+Required properties:
+-compatible: "qcom,msm-imem-dload-type"
+-reg: start address and size of dload type region in imem
+
Download Mode:
--------------
Required properties:
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
new file mode 100644
index 000000000000..9f8ea0d6ef8f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -0,0 +1,23 @@
+Qualcomm Technologies, Inc Graphics Clock & Reset Controller Binding
+--------------------------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+ "qcom,gpucc-msmfalcon"
+
+- reg : shall contain base register location and length
+- #clock-cells : shall contain 1
+- #reset-cells : shall contain 1
+
+Optional properties :
+- #power-domain-cells : shall contain 1
+
+Example:
+ clock-controller@4000000 {
+ compatible = "qcom,gpucc-msmfalcon";
+ reg = <<0x5065000 0x10000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index fffb8cc39d0f..ca58f0da07ef 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -139,6 +139,10 @@ Optional Properties:
baseAddr - base address of the gpu channels in the qdss stm memory region
size - size of the gpu stm region
+- qcom,tsens-name:
+ Specify the name of GPU temperature sensor. This name will be used
+ to get the temperature from the thermal driver API.
+
GPU Quirks:
- qcom,gpu-quirk-two-pass-use-wfi:
Signal the GPU to set Set TWOPASSUSEWFI bit in
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt
index 93312df2a43b..babc4523a29a 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt
@@ -6,6 +6,10 @@ Required properties:
- compatible : should be "qcom,qpnp-revid"
- reg : offset and length of the PMIC peripheral register map.
+Optional property:
+- qcom,fab-id-valid: Use this property when support to read Fab
+ identification from REV ID peripheral is available.
+
Example:
qcom,revid@100 {
compatible = "qcom,qpnp-revid";
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi
new file mode 100644
index 000000000000..6c17bca64a86
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi
@@ -0,0 +1,80 @@
+/* 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.
+ */
+
+&mdss_mdp {
+ dsi_dual_jdi_a407_cmd: qcom,mdss_dsi_jdi_a407_wqhd_cmd {
+ qcom,mdss-dsi-panel-name = "JDI a407 wqhd cmd mode dsi panel";
+ qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <2560>;
+ qcom,mdss-dsi-h-front-porch = <16>;
+ qcom,mdss-dsi-h-back-porch = <40>;
+ qcom,mdss-dsi-h-pulse-width = <4>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <20>;
+ qcom,mdss-dsi-v-front-porch = <7>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [
+ 15 01 00 00 00 00 02 35 00
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
+ qcom,mdss-dsi-off-command = [
+ 05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
+ qcom,mdss-dsi-lane-map = "lane_map_0123";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+
+ qcom,mdss-dsi-te-using-te-pin;
+ qcom,mdss-dsi-te-pin-select = <1>;
+ qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+ qcom,mdss-dsi-te-dcs-command = <1>;
+
+ qcom,mdss-dsi-lp11-init;
+ qcom,adjust-timer-wakeup-ms = <1>;
+ qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>;
+
+ qcom,config-select = <&dsi_dual_jdi_a407_cmd_config0>;
+
+ dsi_dual_jdi_a407_cmd_config0: config0 {
+ qcom,split-mode = "dualctl-split";
+ };
+
+ dsi_dual_jdi_a407_cmd_config1: config1 {
+ qcom,split-mode = "pingpong-split";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
index 8a8782f5f8b3..4f76276b2790 100644
--- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
@@ -23,6 +23,7 @@
pmicobalt_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
+ qcom,fab-id-valid;
};
qcom,power-on@800 {
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index dc1bbcd13c36..912bdd88be68 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -1355,7 +1355,7 @@
gdsc-vdd-supply = <&gdsc_pcie_0>;
vreg-1.8-supply = <&pm8994_l12>;
vreg-0.9-supply = <&pm8994_l28>;
- vreg-cx-supply = <&pm8994_s1_corner_ao>;
+ vreg-cx-supply = <&pm8994_s1_corner>;
qcom,vreg-0.9-voltage-level = <925000 925000 24000>;
qcom,vreg-cx-voltage-level = <7 4 0>;
@@ -1510,7 +1510,7 @@
gdsc-vdd-supply = <&gdsc_pcie_1>;
vreg-1.8-supply = <&pm8994_l12>;
vreg-0.9-supply = <&pm8994_l28>;
- vreg-cx-supply = <&pm8994_s1_corner_ao>;
+ vreg-cx-supply = <&pm8994_s1_corner>;
qcom,vreg-0.9-voltage-level = <925000 925000 24000>;
qcom,vreg-cx-voltage-level = <7 5 0>;
@@ -1663,10 +1663,10 @@
gdsc-vdd-supply = <&gdsc_pcie_2>;
vreg-1.8-supply = <&pm8994_l12>;
vreg-0.9-supply = <&pm8994_l28>;
- vreg-cx-supply = <&pm8994_s1_corner_ao>;
+ vreg-cx-supply = <&pm8994_s1_corner>;
qcom,vreg-0.9-voltage-level = <925000 925000 24000>;
- qcom,vreg-cx-voltage-level = <7 4 0>;
+ qcom,vreg-cx-voltage-level = <7 5 0>;
qcom,l1-supported;
qcom,l1ss-supported;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
index 445f32df8aa4..a1d80075abe0 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
@@ -157,6 +157,7 @@
qcom,audio-routing =
"RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
"AMIC2", "MIC BIAS2",
"MIC BIAS2", "Headset Mic",
"AMIC3", "MIC BIAS2",
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 ed29dd9e1508..ed8eb8459e51 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi
@@ -87,7 +87,7 @@
cam_vdig-supply = <&pmcobalt_s3>;
qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
- qcom,cam-vreg-max-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1352000>;
qcom,cam-vreg-op-mode = <0 80000 105000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -132,7 +132,7 @@
cam_vana-supply = <&pmicobalt_bob>;
qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
qcom,cam-vreg-min-voltage = <0 0 3312000>;
- qcom,cam-vreg-max-voltage = <0 0 3312000>;
+ qcom,cam-vreg-max-voltage = <0 0 3600000>;
qcom,cam-vreg-op-mode = <0 0 80000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -215,7 +215,7 @@
cam_vdig-supply = <&pmcobalt_s3>;
qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
- qcom,cam-vreg-max-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1352000>;
qcom,cam-vreg-op-mode = <0 80000 105000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -259,7 +259,7 @@
cam_vana-supply = <&pmicobalt_bob>;
qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
qcom,cam-vreg-min-voltage = <0 0 3312000>;
- qcom,cam-vreg-max-voltage = <0 0 3312000>;
+ qcom,cam-vreg-max-voltage = <0 0 3600000>;
qcom,cam-vreg-op-mode = <0 0 80000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
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 485bc560eef5..2be67ab52ba7 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
@@ -87,7 +87,7 @@
cam_vdig-supply = <&pmcobalt_s3>;
qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
- qcom,cam-vreg-max-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1352000>;
qcom,cam-vreg-op-mode = <0 80000 105000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -132,7 +132,7 @@
cam_vana-supply = <&pmicobalt_bob>;
qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
qcom,cam-vreg-min-voltage = <0 0 3312000>;
- qcom,cam-vreg-max-voltage = <0 0 3312000>;
+ qcom,cam-vreg-max-voltage = <0 0 3600000>;
qcom,cam-vreg-op-mode = <0 0 80000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -215,7 +215,7 @@
cam_vdig-supply = <&pmcobalt_s3>;
qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
- qcom,cam-vreg-max-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1352000>;
qcom,cam-vreg-op-mode = <0 80000 105000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -259,7 +259,7 @@
cam_vana-supply = <&pmicobalt_bob>;
qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
qcom,cam-vreg-min-voltage = <0 0 3312000>;
- qcom,cam-vreg-max-voltage = <0 0 3312000>;
+ qcom,cam-vreg-max-voltage = <0 0 3600000>;
qcom,cam-vreg-op-mode = <0 0 80000>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-qrd.dtsi
new file mode 100644
index 000000000000..4b435aee73b0
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-qrd.dtsi
@@ -0,0 +1,356 @@
+
+/*
+ * 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.
+ */
+
+&soc {
+ led_flash0: qcom,camera-flash@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-source = <&pmicobalt_flash0 &pmicobalt_flash1>;
+ qcom,torch-source = <&pmicobalt_torch0 &pmicobalt_torch1>;
+ qcom,switch-source = <&pmicobalt_switch0>;
+ status = "ok";
+ };
+
+ led_flash1: qcom,camera-flash@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-source = <&pmicobalt_flash2>;
+ qcom,torch-source = <&pmicobalt_torch2>;
+ qcom,switch-source = <&pmicobalt_switch1>;
+ status = "ok";
+ };
+};
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <1>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ ois0: qcom,ois@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,ois";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ status = "disabled";
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ reg = <0>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pmcobalt_lvs1>;
+ cam_vana-supply = <&pmicobalt_bob>;
+ cam_vdig-supply = <&pmcobalt_s3>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-max-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active
+ &cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend
+ &cam_actuator_vaf_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 30 0>,
+ <&pmcobalt_gpios 20 0>,
+ <&tlmm 29 0>,
+ <&tlmm 27 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-vaf = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA",
+ "CAM_VAF";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ eeprom1: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,eeprom";
+ cam_vdig-supply = <&pmcobalt_lvs1>;
+ cam_vio-supply = <&pmcobalt_lvs1>;
+ cam_vana-supply = <&pmicobalt_bob>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-min-voltage = <0 0 3312000>;
+ qcom,cam-vreg-max-voltage = <0 0 3312000>;
+ qcom,cam-vreg-op-mode = <0 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vana = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ 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>;
+ };
+
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ reg = <0x2>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pmcobalt_lvs1>;
+ cam_vana-supply = <&pmcobalt_l22>;
+ cam_vdig-supply = <&pmcobalt_s3>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage =
+ <0 2864000 1352000>;
+ qcom,cam-vreg-max-voltage =
+ <0 2864000 1352000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_front_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_front_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 28 0>,
+ <&pmcobalt_gpios 9 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VDIG";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ 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>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,ois-src = <&ois0>;
+ qcom,eeprom-src = <&eeprom0>;
+ cam_vio-supply = <&pmcobalt_lvs1>;
+ cam_vana-supply = <&pmicobalt_bob>;
+ cam_vdig-supply = <&pmcobalt_s3>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-max-voltage = <0 3312000 1352000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 30 0>,
+ <&pmcobalt_gpios 20 0>,
+ <&tlmm 29 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom1>;
+ cam_vdig-supply = <&pmcobalt_lvs1>;
+ cam_vio-supply = <&pmcobalt_lvs1>;
+ cam_vana-supply = <&pmicobalt_bob>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-min-voltage = <0 0 3312000>;
+ qcom,cam-vreg-max-voltage = <0 0 3312000>;
+ qcom,cam-vreg-op-mode = <0 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vana = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ 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>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <270>;
+ qcom,eeprom-src = <&eeprom2>;
+ qcom,led-flash-src = <&led_flash1>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vio-supply = <&pmcobalt_lvs1>;
+ cam_vana-supply = <&pmcobalt_l22>;
+ cam_vdig-supply = <&pmcobalt_s3>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage =
+ <0 2864000 1352000>;
+ qcom,cam-vreg-max-voltage =
+ <0 2864000 1352000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_front_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_front_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 28 0>,
+ <&pmcobalt_gpios 9 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VDIG";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ 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>;
+ };
+};
+&pmcobalt_gpios {
+ gpio@c800 { /* GPIO 9 - CAMERA SENSOR 2 VDIG */
+ qcom,mode = <1>; /* Output */
+ qcom,pull = <5>; /* No Pull */
+ qcom,vin-sel = <0>; /* VIN1 GPIO_LV */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "ok";
+ };
+
+ gpio@d300 { /* GPIO 20 - CAMERA SENSOR 0 VDIG */
+ qcom,mode = <1>; /* Output */
+ qcom,pull = <5>; /* No Pull */
+ qcom,vin-sel = <1>; /* VIN1 GPIO_MV */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi
index 190feb5000fc..a37fa26b1055 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi
@@ -147,21 +147,20 @@
<&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_csiphy_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_cphy_csid0_clk>,
- <&clock_mmss clk_csiphy_clk_src>;
+ <&clock_mmss clk_mmss_camss_cphy_csid0_clk>;
clock-names = "mmssnoc_axi", "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", "cphy_csid_clk", "cphy_clk_src";
- qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0 0 0
- 256000000>;
+ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
+ "csi_clk", "csi_ahb_clk", "csi_rdi_clk",
+ "csi_pix_clk", "cphy_csid_clk";
+ qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000
+ 0 0 0 0 0>;
status = "ok";
};
@@ -186,21 +185,20 @@
<&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_csiphy_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_cphy_csid1_clk>,
- <&clock_mmss clk_csiphy_clk_src>;
+ <&clock_mmss clk_mmss_camss_cphy_csid1_clk>;
clock-names = "mmssnoc_axi", "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", "cphy_csid_clk", "cphy_clk_src";
- qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0 0 0
- 256000000>;
+ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
+ "csi_clk", "csi_ahb_clk", "csi_rdi_clk",
+ "csi_pix_clk", "cphy_csid_clk";
+ qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000
+ 0 0 0 0 0>;
status = "ok";
};
@@ -225,21 +223,20 @@
<&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_csiphy_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_cphy_csid2_clk>,
- <&clock_mmss clk_csiphy_clk_src>;
+ <&clock_mmss clk_mmss_camss_cphy_csid2_clk>;
clock-names = "mmssnoc_axi", "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", "cphy_csid_clk", "cphy_clk_src";
- qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0 0 0
- 256000000>;
+ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
+ "csi_clk", "csi_ahb_clk", "csi_rdi_clk",
+ "csi_pix_clk", "cphy_csid_clk";
+ qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000
+ 0 0 0 0 0>;
status = "ok";
};
@@ -264,20 +261,20 @@
<&clock_mmss clk_mmss_camss_top_ahb_clk>,
<&clock_mmss clk_mmss_camss_ispif_ahb_clk>,
<&clock_mmss clk_csi3_clk_src>,
+ <&clock_mmss clk_csiphy_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_mmss clk_mmss_camss_cphy_csid1_clk>,
- <&clock_mmss clk_csiphy_clk_src>;
+ <&clock_mmss clk_mmss_camss_cphy_csid3_clk>;
clock-names = "mmssnoc_axi", "mnoc_ahb",
"bmic_smmu_ahb", "bmic_smmu_axi",
"camss_ahb_clk", "camss_top_ahb_clk",
- "ispif_ahb_clk", "csi_src_clk", "csi_clk",
- "csi_ahb_clk", "csi_rdi_clk",
- "csi_pix_clk", "cphy_csid_clk", "cphy_clk_src";
- qcom,clock-rates = <0 0 0 0 0 0 0 256000000 0 0 0 0 0
- 256000000>;
+ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
+ "csi_clk", "csi_ahb_clk", "csi_rdi_clk",
+ "csi_pix_clk", "cphy_csid_clk";
+ qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000
+ 0 0 0 0 0>;
status = "ok";
};
@@ -355,14 +352,18 @@
"mmss_fd_ahb_clk",
"mmss_camss_cpp_axi_clk",
"mmss_camss_cpp_vbif_ahb_clk";
- qcom,clock-rates = <0 0 0 0 0 0 200000000 0 0 0 0>;
+ qcom,clock-rates =
+ <0 0 0 0 0 0 404000000 0 0 0 0>,
+ <0 0 0 0 0 0 100000000 0 0 0 0>,
+ <0 0 0 0 0 0 404000000 0 0 0 0>,
+ <0 0 0 0 0 0 404000000 0 0 0 0>;
qcom,msm-bus,name = "msm_camera_fd";
qcom,msm-bus,num-cases = <4>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps = <106 512 0 0>,
- <106 512 13000000 13000000>,
- <106 512 45000000 45000000>,
- <106 512 90000000 90000000>;
+ <106 512 1625 0>,
+ <106 512 2995 0>,
+ <106 512 7200 0>;
qcom,fd-vbif-reg-settings = <0x20 0x10000000 0x30000000>,
<0x24 0x10000000 0x30000000>,
<0x28 0x10000000 0x30000000>,
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi
index ad293d9827d1..085ca0187ee6 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi
@@ -376,6 +376,8 @@
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,5v-boost-gpio = <&tlmm 51 0>;
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,partial-update-enabled;
+ qcom,panel-roi-alignment = <4 2 4 2 20 20>;
};
&dsi_sharp_1080_cmd {
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi
index 1267e578f9b4..e140074465ef 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi
@@ -75,6 +75,8 @@
qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size
+ qcom,tsens-name = "tsens_tz_sensor12";
+
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-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi
index a4ba9a61cded..d973bc5ed84f 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi
@@ -25,6 +25,7 @@
#include "dsi-panel-sharp-1080p-cmd.dtsi"
#include "dsi-panel-jdi-1080p-video.dtsi"
#include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi"
+#include "dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi"
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -156,3 +157,9 @@
qcom,mdss-dsi-t-clk-post = <0x7>;
qcom,mdss-dsi-t-clk-pre = <0x26>;
};
+
+&dsi_dual_jdi_a407_cmd {
+ qcom,mdss-dsi-panel-timings = [00 16 05 05 09 0e 05 05 04 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x06>;
+ qcom,mdss-dsi-t-clk-pre = <0x22>;
+};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi
index 1ae0ab804eac..5f89985db0a3 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi
@@ -126,3 +126,70 @@
qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft";
};
};
+
+&pmx_mdss {
+ mdss_dsi_active: mdss_dsi_active {
+ mux {
+ pins = "gpio94";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio94";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable = <0>; /* no pull */
+ output-high;
+ };
+ };
+
+ mdss_dsi_suspend: mdss_dsi_suspend {
+ mux {
+ pins = "gpio94";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio94";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "split_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_dual_jdi_a407_cmd>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 94 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&mdss_dsi1 {
+ qcom,dsi-pref-prim-pan = <&dsi_dual_jdi_a407_cmd>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 94 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&labibb {
+ status = "ok";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&dsi_dual_jdi_a407_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
index e0ae9a8873a7..51e1154beaa9 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
@@ -10,7 +10,529 @@
* GNU General Public License for more details.
*/
-#include "msmcobalt-mtp.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "msmcobalt-pinctrl.dtsi"
+#include "msmcobalt-camera-sensor-qrd.dtsi"
+/ {
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pmcobalt_s3>;
+ qca,bt-vdd-xtal-supply = <&pmcobalt_s5>;
+ qca,bt-vdd-core-supply = <&pmcobalt_l7_pin_ctrl>;
+ qca,bt-vdd-pa-supply = <&pmcobalt_l17_pin_ctrl>;
+ qca,bt-vdd-ldo-supply = <&pmcobalt_l25_pin_ctrl>;
+ qca,bt-chip-pwd-supply = <&pmicobalt_bob_pin1>;
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+ qca,bt-chip-pwd-voltage-level = <3600000 3600000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <0>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <0>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <0>; /* LPM/PFM */
+ };
+};
+
+&blsp1_uart3_hs {
+ status = "ok";
+};
+
+&ufsphy1 {
+ vdda-phy-supply = <&pmcobalt_l1>;
+ vdda-pll-supply = <&pmcobalt_l2>;
+ vddp-ref-clk-supply = <&pmcobalt_l26>;
+ vdda-phy-max-microamp = <51400>;
+ vdda-pll-max-microamp = <14600>;
+ vddp-ref-clk-max-microamp = <100>;
+ vddp-ref-clk-always-on;
+ status = "ok";
+};
+
+&ufs1 {
+ vdd-hba-supply = <&gdsc_ufs>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pmcobalt_l20>;
+ vccq-supply = <&pmcobalt_l26>;
+ vccq2-supply = <&pmcobalt_s4>;
+ vcc-max-microamp = <750000>;
+ vccq-max-microamp = <560000>;
+ vccq2-max-microamp = <750000>;
+ status = "ok";
+};
+
+&ufs_ice {
+ status = "ok";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pmcobalt_l21>;
+ qcom,vdd-voltage-level = <2950000 2960000>;
+ qcom,vdd-current-level = <200 800000>;
+
+ vdd-io-supply = <&pmcobalt_l13>;
+ qcom,vdd-io-voltage-level = <1808000 2960000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ cd-gpios = <&tlmm 95 0x1>;
+
+ status = "ok";
+};
+
+&uartblsp2dm1 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+&pmcobalt_gpios {
+ /* GPIO 6 for Vol+ Key */
+ gpio@c500 {
+ status = "okay";
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <0>;
+ qcom,out-strength = <1>;
+ };
+
+ /* GPIO 7 for Snapshot Key */
+ gpio@c600 {
+ status = "okay";
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <0>;
+ qcom,out-strength = <1>;
+ };
+
+ /* GPIO 8 for Focus Key */
+ gpio@c700 {
+ status = "okay";
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <0>;
+ qcom,out-strength = <1>;
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,out-strength = <1>;
+ qcom,src-sel = <3>;
+ qcom,master-en = <1>;
+ status = "okay";
+ };
+
+ /* GPIO 21 (NFC_CLK_REQ) */
+ gpio@d400 {
+ qcom,mode = <0>;
+ qcom,vin-sel = <1>;
+ qcom,src-sel = <0>;
+ qcom,master-en = <1>;
+ status = "okay";
+ };
+
+ /* GPIO 18 SMB138X */
+ gpio@d100 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <0>;
+ qcom,master-en = <1>;
+ status = "okay";
+ };
+};
+
+&i2c_5 {
+ status = "okay";
+ synaptics@20 {
+ compatible = "synaptics,dsx";
+ reg = <0x20>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <125 0x2008>;
+ vdd-supply = <&pmcobalt_l6>;
+ avdd-supply = <&pmcobalt_l28>;
+ synaptics,vdd-voltage = <1808000 1808000>;
+ synaptics,avdd-voltage = <3008000 3008000>;
+ synaptics,vdd-current = <40000>;
+ synaptics,avdd-current = <20000>;
+ pinctrl-names = "pmx_ts_active", "pmx_ts_suspend";
+ pinctrl-0 = <&ts_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ synaptics,display-coords = <0 0 1439 2559>;
+ synaptics,panel-coords = <0 0 1439 2559>;
+ synaptics,reset-gpio = <&tlmm 89 0x00>;
+ synaptics,irq-gpio = <&tlmm 125 0x2008>;
+ synaptics,disable-gpios;
+ synaptics,fw-name = "PR1702898-s3528t_60QHD_00400001.img";
+ };
+};
+
+&i2c_6 { /* BLSP1 QUP6 (NFC) */
+ status = "okay";
+ nq@28 {
+ compatible = "qcom,nq-nci";
+ reg = <0x28>;
+ qcom,nq-irq = <&tlmm 92 0x00>;
+ qcom,nq-ven = <&tlmm 12 0x00>;
+ qcom,nq-firm = <&tlmm 93 0x00>;
+ qcom,nq-clkreq = <&pmcobalt_gpios 21 0x00>;
+ qcom,nq-esepwr = <&tlmm 116 0x00>;
+ interrupt-parent = <&tlmm>;
+ qcom,clk-src = "BBCLK3";
+ interrupts = <92 0>;
+ interrupt-names = "nfc_irq";
+ pinctrl-names = "nfc_active", "nfc_suspend";
+ pinctrl-0 = <&nfc_int_active &nfc_enable_active>;
+ pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
+ clocks = <&clock_gcc clk_ln_bb_clk3_pin>;
+ clock-names = "ref_clk";
+ };
+};
+
+&mdss_hdmi_tx {
+ pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active",
+ "hdmi_active", "hdmi_sleep";
+ pinctrl-0 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
+ &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>;
+ pinctrl-1 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
+ &mdss_hdmi_ddc_active &mdss_hdmi_cec_suspend>;
+ pinctrl-2 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
+ &mdss_hdmi_cec_active &mdss_hdmi_ddc_suspend>;
+ pinctrl-3 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
+ &mdss_hdmi_ddc_active &mdss_hdmi_cec_active>;
+ pinctrl-4 = <&mdss_hdmi_5v_suspend &mdss_hdmi_hpd_suspend
+ &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>;
+};
+
+&mdss_dp_ctrl {
+ pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+ pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>;
+ pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>;
+ qcom,aux-en-gpio = <&tlmm 77 0>;
+ qcom,aux-sel-gpio = <&tlmm 78 0>;
+ qcom,usbplug-cc-gpio = <&tlmm 38 0>;
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "split_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 94 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,panel-mode-gpio = <&tlmm 91 0>;
+};
+
+&mdss_dsi1 {
+ qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 94 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,panel-mode-gpio = <&tlmm 91 0>;
+};
+
+&labibb {
+ status = "ok";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&dsi_dual_nt35597_video {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_dual_nt35597_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_dual_nt35597_truly_video {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_dual_nt35597_truly_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_nt35597_dsc_video {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_nt35597_dsc_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_dual_jdi_video {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,5v-boost-gpio = <&tlmm 51 0>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_dual_jdi_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,5v-boost-gpio = <&tlmm 51 0>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_sharp_1080_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_jdi_1080_vid {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>;
+ qcom,5v-boost-gpio = <&tlmm 51 0>;
+};
+
+&i2c_7 {
+ status = "okay";
+ qcom,smb138x@8 {
+ compatible = "qcom,i2c-pmic";
+ reg = <0x8>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt_names = "smb138x";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>;
+
+ smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 {
+ compatible = "qcom,smb138x-parallel-slave";
+ reg = <0x1000 0x700>;
+ };
+ };
+};
+
+&pmicobalt_haptics {
+ status = "okay";
+};
+
+&pmcobalt_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@85 {
+ label = "vcoin";
+ reg = <0x85>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+&pmcobalt_adc_tm {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x60>;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+};
+
+&wil6210 {
+ status = "ok";
+};
+
+&soc {
+ sound-9335 {
+ qcom,wcn-btfm;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ status = "okay";
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pmcobalt_gpios 6 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ cam_snapshot {
+ label = "cam_snapshot";
+ gpios = <&pmcobalt_gpios 7 0x1>;
+ linux,input-type = <1>;
+ linux,code = <766>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ cam_focus {
+ label = "cam_focus";
+ gpios = <&pmcobalt_gpios 8 0x1>;
+ linux,input-type = <1>;
+ linux,code = <528>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+};
+
+/{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "fg-gen3-batterydata-itech-3000mah.dtsi"
+ #include "fg-gen3-batterydata-ascent-3450mah.dtsi"
+ };
+};
&mdss_mdp {
qcom,mdss-pref-prim-intf = "dsi";
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2-camera.dtsi
index 99d80a3b3848..fcc4d6d8ee2d 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-v2-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-v2-camera.dtsi
@@ -19,7 +19,10 @@
reg-names = "csiphy";
interrupts = <0 78 0>;
interrupt-names = "csiphy";
- clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>,
+ gdscr-supply = <&gdsc_camss_top>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "gdscr", "bimc_smmu";
+ clocks = <&clock_gcc clk_mmssnoc_axi_clk>,
<&clock_mmss clk_mmss_mnoc_ahb_clk>,
<&clock_mmss clk_mmss_bimc_smmu_ahb_clk>,
<&clock_mmss clk_mmss_bimc_smmu_axi_clk>,
@@ -33,13 +36,13 @@
<&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",
+ clock-names = "mmssnoc_axi", "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 269333333 0
+ qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0
0 256000000 0>;
status = "ok";
};
@@ -51,7 +54,10 @@
reg-names = "csiphy";
interrupts = <0 79 0>;
interrupt-names = "csiphy";
- clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>,
+ gdscr-supply = <&gdsc_camss_top>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "gdscr", "bimc_smmu";
+ clocks = <&clock_gcc clk_mmssnoc_axi_clk>,
<&clock_mmss clk_mmss_mnoc_ahb_clk>,
<&clock_mmss clk_mmss_bimc_smmu_ahb_clk>,
<&clock_mmss clk_mmss_bimc_smmu_axi_clk>,
@@ -65,13 +71,13 @@
<&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",
+ clock-names = "mmssnoc_axi", "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 269333333 0
+ qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0
0 256000000 0>;
status = "ok";
};
@@ -83,7 +89,10 @@
reg-names = "csiphy";
interrupts = <0 80 0>;
interrupt-names = "csiphy";
- clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>,
+ gdscr-supply = <&gdsc_camss_top>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "gdscr", "bimc_smmu";
+ clocks = <&clock_gcc clk_mmssnoc_axi_clk>,
<&clock_mmss clk_mmss_mnoc_ahb_clk>,
<&clock_mmss clk_mmss_bimc_smmu_ahb_clk>,
<&clock_mmss clk_mmss_bimc_smmu_axi_clk>,
@@ -97,13 +106,13 @@
<&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",
+ clock-names = "mmssnoc_axi", "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 269333333 0
+ qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0
0 256000000 0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-bus.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-bus.dtsi
index 11f602d842bc..cb5fce378b6c 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-bus.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-bus.dtsi
@@ -39,8 +39,8 @@
qcom,qos-off = <4096>;
qcom,base-offset = <16384>;
clock-names = "bus_clk", "bus_a_clk";
- clocks = <&clock_gcc RPM_AGGRE2_NOC_CLK>,
- <&clock_gcc RPM_AGGRE2_NOC_A_CLK>;
+ clocks = <&clock_rpmcc RPM_AGGR2_NOC_CLK>,
+ <&clock_rpmcc RPM_AGGR2_NOC_A_CLK>;
};
fab_bimc: fab-bimc {
@@ -52,8 +52,8 @@
qcom,bypass-qos-prg;
qcom,util-fact = <153>;
clock-names = "bus_clk", "bus_a_clk";
- clocks = <&clock_gcc RPM_BIMC_MSMBUS_CLK>,
- <&clock_gcc RPM_BIMC_MSMBUS_A_CLK>;
+ clocks = <&clock_rpmcc BIMC_MSMBUS_CLK>,
+ <&clock_rpmcc BIMC_MSMBUS_A_CLK>;
};
fab_cnoc: fab-cnoc {
@@ -64,8 +64,8 @@
qcom,bypass-qos-prg;
qcom,bus-type = <1>;
clock-names = "bus_clk", "bus_a_clk";
- clocks = <&clock_gcc RPM_CNOC_MSMBUS_CLK>,
- <&clock_gcc RPM_CNOC_MSMBUS_A_CLK>;
+ clocks = <&clock_rpmcc CNOC_MSMBUS_CLK>,
+ <&clock_rpmcc CNOC_MSMBUS_A_CLK>;
};
fab_gnoc: fab-gnoc {
@@ -87,8 +87,8 @@
qcom,base-offset = <20480>;
qcom,util-fact = <154>;
clock-names = "bus_clk", "bus_a_clk";
- clocks = <&clock_gcc RPM_MMSSNOC_AXI_CLK>,
- <&clock_gcc RPM_MMSSNOC_AXI_A_CLK>;
+ clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>,
+ <&clock_rpmcc MMSSNOC_AXI_A_CLK>;
};
fab_snoc: fab-snoc {
@@ -101,8 +101,8 @@
qcom,qos-off = <4096>;
qcom,base-offset = <24576>;
clock-names = "bus_clk", "bus_a_clk";
- clocks = <&clock_gcc RPM_SNOC_MSMBUS_CLK>,
- <&clock_gcc RPM_SNOC_MSMBUS_A_CLK>;
+ clocks = <&clock_rpmcc SNOC_MSMBUS_CLK>,
+ <&clock_rpmcc SNOC_MSMBUS_A_CLK>;
};
fab_mnoc_ahb: fab-mnoc-ahb {
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi
index b60d4013dad8..3826b00bf09e 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi
@@ -30,8 +30,8 @@
coresight-name = "coresight-tmc-etr";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "apb_pclk", "core_a_clk";
port{
@@ -80,8 +80,8 @@
coresight-ctis = <&cti0 &cti8>;
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "apb_pclk", "core_a_clk";
ports{
@@ -115,8 +115,8 @@
coresight-name = "coresight-funnel-merg";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "apb_pclk", "core_a_clk";
ports {
@@ -150,8 +150,8 @@
coresight-name = "coresight-funnel-in0";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "apb_pclk", "core_a_clk";
ports {
@@ -193,8 +193,8 @@
coresight-name = "coresight-stm";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "apb_pclk", "core_a_clk";
port{
@@ -211,8 +211,8 @@
coresight-name = "coresight-cti0";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -223,8 +223,8 @@
coresight-name = "coresight-cti1";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -235,8 +235,8 @@
coresight-name = "coresight-cti2";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -247,8 +247,8 @@
coresight-name = "coresight-cti3";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -259,8 +259,8 @@
coresight-name = "coresight-cti4";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -271,8 +271,8 @@
coresight-name = "coresight-cti5";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -283,8 +283,8 @@
coresight-name = "coresight-cti6";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -295,8 +295,8 @@
coresight-name = "coresight-cti7";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -307,8 +307,8 @@
coresight-name = "coresight-cti8";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -319,8 +319,8 @@
coresight-name = "coresight-cti9";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -331,8 +331,8 @@
coresight-name = "coresight-cti10";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -343,8 +343,8 @@
coresight-name = "coresight-cti11";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -355,8 +355,8 @@
coresight-name = "coresight-cti12";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -367,8 +367,8 @@
coresight-name = "coresight-cti13";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -379,8 +379,8 @@
coresight-name = "coresight-cti14";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -391,8 +391,8 @@
coresight-name = "coresight-cti15";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
};
@@ -405,8 +405,8 @@
coresight-name = "coresight-funnel-qatb";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "apb_pclk", "core_a_clk";
ports {
@@ -451,8 +451,8 @@
<5 32>,
<9 64>;
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
ports {
@@ -483,8 +483,8 @@
coresight-name = "coresight-tpdm-dcc";
- clocks = <&clock_gcc RPM_QDSS_CLK>,
- <&clock_gcc RPM_QDSS_A_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
clock-names = "core_clk", "core_a_clk";
port{
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index 67748d6683c0..dcb58699ca7b 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -14,6 +14,7 @@
#include <dt-bindings/clock/qcom,gcc-msmfalcon.h>
#include <dt-bindings/clock/qcom,gpu-msmfalcon.h>
#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
@@ -135,6 +136,22 @@
};
};
+ clocks {
+ xo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ clock-output-names = "xo_board";
+ };
+
+ sleep_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32764>;
+ clock-output-names = "sleep_clk";
+ };
+ };
+
soc: soc { };
reserved-memory {
@@ -360,19 +377,31 @@
};
};
- clock_gcc: qcom,dummycc {
+ clock_rpmcc: qcom,dummycc {
+ compatible = "qcom,dummycc";
+ clock-output-names = "rpmcc_clocks";
+ #clock-cells = <1>;
+ };
+
+ clock_gcc: clock-controller@100000 {
compatible = "qcom,dummycc";
+ clock-output-names = "gcc_clocks";
#clock-cells = <1>;
+ #reset-cells = <1>;
};
- clock_mmss: qcom,dummycc {
+ clock_mmss: clock-controller@c8c0000 {
compatible = "qcom,dummycc";
+ clock-output-names = "mmss_clocks";
#clock-cells = <1>;
+ #reset-cells = <1>;
};
- clock_gfx: qcom,dummycc {
+ clock_gfx: clock-controller@5065000 {
compatible = "qcom,dummycc";
+ clock-output-names = "gfx_clocks";
#clock-cells = <1>;
+ #reset-cells = <1>;
};
qcom,ipc-spinlock@1f40000 {
@@ -398,7 +427,7 @@
<0x10b4000 0x800>;
reg-names = "dcc-base", "dcc-ram-base";
- clocks = <&clock_gcc RPM_QDSS_CLK>;
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>;
clock-names = "dcc_clk";
};
diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi
index 3f0d4cc48696..f847d00c2cc9 100644
--- a/arch/arm/boot/dts/qcom/msmtriton.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi
@@ -14,6 +14,7 @@
#include <dt-bindings/clock/qcom,gcc-msmfalcon.h>
#include <dt-bindings/clock/qcom,gpu-msmfalcon.h>
#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
@@ -134,6 +135,22 @@
};
};
+ clocks {
+ xo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ clock-output-names = "xo_board";
+ };
+
+ sleep_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32764>;
+ clock-output-names = "sleep_clk";
+ };
+ };
+
soc: soc { };
reserved-memory {
@@ -308,19 +325,31 @@
};
};
- clock_gcc: qcom,dummycc {
+ clock_rpmcc: qcom,dummycc {
+ compatible = "qcom,dummycc";
+ clock-output-names = "rpmcc_clocks";
+ #clock-cells = <1>;
+ };
+
+ clock_gcc: clock-controller@100000 {
compatible = "qcom,dummycc";
+ clock-output-names = "gcc_clocks";
#clock-cells = <1>;
+ #reset-cells = <1>;
};
- clock_mmss: qcom,dummycc {
+ clock_mmss: clock-controller@c8c0000 {
compatible = "qcom,dummycc";
+ clock-output-names = "mmss_clocks";
#clock-cells = <1>;
+ #reset-cells = <1>;
};
- clock_gfx: qcom,dummycc {
+ clock_gfx: clock-controller@5065000 {
compatible = "qcom,dummycc";
+ clock-output-names = "gfx_clocks";
#clock-cells = <1>;
+ #reset-cells = <1>;
};
qcom,ipc-spinlock@1f40000 {
diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig
index db50dce9f9a4..64da50bb55b2 100644
--- a/arch/arm/configs/msmfalcon_defconfig
+++ b/arch/arm/configs/msmfalcon_defconfig
@@ -222,6 +222,8 @@ CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_HDCP_QSEECOM=y
CONFIG_UID_CPUTIME=y
CONFIG_MSM_ULTRASOUND=y
CONFIG_SCSI=y
@@ -330,6 +332,12 @@ CONFIG_MSM_SDE_ROTATOR=y
CONFIG_QCOM_KGSL=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_DP_PANEL=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
@@ -399,7 +407,6 @@ CONFIG_STAGING=y
CONFIG_ASHMEM=y
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_SYNC=y
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_QPNP_REVID=y
@@ -413,6 +420,7 @@ CONFIG_IPA3=y
CONFIG_RMNET_IPA3=y
CONFIG_GPIO_USB_DETECT=y
CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index 6ba13806cf16..5f8b02904d49 100644
--- a/arch/arm64/configs/msm-perf_defconfig
+++ b/arch/arm64/configs/msm-perf_defconfig
@@ -547,6 +547,9 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig
index bc5fc905188c..c1c0ae9da001 100644
--- a/arch/arm64/configs/msm_defconfig
+++ b/arch/arm64/configs/msm_defconfig
@@ -554,6 +554,9 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 938e11151050..036d6aa5c062 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -555,6 +555,9 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index 8674161f29e9..77f0129776a3 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -575,6 +575,9 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index e5389bc981ee..eff70892dada 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -49,6 +49,17 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
return prot;
}
+static int __get_iommu_pgprot(struct dma_attrs *attrs, int prot,
+ bool coherent)
+{
+ if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
+ prot |= IOMMU_NOEXEC;
+ if (coherent)
+ prot |= IOMMU_CACHE;
+
+ return prot;
+}
+
static struct gen_pool *atomic_pool;
#define NO_KERNEL_MAPPING_DUMMY 0x2222
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
@@ -1153,7 +1164,7 @@ static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
/* IOMMU */
static void __dma_clear_buffer(struct page *page, size_t size,
- struct dma_attrs *attrs)
+ struct dma_attrs *attrs, bool is_coherent)
{
/*
* Ensure that the allocated pages are zeroed, and that any data
@@ -1162,7 +1173,8 @@ static void __dma_clear_buffer(struct page *page, size_t size,
void *ptr = page_address(page);
if (!dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs))
memset(ptr, 0, size);
- dmac_flush_range(ptr, ptr + size);
+ if (!is_coherent)
+ dmac_flush_range(ptr, ptr + size);
}
static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
@@ -1212,6 +1224,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
size_t count = size >> PAGE_SHIFT;
size_t array_size = count * sizeof(struct page *);
int i = 0;
+ bool is_coherent = is_device_dma_coherent(dev);
if (array_size <= PAGE_SIZE)
pages = kzalloc(array_size, gfp);
@@ -1228,7 +1241,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
if (!page)
goto error;
- __dma_clear_buffer(page, size, attrs);
+ __dma_clear_buffer(page, size, attrs, is_coherent);
for (i = 0; i < count; i++)
pages[i] = page + i;
@@ -1257,7 +1270,8 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
pages[i + j] = pages[i] + j;
}
- __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs);
+ __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs,
+ is_coherent);
i += 1 << order;
count -= 1 << order;
}
@@ -1322,9 +1336,8 @@ static dma_addr_t __iommu_create_mapping(struct device *dev,
dma_addr = __alloc_iova(mapping, size);
if (dma_addr == DMA_ERROR_CODE)
return dma_addr;
-
- if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
- prot |= IOMMU_NOEXEC;
+ prot = __get_iommu_pgprot(attrs, prot,
+ is_device_dma_coherent(dev));
iova = dma_addr;
for (i = 0; i < count; ) {
@@ -1404,6 +1417,7 @@ static void *__iommu_alloc_atomic(struct device *dev, size_t size,
size_t array_size = count * sizeof(struct page *);
int i;
void *addr;
+ bool coherent = is_device_dma_coherent(dev);
if (array_size <= PAGE_SIZE)
pages = kzalloc(array_size, gfp);
@@ -1413,7 +1427,13 @@ static void *__iommu_alloc_atomic(struct device *dev, size_t size,
if (!pages)
return NULL;
- addr = __alloc_from_pool(size, &page, gfp);
+ if (coherent) {
+ page = alloc_pages(gfp, get_order(size));
+ addr = page ? page_address(page) : NULL;
+ } else {
+ addr = __alloc_from_pool(size, &page, gfp);
+ }
+
if (!addr)
goto err_free;
@@ -1428,7 +1448,10 @@ static void *__iommu_alloc_atomic(struct device *dev, size_t size,
return addr;
err_mapping:
- __free_from_pool(addr, size);
+ if (coherent)
+ __free_pages(page, get_order(size));
+ else
+ __free_from_pool(addr, size);
err_free:
kvfree(pages);
return NULL;
@@ -1444,7 +1467,8 @@ static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
{
- pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, false);
+ bool coherent = is_device_dma_coherent(dev);
+ pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
struct page **pages;
void *addr = NULL;
@@ -1495,8 +1519,10 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
unsigned long uaddr = vma->vm_start;
unsigned long usize = vma->vm_end - vma->vm_start;
struct page **pages = __iommu_get_pages(cpu_addr, attrs);
+ bool coherent = is_device_dma_coherent(dev);
- vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, false);
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
+ coherent);
if (!pages)
return -ENXIO;
@@ -1577,121 +1603,6 @@ static int __dma_direction_to_prot(enum dma_data_direction dir)
return prot;
}
-/*
- * Map a part of the scatter-gather list into contiguous io address space
- */
-static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
- size_t size, dma_addr_t *handle,
- enum dma_data_direction dir, struct dma_attrs *attrs,
- bool is_coherent)
-{
- struct dma_iommu_mapping *mapping = dev->archdata.mapping;
- dma_addr_t iova, iova_base;
- int ret = 0;
- unsigned int count;
- struct scatterlist *s;
- int prot;
-
- size = PAGE_ALIGN(size);
- *handle = DMA_ERROR_CODE;
-
- iova_base = iova = __alloc_iova(mapping, size);
- if (iova == DMA_ERROR_CODE)
- return -ENOMEM;
-
- for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
- phys_addr_t phys = page_to_phys(sg_page(s));
- unsigned int len = PAGE_ALIGN(s->offset + s->length);
-
- if (!is_coherent &&
- !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
- __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length,
- dir);
-
- prot = __dma_direction_to_prot(dir);
- if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
- prot |= IOMMU_NOEXEC;
-
- ret = iommu_map(mapping->domain, iova, phys, len, prot);
- if (ret < 0)
- goto fail;
- count += len >> PAGE_SHIFT;
- iova += len;
- }
- *handle = iova_base;
-
- return 0;
-fail:
- iommu_unmap(mapping->domain, iova_base, count * PAGE_SIZE);
- __free_iova(mapping, iova_base, size);
- return ret;
-}
-
-static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir, struct dma_attrs *attrs,
- bool is_coherent)
-{
- struct scatterlist *s = sg, *dma = sg, *start = sg;
- int i, count = 0;
- unsigned int offset = s->offset;
- unsigned int size = s->offset + s->length;
- unsigned int max = dma_get_max_seg_size(dev);
-
- for (i = 1; i < nents; i++) {
- s = sg_next(s);
-
- s->dma_address = DMA_ERROR_CODE;
- s->dma_length = 0;
-
- if (s->offset || (size & ~PAGE_MASK)
- || size + s->length > max) {
- if (__map_sg_chunk(dev, start, size, &dma->dma_address,
- dir, attrs, is_coherent) < 0)
- goto bad_mapping;
-
- dma->dma_address += offset;
- dma->dma_length = size - offset;
-
- size = offset = s->offset;
- start = s;
- dma = sg_next(dma);
- count += 1;
- }
- size += s->length;
- }
- if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs,
- is_coherent) < 0)
- goto bad_mapping;
-
- dma->dma_address += offset;
- dma->dma_length = size - offset;
-
- return count+1;
-
-bad_mapping:
- for_each_sg(sg, s, count, i)
- __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
- return 0;
-}
-
-/**
- * arm_coherent_iommu_map_sg - map a set of SG buffers for streaming mode DMA
- * @dev: valid struct device pointer
- * @sg: list of buffers
- * @nents: number of buffers to map
- * @dir: DMA transfer direction
- *
- * Map a set of i/o coherent buffers described by scatterlist in streaming
- * mode for DMA. The scatter gather list elements are merged together (if
- * possible) and tagged with the appropriate dma address and length. They are
- * obtained via sg_dma_{address,length}.
- */
-int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
-{
- return __iommu_map_sg(dev, sg, nents, dir, attrs, true);
-}
-
/**
* arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
* @dev: valid struct device pointer
@@ -1722,9 +1633,8 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
dev_err(dev, "Couldn't allocate iova for sg %p\n", sg);
return 0;
}
-
- if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
- prot |= IOMMU_NOEXEC;
+ prot = __get_iommu_pgprot(attrs, prot,
+ is_device_dma_coherent(dev));
ret = iommu_map_sg(mapping->domain, iova, sg, nents, prot);
if (ret != total_length) {
@@ -1741,40 +1651,6 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
return nents;
}
-static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir, struct dma_attrs *attrs,
- bool is_coherent)
-{
- struct scatterlist *s;
- int i;
-
- for_each_sg(sg, s, nents, i) {
- if (sg_dma_len(s))
- __iommu_remove_mapping(dev, sg_dma_address(s),
- sg_dma_len(s));
- if (!is_coherent &&
- !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
- __dma_page_dev_to_cpu(sg_page(s), s->offset,
- s->length, dir);
- }
-}
-
-/**
- * arm_coherent_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
- * @dev: valid struct device pointer
- * @sg: list of buffers
- * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
- * @dir: DMA transfer direction (same as was passed to dma_map_sg)
- *
- * Unmap a set of streaming mode DMA translations. Again, CPU access
- * rules concerning calls here are the same as for dma_unmap_single().
- */
-void arm_coherent_iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
-{
- __iommu_unmap_sg(dev, sg, nents, dir, attrs, true);
-}
-
/**
* arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
* @dev: valid struct device pointer
@@ -1812,6 +1688,9 @@ void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
struct scatterlist *s;
int i;
+ if (is_device_dma_coherent(dev))
+ return;
+
for_each_sg(sg, s, nents, i)
__dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);
@@ -1830,6 +1709,9 @@ void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
struct scatterlist *s;
int i;
+ if (is_device_dma_coherent(dev))
+ return;
+
for_each_sg(sg, s, nents, i)
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
}
@@ -1858,8 +1740,8 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev,
return dma_addr;
prot = __dma_direction_to_prot(dir);
- if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
- prot |= IOMMU_NOEXEC;
+ prot = __get_iommu_pgprot(attrs, prot,
+ is_device_dma_coherent(dev));
ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len,
prot);
@@ -1886,38 +1768,14 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
- if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ if (!is_device_dma_coherent(dev) &&
+ !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
__dma_page_cpu_to_dev(page, offset, size, dir);
return arm_coherent_iommu_map_page(dev, page, offset, size, dir, attrs);
}
/**
- * arm_coherent_iommu_unmap_page
- * @dev: valid struct device pointer
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_page)
- * @dir: DMA transfer direction (same as passed to dma_map_page)
- *
- * Coherent IOMMU aware version of arm_dma_unmap_page()
- */
-static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir,
- struct dma_attrs *attrs)
-{
- struct dma_iommu_mapping *mapping = dev->archdata.mapping;
- dma_addr_t iova = handle & PAGE_MASK;
- int offset = handle & ~PAGE_MASK;
- int len = PAGE_ALIGN(size + offset);
-
- if (!iova)
- return;
-
- iommu_unmap(mapping->domain, iova, len);
- __free_iova(mapping, iova, len);
-}
-
-/**
* arm_iommu_unmap_page
* @dev: valid struct device pointer
* @handle: DMA address of buffer
@@ -1940,7 +1798,8 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
if (!iova)
return;
- if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ if (!(is_device_dma_coherent(dev) ||
+ dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)))
__dma_page_dev_to_cpu(page, offset, size, dir);
iommu_unmap(mapping->domain, iova, len);
@@ -1959,7 +1818,8 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev,
if (!iova)
return;
- __dma_page_dev_to_cpu(page, offset, size, dir);
+ if (!is_device_dma_coherent(dev))
+ __dma_page_dev_to_cpu(page, offset, size, dir);
}
static void arm_iommu_sync_single_for_device(struct device *dev,
@@ -1974,7 +1834,8 @@ static void arm_iommu_sync_single_for_device(struct device *dev,
if (!iova)
return;
- __dma_page_cpu_to_dev(page, offset, size, dir);
+ if (!is_device_dma_coherent(dev))
+ __dma_page_cpu_to_dev(page, offset, size, dir);
}
static int arm_iommu_dma_supported(struct device *dev, u64 mask)
@@ -2016,22 +1877,6 @@ const struct dma_map_ops iommu_ops = {
.mapping_error = arm_iommu_mapping_error,
};
-const struct dma_map_ops iommu_coherent_ops = {
- .alloc = arm_iommu_alloc_attrs,
- .free = arm_iommu_free_attrs,
- .mmap = arm_iommu_mmap_attrs,
- .get_sgtable = arm_iommu_get_sgtable,
-
- .map_page = arm_coherent_iommu_map_page,
- .unmap_page = arm_coherent_iommu_unmap_page,
-
- .map_sg = arm_coherent_iommu_map_sg,
- .unmap_sg = arm_coherent_iommu_unmap_sg,
-
- .set_dma_mask = arm_dma_set_mask,
- .dma_supported = arm_iommu_dma_supported,
-};
-
/**
* arm_iommu_create_mapping
* @bus: pointer to the bus holding the client device (for IOMMU calls)
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index b830334dc701..f0cd6cf3967d 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -3066,8 +3066,8 @@ int diag_dci_write_proc(uint8_t peripheral, int pkt_type, char *buf, int len)
!(driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask)) {
DIAG_LOG(DIAG_DEBUG_DCI,
"buf: 0x%pK, p: %d, len: %d, f_mask: %d\n",
- buf, peripheral, len,
- driver->feature[peripheral].rcvd_feature_mask);
+ buf, peripheral, len,
+ driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask);
return -EINVAL;
}
diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c
index fea1b74aacae..a2ffabe43c86 100644
--- a/drivers/char/diag/diagfwd_glink.c
+++ b/drivers/char/diag/diagfwd_glink.c
@@ -413,19 +413,16 @@ static int diag_glink_write(void *ctxt, unsigned char *buf, int len)
return -ENODEV;
}
- err = wait_event_interruptible(glink_info->wait_q,
- atomic_read(&glink_info->tx_intent_ready));
- if (err) {
- diagfwd_write_buffer_done(glink_info->fwd_ctxt, buf);
- return -ERESTARTSYS;
- }
-
- atomic_dec(&glink_info->tx_intent_ready);
- err = glink_tx(glink_info->hdl, glink_info, buf, len, tx_flags);
- if (!err) {
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s wrote to glink, len: %d\n",
- glink_info->name, len);
- }
+ if (atomic_read(&glink_info->tx_intent_ready)) {
+ atomic_dec(&glink_info->tx_intent_ready);
+ err = glink_tx(glink_info->hdl, glink_info, buf, len, tx_flags);
+ if (!err) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s wrote to glink, len: %d\n",
+ glink_info->name, len);
+ }
+ } else
+ err = -ENOMEM;
return err;
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 066890aebf39..22b9e05086bd 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -751,7 +751,9 @@ int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len)
if (!err)
fwd_info->write_bytes += len;
-
+ else
+ if (fwd_info->transport == TRANSPORT_GLINK)
+ diagfwd_write_buffer_done(fwd_info, buf_ptr);
return err;
}
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index 0d733f49f184..d6cdbbc78827 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -79,6 +79,7 @@ enum clk_osm_trace_packet_id {
#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40))
#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n)))
#define SEQ_REG1_MSMCOBALT_V2 0x1048
+#define VERSION_REG 0x0
#define OSM_TABLE_SIZE 40
#define MAX_CLUSTER_CNT 2
@@ -182,7 +183,9 @@ enum clk_osm_trace_packet_id {
#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC
#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0
#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4
+#define OSM_PLL_SW_OVERRIDE_EN 0x10C0
+#define PLL_SW_OVERRIDE_DROOP_EN BIT(0)
#define DCVS_DROOP_TIMER_CTRL 0x10B8
#define SEQ_MEM_ADDR 0x500
#define SEQ_CFG_BR_ADDR 0x170
@@ -377,6 +380,11 @@ static inline int clk_osm_read_reg_no_log(struct clk_osm *c, u32 offset)
return readl_relaxed_no_log((char *)c->vbases[OSM_BASE] + offset);
}
+static inline int clk_osm_mb(struct clk_osm *c, int base)
+{
+ return readl_relaxed_no_log((char *)c->vbases[base] + VERSION_REG);
+}
+
static inline int clk_osm_count_ns(struct clk_osm *c, u64 nsec)
{
u64 temp;
@@ -478,7 +486,7 @@ static int clk_osm_set_rate(struct clk *c, unsigned long rate)
}
/* Make sure the write goes through before proceeding */
- mb();
+ clk_osm_mb(cpuclk, OSM_BASE);
return 0;
}
@@ -490,7 +498,7 @@ static int clk_osm_enable(struct clk *c)
clk_osm_write_reg(cpuclk, 1, ENABLE_REG);
/* Make sure the write goes through before proceeding */
- mb();
+ clk_osm_mb(cpuclk, OSM_BASE);
/* Wait for 5us for OSM hardware to enable */
udelay(5);
@@ -1101,14 +1109,14 @@ static void clk_osm_setup_cluster_pll(struct clk_osm *c)
PLL_MODE);
/* Ensure writes complete before delaying */
- mb();
+ clk_osm_mb(c, PLL_BASE);
udelay(PLL_WAIT_LOCK_TIME_US);
writel_relaxed(0x6, c->vbases[PLL_BASE] + PLL_MODE);
/* Ensure write completes before delaying */
- mb();
+ clk_osm_mb(c, PLL_BASE);
usleep_range(50, 75);
@@ -1153,7 +1161,7 @@ static int clk_osm_setup_hw_table(struct clk_osm *c)
}
/* Make sure all writes go through */
- mb();
+ clk_osm_mb(c, OSM_BASE);
return 0;
}
@@ -1272,7 +1280,7 @@ static int clk_osm_set_cc_policy(struct platform_device *pdev)
}
/* Wait for the writes to complete */
- mb();
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
rc = of_property_read_bool(pdev->dev.of_node, "qcom,set-ret-inactive");
if (rc) {
@@ -1297,7 +1305,7 @@ static int clk_osm_set_cc_policy(struct platform_device *pdev)
clk_osm_write_reg(&perfcl_clk, val, SPM_CC_DCVS_DISABLE);
/* Wait for the writes to complete */
- mb();
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
devm_kfree(&pdev->dev, array);
return 0;
@@ -1392,7 +1400,7 @@ static int clk_osm_set_llm_freq_policy(struct platform_device *pdev)
clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE);
/* Wait for the write to complete */
- mb();
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
devm_kfree(&pdev->dev, array);
return 0;
@@ -1467,7 +1475,7 @@ static int clk_osm_set_llm_volt_policy(struct platform_device *pdev)
clk_osm_write_reg(&perfcl_clk, val, LLM_INTF_DCVS_DISABLE);
/* Wait for the writes to complete */
- mb();
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
devm_kfree(&pdev->dev, array);
return 0;
@@ -1668,7 +1676,7 @@ static void clk_osm_setup_osm_was(struct clk_osm *c)
}
/* Ensure writes complete before returning */
- mb();
+ clk_osm_mb(c, OSM_BASE);
}
static void clk_osm_setup_fsms(struct clk_osm *c)
@@ -1778,7 +1786,7 @@ static void clk_osm_setup_fsms(struct clk_osm *c)
val = clk_osm_read_reg(c,
DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
- val |= BVAL(15, 0, clk_osm_count_ns(c, 500));
+ val |= BVAL(15, 0, clk_osm_count_ns(c, 15000));
clk_osm_write_reg(c, val,
DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
}
@@ -1792,7 +1800,7 @@ static void clk_osm_setup_fsms(struct clk_osm *c)
if (c->wfx_fsm_en || c->ps_fsm_en || c->droop_fsm_en) {
clk_osm_write_reg(c, 0x1, DROOP_PROG_SYNC_DELAY_REG);
- clk_osm_write_reg(c, clk_osm_count_ns(c, 250),
+ clk_osm_write_reg(c, clk_osm_count_ns(c, 500),
DROOP_RELEASE_TIMER_CTRL);
clk_osm_write_reg(c, clk_osm_count_ns(c, 500),
DCVS_DROOP_TIMER_CTRL);
@@ -1801,6 +1809,11 @@ static void clk_osm_setup_fsms(struct clk_osm *c)
BVAL(6, 0, 0x8);
clk_osm_write_reg(c, val, DROOP_CTRL_REG);
}
+
+ /* Enable the PLL Droop Override */
+ val = clk_osm_read_reg(c, OSM_PLL_SW_OVERRIDE_EN);
+ val |= PLL_SW_OVERRIDE_DROOP_EN;
+ clk_osm_write_reg(c, val, OSM_PLL_SW_OVERRIDE_EN);
}
static void clk_osm_do_additional_setup(struct clk_osm *c,
@@ -1869,7 +1882,7 @@ static void clk_osm_apm_vc_setup(struct clk_osm *c)
SEQ_REG(76));
/* Ensure writes complete before returning */
- mb();
+ clk_osm_mb(c, OSM_BASE);
} else {
if (msmcobalt_v1) {
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1),
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
index f6c85cf8d9a4..5f779ec9bcc3 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
@@ -685,6 +685,10 @@ static void pll_db_commit_8996(struct mdss_pll_resources *pll,
MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0);
wmb(); /* make sure register committed */
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_VCO_TUNE, 0);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_CODE, 0);
+ wmb(); /* make sure register committed */
+
data = pdb->in.dsiclk_sel; /* set dsiclk_sel = 1 */
MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG1, data);
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-cobalt.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-cobalt.c
index d5d55a58bf7f..c4f77e01b682 100644
--- a/drivers/clk/msm/mdss/mdss-hdmi-pll-cobalt.c
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-cobalt.c
@@ -145,7 +145,7 @@ static void hdmi_cobalt_get_div(struct cobalt_reg_cfg *cfg, unsigned long pclk)
u32 const min_freq = 8000, max_freq = 12000;
u32 const cmp_cnt = 1024;
u32 const th_min = 500, th_max = 1000;
- u64 bit_clk = pclk * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+ u64 bit_clk = ((u64)pclk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
u32 half_rate_mode = 0;
u32 freq_optimal, list_elements;
int optimal_index;
@@ -161,7 +161,7 @@ find_optimal_index:
for (i = 0; i < sz_ratio; i++) {
for (j = 0; j < sz_band; j++) {
- u64 freq = (bit_clk / (1 << half_rate_mode));
+ u64 freq = div_u64(bit_clk, (1 << half_rate_mode));
freq *= (ratio_list[i] * (1 << band_list[j]));
do_div(freq, (u64) HDMI_MHZ_TO_HZ);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 5b9ce12c1e02..e39686ca4feb 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -155,6 +155,7 @@ config MSM_MMCC_8996
config MSM_GCC_FALCON
tristate "MSMFALCON Global Clock Controller"
+ select QCOM_GDSC
depends on COMMON_CLK_QCOM
---help---
Support for the global clock controller on Qualcomm Technologies, Inc
@@ -162,6 +163,16 @@ config MSM_GCC_FALCON
Say Y if you want to use peripheral devices such as UART, SPI, I2C,
USB, UFS, SD/eMMC, PCIe, etc.
+config MSM_GPUCC_FALCON
+ tristate "MSMFALCON Graphics Clock Controller"
+ select MSM_GCC_FALCON
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the graphics clock controller on Qualcomm Technologies, Inc
+ MSMfalcon devices.
+ Say Y if you want to support graphics controller devices which will
+ be required to enable those device.
+
config QCOM_HFPLL
tristate "High-Frequency PLL (HFPLL) Clock Controller"
depends on COMMON_CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index af58f206bc4a..7ee0294e9dc7 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_MSM_GCC_FALCON) += gcc-msmfalcon.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_MSM_GPUCC_FALCON) += gpucc-msmfalcon.o
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
obj-$(CONFIG_KRAITCC) += krait-cc.o
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index a075859771d3..933a208392bd 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -870,6 +870,7 @@ EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
static int clk_gfx3d_src_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
struct clk_rate_request parent_req = { };
struct clk_hw *p1, *p3, *xo, *curr_p;
const struct freq_tbl *f;
diff --git a/drivers/clk/qcom/gpucc-msmfalcon.c b/drivers/clk/qcom/gpucc-msmfalcon.c
new file mode 100644
index 000000000000..a2127e2629c7
--- /dev/null
+++ b/drivers/clk/qcom/gpucc-msmfalcon.c
@@ -0,0 +1,482 @@
+/*
+ * 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/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <dt-bindings/clock/qcom,gpu-msmfalcon.h>
+
+#include "clk-alpha-pll.h"
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "vdd-level-falcon.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+#define F_GFX(f, s, h, m, n, sf) { (f), (s), (2 * (h) - 1), (m), (n), (sf) }
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_DIG_NUM, 1, vdd_corner, NULL);
+static DEFINE_VDD_REGS_INIT(vdd_gfx, 1);
+
+enum {
+ P_CORE_BI_PLL_TEST_SE,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL0_OUT_MAIN_DIV,
+ P_GPU_PLL0_PLL_OUT_MAIN,
+ P_GPU_PLL1_PLL_OUT_MAIN,
+ P_XO,
+};
+
+static const struct parent_map gpucc_parent_map_0[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpucc_parent_names_0[] = {
+ "cxo_a",
+ "gcc_gpu_gpll0_clk",
+ "gcc_gpu_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gpucc_parent_map_1[] = {
+ { P_XO, 0 },
+ { P_GPU_PLL0_PLL_OUT_MAIN, 1 },
+ { P_GPU_PLL1_PLL_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpucc_parent_names_1[] = {
+ "xo",
+ "gpu_pll0_pll_out_main",
+ "gpu_pll1_pll_out_main",
+ "gcc_gpu_gpll0_clk",
+ "core_bi_pll_test_se",
+};
+
+static struct pll_vco gpu_vco[] = {
+ { 1000000000, 2000000000, 0 },
+ { 500000000, 1000000000, 2 },
+ { 250000000, 500000000, 3 },
+};
+
+/* 640MHz configuration */
+static const struct pll_config gpu_pll0_config = {
+ .l = 0x21,
+ .config_ctl_val = 0x4001055b,
+ .alpha = 0x55555600,
+ .alpha_u = 0x55,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct pll_vco_data pll_data[] = {
+ /* Frequency post-div */
+ { 640000000, 0x1 },
+};
+
+static struct clk_alpha_pll gpu_pll0_pll_out_main = {
+ .offset = 0x0,
+ .vco_table = gpu_vco,
+ .num_vco = ARRAY_SIZE(gpu_vco),
+ .vco_data = pll_data,
+ .num_vco_data = ARRAY_SIZE(pll_data),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_pll0_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_GPU_PLL_FMAX_MAP6(
+ MIN, 266000000,
+ LOWER, 432000000,
+ LOW, 640000000,
+ LOW_L1, 800000000,
+ NOMINAL, 1020000000,
+ HIGH, 1500000000),
+ },
+ },
+};
+
+static struct clk_alpha_pll gpu_pll1_pll_out_main = {
+ .offset = 0x40,
+ .vco_table = gpu_vco,
+ .num_vco = ARRAY_SIZE(gpu_vco),
+ .vco_data = pll_data,
+ .num_vco_data = ARRAY_SIZE(pll_data),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_pll1_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_GPU_PLL_FMAX_MAP6(
+ MIN, 266000000,
+ LOWER, 432000000,
+ LOW, 640000000,
+ LOW_L1, 800000000,
+ NOMINAL, 1020000000,
+ HIGH, 1500000000),
+ },
+ },
+};
+
+/* GFX clock init data */
+static struct clk_init_data gpu_clks_init[] = {
+ [0] = {
+ .name = "gfx3d_clk_src",
+ .parent_names = gpucc_parent_names_1,
+ .num_parents = 3,
+ .ops = &clk_gfx3d_src_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ [1] = {
+ .name = "gpucc_gfx3d_clk",
+ .parent_names = (const char *[]){
+ "gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ .vdd_class = &vdd_gfx,
+ },
+};
+
+/*
+ * Frequencies and PLL configuration
+ * The PLL source would be to ping-pong between GPU-PLL0
+ * and GPU-PLL1.
+ * ====================================================
+ * | F | PLL SRC Freq | PLL postdiv | RCG Div |
+ * ====================================================
+ * | 160000000 | 640000000 | 2 | 2 |
+ * | 266000000 | 532000000 | 1 | 2 |
+ * | 370000000 | 740000000 | 1 | 2 |
+ * | 465000000 | 930000000 | 1 | 2 |
+ * | 588000000 | 1176000000 | 1 | 2 |
+ * | 647000000 | 1294000000 | 1 | 2 |
+ * | 750000000 | 1500000000 | 1 | 2 |
+ * ====================================================
+*/
+
+static const struct freq_tbl ftbl_gfx3d_clk_src[] = {
+ F_GFX( 19200000, 0, 1, 0, 0, 0),
+ F_GFX(160000000, 0, 2, 0, 0, 640000000),
+ F_GFX(266000000, 0, 2, 0, 0, 532000000),
+ F_GFX(370000000, 0, 2, 0, 0, 740000000),
+ F_GFX(465000000, 0, 2, 0, 0, 930000000),
+ F_GFX(588000000, 0, 2, 0, 0, 1176000000),
+ F_GFX(647000000, 0, 2, 0, 0, 1294000000),
+ F_GFX(750000000, 0, 2, 0, 0, 1500000000),
+ { }
+};
+
+static struct clk_rcg2 gfx3d_clk_src = {
+ .cmd_rcgr = 0x1070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .freq_tbl = ftbl_gfx3d_clk_src,
+ .parent_map = gpucc_parent_map_1,
+ .flags = FORCE_ENABLE_RCGR,
+ .clkr.hw.init = &gpu_clks_init[0],
+};
+
+static const struct freq_tbl ftbl_rbbmtimer_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 rbbmtimer_clk_src = {
+ .cmd_rcgr = 0x10b0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpucc_parent_map_0,
+ .freq_tbl = ftbl_rbbmtimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "rbbmtimer_clk_src",
+ .parent_names = gpucc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(MIN, 19200000),
+ },
+};
+
+static const struct freq_tbl ftbl_rbcpr_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 rbcpr_clk_src = {
+ .cmd_rcgr = 0x1030,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpucc_parent_map_0,
+ .freq_tbl = ftbl_rbcpr_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "rbcpr_clk_src",
+ .parent_names = gpucc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ MIN, 19200000,
+ NOMINAL, 50000000),
+ },
+};
+
+static struct clk_branch gpucc_cxo_clk = {
+ .halt_reg = 0x1020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpucc_cxo_clk",
+ .parent_names = (const char *[]) {
+ "cxo_a",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpucc_gfx3d_clk = {
+ .halt_reg = 0x1098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1098,
+ .enable_mask = BIT(0),
+ .hw.init = &gpu_clks_init[1],
+ },
+};
+
+static struct clk_branch gpucc_rbbmtimer_clk = {
+ .halt_reg = 0x10d0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpucc_rbbmtimer_clk",
+ .parent_names = (const char *[]){
+ "rbbmtimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpucc_rbcpr_clk = {
+ .halt_reg = 0x1054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpucc_rbcpr_clk",
+ .parent_names = (const char *[]){
+ "rbcpr_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *gpucc_falcon_clocks[] = {
+ [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
+ [GPU_PLL0_PLL] = &gpu_pll0_pll_out_main.clkr,
+ [GPU_PLL1_PLL] = &gpu_pll1_pll_out_main.clkr,
+ [GPUCC_CXO_CLK] = &gpucc_cxo_clk.clkr,
+ [GPUCC_GFX3D_CLK] = &gpucc_gfx3d_clk.clkr,
+ [GPUCC_RBBMTIMER_CLK] = &gpucc_rbbmtimer_clk.clkr,
+ [GPUCC_RBCPR_CLK] = &gpucc_rbcpr_clk.clkr,
+ [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
+ [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
+};
+
+static const struct regmap_config gpucc_falcon_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x9034,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gpucc_falcon_desc = {
+ .config = &gpucc_falcon_regmap_config,
+ .clks = gpucc_falcon_clocks,
+ .num_clks = ARRAY_SIZE(gpucc_falcon_clocks),
+};
+
+static const struct of_device_id gpucc_falcon_match_table[] = {
+ { .compatible = "qcom,gpucc-msmfalcon" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpucc_falcon_match_table);
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev,
+ struct clk_hw *hw, char *prop_name, u32 index)
+{
+ struct device_node *of = pdev->dev.of_node;
+ int prop_len, i, j;
+ struct clk_vdd_class *vdd = hw->init->vdd_class;
+ int num = vdd->num_regulators + 1;
+ u32 *array;
+
+ if (!of_find_property(of, prop_name, &prop_len)) {
+ dev_err(&pdev->dev, "missing %s\n", prop_name);
+ return -EINVAL;
+ }
+
+ prop_len /= sizeof(u32);
+ if (prop_len % num) {
+ dev_err(&pdev->dev, "bad length %d\n", prop_len);
+ return -EINVAL;
+ }
+
+ prop_len /= num;
+ vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+ GFP_KERNEL);
+ if (!vdd->level_votes)
+ return -ENOMEM;
+
+ vdd->vdd_uv = devm_kzalloc(&pdev->dev,
+ prop_len * sizeof(int) * (num - 1), GFP_KERNEL);
+ if (!vdd->vdd_uv)
+ return -ENOMEM;
+
+ gpu_clks_init[index].fmax = devm_kzalloc(&pdev->dev, prop_len *
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!gpu_clks_init[index].fmax)
+ return -ENOMEM;
+
+ array = devm_kzalloc(&pdev->dev, prop_len * sizeof(u32) * num,
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ of_property_read_u32_array(of, prop_name, array, prop_len * num);
+ for (i = 0; i < prop_len; i++) {
+ gpu_clks_init[index].fmax[i] = array[num * i];
+ for (j = 1; j < num; j++) {
+ vdd->vdd_uv[(num - 1) * i + (j - 1)] =
+ array[num * i + j];
+ }
+ }
+
+ devm_kfree(&pdev->dev, array);
+ vdd->num_levels = prop_len;
+ vdd->cur_level = prop_len;
+ gpu_clks_init[index].num_fmax = prop_len;
+
+ return 0;
+}
+
+static int gpucc_falcon_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &gpucc_falcon_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* CX Regulator for RBBMTimer and RBCPR clock */
+ vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_gfx");
+ if (IS_ERR(vdd_dig.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_dig regulator\n");
+ return PTR_ERR(vdd_dig.regulator[0]);
+ }
+
+ /* Mx Regulator for GPU-PLLs */
+ vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx_gfx");
+ if (IS_ERR(vdd_mx.regulator[0])) {
+ if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_mx regulator\n");
+ return PTR_ERR(vdd_mx.regulator[0]);
+ }
+
+ /* GFX Rail Regulator for GFX3D clock */
+ vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx");
+ if (IS_ERR(vdd_gfx.regulator[0])) {
+ if (!(PTR_ERR(vdd_gfx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_gfx regulator\n");
+ return PTR_ERR(vdd_gfx.regulator[0]);
+ }
+
+ /* GFX rail fmax data linked to branch clock */
+ of_get_fmax_vdd_class(pdev, &gpucc_gfx3d_clk.clkr.hw,
+ "qcom,gfxfreq-corner", 1);
+
+ clk_alpha_pll_configure(&gpu_pll0_pll_out_main, regmap,
+ &gpu_pll0_config);
+ clk_alpha_pll_configure(&gpu_pll1_pll_out_main, regmap,
+ &gpu_pll0_config);
+
+ ret = qcom_cc_really_probe(pdev, &gpucc_falcon_desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register GPUCC clocks\n");
+ return ret;
+ }
+
+ clk_prepare_enable(gpucc_cxo_clk.clkr.hw.clk);
+
+ dev_info(&pdev->dev, "Registered GPUCC clocks\n");
+
+ return ret;
+}
+
+static struct platform_driver gpucc_falcon_driver = {
+ .probe = gpucc_falcon_probe,
+ .driver = {
+ .name = "gpucc-msmfalcon",
+ .of_match_table = gpucc_falcon_match_table,
+ },
+};
+
+static int __init gpucc_falcon_init(void)
+{
+ return platform_driver_register(&gpucc_falcon_driver);
+}
+core_initcall_sync(gpucc_falcon_init);
+
+static void __exit gpucc_falcon_exit(void)
+{
+ platform_driver_unregister(&gpucc_falcon_driver);
+}
+module_exit(gpucc_falcon_exit);
diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c
index f4ae70ac9315..b40231dd8dd1 100644
--- a/drivers/cpuidle/lpm-levels-of.c
+++ b/drivers/cpuidle/lpm-levels-of.c
@@ -38,34 +38,138 @@ static const struct lpm_type_str lpm_types[] = {
{SUSPEND, "suspend_enabled"},
};
+static DEFINE_PER_CPU(uint32_t *, max_residency);
+static DEFINE_PER_CPU(uint32_t *, min_residency);
static struct lpm_level_avail *cpu_level_available[NR_CPUS];
static struct platform_device *lpm_pdev;
-static void *get_avail_val(struct kobject *kobj, struct kobj_attribute *attr)
+static void *get_enabled_ptr(struct kobj_attribute *attr,
+ struct lpm_level_avail *avail)
{
void *arg = NULL;
+
+ if (!strcmp(attr->attr.name, lpm_types[IDLE].str))
+ arg = (void *) &avail->idle_enabled;
+ else if (!strcmp(attr->attr.name, lpm_types[SUSPEND].str))
+ arg = (void *) &avail->suspend_enabled;
+
+ return arg;
+}
+
+static struct lpm_level_avail *get_avail_ptr(struct kobject *kobj,
+ struct kobj_attribute *attr)
+{
struct lpm_level_avail *avail = NULL;
- if (!strcmp(attr->attr.name, lpm_types[IDLE].str)) {
+ if (!strcmp(attr->attr.name, lpm_types[IDLE].str))
avail = container_of(attr, struct lpm_level_avail,
idle_enabled_attr);
- arg = (void *) &avail->idle_enabled;
- } else if (!strcmp(attr->attr.name, lpm_types[SUSPEND].str)) {
+ else if (!strcmp(attr->attr.name, lpm_types[SUSPEND].str))
avail = container_of(attr, struct lpm_level_avail,
suspend_enabled_attr);
- arg = (void *) &avail->suspend_enabled;
+
+ return avail;
+}
+
+static void set_optimum_cpu_residency(struct lpm_cpu *cpu, int cpu_id,
+ bool probe_time)
+{
+ int i, j;
+ bool mode_avail;
+ uint32_t *maximum_residency = per_cpu(max_residency, cpu_id);
+ uint32_t *minimum_residency = per_cpu(min_residency, cpu_id);
+
+ for (i = 0; i < cpu->nlevels; i++) {
+ struct power_params *pwr = &cpu->levels[i].pwr;
+
+ mode_avail = probe_time ||
+ lpm_cpu_mode_allow(cpu_id, i, true);
+
+ if (!mode_avail) {
+ maximum_residency[i] = 0;
+ minimum_residency[i] = 0;
+ continue;
+ }
+
+ maximum_residency[i] = ~0;
+ for (j = i + 1; j < cpu->nlevels; j++) {
+ mode_avail = probe_time ||
+ lpm_cpu_mode_allow(cpu_id, j, true);
+
+ if (mode_avail &&
+ (maximum_residency[i] > pwr->residencies[j]) &&
+ (pwr->residencies[j] != 0))
+ maximum_residency[i] = pwr->residencies[j];
+ }
+
+ minimum_residency[i] = pwr->time_overhead_us;
+ for (j = i-1; j >= 0; j--) {
+ if (probe_time || lpm_cpu_mode_allow(cpu_id, j, true)) {
+ minimum_residency[i] = maximum_residency[j] + 1;
+ break;
+ }
+ }
}
+}
- return arg;
+static void set_optimum_cluster_residency(struct lpm_cluster *cluster,
+ bool probe_time)
+{
+ int i, j;
+ bool mode_avail;
+
+ for (i = 0; i < cluster->nlevels; i++) {
+ struct power_params *pwr = &cluster->levels[i].pwr;
+
+ mode_avail = probe_time ||
+ lpm_cluster_mode_allow(cluster, i,
+ true);
+
+ if (!mode_avail) {
+ pwr->max_residency = 0;
+ pwr->min_residency = 0;
+ continue;
+ }
+
+ pwr->max_residency = ~0;
+ for (j = i+1; j < cluster->nlevels; j++) {
+ mode_avail = probe_time ||
+ lpm_cluster_mode_allow(cluster, j,
+ true);
+ if (mode_avail &&
+ (pwr->max_residency > pwr->residencies[j]) &&
+ (pwr->residencies[j] != 0))
+ pwr->max_residency = pwr->residencies[j];
+ }
+
+ pwr->min_residency = pwr->time_overhead_us;
+ for (j = i-1; j >= 0; j--) {
+ if (probe_time ||
+ lpm_cluster_mode_allow(cluster, j, true)) {
+ pwr->min_residency =
+ cluster->levels[j].pwr.max_residency + 1;
+ break;
+ }
+ }
+ }
}
+uint32_t *get_per_cpu_max_residency(int cpu)
+{
+ return per_cpu(max_residency, cpu);
+}
+
+uint32_t *get_per_cpu_min_residency(int cpu)
+{
+ return per_cpu(min_residency, cpu);
+}
ssize_t lpm_enable_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
int ret = 0;
struct kernel_param kp;
- kp.arg = get_avail_val(kobj, attr);
+ kp.arg = get_enabled_ptr(attr, get_avail_ptr(kobj, attr));
ret = param_get_bool(buf, &kp);
if (ret > 0) {
strlcat(buf, "\n", PAGE_SIZE);
@@ -80,15 +184,25 @@ ssize_t lpm_enable_store(struct kobject *kobj, struct kobj_attribute *attr,
{
int ret = 0;
struct kernel_param kp;
+ struct lpm_level_avail *avail;
- kp.arg = get_avail_val(kobj, attr);
+ avail = get_avail_ptr(kobj, attr);
+ if (WARN_ON(!avail))
+ return -EINVAL;
+ kp.arg = get_enabled_ptr(attr, avail);
ret = param_set_bool(buf, &kp);
+ if (avail->cpu_node)
+ set_optimum_cpu_residency(avail->data, avail->idx, false);
+ else
+ set_optimum_cluster_residency(avail->data, false);
+
return ret ? ret : len;
}
static int create_lvl_avail_nodes(const char *name,
- struct kobject *parent, struct lpm_level_avail *avail)
+ struct kobject *parent, struct lpm_level_avail *avail,
+ void *data, int index, bool cpu_node)
{
struct attribute_group *attr_group = NULL;
struct attribute **attr = NULL;
@@ -139,6 +253,9 @@ static int create_lvl_avail_nodes(const char *name,
avail->idle_enabled = true;
avail->suspend_enabled = true;
avail->kobj = kobj;
+ avail->data = data;
+ avail->idx = index;
+ avail->cpu_node = cpu_node;
return ret;
@@ -181,7 +298,8 @@ static int create_cpu_lvl_nodes(struct lpm_cluster *p, struct kobject *parent)
for (i = 0; i < p->cpu->nlevels; i++) {
ret = create_lvl_avail_nodes(p->cpu->levels[i].name,
- cpu_kobj[cpu_idx], &level_list[i]);
+ cpu_kobj[cpu_idx], &level_list[i],
+ (void *)p->cpu, cpu, true);
if (ret)
goto release_kobj;
}
@@ -215,7 +333,8 @@ int create_cluster_lvl_nodes(struct lpm_cluster *p, struct kobject *kobj)
for (i = 0; i < p->nlevels; i++) {
ret = create_lvl_avail_nodes(p->levels[i].level_name,
- cluster_kobj, &p->levels[i].available);
+ cluster_kobj, &p->levels[i].available,
+ (void *)p, 0, false);
if (ret)
return ret;
}
@@ -421,6 +540,9 @@ static int parse_power_params(struct device_node *node,
key = "qcom,time-overhead";
ret = of_property_read_u32(node, key, &pwr->time_overhead_us);
+ if (ret)
+ goto fail;
+
fail:
if (ret)
pr_err("%s(): %s Error reading %s\n", __func__, node->name,
@@ -615,11 +737,31 @@ static int get_cpumask_for_node(struct device_node *node, struct cpumask *mask)
return 0;
}
+static int calculate_residency(struct power_params *base_pwr,
+ struct power_params *next_pwr)
+{
+ int32_t residency = (int32_t)(next_pwr->energy_overhead -
+ base_pwr->energy_overhead) -
+ ((int32_t)(next_pwr->ss_power * next_pwr->time_overhead_us)
+ - (int32_t)(base_pwr->ss_power * base_pwr->time_overhead_us));
+
+ residency /= (int32_t)(base_pwr->ss_power - next_pwr->ss_power);
+
+ if (residency < 0) {
+ __WARN_printf("%s: Incorrect power attributes for LPM\n",
+ __func__);
+ return next_pwr->time_overhead_us;
+ }
+
+ return residency < next_pwr->time_overhead_us ?
+ next_pwr->time_overhead_us : residency;
+}
+
static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c)
{
struct device_node *n;
int ret = -ENOMEM;
- int i;
+ int i, j;
char *key;
c->cpu = devm_kzalloc(&lpm_pdev->dev, sizeof(*c->cpu), GFP_KERNEL);
@@ -676,6 +818,22 @@ static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c)
else if (ret)
goto failed;
}
+ for (i = 0; i < c->cpu->nlevels; i++) {
+ for (j = 0; j < c->cpu->nlevels; j++) {
+ if (i >= j) {
+ c->cpu->levels[i].pwr.residencies[j] = 0;
+ continue;
+ }
+
+ c->cpu->levels[i].pwr.residencies[j] =
+ calculate_residency(&c->cpu->levels[i].pwr,
+ &c->cpu->levels[j].pwr);
+
+ pr_err("%s: idx %d %u\n", __func__, j,
+ c->cpu->levels[i].pwr.residencies[j]);
+ }
+ }
+
return 0;
failed:
for (i = 0; i < c->cpu->nlevels; i++) {
@@ -732,6 +890,7 @@ struct lpm_cluster *parse_cluster(struct device_node *node,
struct device_node *n;
char *key;
int ret = 0;
+ int i, j;
c = devm_kzalloc(&lpm_pdev->dev, sizeof(*c), GFP_KERNEL);
if (!c)
@@ -789,6 +948,22 @@ struct lpm_cluster *parse_cluster(struct device_node *node,
goto failed_parse_cluster;
c->aff_level = 1;
+
+ for_each_cpu(i, &c->child_cpus) {
+ per_cpu(max_residency, i) = devm_kzalloc(
+ &lpm_pdev->dev,
+ sizeof(uint32_t) * c->cpu->nlevels,
+ GFP_KERNEL);
+ if (!per_cpu(max_residency, i))
+ return ERR_PTR(-ENOMEM);
+ per_cpu(min_residency, i) = devm_kzalloc(
+ &lpm_pdev->dev,
+ sizeof(uint32_t) * c->cpu->nlevels,
+ GFP_KERNEL);
+ if (!per_cpu(min_residency, i))
+ return ERR_PTR(-ENOMEM);
+ set_optimum_cpu_residency(c->cpu, i, true);
+ }
}
}
@@ -797,6 +972,17 @@ struct lpm_cluster *parse_cluster(struct device_node *node,
else
c->last_level = c->nlevels-1;
+ for (i = 0; i < c->nlevels; i++) {
+ for (j = 0; j < c->nlevels; j++) {
+ if (i >= j) {
+ c->levels[i].pwr.residencies[j] = 0;
+ continue;
+ }
+ c->levels[i].pwr.residencies[j] = calculate_residency(
+ &c->levels[i].pwr, &c->levels[j].pwr);
+ }
+ }
+ set_optimum_cluster_residency(c, true);
return c;
failed_parse_cluster:
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 4f880fdd1478..ced95aa2b649 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1,4 +1,6 @@
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2006-2007 Adam Belay <abelay@novell.com>
+ * Copyright (C) 2009 Intel Corporation
*
* 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
@@ -83,9 +85,37 @@ struct lpm_debug {
struct lpm_cluster *lpm_root_node;
+#define MAXSAMPLES 5
+
+static bool lpm_prediction;
+module_param_named(lpm_prediction,
+ lpm_prediction, bool, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static uint32_t ref_stddev = 100;
+module_param_named(
+ ref_stddev, ref_stddev, uint, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static uint32_t tmr_add = 100;
+module_param_named(
+ tmr_add, tmr_add, uint, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+struct lpm_history {
+ uint32_t resi[MAXSAMPLES];
+ int mode[MAXSAMPLES];
+ int nsamp;
+ uint32_t hptr;
+ uint32_t hinvalid;
+ uint32_t htmr_wkup;
+};
+
+static DEFINE_PER_CPU(struct lpm_history, hist);
+
static DEFINE_PER_CPU(struct lpm_cluster*, cpu_cluster);
static bool suspend_in_progress;
static struct hrtimer lpm_hrtimer;
+static struct hrtimer histtimer;
static struct lpm_debug *lpm_debug;
static phys_addr_t lpm_debug_phys;
static const int num_dbg_elements = 0x100;
@@ -327,10 +357,37 @@ static enum hrtimer_restart lpm_hrtimer_cb(struct hrtimer *h)
return HRTIMER_NORESTART;
}
+static void histtimer_cancel(void)
+{
+ if (!lpm_prediction)
+ return;
+
+ hrtimer_try_to_cancel(&histtimer);
+}
+
+static enum hrtimer_restart histtimer_fn(struct hrtimer *h)
+{
+ int cpu = raw_smp_processor_id();
+ struct lpm_history *history = &per_cpu(hist, cpu);
+
+ history->hinvalid = 1;
+ return HRTIMER_NORESTART;
+}
+
+static void histtimer_start(uint32_t time_us)
+{
+ uint64_t time_ns = time_us * NSEC_PER_USEC;
+ ktime_t hist_ktime = ns_to_ktime(time_ns);
+
+ histtimer.function = histtimer_fn;
+ hrtimer_start(&histtimer, hist_ktime, HRTIMER_MODE_REL_PINNED);
+}
+
static void msm_pm_set_timer(uint32_t modified_time_us)
{
u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
+
lpm_hrtimer.function = lpm_hrtimer_cb;
hrtimer_start(&lpm_hrtimer, modified_ktime, HRTIMER_MODE_REL_PINNED);
}
@@ -415,22 +472,160 @@ static int set_device_mode(struct lpm_cluster *cluster, int ndevice,
return -EINVAL;
}
+static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev,
+ struct lpm_cpu *cpu, int *idx_restrict,
+ uint32_t *idx_restrict_time)
+{
+ int i, j, divisor;
+ uint64_t max, avg, stddev;
+ int64_t thresh = LLONG_MAX;
+ struct lpm_history *history = &per_cpu(hist, dev->cpu);
+ uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu);
+
+ if (!lpm_prediction)
+ return 0;
+
+ /*
+ * Samples are marked invalid when woken-up due to timer,
+ * so donot predict.
+ */
+ if (history->hinvalid) {
+ history->hinvalid = 0;
+ history->htmr_wkup = 1;
+ return 0;
+ }
+
+ /*
+ * Predict only when all the samples are collected.
+ */
+ if (history->nsamp < MAXSAMPLES)
+ return 0;
+
+ /*
+ * Check if the samples are not much deviated, if so use the
+ * average of those as predicted sleep time. Else if any
+ * specific mode has more premature exits return the index of
+ * that mode.
+ */
+
+again:
+ max = avg = divisor = stddev = 0;
+ for (i = 0; i < MAXSAMPLES; i++) {
+ int64_t value = history->resi[i];
+
+ if (value <= thresh) {
+ avg += value;
+ divisor++;
+ if (value > max)
+ max = value;
+ }
+ }
+ do_div(avg, divisor);
+
+ for (i = 0; i < MAXSAMPLES; i++) {
+ int64_t value = history->resi[i];
+
+ if (value <= thresh) {
+ int64_t diff = value - avg;
+
+ stddev += diff * diff;
+ }
+ }
+ do_div(stddev, divisor);
+ stddev = int_sqrt(stddev);
+
+ /*
+ * If the deviation is less, return the average, else
+ * ignore one maximum sample and retry
+ */
+ if (((avg > stddev * 6) && (divisor >= (MAXSAMPLES - 1)))
+ || stddev <= ref_stddev) {
+ return avg;
+ } else if (divisor > (MAXSAMPLES - 1)) {
+ thresh = max - 1;
+ goto again;
+ }
+
+ /*
+ * Find the number of premature exits for each of the mode,
+ * excluding clockgating mode, and they are more than fifty
+ * percent restrict that and deeper modes.
+ */
+ if (history->htmr_wkup != 1) {
+ for (j = 1; j < cpu->nlevels; j++) {
+ uint32_t failed = 0;
+ uint64_t total = 0;
+
+ for (i = 0; i < MAXSAMPLES; i++) {
+ if ((history->mode[i] == j) &&
+ (history->resi[i] < min_residency[j])) {
+ failed++;
+ total += history->resi[i];
+ }
+ }
+ if (failed > (MAXSAMPLES/2)) {
+ *idx_restrict = j;
+ do_div(total, failed);
+ *idx_restrict_time = total;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static inline void invalidate_predict_history(struct cpuidle_device *dev)
+{
+ struct lpm_history *history = &per_cpu(hist, dev->cpu);
+
+ if (!lpm_prediction)
+ return;
+
+ if (history->hinvalid) {
+ history->hinvalid = 0;
+ history->htmr_wkup = 1;
+ }
+}
+
+static void clear_predict_history(void)
+{
+ struct lpm_history *history;
+ int i;
+ unsigned int cpu;
+
+ if (!lpm_prediction)
+ return;
+
+ for_each_possible_cpu(cpu) {
+ history = &per_cpu(hist, cpu);
+ for (i = 0; i < MAXSAMPLES; i++) {
+ history->resi[i] = 0;
+ history->mode[i] = -1;
+ history->hptr = 0;
+ history->nsamp = 0;
+ }
+ }
+}
+
+static void update_history(struct cpuidle_device *dev, int idx);
+
static int cpu_power_select(struct cpuidle_device *dev,
struct lpm_cpu *cpu)
{
int best_level = -1;
- uint32_t best_level_pwr = ~0U;
uint32_t latency_us = pm_qos_request_for_cpu(PM_QOS_CPU_DMA_LATENCY,
dev->cpu);
uint32_t sleep_us =
(uint32_t)(ktime_to_us(tick_nohz_get_sleep_length()));
uint32_t modified_time_us = 0;
uint32_t next_event_us = 0;
- uint32_t pwr;
- int i;
+ int i, idx_restrict;
uint32_t lvl_latency_us = 0;
- uint32_t lvl_overhead_us = 0;
- uint32_t lvl_overhead_energy = 0;
+ uint64_t predicted = 0;
+ uint32_t htime = 0, idx_restrict_time = 0;
+ uint32_t next_wakeup_us = sleep_us;
+ uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu);
+ uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu);
if (!cpu)
return -EINVAL;
@@ -438,12 +633,13 @@ static int cpu_power_select(struct cpuidle_device *dev,
if (sleep_disabled)
return 0;
+ idx_restrict = cpu->nlevels + 1;
+
next_event_us = (uint32_t)(ktime_to_us(get_next_event_time(dev->cpu)));
for (i = 0; i < cpu->nlevels; i++) {
struct lpm_cpu_level *level = &cpu->levels[i];
struct power_params *pwr_params = &level->pwr;
- uint32_t next_wakeup_us = sleep_us;
enum msm_pm_sleep_mode mode = level->mode;
bool allow;
@@ -454,56 +650,76 @@ static int cpu_power_select(struct cpuidle_device *dev,
lvl_latency_us = pwr_params->latency_us;
- lvl_overhead_us = pwr_params->time_overhead_us;
-
- lvl_overhead_energy = pwr_params->energy_overhead;
-
if (latency_us < lvl_latency_us)
- continue;
+ break;
if (next_event_us) {
if (next_event_us < lvl_latency_us)
- continue;
+ break;
if (((next_event_us - lvl_latency_us) < sleep_us) ||
(next_event_us < sleep_us))
next_wakeup_us = next_event_us - lvl_latency_us;
}
- if (next_wakeup_us <= pwr_params->time_overhead_us)
- continue;
-
- /*
- * If wakeup time greater than overhead by a factor of 1000
- * assume that core steady state power dominates the power
- * equation
- */
- if ((next_wakeup_us >> 10) > lvl_overhead_us) {
- pwr = pwr_params->ss_power;
- } else {
- pwr = pwr_params->ss_power;
- pwr -= (lvl_overhead_us * pwr_params->ss_power) /
- next_wakeup_us;
- pwr += pwr_params->energy_overhead / next_wakeup_us;
+ if (!i) {
+ /*
+ * If the next_wake_us itself is not sufficient for
+ * deeper low power modes than clock gating do not
+ * call prediction.
+ */
+ if (next_wakeup_us > max_residency[i]) {
+ predicted = lpm_cpuidle_predict(dev, cpu,
+ &idx_restrict, &idx_restrict_time);
+ if (predicted < min_residency[i])
+ predicted = 0;
+ } else
+ invalidate_predict_history(dev);
}
- if (best_level_pwr >= pwr) {
- best_level = i;
- best_level_pwr = pwr;
- if (next_event_us && next_event_us < sleep_us &&
- (mode != MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
- modified_time_us
- = next_event_us - lvl_latency_us;
- else
- modified_time_us = 0;
- }
+ if (i >= idx_restrict)
+ break;
+
+ best_level = i;
+
+ if (next_event_us && next_event_us < sleep_us &&
+ (mode != MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
+ modified_time_us
+ = next_event_us - lvl_latency_us;
+ else
+ modified_time_us = 0;
+
+ if (predicted ? (predicted <= max_residency[i])
+ : (next_wakeup_us <= max_residency[i]))
+ break;
}
if (modified_time_us)
msm_pm_set_timer(modified_time_us);
+ /*
+ * Start timer to avoid staying in shallower mode forever
+ * incase of misprediciton
+ */
+ if ((predicted || (idx_restrict != (cpu->nlevels + 1)))
+ && ((best_level >= 0)
+ && (best_level < (cpu->nlevels-1)))) {
+ htime = predicted + tmr_add;
+ if (htime == tmr_add)
+ htime = idx_restrict_time;
+ else if (htime > max_residency[best_level])
+ htime = max_residency[best_level];
+
+ if ((next_wakeup_us > htime) &&
+ ((next_wakeup_us - htime) > max_residency[best_level]))
+ histtimer_start(htime);
+ }
+
trace_cpu_power_select(best_level, sleep_us, latency_us, next_event_us);
+ trace_cpu_pred_select(idx_restrict_time ? 2 : (predicted ? 1 : 0),
+ predicted, htime);
+
return best_level;
}
@@ -554,8 +770,6 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle)
{
int best_level = -1;
int i;
- uint32_t best_level_pwr = ~0U;
- uint32_t pwr;
struct cpumask mask;
uint32_t latency_us = ~0U;
uint32_t sleep_us;
@@ -596,10 +810,10 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle)
continue;
if (from_idle && latency_us < pwr_params->latency_us)
- continue;
+ break;
if (sleep_us < pwr_params->time_overhead_us)
- continue;
+ break;
if (suspend_in_progress && from_idle && level->notify_rpm)
continue;
@@ -607,19 +821,10 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle)
if (level->notify_rpm && msm_rpm_waiting_for_ack())
continue;
- if ((sleep_us >> 10) > pwr_params->time_overhead_us) {
- pwr = pwr_params->ss_power;
- } else {
- pwr = pwr_params->ss_power;
- pwr -= (pwr_params->time_overhead_us *
- pwr_params->ss_power) / sleep_us;
- pwr += pwr_params->energy_overhead / sleep_us;
- }
+ best_level = i;
- if (best_level_pwr >= pwr) {
- best_level = i;
- best_level_pwr = pwr;
- }
+ if (sleep_us <= pwr_params->max_residency)
+ break;
}
return best_level;
@@ -675,6 +880,7 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
}
us = us + 1;
+ clear_predict_history();
do_div(us, USEC_PER_SEC/SCLK_HZ);
msm_mpm_enter_sleep(us, from_idle, cpumask);
}
@@ -1009,6 +1215,39 @@ static int lpm_cpuidle_select(struct cpuidle_driver *drv,
return idx;
}
+static void update_history(struct cpuidle_device *dev, int idx)
+{
+ struct lpm_history *history = &per_cpu(hist, dev->cpu);
+ uint32_t tmr = 0;
+
+ if (!lpm_prediction)
+ return;
+
+ if (history->htmr_wkup) {
+ if (!history->hptr)
+ history->hptr = MAXSAMPLES-1;
+ else
+ history->hptr--;
+
+ history->resi[history->hptr] += dev->last_residency;
+ history->htmr_wkup = 0;
+ tmr = 1;
+ } else
+ history->resi[history->hptr] = dev->last_residency;
+
+ history->mode[history->hptr] = idx;
+
+ trace_cpu_pred_hist(history->mode[history->hptr],
+ history->resi[history->hptr], history->hptr, tmr);
+
+ if (history->nsamp < MAXSAMPLES)
+ history->nsamp++;
+
+ (history->hptr)++;
+ if (history->hptr >= MAXSAMPLES)
+ history->hptr = 0;
+}
+
static int lpm_cpuidle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int idx)
{
@@ -1043,12 +1282,13 @@ exit:
cluster_unprepare(cluster, cpumask, idx, true, end_time);
cpu_unprepare(cluster, idx, true);
sched_set_cpu_cstate(smp_processor_id(), 0, 0, 0);
-
- trace_cpu_idle_exit(idx, success);
end_time = ktime_to_ns(ktime_get()) - start_time;
- dev->last_residency = do_div(end_time, 1000);
+ do_div(end_time, 1000);
+ dev->last_residency = end_time;
+ update_history(dev, idx);
+ trace_cpu_idle_exit(idx, success);
local_irq_enable();
-
+ histtimer_cancel();
return idx;
}
@@ -1320,6 +1560,7 @@ static int lpm_probe(struct platform_device *pdev)
*/
suspend_set_ops(&lpm_suspend_ops);
hrtimer_init(&lpm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&histtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ret = remote_spin_lock_init(&scm_handoff_lock, SCM_HANDOFF_LOCK_ID);
if (ret) {
diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h
index 8e05336be21a..63fe0a0fbc08 100644
--- a/drivers/cpuidle/lpm-levels.h
+++ b/drivers/cpuidle/lpm-levels.h
@@ -27,6 +27,9 @@ struct power_params {
uint32_t ss_power; /* Steady state power */
uint32_t energy_overhead; /* Enter + exit over head */
uint32_t time_overhead_us; /* Enter + exit overhead */
+ uint32_t residencies[NR_LPM_LEVELS];
+ uint32_t min_residency;
+ uint32_t max_residency;
};
struct lpm_cpu_level {
@@ -55,6 +58,9 @@ struct lpm_level_avail {
struct kobject *kobj;
struct kobj_attribute idle_enabled_attr;
struct kobj_attribute suspend_enabled_attr;
+ void *data;
+ int idx;
+ bool cpu_node;
};
struct lpm_cluster_level {
@@ -119,7 +125,8 @@ bool lpm_cpu_mode_allow(unsigned int cpu,
unsigned int mode, bool from_idle);
bool lpm_cluster_mode_allow(struct lpm_cluster *cluster,
unsigned int mode, bool from_idle);
-
+uint32_t *get_per_cpu_max_residency(int cpu);
+uint32_t *get_per_cpu_min_residency(int cpu);
extern struct lpm_cluster *lpm_root_node;
#ifdef CONFIG_SMP
diff --git a/drivers/gpu/msm/a5xx_reg.h b/drivers/gpu/msm/a5xx_reg.h
index 3b29452ce8bd..f3b4e6622043 100644
--- a/drivers/gpu/msm/a5xx_reg.h
+++ b/drivers/gpu/msm/a5xx_reg.h
@@ -640,6 +640,7 @@
/* UCHE registers */
#define A5XX_UCHE_ADDR_MODE_CNTL 0xE80
+#define A5XX_UCHE_MODE_CNTL 0xE81
#define A5XX_UCHE_WRITE_THRU_BASE_LO 0xE87
#define A5XX_UCHE_WRITE_THRU_BASE_HI 0xE88
#define A5XX_UCHE_TRAP_BASE_LO 0xE89
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index a3b25b3d8dd1..3615be45b6d9 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -244,6 +244,28 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
.core = 5,
.major = 4,
.minor = 0,
+ .patchid = 0,
+ .features = ADRENO_PREEMPTION | ADRENO_64BIT |
+ ADRENO_CONTENT_PROTECTION |
+ ADRENO_GPMU | ADRENO_SPTP_PC,
+ .pm4fw_name = "a530_pm4.fw",
+ .pfpfw_name = "a530_pfp.fw",
+ .zap_name = "a540_zap",
+ .gpudev = &adreno_a5xx_gpudev,
+ .gmem_size = SZ_1M,
+ .num_protected_regs = 0x20,
+ .busy_mask = 0xFFFFFFFE,
+ .gpmufw_name = "a540_gpmu.fw2",
+ .gpmu_major = 3,
+ .gpmu_minor = 0,
+ .gpmu_tsens = 0x000C000D,
+ .max_power = 5448,
+ },
+ {
+ .gpurev = ADRENO_REV_A540,
+ .core = 5,
+ .major = 4,
+ .minor = 0,
.patchid = ANY_ID,
.features = ADRENO_PREEMPTION | ADRENO_64BIT |
ADRENO_CONTENT_PROTECTION |
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 498386903936..1356835d0e93 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2799,6 +2799,18 @@ static void adreno_regulator_disable_poll(struct kgsl_device *device)
adreno_iommu_sync(device, false);
}
+static void adreno_gpu_model(struct kgsl_device *device, char *str,
+ size_t bufsz)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ snprintf(str, bufsz, "Adreno%d%d%dv%d",
+ ADRENO_CHIPID_CORE(adreno_dev->chipid),
+ ADRENO_CHIPID_MAJOR(adreno_dev->chipid),
+ ADRENO_CHIPID_MINOR(adreno_dev->chipid),
+ ADRENO_CHIPID_PATCH(adreno_dev->chipid) + 1);
+}
+
static const struct kgsl_functable adreno_functable = {
/* Mandatory functions */
.regread = adreno_regread,
@@ -2835,7 +2847,8 @@ static const struct kgsl_functable adreno_functable = {
.regulator_disable = adreno_regulator_disable,
.pwrlevel_change_settings = adreno_pwrlevel_change_settings,
.regulator_disable_poll = adreno_regulator_disable_poll,
- .clk_set_options = adreno_clk_set_options
+ .clk_set_options = adreno_clk_set_options,
+ .gpu_model = adreno_gpu_model,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 286f7d63c8fe..d4858f3f818e 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -1015,6 +1015,12 @@ static inline int adreno_is_a540v1(struct adreno_device *adreno_dev)
(ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 0);
}
+static inline int adreno_is_a540v2(struct adreno_device *adreno_dev)
+{
+ return (ADRENO_GPUREV(adreno_dev) == ADRENO_REV_A540) &&
+ (ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 1);
+}
+
/*
* adreno_checkreg_off() - Checks the validity of a register enum
* @adreno_dev: Pointer to adreno device
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 1782d1d54946..d52981d10ff5 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -1875,6 +1875,11 @@ static void a5xx_start(struct adreno_device *adreno_dev)
*/
kgsl_regrmw(device, A5XX_RB_DBG_ECO_CNT, 0, (1 << 9));
}
+ /*
+ * Disable UCHE global filter as SP can invalidate/flush
+ * independently
+ */
+ kgsl_regwrite(device, A5XX_UCHE_MODE_CNTL, BIT(29));
/* Set the USE_RETENTION_FLOPS chicken bit */
kgsl_regwrite(device, A5XX_CP_CHICKEN_DBG, 0x02000000);
@@ -2147,9 +2152,11 @@ static int _me_init_ucode_workarounds(struct adreno_device *adreno_dev)
case ADRENO_REV_A540:
/*
* WFI after every direct-render 3D mode draw and
- * WFI after every 2D Mode 3 draw.
+ * WFI after every 2D Mode 3 draw. This is needed
+ * only on a540v1.
*/
- return 0x0000000A;
+ if (adreno_is_a540v1(adreno_dev))
+ return 0x0000000A;
default:
return 0x00000000; /* No ucode workarounds enabled */
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index fb95f6108fb8..d9ebe37d0cf0 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -499,13 +499,20 @@ void adreno_drawctxt_detach(struct kgsl_context *context)
/*
* If the wait for global fails due to timeout then nothing after this
- * point is likely to work very well - BUG_ON() so we can take advantage
- * of the debug tools to figure out what the h - e - double hockey
- * sticks happened. If EAGAIN error is returned then recovery will kick
- * in and there will be no more commands in the RB pipe from this
- * context which is waht we are waiting for, so ignore -EAGAIN error
+ * point is likely to work very well - Get GPU snapshot and BUG_ON()
+ * so we can take advantage of the debug tools to figure out what the
+ * h - e - double hockey sticks happened. If EAGAIN error is returned
+ * then recovery will kick in and there will be no more commands in the
+ * RB pipe from this context which is waht we are waiting for, so ignore
+ * -EAGAIN error
*/
- BUG_ON(ret && ret != -EAGAIN);
+ if (ret && ret != -EAGAIN) {
+ KGSL_DRV_ERR(device, "Wait for global ts=%d type=%d error=%d\n",
+ drawctxt->internal_timestamp,
+ drawctxt->type, ret);
+ device->force_panic = 1;
+ kgsl_device_snapshot(device, context);
+ }
kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context->id, soptimestamp),
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 25f5de6ce645..7ac84b777051 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -579,4 +579,19 @@ static inline void __user *to_user_ptr(uint64_t address)
return (void __user *)(uintptr_t)address;
}
+static inline void kgsl_gpu_sysfs_add_link(struct kobject *dst,
+ struct kobject *src, const char *src_name,
+ const char *dst_name)
+{
+ struct kernfs_node *old;
+
+ if (dst == NULL || src == NULL)
+ return;
+
+ old = sysfs_get_dirent(src->sd, src_name);
+ if (IS_ERR_OR_NULL(old))
+ return;
+
+ kernfs_create_link(dst->sd, dst_name, old);
+}
#endif /* __KGSL_H */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 0df6dd8628a5..24511a4de6f1 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -167,6 +167,8 @@ struct kgsl_functable {
void (*regulator_disable_poll)(struct kgsl_device *device);
void (*clk_set_options)(struct kgsl_device *device,
const char *name, struct clk *clk);
+ void (*gpu_model)(struct kgsl_device *device, char *str,
+ size_t bufsz);
};
struct kgsl_ioctl {
@@ -261,6 +263,7 @@ struct kgsl_device {
struct kgsl_snapshot *snapshot;
u32 snapshot_faultcount; /* Total number of faults since boot */
+ bool force_panic; /* Force panic after snapshot dump */
struct kobject snapshot_kobj;
struct kobject ppd_kobj;
@@ -281,6 +284,7 @@ struct kgsl_device {
/* Number of active contexts seen globally for this device */
int active_context_count;
+ struct kobject *gpu_sysfs_kobj;
};
#define KGSL_MMU_DEVICE(_mmu) \
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 0fcc0c3b0d49..d71c6a63f2d3 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -21,6 +21,7 @@
#include <linux/delay.h>
#include <linux/msm_adreno_devfreq.h>
#include <linux/of_device.h>
+#include <linux/thermal.h>
#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -590,22 +591,10 @@ static ssize_t kgsl_pwrctrl_max_pwrlevel_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", pwr->max_pwrlevel);
}
-static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{ struct kgsl_device *device = kgsl_device_from_dev(dev);
- struct kgsl_pwrctrl *pwr;
- int ret;
- unsigned int level = 0;
-
- if (device == NULL)
- return 0;
-
- pwr = &device->pwrctrl;
-
- ret = kgsl_sysfs_store(buf, &level);
- if (ret)
- return ret;
+static void kgsl_pwrctrl_min_pwrlevel_set(struct kgsl_device *device,
+ int level)
+{
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
mutex_lock(&device->mutex);
if (level > pwr->num_pwrlevels - 2)
@@ -621,6 +610,24 @@ static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev,
kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel);
mutex_unlock(&device->mutex);
+}
+
+static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ int ret;
+ unsigned int level = 0;
+
+ if (device == NULL)
+ return 0;
+
+ ret = kgsl_sysfs_store(buf, &level);
+ if (ret)
+ return ret;
+
+ kgsl_pwrctrl_min_pwrlevel_set(device, level);
return count;
}
@@ -664,24 +671,13 @@ static int _get_nearest_pwrlevel(struct kgsl_pwrctrl *pwr, unsigned int clock)
return -ERANGE;
}
-static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static void kgsl_pwrctrl_max_clock_set(struct kgsl_device *device, int val)
{
- struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- unsigned int val = 0;
- int level, ret;
-
- if (device == NULL)
- return 0;
+ int level;
pwr = &device->pwrctrl;
- ret = kgsl_sysfs_store(buf, &val);
- if (ret)
- return ret;
-
mutex_lock(&device->mutex);
level = _get_nearest_pwrlevel(pwr, val);
/* If the requested power level is not supported by hw, try cycling */
@@ -715,21 +711,37 @@ static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
if (pwr->sysfs_pwr_limit)
kgsl_pwr_limits_set_freq(pwr->sysfs_pwr_limit,
pwr->pwrlevels[level].gpu_freq);
- return count;
+ return;
err:
mutex_unlock(&device->mutex);
- return count;
}
-static ssize_t kgsl_pwrctrl_max_gpuclk_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
-
struct kgsl_device *device = kgsl_device_from_dev(dev);
+ unsigned int val = 0;
+ int ret;
+
+ if (device == NULL)
+ return 0;
+
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
+
+ kgsl_pwrctrl_max_clock_set(device, val);
+
+ return count;
+}
+
+static unsigned int kgsl_pwrctrl_max_clock_get(struct kgsl_device *device)
+{
struct kgsl_pwrctrl *pwr;
unsigned int freq;
+
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
@@ -743,7 +755,17 @@ static ssize_t kgsl_pwrctrl_max_gpuclk_show(struct device *dev,
(TH_HZ - pwr->thermal_timeout) * (hfreq / TH_HZ);
}
- return snprintf(buf, PAGE_SIZE, "%d\n", freq);
+ return freq;
+}
+
+static ssize_t kgsl_pwrctrl_max_gpuclk_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ kgsl_pwrctrl_max_clock_get(device));
}
static ssize_t kgsl_pwrctrl_gpuclk_store(struct device *dev,
@@ -903,9 +925,14 @@ static ssize_t kgsl_pwrctrl_gpu_available_frequencies_show(
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- for (index = 0; index < pwr->num_pwrlevels - 1; index++)
- num_chars += snprintf(buf + num_chars, PAGE_SIZE, "%d ",
- pwr->pwrlevels[index].gpu_freq);
+ for (index = 0; index < pwr->num_pwrlevels - 1; index++) {
+ num_chars += scnprintf(buf + num_chars,
+ PAGE_SIZE - num_chars - 1,
+ "%d ", pwr->pwrlevels[index].gpu_freq);
+ /* One space for trailing null and another for the newline */
+ if (num_chars >= PAGE_SIZE - 2)
+ break;
+ }
buf[num_chars++] = '\n';
return num_chars;
}
@@ -1171,6 +1198,195 @@ static ssize_t kgsl_popp_show(struct device *dev,
test_bit(POPP_ON, &device->pwrscale.popp_state));
}
+static ssize_t kgsl_pwrctrl_gpu_model_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ char model_str[32] = {0};
+
+ if (device == NULL)
+ return 0;
+
+ device->ftbl->gpu_model(device, model_str, sizeof(model_str));
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", model_str);
+}
+
+static ssize_t kgsl_pwrctrl_gpu_busy_percentage_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_clk_stats *stats;
+ unsigned int busy_percent = 0;
+
+ if (device == NULL)
+ return 0;
+ stats = &device->pwrctrl.clk_stats;
+
+ if (stats->total_old != 0)
+ busy_percent = (stats->busy_old * 100) / stats->total_old;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d %%\n", busy_percent);
+
+ /* Reset the stats if GPU is OFF */
+ if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
+ stats->busy_old = 0;
+ stats->total_old = 0;
+ }
+ return ret;
+}
+
+static ssize_t kgsl_pwrctrl_min_clock_mhz_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ pwr->pwrlevels[pwr->min_pwrlevel].gpu_freq / 1000000);
+}
+
+static ssize_t kgsl_pwrctrl_min_clock_mhz_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ int level, ret;
+ unsigned int freq;
+ struct kgsl_pwrctrl *pwr;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = kgsl_sysfs_store(buf, &freq);
+ if (ret)
+ return ret;
+
+ freq *= 1000000;
+ level = _get_nearest_pwrlevel(pwr, freq);
+
+ if (level >= 0)
+ kgsl_pwrctrl_min_pwrlevel_set(device, level);
+
+ return count;
+}
+
+static ssize_t kgsl_pwrctrl_max_clock_mhz_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ unsigned int freq;
+
+ if (device == NULL)
+ return 0;
+
+ freq = kgsl_pwrctrl_max_clock_get(device);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", freq / 1000000);
+}
+
+static ssize_t kgsl_pwrctrl_max_clock_mhz_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ unsigned int val = 0;
+ int ret;
+
+ if (device == NULL)
+ return 0;
+
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
+
+ val *= 1000000;
+ kgsl_pwrctrl_max_clock_set(device, val);
+
+ return count;
+}
+
+static ssize_t kgsl_pwrctrl_clock_mhz_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+
+ if (device == NULL)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n",
+ kgsl_pwrctrl_active_freq(&device->pwrctrl) / 1000000);
+}
+
+static ssize_t kgsl_pwrctrl_freq_table_mhz_show(
+ struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ int index, num_chars = 0;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+ for (index = 0; index < pwr->num_pwrlevels - 1; index++) {
+ num_chars += scnprintf(buf + num_chars,
+ PAGE_SIZE - num_chars - 1,
+ "%d ", pwr->pwrlevels[index].gpu_freq / 1000000);
+ /* One space for trailing null and another for the newline */
+ if (num_chars >= PAGE_SIZE - 2)
+ break;
+ }
+
+ buf[num_chars++] = '\n';
+
+ return num_chars;
+}
+
+static ssize_t kgsl_pwrctrl_temp_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ int ret, id = 0, temperature = 0;
+
+ if (device == NULL)
+ goto done;
+
+ pwr = &device->pwrctrl;
+
+ if (!pwr->tsens_name)
+ goto done;
+
+ id = sensor_get_id((char *)pwr->tsens_name);
+ if (id < 0)
+ goto done;
+
+ ret = sensor_get_temp(id, &temperature);
+ if (ret)
+ goto done;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ temperature);
+done:
+ return 0;
+}
+
static DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show,
kgsl_pwrctrl_gpuclk_store);
static DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
@@ -1222,6 +1438,17 @@ static DEVICE_ATTR(popp, 0644, kgsl_popp_show, kgsl_popp_store);
static DEVICE_ATTR(force_no_nap, 0644,
kgsl_pwrctrl_force_no_nap_show,
kgsl_pwrctrl_force_no_nap_store);
+static DEVICE_ATTR(gpu_model, 0444, kgsl_pwrctrl_gpu_model_show, NULL);
+static DEVICE_ATTR(gpu_busy_percentage, 0444,
+ kgsl_pwrctrl_gpu_busy_percentage_show, NULL);
+static DEVICE_ATTR(min_clock_mhz, 0644, kgsl_pwrctrl_min_clock_mhz_show,
+ kgsl_pwrctrl_min_clock_mhz_store);
+static DEVICE_ATTR(max_clock_mhz, 0644, kgsl_pwrctrl_max_clock_mhz_show,
+ kgsl_pwrctrl_max_clock_mhz_store);
+static DEVICE_ATTR(clock_mhz, 0444, kgsl_pwrctrl_clock_mhz_show, NULL);
+static DEVICE_ATTR(freq_table_mhz, 0444,
+ kgsl_pwrctrl_freq_table_mhz_show, NULL);
+static DEVICE_ATTR(temp, 0444, kgsl_pwrctrl_temp_show, NULL);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -1243,12 +1470,50 @@ static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_bus_split,
&dev_attr_default_pwrlevel,
&dev_attr_popp,
+ &dev_attr_gpu_model,
+ &dev_attr_gpu_busy_percentage,
+ &dev_attr_min_clock_mhz,
+ &dev_attr_max_clock_mhz,
+ &dev_attr_clock_mhz,
+ &dev_attr_freq_table_mhz,
+ &dev_attr_temp,
NULL
};
+struct sysfs_link {
+ const char *src;
+ const char *dst;
+};
+
+static struct sysfs_link link_names[] = {
+ { "gpu_model", "gpu_model",},
+ { "gpu_busy_percentage", "gpu_busy",},
+ { "min_clock_mhz", "gpu_min_clock",},
+ { "max_clock_mhz", "gpu_max_clock",},
+ { "clock_mhz", "gpu_clock",},
+ { "freq_table_mhz", "gpu_freq_table",},
+ { "temp", "gpu_tmu",},
+};
+
int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device)
{
- return kgsl_create_device_sysfs_files(device->dev, pwrctrl_attr_list);
+ int i, ret;
+
+ ret = kgsl_create_device_sysfs_files(device->dev, pwrctrl_attr_list);
+ if (ret)
+ return ret;
+
+ device->gpu_sysfs_kobj = kobject_create_and_add("gpu", kernel_kobj);
+ if (IS_ERR_OR_NULL(device->gpu_sysfs_kobj))
+ return (device->gpu_sysfs_kobj == NULL) ?
+ -ENOMEM : PTR_ERR(device->gpu_sysfs_kobj);
+
+ for (i = 0; i < ARRAY_SIZE(link_names); i++)
+ kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj,
+ &device->dev->kobj, link_names[i].src,
+ link_names[i].dst);
+
+ return 0;
}
void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device)
@@ -1860,6 +2125,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
kgsl_pwrctrl_vbif_init();
+ /* temperature sensor name */
+ of_property_read_string(pdev->dev.of_node, "qcom,tsens-name",
+ &pwr->tsens_name);
+
return result;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index ae21a274fada..2de42d87bcbe 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -152,6 +152,7 @@ struct kgsl_regulator {
* @sysfs_pwr_limit - pointer to the sysfs limits node
* isense_clk_indx - index of isense clock, 0 if no isense
* isense_clk_on_level - isense clock rate is XO rate below this level.
+ * tsens_name - pointer to temperature sensor name of GPU temperature sensor
*/
struct kgsl_pwrctrl {
@@ -204,6 +205,7 @@ struct kgsl_pwrctrl {
struct kgsl_pwr_limit *sysfs_pwr_limit;
unsigned int gpu_bimc_int_clk_freq;
bool gpu_bimc_interface_enabled;
+ const char *tsens_name;
};
int kgsl_pwrctrl_init(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index d90aec42f30a..01d3b74c16fd 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -910,6 +910,14 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
pwrscale->history[i].type = i;
}
+ /* Add links to the devfreq sysfs nodes */
+ kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj,
+ &pwrscale->devfreqptr->dev.kobj, "governor",
+ "gpu_governor");
+ kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj,
+ &pwrscale->devfreqptr->dev.kobj,
+ "available_governors", "gpu_available_governor");
+
return 0;
}
EXPORT_SYMBOL(kgsl_pwrscale_init);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 2c9f17f9e7a4..a2e4a909062f 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -810,6 +810,29 @@ static ssize_t faultcount_store(struct kgsl_device *device, const char *buf,
return count;
}
+/* Show the force_panic request status */
+static ssize_t force_panic_show(struct kgsl_device *device, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", device->force_panic);
+}
+
+/* Store the panic request value to force_panic */
+static ssize_t force_panic_store(struct kgsl_device *device, const char *buf,
+ size_t count)
+{
+ unsigned int val = 0;
+ int ret;
+
+ if (device && count > 0)
+ device->force_panic = 0;
+
+ ret = kgsl_sysfs_store(buf, &val);
+
+ if (!ret && device)
+ device->force_panic = (bool)val;
+
+ return (ssize_t) ret < 0 ? ret : count;
+}
/* Show the timestamp of the last collected snapshot */
static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
{
@@ -835,6 +858,7 @@ struct kgsl_snapshot_attribute attr_##_name = { \
static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
+static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store);
static ssize_t snapshot_sysfs_show(struct kobject *kobj,
struct attribute *attr, char *buf)
@@ -914,6 +938,7 @@ int kgsl_device_snapshot_init(struct kgsl_device *device)
device->snapshot = NULL;
device->snapshot_faultcount = 0;
+ device->force_panic = 0;
ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
&device->dev->kobj, "snapshot");
@@ -929,7 +954,11 @@ int kgsl_device_snapshot_init(struct kgsl_device *device)
goto done;
ret = sysfs_create_file(&device->snapshot_kobj, &attr_faultcount.attr);
+ if (ret)
+ goto done;
+ ret = sysfs_create_file(&device->snapshot_kobj,
+ &attr_force_panic.attr);
done:
return ret;
}
@@ -954,6 +983,7 @@ void kgsl_device_snapshot_close(struct kgsl_device *device)
device->snapshot_memory.ptr = NULL;
device->snapshot_memory.size = 0;
device->snapshot_faultcount = 0;
+ device->force_panic = 0;
}
EXPORT_SYMBOL(kgsl_device_snapshot_close);
@@ -1032,6 +1062,7 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work)
{
struct kgsl_snapshot *snapshot = container_of(work,
struct kgsl_snapshot, work);
+ struct kgsl_device *device = kgsl_get_device(KGSL_DEVICE_3D0);
struct kgsl_snapshot_object *obj, *tmp;
size_t size = 0;
void *ptr;
@@ -1073,12 +1104,15 @@ done:
snapshot->process = NULL;
if (snapshot->ib1base && !snapshot->ib1dumped)
- pr_warn("kgsl: snapshot: Active IB1:%016llx not dumped\n",
+ KGSL_DRV_ERR(device,
+ "snapshot: Active IB1:%016llx not dumped\n",
snapshot->ib1base);
else if (snapshot->ib2base && !snapshot->ib2dumped)
- pr_warn("kgsl: snapshot: Active IB2:%016llx not dumped\n",
+ KGSL_DRV_ERR(device,
+ "snapshot: Active IB2:%016llx not dumped\n",
snapshot->ib2base);
complete_all(&snapshot->dump_gate);
+ BUG_ON(device->force_panic);
return;
}
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index a892b73a4288..4036997f49c7 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -935,9 +935,14 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
return NULL;
/* TCR */
- reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) |
- (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) |
- (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_ORGN0_SHIFT);
+ if (cfg->iommu_dev && cfg->iommu_dev->archdata.dma_coherent)
+ reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
+ else
+ reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_ORGN0_SHIFT);
switch (1 << data->pg_shift) {
case SZ_4K:
diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c
index 334f4e95c068..0a8728ce36dc 100644
--- a/drivers/iommu/msm_dma_iommu_mapping.c
+++ b/drivers/iommu/msm_dma_iommu_mapping.c
@@ -376,6 +376,7 @@ int msm_dma_unmap_all_for_dev(struct device *dev)
return ret;
}
+EXPORT_SYMBOL(msm_dma_unmap_all_for_dev);
/*
* Only to be called by ION code when a buffer is freed
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 4a32de1a85bf..7488f371545b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1104,7 +1104,6 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
uint32_t io_format = 0;
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg;
struct msm_vfe_axi_stream *stream_info;
- unsigned long flags;
if (stream_cfg_cmd->stream_src >= VFE_AXI_SRC_MAX) {
pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__,
@@ -1114,12 +1113,9 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
stream_info = msm_isp_get_stream_common_data(vfe_dev,
stream_cfg_cmd->stream_src);
- spin_lock_irqsave(&stream_info->lock, flags);
-
rc = msm_isp_axi_create_stream(vfe_dev,
&vfe_dev->axi_data, stream_cfg_cmd, stream_info);
if (rc) {
- spin_unlock_irqrestore(&stream_info->lock, flags);
pr_err("%s: create stream failed\n", __func__);
return rc;
}
@@ -1128,7 +1124,6 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
vfe_dev, stream_info, stream_cfg_cmd);
if (rc) {
msm_isp_axi_destroy_stream(vfe_dev, stream_info);
- spin_unlock_irqrestore(&stream_info->lock, flags);
pr_err("%s: Request validation failed\n", __func__);
return rc;
}
@@ -1236,7 +1231,6 @@ done:
msm_isp_axi_free_wm(vfe_dev, stream_info);
msm_isp_axi_destroy_stream(vfe_dev, stream_info);
}
- spin_unlock_irqrestore(&stream_info->lock, flags);
return rc;
}
@@ -1247,7 +1241,6 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_stream_cfg_cmd stream_cfg;
int vfe_idx;
- unsigned long flags;
if (HANDLE_TO_IDX(stream_release_cmd->stream_handle) >=
VFE_AXI_SRC_MAX) {
@@ -1257,13 +1250,10 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
stream_info = msm_isp_get_stream_common_data(vfe_dev,
HANDLE_TO_IDX(stream_release_cmd->stream_handle));
- spin_lock_irqsave(&stream_info->lock, flags);
-
vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev, stream_info);
if (vfe_idx == -ENOTTY ||
stream_release_cmd->stream_handle !=
stream_info->stream_handle[vfe_idx]) {
- spin_unlock_irqrestore(&stream_info->lock, flags);
pr_err("%s: Invalid stream %p handle %x/%x vfe_idx %d vfe_dev %d num_isp %d\n",
__func__, stream_info,
stream_release_cmd->stream_handle,
@@ -1277,9 +1267,7 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
stream_cfg.cmd = STOP_STREAM;
stream_cfg.num_streams = 1;
stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle;
- spin_unlock_irqrestore(&stream_info->lock, flags);
msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg);
- spin_lock_irqsave(&stream_info->lock, flags);
}
for (i = 0; i < stream_info->num_planes; i++) {
@@ -1297,7 +1285,6 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
msm_isp_axi_free_wm(vfe_dev, stream_info);
msm_isp_axi_destroy_stream(vfe_dev, stream_info);
- spin_unlock_irqrestore(&stream_info->lock, flags);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 923cd9aa5954..e226f7e40a07 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -460,7 +460,6 @@ int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg;
struct msm_vfe_stats_stream *stream_info = NULL;
uint32_t stats_idx;
- unsigned long flags;
stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
get_stats_idx(stream_req_cmd->stats_type);
@@ -472,11 +471,8 @@ int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx);
- spin_lock_irqsave(&stream_info->lock, flags);
-
rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd, stream_info);
if (rc < 0) {
- spin_unlock_irqrestore(&stream_info->lock, flags);
pr_err("%s: create stream failed\n", __func__);
return rc;
}
@@ -491,7 +487,6 @@ int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
msm_isp_stats_cfg_stream_scratch(stream_info,
VFE_PONG_FLAG);
}
- spin_unlock_irqrestore(&stream_info->lock, flags);
return rc;
}
@@ -505,7 +500,6 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
int vfe_idx;
int i;
int k;
- unsigned long flags;
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
@@ -513,12 +507,10 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
}
stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx);
- spin_lock_irqsave(&stream_info->lock, flags);
vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(
vfe_dev, stream_info);
if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] !=
stream_release_cmd->stream_handle) {
- spin_unlock_irqrestore(&stream_info->lock, flags);
pr_err("%s: Invalid stream handle %x, expected %x\n",
__func__, stream_release_cmd->stream_handle,
vfe_idx != -ENOTTY ?
@@ -526,7 +518,6 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
return -EINVAL;
}
if (stream_info->state == STATS_AVAILABLE) {
- spin_unlock_irqrestore(&stream_info->lock, flags);
pr_err("%s: stream already release\n", __func__);
return rc;
}
@@ -537,9 +528,7 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
stream_cfg_cmd.num_streams = 1;
stream_cfg_cmd.stream_handle[0] =
stream_release_cmd->stream_handle;
- spin_unlock_irqrestore(&stream_info->lock, flags);
msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd);
- spin_lock_irqsave(&stream_info->lock, flags);
}
for (i = vfe_idx, k = vfe_idx + 1; k < stream_info->num_isp; k++, i++) {
@@ -556,7 +545,6 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
if (stream_info->num_isp == 0)
stream_info->state = STATS_AVAILABLE;
- spin_unlock_irqrestore(&stream_info->lock, flags);
return 0;
}
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 8f911d362477..a4ee5041bfff 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
@@ -276,6 +276,12 @@ int32_t msm_camera_cci_i2c_write_seq_table(
client_addr_type = client->addr_type;
client->addr_type = write_setting->addr_type;
+ if (reg_setting->reg_data_size > I2C_SEQ_REG_DATA_MAX) {
+ pr_err("%s: number of bytes %u exceeding the max supported %d\n",
+ __func__, reg_setting->reg_data_size, I2C_SEQ_REG_DATA_MAX);
+ return rc;
+ }
+
for (i = 0; i < write_setting->size; i++) {
rc = msm_camera_cci_i2c_write_seq(client, reg_setting->reg_addr,
reg_setting->reg_data, reg_setting->reg_data_size);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
index 3b101798edac..7a0fb97061d5 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
@@ -290,6 +290,12 @@ int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client,
client_addr_type = client->addr_type;
client->addr_type = write_setting->addr_type;
+ if (reg_setting->reg_data_size > I2C_SEQ_REG_DATA_MAX) {
+ pr_err("%s: number of bytes %u exceeding the max supported %d\n",
+ __func__, reg_setting->reg_data_size, I2C_SEQ_REG_DATA_MAX);
+ return rc;
+ }
+
for (i = 0; i < write_setting->size; i++) {
rc = msm_camera_qup_i2c_write_seq(client, reg_setting->reg_addr,
reg_setting->reg_data, reg_setting->reg_data_size);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index 43aadffa2983..86e7837cc02a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -1167,6 +1167,7 @@ static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl)
if (!s_ctrl->msm_sensor_mutex) {
pr_err("failed: no memory msm_sensor_mutex %pK",
s_ctrl->msm_sensor_mutex);
+ rc = -ENOMEM;
goto FREE_SENSOR_I2C_CLIENT;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 930b18abd71b..b88f03ce89ae 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1123,6 +1123,13 @@ static int sde_rotator_try_fmt_vid_cap(struct file *file,
struct sde_rotation_config config;
int ret;
+ if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0)) {
+ SDEDEV_WARN(ctx->rot_dev->dev,
+ "Not supporting 0 width/height: %dx%d\n",
+ f->fmt.pix.width, f->fmt.pix.height);
+ return -EINVAL;
+ }
+
sde_rot_mgr_lock(rot_dev->mgr);
sde_rotator_get_config_from_ctx(ctx, &config);
config.output.format = f->fmt.pix.pixelformat;
@@ -1162,6 +1169,13 @@ static int sde_rotator_try_fmt_vid_out(struct file *file,
struct sde_rotation_config config;
int ret;
+ if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0)) {
+ SDEDEV_WARN(ctx->rot_dev->dev,
+ "Not supporting 0 width/height: %dx%d\n",
+ f->fmt.pix.width, f->fmt.pix.height);
+ return -EINVAL;
+ }
+
sde_rot_mgr_lock(rot_dev->mgr);
sde_rotator_get_config_from_ctx(ctx, &config);
config.input.format = f->fmt.pix.pixelformat;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
index eed177ea5bab..60c4c81eddf2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
@@ -355,13 +355,6 @@ int sde_mdp_get_plane_sizes(struct sde_mdp_format_params *fmt, u32 w, u32 h,
chroma_samp = fmt->chroma_sample;
- if (rotation) {
- if (chroma_samp == SDE_MDP_CHROMA_H2V1)
- chroma_samp = SDE_MDP_CHROMA_H1V2;
- else if (chroma_samp == SDE_MDP_CHROMA_H1V2)
- chroma_samp = SDE_MDP_CHROMA_H2V1;
- }
-
sde_mdp_get_v_h_subsample_rate(chroma_samp,
&v_subsample, &h_subsample);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index fdf6e1b1c5d0..becea0c59521 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -626,6 +626,11 @@ static u32 get_frame_size_compressed(int plane,
return (max_mbs_per_frame * size_per_mb * 3/2)/2;
}
+static u32 get_frame_size_nv12_ubwc_10bit(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
+}
+
static u32 get_frame_size(struct msm_vidc_inst *inst,
const struct msm_vidc_format *fmt,
int fmt_type, int plane)
@@ -662,7 +667,7 @@ static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
int rc = 0;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
- if (inst->fmts[OUTPUT_PORT]->fourcc != V4L2_PIX_FMT_H264_MVC) {
+ if (inst->fmts[OUTPUT_PORT].fourcc != V4L2_PIX_FMT_H264_MVC) {
dprintk(VIDC_ERR, "Control %#x only valid for MVC\n",
ctrl->id);
rc = -ENOTSUPP;
@@ -670,7 +675,7 @@ static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
}
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- if (inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_H264_MVC &&
+ if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) {
dprintk(VIDC_ERR,
"Profile %#x not supported for MVC\n",
@@ -680,7 +685,7 @@ static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
}
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- if (inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_H264_MVC &&
+ if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) {
dprintk(VIDC_ERR, "Level %#x not supported for MVC\n",
ctrl->val);
@@ -712,6 +717,14 @@ struct msm_vidc_format vdec_formats[] = {
.type = CAPTURE_PORT,
},
{
+ .name = "UBWC YCbCr Semiplanar 4:2:0 10bit",
+ .description = "UBWC Y/CbCr 4:2:0 10bit",
+ .fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
+ .num_planes = 2,
+ .get_frame_size = get_frame_size_nv12_ubwc_10bit,
+ .type = CAPTURE_PORT,
+ },
+ {
.name = "Mpeg4",
.description = "Mpeg4 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG4,
@@ -883,10 +896,10 @@ int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, allocated: %d\n",
- inst->fmts[CAPTURE_PORT]->num_planes,
+ inst->fmts[CAPTURE_PORT].num_planes,
b->length);
rc = -EINVAL;
break;
@@ -962,10 +975,10 @@ int msm_vdec_release_buf(struct msm_vidc_inst *inst,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, to release: %d\n",
- inst->fmts[CAPTURE_PORT]->num_planes, b->length);
+ inst->fmts[CAPTURE_PORT].num_planes, b->length);
rc = -EINVAL;
break;
}
@@ -1086,9 +1099,9 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
hdev = inst->core->device;
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- fmt = inst->fmts[CAPTURE_PORT];
+ fmt = &inst->fmts[CAPTURE_PORT];
else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- fmt = inst->fmts[OUTPUT_PORT];
+ fmt = &inst->fmts[OUTPUT_PORT];
else
return -ENOTSUPP;
@@ -1237,6 +1250,8 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
rc = -EINVAL;
goto err_invalid_fmt;
}
+ memcpy(&inst->fmts[fmt->type], fmt,
+ sizeof(struct msm_vidc_format));
inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
@@ -1244,7 +1259,6 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
msm_comm_get_hal_output_buffer(inst),
f->fmt.pix_mp.pixelformat);
- inst->fmts[fmt->type] = fmt;
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
@@ -1259,10 +1273,10 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
}
f->fmt.pix_mp.plane_fmt[0].sizeimage =
- fmt->get_frame_size(0,
+ inst->fmts[fmt->type].get_frame_size(0,
f->fmt.pix_mp.height, f->fmt.pix_mp.width);
- extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
VENUS_EXTRADATA_SIZE(
@@ -1270,8 +1284,8 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
inst->prop.width[CAPTURE_PORT]);
}
- f->fmt.pix_mp.num_planes = fmt->num_planes;
- for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
+ for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
@@ -1290,6 +1304,8 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
rc = -EINVAL;
goto err_invalid_fmt;
}
+ memcpy(&inst->fmts[fmt->type], fmt,
+ sizeof(struct msm_vidc_format));
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
if (rc) {
@@ -1297,17 +1313,16 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
goto err_invalid_fmt;
}
- if (!(get_hal_codec(fmt->fourcc) &
+ if (!(get_hal_codec(inst->fmts[fmt->type].fourcc) &
inst->core->dec_codec_supported)) {
dprintk(VIDC_ERR,
"Codec(%#x) is not present in the supported codecs list(%#x)\n",
- get_hal_codec(fmt->fourcc),
+ get_hal_codec(inst->fmts[fmt->type].fourcc),
inst->core->dec_codec_supported);
rc = -EINVAL;
goto err_invalid_fmt;
}
- inst->fmts[fmt->type] = fmt;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to open instance\n");
@@ -1330,14 +1345,15 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
frame_sz.height);
msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
- max_input_size = get_frame_size(inst, fmt, f->type, 0);
+ max_input_size = get_frame_size(
+inst, &inst->fmts[fmt->type], f->type, 0);
if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
!f->fmt.pix_mp.plane_fmt[0].sizeimage) {
f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
}
- f->fmt.pix_mp.num_planes = fmt->num_planes;
- for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
+ for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
@@ -1451,20 +1467,20 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- *num_planes = inst->fmts[OUTPUT_PORT]->num_planes;
+ *num_planes = inst->fmts[OUTPUT_PORT].num_planes;
if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
for (i = 0; i < *num_planes; i++) {
sizes[i] = get_frame_size(inst,
- inst->fmts[OUTPUT_PORT], q->type, i);
+ &inst->fmts[OUTPUT_PORT], q->type, i);
}
rc = set_actual_buffer_count(inst, *num_buffers,
HAL_BUFFER_INPUT);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
- *num_planes = inst->fmts[CAPTURE_PORT]->num_planes;
+ *num_planes = inst->fmts[CAPTURE_PORT].num_planes;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to open instance\n");
@@ -1549,7 +1565,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
}
extra_idx =
- EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
sizes[extra_idx] =
VENUS_EXTRADATA_SIZE(
@@ -1650,7 +1666,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
unsigned int buffer_size;
struct msm_vidc_format *fmt = NULL;
- fmt = inst->fmts[CAPTURE_PORT];
+ fmt = &inst->fmts[CAPTURE_PORT];
buffer_size = fmt->get_frame_size(0,
inst->prop.height[CAPTURE_PORT],
inst->prop.width[CAPTURE_PORT]);
@@ -1872,8 +1888,6 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "Invalid input = %pK\n", inst);
return -EINVAL;
}
- inst->fmts[OUTPUT_PORT] = &vdec_formats[2];
- inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
@@ -1889,6 +1903,10 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst)
inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = DEFAULT_FPS;
+ memcpy(&inst->fmts[OUTPUT_PORT], &vdec_formats[2],
+ sizeof(struct msm_vidc_format));
+ memcpy(&inst->fmts[CAPTURE_PORT], &vdec_formats[0],
+ sizeof(struct msm_vidc_format));
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 99f30d9cb97b..9c855e89e3ff 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1485,7 +1485,7 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
default:
break;
}
- inst->fmts[CAPTURE_PORT]->num_planes = *num_planes;
+ inst->fmts[CAPTURE_PORT].num_planes = *num_planes;
for (i = 0; i < *num_planes; i++) {
int extra_idx = EXTRADATA_IDX(*num_planes);
@@ -1560,7 +1560,7 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
break;
}
- inst->fmts[OUTPUT_PORT]->num_planes = *num_planes;
+ inst->fmts[OUTPUT_PORT].num_planes = *num_planes;
rc = call_hfi_op(hdev, session_set_property, inst->session,
property_id, &new_buf_count);
if (rc)
@@ -1570,12 +1570,12 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
inst->buff_req.buffer[0].buffer_size,
inst->buff_req.buffer[0].buffer_alignment,
inst->buff_req.buffer[0].buffer_count_actual);
- sizes[0] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ sizes[0] = inst->fmts[OUTPUT_PORT].get_frame_size(
0, inst->prop.height[OUTPUT_PORT],
inst->prop.width[OUTPUT_PORT]);
extra_idx =
- EXTRADATA_IDX(inst->fmts[OUTPUT_PORT]->num_planes);
+ EXTRADATA_IDX(inst->fmts[OUTPUT_PORT].num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
buff_req_buffer = get_buff_req_buffer(inst,
HAL_BUFFER_EXTRADATA_INPUT);
@@ -1610,7 +1610,7 @@ static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers)
return -EINVAL;
}
- if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_VP8)
+ if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_VP8)
return 0;
num_enh_layers = layers ? : 0;
@@ -2177,10 +2177,10 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
- if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264 &&
- inst->fmts[CAPTURE_PORT]->fourcc !=
+ if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_H264 &&
+ inst->fmts[CAPTURE_PORT].fourcc !=
V4L2_PIX_FMT_H264_NO_SC &&
- inst->fmts[CAPTURE_PORT]->fourcc !=
+ inst->fmts[CAPTURE_PORT].fourcc !=
V4L2_PIX_FMT_HEVC) {
dprintk(VIDC_ERR,
"Control %#x only valid for H264 and HEVC\n",
@@ -2669,8 +2669,8 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
bool codec_avc =
- inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_H264 ||
- inst->fmts[CAPTURE_PORT]->fourcc ==
+ inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264 ||
+ inst->fmts[CAPTURE_PORT].fourcc ==
V4L2_PIX_FMT_H264_NO_SC;
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
@@ -2696,8 +2696,8 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
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);
+ (inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264) ||
+ (inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_HEVC);
if (is_cont_intra_supported) {
if (ctrl->val != HAL_INTRA_REFRESH_NONE)
@@ -3054,7 +3054,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS:
- if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_HEVC) {
+ if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) {
dprintk(VIDC_ERR, "Hier B supported for HEVC only\n");
rc = -ENOTSUPP;
break;
@@ -3483,8 +3483,6 @@ int msm_venc_inst_init(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "Invalid input = %pK\n", inst);
return -EINVAL;
}
- inst->fmts[CAPTURE_PORT] = &venc_formats[4];
- inst->fmts[OUTPUT_PORT] = &venc_formats[0];
inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
@@ -3501,6 +3499,10 @@ int msm_venc_inst_init(struct msm_vidc_inst *inst)
inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = DEFAULT_FPS;
inst->capability.pixelprocess_capabilities = 0;
+ memcpy(&inst->fmts[CAPTURE_PORT], &venc_formats[4],
+ sizeof(struct msm_vidc_format));
+ memcpy(&inst->fmts[OUTPUT_PORT], &venc_formats[0],
+ sizeof(struct msm_vidc_format));
return rc;
}
@@ -3624,7 +3626,8 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
goto exit;
}
- inst->fmts[fmt->type] = fmt;
+ memcpy(&inst->fmts[fmt->type], fmt,
+ sizeof(struct msm_vidc_format));
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
@@ -3676,7 +3679,8 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
rc = -EINVAL;
goto exit;
}
- inst->fmts[fmt->type] = fmt;
+ memcpy(&inst->fmts[fmt->type], fmt,
+ sizeof(struct msm_vidc_format));
msm_comm_set_color_format(inst, HAL_BUFFER_INPUT, fmt->fourcc);
} else {
@@ -3686,7 +3690,7 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
goto exit;
}
- f->fmt.pix_mp.num_planes = fmt->num_planes;
+ f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
struct hal_frame_size frame_sz = {0};
@@ -3717,12 +3721,12 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
struct hal_buffer_requirements *bufreq = NULL;
int extra_idx = 0;
- for (i = 0; i < fmt->num_planes; ++i) {
+ for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
- fmt->get_frame_size(i,
+ inst->fmts[fmt->type].get_frame_size(i,
f->fmt.pix_mp.height, f->fmt.pix_mp.width);
}
- extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
bufreq = get_buff_req_buffer(inst,
HAL_BUFFER_EXTRADATA_INPUT);
@@ -3757,11 +3761,11 @@ int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- fmt = inst->fmts[CAPTURE_PORT];
+ fmt = &inst->fmts[CAPTURE_PORT];
height = inst->prop.height[CAPTURE_PORT];
width = inst->prop.width[CAPTURE_PORT];
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- fmt = inst->fmts[OUTPUT_PORT];
+ fmt = &inst->fmts[OUTPUT_PORT];
height = inst->prop.height[OUTPUT_PORT];
width = inst->prop.width[OUTPUT_PORT];
} else {
@@ -3864,10 +3868,10 @@ int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, allocated: %d\n",
- inst->fmts[CAPTURE_PORT]->num_planes,
+ inst->fmts[CAPTURE_PORT].num_planes,
b->length);
rc = -EINVAL;
break;
@@ -3935,10 +3939,10 @@ int msm_venc_release_buf(struct msm_vidc_inst *inst,
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
if (b->length !=
- inst->fmts[CAPTURE_PORT]->num_planes) {
+ inst->fmts[CAPTURE_PORT].num_planes) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, to release: %d\n",
- inst->fmts[CAPTURE_PORT]->num_planes,
+ inst->fmts[CAPTURE_PORT].num_planes,
b->length);
rc = -EINVAL;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 437ad43e23e9..b12eeddc678f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -682,7 +682,7 @@ static bool valid_v4l2_buffer(struct v4l2_buffer *b,
MAX_PORT_NUM;
return port != MAX_PORT_NUM &&
- inst->fmts[port]->num_planes == b->length;
+ inst->fmts[port].num_planes == b->length;
}
int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
@@ -849,7 +849,7 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
dprintk(VIDC_DBG, "Queueing device address = %pa\n",
&binfo->device_addr[i]);
- if (inst->fmts[OUTPUT_PORT]->fourcc ==
+ if (inst->fmts[OUTPUT_PORT].fourcc ==
V4L2_PIX_FMT_HEVC_HYBRID && binfo->handle[i] &&
b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
rc = msm_comm_smem_cache_operations(inst,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 40643239712f..d1cc08d53017 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -521,12 +521,12 @@ static int msm_comm_vote_bus(struct msm_vidc_core *core)
struct v4l2_control ctrl;
codec = inst->session_type == MSM_VIDC_DECODER ?
- inst->fmts[OUTPUT_PORT]->fourcc :
- inst->fmts[CAPTURE_PORT]->fourcc;
+ inst->fmts[OUTPUT_PORT].fourcc :
+ inst->fmts[CAPTURE_PORT].fourcc;
yuv = inst->session_type == MSM_VIDC_DECODER ?
- inst->fmts[CAPTURE_PORT]->fourcc :
- inst->fmts[OUTPUT_PORT]->fourcc;
+ inst->fmts[CAPTURE_PORT].fourcc :
+ inst->fmts[OUTPUT_PORT].fourcc;
vote_data[i].domain = get_hal_domain(inst->session_type);
vote_data[i].codec = get_hal_codec(codec);
@@ -1004,8 +1004,8 @@ static void handle_session_init_done(enum hal_command_response cmd, void *data)
core = inst->core;
hdev = inst->core->device;
codec = inst->session_type == MSM_VIDC_DECODER ?
- inst->fmts[OUTPUT_PORT]->fourcc :
- inst->fmts[CAPTURE_PORT]->fourcc;
+ inst->fmts[OUTPUT_PORT].fourcc :
+ inst->fmts[CAPTURE_PORT].fourcc;
/* check if capabilities are available for this session */
for (i = 0; i < VIDC_MAX_SESSIONS; i++) {
@@ -2028,7 +2028,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data)
ns_to_timeval(time_usec * NSEC_PER_USEC);
vbuf->flags = 0;
extra_idx =
- EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
vb->planes[extra_idx].m.userptr =
(unsigned long)fill_buf_done->extra_data_buffer;
@@ -2279,8 +2279,8 @@ int msm_comm_scale_clocks_load(struct msm_vidc_core *core,
list_for_each_entry(inst, &core->instances, list) {
codec = inst->session_type == MSM_VIDC_DECODER ?
- inst->fmts[OUTPUT_PORT]->fourcc :
- inst->fmts[CAPTURE_PORT]->fourcc;
+ inst->fmts[OUTPUT_PORT].fourcc :
+ inst->fmts[CAPTURE_PORT].fourcc;
if (msm_comm_turbo_session(inst))
clk_scale_data.power_mode[num_sessions] =
@@ -2711,9 +2711,9 @@ static int msm_comm_session_init(int flipped_state,
goto exit;
}
if (inst->session_type == MSM_VIDC_DECODER) {
- fourcc = inst->fmts[OUTPUT_PORT]->fourcc;
+ fourcc = inst->fmts[OUTPUT_PORT].fourcc;
} else if (inst->session_type == MSM_VIDC_ENCODER) {
- fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
+ fourcc = inst->fmts[CAPTURE_PORT].fourcc;
} else {
dprintk(VIDC_ERR, "Invalid session\n");
return -EINVAL;
@@ -3601,7 +3601,7 @@ static void populate_frame_data(struct vidc_frame_data *data,
data->buffer_type = msm_comm_get_hal_output_buffer(inst);
}
- extra_idx = EXTRADATA_IDX(inst->fmts[port]->num_planes);
+ extra_idx = EXTRADATA_IDX(inst->fmts[port].num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
vb->planes[extra_idx].m.userptr) {
data->extradata_addr = vb->planes[extra_idx].m.userptr;
@@ -4792,9 +4792,20 @@ int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
return -EINVAL;
}
hdev = core->device;
- if (core->state == VIDC_CORE_INIT_DONE)
+ if (core->state == VIDC_CORE_INIT_DONE) {
+ /*
+ * In current implementation user-initiated SSR triggers
+ * a fatal error from hardware. However, there is no way
+ * to know if fatal error is due to SSR or not. Handle
+ * user SSR as non-fatal.
+ */
+ mutex_lock(&core->lock);
+ core->resources.debug_timeout = false;
+ mutex_unlock(&core->lock);
rc = call_hfi_op(hdev, core_trigger_ssr,
hdev->hfi_device_data, type);
+ }
+
return rc;
}
@@ -5265,7 +5276,7 @@ void msm_comm_print_inst_info(struct msm_vidc_inst *inst)
port = is_decode ? OUTPUT_PORT : CAPTURE_PORT;
dprintk(VIDC_ERR,
"%s session, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n",
- is_decode ? "Decode" : "Encode", inst->fmts[port]->name,
+ is_decode ? "Decode" : "Encode", inst->fmts[port].name,
inst->prop.height[port], inst->prop.width[port],
inst->prop.fps, inst->prop.bitrate,
!inst->bit_depth ? "8" : "10");
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
index 9e67ef096c63..0e62811bf41b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
@@ -237,8 +237,8 @@ void msm_dcvs_init_load(struct msm_vidc_inst *inst)
}
fourcc = inst->session_type == MSM_VIDC_DECODER ?
- inst->fmts[OUTPUT_PORT]->fourcc :
- inst->fmts[CAPTURE_PORT]->fourcc;
+ inst->fmts[OUTPUT_PORT].fourcc :
+ inst->fmts[CAPTURE_PORT].fourcc;
for (i = 0; i < num_rows; i++) {
bool matches = msm_dcvs_check_codec_supported(
@@ -589,7 +589,7 @@ static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst)
}
is_codec_supported =
msm_dcvs_check_codec_supported(
- inst->fmts[OUTPUT_PORT]->fourcc,
+ inst->fmts[OUTPUT_PORT].fourcc,
inst->dcvs.supported_codecs,
inst->session_type);
if (!is_codec_supported ||
@@ -607,7 +607,7 @@ static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst)
inst->dcvs.extra_buffer_count = DCVS_ENC_EXTRA_OUTPUT_BUFFERS;
is_codec_supported =
msm_dcvs_check_codec_supported(
- inst->fmts[CAPTURE_PORT]->fourcc,
+ inst->fmts[CAPTURE_PORT].fourcc,
inst->dcvs.supported_codecs,
inst->session_type);
if (!is_codec_supported ||
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index d3027c08d24e..efb90c69881f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -289,10 +289,10 @@ static ssize_t inst_info_read(struct file *file, char __user *buf,
for (i = 0; i < MAX_PORT_NUM; i++) {
write_str(&dbg_buf, "capability: %s\n", i == OUTPUT_PORT ?
"Output" : "Capture");
- write_str(&dbg_buf, "name : %s\n", inst->fmts[i]->name);
- write_str(&dbg_buf, "planes : %d\n", inst->fmts[i]->num_planes);
+ write_str(&dbg_buf, "name : %s\n", inst->fmts[i].name);
+ write_str(&dbg_buf, "planes : %d\n", inst->fmts[i].num_planes);
write_str(
- &dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ?
+ &dbg_buf, "type: %s\n", inst->fmts[i].type == OUTPUT_PORT ?
"Output" : "Capture");
switch (inst->buffer_mode_set[i]) {
case HAL_BUFFER_MODE_STATIC:
@@ -311,7 +311,7 @@ static ssize_t inst_info_read(struct file *file, char __user *buf,
write_str(&dbg_buf, "count: %u\n",
inst->bufq[i].vb2_bufq.num_buffers);
- for (j = 0; j < inst->fmts[i]->num_planes; j++)
+ for (j = 0; j < inst->fmts[i].num_planes; j++)
write_str(&dbg_buf, "size for plane %d: %u\n", j,
inst->bufq[i].vb2_bufq.plane_sizes[j]);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index b6e74715ad07..161e94f99040 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -261,7 +261,7 @@ struct msm_vidc_inst {
void *session;
struct session_prop prop;
enum instance_state state;
- struct msm_vidc_format *fmts[MAX_PORT_NUM];
+ struct msm_vidc_format fmts[MAX_PORT_NUM];
struct buf_queue bufq[MAX_PORT_NUM];
struct msm_vidc_list pendingq;
struct msm_vidc_list scratchbufs;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c
index 08ed47f3cacf..d14f8da15595 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c
@@ -150,10 +150,16 @@ int ipa2_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data)
{
int ret;
+ if (!ipa_ctx) {
+ IPAERR("IPA ctx is null\n");
+ return -ENXIO;
+ }
+
ret = ipa2_uc_state_check();
if (ret) {
ipa_ctx->uc_ntn_ctx.uc_ready_cb = ipa_ready_cb;
ipa_ctx->uc_ntn_ctx.priv = user_data;
+ return 0;
}
return -EEXIST;
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 0bbda4eb4116..78e685f789cd 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -27,6 +27,7 @@
#define REVID_SUBTYPE 0x5
#define REVID_STATUS1 0x8
#define REVID_SPARE_0 0x60
+#define REVID_FAB_ID 0xf2
#define QPNP_REVID_DEV_NAME "qcom,qpnp-revid"
@@ -154,7 +155,7 @@ static size_t build_pmic_string(char *buf, size_t n, int sid,
static int qpnp_revid_probe(struct platform_device *pdev)
{
u8 rev1, rev2, rev3, rev4, pmic_type, pmic_subtype, pmic_status;
- u8 option1, option2, option3, option4, spare0;
+ u8 option1, option2, option3, option4, spare0, fab_id;
unsigned int base;
int rc;
char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'};
@@ -199,6 +200,11 @@ static int qpnp_revid_probe(struct platform_device *pdev)
pmic_subtype = PMI8937_PERIPHERAL_SUBTYPE;
}
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,fab-id-valid"))
+ fab_id = qpnp_read_byte(regmap, base + REVID_FAB_ID);
+ else
+ fab_id = -EINVAL;
+
revid_chip = devm_kzalloc(&pdev->dev, sizeof(struct revid_chip),
GFP_KERNEL);
if (!revid_chip)
@@ -211,6 +217,7 @@ static int qpnp_revid_probe(struct platform_device *pdev)
revid_chip->data.rev4 = rev4;
revid_chip->data.pmic_subtype = pmic_subtype;
revid_chip->data.pmic_type = pmic_type;
+ revid_chip->data.fab_id = fab_id;
if (pmic_subtype < ARRAY_SIZE(pmic_names))
revid_chip->data.pmic_name = pmic_names[pmic_subtype];
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 57f31d8c58e7..8fa4fe301676 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -605,6 +605,7 @@ static enum power_supply_property smb2_batt_props[] = {
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
POWER_SUPPLY_PROP_STEP_CHARGING_STEP,
+ POWER_SUPPLY_PROP_CHARGE_DONE,
};
static int smb2_batt_get_prop(struct power_supply *psy,
@@ -662,6 +663,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
+ case POWER_SUPPLY_PROP_CHARGE_DONE:
+ val->intval = chg->chg_done;
+ break;
default:
pr_err("batt power supply prop %d not supported\n", psp);
return -EINVAL;
@@ -692,6 +696,9 @@ static int smb2_batt_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CAPACITY:
rc = smblib_set_prop_batt_capacity(chg, val);
break;
+ case POWER_SUPPLY_PROP_CHARGE_DONE:
+ chg->chg_done = val->intval;
+ break;
default:
rc = -EINVAL;
}
@@ -992,14 +999,10 @@ static int smb2_init_hw(struct smb2 *chip)
vote(chg->dc_icl_votable,
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
- /*
- * Configure charge enable for software control; active high, and end
- * the charge cycle while the battery is OV.
- */
+ /* Configure charge enable for software control; active high */
rc = smblib_masked_write(chg, CHGR_CFG2_REG,
CHG_EN_POLARITY_BIT |
- CHG_EN_SRC_BIT |
- BAT_OV_ECC_BIT, BAT_OV_ECC_BIT);
+ CHG_EN_SRC_BIT, 0);
if (rc < 0) {
dev_err(chg->dev, "Couldn't configure charger rc=%d\n", rc);
return rc;
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index e93d03788f11..a869fc592474 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -883,25 +883,28 @@ int smblib_get_prop_batt_capacity(struct smb_charger *chg,
int smblib_get_prop_batt_status(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc;
- u8 stat;
union power_supply_propval pval = {0, };
+ bool usb_online, dc_online;
+ u8 stat;
+ int rc;
- smblib_get_prop_input_suspend(chg, &pval);
- if (pval.intval) {
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ rc = smblib_get_prop_usb_online(chg, &pval);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't get usb online property rc=%d\n",
+ rc);
return rc;
}
+ usb_online = (bool)pval.intval;
- rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+ rc = smblib_get_prop_dc_online(chg, &pval);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+ dev_err(chg->dev, "Couldn't get dc online property rc=%d\n",
rc);
return rc;
}
+ dc_online = (bool)pval.intval;
- if (!(stat & (USE_USBIN_BIT | USE_DCIN_BIT)) ||
- !(stat & VALID_INPUT_POWER_SOURCE_BIT)) {
+ if (!usb_online && !dc_online) {
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
return rc;
}
@@ -912,16 +915,29 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
rc);
return rc;
}
- smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_1 = 0x%02x\n",
- stat);
stat = stat & BATTERY_CHARGER_STATUS_MASK;
- if (stat >= COMPLETED_CHARGE)
- val->intval = POWER_SUPPLY_STATUS_FULL;
- else
+ switch (stat) {
+ case TRICKLE_CHARGE:
+ case PRE_CHARGE:
+ case FAST_CHARGE:
+ case FULLON_CHARGE:
+ case TAPER_CHARGE:
val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case TERMINATE_CHARGE:
+ case INHIBIT_CHARGE:
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case DISABLE_CHARGE:
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ }
- return rc;
+ return 0;
}
int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
@@ -936,8 +952,6 @@ int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
rc);
return rc;
}
- smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_1 = 0x%02x\n",
- stat);
switch (stat & BATTERY_CHARGER_STATUS_MASK) {
case TRICKLE_CHARGE:
@@ -1257,7 +1271,6 @@ int smblib_get_prop_usb_online(struct smb_charger *chg,
val->intval = (stat & USE_USBIN_BIT) &&
(stat & VALID_INPUT_POWER_SOURCE_BIT);
-
return rc;
}
@@ -1672,43 +1685,58 @@ irqreturn_t smblib_handle_debug(int irq, void *data)
return IRQ_HANDLED;
}
-irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
+static void smblib_pl_handle_chg_state_change(struct smb_charger *chg, u8 stat)
{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
- union power_supply_propval pval = {0, };
- int rc;
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+ bool pl_enabled;
if (chg->mode != PARALLEL_MASTER)
- return IRQ_HANDLED;
+ return;
- rc = smblib_get_prop_batt_charge_type(chg, &pval);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't get batt charge type rc=%d\n", rc);
- return IRQ_HANDLED;
+ pl_enabled = !get_effective_result_locked(chg->pl_disable_votable);
+ switch (stat) {
+ case FAST_CHARGE:
+ case FULLON_CHARGE:
+ vote(chg->pl_disable_votable, CHG_STATE_VOTER, false, 0);
+ break;
+ case TAPER_CHARGE:
+ if (pl_enabled) {
+ cancel_delayed_work_sync(&chg->pl_taper_work);
+ schedule_delayed_work(&chg->pl_taper_work, 0);
+ }
+ break;
+ case TERMINATE_CHARGE:
+ case INHIBIT_CHARGE:
+ case DISABLE_CHARGE:
+ vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
+ break;
+ default:
+ break;
}
+}
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST)
- vote(chg->pl_disable_votable, CHG_STATE_VOTER, false, 0);
+irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
+{
+ union power_supply_propval pval = {0, };
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+ u8 stat;
+ int rc;
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER
- && !get_effective_result_locked(chg->pl_disable_votable)) {
- cancel_delayed_work_sync(&chg->pl_taper_work);
- schedule_delayed_work(&chg->pl_taper_work, 0);
- }
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
- rc = smblib_get_prop_batt_status(chg, &pval);
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't get batt status type rc=%d\n", rc);
+ dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ rc);
return IRQ_HANDLED;
}
- if (pval.intval == POWER_SUPPLY_STATUS_FULL) {
- power_supply_changed(chg->batt_psy);
- vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
- }
+ stat = stat & BATTERY_CHARGER_STATUS_MASK;
+ smblib_pl_handle_chg_state_change(chg, stat);
+ pval.intval = (stat == TERMINATE_CHARGE);
+ power_supply_set_property(chg->batt_psy, POWER_SUPPLY_PROP_CHARGE_DONE,
+ &pval);
+ power_supply_changed(chg->batt_psy);
return IRQ_HANDLED;
}
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index f5d9dda8330a..1f2457e04ed6 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -163,6 +163,7 @@ struct smb_charger {
bool step_chg_enabled;
bool is_hdc;
+ bool chg_done;
/* workaround flag */
u32 wa_flags;
diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h
index c88d132fbf70..4a50d2fcbf97 100644
--- a/drivers/power/qcom-charger/smb-reg.h
+++ b/drivers/power/qcom-charger/smb-reg.h
@@ -41,8 +41,9 @@ enum {
FAST_CHARGE,
FULLON_CHARGE,
TAPER_CHARGE,
- COMPLETED_CHARGE,
+ TERMINATE_CHARGE,
INHIBIT_CHARGE,
+ DISABLE_CHARGE,
};
#define BATTERY_CHARGER_STATUS_2_REG (CHGR_BASE + 0x07)
diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c
index e990425bd63a..727a768e63eb 100644
--- a/drivers/power/qcom/msm-core.c
+++ b/drivers/power/qcom/msm-core.c
@@ -240,10 +240,10 @@ void trigger_cpu_pwr_stats_calc(void)
if (cpu_node->sensor_id < 0)
continue;
- if (cpu_node->temp == prev_temp[cpu])
+ if (cpu_node->temp == prev_temp[cpu]) {
sensor_get_temp(cpu_node->sensor_id, &temp);
-
- cpu_node->temp = temp / scaling_factor;
+ cpu_node->temp = temp / scaling_factor;
+ }
prev_temp[cpu] = cpu_node->temp;
@@ -373,7 +373,7 @@ static int update_userspace_power(struct sched_params __user *argp)
{
int i;
int ret;
- int cpu;
+ int cpu = -1;
struct cpu_activity_info *node;
struct cpu_static_info *sp, *clear_sp;
int cpumask, cluster, mpidr;
@@ -396,7 +396,7 @@ static int update_userspace_power(struct sched_params __user *argp)
}
}
- if (cpu >= num_possible_cpus())
+ if ((cpu < 0) || (cpu >= num_possible_cpus()))
return -EINVAL;
node = &activity[cpu];
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index 75a0de0c532b..2f109013f723 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -36,6 +36,7 @@
#define EMERGENCY_DLOAD_MAGIC1 0x322A4F99
#define EMERGENCY_DLOAD_MAGIC2 0xC67E4350
#define EMERGENCY_DLOAD_MAGIC3 0x77777777
+#define EMMC_DLOAD_TYPE 0x2
#define SCM_IO_DISABLE_PMIC_ARBITER 1
#define SCM_IO_DEASSERT_PS_HOLD 2
@@ -46,12 +47,20 @@
static int restart_mode;
-void *restart_reason;
+static void *restart_reason, *dload_type_addr;
static bool scm_pmic_arbiter_disable_supported;
static bool scm_deassert_ps_hold_supported;
/* Download mode master kill-switch */
static void __iomem *msm_ps_hold;
static phys_addr_t tcsr_boot_misc_detect;
+static void scm_disable_sdi(void);
+
+/* Runtime could be only changed value once.
+ * There is no API from TZ to re-enable the registers.
+ * So the SDI cannot be re-enabled when it already by-passed.
+*/
+static int download_mode = 1;
+static struct kobject dload_kobj;
#ifdef CONFIG_QCOM_DLOAD_MODE
#define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode"
@@ -64,9 +73,23 @@ static void *emergency_dload_mode_addr;
static bool scm_dload_supported;
static int dload_set(const char *val, struct kernel_param *kp);
-static int download_mode = 1;
+/* interface for exporting attributes */
+struct reset_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
+ char *buf);
+ size_t (*store)(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count);
+};
+#define to_reset_attr(_attr) \
+ container_of(_attr, struct reset_attribute, attr)
+#define RESET_ATTR(_name, _mode, _show, _store) \
+ static struct reset_attribute reset_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
module_param_call(download_mode, dload_set, param_get_int,
&download_mode, 0644);
+
static int panic_prep_restart(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -170,7 +193,10 @@ static int dload_set(const char *val, struct kernel_param *kp)
return 0;
}
#else
-#define set_dload_mode(x) do {} while (0)
+static void set_dload_mode(int on)
+{
+ return;
+}
static void enable_emergency_dload_mode(void)
{
@@ -183,6 +209,26 @@ static bool get_dload_mode(void)
}
#endif
+static void scm_disable_sdi(void)
+{
+ int ret;
+ struct scm_desc desc = {
+ .args[0] = 1,
+ .args[1] = 0,
+ .arginfo = SCM_ARGS(2),
+ };
+
+ /* Needed to bypass debug image on some chips */
+ if (!is_scm_armv8())
+ ret = scm_call_atomic2(SCM_SVC_BOOT,
+ SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
+ else
+ ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT,
+ SCM_WDOG_DEBUG_BOOT_PART), &desc);
+ if (ret)
+ pr_err("Failed to disable secure wdog debug: %d\n", ret);
+}
+
void msm_set_restart_mode(int mode)
{
restart_mode = mode;
@@ -320,13 +366,6 @@ static void deassert_ps_hold(void)
static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
{
- int ret;
- struct scm_desc desc = {
- .args[0] = 1,
- .args[1] = 0,
- .arginfo = SCM_ARGS(2),
- };
-
pr_notice("Going down for restart now\n");
msm_restart_prepare(cmd);
@@ -341,16 +380,7 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
msm_trigger_wdog_bite();
#endif
- /* Needed to bypass debug image on some chips */
- if (!is_scm_armv8())
- ret = scm_call_atomic2(SCM_SVC_BOOT,
- SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
- else
- ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT,
- SCM_WDOG_DEBUG_BOOT_PART), &desc);
- if (ret)
- pr_err("Failed to disable secure wdog debug: %d\n", ret);
-
+ scm_disable_sdi();
halt_spmi_pmic_arbiter();
deassert_ps_hold();
@@ -359,27 +389,11 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
static void do_msm_poweroff(void)
{
- int ret;
- struct scm_desc desc = {
- .args[0] = 1,
- .args[1] = 0,
- .arginfo = SCM_ARGS(2),
- };
-
pr_notice("Powering off the SoC\n");
-#ifdef CONFIG_QCOM_DLOAD_MODE
+
set_dload_mode(0);
-#endif
+ scm_disable_sdi();
qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
- /* Needed to bypass debug image on some chips */
- if (!is_scm_armv8())
- ret = scm_call_atomic2(SCM_SVC_BOOT,
- SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
- else
- ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT,
- SCM_WDOG_DEBUG_BOOT_PART), &desc);
- if (ret)
- pr_err("Failed to disable wdog debug: %d\n", ret);
halt_spmi_pmic_arbiter();
deassert_ps_hold();
@@ -389,6 +403,84 @@ static void do_msm_poweroff(void)
return;
}
+static ssize_t attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct reset_attribute *reset_attr = to_reset_attr(attr);
+ ssize_t ret = -EIO;
+
+ if (reset_attr->show)
+ ret = reset_attr->show(kobj, attr, buf);
+
+ return ret;
+}
+
+static ssize_t attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct reset_attribute *reset_attr = to_reset_attr(attr);
+ ssize_t ret = -EIO;
+
+ if (reset_attr->store)
+ ret = reset_attr->store(kobj, attr, buf, count);
+
+ return ret;
+}
+
+static const struct sysfs_ops reset_sysfs_ops = {
+ .show = attr_show,
+ .store = attr_store,
+};
+
+static struct kobj_type reset_ktype = {
+ .sysfs_ops = &reset_sysfs_ops,
+};
+
+static ssize_t show_emmc_dload(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ uint32_t read_val, show_val;
+
+ read_val = __raw_readl(dload_type_addr);
+ if (read_val == EMMC_DLOAD_TYPE)
+ show_val = 1;
+ else
+ show_val = 0;
+
+ return snprintf(buf, sizeof(show_val), "%u\n", show_val);
+}
+
+static size_t store_emmc_dload(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ uint32_t enabled;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &enabled);
+ if (ret < 0)
+ return ret;
+
+ if (!((enabled == 0) || (enabled == 1)))
+ return -EINVAL;
+
+ if (enabled == 1)
+ __raw_writel(EMMC_DLOAD_TYPE, dload_type_addr);
+ else
+ __raw_writel(0, dload_type_addr);
+
+ return count;
+}
+RESET_ATTR(emmc_dload, 0644, show_emmc_dload, store_emmc_dload);
+
+static struct attribute *reset_attrs[] = {
+ &reset_attr_emmc_dload.attr,
+ NULL
+};
+
+static struct attribute_group reset_attr_group = {
+ .attrs = reset_attrs,
+};
+
static int msm_restart_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -419,6 +511,33 @@ static int msm_restart_probe(struct platform_device *pdev)
pr_err("unable to map imem EDLOAD mode offset\n");
}
+ np = of_find_compatible_node(NULL, NULL,
+ "qcom,msm-imem-dload-type");
+ if (!np) {
+ pr_err("unable to find DT imem dload-type node\n");
+ goto skip_sysfs_create;
+ } else {
+ dload_type_addr = of_iomap(np, 0);
+ if (!dload_type_addr) {
+ pr_err("unable to map imem dload-type offset\n");
+ goto skip_sysfs_create;
+ }
+ }
+
+ ret = kobject_init_and_add(&dload_kobj, &reset_ktype,
+ kernel_kobj, "%s", "dload");
+ if (ret) {
+ pr_err("%s:Error in creation kobject_add\n", __func__);
+ kobject_put(&dload_kobj);
+ goto skip_sysfs_create;
+ }
+
+ ret = sysfs_create_group(&dload_kobj, &reset_attr_group);
+ if (ret) {
+ pr_err("%s:Error in creation sysfs_create_group\n", __func__);
+ kobject_del(&dload_kobj);
+ }
+skip_sysfs_create:
#endif
np = of_find_compatible_node(NULL, NULL,
"qcom,msm-imem-restart_reason");
@@ -454,6 +573,8 @@ static int msm_restart_probe(struct platform_device *pdev)
download_mode = scm_is_secure_device();
set_dload_mode(download_mode);
+ if (!download_mode)
+ scm_disable_sdi();
return 0;
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index cd02debc37aa..0df2b80ceca5 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -1264,6 +1264,8 @@ static void cprh_controller_program_sdelta(
mb();
}
+static int cprh_regulator_aging_adjust(struct cpr3_controller *ctrl);
+
/**
* cpr3_regulator_init_cprh() - performs hardware initialization at the
* controller and thread level required for CPRh operation.
@@ -1290,6 +1292,16 @@ static int cpr3_regulator_init_cprh(struct cpr3_controller *ctrl)
return -EINVAL;
}
+ rc = cprh_regulator_aging_adjust(ctrl);
+ if (rc && rc != -ETIMEDOUT) {
+ /*
+ * Don't fail initialization if the CPR aging measurement
+ * timed out due to sensors not being available.
+ */
+ cpr3_err(ctrl, "CPR aging adjustment failed, rc=%d\n", rc);
+ return rc;
+ }
+
cprh_controller_program_sdelta(ctrl);
rc = cpr3_regulator_init_cprh_corners(&ctrl->thread[0].vreg[0]);
@@ -3346,7 +3358,7 @@ static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
u32 mask, reg, result, quot_min, quot_max, sel_min, sel_max;
u32 quot_min_scaled, quot_max_scaled;
u32 gcnt, gcnt_ref, gcnt0_restore, gcnt1_restore, irq_restore;
- u32 cont_dly_restore, up_down_dly_restore = 0;
+ u32 ro_mask_restore, cont_dly_restore, up_down_dly_restore = 0;
int quot_delta, quot_delta_scaled, quot_delta_scaled_sum;
int *quot_delta_results;
int rc, rc2, i, aging_measurement_count, filtered_count;
@@ -3379,7 +3391,8 @@ static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
/* Switch from HW to SW closed-loop if necessary */
if (ctrl->supports_hw_closed_loop) {
- if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
+ if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4 ||
+ ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
@@ -3397,6 +3410,10 @@ static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt);
cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt);
+ /* Unmask all RO's */
+ ro_mask_restore = cpr3_read(ctrl, CPR3_REG_RO_MASK(0));
+ cpr3_write(ctrl, CPR3_REG_RO_MASK(0), 0);
+
/*
* Mask all sensors except for the one to measure and bypass all
* sensors in collapsible domains.
@@ -3535,6 +3552,8 @@ cleanup:
cpr3_write(ctrl, CPR3_REG_IRQ_EN, irq_restore);
+ cpr3_write(ctrl, CPR3_REG_RO_MASK(0), ro_mask_restore);
+
cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt0_restore);
cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt1_restore);
@@ -3565,7 +3584,8 @@ cleanup:
CPR3_IRQ_UP | CPR3_IRQ_DOWN | CPR3_IRQ_MID);
if (ctrl->supports_hw_closed_loop) {
- if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
+ if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4 ||
+ ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
ctrl->use_hw_closed_loop
@@ -3671,14 +3691,16 @@ static void cpr3_regulator_readjust_volt_and_quot(struct cpr3_regulator *vreg,
static void cpr3_regulator_set_aging_ref_adjustment(
struct cpr3_controller *ctrl, int ref_adjust_volt)
{
+ struct cpr3_regulator *vreg;
int i, j;
for (i = 0; i < ctrl->thread_count; i++) {
for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
- cpr3_regulator_readjust_volt_and_quot(
- &ctrl->thread[i].vreg[j],
- ctrl->aging_ref_adjust_volt,
- ref_adjust_volt);
+ vreg = &ctrl->thread[i].vreg[j];
+ cpr3_regulator_readjust_volt_and_quot(vreg,
+ ctrl->aging_ref_adjust_volt, ref_adjust_volt);
+ if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH)
+ cprh_adjust_voltages_for_apm(vreg);
}
}
@@ -3867,6 +3889,126 @@ cleanup:
}
/**
+ * cprh_regulator_aging_adjust() - adjust the target quotients and open-loop
+ * voltages for CPRh regulators based on the output of CPR aging
+ * sensors
+ * @ctrl: Pointer to the CPR3 controller
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cprh_regulator_aging_adjust(struct cpr3_controller *ctrl)
+{
+ int i, j, id, rc, rc2, aging_volt, init_volt;
+ int max_aging_volt = 0;
+ u32 reg;
+
+ if (!ctrl->aging_required || !ctrl->cpr_enabled)
+ return 0;
+
+ if (!ctrl->vdd_regulator) {
+ cpr3_err(ctrl, "vdd-supply regulator missing\n");
+ return -ENODEV;
+ }
+
+ init_volt = regulator_get_voltage(ctrl->vdd_regulator);
+ if (init_volt < 0) {
+ cpr3_err(ctrl, "could not get vdd-supply voltage, rc=%d\n",
+ init_volt);
+ return init_volt;
+ }
+
+ if (init_volt > ctrl->aging_ref_volt) {
+ cpr3_info(ctrl, "unable to perform CPR aging measurement as vdd=%d uV > aging voltage=%d uV\n",
+ init_volt, ctrl->aging_ref_volt);
+ return 0;
+ }
+
+ /* Verify that none of the aging sensors are currently masked. */
+ for (i = 0; i < ctrl->aging_sensor_count; i++) {
+ id = ctrl->aging_sensor[i].sensor_id;
+ reg = cpr3_read(ctrl, CPR3_REG_SENSOR_MASK_READ(id));
+ if (reg & BIT(id % 32)) {
+ cpr3_info(ctrl, "unable to perform CPR aging measurement as CPR sensor %d is masked\n",
+ id);
+ return 0;
+ }
+ }
+
+ rc = regulator_set_voltage(ctrl->vdd_regulator, ctrl->aging_ref_volt,
+ INT_MAX);
+ if (rc) {
+ cpr3_err(ctrl, "unable to set vdd-supply to aging voltage=%d uV, rc=%d\n",
+ ctrl->aging_ref_volt, rc);
+ return rc;
+ }
+
+ if (ctrl->aging_vdd_mode) {
+ rc = regulator_set_mode(ctrl->vdd_regulator,
+ ctrl->aging_vdd_mode);
+ if (rc) {
+ cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
+ ctrl->aging_vdd_mode, rc);
+ goto cleanup;
+ }
+ }
+
+ /* Perform aging measurement on all aging sensors */
+ for (i = 0; i < ctrl->aging_sensor_count; i++) {
+ for (j = 0; j < CPR3_AGING_RETRY_COUNT; j++) {
+ rc = cpr3_regulator_measure_aging(ctrl,
+ &ctrl->aging_sensor[i]);
+ if (!rc)
+ break;
+ }
+
+ if (!rc) {
+ aging_volt =
+ cpr3_voltage_adjustment(
+ ctrl->aging_sensor[i].ro_scale,
+ ctrl->aging_sensor[i].measured_quot_diff
+ - ctrl->aging_sensor[i].init_quot_diff);
+ max_aging_volt = max(max_aging_volt, aging_volt);
+ } else {
+ cpr3_err(ctrl, "CPR aging measurement failed after %d tries, rc=%d\n",
+ j, rc);
+ ctrl->aging_failed = true;
+ ctrl->aging_required = false;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ /* Adjust the CPR target quotients according to the aging measurement */
+ if (!rc) {
+ cpr3_regulator_set_aging_ref_adjustment(ctrl, max_aging_volt);
+
+ cpr3_info(ctrl, "aging measurement successful; aging reference adjustment voltage=%d uV\n",
+ ctrl->aging_ref_adjust_volt);
+ ctrl->aging_succeeded = true;
+ ctrl->aging_required = false;
+ }
+
+ rc2 = regulator_set_voltage(ctrl->vdd_regulator, init_volt, INT_MAX);
+ if (rc2) {
+ cpr3_err(ctrl, "unable to reset vdd-supply to initial voltage=%d uV, rc=%d\n",
+ init_volt, rc2);
+ return rc2;
+ }
+
+ if (ctrl->aging_complete_vdd_mode) {
+ rc2 = regulator_set_mode(ctrl->vdd_regulator,
+ ctrl->aging_complete_vdd_mode);
+ if (rc2) {
+ cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
+ ctrl->aging_complete_vdd_mode, rc2);
+ return rc2;
+ }
+ }
+
+ return rc;
+}
+
+/**
* cpr3_regulator_update_ctrl_state() - update the state of the CPR controller
* to reflect the corners used by all CPR3 regulators as well as
* the CPR operating mode and perform aging adjustments if needed
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 8897def3ef76..ac571271b0d5 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -875,6 +875,7 @@ int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg,
bool use_corner_band);
int cpr3_apm_init(struct cpr3_controller *ctrl);
int cpr3_mem_acc_init(struct cpr3_regulator *vreg);
+void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg);
#else
@@ -1047,6 +1048,10 @@ static inline int cpr3_mem_acc_init(struct cpr3_regulator *vreg)
return 0;
}
+static inline void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
+{
+}
+
#endif /* CONFIG_REGULATOR_CPR3 */
#endif /* __REGULATOR_CPR_REGULATOR_H__ */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 51179f28fcf5..c377a65a6393 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -1202,6 +1202,23 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
if (rc)
return rc;
+ ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
+ if (IS_ERR(ctrl->vdd_regulator)) {
+ rc = PTR_ERR(ctrl->vdd_regulator);
+ if (rc != -EPROBE_DEFER) {
+ /* vdd-supply is optional for CPRh controllers. */
+ if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
+ cpr3_debug(ctrl, "unable to request vdd regulator, rc=%d\n",
+ rc);
+ ctrl->vdd_regulator = NULL;
+ return 0;
+ }
+ cpr3_err(ctrl, "unable to request vdd regulator, rc=%d\n",
+ rc);
+ }
+ return rc;
+ }
+
/*
* Regulator device handles are not necessary for CPRh controllers
* since communication with the regulators is completely managed
@@ -1210,15 +1227,6 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH)
return rc;
- ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
- if (IS_ERR(ctrl->vdd_regulator)) {
- rc = PTR_ERR(ctrl->vdd_regulator);
- if (rc != -EPROBE_DEFER)
- cpr3_err(ctrl, "unable request vdd regulator, rc=%d\n",
- rc);
- return rc;
- }
-
ctrl->system_regulator = devm_regulator_get_optional(ctrl->dev,
"system");
if (IS_ERR(ctrl->system_regulator)) {
@@ -2000,3 +2008,78 @@ done:
return rc;
}
+
+/**
+ * cprh_adjust_voltages_for_apm() - adjust per-corner floor and ceiling voltages
+ * so that they do not overlap the APM threshold voltage.
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * The memory array power mux (APM) must be configured for a specific supply
+ * based upon where the VDD voltage lies with respect to the APM threshold
+ * voltage. When using CPR hardware closed-loop, the voltage may vary anywhere
+ * between the floor and ceiling voltage without software notification.
+ * Therefore, it is required that the floor to ceiling range for every corner
+ * not intersect the APM threshold voltage. This function adjusts the floor to
+ * ceiling range for each corner which violates this requirement.
+ *
+ * The following algorithm is applied:
+ * if floor < threshold <= ceiling:
+ * if open_loop >= threshold, then floor = threshold - adj
+ * else ceiling = threshold - step
+ * where:
+ * adj = APM hysteresis voltage established to minimize the number of
+ * corners with artificially increased floor voltages
+ * step = voltage in microvolts of a single step of the VDD supply
+ *
+ * The open-loop voltage is also bounded by the new floor or ceiling value as
+ * needed.
+ *
+ * Return: none
+ */
+void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
+{
+ struct cpr3_controller *ctrl = vreg->thread->ctrl;
+ struct cpr3_corner *corner;
+ int i, adj, threshold, prev_ceiling, prev_floor, prev_open_loop;
+
+ if (!ctrl->apm_threshold_volt) {
+ /* APM not being used. */
+ return;
+ }
+
+ ctrl->apm_threshold_volt = CPR3_ROUND(ctrl->apm_threshold_volt,
+ ctrl->step_volt);
+ ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
+
+ threshold = ctrl->apm_threshold_volt;
+ adj = ctrl->apm_adj_volt;
+
+ for (i = 0; i < vreg->corner_count; i++) {
+ corner = &vreg->corner[i];
+
+ if (threshold <= corner->floor_volt
+ || threshold > corner->ceiling_volt)
+ continue;
+
+ prev_floor = corner->floor_volt;
+ prev_ceiling = corner->ceiling_volt;
+ prev_open_loop = corner->open_loop_volt;
+
+ if (corner->open_loop_volt >= threshold) {
+ corner->floor_volt = max(corner->floor_volt,
+ threshold - adj);
+ if (corner->open_loop_volt < corner->floor_volt)
+ corner->open_loop_volt = corner->floor_volt;
+ } else {
+ corner->ceiling_volt = threshold - ctrl->step_volt;
+ }
+
+ if (corner->floor_volt != prev_floor
+ || corner->ceiling_volt != prev_ceiling
+ || corner->open_loop_volt != prev_open_loop)
+ cpr3_debug(vreg, "APM threshold=%d, APM adj=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
+ threshold, adj, i, prev_floor, prev_ceiling,
+ prev_open_loop, corner->floor_volt,
+ corner->ceiling_volt, corner->open_loop_volt);
+ }
+}
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index 284180b0e72f..953ea5f33f40 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -54,6 +54,8 @@
* @force_highest_corner: Flag indicating that all corners must operate
* at the voltage of the highest corner. This is
* applicable to MSMCOBALT only.
+ * @aging_init_quot_diff: Initial quotient difference between CPR aging
+ * min and max sensors measured at time of manufacturing
*
* This struct holds the values for all of the fuses read from memory.
*/
@@ -65,6 +67,7 @@ struct cprh_msmcobalt_kbss_fuses {
u64 speed_bin;
u64 cpr_fusing_rev;
u64 force_highest_corner;
+ u64 aging_init_quot_diff;
};
/*
@@ -192,6 +195,18 @@ msmcobalt_cpr_force_highest_corner_param[] = {
{},
};
+static const struct cpr3_fuse_param
+msmcobalt_kbss_aging_init_quot_diff_param[2][2] = {
+ [MSMCOBALT_KBSS_POWER_CLUSTER_ID] = {
+ {69, 6, 13},
+ {},
+ },
+ [MSMCOBALT_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ {71, 25, 32},
+ {},
+ },
+};
+
/*
* Open loop voltage fuse reference voltages in microvolts for MSMCOBALT v1
*/
@@ -225,6 +240,8 @@ msmcobalt_v2_kbss_fuse_ref_volt[2][MSMCOBALT_KBSS_FUSE_CORNERS] = {
#define MSMCOBALT_KBSS_FUSE_STEP_VOLT 10000
#define MSMCOBALT_KBSS_VOLTAGE_FUSE_SIZE 6
#define MSMCOBALT_KBSS_QUOT_OFFSET_SCALE 5
+#define MSMCOBALT_KBSS_AGING_INIT_QUOT_DIFF_SIZE 8
+#define MSMCOBALT_KBSS_AGING_INIT_QUOT_DIFF_SCALE 1
#define MSMCOBALT_KBSS_POWER_CPR_SENSOR_COUNT 6
#define MSMCOBALT_KBSS_PERFORMANCE_CPR_SENSOR_COUNT 9
@@ -242,6 +259,12 @@ msmcobalt_v2_kbss_fuse_ref_volt[2][MSMCOBALT_KBSS_FUSE_CORNERS] = {
#define MSMCOBALT_KBSS_PERFORMANCE_TEMP_SENSOR_ID_START 6
#define MSMCOBALT_KBSS_PERFORMANCE_TEMP_SENSOR_ID_END 11
+#define MSMCOBALT_KBSS_POWER_AGING_SENSOR_ID 0
+#define MSMCOBALT_KBSS_POWER_AGING_BYPASS_MASK0 0
+
+#define MSMCOBALT_KBSS_PERFORMANCE_AGING_SENSOR_ID 0
+#define MSMCOBALT_KBSS_PERFORMANCE_AGING_BYPASS_MASK0 0
+
/**
* cprh_msmcobalt_kbss_read_fuse_data() - load KBSS specific fuse parameter values
* @vreg: Pointer to the CPR3 regulator
@@ -321,6 +344,15 @@ static int cprh_msmcobalt_kbss_read_fuse_data(struct cpr3_regulator *vreg)
}
rc = cpr3_read_fuse_param(base,
+ msmcobalt_kbss_aging_init_quot_diff_param[id],
+ &fuse->aging_init_quot_diff);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
msmcobalt_cpr_force_highest_corner_param,
&fuse->force_highest_corner);
if (rc) {
@@ -826,6 +858,7 @@ static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg)
corner->floor_volt = ctrl->apm_crossover_volt;
corner->ceiling_volt = ctrl->apm_crossover_volt;
corner->open_loop_volt = ctrl->apm_crossover_volt;
+ corner->abs_ceiling_volt = ctrl->apm_crossover_volt;
corner->use_open_loop = true;
vreg->corner_count++;
@@ -833,79 +866,6 @@ static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg)
}
/**
- * cprh_kbss_adjust_voltages_for_apm() - adjust per-corner floor and ceiling
- * voltages so that they do not overlap the APM threshold voltage.
- * @vreg: Pointer to the CPR3 regulator
- *
- * The KBSS memory array power mux (APM) must be configured for a specific
- * supply based upon where the VDD voltage lies with respect to the APM
- * threshold voltage. When using CPR hardware closed-loop, the voltage may vary
- * anywhere between the floor and ceiling voltage without software notification.
- * Therefore, it is required that the floor to ceiling range for every corner
- * not intersect the APM threshold voltage. This function adjusts the floor to
- * ceiling range for each corner which violates this requirement.
- *
- * The following algorithm is applied in the case that
- * floor < threshold <= ceiling:
- * if open_loop >= threshold, then floor = threshold - adj
- * else ceiling = threshold - step
- * where adj = APM hysteresis voltage established to minimize number
- * of corners with artificially increased floor voltages
- * and step = voltage in microvolts of a single step of the VDD supply
- *
- * The open-loop voltage is also bounded by the new floor or ceiling value as
- * needed.
- *
- * Return: 0 on success, errno on failure
- */
-static int cprh_kbss_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
-{
- struct cpr3_controller *ctrl = vreg->thread->ctrl;
- struct cpr3_corner *corner;
- int i, adj, threshold, prev_ceiling, prev_floor, prev_open_loop;
-
- if (!ctrl->apm_threshold_volt) {
- /* APM not being used. */
- return 0;
- }
-
- ctrl->apm_threshold_volt = CPR3_ROUND(ctrl->apm_threshold_volt,
- ctrl->step_volt);
- ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
-
- threshold = ctrl->apm_threshold_volt;
- adj = ctrl->apm_adj_volt;
-
- for (i = 0; i < vreg->corner_count; i++) {
- corner = &vreg->corner[i];
-
- if (threshold <= corner->floor_volt
- || threshold > corner->ceiling_volt)
- continue;
-
- prev_floor = corner->floor_volt;
- prev_ceiling = corner->ceiling_volt;
- prev_open_loop = corner->open_loop_volt;
-
- if (corner->open_loop_volt >= threshold) {
- corner->floor_volt = max(corner->floor_volt,
- threshold - adj);
- if (corner->open_loop_volt < corner->floor_volt)
- corner->open_loop_volt = corner->floor_volt;
- } else {
- corner->ceiling_volt = threshold - ctrl->step_volt;
- }
-
- cpr3_debug(vreg, "APM threshold=%d, APM adj=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
- threshold, adj, i, prev_floor, prev_ceiling,
- prev_open_loop, corner->floor_volt,
- corner->ceiling_volt, corner->open_loop_volt);
- }
-
- return 0;
-}
-
-/**
* cprh_msmcobalt_kbss_set_no_interpolation_quotients() - use the fused target
* quotient values for lower frequencies.
* @vreg: Pointer to the CPR3 regulator
@@ -1235,12 +1195,7 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
return rc;
}
- rc = cprh_kbss_adjust_voltages_for_apm(vreg);
- if (rc) {
- cpr3_err(vreg, "unable to adjust voltages for APM\n, rc=%d\n",
- rc);
- return rc;
- }
+ cprh_adjust_voltages_for_apm(vreg);
cpr3_open_loop_voltage_as_ceiling(vreg);
@@ -1299,6 +1254,80 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
}
/**
+ * cprh_kbss_init_aging() - perform KBSS CPRh controller specific aging
+ * initializations
+ * @ctrl: Pointer to the CPR3 controller
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cprh_kbss_init_aging(struct cpr3_controller *ctrl)
+{
+ struct cprh_msmcobalt_kbss_fuses *fuse = NULL;
+ struct cpr3_regulator *vreg;
+ u32 aging_ro_scale;
+ int i, j, rc;
+
+ for (i = 0; i < ctrl->thread_count; i++) {
+ for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
+ if (ctrl->thread[i].vreg[j].aging_allowed) {
+ ctrl->aging_required = true;
+ vreg = &ctrl->thread[i].vreg[j];
+ fuse = vreg->platform_fuses;
+ break;
+ }
+ }
+ }
+
+ if (!ctrl->aging_required || !fuse || !vreg)
+ return 0;
+
+ rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor",
+ 1, &aging_ro_scale);
+ if (rc)
+ return rc;
+
+ if (aging_ro_scale == 0) {
+ cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n",
+ aging_ro_scale);
+ return -EINVAL;
+ }
+
+ ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL;
+ ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE;
+
+ ctrl->aging_sensor_count = 1;
+ ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL);
+ if (!ctrl->aging_sensor)
+ return -ENOMEM;
+
+ if (ctrl->ctrl_id == MSMCOBALT_KBSS_POWER_CLUSTER_ID) {
+ ctrl->aging_sensor->sensor_id
+ = MSMCOBALT_KBSS_POWER_AGING_SENSOR_ID;
+ ctrl->aging_sensor->bypass_mask[0]
+ = MSMCOBALT_KBSS_POWER_AGING_BYPASS_MASK0;
+ } else {
+ ctrl->aging_sensor->sensor_id
+ = MSMCOBALT_KBSS_PERFORMANCE_AGING_SENSOR_ID;
+ ctrl->aging_sensor->bypass_mask[0]
+ = MSMCOBALT_KBSS_PERFORMANCE_AGING_BYPASS_MASK0;
+ }
+ ctrl->aging_sensor->ro_scale = aging_ro_scale;
+
+ ctrl->aging_sensor->init_quot_diff
+ = cpr3_convert_open_loop_voltage_fuse(0,
+ MSMCOBALT_KBSS_AGING_INIT_QUOT_DIFF_SCALE,
+ fuse->aging_init_quot_diff,
+ MSMCOBALT_KBSS_AGING_INIT_QUOT_DIFF_SIZE);
+
+ cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n",
+ ctrl->aging_sensor->sensor_id,
+ ctrl->aging_sensor->init_quot_diff,
+ ctrl->aging_sensor->ro_scale);
+
+ return 0;
+}
+
+/**
* cprh_kbss_init_controller() - perform KBSS CPRh controller specific
* initializations
* @ctrl: Pointer to the CPR3 controller
@@ -1566,6 +1595,13 @@ static int cprh_kbss_regulator_probe(struct platform_device *pdev)
return rc;
}
+ rc = cprh_kbss_init_aging(ctrl);
+ if (rc) {
+ cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n",
+ rc);
+ return rc;
+ }
+
platform_set_drvdata(pdev, ctrl);
rc = cprh_kbss_populate_opp_table(ctrl);
diff --git a/drivers/scsi/ufs/ufs_test.c b/drivers/scsi/ufs/ufs_test.c
index 8953722e8dad..e23dc3e8d9da 100644
--- a/drivers/scsi/ufs/ufs_test.c
+++ b/drivers/scsi/ufs/ufs_test.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
@@ -689,13 +689,13 @@ static void scenario_free_end_io_fn(struct request *rq, int err)
__blk_put_request(test_iosched->req_q, test_rq->rq);
spin_unlock_irqrestore(&test_iosched->lock, flags);
- test_iosched_free_test_req_data_buffer(test_rq);
- kfree(test_rq);
-
if (err)
pr_err("%s: request %d completed, err=%d", __func__,
test_rq->req_id, err);
+ test_iosched_free_test_req_data_buffer(test_rq);
+ kfree(test_rq);
+
check_test_completion(test_iosched);
}
@@ -984,14 +984,14 @@ static void long_test_free_end_io_fn(struct request *rq, int err)
return;
}
- test_iosched_free_test_req_data_buffer(test_rq);
- kfree(test_rq);
- utd->completed_req_count++;
-
if (err)
pr_err("%s: request %d completed, err=%d", __func__,
test_rq->req_id, err);
+ test_iosched_free_test_req_data_buffer(test_rq);
+ kfree(test_rq);
+ utd->completed_req_count++;
+
check_test_completion(test_iosched);
}
@@ -1007,7 +1007,7 @@ static void long_test_free_end_io_fn(struct request *rq, int err)
static int run_long_test(struct test_iosched *test_iosched)
{
int ret = 0;
- int direction, num_bios_per_request;
+ int direction, num_bios_per_request = 1;
static unsigned int inserted_requests;
u32 sector, seed, num_bios, seq_sector_delta;
struct ufs_test_data *utd = test_iosched->blk_dev_test_data;
@@ -1028,14 +1028,12 @@ static int run_long_test(struct test_iosched *test_iosched)
/* Set test parameters */
switch (test_iosched->test_info.testcase) {
case UFS_TEST_LONG_RANDOM_READ:
- num_bios_per_request = 1;
utd->long_test_num_reqs = (utd->sector_range * SECTOR_SIZE) /
(LONG_RAND_TEST_REQ_RATIO * TEST_BIO_SIZE *
num_bios_per_request);
direction = READ;
break;
case UFS_TEST_LONG_RANDOM_WRITE:
- num_bios_per_request = 1;
utd->long_test_num_reqs = (utd->sector_range * SECTOR_SIZE) /
(LONG_RAND_TEST_REQ_RATIO * TEST_BIO_SIZE *
num_bios_per_request);
diff --git a/drivers/soc/qcom/common_log.c b/drivers/soc/qcom/common_log.c
index f4c69d624342..ecf89b2b3b37 100644
--- a/drivers/soc/qcom/common_log.c
+++ b/drivers/soc/qcom/common_log.c
@@ -20,7 +20,7 @@
#include <soc/qcom/memory_dump.h>
#define MISC_DUMP_DATA_LEN 4096
-#define PMIC_DUMP_DATA_LEN 4096
+#define PMIC_DUMP_DATA_LEN (64 * 1024)
#define VSENSE_DUMP_DATA_LEN 4096
#define RPM_DUMP_DATA_LEN (160 * 1024)
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 999e6f93e873..25b522806c3e 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -260,7 +260,12 @@ void *icnss_ipc_log_context;
void *icnss_ipc_log_long_context;
#endif
-#define ICNSS_EVENT_PENDING 2989
+#define ICNSS_EVENT_PENDING 2989
+
+#define ICNSS_EVENT_SYNC BIT(0)
+#define ICNSS_EVENT_UNINTERRUPTIBLE BIT(1)
+#define ICNSS_EVENT_SYNC_UNINTERRUPTIBLE (ICNSS_EVENT_UNINTERRUPTIBLE | \
+ ICNSS_EVENT_SYNC)
enum icnss_driver_event_type {
ICNSS_DRIVER_EVENT_SERVER_ARRIVE,
@@ -291,7 +296,6 @@ enum icnss_driver_state {
ICNSS_FW_READY,
ICNSS_DRIVER_PROBED,
ICNSS_FW_TEST_MODE,
- ICNSS_SUSPEND,
ICNSS_PM_SUSPEND,
ICNSS_PM_SUSPEND_NOIRQ,
ICNSS_SSR_ENABLED,
@@ -359,6 +363,8 @@ struct icnss_stats {
uint32_t pm_suspend_noirq_err;
uint32_t pm_resume_noirq;
uint32_t pm_resume_noirq_err;
+ uint32_t pm_stay_awake;
+ uint32_t pm_relax;
uint32_t ind_register_req;
uint32_t ind_register_resp;
@@ -436,7 +442,6 @@ static struct icnss_priv {
struct notifier_block get_service_nb;
void *modem_notify_handler;
struct notifier_block modem_ssr_nb;
- struct wakeup_source ws;
uint32_t diag_reg_read_addr;
uint32_t diag_reg_read_mem_type;
uint32_t diag_reg_read_len;
@@ -445,6 +450,7 @@ static struct icnss_priv {
struct qpnp_adc_tm_chip *adc_tm_dev;
struct qpnp_vadc_chip *vadc_dev;
uint64_t vph_pwr;
+ atomic_t pm_count;
} *penv;
static void icnss_hw_write_reg(void *base, u32 offset, u32 val)
@@ -512,6 +518,35 @@ static int icnss_hw_poll_reg_field(void *base, u32 offset, u32 mask, u32 val,
return 0;
}
+static void icnss_pm_stay_awake(struct icnss_priv *priv)
+{
+ if (atomic_inc_return(&priv->pm_count) != 1)
+ return;
+
+ icnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
+ atomic_read(&priv->pm_count));
+
+ pm_stay_awake(&priv->pdev->dev);
+
+ priv->stats.pm_stay_awake++;
+}
+
+static void icnss_pm_relax(struct icnss_priv *priv)
+{
+ int r = atomic_dec_return(&priv->pm_count);
+
+ WARN_ON(r < 0);
+
+ if (r != 0)
+ return;
+
+ icnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
+ atomic_read(&priv->pm_count));
+
+ pm_relax(&priv->pdev->dev);
+ priv->stats.pm_relax++;
+}
+
static char *icnss_driver_event_to_str(enum icnss_driver_event_type type)
{
switch (type) {
@@ -535,16 +570,16 @@ static char *icnss_driver_event_to_str(enum icnss_driver_event_type type)
};
static int icnss_driver_event_post(enum icnss_driver_event_type type,
- bool sync, void *data)
+ u32 flags, void *data)
{
struct icnss_driver_event *event;
- unsigned long flags;
+ unsigned long irq_flags;
int gfp = GFP_KERNEL;
int ret = 0;
- icnss_pr_dbg("Posting event: %s: %s%s(%d), state: 0x%lx\n",
- current->comm, icnss_driver_event_to_str(type),
- sync ? "-sync" : "", type, penv->state);
+ icnss_pr_dbg("Posting event: %s(%d), %s, flags: 0x%x, state: 0x%lx\n",
+ icnss_driver_event_to_str(type), type, current->comm,
+ flags, penv->state);
if (type >= ICNSS_DRIVER_EVENT_MAX) {
icnss_pr_err("Invalid Event type: %d, can't post", type);
@@ -558,39 +593,47 @@ static int icnss_driver_event_post(enum icnss_driver_event_type type,
if (event == NULL)
return -ENOMEM;
+ icnss_pm_stay_awake(penv);
+
event->type = type;
event->data = data;
init_completion(&event->complete);
event->ret = ICNSS_EVENT_PENDING;
- event->sync = sync;
+ event->sync = !!(flags & ICNSS_EVENT_SYNC);
- spin_lock_irqsave(&penv->event_lock, flags);
+ spin_lock_irqsave(&penv->event_lock, irq_flags);
list_add_tail(&event->list, &penv->event_list);
- spin_unlock_irqrestore(&penv->event_lock, flags);
+ spin_unlock_irqrestore(&penv->event_lock, irq_flags);
penv->stats.events[type].posted++;
queue_work(penv->event_wq, &penv->event_work);
- if (!sync)
- return ret;
+ if (!(flags & ICNSS_EVENT_SYNC))
+ goto out;
- ret = wait_for_completion_interruptible(&event->complete);
+ if (flags & ICNSS_EVENT_UNINTERRUPTIBLE)
+ wait_for_completion(&event->complete);
+ else
+ ret = wait_for_completion_interruptible(&event->complete);
icnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
icnss_driver_event_to_str(type), type, penv->state, ret,
event->ret);
- spin_lock_irqsave(&penv->event_lock, flags);
+ spin_lock_irqsave(&penv->event_lock, irq_flags);
if (ret == -ERESTARTSYS && event->ret == ICNSS_EVENT_PENDING) {
event->sync = false;
- spin_unlock_irqrestore(&penv->event_lock, flags);
- return ret;
+ spin_unlock_irqrestore(&penv->event_lock, irq_flags);
+ ret = -EINTR;
+ goto out;
}
- spin_unlock_irqrestore(&penv->event_lock, flags);
+ spin_unlock_irqrestore(&penv->event_lock, irq_flags);
ret = event->ret;
kfree(event);
+out:
+ icnss_pm_relax(penv);
return ret;
}
@@ -2194,7 +2237,7 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
switch (msg_id) {
case QMI_WLFW_FW_READY_IND_V01:
icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_READY_IND,
- false, NULL);
+ 0, NULL);
break;
case QMI_WLFW_MSA_READY_IND_V01:
icnss_pr_dbg("Received MSA Ready Indication msg_id 0x%x\n",
@@ -2382,8 +2425,6 @@ static int icnss_driver_event_fw_ready_ind(void *data)
if (!penv)
return -ENODEV;
- __pm_stay_awake(&penv->ws);
-
set_bit(ICNSS_FW_READY, &penv->state);
icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state);
@@ -2401,10 +2442,7 @@ static int icnss_driver_event_fw_ready_ind(void *data)
else
ret = icnss_call_driver_probe(penv);
- __pm_relax(&penv->ws);
-
out:
- __pm_relax(&penv->ws);
return ret;
}
@@ -2415,8 +2453,6 @@ static int icnss_driver_event_register_driver(void *data)
if (penv->ops)
return -EEXIST;
- __pm_stay_awake(&penv->ws);
-
penv->ops = data;
if (test_bit(SKIP_QMI, &quirks))
@@ -2442,21 +2478,16 @@ static int icnss_driver_event_register_driver(void *data)
set_bit(ICNSS_DRIVER_PROBED, &penv->state);
- __pm_relax(&penv->ws);
-
return 0;
power_off:
icnss_hw_power_off(penv);
out:
- __pm_relax(&penv->ws);
return ret;
}
static int icnss_driver_event_unregister_driver(void *data)
{
- __pm_stay_awake(&penv->ws);
-
if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) {
penv->ops = NULL;
goto out;
@@ -2472,7 +2503,6 @@ static int icnss_driver_event_unregister_driver(void *data)
icnss_hw_power_off(penv);
out:
- __pm_relax(&penv->ws);
return 0;
}
@@ -2550,6 +2580,8 @@ static void icnss_driver_event_work(struct work_struct *work)
unsigned long flags;
int ret;
+ icnss_pm_stay_awake(penv);
+
spin_lock_irqsave(&penv->event_lock, flags);
while (!list_empty(&penv->event_list)) {
@@ -2609,6 +2641,8 @@ static void icnss_driver_event_work(struct work_struct *work)
spin_lock_irqsave(&penv->event_lock, flags);
}
spin_unlock_irqrestore(&penv->event_lock, flags);
+
+ icnss_pm_relax(penv);
}
static int icnss_qmi_wlfw_clnt_svc_event_notify(struct notifier_block *this,
@@ -2625,12 +2659,12 @@ static int icnss_qmi_wlfw_clnt_svc_event_notify(struct notifier_block *this,
switch (code) {
case QMI_SERVER_ARRIVE:
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_SERVER_ARRIVE,
- false, NULL);
+ 0, NULL);
break;
case QMI_SERVER_EXIT:
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_SERVER_EXIT,
- false, NULL);
+ 0, NULL);
break;
default:
icnss_pr_dbg("Invalid code: %ld", code);
@@ -2667,7 +2701,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
event_data->crashed = notif->crashed;
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
- true, event_data);
+ ICNSS_EVENT_SYNC, event_data);
return NOTIFY_OK;
}
@@ -2742,7 +2776,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
event_data->crashed = true;
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
- true, event_data);
+ ICNSS_EVENT_SYNC, event_data);
break;
case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
icnss_pr_dbg("Service up, state: 0x%lx\n", priv->state);
@@ -2914,7 +2948,7 @@ int icnss_register_driver(struct icnss_driver_ops *ops)
}
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
- true, ops);
+ ICNSS_EVENT_SYNC, ops);
if (ret == -ERESTARTSYS)
ret = 0;
@@ -2942,7 +2976,7 @@ int icnss_unregister_driver(struct icnss_driver_ops *ops)
}
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
- true, NULL);
+ ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
out:
return ret;
}
@@ -3270,6 +3304,12 @@ int icnss_wlan_disable(enum icnss_driver_mode mode)
}
EXPORT_SYMBOL(icnss_wlan_disable);
+bool icnss_is_qmi_disable(void)
+{
+ return test_bit(SKIP_QMI, &quirks) ? true : false;
+}
+EXPORT_SYMBOL(icnss_is_qmi_disable);
+
int icnss_get_ce_id(int irq)
{
int i;
@@ -3821,9 +3861,6 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_FW_TEST_MODE:
seq_puts(s, "FW TEST MODE");
continue;
- case ICNSS_SUSPEND:
- seq_puts(s, "SUSPEND");
- continue;
case ICNSS_PM_SUSPEND:
seq_puts(s, "PM SUSPEND");
continue;
@@ -3843,6 +3880,7 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
seq_puts(s, "MSA0 ASSIGNED");
continue;
case ICNSS_WLFW_EXISTS:
+ seq_puts(s, "WLAN FW EXISTS");
continue;
}
@@ -3947,6 +3985,8 @@ static int icnss_stats_show(struct seq_file *s, void *data)
ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq_err);
ICNSS_STATS_DUMP(s, priv, pm_resume_noirq);
ICNSS_STATS_DUMP(s, priv, pm_resume_noirq_err);
+ ICNSS_STATS_DUMP(s, priv, pm_stay_awake);
+ ICNSS_STATS_DUMP(s, priv, pm_relax);
icnss_stats_show_irqs(s, priv);
@@ -4398,8 +4438,6 @@ static int icnss_probe(struct platform_device *pdev)
spin_lock_init(&priv->event_lock);
spin_lock_init(&priv->on_off_lock);
- wakeup_source_init(&priv->ws, "icnss_ws");
-
priv->event_wq = alloc_workqueue("icnss_driver_event", WQ_UNBOUND, 1);
if (!priv->event_wq) {
icnss_pr_err("Workqueue creation failed\n");
@@ -4461,8 +4499,6 @@ static int icnss_remove(struct platform_device *pdev)
icnss_bw_deinit(penv);
- wakeup_source_trash(&penv->ws);
-
icnss_hw_power_off(penv);
dev_set_drvdata(&pdev->dev, NULL);
@@ -4470,55 +4506,6 @@ static int icnss_remove(struct platform_device *pdev)
return 0;
}
-static int icnss_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- int ret = 0;
-
- if (!penv) {
- ret = -ENODEV;
- goto out;
- }
-
- icnss_pr_dbg("Driver suspending, state: 0x%lx\n",
- penv->state);
-
- if (!penv->ops || !penv->ops->suspend ||
- !test_bit(ICNSS_DRIVER_PROBED, &penv->state))
- goto out;
-
- ret = penv->ops->suspend(&pdev->dev, state);
-
-out:
- if (ret == 0)
- set_bit(ICNSS_SUSPEND, &penv->state);
- return ret;
-}
-
-static int icnss_resume(struct platform_device *pdev)
-{
- int ret = 0;
-
- if (!penv) {
- ret = -ENODEV;
- goto out;
- }
-
- icnss_pr_dbg("Driver resuming, state: 0x%lx\n",
- penv->state);
-
- if (!penv->ops || !penv->ops->resume ||
- !test_bit(ICNSS_DRIVER_PROBED, &penv->state))
- goto out;
-
- ret = penv->ops->resume(&pdev->dev);
-
-out:
- if (ret == 0)
- clear_bit(ICNSS_SUSPEND, &penv->state);
- return ret;
-}
-
#ifdef CONFIG_PM_SLEEP
static int icnss_pm_suspend(struct device *dev)
{
@@ -4654,8 +4641,6 @@ MODULE_DEVICE_TABLE(of, icnss_dt_match);
static struct platform_driver icnss_driver = {
.probe = icnss_probe,
.remove = icnss_remove,
- .suspend = icnss_suspend,
- .resume = icnss_resume,
.driver = {
.name = "icnss",
.pm = &icnss_pm_ops,
diff --git a/drivers/soc/qcom/rpm-smd-debug.c b/drivers/soc/qcom/rpm-smd-debug.c
index c08668149636..4e406f7cd379 100644
--- a/drivers/soc/qcom/rpm-smd-debug.c
+++ b/drivers/soc/qcom/rpm-smd-debug.c
@@ -104,8 +104,6 @@ static ssize_t rsc_ops_write(struct file *fp, const char __user *user_buffer,
if (msm_rpm_wait_for_ack(msm_rpm_send_request(req)))
pr_err("Sending the RPM message failed\n");
- else
- pr_info("RPM message sent succesfully\n");
err_request:
msm_rpm_free_request(req);
diff --git a/drivers/soc/qcom/system_stats.c b/drivers/soc/qcom/system_stats.c
index 476d2f6dca27..ba35928a991b 100644
--- a/drivers/soc/qcom/system_stats.c
+++ b/drivers/soc/qcom/system_stats.c
@@ -154,7 +154,7 @@ static int rpm_stats_write_buf(struct seq_file *m)
time = get_time_in_msec(time);
seq_printf(m, "\ttime in last mode(msec):%llu\n", time);
- time = arch_counter_get_cntpct() - rs.last_exited_at;
+ time = arch_counter_get_cntvct() - rs.last_exited_at;
time = get_time_in_sec(time);
seq_printf(m, "\ttime since last mode(sec):%llu\n", time);
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index a8c8e120c348..e0af922a0329 100755
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -1201,7 +1201,7 @@ static void ion_vm_open(struct vm_area_struct *vma)
mutex_lock(&buffer->lock);
list_add(&vma_list->list, &buffer->vmas);
mutex_unlock(&buffer->lock);
- pr_debug("%s: adding %p\n", __func__, vma);
+ pr_debug("%s: adding %pK\n", __func__, vma);
}
static void ion_vm_close(struct vm_area_struct *vma)
@@ -1216,7 +1216,7 @@ static void ion_vm_close(struct vm_area_struct *vma)
continue;
list_del(&vma_list->list);
kfree(vma_list);
- pr_debug("%s: deleting %p\n", __func__, vma);
+ pr_debug("%s: deleting %pK\n", __func__, vma);
break;
}
mutex_unlock(&buffer->lock);
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index aaea7bed36e1..b2e1a4c1b170 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -94,7 +94,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
/* keep this for memory release */
buffer->priv_virt = info;
- dev_dbg(dev, "Allocate buffer %p\n", buffer);
+ dev_dbg(dev, "Allocate buffer %pK\n", buffer);
return 0;
err:
@@ -107,7 +107,7 @@ static void ion_cma_free(struct ion_buffer *buffer)
struct device *dev = buffer->heap->priv;
struct ion_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(dev, "Release buffer %p\n", buffer);
+ dev_dbg(dev, "Release buffer %pK\n", buffer);
/* release memory */
dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
sg_free_table(info->table);
@@ -123,7 +123,7 @@ static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
struct device *dev = heap->priv;
struct ion_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(dev, "Return buffer %p physical address %pa\n", buffer,
+ dev_dbg(dev, "Return buffer %pK physical address %pa\n", buffer,
&info->handle);
*addr = info->handle;
diff --git a/drivers/staging/android/ion/ion_cma_secure_heap.c b/drivers/staging/android/ion/ion_cma_secure_heap.c
index d945b9251437..90ae7eb65b65 100644
--- a/drivers/staging/android/ion/ion_cma_secure_heap.c
+++ b/drivers/staging/android/ion/ion_cma_secure_heap.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linaro 2012
* Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-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
@@ -501,7 +501,7 @@ retry:
/* keep this for memory release */
buffer->priv_virt = info;
- dev_dbg(sheap->dev, "Allocate buffer %p\n", buffer);
+ dev_dbg(sheap->dev, "Allocate buffer %pK\n", buffer);
return info;
err:
@@ -634,7 +634,7 @@ retry:
sg = sg_next(sg);
}
buffer->priv_virt = info;
- dev_dbg(sheap->dev, "Allocate buffer %p\n", buffer);
+ dev_dbg(sheap->dev, "Allocate buffer %pK\n", buffer);
return info;
err2:
@@ -721,7 +721,7 @@ static void ion_secure_cma_free(struct ion_buffer *buffer)
struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
int ret = 0;
- dev_dbg(sheap->dev, "Release buffer %p\n", buffer);
+ dev_dbg(sheap->dev, "Release buffer %pK\n", buffer);
if (msm_secure_v2_is_supported())
ret = msm_unsecure_table(info->table);
atomic_sub(buffer->size, &sheap->total_allocated);
@@ -743,8 +743,8 @@ static int ion_secure_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
container_of(heap, struct ion_cma_secure_heap, heap);
struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(sheap->dev, "Return buffer %p physical address 0x%pa\n", buffer,
- &info->phys);
+ dev_dbg(sheap->dev, "Return buffer %pK physical address 0x%pa\n",
+ buffer, &info->phys);
*addr = info->phys;
*len = buffer->size;
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index fd4d45ad8db2..03b2b8a38991 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -204,11 +204,16 @@ static struct page *split_page_from_secure_pool(struct ion_system_heap *heap,
split_page(page, order);
break;
}
- /* Return the remaining order-0 pages to the pool */
- if (page)
- for (j = 1; j < (1 << order); j++)
+ /*
+ * Return the remaining order-0 pages to the pool.
+ * SetPagePrivate flag to mark memory as secure.
+ */
+ if (page) {
+ for (j = 1; j < (1 << order); j++) {
+ SetPagePrivate(page + j);
free_buffer_page(heap, buffer, page + j, 0);
-
+ }
+ }
got_page:
mutex_unlock(&heap->split_page_mutex);
diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c
index 592c603b1780..176f22ba570c 100644
--- a/drivers/staging/android/ion/msm/msm_ion.c
+++ b/drivers/staging/android/ion/msm/msm_ion.c
@@ -711,7 +711,7 @@ long msm_ion_custom_ioctl(struct ion_client *client,
} else {
handle = ion_import_dma_buf(client, data.flush_data.fd);
if (IS_ERR(handle)) {
- pr_info("%s: Could not import handle: %p\n",
+ pr_info("%s: Could not import handle: %pK\n",
__func__, handle);
return -EINVAL;
}
@@ -724,8 +724,8 @@ long msm_ion_custom_ioctl(struct ion_client *client,
+ data.flush_data.length;
if (start && check_vaddr_bounds(start, end)) {
- pr_err("%s: virtual address %p is out of bounds\n",
- __func__, data.flush_data.vaddr);
+ pr_err("%s: virtual address %pK is out of bounds\n",
+ __func__, data.flush_data.vaddr);
ret = -EINVAL;
} else {
ret = ion_do_cache_op(
diff --git a/drivers/thermal/lmh_lite.c b/drivers/thermal/lmh_lite.c
index bd456d25b124..32a573d22270 100644
--- a/drivers/thermal/lmh_lite.c
+++ b/drivers/thermal/lmh_lite.c
@@ -640,7 +640,7 @@ sens_exit:
static int lmh_get_sensor_list(void)
{
- int ret = 0;
+ int ret = 0, buf_size = 0;
uint32_t size = 0, next = 0, idx = 0, count = 0;
struct scm_desc desc_arg;
struct lmh_sensor_packet *payload = NULL;
@@ -649,12 +649,13 @@ static int lmh_get_sensor_list(void)
uint32_t size;
} cmd_buf;
- payload = kzalloc(sizeof(*payload), GFP_KERNEL);
+ buf_size = PAGE_ALIGN(sizeof(*payload));
+ payload = kzalloc(buf_size, GFP_KERNEL);
if (!payload)
return -ENOMEM;
do {
- memset(payload, 0, sizeof(*payload));
+ memset(payload, 0, buf_size);
payload->count = next;
cmd_buf.addr = SCM_BUFFER_PHYS(payload);
/* payload_phys may be a physical address > 4 GB */
@@ -663,7 +664,7 @@ static int lmh_get_sensor_list(void)
lmh_sensor_packet);
desc_arg.arginfo = SCM_ARGS(2, SCM_RW, SCM_VAL);
trace_lmh_event_call("GET_SENSORS enter");
- dmac_flush_range(payload, payload + sizeof(*payload));
+ dmac_flush_range(payload, payload + buf_size);
if (!is_scm_armv8())
ret = scm_call(SCM_SVC_LMH, LMH_GET_SENSORS,
(void *) &cmd_buf,
@@ -881,7 +882,8 @@ static int lmh_debug_read(struct lmh_debug_ops *ops, uint32_t **buf)
if (curr_size != size) {
if (payload)
devm_kfree(lmh_data->dev, payload);
- payload = devm_kzalloc(lmh_data->dev, size, GFP_KERNEL);
+ payload = devm_kzalloc(lmh_data->dev, PAGE_ALIGN(size),
+ GFP_KERNEL);
if (!payload) {
pr_err("payload buffer alloc failed\n");
ret = -ENOMEM;
@@ -948,7 +950,8 @@ static int lmh_debug_config_write(uint32_t cmd_id, uint32_t *buf, int size)
trace_lmh_debug_data("Config LMH", buf, size);
size_bytes = (size - 3) * sizeof(uint32_t);
- payload = devm_kzalloc(lmh_data->dev, size_bytes, GFP_KERNEL);
+ payload = devm_kzalloc(lmh_data->dev, PAGE_ALIGN(size_bytes),
+ GFP_KERNEL);
if (!payload) {
ret = -ENOMEM;
goto set_cfg_exit;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 3df80c73b74a..ac0eb0939ecf 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2990,6 +2990,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
+ /* handle any pending hub events before XHCI stops */
+ usb_flush_hub_wq();
+
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_list_lock);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 84df093639ac..269c1ee2da44 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -610,6 +610,12 @@ void usb_kick_hub_wq(struct usb_device *hdev)
kick_hub_wq(hub);
}
+void usb_flush_hub_wq(void)
+{
+ flush_workqueue(hub_wq);
+}
+EXPORT_SYMBOL(usb_flush_hub_wq);
+
/*
* Let the USB core know that a USB 3.0 device has sent a Function Wake Device
* Notification, which indicates it had initiated remote wakeup.
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 4a4f1083198c..08006d84fb38 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1249,6 +1249,7 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
struct usb_gsi_request *request;
struct gsi_channel_info *ch_info;
bool block_db, f_suspend;
+ unsigned long flags;
switch (op) {
case GSI_EP_OP_PREPARE_TRBS:
@@ -1263,11 +1264,15 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
case GSI_EP_OP_CONFIG:
request = (struct usb_gsi_request *)op_data;
dev_dbg(mdwc->dev, "EP_OP_CONFIG for %s\n", ep->name);
+ spin_lock_irqsave(&dwc->lock, flags);
gsi_configure_ep(ep, request);
+ spin_unlock_irqrestore(&dwc->lock, flags);
break;
case GSI_EP_OP_STARTXFER:
dev_dbg(mdwc->dev, "EP_OP_STARTXFER for %s\n", ep->name);
+ spin_lock_irqsave(&dwc->lock, flags);
ret = gsi_startxfer_for_ep(ep);
+ spin_unlock_irqrestore(&dwc->lock, flags);
break;
case GSI_EP_OP_GET_XFER_IDX:
dev_dbg(mdwc->dev, "EP_OP_GET_XFER_IDX for %s\n", ep->name);
@@ -1293,12 +1298,16 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
case GSI_EP_OP_UPDATEXFER:
request = (struct usb_gsi_request *)op_data;
dev_dbg(mdwc->dev, "EP_OP_UPDATEXFER\n");
+ spin_lock_irqsave(&dwc->lock, flags);
ret = gsi_updatexfer_for_ep(ep, request);
+ spin_unlock_irqrestore(&dwc->lock, flags);
break;
case GSI_EP_OP_ENDXFER:
request = (struct usb_gsi_request *)op_data;
dev_dbg(mdwc->dev, "EP_OP_ENDXFER for %s\n", ep->name);
+ spin_lock_irqsave(&dwc->lock, flags);
gsi_endxfer_for_ep(ep);
+ spin_unlock_irqrestore(&dwc->lock, flags);
break;
case GSI_EP_OP_SET_CLR_BLOCK_DBL:
block_db = *((bool *)op_data);
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index d489e453594a..f058ab4cedaa 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -461,7 +461,7 @@ static struct usb_gadget_strings *rmnet_gsi_strings[] = {
/* rndis device descriptors */
-/* interface descriptor: */
+/* interface descriptor: Supports "Wireless" RNDIS; auto-detected by Windows*/
static struct usb_interface_descriptor rndis_gsi_control_intf = {
.bLength = sizeof(rndis_gsi_control_intf),
.bDescriptorType = USB_DT_INTERFACE,
@@ -469,9 +469,9 @@ static struct usb_interface_descriptor rndis_gsi_control_intf = {
/* .bInterfaceNumber = DYNAMIC */
/* status endpoint is optional; this could be patched later */
.bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
+ .bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x03,
/* .iInterface = DYNAMIC */
};
@@ -522,15 +522,16 @@ static struct usb_interface_descriptor rndis_gsi_data_intf = {
/* .iInterface = DYNAMIC */
};
+/* Supports "Wireless" RNDIS; auto-detected by Windows */
static struct usb_interface_assoc_descriptor
rndis_gsi_iad_descriptor = {
.bLength = sizeof(rndis_gsi_iad_descriptor),
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = 0, /* XXX, hardcoded */
.bInterfaceCount = 2, /* control + data */
- .bFunctionClass = USB_CLASS_COMM,
- .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
- .bFunctionProtocol = USB_CDC_PROTO_NONE,
+ .bFunctionClass = USB_CLASS_WIRELESS_CONTROLLER,
+ .bFunctionSubClass = 0x01,
+ .bFunctionProtocol = 0x03,
/* .iFunction = DYNAMIC */
};
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index aa186781ef22..5e50fe245a59 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -1876,7 +1876,8 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi,
dev->function.disable = mtp_function_disable;
dev->function.setup = mtp_ctrlreq_configfs;
dev->function.free_func = mtp_free;
- dev->is_ptp = mtp_config;
+ dev->is_ptp = !mtp_config;
+ fi->f = &dev->function;
return &dev->function;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index dd7669331d00..b30831ef4014 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -116,17 +116,20 @@ int xhci_halt(struct xhci_hcd *xhci)
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
if (!ret) {
xhci->xhc_state |= XHCI_STATE_HALTED;
- xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
-
- if (timer_pending(&xhci->cmd_timer)) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Cleanup command queue");
- del_timer(&xhci->cmd_timer);
- xhci_cleanup_command_queue(xhci);
- }
- } else
+ } else {
xhci_warn(xhci, "Host not halted after %u microseconds.\n",
XHCI_MAX_HALT_USEC);
+ }
+
+ xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
+
+ if (timer_pending(&xhci->cmd_timer)) {
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Cleanup command queue");
+ del_timer(&xhci->cmd_timer);
+ xhci_cleanup_command_queue(xhci);
+ }
+
return ret;
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index a1451a2d4826..12b98017beb2 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -2267,12 +2267,15 @@ struct usbpd *devm_usbpd_get_by_phandle(struct device *dev, const char *phandle)
struct platform_device *pdev;
struct device *pd_dev;
+ if (!usbpd_class.p) /* usbpd_init() not yet called */
+ return ERR_PTR(-EAGAIN);
+
if (!dev->of_node)
- return ERR_PTR(-ENODEV);
+ return ERR_PTR(-EINVAL);
pd_np = of_parse_phandle(dev->of_node, phandle, 0);
if (!pd_np)
- return ERR_PTR(-ENODEV);
+ return ERR_PTR(-ENXIO);
pdev = of_find_device_by_node(pd_np);
if (!pdev)
@@ -2282,7 +2285,8 @@ struct usbpd *devm_usbpd_get_by_phandle(struct device *dev, const char *phandle)
match_usbpd_device);
if (!pd_dev) {
platform_device_put(pdev);
- return ERR_PTR(-ENODEV);
+ /* device was found but maybe hadn't probed yet, so defer */
+ return ERR_PTR(-EPROBE_DEFER);
}
ptr = devres_alloc(devm_usbpd_put, sizeof(*ptr), GFP_KERNEL);
@@ -2294,7 +2298,7 @@ struct usbpd *devm_usbpd_get_by_phandle(struct device *dev, const char *phandle)
pd = dev_get_drvdata(pd_dev);
if (!pd)
- return ERR_PTR(-ENODEV);
+ return ERR_PTR(-EPROBE_DEFER);
*ptr = pd;
devres_add(dev, ptr);
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 584d2edc364e..d9297a7af764 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -510,8 +510,8 @@ char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt)
pr_debug("clk_rate=%llu, bpp= %d, lane_cnt=%d\n",
pinfo->clk_rate, pinfo->bpp, lane_cnt);
- min_link_rate = (pinfo->clk_rate * 10) /
- (lane_cnt * encoding_factx10);
+ min_link_rate = (u32)div_u64((pinfo->clk_rate * 10),
+ (lane_cnt * encoding_factx10));
min_link_rate = (min_link_rate * pinfo->bpp)
/ (DP_LINK_RATE_MULTIPLIER);
min_link_rate /= ln_to_link_ratio;
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index c145f72c3c70..66cd99720afa 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -357,7 +357,7 @@ static int mdss_dsi_panel_power_lp(struct mdss_panel_data *pdata, int enable)
static int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata,
int power_state)
{
- int ret;
+ int ret = 0;
struct mdss_panel_info *pinfo;
if (pdata == NULL) {
@@ -383,7 +383,11 @@ static int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata,
switch (power_state) {
case MDSS_PANEL_POWER_OFF:
- ret = mdss_dsi_panel_power_off(pdata);
+ case MDSS_PANEL_POWER_LCD_DISABLED:
+ /* if LCD has not been disabled, then disable it now */
+ if ((pinfo->panel_power_state != MDSS_PANEL_POWER_LCD_DISABLED)
+ && (pinfo->panel_power_state != MDSS_PANEL_POWER_OFF))
+ ret = mdss_dsi_panel_power_off(pdata);
break;
case MDSS_PANEL_POWER_ON:
if (mdss_dsi_is_panel_on_lp(pdata))
@@ -2469,6 +2473,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int power_state;
u32 mode;
struct mdss_panel_info *pinfo;
+ int ret;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -2529,6 +2534,20 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
rc = mdss_dsi_blank(pdata, power_state);
rc = mdss_dsi_off(pdata, power_state);
break;
+ case MDSS_EVENT_DISABLE_PANEL:
+ /* disable esd thread */
+ disable_esd_thread();
+
+ /* disable backlight */
+ ctrl_pdata->panel_data.set_backlight(pdata, 0);
+
+ /* send the off commands */
+ ctrl_pdata->off(pdata);
+
+ /* disable panel power */
+ ret = mdss_dsi_panel_power_ctrl(pdata,
+ MDSS_PANEL_POWER_LCD_DISABLED);
+ break;
case MDSS_EVENT_CONT_SPLASH_FINISH:
if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_blank(pdata, MDSS_PANEL_POWER_OFF);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index bd1854092c6a..7091dc2f38b9 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -614,6 +614,7 @@ int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl);
irqreturn_t mdss_dsi_isr(int irq, void *ptr);
irqreturn_t hw_vsync_handler(int irq, void *data);
+void disable_esd_thread(void);
void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index e8d68059581f..8ffba091e2b2 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -667,6 +667,11 @@ static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
* for the backlight brightness. If the brightness is less
* than it, the controller can malfunction.
*/
+ pr_debug("%s: bl_level:%d\n", __func__, bl_level);
+
+ /* do not allow backlight to change when panel in disable mode */
+ if (pdata->panel_disable_mode && (bl_level != 0))
+ return;
if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0))
bl_level = pdata->panel_info.bl_min;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c
index bf545ae311f2..4208c2c43efb 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_status.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_status.c
@@ -101,6 +101,16 @@ irqreturn_t hw_vsync_handler(int irq, void *data)
}
/*
+ * disable_esd_thread() - Cancels work item for the esd check.
+ */
+void disable_esd_thread(void)
+{
+ if (pstatus_data &&
+ cancel_delayed_work(&pstatus_data->check_status))
+ pr_debug("esd thread killed\n");
+}
+
+/*
* fb_event_callback() - Call back function for the fb_register_client()
* notifying events
* @self : notifier block
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 50c7015c6731..fc8d3898351e 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1950,6 +1950,9 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
pdata->panel_info.is_lpm_mode = false;
}
+ if (pdata->panel_disable_mode)
+ mdss_mdp_enable_panel_disable_mode(mfd, false);
+
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 921391dc4bde..0085163ada52 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -394,6 +394,8 @@ struct mdss_mdp_ctl_intfs_ops {
enum dynamic_switch_modes mode, bool pre);
/* called before do any register programming from commit thread */
void (*pre_programming)(struct mdss_mdp_ctl *ctl);
+ /* called to do any interface programming for the panel disable mode */
+ void (*panel_disable_cfg)(struct mdss_mdp_ctl *ctl, bool disable);
/* to update lineptr, [1..yres] - enable, 0 - disable */
int (*update_lineptr)(struct mdss_mdp_ctl *ctl, bool enable);
@@ -1863,6 +1865,8 @@ int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *ctl, int frame_cnt);
int mdss_mdp_cmd_get_autorefresh_mode(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt);
int mdss_mdp_ctl_cmd_get_autorefresh(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_enable_panel_disable_mode(struct msm_fb_data_type *mfd,
+ bool disable_panel);
int mdss_mdp_pp_get_version(struct mdp_pp_feature_version *version);
int mdss_mdp_layer_pre_commit_cwb(struct msm_fb_data_type *mfd,
struct mdp_layer_commit_v1 *commit);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 2c2dc6f18fd9..72d6175686b7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -295,9 +295,9 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
__func__, pinfo->yres, vclks_line, te->sync_cfg_height,
te->vsync_init_val, te->rd_ptr_irq, te->start_pos,
te->wr_ptr_irq);
- pr_debug("thrd_start =%d thrd_cont=%d pp_split=%d\n",
+ pr_debug("thrd_start =%d thrd_cont=%d pp_split=%d hw_vsync_mode:%d\n",
te->sync_threshold_start, te->sync_threshold_continue,
- ctx->pingpong_split_slave);
+ ctx->pingpong_split_slave, pinfo->mipi.hw_vsync_mode);
pingpong_base = mixer->pingpong_base;
@@ -2130,6 +2130,88 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl,
}
/*
+ * This function will be called from the sysfs node to tear down or restore
+ * any dependencies of the interface to disable the panel
+ */
+void mdss_mdp_cmd_panel_disable_cfg(struct mdss_mdp_ctl *ctl,
+ bool disable)
+{
+ struct mdss_panel_info *pinfo, *spinfo = NULL;
+ struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL;
+
+ pinfo = &ctl->panel_data->panel_info;
+ mutex_lock(&ctl->offlock);
+
+ if ((pinfo->sim_panel_mode == SIM_MODE) ||
+ ((!ctl->panel_data->panel_disable_mode) &&
+ (pinfo->mipi.hw_vsync_mode == 0))) {
+ pr_err("te already in simulaiton mode\n");
+ goto exit;
+ }
+
+ ctx = (struct mdss_mdp_cmd_ctx *)ctl->intf_ctx[MASTER_CTX];
+ if (is_pingpong_split(ctl->mfd)) {
+ sctx = (struct mdss_mdp_cmd_ctx *)ctl->intf_ctx[SLAVE_CTX];
+ } else if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
+ struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
+
+ if (sctl) {
+ sctx = (struct mdss_mdp_cmd_ctx *)
+ sctl->intf_ctx[MASTER_CTX];
+ spinfo = &sctl->panel_data->panel_info;
+ }
+ }
+
+ if (disable) {
+ /* cache the te params */
+ memcpy(&pinfo->te_cached, &pinfo->te,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ pinfo->mipi.hw_vsync_mode = 0;
+
+ if (spinfo) {
+ spinfo->mipi.hw_vsync_mode = 0;
+ memcpy(&spinfo->te_cached, &spinfo->te,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ }
+
+ pr_debug("%s: update info\n", __func__);
+ /* update the te information to use sim mode */
+ mdss_panel_override_te_params(pinfo);
+ if (spinfo)
+ mdss_panel_override_te_params(spinfo);
+
+ pr_debug("%s: reconfig tear check\n", __func__);
+ /* reconfigure tear check, remove dependency to external te */
+ if (mdss_mdp_cmd_tearcheck_setup(ctx, false)) {
+ pr_warn("%s: ctx%d tearcheck setup failed\n", __func__,
+ ctx->current_pp_num);
+ } else {
+ if (sctx && mdss_mdp_cmd_tearcheck_setup(sctx, false))
+ pr_warn("%s: ctx%d tearcheck setup failed\n",
+ __func__, sctx->current_pp_num);
+ }
+ } else {
+ /*
+ * restore the information in the panel information,
+ * the actual programming will happen during restore
+ */
+ pr_debug("%s: reset tear check\n", __func__);
+ memcpy(&pinfo->te, &pinfo->te_cached,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ pinfo->mipi.hw_vsync_mode = 1;
+
+ if (spinfo) {
+ spinfo->mipi.hw_vsync_mode = 1;
+ memcpy(&spinfo->te, &spinfo->te_cached,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ }
+ }
+
+exit:
+ mutex_unlock(&ctl->offlock);
+}
+
+/*
* This function will be called from the sysfs node to enable and disable the
* feature with master ctl only.
*/
@@ -3481,6 +3563,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
ctl->ops.reconfigure = mdss_mdp_cmd_reconfigure;
ctl->ops.pre_programming = mdss_mdp_cmd_pre_programming;
ctl->ops.update_lineptr = mdss_mdp_cmd_update_lineptr;
+ ctl->ops.panel_disable_cfg = mdss_mdp_cmd_panel_disable_cfg;
pr_debug("%s:-\n", __func__);
return 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 9dda467e53cc..965d4a6cfb5e 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -3243,6 +3243,110 @@ static ssize_t mdss_mdp_dyn_pu_store(struct device *dev,
return count;
}
+
+static ssize_t mdss_mdp_panel_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_panel_data *pdata;
+
+ if (!mfd) {
+ pr_err("Invalid mfd structure\n");
+ return -EINVAL;
+ }
+
+ ctl = mfd_to_ctl(mfd);
+ if (!ctl) {
+ pr_err("Invalid ctl structure\n");
+ return -EINVAL;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ pdata->panel_disable_mode);
+
+ return ret;
+}
+
+int mdss_mdp_enable_panel_disable_mode(struct msm_fb_data_type *mfd,
+ bool disable_panel)
+{
+ struct mdss_mdp_ctl *ctl;
+ int ret = 0;
+ struct mdss_panel_data *pdata;
+
+ ctl = mfd_to_ctl(mfd);
+ if (!ctl) {
+ pr_err("Invalid ctl structure\n");
+ ret = -EINVAL;
+ return ret;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ pr_debug("config panel %d\n", disable_panel);
+ if (disable_panel) {
+ /* first set the flag that we enter this mode */
+ pdata->panel_disable_mode = true;
+
+ /*
+ * setup any interface config that needs to change before
+ * disabling the panel
+ */
+ if (ctl->ops.panel_disable_cfg)
+ ctl->ops.panel_disable_cfg(ctl, disable_panel);
+
+ /* disable panel */
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DISABLE_PANEL,
+ NULL, CTL_INTF_EVENT_FLAG_DEFAULT);
+ if (ret)
+ pr_err("failed to disable panel! %d\n", ret);
+ } else {
+ /* restore any interface configuration */
+ if (ctl->ops.panel_disable_cfg)
+ ctl->ops.panel_disable_cfg(ctl, disable_panel);
+
+ /*
+ * no other action is needed when reconfiguring, since all the
+ * re-configuration will happen during restore
+ */
+ pdata->panel_disable_mode = false;
+ }
+
+ return ret;
+}
+
+static ssize_t mdss_mdp_panel_disable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ int disable_panel, rc;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+
+ if (!mfd) {
+ pr_err("Invalid mfd structure\n");
+ rc = -EINVAL;
+ return rc;
+ }
+
+ rc = kstrtoint(buf, 10, &disable_panel);
+ if (rc) {
+ pr_err("kstrtoint failed. rc=%d\n", rc);
+ return rc;
+ }
+
+ pr_debug("disable panel: %d ++\n", disable_panel);
+ /* we only support disabling the panel from sysfs */
+ if (disable_panel)
+ mdss_mdp_enable_panel_disable_mode(mfd, true);
+
+ return len;
+}
+
static ssize_t mdss_mdp_cmd_autorefresh_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -3433,6 +3537,8 @@ static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR,
mdss_mdp_misr_show, mdss_mdp_misr_store);
static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR,
mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store);
+static DEVICE_ATTR(msm_disable_panel, S_IRUGO | S_IWUSR,
+ mdss_mdp_panel_disable_show, mdss_mdp_panel_disable_store);
static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
static DEVICE_ATTR(lineptr_event, S_IRUGO, mdss_mdp_lineptr_show_event, NULL);
static DEVICE_ATTR(lineptr_value, S_IRUGO | S_IWUSR | S_IWGRP,
@@ -3454,6 +3560,7 @@ static struct attribute *mdp_overlay_sysfs_attrs[] = {
&dev_attr_dyn_pu.attr,
&dev_attr_msm_misr_en.attr,
&dev_attr_msm_cmd_autorefresh_en.attr,
+ &dev_attr_msm_disable_panel.attr,
&dev_attr_hist_event.attr,
&dev_attr_bl_event.attr,
&dev_attr_ad_event.attr,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
index 48235c5b85ba..5bd627853c59 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
@@ -1570,7 +1570,7 @@ static int pp_pa_dither_cache_params_v1_7(
res_data->strength = dither_data.strength;
res_data->matrix_sz = MDP_DITHER_DATA_V1_7_SZ;
ret = copy_from_user(res_data->matrix_data,
- (u8 *)dither_data.matrix_data,
+ (u8 *)((unsigned long)dither_data.matrix_data),
(MDP_DITHER_DATA_V1_7_SZ * sizeof(u32)));
if (ret) {
pr_err("failed to copy the dither matrix ret %d sz %zd", ret,
@@ -1700,8 +1700,8 @@ static int pp_igc_lut_cache_params_v3(struct mdp_igc_lut_data *config,
v3_cache_data->table_fmt = v3_kernel_data->table_fmt;
} else {
ret = copy_from_user(v3_cache_data->c0_c1_data,
- (u8 *)v3_usr_config.c0_c1_data,
- len * sizeof(u32));
+ (u8 *)((unsigned long)v3_usr_config.c0_c1_data),
+ len * sizeof(u32));
if (ret) {
pr_err("copy from user failed for c0_c1_data size %zd ret %d\n",
len * sizeof(u32), ret);
@@ -1709,8 +1709,8 @@ static int pp_igc_lut_cache_params_v3(struct mdp_igc_lut_data *config,
goto igc_config_exit;
}
ret = copy_from_user(v3_cache_data->c2_data,
- (u8 *)v3_usr_config.c2_data,
- len * sizeof(u32));
+ (u8 *)((unsigned long)v3_usr_config.c2_data),
+ len * sizeof(u32));
if (ret) {
pr_err("copy from user failed for c2_data size %zd ret %d\n",
len * sizeof(u32), ret);
@@ -1846,7 +1846,7 @@ static int pp_igc_lut_cache_params_pipe_v3(
}
} else {
if (copy_from_user(v3_cache_data->c0_c1_data,
- (u8 *)v3_usr_config.c0_c1_data,
+ (u8 *)((unsigned long)v3_usr_config.c0_c1_data),
IGC_LUT_ENTRIES * sizeof(u32))) {
pr_err("error in copying the c0_c1_data of size %zd\n",
IGC_LUT_ENTRIES * sizeof(u32));
@@ -1854,7 +1854,7 @@ static int pp_igc_lut_cache_params_pipe_v3(
goto igc_config_exit;
}
if (copy_from_user(v3_cache_data->c2_data,
- (u8 *)v3_usr_config.c2_data,
+ (u8 *)((unsigned long)v3_usr_config.c2_data),
IGC_LUT_ENTRIES * sizeof(u32))) {
pr_err("error in copying the c2_data of size %zd\n",
IGC_LUT_ENTRIES * sizeof(u32));
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index b2b647dcc017..a633528b5373 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -104,6 +104,7 @@ enum {
MDSS_PANEL_POWER_ON,
MDSS_PANEL_POWER_LP1,
MDSS_PANEL_POWER_LP2,
+ MDSS_PANEL_POWER_LCD_DISABLED,
};
enum {
@@ -265,6 +266,7 @@ enum mdss_intf_events {
MDSS_EVENT_DSI_RESET_WRITE_PTR,
MDSS_EVENT_PANEL_TIMING_SWITCH,
MDSS_EVENT_DEEP_COLOR,
+ MDSS_EVENT_DISABLE_PANEL,
MDSS_EVENT_MAX,
};
@@ -692,6 +694,7 @@ struct mdss_panel_info {
char panel_name[MDSS_MAX_PANEL_LEN];
struct mdss_mdp_pp_tear_check te;
+ struct mdss_mdp_pp_tear_check te_cached;
/*
* Value of 2 only when single DSI is configured with 2 DSC
@@ -789,6 +792,12 @@ struct mdss_panel_data {
/* To store dsc cfg name passed by bootloader */
char dsc_cfg_np_name[MDSS_MAX_PANEL_LEN];
struct mdss_panel_data *next;
+
+ /*
+ * Set when the power of the panel is disabled while dsi/mdp
+ * are still on; panel will recover after unblank
+ */
+ bool panel_disable_mode;
};
struct mdss_panel_debugfs_info {
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
index e8671942c2a0..785af63acabd 100644
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -71,10 +71,12 @@ static ssize_t fuse_passthrough_read_write_iter(struct kiocb *iocb,
struct fuse_file *ff;
struct file *fuse_file, *passthrough_filp;
struct inode *fuse_inode, *passthrough_inode;
+ struct fuse_conn *fc;
ff = iocb->ki_filp->private_data;
fuse_file = iocb->ki_filp;
passthrough_filp = ff->passthrough_filp;
+ fc = ff->fc;
/* lock passthrough file to prevent it from being released */
get_file(passthrough_filp);
@@ -88,7 +90,9 @@ static ssize_t fuse_passthrough_read_write_iter(struct kiocb *iocb,
ret_val = passthrough_filp->f_op->write_iter(iocb, iter);
if (ret_val >= 0 || ret_val == -EIOCBQUEUED) {
+ spin_lock(&fc->lock);
fsstack_copy_inode_size(fuse_inode, passthrough_inode);
+ spin_unlock(&fc->lock);
fsstack_copy_attr_times(fuse_inode, passthrough_inode);
}
} else {
diff --git a/include/dt-bindings/clock/qcom,gcc-msmfalcon.h b/include/dt-bindings/clock/qcom,gcc-msmfalcon.h
index 0bbcbd28af33..609a20422ed1 100644
--- a/include/dt-bindings/clock/qcom,gcc-msmfalcon.h
+++ b/include/dt-bindings/clock/qcom,gcc-msmfalcon.h
@@ -207,52 +207,4 @@
#define GCC_USB_30_BCR 7
#define GCC_USB_PHY_CFG_AHB2PHY_BCR 8
-/* RPM controlled clocks */
-#define RPM_CE1_CLK 1
-#define RPM_CE1_A_CLK 2
-#define RPM_CXO_CLK_SRC 3
-#define RPM_BIMC_CLK 4
-#define RPM_BIMC_A_CLK 5
-#define RPM_CNOC_CLK 6
-#define RPM_CNOC_A_CLK 7
-#define RPM_SNOC_CLK 8
-#define RPM_SNOC_A_CLK 9
-#define RPM_CNOC_PERIPH_CLK 10
-#define RPM_CNOC_PERIPH_A_CLK 11
-#define RPM_CNOC_PERIPH_KEEPALIVE_A_CLK 12
-#define RPM_LN_BB_CLK1 13
-#define RPM_LN_BB_CLK1_AO 14
-#define RPM_LN_BB_CLK1_PIN 15
-#define RPM_LN_BB_CLK1_PIN_AO 16
-#define RPM_BIMC_MSMBUS_CLK 17
-#define RPM_BIMC_MSMBUS_A_CLK 18
-#define RPM_CNOC_MSMBUS_CLK 19
-#define RPM_CNOC_MSMBUS_A_CLK 20
-#define RPM_CXO_CLK_SRC_AO 21
-#define RPM_CXO_DWC3_CLK 22
-#define RPM_CXO_LPM_CLK 23
-#define RPM_CXO_OTG_CLK 24
-#define RPM_CXO_PIL_LPASS_CLK 25
-#define RPM_CXO_PIL_SSC_CLK 26
-#define RPM_CXO_PIL_SPSS_CLK 27
-#define RPM_DIV_CLK1 28
-#define RPM_DIV_CLK1_AO 29
-#define RPM_IPA_CLK 30
-#define RPM_IPA_A_CLK 31
-#define RPM_MCD_CE1_CLK 32
-#define RPM_MMSSNOC_AXI_CLK 33
-#define RPM_MMSSNOC_AXI_A_CLK 34
-#define RPM_QCEDEV_CE1_CLK 35
-#define RPM_QCRYPTO_CE1_CLK 36
-#define RPM_QDSS_CLK 37
-#define RPM_QDSS_A_CLK 38
-#define RPM_QSEECOM_CE1_CLK 39
-#define RPM_RF_CLK2 40
-#define RPM_RF_CLK2_AO 41
-#define RPM_SCM_CE1_CLK 42
-#define RPM_SNOC_MSMBUS_CLK 43
-#define RPM_SNOC_MSMBUS_A_CLK 44
-#define RPM_AGGRE2_NOC_CLK 45
-#define RPM_AGGRE2_NOC_A_CLK 46
-
#endif
diff --git a/include/dt-bindings/clock/qcom,gpu-msmfalcon.h b/include/dt-bindings/clock/qcom,gpu-msmfalcon.h
index 427c6aae05d3..2ef1e34db3a1 100644
--- a/include/dt-bindings/clock/qcom,gpu-msmfalcon.h
+++ b/include/dt-bindings/clock/qcom,gpu-msmfalcon.h
@@ -14,27 +14,32 @@
#ifndef _DT_BINDINGS_CLK_MSM_GPU_FALCON_H
#define _DT_BINDINGS_CLK_MSM_GPU_FALCON_H
-#define GFX3D_CLK_SRC 0
-#define GPU_PLL0_PLL 1
-#define GPU_PLL0_PLL_OUT_AUX 2
-#define GPU_PLL0_PLL_OUT_AUX2 3
-#define GPU_PLL0_PLL_OUT_EARLY 4
-#define GPU_PLL0_PLL_OUT_MAIN 5
-#define GPU_PLL0_PLL_OUT_TEST 6
-#define GPU_PLL1_PLL 7
-#define GPU_PLL1_PLL_OUT_AUX 8
-#define GPU_PLL1_PLL_OUT_AUX2 9
-#define GPU_PLL1_PLL_OUT_EARLY 10
-#define GPU_PLL1_PLL_OUT_MAIN 11
-#define GPU_PLL1_PLL_OUT_TEST 12
-#define GPUCC_CXO_CLK 13
-#define GPUCC_GFX3D_CLK 14
-#define GPUCC_RBBMTIMER_CLK 15
-#define GPUCC_RBCPR_CLK 16
-#define RBBMTIMER_CLK_SRC 18
-#define RBCPR_CLK_SRC 19
+#define GFX3D_CLK_SRC 0
+#define GPU_PLL0_PLL 1
+#define GPU_PLL0_PLL_OUT_AUX 2
+#define GPU_PLL0_PLL_OUT_AUX2 3
+#define GPU_PLL0_PLL_OUT_EARLY 4
+#define GPU_PLL0_PLL_OUT_MAIN 5
+#define GPU_PLL0_PLL_OUT_TEST 6
+#define GPU_PLL1_PLL 7
+#define GPU_PLL1_PLL_OUT_AUX 8
+#define GPU_PLL1_PLL_OUT_AUX2 9
+#define GPU_PLL1_PLL_OUT_EARLY 10
+#define GPU_PLL1_PLL_OUT_MAIN 11
+#define GPU_PLL1_PLL_OUT_TEST 12
+#define GPUCC_CXO_CLK 13
+#define GPUCC_GFX3D_CLK 14
+#define GPUCC_RBBMTIMER_CLK 15
+#define GPUCC_RBCPR_CLK 16
+#define RBBMTIMER_CLK_SRC 17
+#define RBCPR_CLK_SRC 18
-#define GPU_CX_GDSC 0
-#define GPU_GX_GDSC 1
+#define GPU_CX_GDSC 0
+#define GPU_GX_GDSC 1
+
+#define GPUCC_GPU_CX_BCR 0
+#define GPUCC_GPU_GX_BCR 1
+#define GPUCC_RBCPR_BCR 2
+#define GPUCC_SPDM_BCR 3
#endif
diff --git a/include/linux/dma-mapping-fast.h b/include/linux/dma-mapping-fast.h
index aa9fcfe73162..ddd126c0fd85 100644
--- a/include/linux/dma-mapping-fast.h
+++ b/include/linux/dma-mapping-fast.h
@@ -16,6 +16,8 @@
#include <linux/iommu.h>
#include <linux/io-pgtable-fast.h>
+struct dma_iommu_mapping;
+
struct dma_fast_smmu_mapping {
struct device *dev;
struct iommu_domain *domain;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 56855724271c..f4f5af978c7c 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -650,8 +650,8 @@ static inline void iommu_device_unlink(struct device *dev, struct device *link)
{
}
-static int iommu_dma_supported(struct iommu_domain *domain, struct device *dev,
- u64 mask)
+static inline int iommu_dma_supported(struct iommu_domain *domain,
+ struct device *dev, u64 mask)
{
return -EINVAL;
}
diff --git a/include/linux/msm_dma_iommu_mapping.h b/include/linux/msm_dma_iommu_mapping.h
index 76451faa2073..73e69383b9b6 100644
--- a/include/linux/msm_dma_iommu_mapping.h
+++ b/include/linux/msm_dma_iommu_mapping.h
@@ -90,7 +90,7 @@ static inline void msm_dma_unmap_sg(struct device *dev,
{
}
-int msm_dma_unmap_all_for_dev(struct device *dev)
+static inline int msm_dma_unmap_all_for_dev(struct device *dev)
{
return 0;
}
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index b13ebe50c3d6..7c12823894df 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -212,6 +212,7 @@ struct pmic_revid_data {
u8 pmic_type;
u8 pmic_subtype;
const char *pmic_name;
+ int fab_id;
};
#ifdef CONFIG_QPNP_REVID
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 861f715a673d..9fe71c774543 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -121,6 +121,22 @@ extern int sysctl_sched_rt_runtime;
extern unsigned int sysctl_sched_cfs_bandwidth_slice;
#endif
+#ifdef CONFIG_SCHED_TUNE
+extern unsigned int sysctl_sched_cfs_boost;
+int sysctl_sched_cfs_boost_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length,
+ loff_t *ppos);
+static inline unsigned int get_sysctl_sched_cfs_boost(void)
+{
+ return sysctl_sched_cfs_boost;
+}
+#else
+static inline unsigned int get_sysctl_sched_cfs_boost(void)
+{
+ return 0;
+}
+#endif
+
#ifdef CONFIG_SCHED_AUTOGROUP
extern unsigned int sysctl_sched_autogroup_enabled;
#endif
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 3740366d9fc5..cef429cf3dce 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -502,7 +502,7 @@ extern void usb_hc_died(struct usb_hcd *hcd);
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
extern void usb_wakeup_notification(struct usb_device *hdev,
unsigned int portnum);
-
+extern void usb_flush_hub_wq(void);
extern void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum);
extern void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum);
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 8704b2e7cfbc..7e2f32883aa4 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -24,8 +24,6 @@ struct icnss_driver_ops {
void (*shutdown)(struct device *dev);
int (*reinit)(struct device *dev);
void (*crash_shutdown)(void *pdev);
- int (*suspend)(struct device *dev, pm_message_t state);
- int (*resume)(struct device *dev);
int (*pm_suspend)(struct device *dev);
int (*pm_resume)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
@@ -125,5 +123,6 @@ extern int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
u16 buf_len);
extern int icnss_wlan_set_dfs_nol(const void *info, u16 info_len);
extern int icnss_wlan_get_dfs_nol(void *info, u16 info_len);
+extern bool icnss_is_qmi_disable(void);
#endif /* _ICNSS_WLAN_H_ */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1a58a146c3b0..06b72b262395 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3678,6 +3678,8 @@ struct asm_softvolume_params {
#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 0x00010DDC
+#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 0x0001320C
+
#define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
#define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
@@ -3780,6 +3782,56 @@ struct asm_multi_channel_pcm_fmt_blk_v3 {
*/
} __packed;
+struct asm_multi_channel_pcm_fmt_blk_v4 {
+ uint16_t num_channels;
+/*
+ * Number of channels
+ * Supported values: 1 to 8
+ */
+
+ uint16_t bits_per_sample;
+/*
+ * Number of bits per sample per channel
+ * Supported values: 16, 24, 32
+ */
+
+ uint32_t sample_rate;
+/*
+ * Number of samples per second
+ * Supported values: 2000 to 48000, 96000,192000 Hz
+ */
+
+ uint16_t is_signed;
+/* Flag that indicates that PCM samples are signed (1) */
+
+ uint16_t sample_word_size;
+/*
+ * Size in bits of the word that holds a sample of a channel.
+ * Supported values: 12,24,32
+ */
+
+ uint8_t channel_mapping[8];
+/*
+ * Each element, i, in the array describes channel i inside the buffer where
+ * 0 <= i < num_channels. Unused channels are set to 0.
+ */
+ uint16_t endianness;
+/*
+ * Flag to indicate the endianness of the pcm sample
+ * Supported values: 0 - Little endian (all other formats)
+ * 1 - Big endian (AIFF)
+ */
+ uint16_t mode;
+/*
+ * Mode to provide additional info about the pcm input data.
+ * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b,
+ * Q31 for unpacked 24b or 32b)
+ * 15 - for 16 bit
+ * 23 - for 24b packed or 8.24 format
+ * 31 - for 24b unpacked or 32bit
+ */
+} __packed;
+
/*
* Payload of the multichannel PCM configuration parameters in
* the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 media format.
@@ -3790,6 +3842,16 @@ struct asm_multi_channel_pcm_fmt_blk_param_v3 {
struct asm_multi_channel_pcm_fmt_blk_v3 param;
} __packed;
+/*
+ * Payload of the multichannel PCM configuration parameters in
+ * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format.
+ */
+struct asm_multi_channel_pcm_fmt_blk_param_v4 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+ struct asm_multi_channel_pcm_fmt_blk_v4 param;
+} __packed;
+
struct asm_stream_cmd_set_encdec_param {
u32 param_id;
/* ID of the parameter. */
@@ -3825,6 +3887,79 @@ struct asm_dec_ddp_endp_param_v2 {
int endp_param_value;
} __packed;
+/*
+ * Payload of the multichannel PCM encoder configuration parameters in
+ * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format.
+ */
+
+struct asm_multi_channel_pcm_enc_cfg_v4 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ uint16_t num_channels;
+ /*
+ * Number of PCM channels.
+ * @values
+ * - 0 -- Native mode
+ * - 1 -- 8 channels
+ * Native mode indicates that encoding must be performed with the number
+ * of channels at the input.
+ */
+ uint16_t bits_per_sample;
+ /*
+ * Number of bits per sample per channel.
+ * @values 16, 24
+ */
+ uint32_t sample_rate;
+ /*
+ * Number of samples per second.
+ * @values 0, 8000 to 48000 Hz
+ * A value of 0 indicates the native sampling rate. Encoding is
+ * performed at the input sampling rate.
+ */
+ uint16_t is_signed;
+ /*
+ * Flag that indicates the PCM samples are signed (1). Currently, only
+ * signed PCM samples are supported.
+ */
+ uint16_t sample_word_size;
+ /*
+ * The size in bits of the word that holds a sample of a channel.
+ * @values 16, 24, 32
+ * 16-bit samples are always placed in 16-bit words:
+ * sample_word_size = 1.
+ * 24-bit samples can be placed in 32-bit words or in consecutive
+ * 24-bit words.
+ * - If sample_word_size = 32, 24-bit samples are placed in the
+ * most significant 24 bits of a 32-bit word.
+ * - If sample_word_size = 24, 24-bit samples are placed in
+ * 24-bit words. @tablebulletend
+ */
+ uint8_t channel_mapping[8];
+ /*
+ * Channel mapping array expected at the encoder output.
+ * Channel[i] mapping describes channel i inside the buffer, where
+ * 0 @le i < num_channels. All valid used channels must be present at
+ * the beginning of the array.
+ * If Native mode is set for the channels, this field is ignored.
+ * @values See Section @xref{dox:PcmChannelDefs}
+ */
+ uint16_t endianness;
+ /*
+ * Flag to indicate the endianness of the pcm sample
+ * Supported values: 0 - Little endian (all other formats)
+ * 1 - Big endian (AIFF)
+ */
+ uint16_t mode;
+ /*
+ * Mode to provide additional info about the pcm input data.
+ * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b,
+ * Q31 for unpacked 24b or 32b)
+ * 15 - for 16 bit
+ * 23 - for 24b packed or 8.24 format
+ * 31 - for 24b unpacked or 32bit
+ */
+} __packed;
/*
* Payload of the multichannel PCM encoder configuration parameters in
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 9ed6510cd0e1..31f7c02b54b3 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -281,7 +281,7 @@ void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode);
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate);
int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
- u32 rate, u16 afe_in_channels,
+ u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
struct afe_enc_config *enc_config);
int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
int l_ch, int r_ch, u32 enable);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 00129eb08888..f08bd73edb59 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -97,6 +97,24 @@
#define ASM_SHIFT_GAPLESS_MODE_FLAG 31
#define ASM_SHIFT_LAST_BUFFER_FLAG 30
+#define ASM_LITTLE_ENDIAN 0
+#define ASM_BIG_ENDIAN 1
+
+/* PCM_MEDIA_FORMAT_Version */
+enum {
+ PCM_MEDIA_FORMAT_V2 = 0,
+ PCM_MEDIA_FORMAT_V3,
+ PCM_MEDIA_FORMAT_V4,
+};
+
+/* PCM format modes in DSP */
+enum {
+ DEFAULT_QF = 0,
+ Q15 = 15,
+ Q23 = 23,
+ Q31 = 31,
+};
+
/* payload structure bytes */
#define READDONE_IDX_STATUS 0
#define READDONE_IDX_BUFADD_LSW 1
@@ -245,6 +263,9 @@ int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample);
+int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
int q6asm_open_write(struct audio_client *ac, uint32_t format
/*, uint16_t bits_per_sample*/);
@@ -257,6 +278,9 @@ int q6asm_open_shared_io(struct audio_client *ac,
int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample);
+int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, int32_t stream_id,
bool is_gapless_mode);
@@ -265,6 +289,10 @@ int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, int32_t stream_id,
bool is_gapless_mode);
+int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode);
+
int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
uint32_t passthrough_flag);
@@ -369,6 +397,13 @@ int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
bool use_back_flavor, u8 *channel_map,
uint16_t sample_word_size);
+int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, bool use_default_chmap,
+ bool use_back_flavor, u8 *channel_map,
+ uint16_t sample_word_size, uint16_t endianness,
+ uint16_t mode);
+
int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
uint32_t rate, uint32_t channels,
uint16_t bits_per_sample);
@@ -378,6 +413,13 @@ int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
uint16_t bits_per_sample,
uint16_t sample_word_size);
+int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode);
+
int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels);
@@ -427,6 +469,17 @@ int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
char *channel_map,
uint16_t sample_word_size);
+int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode);
+
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels,
bool use_default_chmap, char *channel_map);
@@ -444,6 +497,15 @@ int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
uint16_t bits_per_sample,
uint16_t sample_word_size);
+int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode);
+
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/include/sound/wcd-dsp-mgr.h b/include/sound/wcd-dsp-mgr.h
index 5adcbcf660ba..aa3b363e95e1 100644
--- a/include/sound/wcd-dsp-mgr.h
+++ b/include/sound/wcd-dsp-mgr.h
@@ -36,6 +36,9 @@ enum wdsp_cmpnt_type {
};
enum wdsp_event_type {
+ /* Initialization related */
+ WDSP_EVENT_POST_INIT,
+
/* Image download related */
WDSP_EVENT_PRE_DLOAD_CODE,
WDSP_EVENT_DLOAD_SECTION,
@@ -44,6 +47,8 @@ enum wdsp_event_type {
WDSP_EVENT_POST_DLOAD_DATA,
WDSP_EVENT_DLOAD_FAILED,
+ WDSP_EVENT_READ_SECTION,
+
/* DSP boot related */
WDSP_EVENT_PRE_BOOTUP,
WDSP_EVENT_DO_BOOT,
@@ -62,6 +67,7 @@ enum wdsp_event_type {
enum wdsp_intr {
WDSP_IPC1_INTR,
+ WDSP_ERR_INTR,
};
/*
@@ -86,6 +92,12 @@ struct wdsp_img_section {
u8 *data;
};
+struct wdsp_err_intr_arg {
+ bool mem_dumps_enabled;
+ u32 remote_start_addr;
+ size_t dump_size;
+};
+
/*
* wdsp_ops: ops/function callbacks for manager driver
* @register_cmpnt_ops: components will use this to register
@@ -109,7 +121,7 @@ struct wdsp_mgr_ops {
struct device *(*get_dev_for_cmpnt)(struct device *wdsp_dev,
enum wdsp_cmpnt_type type);
int (*intr_handler)(struct device *wdsp_dev,
- enum wdsp_intr intr);
+ enum wdsp_intr intr, void *arg);
int (*vote_for_dsp)(struct device *wdsp_dev, bool vote);
int (*suspend)(struct device *wdsp_dev);
int (*resume)(struct device *wdsp_dev);
diff --git a/include/trace/events/trace_msm_low_power.h b/include/trace/events/trace_msm_low_power.h
index 691df1b2689b..e14cab59e90a 100644
--- a/include/trace/events/trace_msm_low_power.h
+++ b/include/trace/events/trace_msm_low_power.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 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
@@ -43,6 +43,54 @@ TRACE_EVENT(cpu_power_select,
__entry->next_event_us)
);
+TRACE_EVENT(cpu_pred_select,
+
+ TP_PROTO(u32 predtype, u64 predicted, u32 tmr_time),
+
+ TP_ARGS(predtype, predicted, tmr_time),
+
+ TP_STRUCT__entry(
+ __field(u32, predtype)
+ __field(u64, predicted)
+ __field(u32, tmr_time)
+ ),
+
+ TP_fast_assign(
+ __entry->predtype = predtype;
+ __entry->predicted = predicted;
+ __entry->tmr_time = tmr_time;
+ ),
+
+ TP_printk("pred:%u time:%lu tmr_time:%u",
+ __entry->predtype, (unsigned long)__entry->predicted,
+ __entry->tmr_time)
+);
+
+TRACE_EVENT(cpu_pred_hist,
+
+ TP_PROTO(int idx, u32 resi, u32 sample, u32 tmr),
+
+ TP_ARGS(idx, resi, sample, tmr),
+
+ TP_STRUCT__entry(
+ __field(int, idx)
+ __field(u32, resi)
+ __field(u32, sample)
+ __field(u32, tmr)
+ ),
+
+ TP_fast_assign(
+ __entry->idx = idx;
+ __entry->resi = resi;
+ __entry->sample = sample;
+ __entry->tmr = tmr;
+ ),
+
+ TP_printk("idx:%d resi:%u sample:%u tmr:%u",
+ __entry->idx, __entry->resi,
+ __entry->sample, __entry->tmr)
+);
+
TRACE_EVENT(cpu_idle_enter,
TP_PROTO(int index),
diff --git a/include/uapi/linux/msm_vidc_dec.h b/include/uapi/linux/msm_vidc_dec.h
index f502c81665a4..48ce8e929fbf 100644
--- a/include/uapi/linux/msm_vidc_dec.h
+++ b/include/uapi/linux/msm_vidc_dec.h
@@ -486,10 +486,14 @@ enum vdec_interlaced_format {
VDEC_InterlaceInterleaveFrameBottomFieldFirst = 0x4
};
+#define VDEC_YUV_FORMAT_NV12_TP10_UBWC \
+ VDEC_YUV_FORMAT_NV12_TP10_UBWC
+
enum vdec_output_fromat {
VDEC_YUV_FORMAT_NV12 = 0x1,
VDEC_YUV_FORMAT_TILE_4x2 = 0x2,
- VDEC_YUV_FORMAT_NV12_UBWC = 0x3
+ VDEC_YUV_FORMAT_NV12_UBWC = 0x3,
+ VDEC_YUV_FORMAT_NV12_TP10_UBWC = 0x4
};
enum vdec_output_order {
diff --git a/include/uapi/sound/wcd-dsp-glink.h b/include/uapi/sound/wcd-dsp-glink.h
index db92e6b41340..39d128d370a0 100644
--- a/include/uapi/sound/wcd-dsp-glink.h
+++ b/include/uapi/sound/wcd-dsp-glink.h
@@ -8,7 +8,9 @@
enum {
WDSP_REG_PKT = 1,
WDSP_CMD_PKT,
+ WDSP_READY_PKT,
};
+#define WDSP_READY_PKT WDSP_READY_PKT
/*
* struct wdsp_reg_pkt - Glink channel information structure format
diff --git a/init/Kconfig b/init/Kconfig
index 6020a351c57b..311669332867 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1264,6 +1264,32 @@ config SCHED_AUTOGROUP
desktop applications. Task group autogeneration is currently based
upon task session.
+config SCHED_TUNE
+ bool "Boosting for CFS tasks (EXPERIMENTAL)"
+ help
+ This option enables the system-wide support for task boosting.
+ When this support is enabled a new sysctl interface is exposed to
+ userspace via:
+ /proc/sys/kernel/sched_cfs_boost
+ which allows to set a system-wide boost value in range [0..100].
+
+ The currently boosting strategy is implemented in such a way that:
+ - a 0% boost value requires to operate in "standard" mode by
+ scheduling all tasks at the minimum capacities required by their
+ workload demand
+ - a 100% boost value requires to push at maximum the task
+ performances, "regardless" of the incurred energy consumption
+
+ A boost value in between these two boundaries is used to bias the
+ power/performance trade-off, the higher the boost value the more the
+ scheduler is biased toward performance boosting instead of energy
+ efficiency.
+
+ Since this support exposes a single system-wide knob, the specified
+ boost value is applied to all (CFS) tasks in the system.
+
+ If unsure, say N.
+
config SYSFS_DEPRECATED
bool "Enable deprecated sysfs features to support old userspace tools"
depends on SYSFS
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 508b65690288..7d0d34c53e08 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -19,5 +19,6 @@ obj-$(CONFIG_SCHED_HMP) += hmp.o
obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
obj-$(CONFIG_SCHEDSTATS) += stats.o
obj-$(CONFIG_SCHED_DEBUG) += debug.o
+obj-$(CONFIG_SCHED_TUNE) += tune.o
obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o
obj-$(CONFIG_SCHED_CORE_CTL) += core_ctl.o
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 4489bec5d68a..df23b0365527 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -7220,6 +7220,10 @@ static inline void init_sd_lb_stats(struct sd_lb_stats *sds)
.avg_load = 0UL,
.sum_nr_running = 0,
.group_type = group_other,
+#ifdef CONFIG_SCHED_HMP
+ .sum_nr_big_tasks = 0UL,
+ .group_cpu_load = 0ULL,
+#endif
},
};
}
diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c
new file mode 100644
index 000000000000..4c44b1a4ad98
--- /dev/null
+++ b/kernel/sched/tune.c
@@ -0,0 +1,17 @@
+#include "sched.h"
+
+unsigned int sysctl_sched_cfs_boost __read_mostly;
+
+int
+sysctl_sched_cfs_boost_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+
+ if (ret || !write)
+ return ret;
+
+ return 0;
+}
+
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index cdce7d0f5a0e..8e2f4ab15498 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -631,6 +631,17 @@ static struct ctl_table kern_table[] = {
.extra1 = &one,
},
#endif
+#ifdef CONFIG_SCHED_TUNE
+ {
+ .procname = "sched_cfs_boost",
+ .data = &sysctl_sched_cfs_boost,
+ .maxlen = sizeof(sysctl_sched_cfs_boost),
+ .mode = 0644,
+ .proc_handler = &sysctl_sched_cfs_boost_handler,
+ .extra1 = &zero,
+ .extra2 = &one_hundred,
+ },
+#endif
#ifdef CONFIG_PROVE_LOCKING
{
.procname = "prove_locking",
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 36ea0d54e05b..902657d4cac5 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1020,7 +1020,7 @@ choice
config DEBUG_SPINLOCK_BITE_ON_BUG
bool "Cause a Watchdog Bite on Spinlock bug"
- depends on MSM_WATCHDOG_V2
+ depends on QCOM_WATCHDOG_V2
help
On a spinlock bug, cause a watchdog bite so that we can get the precise
state of the system captured at the time of spin dump. This is mutually
diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c
index 69246ac9cc87..ee8b27dbec64 100644
--- a/sound/soc/codecs/wcd-dsp-mgr.c
+++ b/sound/soc/codecs/wcd-dsp-mgr.c
@@ -16,6 +16,8 @@
#include <linux/stringify.h>
#include <linux/of.h>
#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include <soc/qcom/ramdump.h>
#include <sound/wcd-dsp-mgr.h>
#include "wcd-dsp-utils.h"
@@ -75,6 +77,32 @@ static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type);
#define WDSP_STATUS_IS_SET(wdsp, state) (wdsp->status & state)
+/* SSR relate status macros */
+#define WDSP_SSR_STATUS_WDSP_READY BIT(0)
+#define WDSP_SSR_STATUS_CDC_READY BIT(1)
+#define WDSP_SSR_STATUS_READY \
+ (WDSP_SSR_STATUS_WDSP_READY | WDSP_SSR_STATUS_CDC_READY)
+#define WDSP_SSR_READY_WAIT_TIMEOUT (10 * HZ)
+
+enum wdsp_ssr_type {
+
+ /* Init value, indicates there is no SSR in progress */
+ WDSP_SSR_TYPE_NO_SSR = 0,
+
+ /*
+ * Indicates WDSP crashed. The manager driver internally
+ * decides when to perform WDSP restart based on the
+ * users of wdsp. Hence there is no explicit WDSP_UP.
+ */
+ WDSP_SSR_TYPE_WDSP_DOWN,
+
+ /* Indicates codec hardware is down */
+ WDSP_SSR_TYPE_CDC_DOWN,
+
+ /* Indicates codec hardware is up, trigger to restart WDSP */
+ WDSP_SSR_TYPE_CDC_UP,
+};
+
struct wdsp_cmpnt {
/* OF node of the phandle */
@@ -96,6 +124,21 @@ struct wdsp_cmpnt {
struct wdsp_cmpnt_ops *ops;
};
+struct wdsp_ramdump_data {
+
+ /* Ramdump device */
+ void *rd_dev;
+
+ /* DMA address of the dump */
+ dma_addr_t rd_addr;
+
+ /* Virtual address of the dump */
+ void *rd_v_addr;
+
+ /* Data provided through error interrupt */
+ struct wdsp_err_intr_arg err_data;
+};
+
struct wdsp_mgr_priv {
/* Manager driver's struct device pointer */
@@ -130,8 +173,35 @@ struct wdsp_mgr_priv {
/* Lock for serializing ops called by components */
struct mutex api_mutex;
+
+ struct wdsp_ramdump_data dump_data;
+
+ /* SSR related */
+ enum wdsp_ssr_type ssr_type;
+ struct mutex ssr_mutex;
+ struct work_struct ssr_work;
+ u16 ready_status;
+ struct completion ready_compl;
};
+static char *wdsp_get_ssr_type_string(enum wdsp_ssr_type type)
+{
+ switch (type) {
+ case WDSP_SSR_TYPE_NO_SSR:
+ return "NO_SSR";
+ case WDSP_SSR_TYPE_WDSP_DOWN:
+ return "WDSP_DOWN";
+ case WDSP_SSR_TYPE_CDC_DOWN:
+ return "CDC_DOWN";
+ case WDSP_SSR_TYPE_CDC_UP:
+ return "CDC_UP";
+ default:
+ pr_err("%s: Invalid ssr_type %d\n",
+ __func__, type);
+ return "Invalid";
+ }
+}
+
static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type type)
{
switch (type) {
@@ -148,6 +218,26 @@ static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type type)
}
}
+static void __wdsp_clr_ready_locked(struct wdsp_mgr_priv *wdsp,
+ u16 value)
+{
+ wdsp->ready_status &= ~(value);
+ WDSP_DBG(wdsp, "ready_status = 0x%x", wdsp->ready_status);
+}
+
+static void __wdsp_set_ready_locked(struct wdsp_mgr_priv *wdsp,
+ u16 value, bool mark_complete)
+{
+ wdsp->ready_status |= value;
+ WDSP_DBG(wdsp, "ready_status = 0x%x", wdsp->ready_status);
+
+ if (mark_complete &&
+ wdsp->ready_status == WDSP_SSR_STATUS_READY) {
+ WDSP_DBG(wdsp, "marking ready completion");
+ complete(&wdsp->ready_compl);
+ }
+}
+
static void wdsp_broadcast_event_upseq(struct wdsp_mgr_priv *wdsp,
enum wdsp_event_type event,
void *data)
@@ -199,6 +289,18 @@ static int wdsp_unicast_event(struct wdsp_mgr_priv *wdsp,
return ret;
}
+static void wdsp_deinit_components(struct wdsp_mgr_priv *wdsp)
+{
+ struct wdsp_cmpnt *cmpnt;
+ int i;
+
+ for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) {
+ cmpnt = WDSP_GET_COMPONENT(wdsp, i);
+ if (cmpnt && cmpnt->ops && cmpnt->ops->deinit)
+ cmpnt->ops->deinit(cmpnt->cdev, cmpnt->priv_data);
+ }
+}
+
static int wdsp_init_components(struct wdsp_mgr_priv *wdsp)
{
struct wdsp_cmpnt *cmpnt;
@@ -230,6 +332,8 @@ static int wdsp_init_components(struct wdsp_mgr_priv *wdsp)
cmpnt->ops->deinit(cmpnt->cdev,
cmpnt->priv_data);
}
+ } else {
+ wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_INIT, NULL);
}
return ret;
@@ -272,6 +376,7 @@ static int wdsp_download_segments(struct wdsp_mgr_priv *wdsp,
struct wdsp_cmpnt *ctl;
struct wdsp_img_segment *seg = NULL;
enum wdsp_event_type pre, post;
+ long status;
int ret;
ctl = WDSP_GET_COMPONENT(wdsp, WDSP_CMPNT_CONTROL);
@@ -279,9 +384,11 @@ static int wdsp_download_segments(struct wdsp_mgr_priv *wdsp,
if (type == WDSP_ELF_FLAG_RE) {
pre = WDSP_EVENT_PRE_DLOAD_CODE;
post = WDSP_EVENT_POST_DLOAD_CODE;
+ status = WDSP_STATUS_CODE_DLOADED;
} else if (type == WDSP_ELF_FLAG_WRITE) {
pre = WDSP_EVENT_PRE_DLOAD_DATA;
post = WDSP_EVENT_POST_DLOAD_DATA;
+ status = WDSP_STATUS_DATA_DLOADED;
} else {
WDSP_ERR(wdsp, "Invalid type %u", type);
return -EINVAL;
@@ -312,6 +419,8 @@ static int wdsp_download_segments(struct wdsp_mgr_priv *wdsp,
}
}
+ WDSP_SET_STATUS(wdsp, status);
+
/* Notify all components that image is downloaded */
wdsp_broadcast_event_downseq(wdsp, post, NULL);
@@ -321,42 +430,47 @@ done:
return ret;
}
-static void wdsp_load_fw_image(struct work_struct *work)
+static int wdsp_init_and_dload_code_sections(struct wdsp_mgr_priv *wdsp)
{
- struct wdsp_mgr_priv *wdsp;
- struct wdsp_cmpnt *cmpnt;
- int ret, idx;
-
- wdsp = container_of(work, struct wdsp_mgr_priv, load_fw_work);
- if (!wdsp) {
- pr_err("%s: Invalid private_data\n", __func__);
- goto done;
- }
+ int ret;
+ bool is_initialized;
- /* Initialize the components first */
- ret = wdsp_init_components(wdsp);
- if (IS_ERR_VALUE(ret))
- goto done;
+ is_initialized = WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_INITIALIZED);
- /* Set init done status */
- WDSP_SET_STATUS(wdsp, WDSP_STATUS_INITIALIZED);
+ if (!is_initialized) {
+ /* Components are not initialized yet, initialize them */
+ ret = wdsp_init_components(wdsp);
+ if (IS_ERR_VALUE(ret)) {
+ WDSP_ERR(wdsp, "INIT failed, err = %d", ret);
+ goto done;
+ }
+ WDSP_SET_STATUS(wdsp, WDSP_STATUS_INITIALIZED);
+ }
/* Download the read-execute sections of image */
ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_RE);
if (IS_ERR_VALUE(ret)) {
WDSP_ERR(wdsp, "Error %d to download code sections", ret);
- for (idx = 0; idx < WDSP_CMPNT_TYPE_MAX; idx++) {
- cmpnt = WDSP_GET_COMPONENT(wdsp, idx);
- if (cmpnt->ops && cmpnt->ops->deinit)
- cmpnt->ops->deinit(cmpnt->cdev,
- cmpnt->priv_data);
- }
- WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_INITIALIZED);
+ goto done;
}
-
- WDSP_SET_STATUS(wdsp, WDSP_STATUS_CODE_DLOADED);
done:
- return;
+ return ret;
+}
+
+static void wdsp_load_fw_image(struct work_struct *work)
+{
+ struct wdsp_mgr_priv *wdsp;
+ int ret;
+
+ wdsp = container_of(work, struct wdsp_mgr_priv, load_fw_work);
+ if (!wdsp) {
+ pr_err("%s: Invalid private_data\n", __func__);
+ return;
+ }
+
+ ret = wdsp_init_and_dload_code_sections(wdsp);
+ if (IS_ERR_VALUE(ret))
+ WDSP_ERR(wdsp, "dload code sections failed, err = %d", ret);
}
static int wdsp_enable_dsp(struct wdsp_mgr_priv *wdsp)
@@ -377,8 +491,6 @@ static int wdsp_enable_dsp(struct wdsp_mgr_priv *wdsp)
goto done;
}
- WDSP_SET_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED);
-
wdsp_broadcast_event_upseq(wdsp, WDSP_EVENT_PRE_BOOTUP, NULL);
ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL,
@@ -399,6 +511,21 @@ static int wdsp_disable_dsp(struct wdsp_mgr_priv *wdsp)
{
int ret;
+ WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+
+ /*
+ * If Disable happened while SSR is in progress, then set the SSR
+ * ready status indicating WDSP is now ready. Ignore the disable
+ * event here and let the SSR handler go through shutdown.
+ */
+ if (wdsp->ssr_type != WDSP_SSR_TYPE_NO_SSR) {
+ __wdsp_set_ready_locked(wdsp, WDSP_SSR_STATUS_WDSP_READY, true);
+ WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+ return 0;
+ }
+
+ WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+
/* Make sure wdsp is in good state */
if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_BOOTED)) {
WDSP_ERR(wdsp, "wdsp in invalid state 0x%x", wdsp->status);
@@ -478,8 +605,190 @@ static struct device *wdsp_get_dev_for_cmpnt(struct device *wdsp_dev,
return cmpnt->cdev;
}
+static void wdsp_collect_ramdumps(struct wdsp_mgr_priv *wdsp)
+{
+ struct wdsp_img_section img_section;
+ struct wdsp_err_intr_arg *data = &wdsp->dump_data.err_data;
+ struct ramdump_segment rd_seg;
+ int ret = 0;
+
+ if (wdsp->ssr_type != WDSP_SSR_TYPE_WDSP_DOWN ||
+ !data->mem_dumps_enabled) {
+ WDSP_DBG(wdsp, "cannot dump memory, ssr_type %s, dumps %s",
+ wdsp_get_ssr_type_string(wdsp->ssr_type),
+ !(data->mem_dumps_enabled) ? "disabled" : "enabled");
+ goto done;
+ }
+
+ if (data->dump_size == 0 ||
+ data->remote_start_addr < wdsp->base_addr) {
+ WDSP_ERR(wdsp, "Invalid start addr 0x%x or dump_size 0x%zx",
+ data->remote_start_addr, data->dump_size);
+ goto done;
+ }
+
+ if (!wdsp->dump_data.rd_dev) {
+ WDSP_ERR(wdsp, "Ramdump device is not setup");
+ goto done;
+ }
+
+ WDSP_DBG(wdsp, "base_addr 0x%x, dump_start_addr 0x%x, dump_size 0x%zx",
+ wdsp->base_addr, data->remote_start_addr, data->dump_size);
+
+ /* Allocate memory for dumps */
+ wdsp->dump_data.rd_v_addr = dma_alloc_coherent(wdsp->mdev,
+ data->dump_size,
+ &wdsp->dump_data.rd_addr,
+ GFP_KERNEL);
+ if (!wdsp->dump_data.rd_v_addr)
+ goto done;
+
+ img_section.addr = data->remote_start_addr - wdsp->base_addr;
+ img_section.size = data->dump_size;
+ img_section.data = wdsp->dump_data.rd_v_addr;
+
+ ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_TRANSPORT,
+ WDSP_EVENT_READ_SECTION,
+ &img_section);
+ if (IS_ERR_VALUE(ret)) {
+ WDSP_ERR(wdsp, "Failed to read dumps, size 0x%zx at addr 0x%x",
+ img_section.size, img_section.addr);
+ goto err_read_dumps;
+ }
+
+ rd_seg.address = (unsigned long) wdsp->dump_data.rd_v_addr;
+ rd_seg.size = img_section.size;
+ rd_seg.v_address = wdsp->dump_data.rd_v_addr;
+
+ ret = do_ramdump(wdsp->dump_data.rd_dev, &rd_seg, 1);
+ if (IS_ERR_VALUE(ret))
+ WDSP_ERR(wdsp, "do_ramdump failed with error %d", ret);
+
+err_read_dumps:
+ dma_free_coherent(wdsp->mdev, data->dump_size,
+ wdsp->dump_data.rd_v_addr, wdsp->dump_data.rd_addr);
+done:
+ return;
+}
+
+static void wdsp_ssr_work_fn(struct work_struct *work)
+{
+ struct wdsp_mgr_priv *wdsp;
+ int ret;
+
+ wdsp = container_of(work, struct wdsp_mgr_priv, ssr_work);
+ if (!wdsp) {
+ pr_err("%s: Invalid private_data\n", __func__);
+ return;
+ }
+
+ WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+
+ wdsp_collect_ramdumps(wdsp);
+
+ /* In case of CDC_DOWN event, the DSP is already shutdown */
+ if (wdsp->ssr_type != WDSP_SSR_TYPE_CDC_DOWN) {
+ ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL,
+ WDSP_EVENT_DO_SHUTDOWN, NULL);
+ if (IS_ERR_VALUE(ret))
+ WDSP_ERR(wdsp, "Failed WDSP shutdown, err = %d", ret);
+ }
+ wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_SHUTDOWN, NULL);
+ WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_BOOTED);
+
+ WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+ ret = wait_for_completion_timeout(&wdsp->ready_compl,
+ WDSP_SSR_READY_WAIT_TIMEOUT);
+ WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+ if (ret == 0) {
+ WDSP_ERR(wdsp, "wait_for_ready timed out, status = 0x%x",
+ wdsp->ready_status);
+ goto done;
+ }
+
+ /* Data sections are to downloaded per WDSP boot */
+ WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED);
+
+ /*
+ * Even though code section could possible be retained on DSP
+ * crash, go ahead and still re-download just to avoid any
+ * memory corruption from previous crash.
+ */
+ WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_CODE_DLOADED);
+
+ /* If codec went down, then all components must be re-initialized */
+ if (wdsp->ssr_type == WDSP_SSR_TYPE_CDC_DOWN) {
+ wdsp_deinit_components(wdsp);
+ WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_INITIALIZED);
+ }
+
+ ret = wdsp_init_and_dload_code_sections(wdsp);
+ if (IS_ERR_VALUE(ret)) {
+ WDSP_ERR(wdsp, "Failed to dload code sections err = %d",
+ ret);
+ goto done;
+ }
+
+ /* SSR handling is finished, mark SSR type as NO_SSR */
+ wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR;
+done:
+ WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+}
+
+static int wdsp_ssr_handler(struct wdsp_mgr_priv *wdsp, void *arg,
+ enum wdsp_ssr_type ssr_type)
+{
+ enum wdsp_ssr_type current_ssr_type;
+ struct wdsp_err_intr_arg *err_data;
+
+ WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+
+ current_ssr_type = wdsp->ssr_type;
+ WDSP_DBG(wdsp, "Current ssr_type %s, handling ssr_type %s",
+ wdsp_get_ssr_type_string(current_ssr_type),
+ wdsp_get_ssr_type_string(ssr_type));
+ wdsp->ssr_type = ssr_type;
+
+ if (arg) {
+ err_data = (struct wdsp_err_intr_arg *) arg;
+ memcpy(&wdsp->dump_data.err_data, err_data,
+ sizeof(*err_data));
+ } else {
+ memset(&wdsp->dump_data.err_data, 0,
+ sizeof(wdsp->dump_data.err_data));
+ }
+
+ switch (ssr_type) {
+
+ case WDSP_SSR_TYPE_WDSP_DOWN:
+ case WDSP_SSR_TYPE_CDC_DOWN:
+ __wdsp_clr_ready_locked(wdsp, WDSP_SSR_STATUS_WDSP_READY);
+ if (ssr_type == WDSP_SSR_TYPE_CDC_DOWN)
+ __wdsp_clr_ready_locked(wdsp,
+ WDSP_SSR_STATUS_CDC_READY);
+ wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_PRE_SHUTDOWN,
+ NULL);
+ schedule_work(&wdsp->ssr_work);
+ break;
+
+ case WDSP_SSR_TYPE_CDC_UP:
+ __wdsp_set_ready_locked(wdsp, WDSP_SSR_STATUS_CDC_READY, true);
+ break;
+
+ default:
+ WDSP_ERR(wdsp, "undefined ssr_type %d\n", ssr_type);
+ /* Revert back the ssr_type for undefined events */
+ wdsp->ssr_type = current_ssr_type;
+ break;
+ }
+
+ WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+
+ return 0;
+}
+
static int wdsp_intr_handler(struct device *wdsp_dev,
- enum wdsp_intr intr)
+ enum wdsp_intr intr, void *arg)
{
struct wdsp_mgr_priv *wdsp;
int ret;
@@ -495,6 +804,9 @@ static int wdsp_intr_handler(struct device *wdsp_dev,
ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_IPC,
WDSP_EVENT_IPC1_INTR, NULL);
break;
+ case WDSP_ERR_INTR:
+ ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_WDSP_DOWN);
+ break;
default:
ret = -EINVAL;
break;
@@ -585,6 +897,11 @@ static int wdsp_mgr_bind(struct device *dev)
wdsp->ops = &wdsp_ops;
+ /* Setup ramdump device */
+ wdsp->dump_data.rd_dev = create_ramdump_device("wdsp", dev);
+ if (!wdsp->dump_data.rd_dev)
+ dev_info(dev, "%s: create_ramdump_device failed\n", __func__);
+
ret = component_bind_all(dev, wdsp->ops);
if (IS_ERR_VALUE(ret))
WDSP_ERR(wdsp, "component_bind_all failed %d\n", ret);
@@ -616,6 +933,11 @@ static void wdsp_mgr_unbind(struct device *dev)
component_unbind_all(dev, wdsp->ops);
+ if (wdsp->dump_data.rd_dev) {
+ destroy_ramdump_device(wdsp->dump_data.rd_dev);
+ wdsp->dump_data.rd_dev = NULL;
+ }
+
/* Clear all status bits */
wdsp->status = 0x00;
@@ -746,6 +1068,12 @@ static int wdsp_mgr_probe(struct platform_device *pdev)
INIT_WORK(&wdsp->load_fw_work, wdsp_load_fw_image);
INIT_LIST_HEAD(wdsp->seg_list);
mutex_init(&wdsp->api_mutex);
+ mutex_init(&wdsp->ssr_mutex);
+ wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR;
+ wdsp->ready_status = WDSP_SSR_STATUS_READY;
+ INIT_WORK(&wdsp->ssr_work, wdsp_ssr_work_fn);
+ init_completion(&wdsp->ready_compl);
+ arch_setup_dma_ops(wdsp->mdev, 0, 0, NULL, 0);
dev_set_drvdata(mdev, wdsp);
ret = component_master_add_with_match(mdev, &wdsp_master_ops,
@@ -759,6 +1087,7 @@ static int wdsp_mgr_probe(struct platform_device *pdev)
err_master_add:
mutex_destroy(&wdsp->api_mutex);
+ mutex_destroy(&wdsp->ssr_mutex);
err_dt_parse:
devm_kfree(mdev, wdsp->seg_list);
devm_kfree(mdev, wdsp);
@@ -775,6 +1104,7 @@ static int wdsp_mgr_remove(struct platform_device *pdev)
component_master_del(mdev, &wdsp_master_ops);
mutex_destroy(&wdsp->api_mutex);
+ mutex_destroy(&wdsp->ssr_mutex);
devm_kfree(mdev, wdsp->seg_list);
devm_kfree(mdev, wdsp);
dev_set_drvdata(mdev, NULL);
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index d207d9ccda34..3cbc1e7821cf 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -2318,7 +2318,7 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc,
schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
usecs_to_jiffies(FW_READ_TIMEOUT));
else
- pr_err("%s: Skipping to read mbhc fw, 0x%p %p\n",
+ pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
__func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
}
pr_debug("%s: leave %d\n", __func__, rc);
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 3049d87c6c05..60efcb174740 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -639,12 +639,10 @@ static int wcd_spi_init(struct spi_device *spi)
WCD_SPI_SLAVE_TRNS_LEN,
0xFFFF0000,
(WCD_SPI_RW_MULTI_MAX_LEN / 4) << 16);
-done:
- return ret;
-
err_wr_en:
wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE,
WCD_SPI_CLK_FLAG_IMMEDIATE);
+done:
return ret;
}
@@ -813,6 +811,27 @@ static int wdsp_spi_dload_section(struct spi_device *spi,
return ret;
}
+static int wdsp_spi_read_section(struct spi_device *spi, void *data)
+{
+ struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+ struct wdsp_img_section *sec = data;
+ struct wcd_spi_msg msg;
+ int ret;
+
+ msg.remote_addr = sec->addr + wcd_spi->mem_base_addr;
+ msg.data = sec->data;
+ msg.len = sec->size;
+
+ dev_dbg(&spi->dev, "%s: addr = 0x%x, size = 0x%zx\n",
+ __func__, msg.remote_addr, msg.len);
+
+ ret = wcd_spi_data_xfer(spi, &msg, WCD_SPI_XFER_READ);
+ if (IS_ERR_VALUE(ret))
+ dev_err(&spi->dev, "%s: fail addr (0x%x) size (0x%zx)\n",
+ __func__, msg.remote_addr, msg.len);
+ return ret;
+}
+
static int wdsp_spi_event_handler(struct device *dev, void *priv_data,
enum wdsp_event_type event,
void *data)
@@ -824,6 +843,7 @@ static int wdsp_spi_event_handler(struct device *dev, void *priv_data,
__func__, event);
switch (event) {
+ case WDSP_EVENT_PRE_DLOAD_CODE:
case WDSP_EVENT_PRE_DLOAD_DATA:
ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE,
WCD_SPI_CLK_FLAG_IMMEDIATE);
@@ -846,6 +866,11 @@ static int wdsp_spi_event_handler(struct device *dev, void *priv_data,
case WDSP_EVENT_DLOAD_SECTION:
ret = wdsp_spi_dload_section(spi, data);
break;
+
+ case WDSP_EVENT_READ_SECTION:
+ ret = wdsp_spi_read_section(spi, data);
+ break;
+
default:
dev_dbg(&spi->dev, "%s: Unhandled event %d\n",
__func__, event);
diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c
index a8d6e0fa4732..fa396aa55ac9 100644
--- a/sound/soc/codecs/wcd9330.c
+++ b/sound/soc/codecs/wcd9330.c
@@ -5474,7 +5474,7 @@ static int tomtom_set_channel_map(struct snd_soc_dai *dai,
struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(dai->codec);
struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
if (!tx_slot || !rx_slot) {
- pr_err("%s: Invalid tx_slot=%p, rx_slot=%p\n",
+ pr_err("%s: Invalid tx_slot=%pK, rx_slot=%pK\n",
__func__, tx_slot, rx_slot);
return -EINVAL;
}
@@ -5519,7 +5519,7 @@ static int tomtom_get_channel_map(struct snd_soc_dai *dai,
case AIF2_PB:
case AIF3_PB:
if (!rx_slot || !rx_num) {
- pr_err("%s: Invalid rx_slot %p or rx_num %p\n",
+ pr_err("%s: Invalid rx_slot %pK or rx_num %pK\n",
__func__, rx_slot, rx_num);
return -EINVAL;
}
@@ -5538,7 +5538,7 @@ static int tomtom_get_channel_map(struct snd_soc_dai *dai,
case AIF4_VIFEED:
case AIF4_MAD_TX:
if (!tx_slot || !tx_num) {
- pr_err("%s: Invalid tx_slot %p or tx_num %p\n",
+ pr_err("%s: Invalid tx_slot %pK or tx_num %pK\n",
__func__, tx_slot, tx_num);
return -EINVAL;
}
@@ -8228,7 +8228,7 @@ static void tomtom_compute_impedance(struct wcd9xxx_mbhc *mbhc, s16 *l, s16 *r,
struct tomtom_priv *tomtom;
if (!mbhc) {
- pr_err("%s: Invalid parameters mbhc = %p\n",
+ pr_err("%s: Invalid parameters mbhc = %pK\n",
__func__, mbhc);
return;
}
@@ -8287,7 +8287,7 @@ static void tomtom_zdet_error_approx(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
const int shift = TOMTOM_ZDET_ERROR_APPROX_SHIFT;
if (!zl || !zr || !mbhc) {
- pr_err("%s: Invalid parameters zl = %p zr = %p, mbhc = %p\n",
+ pr_err("%s: Invalid parameters zl = %pK zr = %pK, mbhc = %pK\n",
__func__, zl, zr, mbhc);
return;
}
@@ -8602,7 +8602,7 @@ static int tomtom_codec_fll_enable(struct snd_soc_codec *codec,
struct wcd9xxx *wcd9xxx;
if (!codec || !codec->control_data) {
- pr_err("%s: Invalid codec handle, %p\n",
+ pr_err("%s: Invalid codec handle, %pK\n",
__func__, codec);
return -EINVAL;
}
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 2cc895cf1d32..46b8e7f72eb8 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -11080,7 +11080,7 @@ static int tasha_get_channel_map(struct snd_soc_dai *dai,
case AIF4_PB:
case AIF_MIX1_PB:
if (!rx_slot || !rx_num) {
- pr_err("%s: Invalid rx_slot %p or rx_num %p\n",
+ pr_err("%s: Invalid rx_slot %pK or rx_num %pK\n",
__func__, rx_slot, rx_num);
return -EINVAL;
}
@@ -11099,7 +11099,7 @@ static int tasha_get_channel_map(struct snd_soc_dai *dai,
case AIF4_MAD_TX:
case AIF4_VIFEED:
if (!tx_slot || !tx_num) {
- pr_err("%s: Invalid tx_slot %p or tx_num %p\n",
+ pr_err("%s: Invalid tx_slot %pK or tx_num %pK\n",
__func__, tx_slot, tx_num);
return -EINVAL;
}
@@ -11137,7 +11137,7 @@ static int tasha_set_channel_map(struct snd_soc_dai *dai,
core = dev_get_drvdata(dai->codec->dev->parent);
if (!tx_slot || !rx_slot) {
- pr_err("%s: Invalid tx_slot=%p, rx_slot=%p\n",
+ pr_err("%s: Invalid tx_slot=%pK, rx_slot=%pK\n",
__func__, tx_slot, rx_slot);
return -EINVAL;
}
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
index 225b3a755f66..e649770297f1 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -28,19 +28,22 @@
#define WCD_MEM_ENABLE_MAX_RETRIES 20
#define WCD_DSP_BOOT_TIMEOUT_MS 3000
#define WCD_SYSFS_ENTRY_MAX_LEN 8
-
-#define WCD_CNTL_MUTEX_LOCK(codec, lock) \
-{ \
- dev_dbg(codec->dev, "mutex_lock(%s)\n", \
- __func__); \
- mutex_lock(&lock); \
+#define WCD_PROCFS_ENTRY_MAX_LEN 16
+#define WCD_934X_RAMDUMP_START_ADDR 0x20100000
+#define WCD_934X_RAMDUMP_SIZE ((1024 * 1024) - 128)
+
+#define WCD_CNTL_MUTEX_LOCK(codec, lock) \
+{ \
+ dev_dbg(codec->dev, "%s: mutex_lock(%s)\n", \
+ __func__, __stringify_1(lock)); \
+ mutex_lock(&lock); \
}
-#define WCD_CNTL_MUTEX_UNLOCK(codec, lock) \
-{ \
- dev_dbg(codec->dev, "mutex_unlock(%s)\n",\
- __func__); \
- mutex_unlock(&lock); \
+#define WCD_CNTL_MUTEX_UNLOCK(codec, lock) \
+{ \
+ dev_dbg(codec->dev, "%s: mutex_unlock(%s)\n", \
+ __func__, __stringify_1(lock)); \
+ mutex_unlock(&lock); \
}
struct wcd_cntl_attribute {
@@ -147,6 +150,97 @@ static struct kobj_type wcd_cntl_ktype = {
.sysfs_ops = &wcd_cntl_sysfs_ops,
};
+static void wcd_cntl_change_online_state(struct wcd_dsp_cntl *cntl,
+ u8 online)
+{
+ struct wdsp_ssr_entry *ssr_entry = &cntl->ssr_entry;
+ unsigned long ret;
+
+ WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
+ ssr_entry->offline = !online;
+ /* Make sure the write is complete */
+ wmb();
+ ret = xchg(&ssr_entry->offline_change, 1);
+ wake_up_interruptible(&ssr_entry->offline_poll_wait);
+ dev_dbg(cntl->codec->dev,
+ "%s: requested %u, offline %u offline_change %u, ret = %ldn",
+ __func__, online, ssr_entry->offline,
+ ssr_entry->offline_change, ret);
+ WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
+}
+
+static ssize_t wdsp_ssr_entry_read(struct snd_info_entry *entry,
+ void *file_priv_data, struct file *file,
+ char __user *buf, size_t count, loff_t pos)
+{
+ int len = 0;
+ char buffer[WCD_PROCFS_ENTRY_MAX_LEN];
+ struct wcd_dsp_cntl *cntl;
+ struct wdsp_ssr_entry *ssr_entry;
+ ssize_t ret;
+ u8 offline;
+
+ cntl = (struct wcd_dsp_cntl *) entry->private_data;
+ if (!cntl) {
+ pr_err("%s: Invalid private data for SSR procfs entry\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ssr_entry = &cntl->ssr_entry;
+
+ WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
+ offline = ssr_entry->offline;
+ /* Make sure the read is complete */
+ rmb();
+ dev_dbg(cntl->codec->dev, "%s: offline = %s\n", __func__,
+ offline ? "true" : "false");
+ len = snprintf(buffer, sizeof(buffer), "%s\n",
+ offline ? "OFFLINE" : "ONLINE");
+ ret = simple_read_from_buffer(buf, count, &pos, buffer, len);
+ WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
+
+ return ret;
+}
+
+static unsigned int wdsp_ssr_entry_poll(struct snd_info_entry *entry,
+ void *private_data, struct file *file,
+ poll_table *wait)
+{
+ struct wcd_dsp_cntl *cntl;
+ struct wdsp_ssr_entry *ssr_entry;
+ unsigned int ret = 0;
+
+ if (!entry || !entry->private_data) {
+ pr_err("%s: %s is NULL\n", __func__,
+ (!entry) ? "entry" : "private_data");
+ return -EINVAL;
+ }
+
+ cntl = (struct wcd_dsp_cntl *) entry->private_data;
+ ssr_entry = &cntl->ssr_entry;
+
+ dev_dbg(cntl->codec->dev, "%s: Poll wait, offline = %u\n",
+ __func__, ssr_entry->offline);
+ poll_wait(file, &ssr_entry->offline_poll_wait, wait);
+ dev_dbg(cntl->codec->dev, "%s: Woken up Poll wait, offline = %u\n",
+ __func__, ssr_entry->offline);
+
+ WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
+ if (xchg(&ssr_entry->offline_change, 0))
+ ret = POLLIN | POLLPRI | POLLRDNORM;
+ dev_dbg(cntl->codec->dev, "%s: ret (%d) from poll_wait\n",
+ __func__, ret);
+ WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
+
+ return ret;
+}
+
+static struct snd_info_entry_ops wdsp_ssr_entry_ops = {
+ .read = wdsp_ssr_entry_read,
+ .poll = wdsp_ssr_entry_poll,
+};
+
static int wcd_cntl_cpe_fll_calibrate(struct wcd_dsp_cntl *cntl)
{
struct snd_soc_codec *codec = cntl->codec;
@@ -553,7 +647,8 @@ static irqreturn_t wcd_cntl_ipc_irq(int irq, void *data)
if (cntl->m_dev && cntl->m_ops &&
cntl->m_ops->intr_handler)
- ret = cntl->m_ops->intr_handler(cntl->m_dev, WDSP_IPC1_INTR);
+ ret = cntl->m_ops->intr_handler(cntl->m_dev, WDSP_IPC1_INTR,
+ NULL);
else
ret = -EINVAL;
@@ -568,8 +663,10 @@ static irqreturn_t wcd_cntl_err_irq(int irq, void *data)
{
struct wcd_dsp_cntl *cntl = data;
struct snd_soc_codec *codec = cntl->codec;
+ struct wdsp_err_intr_arg arg;
u16 status = 0;
u8 reg_val;
+ int ret = 0;
reg_val = snd_soc_read(codec, WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A);
status = status | reg_val;
@@ -580,6 +677,23 @@ static irqreturn_t wcd_cntl_err_irq(int irq, void *data)
dev_info(codec->dev, "%s: error interrupt status = 0x%x\n",
__func__, status);
+ if ((status & cntl->irqs.fatal_irqs) &&
+ (cntl->m_dev && cntl->m_ops && cntl->m_ops->intr_handler)) {
+ arg.mem_dumps_enabled = cntl->ramdump_enable;
+ arg.remote_start_addr = WCD_934X_RAMDUMP_START_ADDR;
+ arg.dump_size = WCD_934X_RAMDUMP_SIZE;
+ ret = cntl->m_ops->intr_handler(cntl->m_dev, WDSP_ERR_INTR,
+ &arg);
+ if (IS_ERR_VALUE(ret))
+ dev_err(cntl->codec->dev,
+ "%s: Failed to handle fatal irq 0x%x\n",
+ __func__, status & cntl->irqs.fatal_irqs);
+ wcd_cntl_change_online_state(cntl, 0);
+ } else {
+ dev_err(cntl->codec->dev, "%s: Invalid intr_handler\n",
+ __func__);
+ }
+
return IRQ_HANDLED;
}
@@ -591,10 +705,15 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
int ret = 0;
switch (event) {
+ case WDSP_EVENT_POST_INIT:
case WDSP_EVENT_POST_DLOAD_CODE:
case WDSP_EVENT_DLOAD_FAILED:
case WDSP_EVENT_POST_SHUTDOWN:
+ if (event == WDSP_EVENT_POST_DLOAD_CODE)
+ /* Mark DSP online since code download is complete */
+ wcd_cntl_change_online_state(cntl, 1);
+
/* Disable CPAR */
wcd_cntl_cpar_ctrl(cntl, false);
/* Disable all the clocks */
@@ -605,12 +724,8 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
__func__, ret);
break;
- case WDSP_EVENT_PRE_DLOAD_CODE:
-
- wcd_cntl_enable_memory(cntl);
- break;
-
case WDSP_EVENT_PRE_DLOAD_DATA:
+ case WDSP_EVENT_PRE_DLOAD_CODE:
/* Enable all the clocks */
ret = wcd_cntl_clocks_enable(cntl);
@@ -623,6 +738,9 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
/* Enable CPAR */
wcd_cntl_cpar_ctrl(cntl, true);
+
+ if (event == WDSP_EVENT_PRE_DLOAD_CODE)
+ wcd_cntl_enable_memory(cntl);
break;
case WDSP_EVENT_DO_BOOT:
@@ -697,6 +815,8 @@ static void wcd_cntl_debugfs_init(char *dir, struct wcd_dsp_cntl *cntl)
debugfs_create_u32("debug_mode", S_IRUGO | S_IWUSR,
cntl->entry, &cntl->debug_mode);
+ debugfs_create_bool("ramdump_enable", S_IRUGO | S_IWUSR,
+ cntl->entry, &cntl->ramdump_enable);
done:
return;
}
@@ -827,6 +947,10 @@ static int wcd_ctrl_component_bind(struct device *dev,
void *data)
{
struct wcd_dsp_cntl *cntl;
+ struct snd_soc_codec *codec;
+ struct snd_card *card;
+ struct snd_info_entry *entry;
+ char proc_name[WCD_PROCFS_ENTRY_MAX_LEN];
int ret = 0;
if (!dev || !master || !data) {
@@ -844,13 +968,47 @@ static int wcd_ctrl_component_bind(struct device *dev,
cntl->m_dev = master;
cntl->m_ops = data;
- if (cntl->m_ops->register_cmpnt_ops)
- ret = cntl->m_ops->register_cmpnt_ops(master, dev, cntl,
- &control_ops);
+ if (!cntl->m_ops->register_cmpnt_ops) {
+ dev_err(dev, "%s: invalid master callback register_cmpnt_ops\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
- if (ret)
+ ret = cntl->m_ops->register_cmpnt_ops(master, dev, cntl, &control_ops);
+ if (ret) {
dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n",
__func__, ret);
+ goto done;
+ }
+
+ codec = cntl->codec;
+ card = codec->component.card->snd_card;
+ snprintf(proc_name, WCD_PROCFS_ENTRY_MAX_LEN, "%s%d%s", "cpe",
+ cntl->dsp_instance, "_state");
+ entry = snd_info_create_card_entry(card, proc_name, card->proc_root);
+ if (!entry) {
+ /* Do not treat this as Fatal error */
+ dev_err(dev, "%s: Failed to create procfs entry %s\n",
+ __func__, proc_name);
+ goto done;
+ }
+
+ cntl->ssr_entry.entry = entry;
+ cntl->ssr_entry.offline = 1;
+ entry->size = WCD_PROCFS_ENTRY_MAX_LEN;
+ entry->content = SNDRV_INFO_CONTENT_DATA;
+ entry->c.ops = &wdsp_ssr_entry_ops;
+ entry->private_data = cntl;
+ ret = snd_info_register(entry);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(dev, "%s: Failed to register entry %s, err = %d\n",
+ __func__, proc_name, ret);
+ snd_info_free_entry(entry);
+ /* Let bind still happen even if creating the entry failed */
+ ret = 0;
+ }
+done:
return ret;
}
@@ -929,6 +1087,8 @@ void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
memcpy(&control->irqs, &params->irqs, sizeof(control->irqs));
init_completion(&control->boot_complete);
mutex_init(&control->clk_mutex);
+ mutex_init(&control->ssr_mutex);
+ init_waitqueue_head(&control->ssr_entry.offline_poll_wait);
/*
* The default state of WDSP is in SVS mode.
@@ -981,6 +1141,7 @@ void wcd_dsp_cntl_deinit(struct wcd_dsp_cntl **cntl)
component_del(codec->dev, &wcd_ctrl_component_ops);
mutex_destroy(&control->clk_mutex);
+ mutex_destroy(&control->ssr_mutex);
kfree(*cntl);
*cntl = NULL;
}
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h
index 3d6db776a0b5..cd6697b3d641 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h
@@ -54,6 +54,13 @@ struct wcd_dsp_params {
u32 dsp_instance;
};
+struct wdsp_ssr_entry {
+ u8 offline;
+ u8 offline_change;
+ wait_queue_head_t offline_poll_wait;
+ struct snd_info_entry *entry;
+};
+
struct wcd_dsp_cntl {
/* Handle to codec */
struct snd_soc_codec *codec;
@@ -77,6 +84,7 @@ struct wcd_dsp_cntl {
/* Debugfs related */
struct dentry *entry;
u32 debug_mode;
+ bool ramdump_enable;
/* WDSP manager drivers data */
struct device *m_dev;
@@ -88,6 +96,10 @@ struct wcd_dsp_cntl {
/* Keep track of WDSP boot status */
bool is_wdsp_booted;
+
+ /* SSR related */
+ struct wdsp_ssr_entry ssr_entry;
+ struct mutex ssr_mutex;
};
void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h
index ac3031ffe615..940fdf89d361 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-routing.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h
@@ -21,6 +21,7 @@ const struct snd_soc_dapm_route tavil_slim_audio_map[] = {
{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+ {"AIF4 MAD", NULL, "AIF4_MAD Mixer"},
/* Virtual input widget Mixer */
{"AIF1_CAP Mixer", "SLIM TX0", "SLIM TX0"},
@@ -65,6 +66,8 @@ const struct snd_soc_dapm_route tavil_slim_audio_map[] = {
{"AIF3_CAP Mixer", "SLIM TX11", "SLIM TX11"},
{"AIF3_CAP Mixer", "SLIM TX13", "SLIM TX13"},
+ {"AIF4_MAD Mixer", "SLIM TX13", "SLIM TX13"},
+
{"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"},
{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
{"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
@@ -121,6 +124,7 @@ const struct snd_soc_dapm_route tavil_audio_map[] = {
{"MAD_INP MUX", "MAD", "MAD_SEL MUX"},
{"MAD_INP MUX", "DEC1", "ADC MUX1"},
+ {"MAD_BROADCAST", "Switch", "MAD_INP MUX"},
{"MAD_CPE1", "Switch", "MAD_INP MUX"},
{"MAD_CPE2", "Switch", "MAD_INP MUX"},
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index b4a73d17c322..9e18c17d6f1c 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -186,6 +186,7 @@ enum {
AIF3_CAP,
AIF4_PB,
AIF4_VIFEED,
+ AIF4_MAD_TX,
NUM_CODEC_DAIS,
};
@@ -301,13 +302,13 @@ static const struct wcd9xxx_ch tavil_tx_chs[WCD934X_TX_MAX] = {
};
static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = {
- 0, /* AIF1_PB */
- BIT(AIF2_CAP) | BIT(AIF3_CAP), /* AIF1_CAP */
- 0, /* AIF2_PB */
- BIT(AIF1_CAP) | BIT(AIF3_CAP), /* AIF2_CAP */
- 0, /* AIF3_PB */
- BIT(AIF1_CAP) | BIT(AIF2_CAP), /* AIF3_CAP */
- 0, /* AIF4_PB */
+ 0, /* AIF1_PB */
+ BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX), /* AIF1_CAP */
+ 0, /* AIF2_PB */
+ BIT(AIF1_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX), /* AIF2_CAP */
+ 0, /* AIF3_PB */
+ BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF4_MAD_TX), /* AIF3_CAP */
+ 0, /* AIF4_PB */
};
/* Codec supports 2 IIR filters */
@@ -1271,6 +1272,8 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
return 0;
}
break;
+ case AIF4_MAD_TX:
+ break;
default:
dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
mutex_unlock(&tavil_p->codec_mutex);
@@ -2474,7 +2477,7 @@ done:
return ret;
}
-static int tavil_codec_enable_mad(struct snd_soc_codec *codec, bool enable)
+static int __tavil_codec_enable_mad(struct snd_soc_codec *codec, bool enable)
{
int rc = 0;
@@ -2519,6 +2522,29 @@ done:
return rc;
}
+static int tavil_codec_ape_enable_mad(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+ int rc = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x40, 0x40);
+ rc = __tavil_codec_enable_mad(codec, true);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x40, 0x00);
+ __tavil_codec_enable_mad(codec, false);
+ break;
+ }
+
+ dev_dbg(tavil->dev, "%s: event = %d\n", __func__, event);
+ return rc;
+}
+
static int tavil_codec_cpe_mad_ctl(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -2533,7 +2559,7 @@ static int tavil_codec_cpe_mad_ctl(struct snd_soc_dapm_widget *w,
goto done;
snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x20, 0x20);
- rc = tavil_codec_enable_mad(codec, true);
+ rc = __tavil_codec_enable_mad(codec, true);
if (IS_ERR_VALUE(rc)) {
tavil->mad_switch_cnt--;
goto done;
@@ -2546,7 +2572,7 @@ static int tavil_codec_cpe_mad_ctl(struct snd_soc_dapm_widget *w,
goto done;
snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x20, 0x00);
- tavil_codec_enable_mad(codec, false);
+ __tavil_codec_enable_mad(codec, false);
break;
}
done:
@@ -5789,6 +5815,11 @@ static const struct snd_kcontrol_new aif3_cap_mixer[] = {
slim_tx_mixer_get, slim_tx_mixer_put),
};
+static const struct snd_kcontrol_new aif4_mad_mixer[] = {
+ SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
WCD_DAPM_ENUM_EXT(slim_rx0, SND_SOC_NOPM, 0, slim_rx_mux_text,
slim_rx_mux_get, slim_rx_mux_put);
WCD_DAPM_ENUM_EXT(slim_rx1, SND_SOC_NOPM, 0, slim_rx_mux_text,
@@ -6110,6 +6141,9 @@ static const struct snd_kcontrol_new mad_cpe1_switch =
static const struct snd_kcontrol_new mad_cpe2_switch =
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+static const struct snd_kcontrol_new mad_brdcst_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
static const struct snd_kcontrol_new adc_us_mux0_switch =
SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
@@ -6532,10 +6566,16 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)),
SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)),
+ SND_SOC_DAPM_MIXER("AIF4_MAD Mixer", SND_SOC_NOPM, AIF4_MAD_TX, 0,
+ aif4_mad_mixer, ARRAY_SIZE(aif4_mad_mixer)),
SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
AIF4_VIFEED, 0, tavil_codec_enable_slimvi_feedback,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT("AIF4 MAD", "AIF4 MAD TX", 0,
+ SND_SOC_NOPM, 0, 0),
+
SND_SOC_DAPM_MIXER("AIF4_VI Mixer", SND_SOC_NOPM, AIF4_VIFEED, 0,
aif4_vi_mixer, ARRAY_SIZE(aif4_vi_mixer)),
SND_SOC_DAPM_INPUT("VIINPUT"),
@@ -6670,6 +6710,10 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
WCD_DAPM_MUX("MAD_SEL MUX", 0, mad_sel),
WCD_DAPM_MUX("MAD_INP MUX", 0, mad_inp_mux),
+ SND_SOC_DAPM_SWITCH_E("MAD_BROADCAST", SND_SOC_NOPM, 0, 0,
+ &mad_brdcst_switch, tavil_codec_ape_enable_mad,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
SND_SOC_DAPM_SWITCH_E("MAD_CPE1", SND_SOC_NOPM, 0, 0,
&mad_cpe1_switch, tavil_codec_cpe_mad_ctl,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -6826,6 +6870,7 @@ static int tavil_get_channel_map(struct snd_soc_dai *dai,
case AIF1_CAP:
case AIF2_CAP:
case AIF3_CAP:
+ case AIF4_MAD_TX:
case AIF4_VIFEED:
if (!tx_slot || !tx_num) {
dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK or tx_num 0x%pK\n",
@@ -6864,6 +6909,7 @@ static int tavil_set_channel_map(struct snd_soc_dai *dai,
{
struct tavil_priv *tavil;
struct wcd9xxx *core;
+ struct wcd9xxx_codec_dai_data *dai_data = NULL;
tavil = snd_soc_codec_get_drvdata(dai->codec);
core = dev_get_drvdata(dai->codec->dev->parent);
@@ -6878,6 +6924,12 @@ static int tavil_set_channel_map(struct snd_soc_dai *dai,
wcd9xxx_init_slimslave(core, core->slim->laddr,
tx_num, tx_slot, rx_num, rx_slot);
+ /* Reserve TX13 for MAD data channel */
+ dai_data = &tavil->dai[AIF4_MAD_TX];
+ if (dai_data)
+ list_add_tail(&core->tx_chs[WCD934X_TX13].list,
+ &dai_data->wcd9xxx_ch_list);
+
return 0;
}
@@ -7208,7 +7260,7 @@ static int tavil_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct tavil_priv *tavil = snd_soc_codec_get_drvdata(dai->codec);
- int ret;
+ int ret = 0;
dev_dbg(tavil->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
__func__, dai->name, dai->id, params_rate(params),
@@ -7238,7 +7290,9 @@ static int tavil_hw_params(struct snd_pcm_substream *substream,
tavil->dai[dai->id].rate = params_rate(params);
break;
case SNDRV_PCM_STREAM_CAPTURE:
- ret = tavil_set_decimator_rate(dai, params_rate(params));
+ if (dai->id != AIF4_MAD_TX)
+ ret = tavil_set_decimator_rate(dai,
+ params_rate(params));
if (ret) {
dev_err(tavil->dev, "%s: cannot set TX Decimator rate: %d\n",
__func__, ret);
@@ -7395,6 +7449,20 @@ static struct snd_soc_dai_driver tavil_dai[] = {
},
.ops = &tavil_vi_dai_ops,
},
+ {
+ .name = "tavil_mad1",
+ .id = AIF4_MAD_TX,
+ .capture = {
+ .stream_name = "AIF4 MAD TX",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = WCD934X_FORMATS_S16_LE,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 1,
+ },
+ .ops = &tavil_dai_ops,
+ },
};
static void tavil_codec_power_gate_digital_core(struct tavil_priv *tavil)
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 52ca82fba8e9..2012e4617ee1 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -4675,7 +4675,7 @@ int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
usecs_to_jiffies(FW_READ_TIMEOUT));
else
- pr_debug("%s: Skipping to read mbhc fw, 0x%p %p\n",
+ pr_debug("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
__func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
}
@@ -5073,7 +5073,7 @@ static int wcd9xxx_remeasure_z_values(struct wcd9xxx_mbhc *mbhc,
right = !!(r);
dev_dbg(codec->dev, "%s: Remeasuring impedance values\n", __func__);
- dev_dbg(codec->dev, "%s: l: %p, r: %p, left=%d, right=%d\n", __func__,
+ dev_dbg(codec->dev, "%s: l: %pK, r: %pK, left=%d, right=%d\n", __func__,
l, r, left, right);
/* Remeasure V2 values */
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index e9f167fa643b..3aa9ac8d40b6 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -473,7 +473,7 @@ static int wcd_cpe_load_fw(struct wcd_cpe_core *core,
bool load_segment;
if (!core || !core->cpe_handle) {
- pr_err("%s: Error CPE core %p\n", __func__,
+ pr_err("%s: Error CPE core %pK\n", __func__,
core);
return -EINVAL;
}
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 28fd8930adb2..d7f4044b71ee 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -917,7 +917,7 @@ int wsa881x_set_channel_map(struct snd_soc_codec *codec, u8 *port, u8 num_port,
if (!port || !ch_mask || !ch_rate ||
(num_port > WSA881X_MAX_SWR_PORTS)) {
dev_err(codec->dev,
- "%s: Invalid port=%p, ch_mask=%p, ch_rate=%p\n",
+ "%s: Invalid port=%pK, ch_mask=%pK, ch_rate=%pK\n",
__func__, port, ch_mask, ch_rate);
return -EINVAL;
}
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 4cb62a6b3e7d..ee9dcacdd5c9 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -96,7 +96,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -108,8 +109,9 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.rates = (SNDRV_PCM_RATE_8000_384000|
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE|
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 4,
.rate_min = 8000,
@@ -127,7 +129,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -140,7 +143,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -210,7 +214,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 6,
.rate_min = 8000,
@@ -222,7 +227,9 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.rates = (SNDRV_PCM_RATE_8000_384000|
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE),
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -240,7 +247,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -259,7 +267,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -271,8 +280,9 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.rates = (SNDRV_PCM_RATE_8000_48000|
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE|
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -290,7 +300,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -303,7 +314,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -321,7 +333,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -340,7 +353,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -353,7 +367,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -2220,7 +2235,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -2239,7 +2255,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -2258,7 +2275,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -2277,7 +2295,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -2296,7 +2315,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -2315,7 +2335,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -2334,7 +2355,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_RATE_KNOT),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c
index d7b0e151f0bf..5c8d91bfe400 100644
--- a/sound/soc/msm/msmcobalt.c
+++ b/sound/soc/msm/msmcobalt.c
@@ -71,6 +71,9 @@
#define WCN_CDC_SLIM_RX_CH_MAX 2
#define WCN_CDC_SLIM_TX_CH_MAX 3
+#define TDM_CHANNEL_MAX 8
+#define TDM_SLOT_OFFSET_MAX 8
+
enum {
SLIM_RX_0 = 0,
SLIM_RX_1,
@@ -170,6 +173,131 @@ struct msm_asoc_wcd93xx_codec {
void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
};
+enum {
+ TDM_0 = 0,
+ TDM_1,
+ TDM_2,
+ TDM_3,
+ TDM_4,
+ TDM_5,
+ TDM_6,
+ TDM_7,
+ TDM_PORT_MAX,
+};
+
+enum {
+ TDM_PRI = 0,
+ TDM_SEC,
+ TDM_TERT,
+ TDM_QUAT,
+ TDM_INTERFACE_MAX,
+};
+
+struct tdm_port {
+ u32 mode;
+ u32 channel;
+};
+
+/* TDM default config */
+static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ }
+};
+
+/* TDM default config */
+static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ }
+};
+
+/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */
+static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
+ {0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */
+};
+
/* Default configuration of slimbus channels */
static struct dev_config slim_rx_cfg[] = {
[SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
@@ -254,7 +382,8 @@ static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven",
"Eight"};
static const char *const vi_feed_ch_text[] = {"One", "Two"};
-static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"};
static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
"KHZ_32", "KHZ_44P1", "KHZ_48",
@@ -269,9 +398,15 @@ static char const *ch_text[] = {"Two", "Three", "Four", "Five",
static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
"KHZ_16", "KHZ_22P05",
"KHZ_32", "KHZ_44P1", "KHZ_48",
- "KHZ_96", "KHZ_192"};
+ "KHZ_96", "KHZ_192", "KHZ_384"};
static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
"KHZ_192"};
+static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
+static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
+ "KHZ_44P1", "KHZ_48", "KHZ_96",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
"KHZ_32", "KHZ_44P1", "KHZ_48",
@@ -308,6 +443,12 @@ static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate,
ext_disp_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
@@ -511,6 +652,9 @@ static int slim_get_bit_format_val(int bit_format)
int val = 0;
switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ val = 3;
+ break;
case SNDRV_PCM_FORMAT_S24_3LE:
val = 2;
break;
@@ -539,6 +683,9 @@ static int slim_get_bit_format(int val)
case 2:
bit_fmt = SNDRV_PCM_FORMAT_S24_3LE;
break;
+ case 3:
+ bit_fmt = SNDRV_PCM_FORMAT_S32_LE;
+ break;
default:
bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
break;
@@ -876,6 +1023,9 @@ static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
int sample_rate_val;
switch (usb_rx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 9;
+ break;
case SAMPLING_RATE_192KHZ:
sample_rate_val = 8;
break;
@@ -916,6 +1066,9 @@ static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
+ case 9:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
case 8:
usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
break;
@@ -958,6 +1111,9 @@ static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
switch (usb_rx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
case SNDRV_PCM_FORMAT_S24_3LE:
ucontrol->value.integer.value[0] = 2;
break;
@@ -982,6 +1138,9 @@ static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol,
int rc = 0;
switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
case 2:
usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
break;
@@ -1024,6 +1183,9 @@ static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
int sample_rate_val;
switch (usb_tx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 9;
+ break;
case SAMPLING_RATE_192KHZ:
sample_rate_val = 8;
break;
@@ -1066,6 +1228,9 @@ static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
+ case 9:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
case 8:
usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
break;
@@ -1108,6 +1273,9 @@ static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
switch (usb_tx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
case SNDRV_PCM_FORMAT_S24_3LE:
ucontrol->value.integer.value[0] = 2;
break;
@@ -1132,6 +1300,9 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
int rc = 0;
switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
case 2:
usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
break;
@@ -1328,6 +1499,45 @@ static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
return 1;
}
+static int tdm_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
static int aux_pcm_get_sample_rate(int value)
{
int sample_rate;
@@ -1344,6 +1554,45 @@ static int aux_pcm_get_sample_rate(int value)
return sample_rate;
}
+static int tdm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 8;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
static int aux_pcm_get_sample_rate_val(int sample_rate)
{
int sample_rate_val;
@@ -1360,6 +1609,361 @@ static int aux_pcm_get_sample_rate_val(int sample_rate)
return sample_rate_val;
}
+static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
+ struct tdm_port *port)
+{
+ if (port) {
+ if (strnstr(kcontrol->id.name, "PRI",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_PRI;
+ } else if (strnstr(kcontrol->id.name, "SEC",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_SEC;
+ } else if (strnstr(kcontrol->id.name, "TERT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_TERT;
+ } else if (strnstr(kcontrol->id.name, "QUAT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_QUAT;
+ } else {
+ pr_err("%s: unsupported mode in: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ if (strnstr(kcontrol->id.name, "RX_0",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_0",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_0;
+ } else if (strnstr(kcontrol->id.name, "RX_1",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_1",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_1;
+ } else if (strnstr(kcontrol->id.name, "RX_2",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_2",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_2;
+ } else if (strnstr(kcontrol->id.name, "RX_3",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_3",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_3;
+ } else if (strnstr(kcontrol->id.name, "RX_4",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_4",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_4;
+ } else if (strnstr(kcontrol->id.name, "RX_5",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_5",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_5;
+ } else if (strnstr(kcontrol->id.name, "RX_6",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_6",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_6;
+ } else if (strnstr(kcontrol->id.name, "RX_7",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_7",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_7;
+ } else {
+ pr_err("%s: unsupported channel in: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_rx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_tx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_get_format(int value)
+{
+ int format = 0;
+
+ switch (value) {
+ case 0:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return format;
+}
+
+static int tdm_get_format_val(int format)
+{
+ int value = 0;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ value = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ value = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ value = 2;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_rx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_tx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+
+ ucontrol->value.enumerated.item[0] =
+ tdm_rx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] =
+ tdm_tx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
{
int idx;
@@ -1758,6 +2362,24 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
ext_disp_rx_sample_rate_get,
ext_disp_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
aux_pcm_rx_sample_rate_get,
aux_pcm_rx_sample_rate_put),
@@ -2095,6 +2717,22 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = SAMPLING_RATE_48KHZ;
break;
+ case MSM_BACKEND_DAI_TERT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
case MSM_BACKEND_DAI_AUXPCM_RX:
rate->min = rate->max =
aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
@@ -2612,7 +3250,7 @@ static void *def_tasha_mbhc_cal(void)
return NULL;
#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tasha_wcd_cal)->X) = (Y))
- S(v_hs_max, 1500);
+ S(v_hs_max, 1600);
#undef S
#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal)->X) = (Y))
S(num_btn, WCD_MBHC_DEF_BUTTONS);
@@ -3176,6 +3814,157 @@ static struct snd_soc_ops msm_aux_pcm_be_ops = {
.shutdown = msm_aux_pcm_snd_shutdown,
};
+static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width,
+ int slots)
+{
+ unsigned int slot_mask = 0;
+ int i, j;
+ unsigned int *slot_offset;
+
+ for (i = TDM_0; i < TDM_PORT_MAX; i++) {
+ slot_offset = tdm_slot_offset[i];
+
+ for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) {
+ if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ slot_mask |=
+ (1 << ((slot_offset[j] * 8) / slot_width));
+ else
+ break;
+ }
+ }
+
+ return slot_mask;
+}
+
+static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width, slots;
+ unsigned int slot_mask;
+ unsigned int *slot_offset;
+ int offset_channels = 0;
+ int i;
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ channels = params_channels(params);
+ switch (channels) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /*
+ * up to 8 channels HW config should
+ * use 32 bit slot width for max support of
+ * stream bit width. (slot_width > bit_width)
+ */
+ slot_width = 32;
+ break;
+ default:
+ pr_err("%s: invalid param format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ slots = 8;
+ slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
+ slot_width,
+ slots);
+ if (!slot_mask) {
+ pr_err("%s: invalid slot_mask 0x%x\n",
+ __func__, slot_mask);
+ return -EINVAL;
+ }
+ break;
+ default:
+ pr_err("%s: invalid param channels %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ /* currently only supporting TDM_RX_0 and TDM_TX_0 */
+ switch (cpu_dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ slot_offset = tdm_slot_offset[TDM_0];
+ break;
+ default:
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ offset_channels++;
+ else
+ break;
+ }
+
+ if (offset_channels == 0) {
+ pr_err("%s: slot offset not supported, offset_channels %d\n",
+ __func__, offset_channels);
+ return -EINVAL;
+ }
+
+ if (channels > offset_channels) {
+ pr_err("%s: channels %d exceed offset_channels %d\n",
+ __func__, channels, offset_channels);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
+ slot_offset, 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
static struct snd_soc_ops msm_be_ops = {
.hw_params = msm_snd_hw_params,
};
@@ -3192,6 +3981,10 @@ static struct snd_soc_ops msm_wcn_ops = {
.hw_params = msm_wcn_hw_params,
};
+static struct snd_soc_ops msm_tdm_be_ops = {
+ .hw_params = msm_tdm_snd_hw_params
+};
+
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm_common_dai_links[] = {
/* FrontEnd DAI Links */
@@ -3992,6 +4785,34 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ {
+ .name = LPASS_BE_TERT_TDM_RX_0,
+ .stream_name = "Tertiary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36896",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_TX_0,
+ .stream_name = "Tertiary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36897",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
};
static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 841bb5bce13f..770bd12eb501 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -709,6 +709,10 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
}
switch (prtd->codec_param.codec.format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bit_width = 32;
+ sample_word_size = 32;
+ break;
case SNDRV_PCM_FORMAT_S24_LE:
bit_width = 24;
sample_word_size = 32;
@@ -723,14 +727,16 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
sample_word_size = 16;
break;
}
- ret = q6asm_media_format_block_pcm_format_support_v3(
+ ret = q6asm_media_format_block_pcm_format_support_v4(
prtd->audio_client,
prtd->sample_rate,
prtd->num_channels,
bit_width, stream_id,
use_default_chmap,
chmap,
- sample_word_size);
+ sample_word_size,
+ ASM_LITTLE_ENDIAN,
+ DEFAULT_QF);
if (ret < 0)
pr_err("%s: CMD Format block failed\n", __func__);
@@ -1010,7 +1016,7 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
} else {
pr_debug("%s: stream_id %d bits_per_sample %d\n",
__func__, ac->stream_id, bits_per_sample);
- ret = q6asm_stream_open_write_v3(ac,
+ ret = q6asm_stream_open_write_v4(ac,
prtd->codec, bits_per_sample,
ac->stream_id,
prtd->gapless_state.use_dsp_gapless_mode);
@@ -1942,7 +1948,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
pr_debug("%s: open_write stream_id %d bits_per_sample %d",
__func__, stream_id, bits_per_sample);
- rc = q6asm_stream_open_write_v3(prtd->audio_client,
+ rc = q6asm_stream_open_write_v4(prtd->audio_client,
prtd->codec, bits_per_sample,
stream_id,
prtd->gapless_state.use_dsp_gapless_mode);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index a89d88eac41e..7eb4a10b83c7 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -173,6 +173,7 @@ struct msm_dai_q6_dai_data {
u32 bitwidth;
u32 cal_mode;
u32 afe_in_channels;
+ u16 afe_in_bitformat;
struct afe_enc_config enc_config;
union afe_port_config port_config;
};
@@ -1417,11 +1418,20 @@ static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
if (dai_data->enc_config.format != ENC_FMT_NONE) {
+ int bitwidth = 0;
+
+ if (dai_data->afe_in_bitformat ==
+ SNDRV_PCM_FORMAT_S24_LE)
+ bitwidth = 24;
+ else if (dai_data->afe_in_bitformat ==
+ SNDRV_PCM_FORMAT_S16_LE)
+ bitwidth = 16;
pr_debug("%s: calling AFE_PORT_START_V2 with enc_format: %d\n",
__func__, dai_data->enc_config.format);
rc = afe_port_start_v2(dai->id, &dai_data->port_config,
dai_data->rate,
dai_data->afe_in_channels,
+ bitwidth,
&dai_data->enc_config);
if (rc < 0)
pr_err("%s: afe_port_start_v2 failed error: %d\n",
@@ -1607,8 +1617,13 @@ static int msm_dai_q6_usb_audio_hw_params(struct snd_pcm_hw_params *params,
dai_data->port_config.usb_audio.bit_width = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
dai_data->port_config.usb_audio.bit_width = 24;
break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dai_data->port_config.usb_audio.bit_width = 32;
+ break;
+
default:
dev_err(dai->dev, "%s: invalid format %d\n",
__func__, params_format(params));
@@ -2140,6 +2155,12 @@ static const struct soc_enum afe_input_chs_enum[] = {
SOC_ENUM_SINGLE_EXT(3, afe_input_chs_text),
};
+static const char *const afe_input_bit_format_text[] = {"S16_LE", "S24_LE"};
+
+static const struct soc_enum afe_input_bit_format_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, afe_input_bit_format_text),
+};
+
static int msm_dai_q6_afe_input_channel_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2168,6 +2189,58 @@ static int msm_dai_q6_afe_input_channel_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int msm_dai_q6_afe_input_bit_format_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (!dai_data) {
+ pr_err("%s: Invalid dai data\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (dai_data->afe_in_bitformat) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: afe input bit format : %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_dai_q6_afe_input_bit_format_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (!dai_data) {
+ pr_err("%s: Invalid dai data\n", __func__);
+ return -EINVAL;
+ }
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: updating afe input bit format : %d\n",
+ __func__, dai_data->afe_in_bitformat);
+
+ return 0;
+}
+
+
static const struct snd_kcontrol_new afe_enc_config_controls[] = {
{
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -2181,6 +2254,9 @@ static const struct snd_kcontrol_new afe_enc_config_controls[] = {
SOC_ENUM_EXT("AFE Input Channels", afe_input_chs_enum[0],
msm_dai_q6_afe_input_channel_get,
msm_dai_q6_afe_input_channel_put),
+ SOC_ENUM_EXT("AFE Input Bit Format", afe_input_bit_format_enum[0],
+ msm_dai_q6_afe_input_bit_format_get,
+ msm_dai_q6_afe_input_bit_format_put),
};
static const char * const afe_cal_mode_text[] = {
@@ -2570,11 +2646,12 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_rx_dai = {
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
- .rate_max = 192000,
+ .rate_max = 384000,
.rate_min = 8000,
},
.ops = &msm_dai_q6_ops,
@@ -2591,11 +2668,12 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_tx_dai = {
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
- .rate_max = 192000,
+ .rate_max = 384000,
.rate_min = 8000,
},
.ops = &msm_dai_q6_ops,
@@ -5825,11 +5903,6 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
pr_debug("%s: dev_name: %s\n",
__func__, dev_name(dai->dev));
- if (params_rate(params) != 48000) {
- dev_err(dai->dev, "%s: invalid param rate %d\n",
- __func__, params_rate(params));
- return -EINVAL;
- }
if ((params_channels(params) == 0) ||
(params_channels(params) > 8)) {
dev_err(dai->dev, "%s: invalid param channels %d\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 4e93780c4da0..c5baf0e63732 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -67,10 +67,11 @@ static struct snd_pcm_hardware msm_pcm_hardware_capture = {
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
- .rates = SNDRV_PCM_RATE_8000_48000,
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .rates = SNDRV_PCM_RATE_8000_384000,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 384000,
.channels_min = 1,
.channels_max = 4,
.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
@@ -90,10 +91,11 @@ static struct snd_pcm_hardware msm_pcm_hardware_playback = {
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S24_3LE),
- .rates = SNDRV_PCM_RATE_8000_192000,
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .rates = SNDRV_PCM_RATE_8000_384000,
.rate_min = 8000,
- .rate_max = 192000,
+ .rate_max = 384000,
.channels_min = 1,
.channels_max = 8,
.buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS *
@@ -108,7 +110,7 @@ static struct snd_pcm_hardware msm_pcm_hardware_playback = {
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
- 88200, 96000, 176400, 192000
+ 88200, 96000, 176400, 192000, 384000
};
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -313,6 +315,10 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits_per_sample = 32;
+ sample_word_size = 32;
+ break;
case SNDRV_PCM_FORMAT_S24_LE:
bits_per_sample = 24;
sample_word_size = 32;
@@ -328,7 +334,7 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
break;
}
- ret = q6asm_open_write_v3(prtd->audio_client,
+ ret = q6asm_open_write_v4(prtd->audio_client,
FORMAT_LINEAR_PCM, bits_per_sample);
if (ret < 0) {
@@ -353,11 +359,12 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
return ret;
}
- ret = q6asm_media_format_block_multi_ch_pcm_v3(
+ ret = q6asm_media_format_block_multi_ch_pcm_v4(
prtd->audio_client, runtime->rate,
runtime->channels, !prtd->set_channel_map,
prtd->channel_map, bits_per_sample,
- sample_word_size);
+ sample_word_size, ASM_LITTLE_ENDIAN,
+ DEFAULT_QF);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -402,6 +409,8 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
(params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
bits_per_sample = 24;
+ else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
+ bits_per_sample = 32;
/* ULL mode is not supported in capture path */
if (pdata->perf_mode == LEGACY_PCM_MODE)
@@ -413,7 +422,7 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
__func__, params_channels(params),
prtd->audio_client->perf_mode);
- ret = q6asm_open_read_v3(prtd->audio_client, FORMAT_LINEAR_PCM,
+ ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
bits_per_sample);
if (ret < 0) {
pr_err("%s: q6asm_open_read failed\n", __func__);
@@ -459,6 +468,10 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
return 0;
switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits_per_sample = 32;
+ sample_word_size = 32;
+ break;
case SNDRV_PCM_FORMAT_S24_LE:
bits_per_sample = 24;
sample_word_size = 32;
@@ -477,11 +490,13 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
__func__, prtd->samp_rate, prtd->channel_mode,
bits_per_sample, sample_word_size);
- ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client,
+ ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client,
prtd->samp_rate,
prtd->channel_mode,
bits_per_sample,
- sample_word_size);
+ sample_word_size,
+ ASM_LITTLE_ENDIAN,
+ DEFAULT_QF);
if (ret < 0)
pr_debug("%s: cmd cfg pcm was block failed", __func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 72418ea56bb9..8fe31394eef0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -59,11 +59,11 @@ struct msm_audio_in_frame_info {
#define PLAYBACK_MIN_NUM_PERIODS 2
#define PLAYBACK_MAX_NUM_PERIODS 8
-#define PLAYBACK_MAX_PERIOD_SIZE 12288
+#define PLAYBACK_MAX_PERIOD_SIZE 122880
#define PLAYBACK_MIN_PERIOD_SIZE 128
#define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8
-#define CAPTURE_MAX_PERIOD_SIZE 61440
+#define CAPTURE_MAX_PERIOD_SIZE 122880
#define CAPTURE_MIN_PERIOD_SIZE 320
struct msm_audio {
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index af5a99e56afc..be0a8b2e3abe 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -2645,8 +2645,9 @@ exit:
}
static int q6afe_send_enc_config(u16 port_id,
- union afe_enc_config_data *cfg, u32 format,
- union afe_port_config afe_config, u16 afe_in_channels)
+ union afe_enc_config_data *cfg, u32 format,
+ union afe_port_config afe_config,
+ u16 afe_in_channels, u16 afe_in_bit_width)
{
struct afe_audioif_config_command config;
int index;
@@ -2728,8 +2729,13 @@ static int q6afe_send_enc_config(u16 port_id,
config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE;
config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE;
config.port.media_type.sample_rate = afe_config.slim_sch.sample_rate;
- config.port.media_type.bit_width = afe_config.slim_sch.bit_width;
- if (afe_in_channels != 0)
+ if (afe_in_bit_width)
+ config.port.media_type.bit_width = afe_in_bit_width;
+ else
+ config.port.media_type.bit_width =
+ afe_config.slim_sch.bit_width;
+
+ if (afe_in_channels)
config.port.media_type.num_channels = afe_in_channels;
else
config.port.media_type.num_channels =
@@ -2749,8 +2755,8 @@ exit:
}
static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
- u32 rate, u16 afe_in_channels,
- union afe_enc_config_data *cfg, u32 enc_format)
+ u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
+ union afe_enc_config_data *cfg, u32 enc_format)
{
struct afe_audioif_config_command config;
int ret = 0;
@@ -2989,7 +2995,8 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n",
__func__, enc_format);
ret = q6afe_send_enc_config(port_id, cfg, enc_format,
- *afe_config, afe_in_channels);
+ *afe_config, afe_in_channels,
+ afe_in_bit_width);
if (ret) {
pr_err("%s: AFE encoder config for port 0x%x failed %d\n",
__func__, port_id, ret);
@@ -3043,7 +3050,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate)
{
return __afe_port_start(port_id, afe_config, rate,
- 0, NULL, ASM_MEDIA_FMT_NONE);
+ 0, 0, NULL, ASM_MEDIA_FMT_NONE);
}
EXPORT_SYMBOL(afe_port_start);
@@ -3061,12 +3068,12 @@ EXPORT_SYMBOL(afe_port_start);
* Returns 0 on success or error value on port start failure.
*/
int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
- u32 rate, u16 afe_in_channels,
+ u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
struct afe_enc_config *enc_cfg)
{
return __afe_port_start(port_id, afe_config, rate,
- afe_in_channels, &enc_cfg->data,
- enc_cfg->format);
+ afe_in_channels, afe_in_bit_width,
+ &enc_cfg->data, enc_cfg->format);
}
EXPORT_SYMBOL(afe_port_start_v2);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index b4257f990aa5..88c27339b299 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -183,6 +183,25 @@ static inline void q6asm_update_token(u32 *token, u8 session_id, u8 stream_id,
*token = asm_token.token;
}
+static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver)
+{
+ uint32_t pcm_format_id;
+
+ switch (media_format_block_ver) {
+ case PCM_MEDIA_FORMAT_V4:
+ pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4;
+ break;
+ case PCM_MEDIA_FORMAT_V3:
+ pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
+ break;
+ case PCM_MEDIA_FORMAT_V2:
+ default:
+ pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+ break;
+ }
+ return pcm_format_id;
+}
+
/*
* q6asm_get_buf_index_from_token:
* Retrieve buffer index from token.
@@ -2263,7 +2282,7 @@ static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
static int __q6asm_open_read(struct audio_client *ac,
uint32_t format, uint16_t bits_per_sample,
- bool use_v3_format)
+ uint32_t pcm_format_block_ver)
{
int rc = 0x00;
struct asm_stream_cmd_open_read_v3 open;
@@ -2306,10 +2325,7 @@ static int __q6asm_open_read(struct audio_client *ac,
switch (format) {
case FORMAT_LINEAR_PCM:
open.mode_flags |= 0x00;
- if (use_v3_format)
- open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
- else
- open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+ open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
break;
case FORMAT_MPEG4_AAC:
open.mode_flags |= BUFFER_META_ENABLE;
@@ -2372,14 +2388,14 @@ int q6asm_open_read(struct audio_client *ac,
uint32_t format)
{
return __q6asm_open_read(ac, format, 16,
- false /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/);
}
int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
return __q6asm_open_read(ac, format, bits_per_sample,
- false /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/);
}
/*
@@ -2393,10 +2409,25 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
return __q6asm_open_read(ac, format, bits_per_sample,
- true /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V3/*media fmt block ver*/);
}
EXPORT_SYMBOL(q6asm_open_read_v3);
+/*
+ * asm_open_read_v4 - Opens audio capture session
+ *
+ * @ac: Client session handle
+ * @format: encoder format
+ * @bits_per_sample: bit width of capture session
+ */
+int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_read(ac, format, bits_per_sample,
+ PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/);
+}
+EXPORT_SYMBOL(q6asm_open_read_v4);
+
int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
uint32_t passthrough_flag)
{
@@ -2488,7 +2519,8 @@ fail_cmd:
static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, uint32_t stream_id,
- bool is_gapless_mode, bool use_v3_format)
+ bool is_gapless_mode,
+ uint32_t pcm_format_block_ver)
{
int rc = 0x00;
struct asm_stream_cmd_open_write_v3 open;
@@ -2564,11 +2596,7 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
}
switch (format) {
case FORMAT_LINEAR_PCM:
- if (use_v3_format)
- open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
- else
- open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
-
+ open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
break;
case FORMAT_MPEG4_AAC:
open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
@@ -2647,7 +2675,7 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format)
{
return __q6asm_open_write(ac, format, 16, ac->stream_id,
false /*gapless*/,
- false /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
}
int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
@@ -2655,7 +2683,7 @@ int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
{
return __q6asm_open_write(ac, format, bits_per_sample,
ac->stream_id, false /*gapless*/,
- false /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
}
/*
@@ -2670,17 +2698,33 @@ int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
{
return __q6asm_open_write(ac, format, bits_per_sample,
ac->stream_id, false /*gapless*/,
- true /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
}
EXPORT_SYMBOL(q6asm_open_write_v3);
+/*
+ * q6asm_open_write_v4 - Opens audio playback session
+ *
+ * @ac: Client session handle
+ * @format: decoder format
+ * @bits_per_sample: bit width of playback session
+ */
+int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ ac->stream_id, false /*gapless*/,
+ PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
+}
+EXPORT_SYMBOL(q6asm_open_write_v4);
+
int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, int32_t stream_id,
bool is_gapless_mode)
{
return __q6asm_open_write(ac, format, bits_per_sample,
stream_id, is_gapless_mode,
- false /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
}
/*
@@ -2698,10 +2742,29 @@ int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
{
return __q6asm_open_write(ac, format, bits_per_sample,
stream_id, is_gapless_mode,
- true /*use_v3_format*/);
+ PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
}
EXPORT_SYMBOL(q6asm_stream_open_write_v3);
+/*
+ * q6asm_stream_open_write_v4 - Creates audio stream for playback
+ *
+ * @ac: Client session handle
+ * @format: asm playback format
+ * @bits_per_sample: bit width of requested stream
+ * @stream_id: stream id of stream to be associated with this session
+ * @is_gapless_mode: true if gapless mode needs to be enabled
+ */
+int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ stream_id, is_gapless_mode,
+ PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
+}
+EXPORT_SYMBOL(q6asm_stream_open_write_v4);
+
static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
uint32_t wr_format, bool is_meta_data_mode,
uint32_t bits_per_sample,
@@ -3525,6 +3588,108 @@ fail_cmd:
}
/*
+ * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map to be used
+ * @use_back_flavor: to configure back left and right channel
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, bool use_default_chmap,
+ bool use_back_flavor, u8 *channel_map,
+ uint16_t sample_word_size, uint16_t endianness,
+ uint16_t mode)
+{
+ struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg;
+ struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
+ u8 *channel_mapping;
+ u32 frames_per_buf = 0;
+ int rc;
+
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&enc_cfg, 0, sizeof(enc_cfg));
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+ sizeof(enc_cfg.encdec);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(enc_fg_blk);
+ enc_cfg.num_channels = channels;
+ enc_cfg.bits_per_sample = bits_per_sample;
+ enc_cfg.sample_rate = rate;
+ enc_cfg.is_signed = 1;
+ enc_cfg.sample_word_size = sample_word_size;
+ enc_cfg.endianness = endianness;
+ enc_cfg.mode = mode;
+ channel_mapping = enc_cfg.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ pr_debug("%s: setting default channel map for %d channels",
+ __func__, channels);
+ if (q6asm_map_channels(channel_mapping, channels,
+ use_back_flavor)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ pr_debug("%s: Using pre-defined channel map", __func__);
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Command open failed %d\n", __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, enc_cfg.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4);
+
+/*
* q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters
*
* @ac: Client session handle
@@ -3700,6 +3865,18 @@ fail_cmd:
return rc;
}
+static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
+ bits_per_sample, true, false, NULL,
+ sample_word_size, endianness, mode);
+}
+
static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
uint32_t rate, uint32_t channels,
uint16_t bits_per_sample,
@@ -3749,6 +3926,31 @@ int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
}
EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3);
+/*
+ * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration
+ * parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
+ bits_per_sample, sample_word_size,
+ endianness, mode);
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4);
+
int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
uint32_t rate, uint32_t channels)
{
@@ -4381,6 +4583,91 @@ fail_cmd:
return rc;
}
+static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
+ u8 *channel_mapping;
+ int rc;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
+ (stream_id & 0xFF);
+
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, fmt.hdr.token, stream_id, ac->session);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.param.num_channels = channels;
+ fmt.param.bits_per_sample = bits_per_sample;
+ fmt.param.sample_rate = rate;
+ fmt.param.is_signed = 1;
+ fmt.param.sample_word_size = sample_word_size;
+ fmt.param.endianness = endianness;
+ fmt.param.mode = mode;
+ channel_mapping = fmt.param.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
int q6asm_media_format_block_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels)
{
@@ -4448,6 +4735,47 @@ int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
}
EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3);
+/*
+ * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder
+ * configuration parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @stream_id: stream id of stream to be associated with this session
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ return -EINVAL;
+ }
+ return __q6asm_media_format_block_pcm_v4(ac, rate,
+ channels, bits_per_sample, stream_id,
+ use_default_chmap, channel_map,
+ sample_word_size, endianness,
+ mode);
+
+}
+EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4);
+
+
static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels,
bool use_default_chmap, char *channel_map,
@@ -4581,6 +4909,78 @@ fail_cmd:
return rc;
}
+static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
+ u8 *channel_mapping;
+ int rc;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.param.num_channels = channels;
+ fmt.param.bits_per_sample = bits_per_sample;
+ fmt.param.sample_rate = rate;
+ fmt.param.is_signed = 1;
+ fmt.param.sample_word_size = sample_word_size;
+ fmt.param.endianness = endianness;
+ fmt.param.mode = mode;
+ channel_mapping = fmt.param.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels,
@@ -4628,6 +5028,39 @@ int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
}
EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3);
+/*
+ * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration
+ * parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels,
+ use_default_chmap,
+ channel_map,
+ bits_per_sample,
+ sample_word_size,
+ endianness,
+ mode);
+}
+EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
+
static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg, int stream_id)
{