summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/cnss/icnss.txt12
-rw-r--r--Documentation/devicetree/bindings/gpu/adreno.txt11
-rw-r--r--Documentation/devicetree/bindings/media/video/laser-sensor.txt28
-rw-r--r--Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt60
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt35
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt30
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660l.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi22
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi21
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi7
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi26
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-sde.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-gpu.dtsi418
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-common.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-gpu.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi18
-rw-r--r--arch/arm/configs/sdm660-perf_defconfig5
-rw-r--r--arch/arm/configs/sdm660_defconfig6
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig14
-rw-r--r--arch/arm64/configs/sdm660-perf_defconfig1
-rw-r--r--arch/arm64/configs/sdm660_defconfig3
-rw-r--r--arch/arm64/kernel/stacktrace.c4
-rw-r--r--drivers/base/firmware_class.c3
-rw-r--r--drivers/char/adsprpc.c2
-rw-r--r--drivers/clk/msm/clock-mmss-8998.c16
-rw-r--r--drivers/gpu/drm/msm/Kconfig1
-rw-r--r--drivers/gpu/drm/msm/Makefile3
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c210
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h71
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c37
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c227
-rw-r--r--drivers/gpu/drm/msm/sde/sde_formats.c79
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c1
-rw-r--r--drivers/gpu/msm/kgsl.c2
-rw-r--r--drivers/gpu/msm/kgsl_debugfs.c7
-rw-r--r--drivers/gpu/msm/kgsl_debugfs.h4
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c69
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.h7
-rw-r--r--drivers/gpu/msm/kgsl_snapshot.c8
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.c8
-rw-r--r--drivers/i2c/busses/i2c-msm-v2.c70
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c13
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.c8
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c27
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c10
-rw-r--r--drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c53
-rw-r--r--drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c11
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c24
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h3
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c39
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h3
-rw-r--r--drivers/misc/hdcp.c3
-rw-r--r--drivers/misc/qseecom.c4
-rw-r--r--drivers/platform/msm/Kconfig7
-rw-r--r--drivers/platform/msm/Makefile1
-rw-r--r--drivers/platform/msm/gsi/gsi.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_client.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dma.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_flt.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c26
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_uc.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c7
-rw-r--r--drivers/platform/msm/msm_ext_display.c (renamed from drivers/video/fbdev/msm/msm_ext_display.c)246
-rw-r--r--drivers/power/supply/qcom/smb-lib.c12
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c40
-rw-r--r--drivers/regulator/qpnp-oledb-regulator.c162
-rw-r--r--drivers/sensors/sensors_ssc.c17
-rw-r--r--drivers/soc/qcom/Kconfig9
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/icnss.c365
-rw-r--r--drivers/soc/qcom/qdsp6v2/adsp-loader.c16
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr_tal_glink.c1
-rw-r--r--drivers/soc/qcom/qdsp6v2/cdsp-loader.c22
-rw-r--r--drivers/soc/qcom/qpnp-haptic.c354
-rw-r--r--drivers/soc/qcom/qpnp-pbs.c361
-rw-r--r--drivers/soc/qcom/service-locator.c5
-rw-r--r--drivers/soc/qcom/spcom.c20
-rw-r--r--drivers/usb/gadget/function/f_gsi.c218
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c8
-rw-r--r--drivers/usb/pd/policy_engine.c2
-rw-r--r--drivers/video/fbdev/msm/Kconfig2
-rw-r--r--drivers/video/fbdev/msm/Makefile1
-rw-r--r--drivers/video/fbdev/msm/mdss.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c172
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c16
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c26
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c5
-rw-r--r--include/linux/msm_ext_display.h2
-rw-r--r--include/linux/msm_kgsl.h21
-rw-r--r--include/linux/qpnp/qpnp-pbs.h25
-rw-r--r--include/uapi/sound/compress_offload.h6
-rw-r--r--sound/soc/codecs/wsa881x.c13
-rw-r--r--sound/soc/msm/msm-cpe-lsm.c61
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c10
-rw-r--r--sound/soc/msm/qdsp6v2/msm-lsm-client.c91
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c1
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c17
-rw-r--r--sound/soc/msm/sdm660-external.c2
111 files changed, 3321 insertions, 921 deletions
diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt
index a1cbf480890a..4b70e670798d 100644
--- a/Documentation/devicetree/bindings/cnss/icnss.txt
+++ b/Documentation/devicetree/bindings/cnss/icnss.txt
@@ -12,9 +12,17 @@ Required properties:
- reg-names: Names of the memory regions defined in reg entry
- interrupts: Copy engine interrupt table
- qcom,wlan-msa-memory: MSA memory size
+ - clocks: List of clock phandles
+ - clock-names: List of clock names corresponding to the "clocks" property
- iommus: SMMUs and corresponding Stream IDs needed by WLAN
- qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
format to be used for allocations associated between WLAN and SMMU
+ - <supply-name>-supply: phandle to the regulator device tree node
+ Required "supply-name" is "vdd-0.8-cx-mx".
+ - qcom,<supply>-config: Specifies voltage levels for supply. Should be
+ specified in pairs (min, max), units uV. There can
+ be optional load in uA and Regulator settle delay in
+ uS.
Optional properties:
- qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
@@ -27,6 +35,8 @@ Example:
compatible = "qcom,icnss";
reg = <0x0a000000 0x1000000>;
reg-names = "membase";
+ clocks = <&clock_gcc clk_aggre2_noc_clk>;
+ clock-names = "smmu_aggre2_noc_clk";
iommus = <&anoc2_smmu 0x1900>,
<&anoc2_smmu 0x1901>;
qcom,wlan-smmu-iova-address = <0 0x10000000>;
@@ -45,4 +55,6 @@ Example:
<0 141 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x200000>;
qcom,smmu-s1-bypass;
+ vdd-0.8-cx-mx-supply = <&pm8998_l5>;
+ qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 453223dc195a..1ca89b587077 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -110,6 +110,17 @@ Optional Properties:
- qcom,l2pc-cpu-mask-latency:
The CPU mask latency in microseconds to avoid L2PC
on masked CPUs.
+
+- qcom,gpu-cx-ipeak:
+ To handle Cx peak current limit.
+ <phandle bit>
+ phandle - phandle of cx ipeak device node
+ bit - bit number of client in relevant register
+- qcom,gpu-cx-ipeak-clk:
+ GPU clock threshold for Cx Ipeak voting. KGSL votes
+ to Cx Ipeak driver when GPU clock crosses this threshold.
+ Cx Ipeak can limit peak current based on voting from other clients.
+
- qcom,force-32bit:
Force the GPU to use 32 bit data sizes even if
it is capable of doing 64 bit.
diff --git a/Documentation/devicetree/bindings/media/video/laser-sensor.txt b/Documentation/devicetree/bindings/media/video/laser-sensor.txt
new file mode 100644
index 000000000000..1bcb0b93cb10
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/laser-sensor.txt
@@ -0,0 +1,28 @@
+Laser Sensor Device Tree Bindings.
+========================================
+
+Boards with the Laser Sensor connected to CCI shall have the following
+properties:
+
+Required node properties:
+ - cell-index: cci hardware core index
+ - compatible:
+ - "st,stmvl53l0" : STMiecroelectronics VL53L0 Laser sensor.
+ - reg : offset and length of the register set for the device
+ - qcom, cci-master: cci master the sensor connected to
+ - cam_cci-supply : cci voltage regulator used
+ - cam_laser-supply: laser sensor voltage regulator
+ - qcom,cam-vreg-name: voltage regulators name
+ - qcom, cam-vreg-min-voltage: specify minimum voltage level for
+ regulators used
+ - qcom, cam-vreg-max-voltage: specify maximum voltage level for
+ regulators used
+ - pinctrl-names : should specify the pin control groups followed by
+ the definition of each group
+ - gpios : should contain phandle to gpio controller node and array of
+ #gpio-cells specifying specific gpio (controller specific)
+ - qcom,gpio-req-tbl-num : contains index to gpios specific to the sensor
+ - qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+ qcom,gpio-req-tbl-num property (in the same order)
+ - qcom,gpio-req-tbl-label : should contain name of gpios present in
+ qcom,gpio-req-tbl-num property (in the same order)
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
index 5d80a04c0b88..38f599ba5321 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
@@ -44,12 +44,12 @@ Required Node Structure
Value type: <bool>
Definition: Enables the voltage programming through SWIRE signal.
- qcom,ext-pin-control
+- qcom,ext-pin-control
Usage: optional
Value type: <bool>
Definition: Configures the OLED module to be enabled by a external pin.
- qcom,dynamic-ext-pinctl-config
+- qcom,dynamic-ext-pinctl-config
Usage: optional
Value type: <bool>
Definition: Used to dynamically enable/disable the OLEDB module
@@ -57,13 +57,27 @@ Required Node Structure
rail. This property is applicable only if qcom,ext-pin-ctl
property is specified and it is specific to PM660A.
- qcom,pbs-control
+- qcom,force-pd-control
+ Usage: optional
+ Value type: <bool>
+ Definition: Used to enable the pull down control forcibly via SPMI by
+ disabling the pull down configuration done by hardware
+ automatically through SWIRE pulses.
+
+- qcom,pbs-client
+ Usage: optional
+ Value type: <phandle>
+ Definition: Used to send the PBS trigger to the specified PBS client.
+ This property is applicable only if qcom,force-pd-control
+ property is specified.
+
+- qcom,pbs-control
Usage: optional
Value type: <bool>
Definition: PMIC PBS logic directly configures the output voltage update
and pull down control.
- qcom,oledb-init-voltage-mv
+- qcom,oledb-init-voltage-mv
Usage: optional
Value type: <u32>
Definition: Sets the AVDD bias voltage (in mV) when the module is
@@ -71,53 +85,53 @@ Required Node Structure
property is not specified. Supported values are from 5.0V
to 8.1V with a step of 100mV.
-qcom,oledb-default-voltage-mv
+- qcom,oledb-default-voltage-mv
Usage: optional
Value type: <u32>
Definition: Sets the default AVDD bias voltage (in mV) before module
enable. Supported values are from 5.0V to 8.1V with the
step of 100mV.
-qcom,bias-gen-warmup-delay-ns
+- qcom,bias-gen-warmup-delay-ns
Usage: optional
Value type: <u32>
Definition: Bias generator warm-up time (ns). Supported values are
6700, 13300, 267000, 534000.
-qcom,peak-curr-limit-ma
+- qcom,peak-curr-limit-ma
Usage: optional
Value type: <u32>
Definition: Peak current limit (in mA). Supported values are 115, 265,
415, 570, 720, 870, 1020, 1170.
-qcom,pull-down-enable
+- qcom,pull-down-enable
Usage: optional
Value type: <u32>
Definition: Pull down configuration of OLEDB.
1 - Enable pull-down
0 - Disable pull-down
-qcom,negative-curr-limit-enable
+- qcom,negative-curr-limit-enable
Usage: optional
Value type: <u32>
Definition: negative current limit enable/disable.
1 = enable negative current limit
0 = disable negative current limit
-qcom,negative-curr-limit-ma
+- qcom,negative-curr-limit-ma
Usage: optional
Value type: <u32>
Definition: Negative current limit (in mA). Supported values are
170, 300, 420, 550.
-qcom,enable-short-circuit
+- qcom,enable-short-circuit
Usage: optional
Value type: <u32>
Definition: Short circuit protection enable/disable.
1 = enable short circuit protection
0 = disable short circuit protection
-qcom,short-circuit-dbnc-time
+- qcom,short-circuit-dbnc-time
usage: optional
Value type: <u32>
Definitioan: Short circuit debounce time (in Fsw). Supported
@@ -126,26 +140,26 @@ qcom,short-circuit-dbnc-time
Fast precharge properties:
-------------------------
-qcom,fast-precharge-ppulse-enable
+- qcom,fast-precharge-ppulse-enable
usage: optional
Value type: <u32>
Definitioan: Fast precharge pfet pulsing enable/disable.
1 = enable fast precharge pfet pulsing
0 = disable fast precharge pfet pulsing
-qcom,precharge-debounce-time-ms
+- qcom,precharge-debounce-time-ms
usage: optional
Value type: <u32>
Definitioan: Fast precharge debounce time (in ms). Supported
values are 1, 2, 4, 8.
-qcom,precharge-pulse-period-us
+- qcom,precharge-pulse-period-us
usage: optional
Value type: <u32>
Definitioan: Fast precharge pulse period (in us). Supported
values are 3, 6, 9, 12.
-qcom,precharge-pulse-on-time-us
+- qcom,precharge-pulse-on-time-us
usage: optional
Value type: <u32>
Definitioan: Fast precharge pulse on time (in ns). Supported
@@ -154,20 +168,20 @@ qcom,precharge-pulse-on-time-us
Pulse Skip Modulation (PSM) properties:
--------------------------------------
-qcom,psm-enable
+- qcom,psm-enable
Usage: optional
Value type: <u32>
Definition: Pulse Skip Modulation mode.
1 - Enable PSM mode
0 - Disable PSM mode
-qcom,psm-hys-mv
+- qcom,psm-hys-mv
Usage: optional
Value type: <u32>
Definition: PSM hysterysis voltage (in mV).
Supported values are 13mV and 26mV.
-qcom,psm-vref-mv
+- qcom,psm-vref-mv
Usage: optional
Value type: <u32>
Definition: Reference voltage(in mV) control for PSM comparator.
@@ -177,26 +191,26 @@ qcom,psm-vref-mv
Pulse Frequency Modulation (PFM) properties:
-------------------------------------------
-qcom,pfm-enable
+- qcom,pfm-enable
Usage: optional
Value type: <u32>
Definition: Pulse Frequency Modulation mode.
1 - Enable PFM mode
0 - Disable PFM mode
-qcom,pfm-hys-mv
+- qcom,pfm-hys-mv
Usage: optional
Value type: <u32>
Definition: PFM hysterysis voltage (in mV).
Supported values are 13mV and 26mV.
-qcom,pfm-curr-limit-ma
+- qcom,pfm-curr-limit-ma
Usage: optional
Value type: <u32>
Definition: PFM current limit (in mA).
Supported values are 130, 200, 270, 340.
-qcom,pfm-off-time-ns
+- qcom,pfm-off-time-ns
Usage: optional
Value type: <u32>
Definition: NFET off time at PFM (in ns).
diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt
index fe94e40a27cd..a7848153f83c 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt
+++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt
@@ -66,6 +66,40 @@ Optional properties when qcom,actuator-type is "lra"
"none", "opt1", "opt2" and "opt3" (default)
- qcom,lra-res-cal-period : Auto resonance calibration period. The values range from
4 to 32(default)
+ - qcom,perform-lra-auto-resonance-search : boolean, define this property if:
+ a) the underlying PMI chip does not have a register in the MISC block to
+ read the error percentage in RC clock
+ b) the actuator type is LRA
+ Defining this causes the auto resonance search algorithm to be be performed
+ for such devices.
+ c) This property is not defined by default.
+
+- qcom,drive-period-code-max-limit-percent-variation: RATE_CFG1 and RATE_CFG2 registers will
+ be updated with the values from AUTO_RES_LO and AUTO_RES_HI registers
+ only if the variation from the resonant frequency is within the value
+ mentioned by this property on the higher side.
+ The default value is 25, which means if the drive period code resulting
+ from AUTO_RES register's is more than 25 percent of the existing drive
+ period code, then driver does not update RATE_CFG registers.
+- qcom,drive-period-code-min-limit-percent-variation: RATE_CFG1 and RATE_CFG2 registers will
+ be updated with the values from AUTO_RES_LO and AUTO_RES_HI registers
+ only if the variation from the resonant frequency is within the value
+ mentioned by this property on the lower side.
+ The default value is 25, which means if the drive period code resulting
+ from AUTO_RES register's is less than 25 percent of the existing drive
+ period code, then driver does not update RATE_CFG registers.
+
+Optional properties when qcom,lra-auto-res-mode is "qwd"
+ - qcom,time-required-to-generate-back-emf-us: Time period required to generate sufficient
+ back-emf (in case of QWD mode only) in us. For auto resonance
+ detection to work properly,sufficient back-emf has to be
+ generated. In general, back-emf takes some time to build up.
+ When the auto resonance mode is chosen as QWD, high-z will
+ be applied for every LRA cycle and hence there won't be
+ enough back-emf at the start-up. So we need to drive the
+ motor for a few LRA cycles. Hence, auto resonance detection
+ is enabled after this delay period after the PLAY bit is
+ asserted. The default value is 20000us.
Example:
qcom,haptic@c000 {
@@ -94,4 +128,5 @@ Example:
qcom,lra-high-z = "opt1";
qcom,lra-auto-res-mode = "qwd";
qcom,lra-res-cal-period = <4>;
+ qcom,time-required-to-generate-back-emf-us = <20000>;
};
diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt
new file mode 100644
index 000000000000..d7aefbf9c19c
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt
@@ -0,0 +1,30 @@
+QPNP PBS
+
+QPNP (Qualcomm Technologies, Inc. Plug N Play) PBS is programmable boot sequence
+and this driver is for helping the client drivers triggering such sequence
+to be configured in PMIC.
+
+This document describes the bindings for QPNP PBS driver.
+
+=======================
+Required Node Structure
+=======================
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: should be "qcom,qpnp-pbs".
+
+- reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Base address of the PBS registers.
+
+
+=======
+Example
+=======
+ pm660l_pbs: qcom,pbs@7300 {
+ compatible = "qcom,qpnp-pbs";
+ reg = <0x7300 0x100>;
+ };
diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index 131ad649ef8b..b8b0f7e26dd9 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -270,6 +270,18 @@
qcom,fast-avg-setup = <0>;
};
+ chan@4e {
+ label = "emmc_therm";
+ reg = <0x4e>;
+ 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>;
+ qcom,vadc-thermal-node;
+ };
+
chan@1d {
label = "drax_temp";
reg = <0x1d>;
diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
index 20016c7ac6ec..f39cc96ea9a6 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
@@ -26,6 +26,11 @@
reg = <0x100 0x100>;
};
+ pm660l_pbs: qcom,pbs@7300 {
+ compatible = "qcom,qpnp-pbs";
+ reg = <0x7300 0x100>;
+ };
+
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
index 2cb08e1709a5..e7a61f42dff1 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -78,6 +78,26 @@
status = "disabled";
};
+ tof0:qcom,tof@0{
+ cell-index = <0>;
+ reg = <0x29>;
+ compatible = "st,stmvl53l0";
+ qcom,cci-master = <0>;
+ cam_cci-supply = <&pm8998_lvs1>;
+ cam_laser-supply = <&pmi8998_bob>;
+ qcom,cam-vreg-name = "cam_cci", "cam_laser";
+ qcom,cam-vreg-min-voltage = <0 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_tof_active>;
+ pinctrl-1 = <&cam_tof_suspend>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 126 0>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <0 0>;
+ qcom,gpio-req-tbl-label = "CAM_TOF", "CAM_CE";
+ };
+
eeprom0: qcom,eeprom@0 {
cell-index = <0>;
reg = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
index 0a41383ba874..c5384eaf17a1 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -61,7 +61,24 @@
pinctrl-0 = <&cam_actuator_vaf_active>;
pinctrl-1 = <&cam_actuator_vaf_suspend>;
};
-
+ tof0:qcom,tof@0{
+ cell-index = <0>;
+ reg = <0x29>;
+ compatible = "st,stmvl53l0";
+ qcom,cci-master = <0>;
+ cam_cci-supply = <&pm8998_lvs1>;
+ cam_laser-supply = <&pmi8998_bob>;
+ qcom,cam-vreg-name = "cam_cci", "cam_laser";
+ qcom,cam-vreg-min-voltage = <0 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_tof_active>;
+ pinctrl-1 = <&cam_tof_suspend>;
+ gpios = <&tlmm 27 0>, <&tlmm 126 0>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <0 0>;
+ qcom,gpio-req-tbl-label = "CAM_TOF", "CAM_CE";
+ };
ois0: qcom,ois@0 {
cell-index = <0>;
reg = <0x0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi
index c9522154ae7d..f4ff7c401a98 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi
@@ -55,6 +55,13 @@
/delete-property/gpios;
};
+&tof0 {
+ /delete-property/cam_cci-supply;
+ /delete-property/cam_laser-supply;
+ /delete-property/gpios;
+};
+
+
&cci {
/delete-node/qcom,camera@1;
/delete-node/qcom,camera@2;
diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
index 19b227f1b60f..4914363b414a 100644
--- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
@@ -954,6 +954,32 @@
};
};
+ cam_tof_active: cam_tof_active {
+ mux {
+ pins = "gpio27", "gpio126";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27", "gpio126";
+ bias-disable;
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_tof_suspend: cam_tof_suspend {
+ mux {
+ pins = "gpio27", "gpio126";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27", "gpio126";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
cam_sensor_mclk0_active: cam_sensor_mclk0_active {
/* MCLK0 */
mux {
diff --git a/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi b/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
index 6cef416eb5b0..6098a96db206 100644
--- a/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
@@ -18,10 +18,20 @@
label = "wb_display";
};
+ msm_ext_disp: qcom,msm_ext_disp {
+ compatible = "qcom,msm-ext-disp";
+
+ ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ qcom,msm_ext_disp = <&msm_ext_disp>;
+ };
+ };
+
sde_hdmi: qcom,hdmi-display {
compatible = "qcom,hdmi-display";
label = "sde_hdmi";
qcom,display-type = "secondary";
+ qcom,msm_ext_disp = <&msm_ext_disp>;
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
index 6db6ec2c3e92..ec70d0367160 100644
--- a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
@@ -193,8 +193,6 @@
qcom,enable-load = <0>;
qcom,disable-load = <0>;
- qcom,msm_ext_disp = <&msm_ext_disp>;
-
clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>,
<&clock_mmss clk_mmss_mdss_ahb_clk>,
<&clock_mmss clk_mmss_mdss_hdmi_clk>,
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index f33b8bc2a8a8..0e014a171156 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -3079,6 +3079,8 @@
<0xa0000000 0x10000000>,
<0xb0000000 0x10000>;
reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
+ clocks = <&clock_gcc clk_rf_clk2_pin>;
+ clock-names = "cxo_ref_clk_pin";
iommus = <&anoc2_smmu 0x1900>,
<&anoc2_smmu 0x1901>;
interrupts = <0 413 0 /* CE0 */ >,
@@ -3094,6 +3096,12 @@
<0 424 0 /* CE10 */ >,
<0 425 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x100000>;
+ vdd-0.8-cx-mx-supply = <&pm8998_l5>;
+ vdd-1.8-xo-supply = <&pm8998_l7_pin_ctrl>;
+ vdd-1.3-rfa-supply = <&pm8998_l17_pin_ctrl>;
+ vdd-3.3-ch0-supply = <&pm8998_l25_pin_ctrl>;
+ qcom,vdd-0.8-cx-mx-config = <800000 800000>;
+ qcom,vdd-3.3-ch0-config = <3104000 3312000>;
qcom,icnss-vadc = <&pm8998_vadc>;
qcom,icnss-adc_tm = <&pm8998_adc_tm>;
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
index e9c8e0456abc..2448e1894387 100644
--- a/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
@@ -56,8 +56,9 @@
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
status = "ok";
- reg = <0x5000000 0x40000>;
- reg-names = "kgsl_3d0_reg_memory";
+ reg = <0x5000000 0x40000
+ 0x780000 0x6220>;
+ reg-names = "kgsl_3d0_reg_memory", "qfprom_memory";
interrupts = <0 300 0>;
interrupt-names = "kgsl_3d0_irq";
qcom,id = <0>;
@@ -129,6 +130,8 @@
/* Context aware jump target power level */
qcom,ca-target-pwrlevel = <4>;
+ qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>;
+
/* GPU Mempools */
qcom,gpu-mempools {
#address-cells= <1>;
@@ -149,92 +152,349 @@
};
};
- /* Power levels */
- qcom,gpu-pwrlevels {
+ /*
+ * Speed-bin zero is default speed bin.
+ * For rest of the speed bins, speed-bin value
+ * is calulated as FMAX/4.8 MHz round up to zero
+ * decimal places.
+ */
+ qcom,gpu-pwrlevel-bins {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "qcom,gpu-pwrlevels";
-
- /* TURBO */
- qcom,gpu-pwrlevel@0 {
- reg = <0>;
- qcom,gpu-freq = <775000000>;
- qcom,bus-freq = <11>;
- qcom,bus-min = <10>;
- qcom,bus-max = <11>;
- };
-
- /* TURBO */
- qcom,gpu-pwrlevel@1 {
- reg = <1>;
- qcom,gpu-freq = <700000000>;
- qcom,bus-freq = <10>;
- qcom,bus-min = <9>;
- qcom,bus-max = <11>;
- };
-
- /* NOM_L1 */
- qcom,gpu-pwrlevel@2 {
- reg = <2>;
- qcom,gpu-freq = <647000000>;
- qcom,bus-freq = <9>;
- qcom,bus-min = <8>;
- qcom,bus-max = <9>;
- };
-
- /* NOM */
- qcom,gpu-pwrlevel@3 {
- reg = <3>;
- qcom,gpu-freq = <588000000>;
- qcom,bus-freq = <9>;
- qcom,bus-min = <7>;
- qcom,bus-max = <9>;
- };
-
- /* SVS_L1 */
- qcom,gpu-pwrlevel@4 {
- reg = <4>;
- qcom,gpu-freq = <465000000>;
- qcom,bus-freq = <8>;
- qcom,bus-min = <6>;
- qcom,bus-max = <9>;
- };
-
- /* SVS */
- qcom,gpu-pwrlevel@5 {
- reg = <5>;
- qcom,gpu-freq = <370000000>;
- qcom,bus-freq = <5>;
- qcom,bus-min = <4>;
- qcom,bus-max = <7>;
+ compatible="qcom,gpu-pwrlevel-bins";
+
+ qcom,gpu-pwrlevels-0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,speed-bin = <0>;
+
+ qcom,initial-pwrlevel = <5>;
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <775000000>;
+ qcom,bus-freq = <11>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <11>;
+ };
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <700000000>;
+ qcom,bus-freq = <10>;
+ qcom,bus-min = <9>;
+ qcom,bus-max = <11>;
+ };
+
+ /* NOM_L1 */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <647000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <9>;
+ };
+
+ /* NOM */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <588000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS_L1 */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <465000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <370000000>;
+ qcom,bus-freq = <5>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <7>;
+ };
+
+ /* Low SVS */
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <240000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ /* Min SVS */
+ qcom,gpu-pwrlevel@7 {
+ reg = <7>;
+ qcom,gpu-freq = <160000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <2>;
+ qcom,bus-max = <4>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@8 {
+ reg = <8>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
};
- /* Low SVS */
- qcom,gpu-pwrlevel@6 {
- reg = <6>;
- qcom,gpu-freq = <240000000>;
- qcom,bus-freq = <3>;
- qcom,bus-min = <3>;
- qcom,bus-max = <5>;
+ qcom,gpu-pwrlevels-1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,speed-bin = <162>;
+
+ qcom,initial-pwrlevel = <5>;
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <775000000>;
+ qcom,bus-freq = <11>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <11>;
+ };
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <700000000>;
+ qcom,bus-freq = <10>;
+ qcom,bus-min = <9>;
+ qcom,bus-max = <11>;
+ };
+
+ /* NOM_L1 */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <647000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <9>;
+ };
+
+ /* NOM */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <588000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS_L1 */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <465000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <370000000>;
+ qcom,bus-freq = <5>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <7>;
+ };
+
+ /* Low SVS */
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <240000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ /* Min SVS */
+ qcom,gpu-pwrlevel@7 {
+ reg = <7>;
+ qcom,gpu-freq = <160000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <2>;
+ qcom,bus-max = <4>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@8 {
+ reg = <8>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
};
- /* Min SVS */
- qcom,gpu-pwrlevel@7 {
- reg = <7>;
- qcom,gpu-freq = <160000000>;
- qcom,bus-freq = <3>;
- qcom,bus-min = <2>;
- qcom,bus-max = <4>;
+ qcom,gpu-pwrlevels-2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,speed-bin = <146>;
+
+ qcom,initial-pwrlevel = <4>;
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <700000000>;
+ qcom,bus-freq = <11>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <11>;
+ };
+
+ /* NOM_L1 */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <647000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <9>;
+ };
+
+ /* NOM */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <588000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS_L1 */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <465000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <370000000>;
+ qcom,bus-freq = <5>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <7>;
+ };
+
+ /* Low SVS */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <240000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ /* Min SVS */
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <160000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <2>;
+ qcom,bus-max = <4>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@7 {
+ reg = <7>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
};
- /* XO */
- qcom,gpu-pwrlevel@8 {
- reg = <8>;
- qcom,gpu-freq = <19200000>;
- qcom,bus-freq = <0>;
- qcom,bus-min = <0>;
- qcom,bus-max = <0>;
+ qcom,gpu-pwrlevels-3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,speed-bin = <135>;
+
+ qcom,initial-pwrlevel = <3>;
+
+ /* NOM_L1 */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <647000000>;
+ qcom,bus-freq = <11>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <11>;
+ };
+
+ /* NOM */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <588000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS_L1 */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <465000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <370000000>;
+ qcom,bus-freq = <5>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <7>;
+ };
+
+ /* Low SVS */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <240000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ /* Min SVS */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <160000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <2>;
+ qcom,bus-max = <4>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index a53094c2e125..cd895a067f65 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -1118,7 +1118,7 @@
qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
qcom,target-dev = <&memlat_cpu0>;
qcom,core-dev-table =
- < 787200 762 >,
+ < 1113600 762 >,
< 1344000 2086 >,
< 1670400 2929 >,
< 2150400 3879 >,
@@ -1767,9 +1767,9 @@
reg = <0x10 8>;
};
- dload_type@18 {
+ dload_type@1c {
compatible = "qcom,msm-imem-dload-type";
- reg = <0x18 4>;
+ reg = <0x1c 4>;
};
restart_reason@65c {
diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
index dc57ee62a867..d4461395891a 100644
--- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
@@ -467,10 +467,10 @@
qcom,devfreq,freq-table = <50000000 200000000>;
qcom,pm-qos-irq-type = "affine_irq";
- qcom,pm-qos-irq-latency = <26 81>;
+ qcom,pm-qos-irq-latency = <43 377>;
qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
- qcom,pm-qos-cmdq-latency-us = <26 81>, <26 81>;
- qcom,pm-qos-legacy-latency-us = <26 81>, <26 81>;
+ qcom,pm-qos-cmdq-latency-us = <43 377>, <40 325>;
+ qcom,pm-qos-legacy-latency-us = <43 377>, <40 325>;
qcom,msm-bus,name = "sdhc1";
qcom,msm-bus,num-cases = <9>;
@@ -531,9 +531,9 @@
qcom,devfreq,freq-table = <50000000 200000000>;
qcom,pm-qos-irq-type = "affine_irq";
- qcom,pm-qos-irq-latency = <26 81>;
+ qcom,pm-qos-irq-latency = <43 377>;
qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
- qcom,pm-qos-legacy-latency-us = <26 81>, <26 81>;
+ qcom,pm-qos-legacy-latency-us = <43 377>, <40 325>;
clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
<&clock_gcc GCC_SDCC2_APPS_CLK>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
index e5cf0b1534ec..a47a788874fa 100644
--- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
@@ -119,8 +119,8 @@
vdd-supply = <&gdsc_gpu_gx>;
/* CPU latency parameter */
- qcom,pm-qos-active-latency = <349>;
- qcom,pm-qos-wakeup-latency = <349>;
+ qcom,pm-qos-active-latency = <518>;
+ qcom,pm-qos-wakeup-latency = <518>;
/* Quirks */
qcom,gpu-quirk-dp2clockgating-disable;
diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi
index 9ba63be179ea..2d44c69ea827 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -320,10 +320,16 @@
reg = <0x0 0x92a00000 0x0 0x1e00000>;
};
- cdsp_fw_mem: cdsp_fw_region@94800000 {
+ pil_mba_mem: pil_mba_region@94800000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x0 0x94800000 0x0 0x600000>;
+ reg = <0x0 0x94800000 0x0 0x200000>;
+ };
+
+ cdsp_fw_mem: cdsp_fw_region@94a00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x94a00000 0x0 0x600000>;
};
venus_fw_mem: venus_fw_region {
@@ -1966,6 +1972,10 @@
/* GPIO output to mss */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
status = "ok";
+ qcom,mba-mem@0 {
+ compatible = "qcom,pil-mba-mem";
+ memory-region = <&pil_mba_mem>;
+ };
};
qcom,msm-rtb {
@@ -1991,9 +2001,9 @@
reg = <0x10 8>;
};
- dload_type@18 {
+ dload_type@1c {
compatible = "qcom,msm-imem-dload-type";
- reg = <0x18 4>;
+ reg = <0x1c 4>;
};
restart_reason@65c {
diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig
index cb20c31ccf1b..309d7a802d07 100644
--- a/arch/arm/configs/sdm660-perf_defconfig
+++ b/arch/arm/configs/sdm660-perf_defconfig
@@ -510,6 +510,7 @@ CONFIG_IOMMU_TESTS=y
CONFIG_QCOM_COMMON_LOG=y
CONFIG_MSM_SMEM=y
CONFIG_QPNP_HAPTIC=y
+CONFIG_QPNP_PBS=y
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_DEBUG=y
CONFIG_MSM_GLINK=y
@@ -641,4 +642,8 @@ CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
CONFIG_CRYPTO_DEV_QCOM_ICE=y
CONFIG_SYSTEM_TRUSTED_KEYS="verity.x509.pem"
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
CONFIG_XZ_DEC=y
diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig
index 37ace58ef8d8..a6a831aba9dc 100644
--- a/arch/arm/configs/sdm660_defconfig
+++ b/arch/arm/configs/sdm660_defconfig
@@ -510,6 +510,7 @@ CONFIG_IOMMU_TESTS=y
CONFIG_QCOM_COMMON_LOG=y
CONFIG_MSM_SMEM=y
CONFIG_QPNP_HAPTIC=y
+CONFIG_QPNP_PBS=y
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_DEBUG=y
CONFIG_MSM_GLINK=y
@@ -536,7 +537,6 @@ CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_IRQ_HELPER=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_ICNSS=y
-CONFIG_ICNSS_DEBUG=y
CONFIG_MSM_GLADIATOR_ERP_V2=y
CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
@@ -681,4 +681,8 @@ CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
CONFIG_CRYPTO_DEV_QCOM_ICE=y
CONFIG_SYSTEM_TRUSTED_KEYS="verity.x509.pem"
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
CONFIG_XZ_DEC=y
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
index 967edf184f1b..27055fc4b9d5 100644
--- a/arch/arm64/configs/msmcortex_mediabox_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -349,7 +349,6 @@ CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_I2C_PMIC=y
CONFIG_WCD9335_CODEC=y
CONFIG_WCD934X_CODEC=y
-CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_RPM_SMD=y
CONFIG_REGULATOR_QPNP=y
@@ -408,14 +407,8 @@ CONFIG_DVB_MPQ_DEMUX=m
CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y
CONFIG_TSPP=m
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_DRM=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
@@ -497,6 +490,7 @@ 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
@@ -545,7 +539,6 @@ CONFIG_MSM_SYSMON_GLINK_COMM=y
CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SPM=y
-CONFIG_QCOM_SCM=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_IRQ_HELPER=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
@@ -608,7 +601,6 @@ CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_EFIVAR_FS=y
CONFIG_ECRYPT_FS=y
diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig
index 29b2c75e70f3..b0bdabf58d62 100644
--- a/arch/arm64/configs/sdm660-perf_defconfig
+++ b/arch/arm64/configs/sdm660-perf_defconfig
@@ -527,6 +527,7 @@ CONFIG_IOMMU_DEBUG_TRACKING=y
CONFIG_IOMMU_TESTS=y
CONFIG_MSM_SMEM=y
CONFIG_QPNP_HAPTIC=y
+CONFIG_QPNP_PBS=y
CONFIG_MSM_SMD=y
CONFIG_MSM_GLINK=y
CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index adfcc6c9531c..7b21409c3266 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -541,6 +541,7 @@ CONFIG_IOMMU_TESTS=y
CONFIG_QCOM_COMMON_LOG=y
CONFIG_MSM_SMEM=y
CONFIG_QPNP_HAPTIC=y
+CONFIG_QPNP_PBS=y
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_DEBUG=y
CONFIG_MSM_GLINK=y
@@ -568,7 +569,6 @@ CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_IRQ_HELPER=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_ICNSS=y
-CONFIG_ICNSS_DEBUG=y
CONFIG_MSM_GLADIATOR_ERP_V2=y
CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
@@ -687,6 +687,7 @@ CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_DEBUG_RODATA=y
CONFIG_FREE_PAGES_RDONLY=y
+CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index 85aea381fbf6..cb3eec8e8e50 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -69,6 +69,8 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
frame->fp = *(unsigned long *)(fp);
frame->pc = *(unsigned long *)(fp + 8);
+ kasan_enable_current();
+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
if (tsk && tsk->ret_stack &&
(frame->pc == (unsigned long)return_to_handler)) {
@@ -112,8 +114,6 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
}
}
- kasan_enable_current();
-
return 0;
}
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 87a48268b663..1c6e4da01e69 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -307,8 +307,7 @@ static const char * const fw_path[] = {
"/lib/firmware/updates/" UTS_RELEASE,
"/lib/firmware/updates",
"/lib/firmware/" UTS_RELEASE,
- "/lib/firmware",
- "/firmware/image"
+ "/lib/firmware"
};
/*
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 88bd6afdeea5..9ca46ae54ce3 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1951,6 +1951,8 @@ static void fastrpc_channel_close(struct kref *kref)
cid = ctx - &gcinfo[0];
fastrpc_glink_close(ctx->chan, cid);
ctx->chan = 0;
+ glink_unregister_link_state_cb(ctx->link.link_notify_handle);
+ ctx->link.link_notify_handle = 0;
mutex_unlock(&me->smd_mutex);
pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
MAJOR(me->dev_no), cid);
diff --git a/drivers/clk/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c
index 1661878fc650..6ebb3ed6ed91 100644
--- a/drivers/clk/msm/clock-mmss-8998.c
+++ b/drivers/clk/msm/clock-mmss-8998.c
@@ -664,8 +664,8 @@ static struct rcg_clk byte0_clk_src = {
.parent = &ext_byte0_clk_src.c,
.ops = &clk_ops_byte_multiparent,
.flags = CLKFLAG_NO_RATE_CACHE,
- VDD_DIG_FMAX_MAP3(LOWER, 150000000, LOW, 240000000,
- NOMINAL, 357140000),
+ VDD_DIG_FMAX_MAP3(LOWER, 131250000, LOW, 210000000,
+ NOMINAL, 312500000),
CLK_INIT(byte0_clk_src.c),
},
};
@@ -681,8 +681,8 @@ static struct rcg_clk byte1_clk_src = {
.parent = &ext_byte1_clk_src.c,
.ops = &clk_ops_byte_multiparent,
.flags = CLKFLAG_NO_RATE_CACHE,
- VDD_DIG_FMAX_MAP3(LOWER, 150000000, LOW, 240000000,
- NOMINAL, 357140000),
+ VDD_DIG_FMAX_MAP3(LOWER, 131250000, LOW, 210000000,
+ NOMINAL, 312500000),
CLK_INIT(byte1_clk_src.c),
},
};
@@ -722,8 +722,8 @@ static struct rcg_clk pclk0_clk_src = {
.parent = &ext_pclk0_clk_src.c,
.ops = &clk_ops_pixel_multiparent,
.flags = CLKFLAG_NO_RATE_CACHE,
- VDD_DIG_FMAX_MAP3(LOWER, 184000000, LOW, 295000000,
- NOMINAL, 610000000),
+ VDD_DIG_FMAX_MAP3(LOWER, 175000000, LOW, 280000000,
+ NOMINAL, 416670000),
CLK_INIT(pclk0_clk_src.c),
},
};
@@ -739,8 +739,8 @@ static struct rcg_clk pclk1_clk_src = {
.parent = &ext_pclk1_clk_src.c,
.ops = &clk_ops_pixel_multiparent,
.flags = CLKFLAG_NO_RATE_CACHE,
- VDD_DIG_FMAX_MAP3(LOWER, 184000000, LOW, 295000000,
- NOMINAL, 610000000),
+ VDD_DIG_FMAX_MAP3(LOWER, 175000000, LOW, 280000000,
+ NOMINAL, 416670000),
CLK_INIT(pclk1_clk_src.c),
},
};
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 62675198d6ac..5838545468f8 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -11,6 +11,7 @@ config DRM_MSM
select TMPFS
select QCOM_SCM
select BACKLIGHT_CLASS_DEVICE
+ select MSM_EXT_DISPLAY
default y
help
DRM/KMS driver for MSM/snapdragon.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d81ec8918ce7..79ea5a9f90ea 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -100,7 +100,8 @@ msm_drm-$(CONFIG_DRM_MSM_DSI_STAGING) += dsi-staging/dsi_phy.o \
msm_drm-$(CONFIG_DRM_SDE_HDMI) += \
hdmi-staging/sde_hdmi.o \
hdmi-staging/sde_hdmi_bridge.o \
- hdmi-staging/sde_hdmi_audio.o
+ hdmi-staging/sde_hdmi_audio.o \
+ hdmi-staging/sde_hdmi_edid.o
msm_drm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \
dsi/pll/dsi_pll_28nm.o
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 15e2d69827e7..347b78886b24 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -22,8 +22,10 @@
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include "sde_kms.h"
+#include "sde_connector.h"
#include "msm_drv.h"
#include "sde_hdmi.h"
@@ -402,6 +404,13 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work)
}
connector = sde_hdmi->ctrl.ctrl->connector;
+
+ if (sde_hdmi->connected)
+ sde_hdmi_get_edid(connector, sde_hdmi);
+ else
+ sde_hdmi_free_edid(sde_hdmi);
+
+ sde_hdmi_notify_clients(connector, sde_hdmi->connected);
drm_helper_hpd_irq_event(connector->dev);
}
@@ -431,7 +440,8 @@ static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi)
hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
- queue_work(hdmi->workq, &sde_hdmi->hpd_work);
+ if (!sde_hdmi->non_pluggable)
+ queue_work(hdmi->workq, &sde_hdmi->hpd_work);
}
}
@@ -460,6 +470,148 @@ static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int _sde_hdmi_audio_info_setup(struct platform_device *pdev,
+ struct msm_ext_disp_audio_setup_params *params)
+{
+ int rc = -EPERM;
+ struct sde_hdmi *display = NULL;
+ struct hdmi *hdmi = NULL;
+
+ display = platform_get_drvdata(pdev);
+
+ if (!display || !params) {
+ SDE_ERROR("invalid param(s), display %pK, params %pK\n",
+ display, params);
+ return -ENODEV;
+ }
+
+ hdmi = display->ctrl.ctrl;
+
+ if (hdmi->hdmi_mode)
+ rc = sde_hdmi_audio_on(hdmi, params);
+
+ return rc;
+}
+
+static int _sde_hdmi_get_audio_edid_blk(struct platform_device *pdev,
+ struct msm_ext_disp_audio_edid_blk *blk)
+{
+ struct sde_hdmi *display = platform_get_drvdata(pdev);
+
+ if (!display || !blk) {
+ SDE_ERROR("invalid param(s), display %pK, blk %pK\n",
+ display, blk);
+ return -ENODEV;
+ }
+
+ blk->audio_data_blk = display->edid.audio_data_block;
+ blk->audio_data_blk_size = display->edid.adb_size;
+
+ blk->spk_alloc_data_blk = display->edid.spkr_alloc_data_block;
+ blk->spk_alloc_data_blk_size = display->edid.sadb_size;
+
+ return 0;
+}
+
+static int _sde_hdmi_get_cable_status(struct platform_device *pdev, u32 vote)
+{
+ struct sde_hdmi *display = NULL;
+ struct hdmi *hdmi = NULL;
+
+ display = platform_get_drvdata(pdev);
+
+ if (!display) {
+ SDE_ERROR("invalid param(s), display %pK\n", display);
+ return -ENODEV;
+ }
+
+ hdmi = display->ctrl.ctrl;
+
+ return hdmi->power_on && display->connected;
+}
+
+static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display)
+{
+ int rc = 0;
+ struct device_node *pd_np;
+ const char *phandle = "qcom,msm_ext_disp";
+
+ if (!display) {
+ SDE_ERROR("[%s]Invalid params\n", display->name);
+ return -EINVAL;
+ }
+
+ display->ext_audio_data.type = EXT_DISPLAY_TYPE_HDMI;
+ display->ext_audio_data.pdev = display->pdev;
+ display->ext_audio_data.codec_ops.audio_info_setup =
+ _sde_hdmi_audio_info_setup;
+ display->ext_audio_data.codec_ops.get_audio_edid_blk =
+ _sde_hdmi_get_audio_edid_blk;
+ display->ext_audio_data.codec_ops.cable_status =
+ _sde_hdmi_get_cable_status;
+
+ if (!display->pdev->dev.of_node) {
+ SDE_ERROR("[%s]cannot find sde_hdmi of_node\n", display->name);
+ return -ENODEV;
+ }
+
+ pd_np = of_parse_phandle(display->pdev->dev.of_node, phandle, 0);
+ if (!pd_np) {
+ SDE_ERROR("[%s]cannot find %s device node\n",
+ display->name, phandle);
+ return -ENODEV;
+ }
+
+ display->ext_pdev = of_find_device_by_node(pd_np);
+ if (!display->ext_pdev) {
+ SDE_ERROR("[%s]cannot find %s platform device\n",
+ display->name, phandle);
+ return -ENODEV;
+ }
+
+ rc = msm_ext_disp_register_intf(display->ext_pdev,
+ &display->ext_audio_data);
+ if (rc)
+ SDE_ERROR("[%s]failed to register disp\n", display->name);
+
+ return rc;
+}
+
+void sde_hdmi_notify_clients(struct drm_connector *connector,
+ bool connected)
+{
+ struct sde_connector *c_conn = to_sde_connector(connector);
+ struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+ int state = connected ?
+ EXT_DISPLAY_CABLE_CONNECT : EXT_DISPLAY_CABLE_DISCONNECT;
+
+ if (display && display->ext_audio_data.intf_ops.hpd) {
+ struct hdmi *hdmi = display->ctrl.ctrl;
+ u32 flags = MSM_EXT_DISP_HPD_VIDEO;
+
+ if (hdmi->hdmi_mode)
+ flags |= MSM_EXT_DISP_HPD_AUDIO;
+
+ display->ext_audio_data.intf_ops.hpd(display->ext_pdev,
+ display->ext_audio_data.type, state, flags);
+ }
+}
+
+void sde_hdmi_ack_state(struct drm_connector *connector,
+ enum drm_connector_status status)
+{
+ struct sde_connector *c_conn = to_sde_connector(connector);
+ struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+
+ if (display) {
+ struct hdmi *hdmi = display->ctrl.ctrl;
+
+ if (hdmi->hdmi_mode && display->ext_audio_data.intf_ops.notify)
+ display->ext_audio_data.intf_ops.notify(
+ display->ext_pdev, status);
+ }
+}
+
void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
{
uint32_t ctrl = 0;
@@ -645,13 +797,29 @@ sde_hdmi_connector_detect(struct drm_connector *connector,
return status;
}
+int _sde_hdmi_update_modes(struct drm_connector *connector,
+ struct sde_hdmi *display)
+{
+ int rc = 0;
+ struct hdmi_edid_ctrl *edid_ctrl = &display->edid;
+
+ if (edid_ctrl->edid) {
+ drm_mode_connector_update_edid_property(connector,
+ edid_ctrl->edid);
+
+ rc = drm_add_edid_modes(connector, edid_ctrl->edid);
+ return rc;
+ }
+
+ drm_mode_connector_update_edid_property(connector, NULL);
+
+ return rc;
+}
+
int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
{
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
- struct hdmi *hdmi;
- struct edid *edid;
struct drm_display_mode *mode, *m;
- uint32_t hdmi_ctrl;
int ret = 0;
if (!connector || !display) {
@@ -662,7 +830,6 @@ int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
SDE_DEBUG("\n");
- hdmi = hdmi_display->ctrl.ctrl;
if (hdmi_display->non_pluggable) {
list_for_each_entry(mode, &hdmi_display->mode_list, head) {
m = drm_mode_duplicate(connector->dev, mode);
@@ -675,21 +842,7 @@ int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
}
ret = hdmi_display->num_of_modes;
} else {
- /* Read EDID */
- hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
- hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
-
- edid = drm_get_edid(connector, hdmi->i2c);
-
- hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
-
- hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
- drm_mode_connector_update_edid_property(connector, edid);
-
- if (edid) {
- ret = drm_add_edid_modes(connector, edid);
- kfree(edid);
- }
+ ret = _sde_hdmi_update_modes(connector, display);
}
return ret;
@@ -778,6 +931,20 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
if (rc) {
SDE_ERROR("[%s]Debugfs init failed, rc=%d\n",
display->name, rc);
+ goto debug_error;
+ }
+
+ rc = _sde_hdmi_ext_disp_init(display);
+ if (rc) {
+ SDE_ERROR("[%s]Ext Disp init failed, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+
+ rc = sde_hdmi_edid_init(display);
+ if (rc) {
+ SDE_ERROR("[%s]Ext Disp init failed, rc=%d\n",
+ display->name, rc);
goto error;
}
@@ -787,6 +954,8 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
display->drm_dev = drm;
error:
+ (void)_sde_hdmi_debugfs_deinit(display);
+debug_error:
mutex_unlock(&display->display_lock);
return rc;
}
@@ -809,6 +978,7 @@ static void sde_hdmi_unbind(struct device *dev, struct device *master,
}
mutex_lock(&display->display_lock);
(void)_sde_hdmi_debugfs_deinit(display);
+ (void)sde_hdmi_edid_deinit(display);
display->drm_dev = NULL;
mutex_unlock(&display->display_lock);
}
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 1c13d9f875f2..869d1bebf9db 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -25,6 +25,10 @@
#include <drm/drm_crtc.h>
#include "hdmi.h"
+#define MAX_NUMBER_ADB 5
+#define MAX_AUDIO_DATA_BLOCK_SIZE 30
+#define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3
+
/**
* struct sde_hdmi_info - defines hdmi display properties
* @display_type: Display type as defined by device tree.
@@ -60,6 +64,14 @@ struct sde_hdmi_ctrl {
u32 hdmi_ctrl_idx;
};
+struct hdmi_edid_ctrl {
+ struct edid *edid;
+ u8 audio_data_block[MAX_NUMBER_ADB * MAX_AUDIO_DATA_BLOCK_SIZE];
+ int adb_size;
+ u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
+ int sadb_size;
+};
+
/**
* struct sde_hdmi - hdmi display information
* @pdev: Pointer to platform device.
@@ -88,6 +100,10 @@ struct sde_hdmi {
struct sde_hdmi_ctrl ctrl;
+ struct platform_device *ext_pdev;
+ struct msm_ext_disp_init_data ext_audio_data;
+ struct hdmi_edid_ctrl edid;
+
bool non_pluggable;
u32 num_of_modes;
struct list_head mode_list;
@@ -268,6 +284,61 @@ void sde_hdmi_audio_off(struct hdmi *hdmi);
* Return: error code.
*/
int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set);
+
+/**
+ * sde_hdmi_notify_clients() - notify hdmi clients of the connection status.
+ * @connector: Handle to the drm_connector.
+ * @connected: connection status.
+ *
+ * Return: void.
+ */
+void sde_hdmi_notify_clients(struct drm_connector *connector,
+ bool connected);
+
+/**
+ * sde_hdmi_ack_state() - acknowledge the connection status.
+ * @connector: Handle to the drm_connector.
+ * @status: connection status.
+ *
+ * Return: void.
+ */
+void sde_hdmi_ack_state(struct drm_connector *connector,
+ enum drm_connector_status status);
+
+/**
+ * sde_hdmi_edid_init() - init edid structure.
+ * @display: Handle to the sde_hdmi.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_edid_init(struct sde_hdmi *display);
+
+/**
+ * sde_hdmi_edid_deinit() - deinit edid structure.
+ * @display: Handle to the sde_hdmi.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_edid_deinit(struct sde_hdmi *display);
+
+/**
+ * sde_hdmi_get_edid() - get edid info.
+ * @connector: Handle to the drm_connector.
+ * @display: Handle to the sde_hdmi.
+ *
+ * Return: void.
+ */
+void sde_hdmi_get_edid(struct drm_connector *connector,
+ struct sde_hdmi *display);
+
+/**
+ * sde_hdmi_free_edid() - free edid structure.
+ * @display: Handle to the sde_hdmi.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_free_edid(struct sde_hdmi *display);
+
#else /*#ifdef CONFIG_DRM_SDE_HDMI*/
static inline u32 sde_hdmi_get_num_of_displays(void)
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
index ecfff7e88689..681dca501f9b 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -18,6 +18,7 @@
#include "drm_edid.h"
#include "sde_kms.h"
+#include "sde_connector.h"
#include "sde_hdmi.h"
#include "hdmi.h"
@@ -111,7 +112,6 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
if (!hdmi->power_on) {
_sde_hdmi_bridge_power_on(bridge);
hdmi->power_on = true;
- hdmi_audio_update(hdmi);
}
if (phy)
@@ -121,14 +121,42 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
hdmi_hdcp_ctrl_on(hdmi->hdcp_ctrl);
+
+ sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_CONNECT);
+}
+
+static void sde_hdmi_force_update_audio(struct drm_connector *connector,
+ enum drm_connector_status status)
+{
+ struct sde_connector *c_conn = to_sde_connector(connector);
+ struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+
+ if (display && display->non_pluggable) {
+ display->ext_audio_data.intf_ops.hpd(display->ext_pdev,
+ display->ext_audio_data.type,
+ status,
+ MSM_EXT_DISP_HPD_AUDIO);
+ }
}
static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
{
+ struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
+ struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
+
+ /* force update audio ops when there's no HPD event */
+ sde_hdmi_force_update_audio(hdmi->connector,
+ EXT_DISPLAY_CABLE_CONNECT);
}
static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
{
+ struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
+ struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
+
+ /* force update audio ops when there's no HPD event */
+ sde_hdmi_force_update_audio(hdmi->connector,
+ EXT_DISPLAY_CABLE_DISCONNECT);
}
static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
@@ -140,6 +168,8 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl);
+ sde_hdmi_audio_off(hdmi);
+
DRM_DEBUG("power down");
sde_hdmi_set_mode(hdmi, false);
@@ -149,8 +179,9 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
if (hdmi->power_on) {
_sde_hdmi_bridge_power_off(bridge);
hdmi->power_on = false;
- hdmi_audio_update(hdmi);
}
+
+ sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_DISCONNECT);
}
static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi,
@@ -342,8 +373,6 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
_sde_hdmi_bridge_set_spd_infoframe(hdmi, mode);
DRM_DEBUG("hdmi setup info frame\n");
}
-
- hdmi_audio_update(hdmi);
}
static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = {
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c
new file mode 100644
index 000000000000..57c79e2aa812
--- /dev/null
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c
@@ -0,0 +1,227 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drm_edid.h>
+
+#include "sde_kms.h"
+#include "sde_hdmi.h"
+
+/* TODO: copy from drm_edid.c and mdss_hdmi_edid.c. remove if using ELD */
+#define DBC_START_OFFSET 4
+#define EDID_DTD_LEN 18
+
+enum data_block_types {
+ RESERVED,
+ AUDIO_DATA_BLOCK,
+ VIDEO_DATA_BLOCK,
+ VENDOR_SPECIFIC_DATA_BLOCK,
+ SPEAKER_ALLOCATION_DATA_BLOCK,
+ VESA_DTC_DATA_BLOCK,
+ RESERVED2,
+ USE_EXTENDED_TAG
+};
+
+static u8 *_sde_hdmi_edid_find_cea_extension(struct edid *edid)
+{
+ u8 *edid_ext = NULL;
+ int i;
+
+ /* No EDID or EDID extensions */
+ if (edid == NULL || edid->extensions == 0)
+ return NULL;
+
+ /* Find CEA extension */
+ for (i = 0; i < edid->extensions; i++) {
+ edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
+ if (edid_ext[0] == CEA_EXT)
+ break;
+ }
+
+ if (i == edid->extensions)
+ return NULL;
+
+ return edid_ext;
+}
+
+static const u8 *_sde_hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
+ u8 type, u8 *len)
+{
+ /* the start of data block collection, start of Video Data Block */
+ u32 offset = start_offset;
+ u32 dbc_offset = in_buf[2];
+
+ /*
+ * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
+ * collection present.
+ * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block
+ * collection present and no DTD data present.
+ */
+ if ((dbc_offset == 0) || (dbc_offset == 4)) {
+ SDE_ERROR("EDID: no DTD or non-DTD data present\n");
+ return NULL;
+ }
+
+ while (offset < dbc_offset) {
+ u8 block_len = in_buf[offset] & 0x1F;
+
+ if ((offset + block_len <= dbc_offset) &&
+ (in_buf[offset] >> 5) == type) {
+ *len = block_len;
+ SDE_DEBUG("EDID: block=%d found @ 0x%x w/ len=%d\n",
+ type, offset, block_len);
+
+ return in_buf + offset;
+ }
+ offset += 1 + block_len;
+ }
+
+ return NULL;
+}
+
+static void _sde_hdmi_extract_audio_data_blocks(
+ struct hdmi_edid_ctrl *edid_ctrl)
+{
+ u8 len = 0;
+ u8 adb_max = 0;
+ const u8 *adb = NULL;
+ u32 offset = DBC_START_OFFSET;
+ u8 *cea = NULL;
+
+ if (!edid_ctrl) {
+ SDE_ERROR("invalid edid_ctrl\n");
+ return;
+ }
+
+ cea = _sde_hdmi_edid_find_cea_extension(edid_ctrl->edid);
+ if (!cea) {
+ SDE_DEBUG("CEA extension not found\n");
+ return;
+ }
+
+ edid_ctrl->adb_size = 0;
+
+ memset(edid_ctrl->audio_data_block, 0,
+ sizeof(edid_ctrl->audio_data_block));
+
+ do {
+ len = 0;
+ adb = _sde_hdmi_edid_find_block(cea, offset, AUDIO_DATA_BLOCK,
+ &len);
+
+ if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE ||
+ adb_max >= MAX_NUMBER_ADB)) {
+ if (!edid_ctrl->adb_size) {
+ SDE_DEBUG("No/Invalid Audio Data Block\n");
+ return;
+ }
+
+ continue;
+ }
+
+ memcpy(edid_ctrl->audio_data_block + edid_ctrl->adb_size,
+ adb + 1, len);
+ offset = (adb - cea) + 1 + len;
+
+ edid_ctrl->adb_size += len;
+ adb_max++;
+ } while (adb);
+
+}
+
+static void _sde_hdmi_extract_speaker_allocation_data(
+ struct hdmi_edid_ctrl *edid_ctrl)
+{
+ u8 len;
+ const u8 *sadb = NULL;
+ u8 *cea = NULL;
+
+ if (!edid_ctrl) {
+ SDE_ERROR("invalid edid_ctrl\n");
+ return;
+ }
+
+ cea = _sde_hdmi_edid_find_cea_extension(edid_ctrl->edid);
+ if (!cea) {
+ SDE_DEBUG("CEA extension not found\n");
+ return;
+ }
+
+ sadb = _sde_hdmi_edid_find_block(cea, DBC_START_OFFSET,
+ SPEAKER_ALLOCATION_DATA_BLOCK, &len);
+ if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) {
+ SDE_DEBUG("No/Invalid Speaker Allocation Data Block\n");
+ return;
+ }
+
+ memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
+ edid_ctrl->sadb_size = len;
+
+ SDE_DEBUG("EDID: speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
+ sadb[1],
+ (sadb[1] & BIT(0)) ? "FL/FR," : "",
+ (sadb[1] & BIT(1)) ? "LFE," : "",
+ (sadb[1] & BIT(2)) ? "FC," : "",
+ (sadb[1] & BIT(3)) ? "RL/RR," : "",
+ (sadb[1] & BIT(4)) ? "RC," : "",
+ (sadb[1] & BIT(5)) ? "FLC/FRC," : "",
+ (sadb[1] & BIT(6)) ? "RLC/RRC," : "");
+}
+
+int sde_hdmi_edid_init(struct sde_hdmi *display)
+{
+ int rc = 0;
+
+ if (!display) {
+ SDE_ERROR("[%s]Invalid params\n", display->name);
+ return -EINVAL;
+ }
+
+ memset(&display->edid, 0, sizeof(display->edid));
+
+ return rc;
+}
+
+int sde_hdmi_free_edid(struct sde_hdmi *display)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = &display->edid;
+
+ kfree(edid_ctrl->edid);
+ edid_ctrl->edid = NULL;
+
+ return 0;
+}
+
+int sde_hdmi_edid_deinit(struct sde_hdmi *display)
+{
+ return sde_hdmi_free_edid(display);
+}
+
+void sde_hdmi_get_edid(struct drm_connector *connector,
+ struct sde_hdmi *display)
+{
+ u32 hdmi_ctrl;
+ struct hdmi_edid_ctrl *edid_ctrl = &display->edid;
+ struct hdmi *hdmi = display->ctrl.ctrl;
+
+ /* Read EDID */
+ hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
+ hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
+ edid_ctrl->edid = drm_get_edid(connector, hdmi->i2c);
+ hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
+
+ if (edid_ctrl->edid) {
+ hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid_ctrl->edid);
+
+ _sde_hdmi_extract_audio_data_blocks(edid_ctrl);
+ _sde_hdmi_extract_speaker_allocation_data(edid_ctrl);
+ }
+};
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 42bbbdcab2c9..dc7827872276 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -102,169 +102,169 @@ flg, fm, np) \
static const struct sde_format sde_format_map[] = {
INTERLEAVED_RGB_FMT(ARGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGB888,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
false, 3, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGR888,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 3, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGB565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ARGB1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ARGB4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
@@ -366,13 +366,13 @@ static const struct sde_format sde_format_map[] = {
PLANAR_YUV_FMT(YUV420,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C0_G_Y, C1_B_Cb, C2_R_Cr,
+ C2_R_Cr, C1_B_Cb, C0_G_Y,
false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV,
SDE_FETCH_LINEAR, 3),
PLANAR_YUV_FMT(YVU420,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C0_G_Y, C2_R_Cr, C1_B_Cb,
+ C1_B_Cb, C2_R_Cr, C0_G_Y,
false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV,
SDE_FETCH_LINEAR, 3),
};
@@ -384,19 +384,19 @@ static const struct sde_format sde_format_map[] = {
* the data will be passed by user-space.
*/
static const struct sde_format sde_format_map_ubwc[] = {
- INTERLEAVED_RGB_FMT(RGB565,
+ INTERLEAVED_RGB_FMT(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, 0,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBA8888,
+ INTERLEAVED_RGB_FMT(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBX8888,
+ INTERLEAVED_RGB_FMT(XBGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, 0,
@@ -513,14 +513,15 @@ static int _sde_format_get_plane_sizes_ubwc(
ALIGN(DIV_ROUND_UP(height / 2, uv_tile_height), 16),
4096);
- } else if (fmt->base.pixel_format == DRM_FORMAT_RGBA8888 ||
- fmt->base.pixel_format == DRM_FORMAT_RGBX8888 ||
- fmt->base.pixel_format == DRM_FORMAT_RGBA1010102 ||
- fmt->base.pixel_format == DRM_FORMAT_RGBX1010102 ||
- fmt->base.pixel_format == DRM_FORMAT_RGB565) {
+ } else if (fmt->base.pixel_format == DRM_FORMAT_ABGR8888 ||
+ fmt->base.pixel_format == DRM_FORMAT_XBGR8888 ||
+ fmt->base.pixel_format == DRM_FORMAT_BGRA1010102 ||
+ fmt->base.pixel_format == DRM_FORMAT_BGRX1010102 ||
+ fmt->base.pixel_format == DRM_FORMAT_BGR565) {
+
uint32_t stride_alignment, aligned_bitstream_width;
- if (fmt->base.pixel_format == DRM_FORMAT_RGB565)
+ if (fmt->base.pixel_format == DRM_FORMAT_BGR565)
stride_alignment = 128;
else
stride_alignment = 64;
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 973884c2c5e7..b58391adf3ab 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -161,6 +161,7 @@ static const struct {
{ adreno_is_a530, a530_efuse_speed_bin },
{ adreno_is_a505, a530_efuse_speed_bin },
{ adreno_is_a512, a530_efuse_speed_bin },
+ { adreno_is_a508, a530_efuse_speed_bin },
};
static void a5xx_check_features(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 601e7a23101b..1de8e212a703 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -4753,6 +4753,7 @@ error_close_mmu:
error_pwrctrl_close:
kgsl_pwrctrl_close(device);
error:
+ kgsl_device_debugfs_close(device);
_unregister_device(device);
return status;
}
@@ -4782,6 +4783,7 @@ void kgsl_device_platform_remove(struct kgsl_device *device)
kgsl_pwrctrl_close(device);
+ kgsl_device_debugfs_close(device);
_unregister_device(device);
}
EXPORT_SYMBOL(kgsl_device_platform_remove);
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 7758fc956055..37d92428f02c 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -87,6 +87,11 @@ void kgsl_device_debugfs_init(struct kgsl_device *device)
&pwr_log_fops);
}
+void kgsl_device_debugfs_close(struct kgsl_device *device)
+{
+ debugfs_remove_recursive(device->d_debugfs);
+}
+
struct type_entry {
int type;
const char *str;
diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index 34875954bb8b..949aed81581c 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011,2013,2015 The Linux Foundation.
+/* Copyright (c) 2002,2008-2011,2013,2015,2017 The Linux Foundation.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@ void kgsl_core_debugfs_init(void);
void kgsl_core_debugfs_close(void);
void kgsl_device_debugfs_init(struct kgsl_device *device);
+void kgsl_device_debugfs_close(struct kgsl_device *device);
extern struct dentry *kgsl_debugfs_dir;
static inline struct dentry *kgsl_get_debugfs_dir(void)
@@ -34,6 +35,7 @@ void kgsl_process_init_debugfs(struct kgsl_process_private *);
#else
static inline void kgsl_core_debugfs_init(void) { }
static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
+static inline void kgsl_device_debugfs_close(struct kgsl_device *device) { }
static inline void kgsl_core_debugfs_close(void) { }
static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
static inline void kgsl_process_init_debugfs(struct kgsl_process_private *priv)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index fe6aa45901d0..e639e197de93 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -361,6 +361,26 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
if (new_level == old_level)
return;
+ if (pwr->gpu_cx_ipeak) {
+ unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq;
+ unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq;
+
+ /*
+ * Set Cx ipeak vote for GPU if it tries to cross
+ * threshold frequency.
+ */
+ if (old_freq < pwr->gpu_cx_ipeak_clk &&
+ new_freq >= pwr->gpu_cx_ipeak_clk) {
+ int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, true);
+
+ if (ret) {
+ KGSL_PWR_ERR(device,
+ "cx_ipeak_update failed %d\n", ret);
+ return;
+ }
+ }
+ }
+
kgsl_pwrscale_update_stats(device);
/*
@@ -422,6 +442,24 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
/* Timestamp the frequency change */
device->pwrscale.freq_change_time = ktime_to_ms(ktime_get());
+
+ if (pwr->gpu_cx_ipeak) {
+ unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq;
+ unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq;
+
+ /*
+ * Reset Cx ipeak vote for GPU if it goes below
+ * threshold frequency.
+ */
+ if (old_freq >= pwr->gpu_cx_ipeak_clk &&
+ new_freq < pwr->gpu_cx_ipeak_clk) {
+ int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, false);
+
+ if (ret)
+ KGSL_PWR_ERR(device,
+ "cx_ipeak_update failed %d\n", ret);
+ }
+ }
}
EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
@@ -2217,8 +2255,37 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
of_property_read_string(pdev->dev.of_node, "qcom,tsens-name",
&pwr->tsens_name);
+ /* Cx ipeak client support */
+ if (of_find_property(pdev->dev.of_node, "qcom,gpu-cx-ipeak", NULL)) {
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "qcom,gpu-cx-ipeak-clk", &pwr->gpu_cx_ipeak_clk)) {
+ pwr->gpu_cx_ipeak = cx_ipeak_register(pdev->dev.of_node,
+ "qcom,gpu-cx-ipeak");
+ } else {
+ KGSL_PWR_ERR(device, "failed to get gpu cxip clk\n");
+ result = -EINVAL;
+ goto error_cleanup_pwr_limit;
+ }
+
+ if (IS_ERR(pwr->gpu_cx_ipeak)) {
+ result = PTR_ERR(pwr->gpu_cx_ipeak);
+ KGSL_PWR_ERR(device,
+ "Failed to register Cx ipeak client %d\n",
+ result);
+ goto error_cleanup_pwr_limit;
+ }
+ }
return result;
+error_cleanup_pwr_limit:
+ pwr->power_flags = 0;
+
+ if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) {
+ list_del(&pwr->sysfs_pwr_limit->node);
+ kfree(pwr->sysfs_pwr_limit);
+ pwr->sysfs_pwr_limit = NULL;
+ }
+ kfree(pwr->bus_ib);
error_cleanup_pcl:
_close_pcl(pwr);
error_cleanup_ocmem_pcl:
@@ -2238,6 +2305,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)
KGSL_PWR_INFO(device, "close device %d\n", device->id);
+ cx_ipeak_unregister(pwr->gpu_cx_ipeak);
+
pwr->power_flags = 0;
if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 2de42d87bcbe..42f918b80fcd 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
#define __KGSL_PWRCTRL_H
#include <linux/pm_qos.h>
+#include <soc/qcom/cx_ipeak.h>
/*****************************************************************************
** power flags
@@ -153,6 +154,8 @@ struct kgsl_regulator {
* 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
+ * gpu_cx_ipeak - pointer to cx ipeak client used by GPU
+ * gpu_cx_ipeak_clk - GPU threshold frequency to call cx ipeak driver API
*/
struct kgsl_pwrctrl {
@@ -206,6 +209,8 @@ struct kgsl_pwrctrl {
unsigned int gpu_bimc_int_clk_freq;
bool gpu_bimc_interface_enabled;
const char *tsens_name;
+ struct cx_ipeak_client *gpu_cx_ipeak;
+ unsigned int gpu_cx_ipeak_clk;
};
int kgsl_pwrctrl_init(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 1caa673db6ff..7de43dd27ffe 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -156,8 +156,10 @@ static size_t snapshot_os(struct kgsl_device *device,
header->osid = KGSL_SNAPSHOT_OS_LINUX_V3;
/* Get the kernel build information */
- strlcpy(header->release, utsname()->release, sizeof(header->release));
- strlcpy(header->version, utsname()->version, sizeof(header->version));
+ strlcpy(header->release, init_utsname()->release,
+ sizeof(header->release));
+ strlcpy(header->version, init_utsname()->version,
+ sizeof(header->version));
/* Get the Unix time for the timestamp */
header->seconds = get_seconds();
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 3a11b061e5b0..596a36ed7dba 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -3725,12 +3725,6 @@ static int tpdm_probe(struct platform_device *pdev)
clk_disable_unprepare(drvdata->clk);
- ret = tpdm_datasets_alloc(drvdata);
- if (ret)
- return ret;
-
- tpdm_init_default_data(drvdata);
-
drvdata->traceid = traceid++;
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c
index 04b1b62f85c3..bf2a1dd7cf15 100644
--- a/drivers/i2c/busses/i2c-msm-v2.c
+++ b/drivers/i2c/busses/i2c-msm-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -50,6 +50,8 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl,
static int i2c_msm_pm_resume(struct device *dev);
static void i2c_msm_pm_suspend(struct device *dev);
static void i2c_msm_clk_path_init(struct i2c_msm_ctrl *ctrl);
+static void i2c_msm_pm_pinctrl_state(struct i2c_msm_ctrl *ctrl,
+ bool runtime_active);
/* string table for enum i2c_msm_xfer_mode_id */
const char * const i2c_msm_mode_str_tbl[] = {
@@ -2157,27 +2159,54 @@ static bool i2c_msm_xfer_next_buf(struct i2c_msm_ctrl *ctrl)
return true;
}
-static void i2c_msm_pm_clk_disable_unprepare(struct i2c_msm_ctrl *ctrl)
+static void i2c_msm_pm_clk_unprepare(struct i2c_msm_ctrl *ctrl)
{
- clk_disable_unprepare(ctrl->rsrcs.core_clk);
- clk_disable_unprepare(ctrl->rsrcs.iface_clk);
+ clk_unprepare(ctrl->rsrcs.core_clk);
+ clk_unprepare(ctrl->rsrcs.iface_clk);
}
-static int i2c_msm_pm_clk_prepare_enable(struct i2c_msm_ctrl *ctrl)
+static int i2c_msm_pm_clk_prepare(struct i2c_msm_ctrl *ctrl)
{
int ret;
- ret = clk_prepare_enable(ctrl->rsrcs.iface_clk);
+ ret = clk_prepare(ctrl->rsrcs.iface_clk);
if (ret) {
dev_err(ctrl->dev,
- "error on clk_prepare_enable(iface_clk):%d\n", ret);
+ "error on clk_prepare(iface_clk):%d\n", ret);
return ret;
}
- ret = clk_prepare_enable(ctrl->rsrcs.core_clk);
+ ret = clk_prepare(ctrl->rsrcs.core_clk);
+ if (ret) {
+ clk_unprepare(ctrl->rsrcs.iface_clk);
+ dev_err(ctrl->dev,
+ "error clk_prepare(core_clk):%d\n", ret);
+ }
+ return ret;
+}
+
+static void i2c_msm_pm_clk_disable(struct i2c_msm_ctrl *ctrl)
+{
+ clk_disable(ctrl->rsrcs.core_clk);
+ clk_disable(ctrl->rsrcs.iface_clk);
+}
+
+static int i2c_msm_pm_clk_enable(struct i2c_msm_ctrl *ctrl)
+{
+ int ret;
+
+ ret = clk_enable(ctrl->rsrcs.iface_clk);
+ if (ret) {
+ dev_err(ctrl->dev,
+ "error on clk_enable(iface_clk):%d\n", ret);
+ i2c_msm_pm_clk_unprepare(ctrl);
+ return ret;
+ }
+ ret = clk_enable(ctrl->rsrcs.core_clk);
if (ret) {
- clk_disable_unprepare(ctrl->rsrcs.iface_clk);
+ clk_disable(ctrl->rsrcs.iface_clk);
+ i2c_msm_pm_clk_unprepare(ctrl);
dev_err(ctrl->dev,
- "error clk_prepare_enable(core_clk):%d\n", ret);
+ "error clk_enable(core_clk):%d\n", ret);
}
return ret;
}
@@ -2198,6 +2227,7 @@ static int i2c_msm_pm_xfer_start(struct i2c_msm_ctrl *ctrl)
return -EIO;
}
+ i2c_msm_pm_pinctrl_state(ctrl, true);
pm_runtime_get_sync(ctrl->dev);
/*
* if runtime PM callback was not invoked (when both runtime-pm
@@ -2208,7 +2238,7 @@ static int i2c_msm_pm_xfer_start(struct i2c_msm_ctrl *ctrl)
i2c_msm_pm_resume(ctrl->dev);
}
- ret = i2c_msm_pm_clk_prepare_enable(ctrl);
+ ret = i2c_msm_pm_clk_enable(ctrl);
if (ret) {
mutex_unlock(&ctrl->xfer.mtx);
return ret;
@@ -2235,13 +2265,14 @@ static void i2c_msm_pm_xfer_end(struct i2c_msm_ctrl *ctrl)
if (ctrl->xfer.mode_id == I2C_MSM_XFER_MODE_DMA)
i2c_msm_dma_free_channels(ctrl);
- i2c_msm_pm_clk_disable_unprepare(ctrl);
+ i2c_msm_pm_clk_disable(ctrl);
if (!pm_runtime_enabled(ctrl->dev))
i2c_msm_pm_suspend(ctrl->dev);
pm_runtime_mark_last_busy(ctrl->dev);
pm_runtime_put_autosuspend(ctrl->dev);
+ i2c_msm_pm_pinctrl_state(ctrl, false);
mutex_unlock(&ctrl->xfer.mtx);
}
@@ -2663,7 +2694,7 @@ static void i2c_msm_pm_suspend(struct device *dev)
return;
}
i2c_msm_dbg(ctrl, MSM_DBG, "suspending...");
- i2c_msm_pm_pinctrl_state(ctrl, false);
+ i2c_msm_pm_clk_unprepare(ctrl);
i2c_msm_clk_path_unvote(ctrl);
/*
@@ -2690,7 +2721,7 @@ static int i2c_msm_pm_resume(struct device *dev)
i2c_msm_dbg(ctrl, MSM_DBG, "resuming...");
i2c_msm_clk_path_vote(ctrl);
- i2c_msm_pm_pinctrl_state(ctrl, true);
+ i2c_msm_pm_clk_prepare(ctrl);
ctrl->pwr_state = I2C_MSM_PM_RT_ACTIVE;
return 0;
}
@@ -2870,9 +2901,13 @@ static int i2c_msm_probe(struct platform_device *pdev)
/* vote for clock to enable reading the version number off the HW */
i2c_msm_clk_path_vote(ctrl);
- ret = i2c_msm_pm_clk_prepare_enable(ctrl);
+ ret = i2c_msm_pm_clk_prepare(ctrl);
+ if (ret)
+ goto clk_err;
+
+ ret = i2c_msm_pm_clk_enable(ctrl);
if (ret) {
- dev_err(ctrl->dev, "error in enabling clocks:%d\n", ret);
+ i2c_msm_pm_clk_unprepare(ctrl);
goto clk_err;
}
@@ -2884,7 +2919,8 @@ static int i2c_msm_probe(struct platform_device *pdev)
if (ret)
dev_err(ctrl->dev, "error error on qup software reset\n");
- i2c_msm_pm_clk_disable_unprepare(ctrl);
+ i2c_msm_pm_clk_disable(ctrl);
+ i2c_msm_pm_clk_unprepare(ctrl);
i2c_msm_clk_path_unvote(ctrl);
ret = i2c_msm_rsrcs_gpio_pinctrl_init(ctrl);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index f7eb0f8ac5a8..8d66232dbda1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -196,6 +196,13 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr,
__func__, stream_id);
return -EINVAL;
}
+
+ if (qbuf_buf->num_planes > MAX_PLANES_PER_STREAM) {
+ pr_err("%s: Invalid num_planes %d , stream id %x\n",
+ __func__, qbuf_buf->num_planes, stream_id);
+ return -EINVAL;
+ }
+
for (i = 0; i < qbuf_buf->num_planes; i++) {
mapped_info = &buf_info->mapped_info[i];
mapped_info->buf_fd = qbuf_buf->planes[i].addr;
@@ -249,6 +256,12 @@ static void msm_isp_unprepare_v4l2_buf(
return;
}
+ if (buf_info->num_planes > VIDEO_MAX_PLANES) {
+ pr_err("%s: Invalid num_planes %d , stream id %x\n",
+ __func__, buf_info->num_planes, stream_id);
+ return;
+ }
+
bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle);
if (!bufq) {
pr_err("%s: Invalid bufq, stream id %x\n",
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 840d84388a17..bb3f0dca9d92 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -588,6 +588,12 @@ int vfe_hw_probe(struct platform_device *pdev)
}
vfe_dev->hw_info =
(struct msm_vfe_hardware_info *) match_dev->data;
+ /* Cx ipeak support */
+ if (of_find_property(pdev->dev.of_node,
+ "qcom,vfe_cx_ipeak", NULL)) {
+ vfe_dev->vfe_cx_ipeak = cx_ipeak_register(
+ pdev->dev.of_node, "qcom,vfe_cx_ipeak");
+ }
} else {
vfe_dev->hw_info = (struct msm_vfe_hardware_info *)
platform_get_device_id(pdev)->driver_data;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index f6fabc61620d..aca8e99650ba 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -29,6 +29,7 @@
#include "msm_buf_mgr.h"
#include "cam_hw_ops.h"
+#include <soc/qcom/cx_ipeak.h>
#define VFE40_8974V1_VERSION 0x10000018
#define VFE40_8974V2_VERSION 0x1001001A
@@ -767,6 +768,8 @@ struct vfe_device {
size_t num_hvx_clk;
size_t num_norm_clk;
enum cam_ahb_clk_vote ahb_vote;
+ bool turbo_vote;
+ struct cx_ipeak_client *vfe_cx_ipeak;
/* Sync variables*/
struct completion reset_complete;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index c7f3b97c83c9..57373c1fc74c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -331,6 +331,7 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev)
goto ahb_vote_fail;
}
vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE;
+ vfe_dev->turbo_vote = 0;
vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] =
vfe_dev->vfe_base;
@@ -763,7 +764,7 @@ long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev,
}
if (blocking_call) {
- rc = wait_for_completion_timeout(
+ rc = wait_for_completion_interruptible_timeout(
&vfe_dev->reset_complete, msecs_to_jiffies(100));
if (rc <= 0) {
pr_err("%s:%d failed: reset timeout\n", __func__,
@@ -1930,7 +1931,7 @@ int msm_vfe47_axi_halt(struct vfe_device *vfe_dev,
init_completion(&vfe_dev->halt_complete);
/* Halt AXI Bus Bridge */
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x400);
- rc = wait_for_completion_timeout(
+ rc = wait_for_completion_interruptible_timeout(
&vfe_dev->halt_complete, msecs_to_jiffies(500));
if (rc <= 0)
pr_err("%s:VFE%d halt timeout rc=%d\n", __func__,
@@ -2556,6 +2557,7 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
{
int rc = 0;
int clk_idx = vfe_dev->hw_info->vfe_clk_idx;
+ int ret;
rc = msm_camera_clk_set_rate(&vfe_dev->pdev->dev,
vfe_dev->vfe_clk[clk_idx], *rate);
@@ -2563,7 +2565,26 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
return rc;
*rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate);
vfe_dev->msm_isp_vfe_clk_rate = *rate;
-
+ if (vfe_dev->vfe_cx_ipeak) {
+ if (vfe_dev->msm_isp_vfe_clk_rate >=
+ vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO]
+ [vfe_dev->hw_info->vfe_clk_idx] &&
+ vfe_dev->turbo_vote == 0) {
+ ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, true);
+ if (ret)
+ pr_debug("%s: cx_ipeak_update failed %d\n",
+ __func__, ret);
+ else
+ vfe_dev->turbo_vote = 1;
+ } else if (vfe_dev->turbo_vote == 1) {
+ ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, false);
+ if (ret)
+ pr_debug("%s: cx_ipeak_update failed %d\n",
+ __func__, ret);
+ else
+ vfe_dev->turbo_vote = 0;
+ }
+ }
if (vfe_dev->hw_info->vfe_ops.core_ops.ahb_clk_cfg)
vfe_dev->hw_info->vfe_ops.core_ops.ahb_clk_cfg(vfe_dev, NULL);
return 0;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 5264bba57c8d..5aa8a59128a8 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -443,7 +443,7 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
msm_camera_io_w(ISPIF_RST_CMD_MASK,
ispif->base + ISPIF_RST_CMD_ADDR);
- timeout = wait_for_completion_timeout(
+ timeout = wait_for_completion_interruptible_timeout(
&ispif->reset_complete[VFE0], msecs_to_jiffies(500));
CDBG("%s: VFE0 done\n", __func__);
@@ -457,7 +457,7 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
atomic_set(&ispif->reset_trig[VFE1], 1);
msm_camera_io_w(ISPIF_RST_CMD_1_MASK,
ispif->base + ISPIF_RST_CMD_1_ADDR);
- timeout = wait_for_completion_timeout(
+ timeout = wait_for_completion_interruptible_timeout(
&ispif->reset_complete[VFE1],
msecs_to_jiffies(500));
CDBG("%s: VFE1 done\n", __func__);
@@ -1120,7 +1120,7 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
/* initiate reset of ISPIF */
msm_camera_io_w(ISPIF_RST_CMD_MASK_RESTART,
ispif->base + ISPIF_RST_CMD_ADDR);
- timeout = wait_for_completion_timeout(
+ timeout = wait_for_completion_interruptible_timeout(
&ispif->reset_complete[VFE0], msecs_to_jiffies(500));
if (timeout <= 0) {
pr_err("%s: VFE0 reset wait timeout\n", __func__);
@@ -1133,7 +1133,7 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
atomic_set(&ispif->reset_trig[VFE1], 1);
msm_camera_io_w(ISPIF_RST_CMD_1_MASK_RESTART,
ispif->base + ISPIF_RST_CMD_1_ADDR);
- timeout = wait_for_completion_timeout(
+ timeout = wait_for_completion_interruptible_timeout(
&ispif->reset_complete[VFE1],
msecs_to_jiffies(500));
if (timeout <= 0) {
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
index 3b38882c4c45..88d90d0a7c08 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -72,6 +72,18 @@ static const struct msm_jpegdma_block msm_jpegdma_block_sel[] = {
};
/*
+* jpegdma_do_div - long division.
+* @num: dividend
+* @den: divisor
+* returns quotient value.
+*/
+static inline long long jpegdma_do_div(long long num, long long den)
+{
+ do_div(num, den);
+ return num;
+}
+
+/*
* msm_jpegdma_hw_read_reg - dma read from register.
* @dma: Pointer to dma device.
* @base_idx: dma memory resource index.
@@ -819,9 +831,9 @@ static int msm_jpegdma_hw_calc_speed(struct msm_jpegdma_device *dma,
}
speed->bus_ab = calc_rate * 2;
- speed->bus_ib = (real_clock *
- (MSM_JPEGDMA_BW_NUM + MSM_JPEGDMA_BW_DEN - 1)) /
- MSM_JPEGDMA_BW_DEN;
+ speed->bus_ib = jpegdma_do_div((real_clock *
+ (MSM_JPEGDMA_BW_NUM + MSM_JPEGDMA_BW_DEN - 1)),
+ MSM_JPEGDMA_BW_DEN);
speed->core_clock = real_clock;
dev_dbg(dma->dev, "Speed core clk %llu ab %llu ib %llu fps %d\n",
speed->core_clock, speed->bus_ab, speed->bus_ib, size->fps);
@@ -923,13 +935,15 @@ static int msm_jpegdma_hw_calc_config(struct msm_jpegdma_size_config *size_cfg,
in_width = size_cfg->in_size.width;
out_width = size_cfg->out_size.width;
- scale_hor = (in_width * MSM_JPEGDMA_SCALE_UNI) / out_width;
+ scale_hor = jpegdma_do_div((in_width * MSM_JPEGDMA_SCALE_UNI),
+ out_width);
if (scale_hor != MSM_JPEGDMA_SCALE_UNI)
config->scale_cfg.enable = 1;
in_height = size_cfg->in_size.height;
out_height = size_cfg->out_size.height;
- scale_ver = (in_height * MSM_JPEGDMA_SCALE_UNI) / out_height;
+ scale_ver = jpegdma_do_div((in_height * MSM_JPEGDMA_SCALE_UNI),
+ out_height);
if (scale_ver != MSM_JPEGDMA_SCALE_UNI)
config->scale_cfg.enable = 1;
@@ -946,23 +960,23 @@ static int msm_jpegdma_hw_calc_config(struct msm_jpegdma_size_config *size_cfg,
config->block_cfg.block = msm_jpegdma_block_sel[i];
if (plane->active_pipes > 1) {
- phase = (out_height * scale_ver + (plane->active_pipes - 1)) /
- plane->active_pipes;
+ phase = jpegdma_do_div((out_height * scale_ver +
+ (plane->active_pipes - 1)), plane->active_pipes);
phase &= (MSM_JPEGDMA_SCALE_UNI - 1);
- out_height = (out_height + (plane->active_pipes - 1)) /
- plane->active_pipes;
+ out_height = jpegdma_do_div((out_height +
+ (plane->active_pipes - 1)), plane->active_pipes);
in_height = (out_height * scale_ver) / MSM_JPEGDMA_SCALE_UNI;
}
- config->block_cfg.blocks_per_row = out_width /
- config->block_cfg.block.width;
+ config->block_cfg.blocks_per_row = (uint32_t) jpegdma_do_div(out_width,
+ config->block_cfg.block.width);
config->block_cfg.blocks_per_col = out_height;
config->block_cfg.h_step = config->block_cfg.block.width;
-
- config->block_cfg.h_step_last = out_width %
- config->block_cfg.block.width;
+ config->size_cfg.out_size.width = out_width;
+ config->block_cfg.h_step_last = (uint32_t) do_div(out_width,
+ config->block_cfg.block.width);
if (!config->block_cfg.h_step_last)
config->block_cfg.h_step_last = config->block_cfg.h_step;
else
@@ -974,7 +988,6 @@ static int msm_jpegdma_hw_calc_config(struct msm_jpegdma_size_config *size_cfg,
config->size_cfg = *size_cfg;
config->size_cfg.in_size.width = in_width;
config->size_cfg.in_size.height = in_height;
- config->size_cfg.out_size.width = out_width;
config->size_cfg.out_size.height = out_height;
config->in_offset = 0;
config->out_offset = 0;
@@ -1013,14 +1026,16 @@ int msm_jpegdma_hw_check_config(struct msm_jpegdma_device *dma,
in_width = size_cfg->in_size.width;
out_width = size_cfg->out_size.width;
- scale = ((in_width * MSM_JPEGDMA_SCALE_UNI)) / out_width;
+ scale = jpegdma_do_div(((in_width * MSM_JPEGDMA_SCALE_UNI)),
+ out_width);
if (scale < MSM_JPEGDMA_SCALE_UNI)
return -EINVAL;
in_height = size_cfg->in_size.height;
out_height = size_cfg->out_size.height;
- scale = (in_height * MSM_JPEGDMA_SCALE_UNI) / out_height;
+ scale = jpegdma_do_div((in_height * MSM_JPEGDMA_SCALE_UNI),
+ out_height);
if (scale < MSM_JPEGDMA_SCALE_UNI)
return -EINVAL;
@@ -1827,7 +1842,7 @@ int msm_jpegdma_hw_map_buffer(struct msm_jpegdma_device *dma, int fd,
buf->fd = fd;
ret = cam_smmu_get_phy_addr(dma->iommu_hndl, buf->fd,
- CAM_SMMU_MAP_RW, &buf->addr, &buf->size);
+ CAM_SMMU_MAP_RW, &buf->addr, (size_t *)&buf->size);
if (ret < 0) {
dev_err(dma->dev, "Can not get physical address\n");
goto error_get_phy;
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 730f8b32ff1a..76a7c6942c68 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -149,10 +149,7 @@ static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev,
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
if ((bufs->session_id == buf_info->session_id) &&
(bufs->stream_id == buf_info->stream_id) &&
- (bufs->vb2_v4l2_buf->vb2_buf.index ==
- buf_info->index)) {
- bufs->vb2_v4l2_buf->sequence = buf_info->frame_id;
- bufs->vb2_v4l2_buf->timestamp = buf_info->timestamp;
+ (bufs->index == buf_info->index)) {
ret = buf_mngr_dev->vb2_ops.buf_done
(bufs->vb2_v4l2_buf,
buf_info->session_id,
@@ -181,7 +178,7 @@ static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev,
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
if ((bufs->session_id == buf_info->session_id) &&
(bufs->stream_id == buf_info->stream_id) &&
- (bufs->vb2_v4l2_buf->vb2_buf.index == buf_info->index)) {
+ (bufs->index == buf_info->index)) {
ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_v4l2_buf,
buf_info->session_id, buf_info->stream_id);
list_del_init(&bufs->entry);
@@ -214,7 +211,7 @@ static int32_t msm_generic_buf_mngr_flush(
buf_info->session_id,
buf_info->stream_id, 0, &ts, 0);
pr_err("Bufs not flushed: str_id = %d buf_index = %d ret = %d\n",
- buf_info->stream_id, bufs->vb2_v4l2_buf->vb2_buf.index,
+ buf_info->stream_id, bufs->index,
ret);
list_del_init(&bufs->entry);
kfree(bufs);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
index 07d522cb01bb..9120a4cc85ca 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -99,6 +99,7 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_1_3ph = {
{0x70C, 0xA5},
{0x38, 0xFE},
{0x81c, 0x2},
+ {0x700, 0x80},
};
struct csiphy_settings_t csiphy_combo_mode_v5_0_1 = {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
index 198d130b24fc..8591f0646080 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -100,6 +100,7 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_3ph = {
{0x70C, 0x16},
{0x38, 0xFE},
{0x81c, 0x6},
+ {0x700, 0x80},
};
struct csiphy_settings_t csiphy_combo_mode_v5_0 = {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index a7cd44636d1d..be266641a105 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -46,6 +46,7 @@
#define MSM_CSIPHY_DRV_NAME "msm_csiphy"
#define CLK_LANE_OFFSET 1
#define NUM_LANES_OFFSET 4
+#define CLOCK_LANE 0x02
#define CSI_3PHASE_HW 1
#define MAX_DPHY_DATA_LN 4
@@ -683,12 +684,21 @@ static int msm_csiphy_2phase_lane_config_v50(
csiphybase + csiphy_dev->ctrl_reg->
csiphy_3ph_reg.
mipi_csiphy_2ph_lnn_ctrl15.addr + offset);
- msm_camera_io_w(csiphy_dev->ctrl_reg->
- csiphy_3ph_reg.
- mipi_csiphy_2ph_lnn_ctrl0.data,
- csiphybase + csiphy_dev->ctrl_reg->
- csiphy_3ph_reg.
- mipi_csiphy_2ph_lnn_ctrl0.addr + offset);
+ if (mask == CLOCK_LANE)
+ msm_camera_io_w(csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnck_ctrl0.data,
+ csiphybase + csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnck_ctrl0.addr);
+ else
+ msm_camera_io_w(csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnn_ctrl0.data,
+ csiphybase + csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnn_ctrl0.addr +
+ offset);
msm_camera_io_w(csiphy_dev->ctrl_reg->
csiphy_3ph_reg.
mipi_csiphy_2ph_lnn_cfg1.data,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
index 70462dcd3b12..c1a9748e8af5 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -141,6 +141,7 @@ struct csiphy_reg_3ph_parms_t {
struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl3;
struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl14;
struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl7_cphy;
+ struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl0;
};
struct csiphy_ctrl_t {
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index a2da663e2046..f41382b5b20c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -990,11 +990,14 @@ static int sde_rotator_debug_base_release(struct inode *inode,
{
struct sde_rotator_debug_base *dbg = file->private_data;
- if (dbg && dbg->buf) {
+ if (dbg) {
+ mutex_lock(&dbg->buflock);
kfree(dbg->buf);
dbg->buf_len = 0;
dbg->buf = NULL;
+ mutex_unlock(&dbg->buflock);
}
+
return 0;
}
@@ -1026,8 +1029,10 @@ static ssize_t sde_rotator_debug_base_offset_write(struct file *file,
if (cnt > (dbg->max_offset - off))
cnt = dbg->max_offset - off;
+ mutex_lock(&dbg->buflock);
dbg->off = off;
dbg->cnt = cnt;
+ mutex_unlock(&dbg->buflock);
SDEROT_DBG("offset=%x cnt=%x\n", off, cnt);
@@ -1047,7 +1052,10 @@ static ssize_t sde_rotator_debug_base_offset_read(struct file *file,
if (*ppos)
return 0; /* the end */
+ mutex_lock(&dbg->buflock);
len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
+ mutex_unlock(&dbg->buflock);
+
if (len < 0 || len >= sizeof(buf))
return 0;
@@ -1086,6 +1094,8 @@ static ssize_t sde_rotator_debug_base_reg_write(struct file *file,
if (off >= dbg->max_offset)
return -EFAULT;
+ mutex_lock(&dbg->buflock);
+
/* Enable Clock for register access */
sde_rotator_clk_ctrl(dbg->mgr, true);
@@ -1094,6 +1104,8 @@ static ssize_t sde_rotator_debug_base_reg_write(struct file *file,
/* Disable Clock after register access */
sde_rotator_clk_ctrl(dbg->mgr, false);
+ mutex_unlock(&dbg->buflock);
+
SDEROT_DBG("addr=%zx data=%x\n", off, data);
return count;
@@ -1104,12 +1116,14 @@ static ssize_t sde_rotator_debug_base_reg_read(struct file *file,
{
struct sde_rotator_debug_base *dbg = file->private_data;
size_t len;
+ int rc = 0;
if (!dbg) {
SDEROT_ERR("invalid handle\n");
return -ENODEV;
}
+ mutex_lock(&dbg->buflock);
if (!dbg->buf) {
char dump_buf[64];
char *ptr;
@@ -1121,7 +1135,8 @@ static ssize_t sde_rotator_debug_base_reg_read(struct file *file,
if (!dbg->buf) {
SDEROT_ERR("not enough memory to hold reg dump\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto debug_read_error;
}
ptr = dbg->base + dbg->off;
@@ -1151,18 +1166,26 @@ static ssize_t sde_rotator_debug_base_reg_read(struct file *file,
dbg->buf_len = tot;
}
- if (*ppos >= dbg->buf_len)
- return 0; /* done reading */
+ if (*ppos >= dbg->buf_len) {
+ rc = 0; /* done reading */
+ goto debug_read_error;
+ }
len = min(count, dbg->buf_len - (size_t) *ppos);
if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
SDEROT_ERR("failed to copy to user\n");
- return -EFAULT;
+ rc = -EFAULT;
+ goto debug_read_error;
}
*ppos += len; /* increase offset */
+ mutex_unlock(&dbg->buflock);
return len;
+
+debug_read_error:
+ mutex_unlock(&dbg->buflock);
+ return rc;
}
static const struct file_operations sde_rotator_off_fops = {
@@ -1196,6 +1219,9 @@ int sde_rotator_debug_register_base(struct sde_rotator_device *rot_dev,
if (!dbg)
return -ENOMEM;
+ mutex_init(&dbg->buflock);
+ mutex_lock(&dbg->buflock);
+
if (name)
strlcpy(dbg->name, name, sizeof(dbg->name));
dbg->base = io_data->base;
@@ -1217,6 +1243,7 @@ int sde_rotator_debug_register_base(struct sde_rotator_device *rot_dev,
dbg->base += rot_dev->mdata->regdump ?
rot_dev->mdata->regdump[0].offset : 0;
}
+ mutex_unlock(&dbg->buflock);
strlcpy(dbgname + prefix_len, "off", sizeof(dbgname) - prefix_len);
ent_off = debugfs_create_file(dbgname, 0644, debugfs_root, dbg,
@@ -1234,7 +1261,9 @@ int sde_rotator_debug_register_base(struct sde_rotator_device *rot_dev,
goto reg_fail;
}
+ mutex_lock(&dbg->buflock);
dbg->mgr = rot_dev->mgr;
+ mutex_unlock(&dbg->buflock);
return 0;
reg_fail:
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
index c2c6f9775602..c6d0151d37de 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -53,6 +53,7 @@ struct sde_rotator_debug_base {
char *buf;
size_t buf_len;
struct sde_rot_mgr *mgr;
+ struct mutex buflock;
};
#if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index bd21f8cca2aa..460ffc79f566 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.c
@@ -2103,7 +2103,8 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
(rc == 0) && (rsp_buf->status == 0)) {
pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n");
- if (!hdcp_lib_enable_encryption(handle)) {
+ if (!handle->authenticated &&
+ !hdcp_lib_enable_encryption(handle)) {
handle->authenticated = true;
cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 134995c9cd3c..8d03c36858b3 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -7043,7 +7043,11 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
pr_debug("SET_MEM_PARAM: qseecom addr = 0x%pK\n", data);
+ mutex_lock(&app_access_lock);
+ atomic_inc(&data->ioctl_count);
ret = qseecom_set_client_mem_param(data, argp);
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed Qqseecom_set_mem_param request: %d\n",
ret);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 024c66ac8e57..66bdc593f811 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -217,4 +217,11 @@ config USB_BAM
Enabling this option adds USB BAM Driver.
USB BAM driver was added to supports SPS Peripheral-to-Peripheral
transfers between the USB and other peripheral.
+
+config MSM_EXT_DISPLAY
+ bool "MSM External Display Driver"
+ help
+ Enabling this option adds MSM External Display Driver.
+ External Display driver was added to support the communication
+ between external display driver and its couterparts.
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index d5e87c209c21..d985aa81a3bb 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SEEMP_CORE) += seemp_core/
obj-$(CONFIG_SSM) += ssm.o
obj-$(CONFIG_USB_BAM) += usb_bam.o
obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/
+obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 23b0428bcf34..f48182cc04df 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -22,7 +22,7 @@
#include "gsi_reg.h"
#define GSI_CMD_TIMEOUT (5*HZ)
-#define GSI_STOP_CMD_TIMEOUT_MS 1
+#define GSI_STOP_CMD_TIMEOUT_MS 10
#define GSI_MAX_CH_LOW_WEIGHT 15
#define GSI_MHI_ER_START 10
#define GSI_MHI_ER_END 16
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index e3dfe8927682..81eae05d7ed9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -1777,7 +1777,8 @@ dealloc_chan_fail:
int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
bool should_force_clear, u32 qmi_req_id, bool is_dpl)
{
- struct ipa3_ep_context *ul_ep, *dl_ep;
+ struct ipa3_ep_context *ul_ep = NULL;
+ struct ipa3_ep_context *dl_ep;
int result = -EFAULT;
u32 source_pipe_bitmask = 0;
bool dl_data_pending = true;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
index 483b2ca118fa..06f65906841d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -853,6 +853,10 @@ void ipa3_dma_async_memcpy_notify_cb(void *priv
mem_info = (struct ipa_mem_buffer *)data;
ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS);
+ if (ep_idx < 0) {
+ IPADMA_ERR("IPA Client mapping failed\n");
+ return;
+ }
sys = ipa3_ctx->ep[ep_idx].sys;
spin_lock_irqsave(&ipa3_dma_ctx->async_lock, flags);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 5c678f1cfc28..8ec0974711a4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -337,7 +337,7 @@ int ipa3_send_one(struct ipa3_sys_context *sys, struct ipa3_desc *desc,
int result;
u16 sps_flags = SPS_IOVEC_FLAG_EOT;
dma_addr_t dma_address;
- u16 len;
+ u16 len = 0;
u32 mem_flag = GFP_ATOMIC;
if (unlikely(!in_atomic))
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index c3a12dd0b17c..362294b0f695 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -14,7 +14,6 @@
#include "ipahal/ipahal.h"
#include "ipahal/ipahal_fltrt.h"
-#define IPA_FLT_TABLE_INDEX_NOT_FOUND (-1)
#define IPA_FLT_STATUS_OF_ADD_FAILED (-1)
#define IPA_FLT_STATUS_OF_DEL_FAILED (-1)
#define IPA_FLT_STATUS_OF_MDFY_FAILED (-1)
@@ -1001,7 +1000,7 @@ error:
static int __ipa_add_flt_get_ep_idx(enum ipa_client_type ep, int *ipa_ep_idx)
{
*ipa_ep_idx = ipa3_get_ep_mapping(ep);
- if (*ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) {
+ if (*ipa_ep_idx < 0) {
IPAERR("ep not valid ep=%d\n", ep);
return -EINVAL;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index 4ef1a96c8450..9e2ffe70170c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -153,10 +153,16 @@ int ipa3_mhi_reset_channel_internal(enum ipa_client_type client)
int ipa3_mhi_start_channel_internal(enum ipa_client_type client)
{
int res;
+ int ipa_ep_idx;
IPA_MHI_FUNC_ENTRY();
- res = ipa3_enable_data_path(ipa3_get_ep_mapping(client));
+ ipa_ep_idx = ipa3_get_ep_mapping(client);
+ if (ipa_ep_idx < 0) {
+ IPA_MHI_ERR("Invalid client %d\n", client);
+ return -EINVAL;
+ }
+ res = ipa3_enable_data_path(ipa_ep_idx);
if (res) {
IPA_MHI_ERR("ipa3_enable_data_path failed %d\n", res);
return res;
@@ -521,6 +527,10 @@ int ipa3_mhi_resume_channels_internal(enum ipa_client_type client,
IPA_MHI_FUNC_ENTRY();
ipa_ep_idx = ipa3_get_ep_mapping(client);
+ if (ipa_ep_idx < 0) {
+ IPA_MHI_ERR("Invalid client %d\n", client);
+ return -EINVAL;
+ }
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (brstmode_enabled && !LPTransitionRejected) {
@@ -557,11 +567,14 @@ int ipa3_mhi_query_ch_info(enum ipa_client_type client,
IPA_MHI_FUNC_ENTRY();
ipa_ep_idx = ipa3_get_ep_mapping(client);
-
+ if (ipa_ep_idx < 0) {
+ IPA_MHI_ERR("Invalid client %d\n", client);
+ return -EINVAL;
+ }
ep = &ipa3_ctx->ep[ipa_ep_idx];
res = gsi_query_channel_info(ep->gsi_chan_hdl, ch_info);
if (res) {
- IPAERR("gsi_query_channel_info failed\n");
+ IPA_MHI_ERR("gsi_query_channel_info failed\n");
return res;
}
@@ -596,7 +609,10 @@ int ipa3_mhi_destroy_channel(enum ipa_client_type client)
struct ipa3_ep_context *ep;
ipa_ep_idx = ipa3_get_ep_mapping(client);
-
+ if (ipa_ep_idx < 0) {
+ IPA_MHI_ERR("Invalid client %d\n", client);
+ return -EINVAL;
+ }
ep = &ipa3_ctx->ep[ipa_ep_idx];
IPA_MHI_DBG("reset event ring (hdl: %lu, ep: %d)\n",
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
index 21ce28204069..c1d1d9659850 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -498,7 +498,7 @@ static int ipa3_uc_send_cmd_64b_param(u32 cmd_lo, u32 cmd_hi, u32 opcode,
{
int index;
union IpaHwCpuCmdCompletedResponseData_t uc_rsp;
- unsigned long flags;
+ unsigned long flags = 0;
int retries = 0;
send_cmd_lock:
@@ -775,7 +775,7 @@ int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
void ipa3_uc_register_handlers(enum ipa3_hw_features feature,
struct ipa3_uc_hdlrs *hdlrs)
{
- unsigned long flags;
+ unsigned long flags = 0;
if (0 > feature || IPA_HW_FEATURE_MAX <= feature) {
IPAERR("Feature %u is invalid, not registering hdlrs\n",
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 9f38af1b520b..2f28ba673d5a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -929,7 +929,7 @@ int ipa3_get_ep_mapping(enum ipa_client_type client)
if (client >= IPA_CLIENT_MAX || client < 0) {
IPAERR("Bad client number! client =%d\n", client);
- return -EINVAL;
+ return IPA_EP_NOT_ALLOCATED;
}
ipa_ep_idx = ipa3_ep_mapping[ipa3_get_hw_type_index()][client].pipe_num;
@@ -3446,6 +3446,11 @@ void ipa3_suspend_apps_pipes(bool suspend)
cfg.ipa_ep_suspend = suspend;
ipa_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
+ if (ipa_ep_idx < 0) {
+ IPAERR("IPA client mapping failed\n");
+ ipa_assert();
+ return;
+ }
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid) {
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
index d74b1432ea71..bb1259e3cfa1 100644
--- a/drivers/video/fbdev/msm/msm_ext_display.c
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -23,9 +23,6 @@
#include <linux/of_platform.h>
#include <linux/msm_ext_display.h>
-#include "mdss_hdmi_util.h"
-#include "mdss_fb.h"
-
struct msm_ext_disp_list {
struct msm_ext_disp_init_data *data;
struct list_head list;
@@ -48,7 +45,6 @@ struct msm_ext_disp {
static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp,
enum msm_ext_disp_type type,
struct msm_ext_disp_init_data **data);
-static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack);
static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp,
enum msm_ext_disp_type type,
enum msm_ext_disp_cable_state state, u32 flags);
@@ -103,128 +99,6 @@ end:
return;
}
-static void msm_ext_disp_get_pdev_by_name(struct device *dev,
- const char *phandle, struct platform_device **pdev)
-{
- struct device_node *pd_np;
-
- if (!dev) {
- pr_err("Invalid device\n");
- return;
- }
-
- if (!dev->of_node) {
- pr_err("Invalid of_node\n");
- return;
- }
-
- pd_np = of_parse_phandle(dev->of_node, phandle, 0);
- if (!pd_np) {
- pr_err("Cannot find %s dev\n", phandle);
- return;
- }
-
- *pdev = of_find_device_by_node(pd_np);
-}
-
-static void msm_ext_disp_get_fb_pdev(struct device *device,
- struct platform_device **fb_pdev)
-{
- struct msm_fb_data_type *mfd = NULL;
- struct fb_info *fbi = dev_get_drvdata(device);
-
- if (!fbi) {
- pr_err("fb_info is null\n");
- return;
- }
-
- mfd = (struct msm_fb_data_type *)fbi->par;
-
- *fb_pdev = mfd->pdev;
-}
-static ssize_t msm_ext_disp_sysfs_wta_audio_cb(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int ack, ret = 0;
- ssize_t size = strnlen(buf, PAGE_SIZE);
- const char *ext_phandle = "qcom,msm_ext_disp";
- struct platform_device *ext_pdev = NULL;
- const char *intf_phandle = "qcom,mdss-intf";
- struct platform_device *intf_pdev = NULL;
- struct platform_device *fb_pdev = NULL;
-
- ret = kstrtoint(buf, 10, &ack);
- if (ret) {
- pr_err("kstrtoint failed. ret=%d\n", ret);
- goto end;
- }
-
- msm_ext_disp_get_fb_pdev(dev, &fb_pdev);
- if (!fb_pdev) {
- pr_err("failed to get fb pdev\n");
- goto end;
- }
-
- msm_ext_disp_get_pdev_by_name(&fb_pdev->dev, intf_phandle, &intf_pdev);
- if (!intf_pdev) {
- pr_err("failed to get display intf pdev\n");
- goto end;
- }
-
- msm_ext_disp_get_pdev_by_name(&intf_pdev->dev, ext_phandle, &ext_pdev);
- if (!ext_pdev) {
- pr_err("failed to get ext_pdev\n");
- goto end;
- }
-
- ret = msm_ext_disp_audio_ack(ext_pdev, ack);
- if (ret)
- pr_err("Failed to process ack. ret=%d\n", ret);
-
-end:
- return size;
-}
-
-static DEVICE_ATTR(hdmi_audio_cb, S_IWUSR, NULL,
- msm_ext_disp_sysfs_wta_audio_cb);
-
-static struct attribute *msm_ext_disp_fs_attrs[] = {
- &dev_attr_hdmi_audio_cb.attr,
- NULL,
-};
-
-static struct attribute_group msm_ext_disp_fs_attrs_group = {
- .attrs = msm_ext_disp_fs_attrs,
-};
-
-static int msm_ext_disp_sysfs_create(struct msm_ext_disp_init_data *data)
-{
- int ret = 0;
-
- if (!data || !data->kobj) {
- pr_err("Invalid params\n");
- ret = -EINVAL;
- goto end;
- }
-
- ret = sysfs_create_group(data->kobj, &msm_ext_disp_fs_attrs_group);
- if (ret)
- pr_err("Failed, ret=%d\n", ret);
-
-end:
- return ret;
-}
-
-static void msm_ext_disp_sysfs_remove(struct msm_ext_disp_init_data *data)
-{
- if (!data || !data->kobj) {
- pr_err("Invalid params\n");
- return;
- }
-
- sysfs_remove_group(data->kobj, &msm_ext_disp_fs_attrs_group);
-}
-
static const char *msm_ext_disp_name(enum msm_ext_disp_type type)
{
switch (type) {
@@ -293,31 +167,6 @@ end:
return ret;
}
-static void msm_ext_disp_remove_intf_data(struct msm_ext_disp *ext_disp,
- enum msm_ext_disp_type type)
-{
- struct msm_ext_disp_list *node;
- struct list_head *position = NULL;
- struct list_head *temp = NULL;
-
- if (!ext_disp) {
- pr_err("Invalid params\n");
- return;
- }
-
- list_for_each_safe(position, temp, &ext_disp->display_list) {
- node = list_entry(position, struct msm_ext_disp_list, list);
- if (node->data->type == type) {
- msm_ext_disp_sysfs_remove(node->data);
- list_del(&node->list);
- pr_debug("Removed display (%s)\n",
- msm_ext_disp_name(type));
- kfree(node);
- break;
- }
- }
-}
-
static int msm_ext_disp_send_cable_notification(struct msm_ext_disp *ext_disp,
enum msm_ext_disp_cable_state new_state)
{
@@ -661,6 +510,46 @@ static void msm_ext_disp_teardown_done(struct platform_device *pdev)
complete_all(&ext_disp->hpd_comp);
}
+static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack)
+{
+ u32 ack_hpd;
+ int ret = 0;
+ struct msm_ext_disp *ext_disp = NULL;
+
+ if (!pdev) {
+ pr_err("Invalid platform device\n");
+ return -EINVAL;
+ }
+
+ ext_disp = platform_get_drvdata(pdev);
+ if (!ext_disp) {
+ pr_err("Invalid drvdata\n");
+ return -EINVAL;
+ }
+
+ if (ack & AUDIO_ACK_SET_ENABLE) {
+ ext_disp->ack_enabled = ack & AUDIO_ACK_ENABLE ?
+ true : false;
+
+ pr_debug("audio ack feature %s\n",
+ ext_disp->ack_enabled ? "enabled" : "disabled");
+ goto end;
+ }
+
+ if (!ext_disp->ack_enabled)
+ goto end;
+
+ ack_hpd = ack & AUDIO_ACK_CONNECT;
+
+ pr_debug("%s acknowledging audio (%d)\n",
+ msm_ext_disp_name(ext_disp->current_disp), ack_hpd);
+
+ if (!ext_disp->audio_session_on)
+ complete_all(&ext_disp->hpd_comp);
+end:
+ return ret;
+}
+
static int msm_ext_disp_get_intf_id(struct platform_device *pdev)
{
int ret = 0;
@@ -710,12 +599,14 @@ static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp,
ops->cable_status = msm_ext_disp_cable_status;
ops->get_intf_id = msm_ext_disp_get_intf_id;
ops->teardown_done = msm_ext_disp_teardown_done;
+ ops->acknowledge = msm_ext_disp_audio_ack;
} else {
ops->audio_info_setup = NULL;
ops->get_audio_edid_blk = NULL;
ops->cable_status = NULL;
ops->get_intf_id = NULL;
ops->teardown_done = NULL;
+ ops->acknowledge = NULL;
}
end:
return ret;
@@ -755,46 +646,6 @@ end:
return ret;
}
-static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack)
-{
- u32 ack_hpd;
- int ret = 0;
- struct msm_ext_disp *ext_disp = NULL;
-
- if (!pdev) {
- pr_err("Invalid platform device\n");
- return -EINVAL;
- }
-
- ext_disp = platform_get_drvdata(pdev);
- if (!ext_disp) {
- pr_err("Invalid drvdata\n");
- return -EINVAL;
- }
-
- if (ack & AUDIO_ACK_SET_ENABLE) {
- ext_disp->ack_enabled = ack & AUDIO_ACK_ENABLE ?
- true : false;
-
- pr_debug("audio ack feature %s\n",
- ext_disp->ack_enabled ? "enabled" : "disabled");
- goto end;
- }
-
- if (!ext_disp->ack_enabled)
- goto end;
-
- ack_hpd = ack & AUDIO_ACK_CONNECT;
-
- pr_debug("%s acknowledging audio (%d)\n",
- msm_ext_disp_name(ext_disp->current_disp), ack_hpd);
-
- if (!ext_disp->audio_session_on)
- complete_all(&ext_disp->hpd_comp);
-end:
- return ret;
-}
-
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
struct msm_ext_disp_audio_codec_ops *ops)
{
@@ -849,11 +700,6 @@ static int msm_ext_disp_validate_intf(struct msm_ext_disp_init_data *init_data)
return -EINVAL;
}
- if (!init_data->kobj) {
- pr_err("Invalid display intf kobj\n");
- return -EINVAL;
- }
-
if (!init_data->codec_ops.get_audio_edid_blk ||
!init_data->codec_ops.cable_status ||
!init_data->codec_ops.audio_info_setup) {
@@ -899,10 +745,6 @@ int msm_ext_disp_register_intf(struct platform_device *pdev,
if (ret)
goto end;
- ret = msm_ext_disp_sysfs_create(init_data);
- if (ret)
- goto sysfs_failure;
-
init_data->intf_ops.hpd = msm_ext_disp_hpd;
init_data->intf_ops.notify = msm_ext_disp_notify;
@@ -913,8 +755,6 @@ int msm_ext_disp_register_intf(struct platform_device *pdev,
return ret;
-sysfs_failure:
- msm_ext_disp_remove_intf_data(ext_disp, init_data->type);
end:
mutex_unlock(&ext_disp->lock);
@@ -1035,7 +875,7 @@ static void __exit msm_ext_disp_exit(void)
platform_driver_unregister(&this_driver);
}
-module_init(msm_ext_disp_init);
+subsys_initcall(msm_ext_disp_init);
module_exit(msm_ext_disp_exit);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index f9784630c327..5d4b46469e9c 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -381,13 +381,13 @@ static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
pval.intval = fsw_khz;
- rc = power_supply_set_property(chg->pl.psy,
+ /*
+ * Some parallel charging implementations may not have
+ * PROP_BUCK_FREQ property - they could be running
+ * with a fixed frequency
+ */
+ power_supply_set_property(chg->pl.psy,
POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
- if (rc < 0) {
- dev_err(chg->dev,
- "Could not set parallel buck_freq rc=%d\n", rc);
- return rc;
- }
}
return rc;
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 37dc15494761..1c7c1e78699f 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -44,6 +44,8 @@
#define SMB2CHG_DC_TM_SREFGEN (DCIN_BASE + 0xE2)
#define STACKED_DIODE_EN_BIT BIT(2)
+#define TDIE_AVG_COUNT 10
+
enum {
OOB_COMP_WA_BIT = BIT(0),
};
@@ -118,6 +120,27 @@ irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
return IRQ_HANDLED;
}
+static int smb138x_get_prop_charger_temp(struct smb138x *chip,
+ union power_supply_propval *val)
+{
+ union power_supply_propval pval;
+ int rc = 0, avg = 0, i;
+ struct smb_charger *chg = &chip->chg;
+
+ for (i = 0; i < TDIE_AVG_COUNT; i++) {
+ pval.intval = 0;
+ rc = smblib_get_prop_charger_temp(chg, &pval);
+ if (rc < 0) {
+ pr_err("Couldnt read chg temp at %dth iteration rc = %d\n",
+ i + 1, rc);
+ return rc;
+ }
+ avg += pval.intval;
+ }
+ val->intval = avg / TDIE_AVG_COUNT;
+ return rc;
+}
+
static int smb138x_parse_dt(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -343,7 +366,7 @@ static int smb138x_batt_get_prop(struct power_supply *psy,
rc = smblib_get_prop_batt_capacity(chg, val);
break;
case POWER_SUPPLY_PROP_CHARGER_TEMP:
- rc = smblib_get_prop_charger_temp(chg, val);
+ rc = smb138x_get_prop_charger_temp(chip, val);
break;
case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
rc = smblib_get_prop_charger_temp_max(chg, val);
@@ -547,7 +570,7 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
rc = smblib_get_prop_slave_current_now(chg, val);
break;
case POWER_SUPPLY_PROP_CHARGER_TEMP:
- rc = smblib_get_prop_charger_temp(chg, val);
+ rc = smb138x_get_prop_charger_temp(chip, val);
break;
case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
rc = smblib_get_prop_charger_temp_max(chg, val);
@@ -621,10 +644,6 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
break;
- case POWER_SUPPLY_PROP_BUCK_FREQ:
- rc = smblib_set_charge_param(chg, &chg->param.freq_buck,
- val->intval);
- break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as the device is active */
if (!val->intval)
@@ -632,7 +651,7 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
rc = smblib_set_prop_ship_mode(chg, val);
break;
default:
- pr_err("parallel power supply set prop %d not supported\n",
+ pr_debug("parallel power supply set prop %d not supported\n",
prop);
return -EINVAL;
}
@@ -911,6 +930,13 @@ static int smb138x_init_hw(struct smb138x *chip)
chg->dcp_icl_ua = chip->dt.usb_icl_ua;
+ /* configure to a fixed 700khz freq to avoid tdie errors */
+ rc = smblib_set_charge_param(chg, &chg->param.freq_buck, 700);
+ if (rc < 0) {
+ pr_err("Couldn't configure 700Khz switch freq rc=%d\n", rc);
+ return rc;
+ }
+
/* configure charge enable for software control; active high */
rc = smblib_masked_write(chg, CHGR_CFG2_REG,
CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0);
diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c
index 8d017fb55a3f..c012f373e80e 100644
--- a/drivers/regulator/qpnp-oledb-regulator.c
+++ b/drivers/regulator/qpnp-oledb-regulator.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/spmi.h>
@@ -24,6 +25,8 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/qpnp-labibb-regulator.h>
+#include <linux/qpnp/qpnp-pbs.h>
#define QPNP_OLEDB_REGULATOR_DRIVER_NAME "qcom,qpnp-oledb-regulator"
#define OLEDB_VOUT_STEP_MV 100
@@ -91,6 +94,12 @@
#define OLEDB_ENABLE_NLIMIT_BIT_SHIFT 7
#define OLEDB_NLIMIT_PGM_MASK GENMASK(1, 0)
+#define OLEDB_SPARE_CTL 0xE9
+#define OLEDB_FORCE_PD_CTL_SPARE_BIT BIT(7)
+
+#define OLEDB_PD_PBS_TRIGGER_BIT BIT(0)
+
+#define OLEDB_SEC_UNLOCK_CODE 0xA5
#define OLEDB_PSM_HYS_CTRL_MIN 13
#define OLEDB_PSM_HYS_CTRL_MAX 26
@@ -150,6 +159,9 @@ struct qpnp_oledb {
struct qpnp_oledb_psm_ctl psm_ctl;
struct qpnp_oledb_pfm_ctl pfm_ctl;
struct qpnp_oledb_fast_precharge_ctl fast_prechg_ctl;
+ struct notifier_block oledb_nb;
+ struct mutex bus_lock;
+ struct device_node *pbs_dev_node;
u32 base;
u8 mod_enable;
@@ -168,6 +180,7 @@ struct qpnp_oledb {
bool ext_pin_control;
bool dynamic_ext_pinctl_config;
bool pbs_control;
+ bool force_pd_control;
};
static const u16 oledb_warmup_dly_ns[] = {6700, 13300, 26700, 53400};
@@ -184,11 +197,13 @@ static int qpnp_oledb_read(struct qpnp_oledb *oledb, u32 address,
int rc = 0;
struct platform_device *pdev = oledb->pdev;
+ mutex_lock(&oledb->bus_lock);
rc = regmap_bulk_read(oledb->regmap, address, val, count);
if (rc)
pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n",
address, to_spmi_device(pdev->dev.parent)->usid, rc);
+ mutex_unlock(&oledb->bus_lock);
return rc;
}
@@ -197,6 +212,7 @@ static int qpnp_oledb_masked_write(struct qpnp_oledb *oledb,
{
int rc;
+ mutex_lock(&oledb->bus_lock);
rc = regmap_update_bits(oledb->regmap, address, mask, val);
if (rc < 0)
pr_err("Failed to write address 0x%04X, rc = %d\n",
@@ -205,6 +221,31 @@ static int qpnp_oledb_masked_write(struct qpnp_oledb *oledb,
pr_debug("Wrote 0x%02X to addr 0x%04X\n",
val, address);
+ mutex_unlock(&oledb->bus_lock);
+ return rc;
+}
+
+#define OLEDB_SEC_ACCESS 0xD0
+static int qpnp_oledb_sec_masked_write(struct qpnp_oledb *oledb, u16 address,
+ u8 mask, u8 val)
+{
+ int rc = 0;
+ u8 sec_val = OLEDB_SEC_UNLOCK_CODE;
+ u16 sec_reg_addr = (address & 0xFF00) | OLEDB_SEC_ACCESS;
+
+ mutex_lock(&oledb->bus_lock);
+ rc = regmap_write(oledb->regmap, sec_reg_addr, sec_val);
+ if (rc < 0) {
+ pr_err("register %x failed rc = %d\n", sec_reg_addr, rc);
+ goto error;
+ }
+
+ rc = regmap_update_bits(oledb->regmap, address, mask, val);
+ if (rc < 0)
+ pr_err("spmi write failed: addr=%03X, rc=%d\n", address, rc);
+
+error:
+ mutex_unlock(&oledb->bus_lock);
return rc;
}
@@ -214,6 +255,7 @@ static int qpnp_oledb_write(struct qpnp_oledb *oledb, u16 address, u8 *val,
int rc = 0;
struct platform_device *pdev = oledb->pdev;
+ mutex_lock(&oledb->bus_lock);
rc = regmap_bulk_write(oledb->regmap, address, val, count);
if (rc)
pr_err("Failed to write address=0x%02x sid=0x%02x rc=%d\n",
@@ -222,7 +264,8 @@ static int qpnp_oledb_write(struct qpnp_oledb *oledb, u16 address, u8 *val,
pr_debug("Wrote 0x%02X to addr 0x%04X\n",
*val, address);
- return 0;
+ mutex_unlock(&oledb->bus_lock);
+ return rc;
}
static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev)
@@ -285,6 +328,8 @@ static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev)
static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev)
{
int rc = 0;
+ u8 trigger_bitmap = OLEDB_PD_PBS_TRIGGER_BIT;
+ u8 val;
struct qpnp_oledb *oledb = rdev_get_drvdata(rdev);
@@ -314,6 +359,27 @@ static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev)
pr_debug("Register-control mode, module disabled\n");
}
+ if (oledb->force_pd_control) {
+ rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_SPARE_CTL,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to read OLEDB_SPARE_CTL rc=%d\n", rc);
+ return rc;
+ }
+
+ if (val & OLEDB_FORCE_PD_CTL_SPARE_BIT) {
+ rc = qpnp_pbs_trigger_event(oledb->pbs_dev_node,
+ trigger_bitmap);
+ if (rc < 0) {
+ pr_err("Failed to trigger the PBS sequence\n");
+ return rc;
+ }
+ pr_debug("PBS event triggered\n");
+ } else {
+ pr_debug("OLEDB_SPARE_CTL register bit not set\n");
+ }
+ }
+
oledb->mod_enable = false;
return rc;
@@ -1034,6 +1100,18 @@ static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb)
oledb->pbs_control =
of_property_read_bool(of_node, "qcom,pbs-control");
+ oledb->force_pd_control =
+ of_property_read_bool(of_node, "qcom,force-pd-control");
+
+ if (oledb->force_pd_control) {
+ oledb->pbs_dev_node = of_parse_phandle(of_node,
+ "qcom,pbs-client", 0);
+ if (!oledb->pbs_dev_node) {
+ pr_err("Missing qcom,pbs-client property\n");
+ return -EINVAL;
+ }
+ }
+
oledb->current_voltage = -EINVAL;
rc = of_property_read_u32(of_node, "qcom,oledb-init-voltage-mv",
&oledb->current_voltage);
@@ -1116,6 +1194,52 @@ static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb)
return rc;
}
+static int qpnp_oledb_force_pulldown_config(struct qpnp_oledb *oledb)
+{
+ int rc = 0;
+ u8 val;
+
+ rc = qpnp_oledb_sec_masked_write(oledb, oledb->base +
+ OLEDB_SPARE_CTL, OLEDB_FORCE_PD_CTL_SPARE_BIT, 0);
+ if (rc < 0) {
+ pr_err("Failed to write SPARE_CTL rc=%d\n", rc);
+ return rc;
+ }
+
+ val = 1;
+ rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_PD_CTL,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to write PD_CTL rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_oledb_masked_write(oledb, oledb->base +
+ OLEDB_SWIRE_CONTROL, OLEDB_EN_SWIRE_PD_UPD_BIT, 0);
+ if (rc < 0)
+ pr_err("Failed to write SWIRE_CTL for pbs mode rc=%d\n",
+ rc);
+
+ return rc;
+}
+
+static int qpnp_labibb_notifier_cb(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ int rc = 0;
+ struct qpnp_oledb *oledb = container_of(nb, struct qpnp_oledb,
+ oledb_nb);
+
+ if (action == LAB_VREG_OK) {
+ /* Disable SWIRE pull down control and enable via spmi mode */
+ rc = qpnp_oledb_force_pulldown_config(oledb);
+ if (rc < 0)
+ return NOTIFY_STOP;
+ }
+
+ return NOTIFY_OK;
+}
+
static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
{
int rc = 0;
@@ -1143,6 +1267,7 @@ static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
return rc;
}
+ mutex_init(&(oledb->bus_lock));
oledb->base = val;
rc = qpnp_oledb_parse_dt(oledb);
if (rc < 0) {
@@ -1156,18 +1281,47 @@ static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
return rc;
}
+ if (oledb->force_pd_control) {
+ oledb->oledb_nb.notifier_call = qpnp_labibb_notifier_cb;
+ rc = qpnp_labibb_notifier_register(&oledb->oledb_nb);
+ if (rc < 0) {
+ pr_err("Failed to register qpnp_labibb_notifier_cb\n");
+ return rc;
+ }
+ }
+
rc = qpnp_oledb_register_regulator(oledb);
- if (!rc)
- pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d cuurent_voltage=%d mV\n",
+ if (rc < 0) {
+ pr_err("Failed to register regulator rc=%d\n", rc);
+ goto out;
+ }
+ pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d current_voltage=%d mV\n",
oledb->ext_pin_control, oledb->mod_enable,
oledb->current_voltage);
+ return 0;
+
+out:
+ if (oledb->force_pd_control) {
+ rc = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
+ if (rc < 0)
+ pr_err("Failed to unregister lab_vreg_ok notifier\n");
+ }
return rc;
}
static int qpnp_oledb_regulator_remove(struct platform_device *pdev)
{
- return 0;
+ int rc = 0;
+ struct qpnp_oledb *oledb = platform_get_drvdata(pdev);
+
+ if (oledb->force_pd_control) {
+ rc = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
+ if (rc < 0)
+ pr_err("Failed to unregister lab_vreg_ok notifier\n");
+ }
+
+ return rc;
}
const struct of_device_id qpnp_oledb_regulator_match_table[] = {
diff --git a/drivers/sensors/sensors_ssc.c b/drivers/sensors/sensors_ssc.c
index 0910ef34e777..0e299efece94 100644
--- a/drivers/sensors/sensors_ssc.c
+++ b/drivers/sensors/sensors_ssc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,8 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+
#include <soc/qcom/subsystem_restart.h>
#define IMAGE_LOAD_CMD 1
@@ -64,10 +66,11 @@ static struct attribute *attrs[] = {
};
static struct platform_device *slpi_private;
+static struct work_struct slpi_ldr_work;
-static void slpi_loader_do(struct platform_device *pdev)
+static void slpi_load_fw(struct work_struct *slpi_ldr_work)
{
-
+ struct platform_device *pdev = slpi_private;
struct slpi_loader_private *priv = NULL;
int ret;
const char *firmware_name = NULL;
@@ -111,6 +114,12 @@ fail:
dev_err(&pdev->dev, "%s: SLPI image loading failed\n", __func__);
}
+static void slpi_loader_do(struct platform_device *pdev)
+{
+ dev_info(&pdev->dev, "%s: scheduling work to load SLPI fw\n", __func__);
+ schedule_work(&slpi_ldr_work);
+}
+
static void slpi_loader_unload(struct platform_device *pdev)
{
struct slpi_loader_private *priv = NULL;
@@ -336,6 +345,8 @@ static int sensors_ssc_probe(struct platform_device *pdev)
goto cdev_add_err;
}
+ INIT_WORK(&slpi_ldr_work, slpi_load_fw);
+
return 0;
cdev_add_err:
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index d3f1050499f3..75bebf66376d 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -46,6 +46,15 @@ config QPNP_HAPTIC
module provides haptic feedback for user actions such as a long press
on the touch screen. It uses the Android timed-output framework.
+config QPNP_PBS
+ tristate "PBS trigger support for QPNP PMIC"
+ depends on SPMI
+ help
+ This driver supports configuring software PBS trigger event through PBS
+ RAM on Qualcomm Technologies, Inc. QPNP PMICs. This module provides
+ the APIs to the client drivers that wants to send the PBS trigger
+ event to the PBS RAM.
+
config MSM_SMD
depends on MSM_SMEM
bool "MSM Shared Memory Driver (SMD)"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 2605107e2dbd..fa350d122384 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -52,6 +52,7 @@ endif
obj-$(CONFIG_QPNP_HAPTIC) += qpnp-haptic.o
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_CPUSS_DUMP) += cpuss_dump.o
+obj-$(CONFIG_QPNP_PBS) += qpnp-pbs.o
obj-$(CONFIG_QCOM_PM) += spm.o
obj-$(CONFIG_QCOM_SMD) += smd.o
obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 768871ffa9a7..8562ada73c1d 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -195,6 +195,38 @@ struct ce_irq_list {
irqreturn_t (*handler)(int, void *);
};
+struct icnss_vreg_info {
+ struct regulator *reg;
+ const char *name;
+ u32 min_v;
+ u32 max_v;
+ u32 load_ua;
+ unsigned long settle_delay;
+ bool required;
+};
+
+struct icnss_clk_info {
+ struct clk *handle;
+ const char *name;
+ u32 freq;
+ bool required;
+};
+
+static struct icnss_vreg_info icnss_vreg_info[] = {
+ {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, true},
+ {NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false},
+ {NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false},
+ {NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false},
+};
+
+#define ICNSS_VREG_INFO_SIZE ARRAY_SIZE(icnss_vreg_info)
+
+static struct icnss_clk_info icnss_clk_info[] = {
+ {NULL, "cxo_ref_clk_pin", 0, false},
+};
+
+#define ICNSS_CLK_INFO_SIZE ARRAY_SIZE(icnss_clk_info)
+
struct icnss_stats {
struct {
uint32_t posted;
@@ -248,6 +280,7 @@ struct icnss_stats {
uint32_t rejuvenate_ack_req;
uint32_t rejuvenate_ack_resp;
uint32_t rejuvenate_ack_err;
+ uint32_t trigger_recovery;
};
#define MAX_NO_OF_MAC_ADDR 4
@@ -267,6 +300,8 @@ static struct icnss_priv {
struct platform_device *pdev;
struct icnss_driver_ops *ops;
struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
+ struct icnss_vreg_info vreg_info[ICNSS_VREG_INFO_SIZE];
+ struct icnss_clk_info clk_info[ICNSS_CLK_INFO_SIZE];
u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
phys_addr_t mem_base_pa;
void __iomem *mem_base_va;
@@ -664,41 +699,220 @@ out:
return ret;
}
+static int icnss_vreg_on(struct icnss_priv *priv)
+{
+ int ret = 0;
+ struct icnss_vreg_info *vreg_info;
+ int i;
+
+ for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
+ vreg_info = &priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ icnss_pr_dbg("Regulator %s being enabled\n", vreg_info->name);
+
+ ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
+ vreg_info->max_v);
+ if (ret) {
+ icnss_pr_err("Regulator %s, can't set voltage: min_v: %u, max_v: %u, ret: %d\n",
+ vreg_info->name, vreg_info->min_v,
+ vreg_info->max_v, ret);
+ break;
+ }
+
+ if (vreg_info->load_ua) {
+ ret = regulator_set_load(vreg_info->reg,
+ vreg_info->load_ua);
+ if (ret < 0) {
+ icnss_pr_err("Regulator %s, can't set load: %u, ret: %d\n",
+ vreg_info->name,
+ vreg_info->load_ua, ret);
+ break;
+ }
+ }
+
+ ret = regulator_enable(vreg_info->reg);
+ if (ret) {
+ icnss_pr_err("Regulator %s, can't enable: %d\n",
+ vreg_info->name, ret);
+ break;
+ }
+
+ if (vreg_info->settle_delay)
+ udelay(vreg_info->settle_delay);
+ }
+
+ if (!ret)
+ return 0;
+
+ for (; i >= 0; i--) {
+ vreg_info = &priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ regulator_disable(vreg_info->reg);
+ regulator_set_load(vreg_info->reg, 0);
+ regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v);
+ }
+
+ return ret;
+}
+
+static int icnss_vreg_off(struct icnss_priv *priv)
+{
+ int ret = 0;
+ struct icnss_vreg_info *vreg_info;
+ int i;
+
+ for (i = ICNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
+ vreg_info = &priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ icnss_pr_dbg("Regulator %s being disabled\n", vreg_info->name);
+
+ ret = regulator_disable(vreg_info->reg);
+ if (ret)
+ icnss_pr_err("Regulator %s, can't disable: %d\n",
+ vreg_info->name, ret);
+
+ ret = regulator_set_load(vreg_info->reg, 0);
+ if (ret < 0)
+ icnss_pr_err("Regulator %s, can't set load: %d\n",
+ vreg_info->name, ret);
+
+ ret = regulator_set_voltage(vreg_info->reg, 0,
+ vreg_info->max_v);
+ if (ret)
+ icnss_pr_err("Regulator %s, can't set voltage: %d\n",
+ vreg_info->name, ret);
+ }
+
+ return ret;
+}
+
+static int icnss_clk_init(struct icnss_priv *priv)
+{
+ struct icnss_clk_info *clk_info;
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+ clk_info = &priv->clk_info[i];
+
+ if (!clk_info->handle)
+ continue;
+
+ icnss_pr_dbg("Clock %s being enabled\n", clk_info->name);
+
+ if (clk_info->freq) {
+ ret = clk_set_rate(clk_info->handle, clk_info->freq);
+
+ if (ret) {
+ icnss_pr_err("Clock %s, can't set frequency: %u, ret: %d\n",
+ clk_info->name, clk_info->freq,
+ ret);
+ break;
+ }
+ }
+
+ ret = clk_prepare_enable(clk_info->handle);
+ if (ret) {
+ icnss_pr_err("Clock %s, can't enable: %d\n",
+ clk_info->name, ret);
+ break;
+ }
+ }
+
+ if (ret == 0)
+ return 0;
+
+ for (; i >= 0; i--) {
+ clk_info = &priv->clk_info[i];
+
+ if (!clk_info->handle)
+ continue;
+
+ clk_disable_unprepare(clk_info->handle);
+ }
+
+ return ret;
+}
+
+static int icnss_clk_deinit(struct icnss_priv *priv)
+{
+ struct icnss_clk_info *clk_info;
+ int i;
+
+ for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+ clk_info = &priv->clk_info[i];
+
+ if (!clk_info->handle)
+ continue;
+
+ icnss_pr_dbg("Clock %s being disabled\n", clk_info->name);
+
+ clk_disable_unprepare(clk_info->handle);
+ }
+
+ return 0;
+}
+
static int icnss_hw_power_on(struct icnss_priv *priv)
{
int ret = 0;
- unsigned long flags;
icnss_pr_dbg("HW Power on: state: 0x%lx\n", priv->state);
- spin_lock_irqsave(&priv->on_off_lock, flags);
+ spin_lock(&priv->on_off_lock);
if (test_bit(ICNSS_POWER_ON, &priv->state)) {
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
return ret;
}
set_bit(ICNSS_POWER_ON, &priv->state);
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
+
+ ret = icnss_vreg_on(priv);
+ if (ret)
+ goto out;
+
+ ret = icnss_clk_init(priv);
+ if (ret)
+ goto vreg_off;
+
+ return ret;
+vreg_off:
+ icnss_vreg_off(priv);
+out:
+ clear_bit(ICNSS_POWER_ON, &priv->state);
return ret;
}
static int icnss_hw_power_off(struct icnss_priv *priv)
{
int ret = 0;
- unsigned long flags;
if (test_bit(HW_ALWAYS_ON, &quirks))
return 0;
icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state);
- spin_lock_irqsave(&priv->on_off_lock, flags);
+ spin_lock(&priv->on_off_lock);
if (!test_bit(ICNSS_POWER_ON, &priv->state)) {
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
return ret;
}
clear_bit(ICNSS_POWER_ON, &priv->state);
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
+
+ icnss_clk_deinit(priv);
+
+ ret = icnss_vreg_off(priv);
return ret;
}
@@ -1895,6 +2109,8 @@ static int icnss_call_driver_remove(struct icnss_priv *priv)
clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
+ icnss_hw_power_off(penv);
+
return 0;
}
@@ -1947,8 +2163,6 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
icnss_call_driver_remove(priv);
out:
- ret = icnss_hw_power_off(priv);
-
kfree(data);
return ret;
@@ -2923,11 +3137,16 @@ int icnss_trigger_recovery(struct device *dev)
}
if (!priv->service_notifier[0].handle) {
- icnss_pr_err("Invalid handle during recovery\n");
+ icnss_pr_err("Invalid handle during recovery, state: 0x%lx\n",
+ priv->state);
ret = -EINVAL;
goto out;
}
+ icnss_pr_dbg("Initiate PD restart at WLAN FW, state: 0x%lx\n",
+ priv->state);
+ priv->stats.trigger_recovery++;
+
/*
* Initiate PDR, required only for the first instance
*/
@@ -3005,6 +3224,114 @@ static void icnss_smmu_deinit(struct icnss_priv *priv)
priv->smmu_mapping = NULL;
}
+static int icnss_get_vreg_info(struct device *dev,
+ struct icnss_vreg_info *vreg_info)
+{
+ int ret = 0;
+ char prop_name[MAX_PROP_SIZE];
+ struct regulator *reg;
+ const __be32 *prop;
+ int len = 0;
+ int i;
+
+ reg = devm_regulator_get_optional(dev, vreg_info->name);
+ if (PTR_ERR(reg) == -EPROBE_DEFER) {
+ icnss_pr_err("EPROBE_DEFER for regulator: %s\n",
+ vreg_info->name);
+ ret = PTR_ERR(reg);
+ goto out;
+ }
+
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+
+ if (vreg_info->required) {
+ icnss_pr_err("Regulator %s doesn't exist: %d\n",
+ vreg_info->name, ret);
+ goto out;
+ } else {
+ icnss_pr_dbg("Optional regulator %s doesn't exist: %d\n",
+ vreg_info->name, ret);
+ goto done;
+ }
+ }
+
+ vreg_info->reg = reg;
+
+ snprintf(prop_name, MAX_PROP_SIZE,
+ "qcom,%s-config", vreg_info->name);
+
+ prop = of_get_property(dev->of_node, prop_name, &len);
+
+ icnss_pr_dbg("Got regulator config, prop: %s, len: %d\n",
+ prop_name, len);
+
+ if (!prop || len < (2 * sizeof(__be32))) {
+ icnss_pr_dbg("Property %s %s\n", prop_name,
+ prop ? "invalid format" : "doesn't exist");
+ goto done;
+ }
+
+ for (i = 0; (i * sizeof(__be32)) < len; i++) {
+ switch (i) {
+ case 0:
+ vreg_info->min_v = be32_to_cpup(&prop[0]);
+ break;
+ case 1:
+ vreg_info->max_v = be32_to_cpup(&prop[1]);
+ break;
+ case 2:
+ vreg_info->load_ua = be32_to_cpup(&prop[2]);
+ break;
+ case 3:
+ vreg_info->settle_delay = be32_to_cpup(&prop[3]);
+ break;
+ default:
+ icnss_pr_dbg("Property %s, ignoring value at %d\n",
+ prop_name, i);
+ break;
+ }
+ }
+
+done:
+ icnss_pr_dbg("Regulator: %s, min_v: %u, max_v: %u, load: %u, delay: %lu\n",
+ vreg_info->name, vreg_info->min_v, vreg_info->max_v,
+ vreg_info->load_ua, vreg_info->settle_delay);
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int icnss_get_clk_info(struct device *dev,
+ struct icnss_clk_info *clk_info)
+{
+ struct clk *handle;
+ int ret = 0;
+
+ handle = devm_clk_get(dev, clk_info->name);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ if (clk_info->required) {
+ icnss_pr_err("Clock %s isn't available: %d\n",
+ clk_info->name, ret);
+ goto out;
+ } else {
+ icnss_pr_dbg("Ignoring clock %s: %d\n", clk_info->name,
+ ret);
+ ret = 0;
+ goto out;
+ }
+ }
+
+ icnss_pr_dbg("Clock: %s, freq: %u\n", clk_info->name, clk_info->freq);
+
+ clk_info->handle = handle;
+out:
+ return ret;
+}
+
static int icnss_fw_debug_show(struct seq_file *s, void *data)
{
struct icnss_priv *priv = s->private;
@@ -3370,6 +3697,7 @@ static int icnss_stats_show(struct seq_file *s, void *data)
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
+ ICNSS_STATS_DUMP(s, priv, trigger_recovery);
seq_puts(s, "\n<------------------ PM stats ------------------->\n");
ICNSS_STATS_DUMP(s, priv, pm_suspend);
@@ -3715,6 +4043,21 @@ static int icnss_probe(struct platform_device *pdev)
if (ret == -EPROBE_DEFER)
goto out;
+ memcpy(priv->vreg_info, icnss_vreg_info, sizeof(icnss_vreg_info));
+ for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
+ ret = icnss_get_vreg_info(dev, &priv->vreg_info[i]);
+
+ if (ret)
+ goto out;
+ }
+
+ memcpy(priv->clk_info, icnss_clk_info, sizeof(icnss_clk_info));
+ for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+ ret = icnss_get_clk_info(dev, &priv->clk_info[i]);
+ if (ret)
+ goto out;
+ }
+
if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass"))
priv->bypass_s1_smmu = true;
diff --git a/drivers/soc/qcom/qdsp6v2/adsp-loader.c b/drivers/soc/qcom/qdsp6v2/adsp-loader.c
index 51539a36a74f..b45eac88ed12 100644
--- a/drivers/soc/qcom/qdsp6v2/adsp-loader.c
+++ b/drivers/soc/qcom/qdsp6v2/adsp-loader.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,8 @@
#include <linux/qdsp6v2/apr.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+
#include <soc/qcom/subsystem_restart.h>
#define Q6_PIL_GET_DELAY_MS 100
@@ -44,12 +46,13 @@ static struct attribute *attrs[] = {
NULL,
};
+static struct work_struct adsp_ldr_work;
static struct platform_device *adsp_private;
static void adsp_loader_unload(struct platform_device *pdev);
-static void adsp_loader_do(struct platform_device *pdev)
+static void adsp_load_fw(struct work_struct *adsp_ldr_work)
{
-
+ struct platform_device *pdev = adsp_private;
struct adsp_loader_private *priv = NULL;
const char *adsp_dt = "qcom,adsp-state";
@@ -146,6 +149,11 @@ fail:
return;
}
+static void adsp_loader_do(struct platform_device *pdev)
+{
+ dev_info(&pdev->dev, "%s: scheduling work to load ADSP fw\n", __func__);
+ schedule_work(&adsp_ldr_work);
+}
static ssize_t adsp_boot_store(struct kobject *kobj,
struct kobj_attribute *attr,
@@ -270,6 +278,8 @@ static int adsp_loader_probe(struct platform_device *pdev)
return ret;
}
+ INIT_WORK(&adsp_ldr_work, adsp_load_fw);
+
return 0;
}
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 19974b61ec1c..d11ffdde23be 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -218,6 +218,7 @@ static void apr_tal_notify_remote_rx_intent(void *handle, const void *priv,
*/
pr_debug("%s: remote queued an intent\n", __func__);
apr_ch->if_remote_intent_ready = true;
+ wake_up(&apr_ch->wait);
}
void apr_tal_notify_state(void *handle, const void *priv, unsigned event)
diff --git a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c
index 0b801c5cd7dd..cae26e3913d6 100644
--- a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c
+++ b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014,2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,8 @@
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+
#include <soc/qcom/subsystem_restart.h>
#define BOOT_CMD 1
@@ -47,11 +49,12 @@ static struct attribute *attrs[] = {
static u32 cdsp_state = CDSP_SUBSYS_DOWN;
static struct platform_device *cdsp_private;
+static struct work_struct cdsp_ldr_work;
static void cdsp_loader_unload(struct platform_device *pdev);
-static int cdsp_loader_do(struct platform_device *pdev)
+static void cdsp_load_fw(struct work_struct *cdsp_ldr_work)
{
-
+ struct platform_device *pdev = cdsp_private;
struct cdsp_loader_private *priv = NULL;
int rc = 0;
@@ -101,14 +104,19 @@ static int cdsp_loader_do(struct platform_device *pdev)
}
dev_dbg(&pdev->dev, "%s: CDSP image is loaded\n", __func__);
- return rc;
+ return;
}
fail:
dev_err(&pdev->dev, "%s: CDSP image loading failed\n", __func__);
- return rc;
+ return;
}
+static void cdsp_loader_do(struct platform_device *pdev)
+{
+ dev_info(&pdev->dev, "%s: scheduling work to load CDSP fw\n", __func__);
+ schedule_work(&cdsp_ldr_work);
+}
static ssize_t cdsp_boot_store(struct kobject *kobj,
struct kobj_attribute *attr,
@@ -126,7 +134,7 @@ static ssize_t cdsp_boot_store(struct kobject *kobj,
pr_debug("%s: going to call cdsp_loader_do\n", __func__);
cdsp_loader_do(cdsp_private);
} else if (boot == IMAGE_UNLOAD_CMD) {
- pr_debug("%s: going to call adsp_unloader\n", __func__);
+ pr_debug("%s: going to call cdsp_unloader\n", __func__);
cdsp_loader_unload(cdsp_private);
}
return count;
@@ -238,6 +246,8 @@ static int cdsp_loader_probe(struct platform_device *pdev)
return ret;
}
+ INIT_WORK(&cdsp_ldr_work, cdsp_load_fw);
+
return 0;
}
diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c
index 39070561d7e4..cf0b7ff25201 100644
--- a/drivers/soc/qcom/qpnp-haptic.c
+++ b/drivers/soc/qcom/qpnp-haptic.c
@@ -141,9 +141,7 @@
#define QPNP_HAP_CYCLS 5
#define QPNP_TEST_TIMER_MS 5
-#define AUTO_RES_ENABLE_TIMEOUT 20000
-#define AUTO_RES_ERR_CAPTURE_RES 5
-#define AUTO_RES_ERR_MAX 15
+#define QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN 20000
#define MISC_TRIM_ERROR_RC19P2_CLK 0x09F5
#define MISC_SEC_ACCESS 0x09D0
@@ -152,8 +150,22 @@
#define POLL_TIME_AUTO_RES_ERR_NS (5 * NSEC_PER_MSEC)
-#define LRA_POS_FREQ_COUNT 6
-int lra_play_rate_code[LRA_POS_FREQ_COUNT];
+#define MAX_POSITIVE_VARIATION_LRA_FREQ 30
+#define MAX_NEGATIVE_VARIATION_LRA_FREQ -30
+#define FREQ_VARIATION_STEP 5
+#define AUTO_RES_ERROR_CAPTURE_RES 5
+#define AUTO_RES_ERROR_MAX 30
+#define ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE \
+ ((MAX_POSITIVE_VARIATION_LRA_FREQ - MAX_NEGATIVE_VARIATION_LRA_FREQ) \
+ / FREQ_VARIATION_STEP)
+#define LRA_DRIVE_PERIOD_POS_ERR(hap, rc_clk_err_percent) \
+ (hap->init_drive_period_code = (hap->init_drive_period_code * \
+ (1000 + rc_clk_err_percent_x10)) / 1000)
+#define LRA_DRIVE_PERIOD_NEG_ERR(hap, rc_clk_err_percent) \
+ (hap->init_drive_period_code = (hap->init_drive_period_code * \
+ (1000 - rc_clk_err_percent_x10)) / 1000)
+
+u32 adjusted_lra_play_rate_code[ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE];
/* haptic debug register set */
static u8 qpnp_hap_dbg_regs[] = {
@@ -246,10 +258,21 @@ struct qpnp_pwm_info {
* @ pwm_info - pwm info
* @ lock - mutex lock
* @ wf_lock - mutex lock for waveform
+ * @ init_drive_period_code - the initial lra drive period code
+ * @ drive_period_code_max_limit_percent_variation - maximum limit of
+ percentage variation of drive period code
+ * @ drive_period_code_min_limit_percent_variation - minimum limit og
+ percentage variation of drive period code
+ * @ drive_period_code_max_limit - calculated drive period code with
+ percentage variation on the higher side.
+ * @ drive_period_code_min_limit - calculated drive period code with
+ percentage variation on the lower side
* @ play_mode - play mode
* @ auto_res_mode - auto resonace mode
* @ lra_high_z - high z option line
* @ timeout_ms - max timeout in ms
+ * @ time_required_to_generate_back_emf_us - the time required for sufficient
+ back-emf to be generated for auto resonance to be successful
* @ vmax_mv - max voltage in mv
* @ ilim_ma - limiting current in ma
* @ sc_deb_cycles - short circuit debounce cycles
@@ -280,6 +303,8 @@ struct qpnp_pwm_info {
* @ sup_brake_pat - support custom brake pattern
* @ correct_lra_drive_freq - correct LRA Drive Frequency
* @ misc_trim_error_rc19p2_clk_reg_present - if MISC Trim Error reg is present
+ * @ perform_lra_auto_resonance_search - whether lra auto resonance search
+ * algorithm should be performed or not.
*/
struct qpnp_hap {
struct platform_device *pdev;
@@ -300,7 +325,9 @@ struct qpnp_hap {
enum qpnp_hap_mode play_mode;
enum qpnp_hap_auto_res_mode auto_res_mode;
enum qpnp_hap_high_z lra_high_z;
+ u32 init_drive_period_code;
u32 timeout_ms;
+ u32 time_required_to_generate_back_emf_us;
u32 vmax_mv;
u32 ilim_ma;
u32 sc_deb_cycles;
@@ -312,16 +339,21 @@ struct qpnp_hap {
u32 play_irq;
u32 sc_irq;
u16 base;
+ u16 drive_period_code_max_limit;
+ u16 drive_period_code_min_limit;
+ u8 drive_period_code_max_limit_percent_variation;
+ u8 drive_period_code_min_limit_percent_variation;
u8 act_type;
u8 wave_shape;
- u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN];
- u8 shadow_wave_samp[QPNP_HAP_WAV_SAMP_LEN];
- u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN];
+ u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN];
+ u8 shadow_wave_samp[QPNP_HAP_WAV_SAMP_LEN];
+ u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN];
u8 reg_en_ctl;
u8 reg_play;
u8 lra_res_cal_period;
u8 sc_duration;
u8 ext_pwm_dtest_line;
+ bool vcc_pon_enabled;
bool state;
bool use_play_irq;
bool use_sc_irq;
@@ -333,6 +365,7 @@ struct qpnp_hap {
bool sup_brake_pat;
bool correct_lra_drive_freq;
bool misc_trim_error_rc19p2_clk_reg_present;
+ bool perform_lra_auto_resonance_search;
};
static struct qpnp_hap *ghap;
@@ -1314,29 +1347,62 @@ static struct device_attribute qpnp_hap_attrs[] = {
qpnp_hap_min_max_test_data_store),
};
-static void calculate_lra_code(struct qpnp_hap *hap)
+static int calculate_lra_code(struct qpnp_hap *hap)
{
- u8 play_rate_code_lo, play_rate_code_hi;
- int play_rate_code, neg_idx = 0, pos_idx = LRA_POS_FREQ_COUNT-1;
- int lra_init_freq, freq_variation, start_variation = AUTO_RES_ERR_MAX;
+ u8 lra_drive_period_code_lo = 0, lra_drive_period_code_hi = 0;
+ u32 lra_drive_period_code, lra_drive_frequency_hz, freq_variation;
+ u8 start_variation = AUTO_RES_ERROR_MAX, i;
+ u8 neg_idx = 0, pos_idx = ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE - 1;
+ int rc = 0;
- qpnp_hap_read_reg(hap, &play_rate_code_lo,
- QPNP_HAP_RATE_CFG1_REG(hap->base));
- qpnp_hap_read_reg(hap, &play_rate_code_hi,
- QPNP_HAP_RATE_CFG2_REG(hap->base));
+ rc = qpnp_hap_read_reg(hap, &lra_drive_period_code_lo,
+ QPNP_HAP_RATE_CFG1_REG(hap->base));
+ if (rc) {
+ dev_err(&hap->pdev->dev,
+ "Error while reading RATE_CFG1 register\n");
+ return rc;
+ }
+
+ rc = qpnp_hap_read_reg(hap, &lra_drive_period_code_hi,
+ QPNP_HAP_RATE_CFG2_REG(hap->base));
+ if (rc) {
+ dev_err(&hap->pdev->dev,
+ "Error while reading RATE_CFG2 register\n");
+ return rc;
+ }
- play_rate_code = (play_rate_code_hi << 8) | (play_rate_code_lo & 0xff);
+ if (!lra_drive_period_code_lo && !lra_drive_period_code_hi) {
+ dev_err(&hap->pdev->dev,
+ "Unexpected Error: both RATE_CFG1 and RATE_CFG2 read 0\n");
+ return -EINVAL;
+ }
- lra_init_freq = 200000 / play_rate_code;
+ lra_drive_period_code =
+ (lra_drive_period_code_hi << 8) | (lra_drive_period_code_lo & 0xff);
+ lra_drive_frequency_hz = 200000 / lra_drive_period_code;
- while (start_variation >= AUTO_RES_ERR_CAPTURE_RES) {
- freq_variation = (lra_init_freq * start_variation) / 100;
- lra_play_rate_code[neg_idx++] = 200000 / (lra_init_freq -
- freq_variation);
- lra_play_rate_code[pos_idx--] = 200000 / (lra_init_freq +
- freq_variation);
- start_variation -= AUTO_RES_ERR_CAPTURE_RES;
+ while (start_variation >= AUTO_RES_ERROR_CAPTURE_RES) {
+ freq_variation =
+ (lra_drive_frequency_hz * start_variation) / 100;
+ adjusted_lra_play_rate_code[neg_idx++] =
+ 200000 / (lra_drive_frequency_hz - freq_variation);
+ adjusted_lra_play_rate_code[pos_idx--] =
+ 200000 / (lra_drive_frequency_hz + freq_variation);
+ start_variation -= AUTO_RES_ERROR_CAPTURE_RES;
}
+
+ dev_dbg(&hap->pdev->dev,
+ "lra_drive_period_code_lo = 0x%x lra_drive_period_code_hi = 0x%x\n"
+ "lra_drive_period_code = 0x%x, lra_drive_frequency_hz = 0x%x\n"
+ "Calculated play rate code values are :\n",
+ lra_drive_period_code_lo, lra_drive_period_code_hi,
+ lra_drive_period_code, lra_drive_frequency_hz);
+
+ for (i = 0; i < ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE; ++i)
+ dev_dbg(&hap->pdev->dev,
+ " 0x%x", adjusted_lra_play_rate_code[i]);
+
+ return 0;
}
static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable)
@@ -1369,20 +1435,37 @@ static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable)
static void update_lra_frequency(struct qpnp_hap *hap)
{
u8 lra_auto_res_lo = 0, lra_auto_res_hi = 0;
+ u32 play_rate_code;
qpnp_hap_read_reg(hap, &lra_auto_res_lo,
QPNP_HAP_LRA_AUTO_RES_LO(hap->base));
qpnp_hap_read_reg(hap, &lra_auto_res_hi,
QPNP_HAP_LRA_AUTO_RES_HI(hap->base));
- if (lra_auto_res_lo && lra_auto_res_hi) {
- qpnp_hap_write_reg(hap, &lra_auto_res_lo,
- QPNP_HAP_RATE_CFG1_REG(hap->base));
+ play_rate_code =
+ (lra_auto_res_hi & 0xF0) << 4 | (lra_auto_res_lo & 0xFF);
- lra_auto_res_hi = lra_auto_res_hi >> 4;
- qpnp_hap_write_reg(hap, &lra_auto_res_hi,
- QPNP_HAP_RATE_CFG2_REG(hap->base));
- }
+ dev_dbg(&hap->pdev->dev,
+ "lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n",
+ lra_auto_res_lo, lra_auto_res_hi, play_rate_code);
+
+ /*
+ * If the drive period code read from AUTO RES_LO and AUTO_RES_HI
+ * registers is more than the max limit percent variation read from
+ * DT or less than the min limit percent variation read from DT, then
+ * RATE_CFG registers are not uptdated.
+ */
+
+ if ((play_rate_code <= hap->drive_period_code_min_limit) ||
+ (play_rate_code >= hap->drive_period_code_max_limit))
+ return;
+
+ qpnp_hap_write_reg(hap, &lra_auto_res_lo,
+ QPNP_HAP_RATE_CFG1_REG(hap->base));
+
+ lra_auto_res_hi = lra_auto_res_hi >> 4;
+ qpnp_hap_write_reg(hap, &lra_auto_res_hi,
+ QPNP_HAP_RATE_CFG2_REG(hap->base));
}
static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer)
@@ -1412,36 +1495,38 @@ static void correct_auto_res_error(struct work_struct *auto_res_err_work)
struct qpnp_hap, auto_res_err_work);
u8 lra_code_lo, lra_code_hi, disable_hap = 0x00;
- static int lra_freq_index;
- ktime_t currtime, remaining_time;
- int temp, rem = 0, index = lra_freq_index % LRA_POS_FREQ_COUNT;
+ static u8 lra_freq_index;
+ ktime_t currtime = ktime_set(0, 0), remaining_time = ktime_set(0, 0);
- if (hrtimer_active(&hap->hap_timer)) {
+ if (hrtimer_active(&hap->hap_timer))
remaining_time = hrtimer_get_remaining(&hap->hap_timer);
- rem = (int)ktime_to_us(remaining_time);
- }
qpnp_hap_play(hap, 0);
qpnp_hap_write_reg(hap, &disable_hap,
QPNP_HAP_EN_CTL_REG(hap->base));
- lra_code_lo = lra_play_rate_code[index] & QPNP_HAP_RATE_CFG1_MASK;
- qpnp_hap_write_reg(hap, &lra_code_lo,
- QPNP_HAP_RATE_CFG1_REG(hap->base));
+ if (hap->perform_lra_auto_resonance_search) {
+ lra_code_lo =
+ adjusted_lra_play_rate_code[lra_freq_index]
+ & QPNP_HAP_RATE_CFG1_MASK;
- qpnp_hap_read_reg(hap, &lra_code_hi,
- QPNP_HAP_RATE_CFG2_REG(hap->base));
+ qpnp_hap_write_reg(hap, &lra_code_lo,
+ QPNP_HAP_RATE_CFG1_REG(hap->base));
- lra_code_hi &= QPNP_HAP_RATE_CFG2_MASK;
- temp = lra_play_rate_code[index] >> QPNP_HAP_RATE_CFG2_SHFT;
- lra_code_hi |= temp;
+ lra_code_hi = adjusted_lra_play_rate_code[lra_freq_index]
+ >> QPNP_HAP_RATE_CFG2_SHFT;
- qpnp_hap_write_reg(hap, &lra_code_hi,
+ qpnp_hap_write_reg(hap, &lra_code_hi,
QPNP_HAP_RATE_CFG2_REG(hap->base));
- lra_freq_index++;
+ lra_freq_index = (lra_freq_index+1) %
+ ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE;
+ }
- if (rem > 0) {
+ dev_dbg(&hap->pdev->dev, "Remaining time is %lld\n",
+ ktime_to_us(remaining_time));
+
+ if ((ktime_to_us(remaining_time)) > 0) {
currtime = ktime_get();
hap->state = 1;
hrtimer_forward(&hap->hap_timer, currtime, remaining_time);
@@ -1455,6 +1540,7 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on)
int rc = 0;
u8 val = 0;
unsigned long timeout_ns = POLL_TIME_AUTO_RES_ERR_NS;
+ u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us;
if (hap->play_mode == QPNP_HAP_PWM) {
if (on)
@@ -1464,8 +1550,21 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on)
} else if (hap->play_mode == QPNP_HAP_BUFFER ||
hap->play_mode == QPNP_HAP_DIRECT) {
if (on) {
- if (hap->correct_lra_drive_freq ||
- hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD)
+ /*
+ * For auto resonance detection to work properly,
+ * sufficient back-emf has to be generated. In general,
+ * back-emf takes some time to build up. When the auto
+ * resonance mode is chosen as QWD, high-z will be
+ * applied for every LRA cycle and hence there won't be
+ * enough back-emf at the start-up. Hence, the motor
+ * needs to vibrate for few LRA cycles after the PLAY
+ * bit is asserted. So disable the auto resonance here
+ * and enable it after the sleep of
+ * 'time_required_to_generate_back_emf_us' is completed.
+ */
+ if ((hap->act_type == QPNP_HAP_LRA) &&
+ (hap->correct_lra_drive_freq ||
+ hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD))
qpnp_hap_auto_res_enable(hap, 0);
rc = qpnp_hap_mod_enable(hap, on);
@@ -1474,17 +1573,18 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on)
rc = qpnp_hap_play(hap, on);
- if ((hap->act_type == QPNP_HAP_LRA &&
- hap->correct_lra_drive_freq) ||
- hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD) {
- usleep_range(AUTO_RES_ENABLE_TIMEOUT,
- (AUTO_RES_ENABLE_TIMEOUT + 1));
+ if ((hap->act_type == QPNP_HAP_LRA) &&
+ (hap->correct_lra_drive_freq ||
+ hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD)) {
+ usleep_range(back_emf_delay_us,
+ (back_emf_delay_us + 1));
rc = qpnp_hap_auto_res_enable(hap, 1);
if (rc < 0)
return rc;
}
- if (hap->correct_lra_drive_freq) {
+ if (hap->act_type == QPNP_HAP_LRA &&
+ hap->correct_lra_drive_freq) {
/*
* Start timer to poll Auto Resonance error bit
*/
@@ -1500,7 +1600,8 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on)
if (rc < 0)
return rc;
- if (hap->correct_lra_drive_freq) {
+ if (hap->act_type == QPNP_HAP_LRA &&
+ hap->correct_lra_drive_freq) {
rc = qpnp_hap_read_reg(hap, &val,
QPNP_HAP_STATUS(hap->base));
if (!(val & AUTO_RES_ERR_BIT))
@@ -1511,7 +1612,6 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on)
if (hap->act_type == QPNP_HAP_LRA &&
hap->correct_lra_drive_freq) {
hrtimer_cancel(&hap->auto_res_err_poll_timer);
- calculate_lra_code(hap);
}
}
}
@@ -1619,13 +1719,15 @@ static void qpnp_hap_worker(struct work_struct *work)
struct qpnp_hap *hap = container_of(work, struct qpnp_hap,
work);
u8 val = 0x00;
- int rc, reg_en = 0;
+ int rc;
- if (hap->vcc_pon) {
- reg_en = regulator_enable(hap->vcc_pon);
- if (reg_en)
- pr_err("%s: could not enable vcc_pon regulator\n",
- __func__);
+ if (hap->vcc_pon && hap->state && !hap->vcc_pon_enabled) {
+ rc = regulator_enable(hap->vcc_pon);
+ if (rc < 0)
+ pr_err("%s: could not enable vcc_pon regulator rc=%d\n",
+ __func__, rc);
+ else
+ hap->vcc_pon_enabled = true;
}
/* Disable haptics module if the duration of short circuit
@@ -1640,11 +1742,13 @@ static void qpnp_hap_worker(struct work_struct *work)
qpnp_hap_set(hap, hap->state);
}
- if (hap->vcc_pon && !reg_en) {
+ if (hap->vcc_pon && !hap->state && hap->vcc_pon_enabled) {
rc = regulator_disable(hap->vcc_pon);
if (rc)
- pr_err("%s: could not disable vcc_pon regulator\n",
- __func__);
+ pr_err("%s: could not disable vcc_pon regulator rc=%d\n",
+ __func__, rc);
+ else
+ hap->vcc_pon_enabled = false;
}
}
@@ -1706,10 +1810,16 @@ static SIMPLE_DEV_PM_OPS(qpnp_haptic_pm_ops, qpnp_haptic_suspend, NULL);
/* Configuration api for haptics registers */
static int qpnp_hap_config(struct qpnp_hap *hap)
{
- u8 reg = 0, unlock_val, error_value;
- int rc, i, temp;
+ u8 reg = 0, unlock_val;
+ u32 temp;
+ int rc, i;
uint error_code = 0;
+ /*
+ * This denotes the percentage error in rc clock multiplied by 10
+ */
+ u8 rc_clk_err_percent_x10;
+
/* Configure the ACTUATOR TYPE register */
rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_ACT_TYPE_REG(hap->base));
if (rc < 0)
@@ -1838,16 +1948,22 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
else if (hap->wave_play_rate_us > QPNP_HAP_WAV_PLAY_RATE_US_MAX)
hap->wave_play_rate_us = QPNP_HAP_WAV_PLAY_RATE_US_MAX;
- temp = hap->wave_play_rate_us / QPNP_HAP_RATE_CFG_STEP_US;
+ hap->init_drive_period_code =
+ hap->wave_play_rate_us / QPNP_HAP_RATE_CFG_STEP_US;
/*
- * The frequency of 19.2Mzhz RC clock is subject to variation.
- * In PMI8950, TRIM_ERROR_RC19P2_CLK register in MISC module
- * holds the frequency error in 19.2Mhz RC clock
+ * The frequency of 19.2Mzhz RC clock is subject to variation. Currently
+ * a few PMI modules have MISC_TRIM_ERROR_RC19P2_CLK register
+ * present in their MISC block. This register holds the frequency error
+ * in 19.2Mhz RC clock.
*/
if ((hap->act_type == QPNP_HAP_LRA) && hap->correct_lra_drive_freq
&& hap->misc_trim_error_rc19p2_clk_reg_present) {
unlock_val = MISC_SEC_UNLOCK;
+ /*
+ * This SID value may change depending on the PMI chip where
+ * the MISC block is present.
+ */
rc = regmap_write(hap->regmap, MISC_SEC_ACCESS, unlock_val);
if (rc)
dev_err(&hap->pdev->dev,
@@ -1855,36 +1971,69 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
regmap_read(hap->regmap, MISC_TRIM_ERROR_RC19P2_CLK,
&error_code);
+ dev_dbg(&hap->pdev->dev, "TRIM register = 0x%x\n", error_code);
- error_value = (error_code & 0x0F) * 7;
+ /*
+ * Extract the 4 LSBs and multiply by 7 to get
+ * the %error in RC clock multiplied by 10
+ */
+ rc_clk_err_percent_x10 = (error_code & 0x0F) * 7;
- if (error_code & 0x80)
- temp = (temp * (1000 - error_value)) / 1000;
+ /*
+ * If the TRIM register holds value less than 0x80,
+ * then there is a positive error in the RC clock.
+ * If the TRIM register holds value greater than or equal to
+ * 0x80, then there is a negative error in the RC clock.
+ *
+ * The adjusted play rate code is calculated as follows:
+ * LRA drive period code (RATE_CFG) =
+ * 200KHz * 1 / LRA drive frequency * ( 1 + %error/ 100)
+ *
+ * This can be rewritten as:
+ * LRA drive period code (RATE_CFG) =
+ * 200KHz * 1/LRA drive frequency *( 1 + %error * 10/1000)
+ *
+ * Since 200KHz * 1/LRA drive frequency is already calculated
+ * above we only do rest of the scaling here.
+ */
+ if (error_code >= 128)
+ LRA_DRIVE_PERIOD_NEG_ERR(hap, rc_clk_err_percent_x10);
else
- temp = (temp * (1000 + error_value)) / 1000;
+ LRA_DRIVE_PERIOD_POS_ERR(hap, rc_clk_err_percent_x10);
}
- reg = temp & QPNP_HAP_RATE_CFG1_MASK;
+ dev_dbg(&hap->pdev->dev,
+ "Play rate code 0x%x\n", hap->init_drive_period_code);
+
+ reg = hap->init_drive_period_code & QPNP_HAP_RATE_CFG1_MASK;
rc = qpnp_hap_write_reg(hap, &reg,
QPNP_HAP_RATE_CFG1_REG(hap->base));
if (rc)
return rc;
- rc = qpnp_hap_read_reg(hap, &reg,
- QPNP_HAP_RATE_CFG2_REG(hap->base));
- if (rc < 0)
- return rc;
- reg &= QPNP_HAP_RATE_CFG2_MASK;
- temp = temp >> QPNP_HAP_RATE_CFG2_SHFT;
- reg |= temp;
+ reg = (hap->init_drive_period_code & 0xF00) >> QPNP_HAP_RATE_CFG2_SHFT;
rc = qpnp_hap_write_reg(hap, &reg,
QPNP_HAP_RATE_CFG2_REG(hap->base));
if (rc)
return rc;
- if ((hap->act_type == QPNP_HAP_LRA) && hap->correct_lra_drive_freq)
+ if (hap->act_type == QPNP_HAP_LRA &&
+ hap->perform_lra_auto_resonance_search)
calculate_lra_code(hap);
+ if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) {
+ hap->drive_period_code_max_limit =
+ (hap->init_drive_period_code * 100) /
+ (100 - hap->drive_period_code_max_limit_percent_variation);
+ hap->drive_period_code_min_limit =
+ (hap->init_drive_period_code * 100) /
+ (100 + hap->drive_period_code_min_limit_percent_variation);
+ dev_dbg(&hap->pdev->dev, "Drive period code max limit %x\n"
+ "Drive period code min limit %x\n",
+ hap->drive_period_code_max_limit,
+ hap->drive_period_code_min_limit);
+ }
+
/* Configure BRAKE register */
rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_EN_CTL2_REG(hap->base));
if (rc < 0)
@@ -2031,13 +2180,44 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap)
return rc;
}
+ hap->perform_lra_auto_resonance_search =
+ of_property_read_bool(pdev->dev.of_node,
+ "qcom,perform-lra-auto-resonance-search");
+
hap->correct_lra_drive_freq =
of_property_read_bool(pdev->dev.of_node,
"qcom,correct-lra-drive-freq");
+ hap->drive_period_code_max_limit_percent_variation = 25;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,drive-period-code-max-limit-percent-variation", &temp);
+ if (!rc)
+ hap->drive_period_code_max_limit_percent_variation =
+ (u8) temp;
+
+ hap->drive_period_code_min_limit_percent_variation = 25;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,drive-period-code-min-limit-percent-variation", &temp);
+ if (!rc)
+ hap->drive_period_code_min_limit_percent_variation =
+ (u8) temp;
+
hap->misc_trim_error_rc19p2_clk_reg_present =
of_property_read_bool(pdev->dev.of_node,
"qcom,misc-trim-error-rc19p2-clk-reg-present");
+
+ if (hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD) {
+ hap->time_required_to_generate_back_emf_us =
+ QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,time-required-to-generate-back-emf-us",
+ &temp);
+ if (!rc)
+ hap->time_required_to_generate_back_emf_us =
+ temp;
+ } else {
+ hap->time_required_to_generate_back_emf_us = 0;
+ }
}
rc = of_property_read_string(pdev->dev.of_node,
diff --git a/drivers/soc/qcom/qpnp-pbs.c b/drivers/soc/qcom/qpnp-pbs.c
new file mode 100644
index 000000000000..287c8a25b391
--- /dev/null
+++ b/drivers/soc/qcom/qpnp-pbs.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "PBS: %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/qpnp/qpnp-pbs.h>
+
+#define QPNP_PBS_DEV_NAME "qcom,qpnp-pbs"
+
+#define PBS_CLIENT_TRIG_CTL 0x42
+#define PBS_CLIENT_SW_TRIG_BIT BIT(7)
+#define PBS_CLIENT_SCRATCH1 0x50
+#define PBS_CLIENT_SCRATCH2 0x51
+
+static LIST_HEAD(pbs_dev_list);
+static DEFINE_MUTEX(pbs_list_lock);
+
+struct qpnp_pbs {
+ struct platform_device *pdev;
+ struct device *dev;
+ struct device_node *dev_node;
+ struct regmap *regmap;
+ struct mutex pbs_lock;
+ struct list_head link;
+
+ u32 base;
+};
+
+static int qpnp_pbs_read(struct qpnp_pbs *pbs, u32 address,
+ u8 *val, int count)
+{
+ int rc = 0;
+ struct platform_device *pdev = pbs->pdev;
+
+ rc = regmap_bulk_read(pbs->regmap, address, val, count);
+ if (rc)
+ pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n",
+ address, to_spmi_device(pdev->dev.parent)->usid, rc);
+
+ return rc;
+}
+
+static int qpnp_pbs_write(struct qpnp_pbs *pbs, u16 address,
+ u8 *val, int count)
+{
+ int rc = 0;
+ struct platform_device *pdev = pbs->pdev;
+
+ rc = regmap_bulk_write(pbs->regmap, address, val, count);
+ if (rc < 0)
+ pr_err("Failed to write address =0x%02x sid=0x%02x rc=%d\n",
+ address, to_spmi_device(pdev->dev.parent)->usid, rc);
+ else
+ pr_debug("Wrote 0x%02X to addr 0x%04x\n", *val, address);
+
+ return rc;
+}
+
+static int qpnp_pbs_masked_write(struct qpnp_pbs *pbs, u16 address,
+ u8 mask, u8 val)
+{
+ int rc;
+
+ rc = regmap_update_bits(pbs->regmap, address, mask, val);
+ if (rc < 0)
+ pr_err("Failed to write address 0x%04X, rc = %d\n",
+ address, rc);
+ else
+ pr_debug("Wrote 0x%02X to addr 0x%04X\n",
+ val, address);
+
+ return rc;
+}
+
+static struct qpnp_pbs *get_pbs_client_node(struct device_node *dev_node)
+{
+ struct qpnp_pbs *pbs;
+
+ mutex_lock(&pbs_list_lock);
+ list_for_each_entry(pbs, &pbs_dev_list, link) {
+ if (dev_node == pbs->dev_node) {
+ mutex_unlock(&pbs_list_lock);
+ return pbs;
+ }
+ }
+
+ mutex_unlock(&pbs_list_lock);
+ return ERR_PTR(-EINVAL);
+}
+
+static int qpnp_pbs_wait_for_ack(struct qpnp_pbs *pbs, u8 bit_pos)
+{
+ int rc = 0;
+ u16 retries = 2000, dly = 1000;
+ u8 val;
+
+ while (retries--) {
+ rc = qpnp_pbs_read(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to read register %x rc = %d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ return rc;
+ }
+
+ if (val == 0xFF) {
+ /* PBS error - clear SCRATCH2 register */
+ rc = qpnp_pbs_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, 0, 1);
+ if (rc < 0) {
+ pr_err("Failed to clear register %x rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ return rc;
+ }
+
+ pr_err("NACK from PBS for bit %d\n", bit_pos);
+ return -EINVAL;
+ }
+
+ if (val & BIT(bit_pos)) {
+ pr_debug("PBS sequence for bit %d executed!\n",
+ bit_pos);
+ break;
+ }
+
+ usleep_range(dly, dly + 100);
+ }
+
+ if (!retries) {
+ pr_err("Timeout for PBS ACK/NACK for bit %d\n", bit_pos);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/**
+ * qpnp_pbs_trigger_event - Trigger the PBS RAM sequence
+ *
+ * Returns = 0 If the PBS RAM sequence executed successfully.
+ *
+ * Returns < 0 for errors.
+ *
+ * This function is used to trigger the PBS RAM sequence to be
+ * executed by the client driver.
+ *
+ * The PBS trigger sequence involves
+ * 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1
+ * 2. Initiating the SW PBS trigger
+ * 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the
+ * completion of the sequence.
+ * 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute
+ */
+int qpnp_pbs_trigger_event(struct device_node *dev_node, u8 bitmap)
+{
+ struct qpnp_pbs *pbs;
+ int rc = 0;
+ u16 bit_pos = 0;
+ u8 val, mask = 0;
+
+ if (!dev_node)
+ return -EINVAL;
+
+ if (!bitmap) {
+ pr_err("Invalid bitmap passed by client\n");
+ return -EINVAL;
+ }
+
+ pbs = get_pbs_client_node(dev_node);
+ if (IS_ERR_OR_NULL(pbs)) {
+ pr_err("Unable to find the PBS dev_node\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&pbs->pbs_lock);
+ rc = qpnp_pbs_read(pbs, pbs->base + PBS_CLIENT_SCRATCH2, &val, 1);
+ if (rc < 0) {
+ pr_err("read register %x failed rc = %d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto out;
+ }
+
+ if (val == 0xFF) {
+ /* PBS error - clear SCRATCH2 register */
+ rc = qpnp_pbs_write(pbs, pbs->base + PBS_CLIENT_SCRATCH2, 0, 1);
+ if (rc < 0) {
+ pr_err("Failed to clear register %x rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto out;
+ }
+ }
+
+ for (bit_pos = 0; bit_pos < 8; bit_pos++) {
+ if (bitmap & BIT(bit_pos)) {
+ /*
+ * Clear the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH2 mask register.
+ */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+ if (rc < 0) {
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto error;
+ }
+
+ /*
+ * Set the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH1 register.
+ */
+ val = mask = BIT(bit_pos);
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH1, mask, val);
+ if (rc < 0) {
+ pr_err("Failed to set %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH1, rc);
+ goto error;
+ }
+
+ /* Initiate the SW trigger */
+ val = mask = PBS_CLIENT_SW_TRIG_BIT;
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_TRIG_CTL, mask, val);
+ if (rc < 0) {
+ pr_err("Failed to write register %x rc=%d\n",
+ PBS_CLIENT_TRIG_CTL, rc);
+ goto error;
+ }
+
+ rc = qpnp_pbs_wait_for_ack(pbs, bit_pos);
+ if (rc < 0) {
+ pr_err("Error during wait_for_ack\n");
+ goto error;
+ }
+
+ /*
+ * Clear the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH1 register.
+ */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH1, BIT(bit_pos), 0);
+ if (rc < 0) {
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH1, rc);
+ goto error;
+ }
+
+ /*
+ * Clear the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH2 mask register.
+ */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+ if (rc < 0) {
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto error;
+ }
+
+ }
+ }
+
+error:
+ /* Clear all the requested bitmap */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base + PBS_CLIENT_SCRATCH1,
+ bitmap, 0);
+ if (rc < 0)
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH1, rc);
+out:
+ mutex_unlock(&pbs->pbs_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_pbs_trigger_event);
+
+static int qpnp_pbs_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ u32 val = 0;
+ struct qpnp_pbs *pbs;
+
+ pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL);
+ if (!pbs)
+ return -ENOMEM;
+
+ pbs->pdev = pdev;
+ pbs->dev = &pdev->dev;
+ pbs->dev_node = pdev->dev.of_node;
+ pbs->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!pbs->regmap) {
+ dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "reg", &val);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't find reg in node = %s rc = %d\n",
+ pdev->dev.of_node->full_name, rc);
+ return rc;
+ }
+
+ pbs->base = val;
+ mutex_init(&pbs->pbs_lock);
+
+ dev_set_drvdata(&pdev->dev, pbs);
+
+ mutex_lock(&pbs_list_lock);
+ list_add(&pbs->link, &pbs_dev_list);
+ mutex_unlock(&pbs_list_lock);
+
+ return 0;
+}
+
+static const struct of_device_id qpnp_pbs_match_table[] = {
+ { .compatible = QPNP_PBS_DEV_NAME },
+ {}
+};
+
+static struct platform_driver qpnp_pbs_driver = {
+ .driver = {
+ .name = QPNP_PBS_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_pbs_match_table,
+ },
+ .probe = qpnp_pbs_probe,
+};
+
+static int __init qpnp_pbs_init(void)
+{
+ return platform_driver_register(&qpnp_pbs_driver);
+}
+arch_initcall(qpnp_pbs_init);
+
+static void __exit qpnp_pbs_exit(void)
+{
+ return platform_driver_unregister(&qpnp_pbs_driver);
+}
+module_exit(qpnp_pbs_exit);
+
+MODULE_DESCRIPTION("QPNP PBS DRIVER");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_PBS_DEV_NAME);
diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c
index 2b708732760f..8581ed587ead 100644
--- a/drivers/soc/qcom/service-locator.c
+++ b/drivers/soc/qcom/service-locator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -111,6 +111,7 @@ static void service_locator_svc_arrive(struct work_struct *work)
qmi_handle_create(service_locator_clnt_notify, NULL);
if (!service_locator.clnt_handle) {
service_locator.clnt_handle = NULL;
+ complete_all(&service_locator.service_available);
mutex_unlock(&service_locator.service_mutex);
pr_err("Service locator QMI client handle alloc failed!\n");
return;
@@ -123,6 +124,7 @@ static void service_locator_svc_arrive(struct work_struct *work)
if (rc) {
qmi_handle_destroy(service_locator.clnt_handle);
service_locator.clnt_handle = NULL;
+ complete_all(&service_locator.service_available);
mutex_unlock(&service_locator.service_mutex);
pr_err("Unable to connnect to service rc:%d\n", rc);
return;
@@ -138,6 +140,7 @@ static void service_locator_svc_exit(struct work_struct *work)
mutex_lock(&service_locator.service_mutex);
qmi_handle_destroy(service_locator.clnt_handle);
service_locator.clnt_handle = NULL;
+ complete_all(&service_locator.service_available);
mutex_unlock(&service_locator.service_mutex);
pr_info("Connection with service locator lost\n");
}
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 6a60e3624420..07610877f140 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -886,10 +886,11 @@ static int spcom_rx(struct spcom_channel *ch,
if (timeleft == 0) {
pr_err("rx_done timeout [%d] msec expired.\n", timeout_msec);
- goto exit_err;
+ mutex_unlock(&ch->lock);
+ return -ETIMEDOUT;
} else if (ch->rx_abort) {
- pr_err("rx aborted.\n");
- goto exit_err;
+ mutex_unlock(&ch->lock);
+ return -ERESTART; /* probably SSR */
} else if (ch->actual_rx_size) {
pr_debug("actual_rx_size is [%d].\n", ch->actual_rx_size);
} else {
@@ -1976,7 +1977,8 @@ static int spcom_handle_read_req_resp(struct spcom_channel *ch,
ret = spcom_rx(ch, rx_buf, rx_buf_size, timeout_msec);
if (ret < 0) {
pr_err("rx error %d.\n", ret);
- goto exit_err;
+ kfree(rx_buf);
+ return ret;
} else {
size = ret; /* actual_rx_size */
}
@@ -2269,8 +2271,14 @@ static ssize_t spcom_device_read(struct file *filp, char __user *user_buff,
if (buf == NULL)
return -ENOMEM;
- actual_size = spcom_handle_read(ch, buf, size);
- if ((actual_size <= 0) || (actual_size > size)) {
+ ret = spcom_handle_read(ch, buf, size);
+ if (ret < 0) {
+ pr_err("read error [%d].\n", ret);
+ kfree(buf);
+ return ret;
+ }
+ actual_size = ret;
+ if ((actual_size == 0) || (actual_size > size)) {
pr_err("invalid actual_size [%d].\n", actual_size);
kfree(buf);
return -EFAULT;
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 2f08a6c9d476..e46edc83430c 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -40,7 +40,6 @@ MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data");
static struct workqueue_struct *ipa_usb_wq;
-static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis);
static void ipa_disconnect_handler(struct gsi_data_port *d_port);
static int gsi_ctrl_send_notification(struct f_gsi *gsi);
static int gsi_alloc_trb_buffer(struct f_gsi *gsi);
@@ -48,6 +47,20 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi);
static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned len, gfp_t flags);
static void gsi_ctrl_pkt_free(struct gsi_ctrl_pkt *pkt);
+static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f)
+{
+ bool remote_wakeup_allowed;
+
+ if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
+ remote_wakeup_allowed = f->func_wakeup_allowed;
+ else
+ remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
+
+ log_event_dbg("%s: remote_wakeup_allowed:%s", __func__,
+ remote_wakeup_allowed ? "true" : "false");
+ return remote_wakeup_allowed;
+}
+
void post_event(struct gsi_data_port *port, u8 event)
{
unsigned long flags;
@@ -477,16 +490,22 @@ static void ipa_disconnect_handler(struct gsi_data_port *d_port)
log_event_dbg("%s: EP Disable for data", __func__);
- /* Block doorbell to GSI to avoid USB wrapper from
- * ringing doorbell in case IPA clocks are OFF
- */
- usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
+ if (gsi->d_port.in_ep) {
+ /*
+ * Block doorbell to GSI to avoid USB wrapper from
+ * ringing doorbell in case IPA clocks are OFF.
+ */
+ usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
GSI_EP_OP_SET_CLR_BLOCK_DBL);
+ gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc;
+ usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE);
+ }
- usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE);
-
- if (gsi->d_port.out_ep)
+ if (gsi->d_port.out_ep) {
+ gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc;
usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_DISABLE);
+ }
+
gsi->d_port.net_ready_trigger = false;
}
@@ -523,19 +542,21 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port)
int ret = 0;
bool block_db, f_suspend;
struct f_gsi *gsi = d_port_to_gsi(d_port);
+ struct usb_function *f = &gsi->function;
+
+ f_suspend = f->func_wakeup_allowed;
+ log_event_dbg("%s: f_suspend:%d", __func__, f_suspend);
- f_suspend = gsi->function.func_wakeup_allowed;
if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend,
GSI_EP_OP_CHECK_FOR_SUSPEND)) {
ret = -EFAULT;
goto done;
}
- log_event_dbg("%s: Calling xdci_suspend", __func__);
+ log_event_dbg("%s: Calling xdci_suspend", __func__);
ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle,
gsi->d_port.in_channel_handle, gsi->prot_id,
- true);
-
+ usb_gsi_remote_wakeup_allowed(f));
if (!ret) {
d_port->sm_state = STATE_SUSPENDED;
log_event_dbg("%s: STATE SUSPENDED", __func__);
@@ -553,10 +574,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port)
log_event_err("%s: Error %d for %d", __func__, ret,
gsi->prot_id);
}
-
- log_event_dbg("%s: xdci_suspend ret %d", __func__, ret);
-
done:
+ log_event_dbg("%s: xdci_suspend ret %d", __func__, ret);
return ret;
}
@@ -591,7 +610,6 @@ static void ipa_work_handler(struct work_struct *w)
struct device *dev;
struct device *gad_dev;
struct f_gsi *gsi;
- bool block_db;
event = read_event(d_port);
@@ -653,6 +671,29 @@ static void ipa_work_handler(struct work_struct *w)
__func__);
break;
}
+
+ /*
+ * Update desc and reconfigure USB GSI OUT and IN
+ * endpoint for RNDIS Adaptor enable case.
+ */
+ if (d_port->out_ep && !d_port->out_ep->desc &&
+ gsi->out_ep_desc_backup) {
+ d_port->out_ep->desc = gsi->out_ep_desc_backup;
+ d_port->out_ep->ep_intr_num = 1;
+ log_event_dbg("%s: OUT ep_op_config", __func__);
+ usb_gsi_ep_op(d_port->out_ep,
+ &d_port->out_request, GSI_EP_OP_CONFIG);
+ }
+
+ if (d_port->in_ep && !d_port->in_ep->desc &&
+ gsi->in_ep_desc_backup) {
+ d_port->in_ep->desc = gsi->in_ep_desc_backup;
+ d_port->in_ep->ep_intr_num = 2;
+ log_event_dbg("%s: IN ep_op_config", __func__);
+ usb_gsi_ep_op(d_port->in_ep,
+ &d_port->in_request, GSI_EP_OP_CONFIG);
+ }
+
ipa_connect_channels(d_port);
ipa_data_path_enable(d_port);
d_port->sm_state = STATE_CONNECTED;
@@ -714,15 +755,7 @@ static void ipa_work_handler(struct work_struct *w)
if (event == EVT_HOST_NRDY) {
log_event_dbg("%s: ST_CON_HOST_NRDY\n",
__func__);
- block_db = true;
- /* stop USB ringing doorbell to GSI(OUT_EP) */
- usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
- GSI_EP_OP_SET_CLR_BLOCK_DBL);
- gsi_rndis_ipa_reset_trigger(gsi);
- usb_gsi_ep_op(d_port->in_ep, NULL,
- GSI_EP_OP_ENDXFER);
- usb_gsi_ep_op(d_port->out_ep, NULL,
- GSI_EP_OP_ENDXFER);
+ ipa_disconnect_handler(d_port);
}
ipa_disconnect_work_handler(d_port);
@@ -1086,9 +1119,9 @@ static ssize_t gsi_ctrl_dev_write(struct file *fp, const char __user *buf,
list_add_tail(&cpkt->list, &c_port->cpkt_resp_q);
spin_unlock_irqrestore(&c_port->lock, flags);
- ret = gsi_ctrl_send_notification(gsi);
+ if (!gsi_ctrl_send_notification(gsi))
+ c_port->modem_to_host++;
- c_port->modem_to_host++;
log_event_dbg("Exit %zu", count);
return ret ? ret : count;
@@ -1345,26 +1378,6 @@ static void gsi_rndis_open(struct f_gsi *rndis)
rndis_signal_connect(rndis->params);
}
-static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis)
-{
- unsigned long flags;
-
- if (!rndis) {
- log_event_err("%s: gsi prot ctx is %pK", __func__, rndis);
- return;
- }
-
- spin_lock_irqsave(&rndis->d_port.lock, flags);
- if (!rndis) {
- log_event_err("%s: No RNDIS instance", __func__);
- spin_unlock_irqrestore(&rndis->d_port.lock, flags);
- return;
- }
-
- rndis->d_port.net_ready_trigger = false;
- spin_unlock_irqrestore(&rndis->d_port.lock, flags);
-}
-
void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param)
{
struct f_gsi *rndis = param->v;
@@ -1392,33 +1405,18 @@ static int queue_notification_request(struct f_gsi *gsi)
{
int ret;
unsigned long flags;
- struct usb_cdc_notification *event;
- struct gsi_ctrl_pkt *cpkt;
ret = usb_func_ep_queue(&gsi->function, gsi->c_port.notify,
gsi->c_port.notify_req, GFP_ATOMIC);
- if (ret == -ENOTSUPP || (ret < 0 && ret != -EAGAIN)) {
+ if (ret < 0) {
spin_lock_irqsave(&gsi->c_port.lock, flags);
gsi->c_port.notify_req_queued = false;
- /* check if device disconnected while we dropped lock */
- if (atomic_read(&gsi->connected) &&
- !list_empty(&gsi->c_port.cpkt_resp_q)) {
- cpkt = list_first_entry(&gsi->c_port.cpkt_resp_q,
- struct gsi_ctrl_pkt, list);
- list_del(&cpkt->list);
- log_event_err("%s: drop ctrl pkt of len %d error %d",
- __func__, cpkt->len, ret);
- gsi_ctrl_pkt_free(cpkt);
- }
- gsi->c_port.cpkt_drop_cnt++;
spin_unlock_irqrestore(&gsi->c_port.lock, flags);
- } else {
- ret = 0;
- event = gsi->c_port.notify_req->buf;
- log_event_dbg("%s: Queued Notify type %02x", __func__,
- event->bNotificationType);
}
+ log_event_dbg("%s: ret:%d req_queued:%d",
+ __func__, ret, gsi->c_port.notify_req_queued);
+
return ret;
}
@@ -2130,7 +2128,6 @@ static void gsi_suspend(struct usb_function *f)
{
bool block_db;
struct f_gsi *gsi = func_to_gsi(f);
- bool remote_wakeup_allowed;
/* Check if function is already suspended in gsi_func_suspend() */
if (f->func_is_suspended) {
@@ -2138,49 +2135,17 @@ static void gsi_suspend(struct usb_function *f)
return;
}
- if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
- remote_wakeup_allowed = f->func_wakeup_allowed;
- else
- remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
-
- log_event_info("%s: remote_wakeup_allowed %d",
- __func__, remote_wakeup_allowed);
-
- if (!remote_wakeup_allowed) {
- if (gsi->prot_id == IPA_USB_RNDIS)
- rndis_flow_control(gsi->params, true);
- /*
- * When remote wakeup is disabled, IPA is disconnected
- * because it cannot send new data until the USB bus is
- * resumed. Endpoint descriptors info is saved before it
- * gets reset by the BAM disconnect API. This lets us
- * restore this info when the USB bus is resumed.
- */
- if (gsi->d_port.in_ep)
- gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc;
- if (gsi->d_port.out_ep)
- gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc;
-
- ipa_disconnect_handler(&gsi->d_port);
-
- post_event(&gsi->d_port, EVT_DISCONNECTED);
- queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
- log_event_dbg("%s: Disconnecting", __func__);
- } else {
- block_db = true;
- usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db,
- GSI_EP_OP_SET_CLR_BLOCK_DBL);
- post_event(&gsi->d_port, EVT_SUSPEND);
- queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
- }
-
+ block_db = true;
+ usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db,
+ GSI_EP_OP_SET_CLR_BLOCK_DBL);
+ post_event(&gsi->d_port, EVT_SUSPEND);
+ queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
log_event_dbg("gsi suspended");
}
static void gsi_resume(struct usb_function *f)
{
struct f_gsi *gsi = func_to_gsi(f);
- bool remote_wakeup_allowed;
struct usb_composite_dev *cdev = f->config->cdev;
log_event_dbg("%s", __func__);
@@ -2193,49 +2158,24 @@ static void gsi_resume(struct usb_function *f)
f->func_is_suspended)
return;
- if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
- remote_wakeup_allowed = f->func_wakeup_allowed;
- else
- remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
-
if (gsi->c_port.notify && !gsi->c_port.notify->desc)
config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify);
/* Check any pending cpkt, and queue immediately on resume */
gsi_ctrl_send_notification(gsi);
- if (!remote_wakeup_allowed) {
-
- /* Configure EPs for GSI */
- if (gsi->d_port.out_ep) {
- gsi->d_port.out_ep->desc = gsi->out_ep_desc_backup;
- gsi->d_port.out_ep->ep_intr_num = 1;
- usb_gsi_ep_op(gsi->d_port.out_ep,
- &gsi->d_port.out_request, GSI_EP_OP_CONFIG);
- }
- gsi->d_port.in_ep->desc = gsi->in_ep_desc_backup;
- if (gsi->prot_id != IPA_USB_DIAG)
- gsi->d_port.in_ep->ep_intr_num = 2;
- else
- gsi->d_port.in_ep->ep_intr_num = 3;
-
- usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request,
- GSI_EP_OP_CONFIG);
- post_event(&gsi->d_port, EVT_CONNECT_IN_PROGRESS);
-
- /*
- * Linux host does not send RNDIS_MSG_INIT or non-zero
- * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume.
- * Trigger state machine explicitly on resume.
- */
- if (gsi->prot_id == IPA_USB_RNDIS)
- rndis_flow_control(gsi->params, false);
- } else
- post_event(&gsi->d_port, EVT_RESUMED);
+ /*
+ * Linux host does not send RNDIS_MSG_INIT or non-zero
+ * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume.
+ * Trigger state machine explicitly on resume.
+ */
+ if (gsi->prot_id == IPA_USB_RNDIS &&
+ !usb_gsi_remote_wakeup_allowed(f))
+ rndis_flow_control(gsi->params, false);
+ post_event(&gsi->d_port, EVT_RESUMED);
queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
-
log_event_dbg("%s: completed", __func__);
}
@@ -3132,7 +3072,7 @@ MODULE_DESCRIPTION("GSI function driver");
static int fgsi_init(void)
{
ipa_usb_wq = alloc_workqueue("k_ipa_usb",
- WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE, 1);
if (!ipa_usb_wq) {
log_event_err("Failed to create workqueue for IPA");
return -ENOMEM;
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 97d86b6ac69b..e309dec68a75 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2289,8 +2289,11 @@ reset:
}
common->running = 0;
- if (!new_fsg || rc)
+ if (!new_fsg || rc) {
+ /* allow usb LPM after eps are disabled */
+ usb_gadget_autopm_put_async(common->gadget);
return rc;
+ }
common->fsg = new_fsg;
fsg = common->fsg;
@@ -2333,6 +2336,9 @@ reset:
bh->outreq->complete = bulk_out_complete;
}
+ /* prevents usb LPM until thread runs to completion */
+ usb_gadget_autopm_get_noresume(common->gadget);
+
common->running = 1;
for (i = 0; i < ARRAY_SIZE(common->luns); ++i)
if (common->luns[i])
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index ea278781440c..935bd0778bfb 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -665,7 +665,7 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
rx_msg->type = PD_MSG_HDR_TYPE(header);
rx_msg->len = PD_MSG_HDR_COUNT(header);
- memcpy(&rx_msg->payload, buf, len);
+ memcpy(&rx_msg->payload, buf, min(len, sizeof(rx_msg->payload)));
spin_lock_irqsave(&pd->rx_lock, flags);
list_add_tail(&rx_msg->entry, &pd->rx_q);
diff --git a/drivers/video/fbdev/msm/Kconfig b/drivers/video/fbdev/msm/Kconfig
index ef5c96214c19..03ee89ad0d99 100644
--- a/drivers/video/fbdev/msm/Kconfig
+++ b/drivers/video/fbdev/msm/Kconfig
@@ -63,6 +63,7 @@ config FB_MSM_MDSS_WRITEBACK
config FB_MSM_MDSS_HDMI_PANEL
depends on FB_MSM_MDSS
+ select MSM_EXT_DISPLAY
bool "MDSS HDMI Tx Panel"
default n
---help---
@@ -98,6 +99,7 @@ config FB_MSM_MDSS_DSI_CTRL_STATUS
config FB_MSM_MDSS_DP_PANEL
depends on FB_MSM_MDSS
+ select MSM_EXT_DISPLAY
bool "MDSS DP Panel"
---help---
The MDSS DP Panel provides support for DP host controller driver
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile
index b905c0e855dd..e101b873f361 100644
--- a/drivers/video/fbdev/msm/Makefile
+++ b/drivers/video/fbdev/msm/Makefile
@@ -49,7 +49,6 @@ obj-$(CONFIG_FB_MSM_MDSS_DP_PANEL) += mdss_dp_aux.o
obj-$(CONFIG_FB_MSM_MDSS_DP_PANEL) += mdss_dp_hdcp2p2.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_io_util.o
-obj-$(CONFIG_FB_MSM_MDSS) += msm_ext_display.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_panel.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp2p2.o
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index bf4dc39f57ee..d9a4bd91f3eb 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -27,6 +27,7 @@
#include <linux/msm-bus.h>
#include <linux/file.h>
#include <linux/dma-direction.h>
+#include <soc/qcom/cx_ipeak.h>
#include "mdss_panel.h"
@@ -535,6 +536,7 @@ struct mdss_data_type {
u32 sec_cam_en;
u32 sec_session_cnt;
wait_queue_head_t secure_waitq;
+ struct cx_ipeak_client *mdss_cx_ipeak;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
index 3bcacf945761..5a677dfe7484 100644
--- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
+++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
@@ -449,7 +449,7 @@ static struct attribute *dp_hdcp2p2_fs_attrs[] = {
};
static struct attribute_group dp_hdcp2p2_fs_attr_group = {
- .name = "dp_hdcp2p2",
+ .name = "hdcp2p2",
.attrs = dp_hdcp2p2_fs_attrs,
};
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index f4c4c509410a..db27842eaccc 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -892,6 +892,12 @@ static ssize_t mdss_fb_get_persist_mode(struct device *dev,
return ret;
}
+static ssize_t mdss_fb_idle_pc_notify(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "idle power collapsed\n");
+}
+
static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
static DEVICE_ATTR(msm_fb_split, S_IRUGO | S_IWUSR, mdss_fb_show_split,
mdss_fb_store_split);
@@ -912,6 +918,8 @@ static DEVICE_ATTR(measured_fps, S_IRUGO | S_IWUSR | S_IWGRP,
mdss_fb_get_fps_info, NULL);
static DEVICE_ATTR(msm_fb_persist_mode, S_IRUGO | S_IWUSR,
mdss_fb_get_persist_mode, mdss_fb_change_persist_mode);
+static DEVICE_ATTR(idle_power_collapse, S_IRUGO, mdss_fb_idle_pc_notify, NULL);
+
static struct attribute *mdss_fb_attrs[] = {
&dev_attr_msm_fb_type.attr,
&dev_attr_msm_fb_split.attr,
@@ -925,6 +933,7 @@ static struct attribute *mdss_fb_attrs[] = {
&dev_attr_msm_fb_dfps_mode.attr,
&dev_attr_measured_fps.attr,
&dev_attr_msm_fb_persist_mode.attr,
+ &dev_attr_idle_power_collapse.attr,
NULL,
};
@@ -4470,7 +4479,7 @@ err:
static int __mdss_fb_copy_destscaler_data(struct fb_info *info,
struct mdp_layer_commit *commit)
{
- int i;
+ int i = 0;
int ret = 0;
u32 data_size;
struct mdp_destination_scaler_data __user *ds_data_user;
@@ -4543,6 +4552,7 @@ static int __mdss_fb_copy_destscaler_data(struct fb_info *info,
data_size);
if (ret) {
pr_err("scale data copy from user failed\n");
+ kfree(scale_data);
goto err;
}
}
@@ -4552,7 +4562,7 @@ static int __mdss_fb_copy_destscaler_data(struct fb_info *info,
err:
if (ds_data) {
- for (i = 0; i < commit->commit_v1.dest_scaler_cnt; i++) {
+ for (i--; i >= 0; i--) {
scale_data = to_user_ptr(ds_data[i].scale);
kfree(scale_data);
}
@@ -5176,3 +5186,16 @@ void mdss_fb_calc_fps(struct msm_fb_data_type *mfd)
mfd->fps_info.frame_count = 0;
}
}
+
+void mdss_fb_idle_pc(struct msm_fb_data_type *mfd)
+{
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+ if (mdss_fb_is_power_off(mfd))
+ return;
+
+ if ((mfd->panel_info->type == MIPI_CMD_PANEL) && mdp5_data) {
+ pr_debug("Notify fb%d idle power collapsed\n", mfd->index);
+ sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_power_collapse");
+ }
+}
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 111d7cfc7c9a..d64580a35775 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -468,4 +468,5 @@ void mdss_fb_report_panel_dead(struct msm_fb_data_type *mfd);
void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
struct fb_var_screeninfo *var);
void mdss_fb_calc_fps(struct msm_fb_data_type *mfd);
+void mdss_fb_idle_pc(struct msm_fb_data_type *mfd);
#endif /* MDSS_FB_H */
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index d8d11f21f3b2..3cadfa4ecef7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1173,6 +1173,31 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr)
return IRQ_HANDLED;
}
+static void mdss_mdp_cxipeak_vote(bool set_vote, unsigned long new_rate,
+ unsigned long prev_rate)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ int ret = 0;
+
+ if (!mdata->mdss_cx_ipeak)
+ return;
+
+ /* fmax threshold for mdp in sdm660 is max MDP clk */
+ if (set_vote) {
+ if ((new_rate >= mdata->max_mdp_clk_rate) &&
+ (prev_rate < mdata->max_mdp_clk_rate))
+ ret = cx_ipeak_update(mdata->mdss_cx_ipeak, true);
+ } else {
+ if ((new_rate < mdata->max_mdp_clk_rate) &&
+ (prev_rate >= mdata->max_mdp_clk_rate))
+ ret = cx_ipeak_update(mdata->mdss_cx_ipeak, false);
+ }
+ if (ret) {
+ pr_err("cxipeak api fail ret:%d set_vote :%d new_rate:%lu prev_rate:%lu\n",
+ ret, (int)set_vote, new_rate, prev_rate);
+ }
+}
+
static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
{
int ret = -ENODEV;
@@ -1234,7 +1259,7 @@ void mdss_mdp_set_clk_rate(unsigned long rate, bool locked)
struct mdss_data_type *mdata = mdss_res;
unsigned long clk_rate;
struct clk *clk = mdss_mdp_get_clk(MDSS_CLK_MDP_CORE);
- unsigned long min_clk_rate;
+ unsigned long min_clk_rate, curr_clk_rate;
min_clk_rate = max(rate, mdata->perf_tune.min_mdp_clk);
@@ -1246,15 +1271,20 @@ void mdss_mdp_set_clk_rate(unsigned long rate, bool locked)
clk_rate = clk_round_rate(clk, min_clk_rate);
else
clk_rate = mdata->max_mdp_clk_rate;
+
+ curr_clk_rate = clk_get_rate(clk);
if (IS_ERR_VALUE(clk_rate)) {
pr_err("unable to round rate err=%ld\n", clk_rate);
- } else if (clk_rate != clk_get_rate(clk)) {
-
+ } else if (clk_rate != curr_clk_rate) {
+ mdss_mdp_cxipeak_vote(true, clk_rate, curr_clk_rate);
mdata->mdp_clk_rate = clk_rate;
- if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate)))
+ if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate))) {
pr_err("clk_set_rate failed\n");
- else
+ } else {
+ mdss_mdp_cxipeak_vote(false, clk_rate,
+ curr_clk_rate);
pr_debug("mdp clk rate=%lu\n", clk_rate);
+ }
}
if (!locked)
mutex_unlock(&mdp_clk_lock);
@@ -1355,6 +1385,68 @@ static inline void __mdss_mdp_reg_access_clk_enable(
}
}
+/*
+ * __mdss_mdp_clk_control - Overall MDSS clock control for power on/off
+ */
+static void __mdss_mdp_clk_control(struct mdss_data_type *mdata, bool enable)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if (enable) {
+ pm_runtime_get_sync(&mdata->pdev->dev);
+
+ mdss_update_reg_bus_vote(mdata->reg_bus_clt,
+ VOTE_INDEX_LOW);
+
+ rc = mdss_iommu_ctrl(1);
+ if (IS_ERR_VALUE(rc))
+ pr_err("IOMMU attach failed\n");
+
+ /* Active+Sleep */
+ msm_bus_scale_client_update_context(mdata->bus_hdl,
+ false, mdata->curr_bw_uc_idx);
+
+ spin_lock_irqsave(&mdp_lock, flags);
+ mdata->clk_ena = enable;
+ spin_unlock_irqrestore(&mdp_lock, flags);
+
+ mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, 1);
+ mdss_mdp_clk_update(MDSS_CLK_AHB, 1);
+ mdss_mdp_clk_update(MDSS_CLK_AXI, 1);
+ mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 1);
+ mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, 1);
+ if (mdata->vsync_ena)
+ mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, 1);
+ } else {
+ spin_lock_irqsave(&mdp_lock, flags);
+ mdata->clk_ena = enable;
+ spin_unlock_irqrestore(&mdp_lock, flags);
+
+ if (mdata->vsync_ena)
+ mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, 0);
+
+ mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, 0);
+ mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 0);
+ mdss_mdp_clk_update(MDSS_CLK_AXI, 0);
+ mdss_mdp_clk_update(MDSS_CLK_AHB, 0);
+ mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, 0);
+
+ /* release iommu control */
+ mdss_iommu_ctrl(0);
+
+ /* Active-Only */
+ msm_bus_scale_client_update_context(mdata->bus_hdl,
+ true, mdata->ao_bw_uc_idx);
+
+ mdss_update_reg_bus_vote(mdata->reg_bus_clt,
+ VOTE_INDEX_DISABLE);
+
+ pm_runtime_mark_last_busy(&mdata->pdev->dev);
+ pm_runtime_put_autosuspend(&mdata->pdev->dev);
+ }
+}
+
int __mdss_mdp_vbif_halt(struct mdss_data_type *mdata, bool is_nrt)
{
int rc = 0;
@@ -1646,9 +1738,7 @@ void mdss_mdp_clk_ctrl(int enable)
{
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
static int mdp_clk_cnt;
- unsigned long flags;
int changed = 0;
- int rc = 0;
mutex_lock(&mdp_clk_lock);
if (enable) {
@@ -1672,49 +1762,8 @@ void mdss_mdp_clk_ctrl(int enable)
__builtin_return_address(0), current->group_leader->comm,
mdata->bus_ref_cnt, changed, enable);
- if (changed) {
- if (enable) {
- pm_runtime_get_sync(&mdata->pdev->dev);
-
- mdss_update_reg_bus_vote(mdata->reg_bus_clt,
- VOTE_INDEX_LOW);
-
- rc = mdss_iommu_ctrl(1);
- if (IS_ERR_VALUE(rc))
- pr_err("IOMMU attach failed\n");
-
- /* Active+Sleep */
- msm_bus_scale_client_update_context(mdata->bus_hdl,
- false, mdata->curr_bw_uc_idx);
- }
-
- spin_lock_irqsave(&mdp_lock, flags);
- mdata->clk_ena = enable;
- spin_unlock_irqrestore(&mdp_lock, flags);
-
- mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, enable);
- mdss_mdp_clk_update(MDSS_CLK_AHB, enable);
- mdss_mdp_clk_update(MDSS_CLK_AXI, enable);
- mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, enable);
- mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, enable);
- if (mdata->vsync_ena)
- mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
-
- if (!enable) {
- /* release iommu control */
- mdss_iommu_ctrl(0);
-
- /* Active-Only */
- msm_bus_scale_client_update_context(mdata->bus_hdl,
- true, mdata->ao_bw_uc_idx);
-
- mdss_update_reg_bus_vote(mdata->reg_bus_clt,
- VOTE_INDEX_DISABLE);
-
- pm_runtime_mark_last_busy(&mdata->pdev->dev);
- pm_runtime_put_autosuspend(&mdata->pdev->dev);
- }
- }
+ if (changed)
+ __mdss_mdp_clk_control(mdata, enable);
if (enable && changed)
mdss_mdp_idle_pc_restore();
@@ -4519,6 +4568,10 @@ static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
pr_debug("max pipe width not specified. Using default value\n");
mdata->max_pipe_width = DEFAULT_MDP_PIPE_WIDTH;
}
+
+ if (of_find_property(pdev->dev.of_node, "qcom,mdss-cx-ipeak", NULL))
+ mdata->mdss_cx_ipeak = cx_ipeak_register(pdev->dev.of_node,
+ "qcom,mdss-cx-ipeak");
return 0;
}
@@ -5092,6 +5145,22 @@ vreg_set_voltage_fail:
}
/**
+ * mdss_mdp_notify_idle_pc() - Notify fb driver of idle power collapse
+ * @mdata: MDP private data
+ *
+ * This function is called if there are active overlays.
+ */
+static void mdss_mdp_notify_idle_pc(struct mdss_data_type *mdata)
+{
+ int i;
+
+ for (i = 0; i < mdata->nctl; i++)
+ if ((mdata->ctl_off[i].ref_cnt) &&
+ !mdss_mdp_ctl_is_power_off(&mdata->ctl_off[i]))
+ mdss_fb_idle_pc(mdata->ctl_off[i].mfd);
+}
+
+/**
* mdss_mdp_footswitch_ctrl() - Disable/enable MDSS GDSC and CX/Batfet rails
* @mdata: MDP private data
* @on: 1 to turn on footswitch, 0 to turn off footswitch
@@ -5155,6 +5224,7 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
mdss_mdp_memory_retention_ctrl(MEM_RETAIN_ON,
PERIPH_RETAIN_OFF);
mdata->idle_pc = true;
+ mdss_mdp_notify_idle_pc(mdata);
pr_debug("idle pc. active overlays=%d\n",
active_cnt);
} else {
@@ -5487,6 +5557,8 @@ static int mdss_mdp_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
mdss_mdp_pp_term(&pdev->dev);
mdss_mdp_bus_scale_unregister(mdata);
+ if (mdata->mdss_cx_ipeak)
+ cx_ipeak_unregister(mdata->mdss_cx_ipeak);
mdss_debugfs_remove(mdata);
if (mdata->regulator_notif_register)
regulator_unregister_notifier(mdata->fs, &(mdata->gdsc_cb));
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 5e98de043e55..36a866685f21 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -1842,7 +1842,7 @@ int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe);
int mdss_mdp_smp_handoff(struct mdss_data_type *mdata);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
- u32 type, struct mdss_mdp_pipe *left_blend_pipe);
+ u32 off, u32 type, struct mdss_mdp_pipe *left_blend_pipe);
struct mdss_mdp_pipe *mdss_mdp_pipe_get(u32 ndx,
enum mdss_mdp_pipe_rect rect_num);
struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index e258f258aeca..7b0207de101a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -892,7 +892,7 @@ static u32 __calc_prefill_line_time_us(struct mdss_mdp_ctl *ctl)
static u32 __get_min_prefill_line_time_us(struct mdss_mdp_ctl *ctl)
{
- u32 vbp_min = 0;
+ u32 vbp_min = UINT_MAX;
int i;
struct mdss_data_type *mdata;
@@ -914,6 +914,9 @@ static u32 __get_min_prefill_line_time_us(struct mdss_mdp_ctl *ctl)
}
}
+ if (vbp_min == UINT_MAX)
+ vbp_min = 0;
+
return vbp_min;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 663d63092ebf..5173567a3420 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1896,7 +1896,6 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_format_params *fmt;
struct mdss_data_type *mdata = ctl->mdata;
struct dsc_desc *dsc = NULL;
- u32 hdmi_dp_core;
ctx->ctl = ctl;
ctx->intf_type = ctl->intf_type;
@@ -2033,10 +2032,19 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
mdp_video_write(ctx, MDSS_MDP_REG_INTF_PANEL_FORMAT, ctl->dst_format);
- hdmi_dp_core = (ctx->intf_type == MDSS_INTF_EDP) ? 1 : 0;
-
- writel_relaxed(hdmi_dp_core, mdata->mdp_base +
+ /* select HDMI or DP core usage */
+ switch (ctx->intf_type) {
+ case MDSS_INTF_EDP:
+ writel_relaxed(0x1, mdata->mdp_base +
+ MDSS_MDP_HDMI_DP_CORE_SELECT);
+ break;
+ case MDSS_INTF_HDMI:
+ writel_relaxed(0x0, mdata->mdp_base +
MDSS_MDP_HDMI_DP_CORE_SELECT);
+ break;
+ default:
+ break;
+ }
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index da08917d334b..5d80c80ebcef 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -609,6 +609,7 @@ int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
bool is_vig_needed = false;
u32 left_lm_w = left_lm_w_from_mfd(mfd);
u32 flags = 0;
+ u32 off = 0;
if (mdp5_data->ctl == NULL)
return -ENODEV;
@@ -692,18 +693,29 @@ int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
break;
case PIPE_TYPE_AUTO:
default:
- if (req->flags & MDP_OV_PIPE_FORCE_DMA)
+ if (req->flags & MDP_OV_PIPE_FORCE_DMA) {
pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
- else if (fmt->is_yuv ||
+ /*
+ * For paths using legacy API's for pipe
+ * allocation, use offset of 2 for allocating
+ * right pipe for pipe type DMA. This is
+ * because from SDM 3.x.x. onwards one DMA
+ * pipe has two instances for multirect.
+ */
+ off = (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT)
+ ? 2 : 0;
+ } else if (fmt->is_yuv ||
(req->flags & MDP_OV_PIPE_SHARE) ||
- is_vig_needed)
+ is_vig_needed) {
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
- else
+ } else {
pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
+ }
break;
}
- pipe = mdss_mdp_pipe_alloc(mixer, pipe_type, left_blend_pipe);
+ pipe = mdss_mdp_pipe_alloc(mixer, off,
+ pipe_type, left_blend_pipe);
/* RGB pipes can be used instead of DMA */
if (IS_ERR_OR_NULL(pipe) &&
@@ -712,7 +724,7 @@ int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
pr_debug("giving RGB pipe for fb%d. flags:0x%x\n",
mfd->index, req->flags);
pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
- pipe = mdss_mdp_pipe_alloc(mixer, pipe_type,
+ pipe = mdss_mdp_pipe_alloc(mixer, off, pipe_type,
left_blend_pipe);
}
@@ -723,7 +735,7 @@ int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
pr_debug("giving ViG pipe for fb%d. flags:0x%x\n",
mfd->index, req->flags);
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
- pipe = mdss_mdp_pipe_alloc(mixer, pipe_type,
+ pipe = mdss_mdp_pipe_alloc(mixer, off, pipe_type,
left_blend_pipe);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index 965a6533dfcb..8d7bd60318ad 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -1250,11 +1250,12 @@ cursor_done:
}
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
- u32 type, struct mdss_mdp_pipe *left_blend_pipe)
+ u32 off, u32 type, struct mdss_mdp_pipe *left_blend_pipe)
{
struct mdss_mdp_pipe *pipe;
+
mutex_lock(&mdss_mdp_sspp_lock);
- pipe = mdss_mdp_pipe_init(mixer, type, 0, left_blend_pipe);
+ pipe = mdss_mdp_pipe_init(mixer, type, off, left_blend_pipe);
mutex_unlock(&mdss_mdp_sspp_lock);
return pipe;
}
diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h
index 4378080da0d9..d9831d7cbb4e 100644
--- a/include/linux/msm_ext_display.h
+++ b/include/linux/msm_ext_display.h
@@ -109,6 +109,7 @@ struct msm_ext_disp_intf_ops {
* @get_audio_edid_blk: retrieve audio edid block
* @cable_status: cable connected/disconnected
* @get_intf_id: id of connected interface
+ * @acknowledge: acknowledge audio status
*/
struct msm_ext_disp_audio_codec_ops {
int (*audio_info_setup)(struct platform_device *pdev,
@@ -118,6 +119,7 @@ struct msm_ext_disp_audio_codec_ops {
int (*cable_status)(struct platform_device *pdev, u32 vote);
int (*get_intf_id)(struct platform_device *pdev);
void (*teardown_done)(struct platform_device *pdev);
+ int (*acknowledge)(struct platform_device *pdev, u32 ack);
};
/*
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 68cfe76e8652..5991485cdea4 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -3,11 +3,32 @@
#include <uapi/linux/msm_kgsl.h>
+#ifdef CONFIG_QCOM_KGSL
/* Limits mitigations APIs */
void *kgsl_pwr_limits_add(enum kgsl_deviceid id);
void kgsl_pwr_limits_del(void *limit);
int kgsl_pwr_limits_set_freq(void *limit, unsigned int freq);
void kgsl_pwr_limits_set_default(void *limit);
unsigned int kgsl_pwr_limits_get_freq(enum kgsl_deviceid id);
+#else
+static inline void *kgsl_pwr_limits_add(enum kgsl_deviceid id)
+{
+ return NULL;
+}
+
+static inline void kgsl_pwr_limits_del(void *limit) { }
+
+static inline int kgsl_pwr_limits_set_freq(void *limit, unsigned int freq)
+{
+ return -EINVAL;
+}
+
+static inline void kgsl_pwr_limits_set_default(void *limit) { }
+
+static inline unsigned int kgsl_pwr_limits_get_freq(enum kgsl_deviceid id)
+{
+ return 0;
+}
+#endif
#endif /* _MSM_KGSL_H */
diff --git a/include/linux/qpnp/qpnp-pbs.h b/include/linux/qpnp/qpnp-pbs.h
new file mode 100644
index 000000000000..39497ac4b552
--- /dev/null
+++ b/include/linux/qpnp/qpnp-pbs.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _QPNP_PBS_H
+#define _QPNP_PBS_H
+
+#ifdef CONFIG_QPNP_PBS
+int qpnp_pbs_trigger_event(struct device_node *dev_node, u8 bitmap);
+#else
+static inline int qpnp_pbs_trigger_event(struct device_node *dev_node,
+ u8 bitmap) {
+ return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
index e04ccf0b6e8b..e050bc758b3b 100644
--- a/include/uapi/sound/compress_offload.h
+++ b/include/uapi/sound/compress_offload.h
@@ -70,7 +70,7 @@ struct snd_compr_tstamp {
__u32 pcm_frames;
__u32 pcm_io_frames;
__u32 sampling_rate;
- uint64_t timestamp;
+ __u64 timestamp;
} __attribute__((packed, aligned(4)));
/**
@@ -128,8 +128,8 @@ struct snd_compr_codec_caps {
* @reserved: reserved for furture use
*/
struct snd_compr_audio_info {
- uint32_t frame_size;
- uint32_t reserved[15];
+ __u32 frame_size;
+ __u32 reserved[15];
} __attribute__((packed, aligned(4)));
/**
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 6addbde34545..676c3b0335ef 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -1094,7 +1094,6 @@ static int wsa881x_swr_startup(struct swr_device *swr_dev)
{
int ret = 0;
u8 devnum = 0;
- u8 retry = WSA881X_NUM_RETRY;
struct wsa881x_priv *wsa881x;
wsa881x = swr_get_dev_data(swr_dev);
@@ -1109,16 +1108,12 @@ static int wsa881x_swr_startup(struct swr_device *swr_dev)
* as per HW requirement.
*/
usleep_range(5000, 5010);
- while (swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum) &&
- retry--) {
- /* Retry after 1 msec delay */
- usleep_range(1000, 1100);
- }
- if (retry == 0) {
- dev_err(&swr_dev->dev,
+ ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
+ if (ret) {
+ dev_dbg(&swr_dev->dev,
"%s get devnum %d for dev addr %lx failed\n",
__func__, devnum, swr_dev->addr);
- return -EINVAL;
+ goto err;
}
swr_dev->dev_num = devnum;
diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c
index b2008d6da2a1..48f8e22e7faa 100644
--- a/sound/soc/msm/msm-cpe-lsm.c
+++ b/sound/soc/msm/msm-cpe-lsm.c
@@ -2152,7 +2152,8 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "LSM_REG_SND_MODEL_V2");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&snd_model, (void *)arg,
@@ -2285,7 +2286,8 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SNDRV_LSM_SET_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&det_params, (void *) arg,
@@ -2312,14 +2314,16 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (!arg) {
dev_err(rtd->dev,
"%s: %s: No Param data to set\n",
__func__, "SET_MODULE_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data, arg,
@@ -2327,7 +2331,8 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "p_data", sizeof(p_data));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (p_data.num_params > LSM_PARAMS_MAX) {
@@ -2335,7 +2340,8 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = p_data.num_params *
@@ -2346,12 +2352,15 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: Invalid size %zd\n",
__func__, "SET_MODULE_PARAMS", p_size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
params = kzalloc(p_size, GFP_KERNEL);
- if (!params)
- return -ENOMEM;
+ if (!params) {
+ err = -ENOMEM;
+ goto done;
+ }
if (copy_from_user(params, p_data.params,
p_data.data_size)) {
@@ -2359,7 +2368,8 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: copy_from_user failed, size = %d\n",
__func__, "params", p_data.data_size);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
err = msm_cpe_lsm_process_params(substream, &p_data, params);
@@ -2470,7 +2480,8 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "LSM_REG_SND_MODEL_V2_32");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
dev_dbg(rtd->dev,
@@ -2690,7 +2701,9 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SNDRV_LSM_SET_PARAMS32");
- return -EINVAL;
+
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&det_params32, arg,
@@ -2734,7 +2747,8 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS_32");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data_32, arg,
@@ -2743,7 +2757,8 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "SET_MODULE_PARAMS_32",
sizeof(p_data_32));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_data.params = compat_ptr(p_data_32.params);
@@ -2755,7 +2770,8 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (p_data.data_size !=
@@ -2764,21 +2780,25 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: Invalid size %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.data_size);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = sizeof(struct lsm_params_info_32) *
p_data.num_params;
params32 = kzalloc(p_size, GFP_KERNEL);
- if (!params32)
- return -ENOMEM;
+ if (!params32) {
+ err = -ENOMEM;
+ goto done;
+ }
p_size = sizeof(struct lsm_params_info) * p_data.num_params;
params = kzalloc(p_size, GFP_KERNEL);
if (!params) {
kfree(params32);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto done;
}
if (copy_from_user(params32, p_data.params,
@@ -2788,7 +2808,8 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
__func__, "params32", p_data.data_size);
kfree(params32);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_info_32 = (struct lsm_params_info_32 *) params32;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 46e2f7109b5a..26b7f3f26b26 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -434,8 +434,10 @@ static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
.playback = {
.stream_name = "HDMI Playback",
.aif_name = "HDMI",
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 2,
.channels_max = 8,
@@ -453,7 +455,9 @@ static struct snd_soc_dai_driver msm_dai_q6_display_port_rx_dai[] = {
.playback = {
.stream_name = "Display Port Playback",
.aif_name = "DISPLAY_PORT",
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE,
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 3fa14d0113ef..ec4380036047 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -86,6 +86,7 @@ struct lsm_priv {
atomic_t buf_count;
atomic_t read_abort;
wait_queue_head_t period_wait;
+ struct mutex lsm_api_lock;
int appl_cnt;
int dma_write;
};
@@ -954,10 +955,18 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
dev_dbg(rtd->dev, "%s: Get event status\n", __func__);
atomic_set(&prtd->event_wait_stop, 0);
+
+ /*
+ * Release the api lock before wait to allow
+ * other IOCTLs to be invoked while waiting
+ * for event
+ */
+ mutex_unlock(&prtd->lsm_api_lock);
rc = wait_event_freezable(prtd->event_wait,
(cmpxchg(&prtd->event_avail, 1, 0) ||
(xchg = atomic_cmpxchg(&prtd->event_wait_stop,
1, 0))));
+ mutex_lock(&prtd->lsm_api_lock);
dev_dbg(rtd->dev, "%s: wait_event_freezable %d event_wait_stop %d\n",
__func__, rc, xchg);
if (!rc && !xchg) {
@@ -1281,6 +1290,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
rtd = substream->private_data;
prtd = runtime->private_data;
+ mutex_lock(&prtd->lsm_api_lock);
+
switch (cmd) {
case SNDRV_LSM_EVENT_STATUS: {
struct snd_lsm_event_status *user = NULL, userarg32;
@@ -1288,7 +1299,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
__func__, "SNDRV_LSM_EVENT_STATUS");
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (userarg32.payload_size >
@@ -1296,7 +1308,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
__func__, userarg32.payload_size,
LISTEN_MAX_STATUS_PAYLOAD_SIZE);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
size = sizeof(*user) + userarg32.payload_size;
@@ -1305,7 +1318,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: Allocation failed event status size %d\n",
__func__, size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
} else {
cmd = SNDRV_LSM_EVENT_STATUS;
user->payload_size = userarg32.payload_size;
@@ -1421,7 +1435,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "REG_SND_MODEL_V2");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&snd_modelv232, arg,
@@ -1462,7 +1477,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SET_PARAMS_32");
- return -EINVAL;
+ err = -EINVAL;
}
if (copy_from_user(&det_params32, arg,
@@ -1505,7 +1520,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS_32");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data_32, arg,
@@ -1514,7 +1530,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "SET_MODULE_PARAMS_32",
sizeof(p_data_32));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_data.params = compat_ptr(p_data_32.params);
@@ -1526,7 +1543,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (p_data.data_size !=
@@ -1535,7 +1553,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: Invalid size %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.data_size);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = sizeof(struct lsm_params_info_32) *
@@ -1546,7 +1565,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: no memory for params32, size = %zd\n",
__func__, p_size);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto done;
}
p_size = sizeof(struct lsm_params_info) * p_data.num_params;
@@ -1556,7 +1576,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: no memory for params, size = %zd\n",
__func__, p_size);
kfree(params32);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto done;
}
if (copy_from_user(params32, p_data.params,
@@ -1566,7 +1587,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
__func__, "params32", p_data.data_size);
kfree(params32);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_info_32 = (struct lsm_params_info_32 *) params32;
@@ -1609,6 +1631,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
err = msm_lsm_ioctl_shared(substream, cmd, arg);
break;
}
+done:
+ mutex_unlock(&prtd->lsm_api_lock);
return err;
}
#else
@@ -1633,6 +1657,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
prtd = runtime->private_data;
rtd = substream->private_data;
+ mutex_lock(&prtd->lsm_api_lock);
switch (cmd) {
case SNDRV_LSM_REG_SND_MODEL_V2: {
struct snd_lsm_sound_model_v2 snd_model_v2;
@@ -1641,7 +1666,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "REG_SND_MODEL_V2");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&snd_model_v2, arg, sizeof(snd_model_v2))) {
@@ -1668,7 +1694,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SET_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
pr_debug("%s: SNDRV_LSM_SET_PARAMS\n", __func__);
@@ -1689,7 +1716,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: LSM_SET_PARAMS failed, err %d\n",
__func__, err);
- return err;
+
+ goto done;
}
case SNDRV_LSM_SET_MODULE_PARAMS: {
@@ -1701,7 +1729,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data, arg,
@@ -1709,7 +1738,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "p_data", sizeof(p_data));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (p_data.num_params > LSM_PARAMS_MAX) {
@@ -1717,7 +1747,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = p_data.num_params *
@@ -1728,7 +1759,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: Invalid size %zd\n",
__func__, "SET_MODULE_PARAMS", p_size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
params = kzalloc(p_size, GFP_KERNEL);
@@ -1736,7 +1768,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: no memory for params\n",
__func__);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto done;
}
if (copy_from_user(params, p_data.params,
@@ -1745,7 +1778,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: copy_from_user failed, size = %d\n",
__func__, "params", p_data.data_size);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
err = msm_lsm_process_params(substream, &p_data, params);
@@ -1765,7 +1799,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: err copyuser event_status\n",
__func__);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (userarg.payload_size >
@@ -1773,7 +1808,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
__func__, userarg.payload_size,
LISTEN_MAX_STATUS_PAYLOAD_SIZE);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
size = sizeof(struct snd_lsm_event_status) +
@@ -1783,7 +1819,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: Allocation failed event status size %d\n",
__func__, size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
} else {
user->payload_size = userarg.payload_size;
err = msm_lsm_ioctl_shared(substream, cmd, user);
@@ -1806,7 +1843,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
if (err)
dev_err(rtd->dev,
"%s: lsmevent failed %d", __func__, err);
- return err;
+ goto done;
}
case SNDRV_LSM_EVENT_STATUS_V3: {
@@ -1873,6 +1910,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
err = msm_lsm_ioctl_shared(substream, cmd, arg);
break;
}
+done:
+ mutex_unlock(&prtd->lsm_api_lock);
return err;
}
@@ -1889,6 +1928,7 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
__func__);
return -ENOMEM;
}
+ mutex_init(&prtd->lsm_api_lock);
spin_lock_init(&prtd->event_lock);
init_waitqueue_head(&prtd->event_wait);
init_waitqueue_head(&prtd->period_wait);
@@ -2048,6 +2088,7 @@ static int msm_lsm_close(struct snd_pcm_substream *substream)
kfree(prtd->event_status);
prtd->event_status = NULL;
spin_unlock_irqrestore(&prtd->event_lock, flags);
+ mutex_destroy(&prtd->lsm_api_lock);
kfree(prtd);
runtime->private_data = NULL;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 727bd6551018..3677a06c65ae 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -14701,6 +14701,7 @@ static void __exit msm_soc_routing_platform_exit(void)
{
msm_routing_delete_cal_data();
memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+ mutex_destroy(&routing_lock);
platform_driver_unregister(&msm_routing_pcm_driver);
}
module_exit(msm_soc_routing_platform_exit);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index c444a27c06e6..b2387a746f61 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -814,20 +814,25 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
if (prtd->mode == MODE_PCM) {
ret = copy_from_user(&buf_node->frame.voc_pkt,
buf, count);
+ if (ret) {
+ pr_err("%s: copy from user failed %d\n",
+ __func__, ret);
+ return -EFAULT;
+ }
buf_node->frame.pktlen = count;
} else {
ret = copy_from_user(&buf_node->frame,
buf, count);
+ if (ret) {
+ pr_err("%s: copy from user failed %d\n",
+ __func__, ret);
+ return -EFAULT;
+ }
if (buf_node->frame.pktlen >= count)
buf_node->frame.pktlen = count -
(sizeof(buf_node->frame.frm_hdr) +
sizeof(buf_node->frame.pktlen));
}
- if (ret) {
- pr_err("%s: copy from user failed %d\n",
- __func__, ret);
- return -EFAULT;
- }
spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
list_add_tail(&buf_node->list, &prtd->in_queue);
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c
index 3fe327ad0442..191db6c2fa9d 100644
--- a/sound/soc/msm/sdm660-external.c
+++ b/sound/soc/msm/sdm660-external.c
@@ -676,7 +676,7 @@ static int msm_ext_get_spk(struct snd_kcontrol *kcontrol,
static int msm_ext_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
pr_debug("%s()\n", __func__);
if (msm_ext_spk_control == ucontrol->value.integer.value[0])