diff options
152 files changed, 4717 insertions, 1041 deletions
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt index bb413af4b54d..c5c82a89f662 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cci.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt @@ -205,6 +205,31 @@ Optional properties: (in the same order). - cam_vaf-supply : should contain regulator from which AF voltage is supplied +* Qualcomm Technologies, Inc. MSM LASER LED + +Required properties: +- cell-index : should contain unique identifier to differentiate + between multiple laser led modules +- reg : should contain i2c slave address of the laser led and length of + data field which is 0x0 +- compatible : + - "qcom,laser-led" +- qcom,cci-master : should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +Optional properties: +- qcom,cam-vreg-name : should contain names of all regulators needed by this + laser led +- qcom,cam-vreg-min-voltage : should contain minimum voltage level in microvolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-max-voltage : should contain maximum voltage level in microvolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-op-mode : should contain the maximum current in microamps + required from the regulators mentioned in the qcom,cam-vreg-name property + (in the same order). + * Qualcomm Technologies, Inc. MSM OIS Required properties: @@ -277,6 +302,13 @@ Example: qcom,cam-vreg-op-mode = <100000>; }; + laserled0: qcom,laserled@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,laser-led"; + qcom,cci-master = <1>; + }; + qcom,camera@0 { cell-index = <0>; compatible = "qcom,camera"; diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt index acc850773210..c1a8d1bd697d 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt @@ -11,13 +11,24 @@ Required properties: - compatible: "qcom,wcn3990-wifi"; - reg: Memory regions defined as starting address and size - reg-names: Names of the memory regions defined in reg entry + - clocks: List of clock phandles + - clock-names: List of clock names corresponding to the "clocks" property - interrupts: Copy engine interrupt table +Optional properties: + - <supply-name>-supply: phandle to the regulator device tree node + optional "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. Example: msm_ath10k_wlan: qcom,msm_ath10k_wlan@18800000 { compatible = "qcom,wcn3990-wifi"; reg = <0x18800000 0x800000>; reg-names = "membase"; + clocks = <&clock_gcc clk_aggre2_noc_clk>; + clock-names = "smmu_aggre2_noc_clk"; interrupts = <0 130 0 /* CE0 */ >, <0 131 0 /* CE1 */ >, @@ -31,4 +42,10 @@ Example: <0 139 0 /* CE9 */ >, <0 140 0 /* CE10 */ >, <0 141 0 /* CE11 */ >; + 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>; }; diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index 47fad8aa4a1a..54792335e67e 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -64,6 +64,8 @@ Optional properties : device provides both "USB" and "USB-HOST" events. - qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs, which is used as a vote by driver to get max performance in perf mode. +- qcom,no-wakeup-src-in-hostmode: If present then driver doesn't use wakeup_source APIs + in host mode. This allows PM suspend to happen irrespective of runtimePM state of host. Sub nodes: - Sub node for "DWC3- USB3 controller". diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 588393412271..22b546e0f845 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1776,7 +1776,7 @@ source "mm/Kconfig" choice prompt "Virtual Memory Reclaim" - default NO_VM_RECLAIM + default ENABLE_VMALLOC_SAVING help Select the method of reclaiming virtual memory diff --git a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi index c156e91dfcf9..fa21dd7995eb 100644 --- a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi +++ b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi @@ -88,7 +88,7 @@ }; }; - smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { + smb1381_charger: qcom,smb1381-charger@1000 { compatible = "qcom,smb138x-parallel-slave"; qcom,pmic-revid = <&smb138x_revid>; reg = <0x1000 0x700>; @@ -129,7 +129,7 @@ }; }; -&smb138x_parallel_slave { +&smb1381_charger { smb138x_vbus: qcom,smb138x-vbus { status = "disabled"; regulator-name = "smb138x-vbus"; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index 1283cdddc2db..c1728da49d5e 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -1381,6 +1381,7 @@ &usb2s { status = "ok"; + qcom,no-wakeup-src-in-hostmode; }; &usb3 { @@ -1388,6 +1389,7 @@ vbus_dwc3-supply = <&usb_otg_switch>; vdda33-supply = <&pm8994_l24>; vdda18-supply = <&pm8994_l12>; + qcom,no-wakeup-src-in-hostmode; }; &blsp1_uart2 { @@ -1557,5 +1559,9 @@ reg = <0 0xb3fff000 0 0x800000>; label = "early_camera_mem"; }; + early_audio_mem: early_audio_mem@0xb5fff000 { + reg = <0x0 0xb5fff000 0x0 0x3FFFFC>; + label = "early_audio_mem"; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index c3b986786034..db822dae6e7f 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -1331,6 +1331,10 @@ reg = <0 0xb3fff000 0 0x800000>; label = "early_camera_mem"; }; + early_audio_mem: early_audio_mem@0xb5fff000 { + reg = <0x0 0xb5fff000 0x0 0x3FFFFC>; + label = "early_audio_mem"; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-sde.dtsi b/arch/arm/boot/dts/qcom/msm8996-sde.dtsi index b0688668e667..11c45606f6c2 100644 --- a/arch/arm/boot/dts/qcom/msm8996-sde.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-sde.dtsi @@ -183,7 +183,7 @@ }; smmu_kms_unsec: qcom,smmu_kms_unsec_cb { - compatible = "qcom,smmu_kms_unsec"; + compatible = "qcom,smmu_sde_unsec"; iommus = <&mdp_smmu 0>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-v3.dtsi b/arch/arm/boot/dts/qcom/msm8996-v3.dtsi index 7e5fa8a495c9..8e46ce5277b3 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-v3.dtsi @@ -259,6 +259,71 @@ }; }; + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <2>; + + qcom,initial-pwrlevel = <4>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <560000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <11>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <401800000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <315000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <214000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <133000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <2>; + qcom,bus-max = <4>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <27000000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + + }; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts index f5c33063643d..0126081e4b03 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts @@ -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 @@ -42,9 +42,6 @@ i2c@75b6000 { /* BLSP8 */ /* ADV7533 HDMI Bridge Chip removed on ADP Lite */ - adv7533@3d { - status = "disabled"; - }; adv7533@39 { status = "disabled"; }; @@ -59,6 +56,14 @@ }; }; +&dsi_adv_7533_2 { + /delete-property/ qcom,dsi-display-active; +}; + +&sde_kms { + connectors = <&sde_hdmi_tx &sde_hdmi &dsi_adv_7533_1>; +}; + &pil_modem { pinctrl-names = "default"; pinctrl-0 = <&modem_mux>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto.dtsi b/arch/arm/boot/dts/qcom/msm8996pro-auto.dtsi index 15295639e361..f0fade10633e 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto.dtsi @@ -466,5 +466,11 @@ qcom,gpu-pwrlevels-0 { qcom,initial-pwrlevel = <1>; }; + + qcom,gpu-pwrlevels-2 { + qcom,initial-pwrlevel = <2>; + + }; + }; }; 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 2095b4e07069..86b68b2440a9 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi @@ -54,6 +54,13 @@ qcom,cam-vreg-op-mode = <0>; }; + laserled0: qcom,laserled@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,laser-led"; + qcom,cci-master = <1>; + }; + actuator1: qcom,actuator@1 { cell-index = <1>; reg = <0x1>; @@ -322,6 +329,7 @@ qcom,eeprom-src = <&eeprom2>; qcom,led-flash-src = <&led_flash1>; qcom,actuator-src = <&actuator1>; + qcom,laserled-src = <&laserled0>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pm8998_l22>; cam_vdig-supply = <&pm8998_s3>; diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index ed1259918620..1abb28897fbd 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -582,7 +582,7 @@ config { pins = "gpio37"; drive-strength = <2>; - bias-pull-down; + bias-pull-up; }; }; @@ -595,7 +595,7 @@ config { pins = "gpio37"; drive-strength = <2>; - bias-disable; + bias-pull-up; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index eafa6b841c17..76e3282d327e 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -3106,6 +3106,8 @@ compatible = "qcom,wcn3990-wifi"; reg = <0x18800000 0x800000>; reg-names = "membase"; + clocks = <&clock_gcc clk_rf_clk2_pin>; + clock-names = "cxo_ref_clk_pin"; interrupts = <0 413 0 /* CE0 */ >, <0 414 0 /* CE1 */ >, @@ -3119,6 +3121,12 @@ <0 423 0 /* CE9 */ >, <0 424 0 /* CE10 */ >, <0 425 0 /* CE11 */ >; + 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@18800000 { diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts index f4a9592bf4ff..ccc1be75f39b 100644 --- a/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts @@ -98,7 +98,7 @@ }; }; - smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { + smb1381_charger: qcom,smb1381-charger@1000 { compatible = "qcom,smb138x-parallel-slave"; qcom,pmic-revid = <&smb138x_revid>; reg = <0x1000 0x700>; diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts index 5f44b4c32c98..0d7b6c0341b5 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts @@ -98,7 +98,7 @@ }; }; - smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { + smb1381_charger: qcom,smb1381-charger@1000 { compatible = "qcom,smb138x-parallel-slave"; qcom,pmic-revid = <&smb138x_revid>; reg = <0x1000 0x700>; diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index af3c5d1b51da..384e24d221c4 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -92,7 +92,7 @@ }; }; - smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { + smb1381_charger: qcom,smb1381-charger@1000 { compatible = "qcom,smb138x-parallel-slave"; qcom,pmic-revid = <&smb138x_revid>; reg = <0x1000 0x700>; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index c436ce643091..c626698ffd51 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -1606,6 +1606,7 @@ qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-adsp"; qcom,fastrpc-glink; + qcom,fastrpc-vmid-heap-shared; qcom,msm_fastrpc_compute_cb1 { compatible = "qcom,msm-fastrpc-compute-cb"; diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 7e3bf18b06f7..e55ebfc79ddb 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -277,10 +277,10 @@ CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CNSS_CRYPTO=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m -CONFIG_CNSS=y -CONFIG_CNSS_ASYNC=y CONFIG_CLD_LL_CORE=y CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS2=y +CONFIG_CNSS2_DEBUG=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y CONFIG_KEYBOARD_GPIO=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index 92fc522c11ed..8f8e696f8866 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -1,4 +1,5 @@ # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_FHANDLE=y CONFIG_AUDIT=y # CONFIG_AUDITSYSCALL is not set CONFIG_NO_HZ=y @@ -232,6 +233,8 @@ CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y @@ -278,10 +281,10 @@ CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CNSS_CRYPTO=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m -CONFIG_CNSS=y -CONFIG_CNSS_ASYNC=y CONFIG_CLD_LL_CORE=y CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS2=y +CONFIG_CNSS2_DEBUG=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y CONFIG_KEYBOARD_GPIO=y @@ -311,7 +314,6 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m -CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MUX=y CONFIG_I2C_QUP=y @@ -348,7 +350,6 @@ CONFIG_THERMAL_TSENS8974=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_MFD_SPMI_PMIC=y CONFIG_WCD9335_CODEC=y -CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y CONFIG_REGULATOR_MAX20010=y @@ -380,15 +381,11 @@ CONFIG_MSM_AIS_CAMERA_SENSOR=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_ADV7481=y CONFIG_QCOM_KGSL=y +CONFIG_DRM=y CONFIG_MSM_BA_V4L2=y -CONFIG_FB=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_XLOG_DEBUG=y +CONFIG_MSM_DBA=y +CONFIG_MSM_DBA_ADV7533=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_GENERIC=m CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set @@ -472,7 +469,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ANDROID_TIMED_GPIO=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_SW_SYNC_USER=y +CONFIG_SYNC=y CONFIG_ION=y CONFIG_ION_MSM=y CONFIG_QPNP_REVID=y @@ -521,7 +518,6 @@ CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y -CONFIG_QCOM_SCM=y CONFIG_QCOM_SCM_XPU=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y @@ -576,7 +572,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_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y @@ -593,6 +588,7 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_OBJECTS_WORK=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index ea3e453fdd14..2ac2abe8a494 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -157,7 +157,8 @@ static int save_trace(struct stackframe *frame, void *d) return trace->nr_entries >= trace->max_entries; } -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +static noinline void __save_stack_trace(struct task_struct *tsk, + struct stack_trace *trace, unsigned int nosched) { struct stack_trace_data data; struct stackframe frame; @@ -167,17 +168,18 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) data.trace = trace; data.skip = trace->skip; + data.no_sched_functions = nosched; if (tsk != current) { - data.no_sched_functions = 1; frame.fp = thread_saved_fp(tsk); frame.sp = thread_saved_sp(tsk); frame.pc = thread_saved_pc(tsk); } else { - data.no_sched_functions = 0; + /* We don't want this function nor the caller */ + data.skip += 2; frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_stack_pointer; - frame.pc = (unsigned long)save_stack_trace_tsk; + frame.pc = (unsigned long)__save_stack_trace; } #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = tsk->curr_ret_stack; @@ -191,9 +193,15 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) } EXPORT_SYMBOL(save_stack_trace_tsk); +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + __save_stack_trace(tsk, trace, 1); +} + void save_stack_trace(struct stack_trace *trace) { - save_stack_trace_tsk(current, trace); + __save_stack_trace(current, trace, 0); } + EXPORT_SYMBOL_GPL(save_stack_trace); #endif diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 13598d807de0..34f45abe0181 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3253,6 +3253,7 @@ static void binder_transaction(struct binder_proc *proc, err_dead_proc_or_thread: return_error = BR_DEAD_REPLY; return_error_line = __LINE__; + binder_dequeue_work(proc, tcomplete); err_translate_failed: err_bad_object_type: err_bad_offset: diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index e206d9db4d7d..e1e86f6e74dc 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -555,6 +555,11 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } if (!diag_apps_responds()) return 0; @@ -656,7 +661,11 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } - + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } if (!diag_apps_responds()) return 0; @@ -669,6 +678,12 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, rsp.status = MSG_STATUS_FAIL; rsp.padding = 0; mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if ((req->ssid_first < mask->ssid_first) || (req->ssid_first > mask->ssid_last_tools)) { @@ -714,11 +729,23 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_msg_build_mask_t *)src_buf; mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if (i < (driver->msg_mask_tbl_count - 1)) { mask_next = mask; @@ -831,6 +858,11 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_msg_config_rsp_t *)src_buf; @@ -838,6 +870,13 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -931,7 +970,11 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } - + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_event_mask_config_t *)src_buf; mask_len = EVENT_COUNT_TO_BYTES(req->num_bits); if (mask_len <= 0 || mask_len > event_mask.mask_len) { @@ -989,6 +1032,11 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } toggle = *(src_buf + 1); mutex_lock(&mask_info->lock); @@ -1046,6 +1094,11 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } if (!diag_apps_responds()) return 0; @@ -1065,6 +1118,11 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, write_len += rsp_header_len; log_item = (struct diag_log_mask_t *)mask_info->ptr; + if (!log_item->ptr) { + pr_err("diag: Invalid input in %s, mask: %pK\n", + __func__, log_item); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) { if (log_item->equip_id != req->equip_id) continue; @@ -1172,11 +1230,20 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_log_config_req_t *)src_buf; read_len += req_header_len; mask = (struct diag_log_mask_t *)mask_info->ptr; - + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + return -EINVAL; + } if (req->equip_id >= MAX_EQUIP_ID) { pr_err("diag: In %s, Invalid logging mask request, equip_id: %d\n", __func__, req->equip_id); @@ -1294,9 +1361,17 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } - + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } mask = (struct diag_log_mask_t *)mask_info->ptr; - + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { mutex_lock(&mask->lock); memset(mask->ptr, 0, mask->range); @@ -1562,7 +1637,7 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len, static void __diag_mask_exit(struct diag_mask_info *mask_info) { - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; mutex_lock(&mask_info->lock); @@ -1619,11 +1694,17 @@ void diag_log_mask_free(struct diag_mask_info *mask_info) int i; struct diag_log_mask_t *mask = NULL; - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; mutex_lock(&mask_info->lock); mask = (struct diag_log_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&mask_info->lock); + return; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; @@ -1698,11 +1779,18 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) int i; struct diag_msg_mask_t *mask = NULL; - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; @@ -1869,6 +1957,11 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + if (!mask_info->ptr || !mask_info->update_buf) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK, mask_info->update_buf: %pK\n", + __func__, mask_info->ptr, mask_info->update_buf); + return -EINVAL; + } mutex_lock(&driver->diag_maskclear_mutex); if (driver->mask_clear) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -1881,6 +1974,13 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)(mask_info->ptr); + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { ptr = mask_info->update_buf; len = 0; @@ -1941,8 +2041,20 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + if (!mask_info->ptr || !mask_info->update_buf) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK, mask_info->update_buf: %pK\n", + __func__, mask_info->ptr, mask_info->update_buf); + return -EINVAL; + } + mutex_lock(&mask_info->lock); mask = (struct diag_log_mask_t *)(mask_info->ptr); + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { ptr = mask_info->update_buf; len = 0; diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h index 0120d71f0daf..7aa8b0d6c051 100644 --- a/drivers/clk/msm/mdss/mdss-pll.h +++ b/drivers/clk/msm/mdss/mdss-pll.h @@ -70,6 +70,7 @@ struct dfps_info { struct dfps_panel_info panel_dfps; struct dfps_codes_info codes_dfps[DFPS_MAX_NUM_OF_FRAME_RATES]; void *dfps_fb_base; + uint32_t chip_serial; }; struct mdss_pll_resources { diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index c085e173232b..049478fd9bcb 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -406,11 +406,9 @@ static const unsigned int a3xx_registers[] = { #ifdef CONFIG_DEBUG_FS static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) { - gpu->funcs->pm_resume(gpu); seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A3XX_RBBM_STATUS)); adreno_show(gpu, m); - gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 624c2a87d593..45c83fbe20e1 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -443,13 +443,9 @@ static const unsigned int a4xx_registers[] = { #ifdef CONFIG_DEBUG_FS static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m) { - gpu->funcs->pm_resume(gpu); - seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A4XX_RBBM_STATUS)); - adreno_show(gpu, m); - gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a5xx_counters.c b/drivers/gpu/drm/msm/adreno/a5xx_counters.c index bc442039c308..1d5e61daca47 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_counters.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_counters.c @@ -86,15 +86,15 @@ static int a5xx_counter_get(struct msm_gpu *gpu, spin_unlock(&group->lock); - if (group->funcs.enable) - group->funcs.enable(gpu, group, empty); + if (pm_runtime_active(&gpu->pdev->dev) && group->funcs.enable) + group->funcs.enable(gpu, group, empty, false); return empty; } /* The majority of the non-fixed counter selects can be programmed by the CPU */ static void a5xx_counter_enable_cpu(struct msm_gpu *gpu, - struct adreno_counter_group *group, int counterid) + struct adreno_counter_group *group, int counterid, bool restore) { struct adreno_counter *counter = &group->counters[counterid]; @@ -102,15 +102,36 @@ static void a5xx_counter_enable_cpu(struct msm_gpu *gpu, } static void a5xx_counter_enable_pm4(struct msm_gpu *gpu, - struct adreno_counter_group *group, int counterid) + struct adreno_counter_group *group, int counterid, bool restore) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); struct msm_ringbuffer *ring = gpu->rb[0]; struct adreno_counter *counter = &group->counters[counterid]; + /* + * If we are restoring the counters after a power cycle we can safely + * use AHB to enable the counters because we know SP/TP power collapse + * isn't active + */ + if (restore) { + a5xx_counter_enable_cpu(gpu, group, counterid, true); + return; + } + mutex_lock(&gpu->dev->struct_mutex); + /* + * If HW init hasn't run yet we can use the CPU to program the counter + * (and indeed we must because we can't submit commands to the + * GPU if it isn't initalized) + */ + if (gpu->needs_hw_init) { + a5xx_counter_enable_cpu(gpu, group, counterid, true); + mutex_unlock(&gpu->dev->struct_mutex); + return; + } + /* Turn off preemption for the duration of this command */ OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); OUT_RING(ring, 0x02); @@ -168,7 +189,7 @@ static void a5xx_counter_enable_pm4(struct msm_gpu *gpu, * registers */ static void a5xx_counter_enable_gpmu(struct msm_gpu *gpu, - struct adreno_counter_group *group, int counterid) + struct adreno_counter_group *group, int counterid, bool restore) { struct adreno_counter *counter = &group->counters[counterid]; u32 reg; @@ -192,7 +213,7 @@ static void a5xx_counter_enable_gpmu(struct msm_gpu *gpu, /* VBIF counters are selectable but have their own programming process */ static void a5xx_counter_enable_vbif(struct msm_gpu *gpu, - struct adreno_counter_group *group, int counterid) + struct adreno_counter_group *group, int counterid, bool restore) { struct adreno_counter *counter = &group->counters[counterid]; @@ -208,7 +229,7 @@ static void a5xx_counter_enable_vbif(struct msm_gpu *gpu, * use */ static void a5xx_counter_enable_vbif_power(struct msm_gpu *gpu, - struct adreno_counter_group *group, int counterid) + struct adreno_counter_group *group, int counterid, bool restore) { gpu_write(gpu, REG_A5XX_VBIF_PERF_PWR_CNT_CLR(counterid), 1); gpu_write(gpu, REG_A5XX_VBIF_PERF_PWR_CNT_CLR(counterid), 0); @@ -217,7 +238,7 @@ static void a5xx_counter_enable_vbif_power(struct msm_gpu *gpu, /* GPMU always on counter needs to be enabled before use */ static void a5xx_counter_enable_alwayson_power(struct msm_gpu *gpu, - struct adreno_counter_group *group, int counterid) + struct adreno_counter_group *group, int counterid, bool restore) { gpu_write(gpu, REG_A5XX_GPMU_ALWAYS_ON_COUNTER_RESET, 1); } @@ -228,6 +249,10 @@ static u64 a5xx_counter_read(struct msm_gpu *gpu, if (counterid >= group->nr_counters) return 0; + /* If the power is off, return the shadow value */ + if (!pm_runtime_active(&gpu->pdev->dev)) + return group->counters[counterid].value; + return gpu_read64(gpu, group->counters[counterid].lo, group->counters[counterid].hi); } @@ -252,6 +277,77 @@ static void a5xx_counter_put(struct msm_gpu *gpu, spin_unlock(&group->lock); } +static void a5xx_counter_group_enable(struct msm_gpu *gpu, + struct adreno_counter_group *group, bool restore) +{ + int i; + + if (!group || !group->funcs.enable) + return; + + spin_lock(&group->lock); + + for (i = 0; i < group->nr_counters; i++) { + if (!group->counters[i].refcount) + continue; + + group->funcs.enable(gpu, group, i, restore); + } + spin_unlock(&group->lock); +} + +static void a5xx_counter_restore(struct msm_gpu *gpu, + struct adreno_counter_group *group) +{ + int i; + + spin_lock(&group->lock); + for (i = 0; i < group->nr_counters; i++) { + struct adreno_counter *counter = &group->counters[i]; + uint32_t bit, offset = counter->load_bit; + + /* Don't load if the counter isn't active or can't be loaded */ + if (!counter->refcount) + continue; + + /* + * Each counter has a specific bit in one of four load command + * registers. Figure out which register / relative bit to use + * for the counter + */ + bit = do_div(offset, 32); + + /* Write the counter value */ + gpu_write64(gpu, REG_A5XX_RBBM_PERFCTR_LOAD_VALUE_LO, + REG_A5XX_RBBM_PERFCTR_LOAD_VALUE_HI, + counter->value); + + /* + * Write the load bit to load the counter - the command register + * will get reset to 0 after the operation completes + */ + gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_LOAD_CMD0 + offset, + (1 << bit)); + } + spin_unlock(&group->lock); +} + +static void a5xx_counter_save(struct msm_gpu *gpu, + struct adreno_counter_group *group) +{ + int i; + + spin_lock(&group->lock); + for (i = 0; i < group->nr_counters; i++) { + struct adreno_counter *counter = &group->counters[i]; + + if (counter->refcount > 0) + counter->value = gpu_read64(gpu, counter->lo, + counter->hi); + } + spin_unlock(&group->lock); +} + static struct adreno_counter a5xx_counters_alwayson[1] = { { REG_A5XX_RBBM_ALWAYSON_COUNTER_LO, REG_A5XX_RBBM_ALWAYSON_COUNTER_HI }, @@ -270,242 +366,242 @@ static struct adreno_counter a5xx_counters_ccu[] = { static struct adreno_counter a5xx_counters_cmp[] = { { REG_A5XX_RBBM_PERFCTR_CMP_0_LO, REG_A5XX_RBBM_PERFCTR_CMP_0_HI, - REG_A5XX_RB_PERFCTR_CMP_SEL_0 }, + REG_A5XX_RB_PERFCTR_CMP_SEL_0, 94 }, { REG_A5XX_RBBM_PERFCTR_CMP_1_LO, REG_A5XX_RBBM_PERFCTR_CMP_1_HI, - REG_A5XX_RB_PERFCTR_CMP_SEL_1 }, + REG_A5XX_RB_PERFCTR_CMP_SEL_1, 95 }, { REG_A5XX_RBBM_PERFCTR_CMP_2_LO, REG_A5XX_RBBM_PERFCTR_CMP_2_HI, - REG_A5XX_RB_PERFCTR_CMP_SEL_2 }, + REG_A5XX_RB_PERFCTR_CMP_SEL_2, 96 }, { REG_A5XX_RBBM_PERFCTR_CMP_3_LO, REG_A5XX_RBBM_PERFCTR_CMP_3_HI, - REG_A5XX_RB_PERFCTR_CMP_SEL_3 }, + REG_A5XX_RB_PERFCTR_CMP_SEL_3, 97 }, }; static struct adreno_counter a5xx_counters_cp[] = { { REG_A5XX_RBBM_PERFCTR_CP_0_LO, REG_A5XX_RBBM_PERFCTR_CP_0_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_0 }, + REG_A5XX_CP_PERFCTR_CP_SEL_0, 0 }, { REG_A5XX_RBBM_PERFCTR_CP_1_LO, REG_A5XX_RBBM_PERFCTR_CP_1_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_1 }, + REG_A5XX_CP_PERFCTR_CP_SEL_1, 1}, { REG_A5XX_RBBM_PERFCTR_CP_2_LO, REG_A5XX_RBBM_PERFCTR_CP_2_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_2 }, + REG_A5XX_CP_PERFCTR_CP_SEL_2, 2 }, { REG_A5XX_RBBM_PERFCTR_CP_3_LO, REG_A5XX_RBBM_PERFCTR_CP_3_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_3 }, + REG_A5XX_CP_PERFCTR_CP_SEL_3, 3 }, { REG_A5XX_RBBM_PERFCTR_CP_4_LO, REG_A5XX_RBBM_PERFCTR_CP_4_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_4 }, + REG_A5XX_CP_PERFCTR_CP_SEL_4, 4 }, { REG_A5XX_RBBM_PERFCTR_CP_5_LO, REG_A5XX_RBBM_PERFCTR_CP_5_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_5 }, + REG_A5XX_CP_PERFCTR_CP_SEL_5, 5 }, { REG_A5XX_RBBM_PERFCTR_CP_6_LO, REG_A5XX_RBBM_PERFCTR_CP_6_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_6 }, + REG_A5XX_CP_PERFCTR_CP_SEL_6, 6 }, { REG_A5XX_RBBM_PERFCTR_CP_7_LO, REG_A5XX_RBBM_PERFCTR_CP_7_HI, - REG_A5XX_CP_PERFCTR_CP_SEL_7 }, + REG_A5XX_CP_PERFCTR_CP_SEL_7, 7 }, }; static struct adreno_counter a5xx_counters_hlsq[] = { { REG_A5XX_RBBM_PERFCTR_HLSQ_0_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_0_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_0 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_0, 28 }, { REG_A5XX_RBBM_PERFCTR_HLSQ_1_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_1_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_1 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_1, 29 }, { REG_A5XX_RBBM_PERFCTR_HLSQ_2_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_2_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_2 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_2, 30 }, { REG_A5XX_RBBM_PERFCTR_HLSQ_3_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_3_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_3 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_3, 31 }, { REG_A5XX_RBBM_PERFCTR_HLSQ_4_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_4_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_4 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_4, 32 }, { REG_A5XX_RBBM_PERFCTR_HLSQ_5_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_5_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_5 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_5, 33 }, { REG_A5XX_RBBM_PERFCTR_HLSQ_6_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_6_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_6 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_6, 34 }, { REG_A5XX_RBBM_PERFCTR_HLSQ_7_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_7_HI, - REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_7 }, + REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_7, 35 }, }; static struct adreno_counter a5xx_counters_lrz[] = { { REG_A5XX_RBBM_PERFCTR_LRZ_0_LO, REG_A5XX_RBBM_PERFCTR_LRZ_0_HI, - REG_A5XX_GRAS_PERFCTR_LRZ_SEL_0 }, + REG_A5XX_GRAS_PERFCTR_LRZ_SEL_0, 90 }, { REG_A5XX_RBBM_PERFCTR_LRZ_1_LO, REG_A5XX_RBBM_PERFCTR_LRZ_1_HI, - REG_A5XX_GRAS_PERFCTR_LRZ_SEL_1 }, + REG_A5XX_GRAS_PERFCTR_LRZ_SEL_1, 91 }, { REG_A5XX_RBBM_PERFCTR_LRZ_2_LO, REG_A5XX_RBBM_PERFCTR_LRZ_2_HI, - REG_A5XX_GRAS_PERFCTR_LRZ_SEL_2 }, + REG_A5XX_GRAS_PERFCTR_LRZ_SEL_2, 92 }, { REG_A5XX_RBBM_PERFCTR_LRZ_3_LO, REG_A5XX_RBBM_PERFCTR_LRZ_3_HI, - REG_A5XX_GRAS_PERFCTR_LRZ_SEL_3 }, + REG_A5XX_GRAS_PERFCTR_LRZ_SEL_3, 93 }, }; static struct adreno_counter a5xx_counters_pc[] = { { REG_A5XX_RBBM_PERFCTR_PC_0_LO, REG_A5XX_RBBM_PERFCTR_PC_0_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_0 }, + REG_A5XX_PC_PERFCTR_PC_SEL_0, 12 }, { REG_A5XX_RBBM_PERFCTR_PC_1_LO, REG_A5XX_RBBM_PERFCTR_PC_1_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_1 }, + REG_A5XX_PC_PERFCTR_PC_SEL_1, 13 }, { REG_A5XX_RBBM_PERFCTR_PC_2_LO, REG_A5XX_RBBM_PERFCTR_PC_2_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_2 }, + REG_A5XX_PC_PERFCTR_PC_SEL_2, 14 }, { REG_A5XX_RBBM_PERFCTR_PC_3_LO, REG_A5XX_RBBM_PERFCTR_PC_3_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_3 }, + REG_A5XX_PC_PERFCTR_PC_SEL_3, 15 }, { REG_A5XX_RBBM_PERFCTR_PC_4_LO, REG_A5XX_RBBM_PERFCTR_PC_4_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_4 }, + REG_A5XX_PC_PERFCTR_PC_SEL_4, 16 }, { REG_A5XX_RBBM_PERFCTR_PC_5_LO, REG_A5XX_RBBM_PERFCTR_PC_5_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_5 }, + REG_A5XX_PC_PERFCTR_PC_SEL_5, 17 }, { REG_A5XX_RBBM_PERFCTR_PC_6_LO, REG_A5XX_RBBM_PERFCTR_PC_6_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_6 }, + REG_A5XX_PC_PERFCTR_PC_SEL_6, 18 }, { REG_A5XX_RBBM_PERFCTR_PC_7_LO, REG_A5XX_RBBM_PERFCTR_PC_7_HI, - REG_A5XX_PC_PERFCTR_PC_SEL_7 }, + REG_A5XX_PC_PERFCTR_PC_SEL_7, 19 }, }; static struct adreno_counter a5xx_counters_ras[] = { { REG_A5XX_RBBM_PERFCTR_RAS_0_LO, REG_A5XX_RBBM_PERFCTR_RAS_0_HI, - REG_A5XX_GRAS_PERFCTR_RAS_SEL_0 }, + REG_A5XX_GRAS_PERFCTR_RAS_SEL_0, 48 }, { REG_A5XX_RBBM_PERFCTR_RAS_1_LO, REG_A5XX_RBBM_PERFCTR_RAS_1_HI, - REG_A5XX_GRAS_PERFCTR_RAS_SEL_1 }, + REG_A5XX_GRAS_PERFCTR_RAS_SEL_1, 49 }, { REG_A5XX_RBBM_PERFCTR_RAS_2_LO, REG_A5XX_RBBM_PERFCTR_RAS_2_HI, - REG_A5XX_GRAS_PERFCTR_RAS_SEL_2 }, + REG_A5XX_GRAS_PERFCTR_RAS_SEL_2, 50 }, { REG_A5XX_RBBM_PERFCTR_RAS_3_LO, REG_A5XX_RBBM_PERFCTR_RAS_3_HI, - REG_A5XX_GRAS_PERFCTR_RAS_SEL_3 }, + REG_A5XX_GRAS_PERFCTR_RAS_SEL_3, 51 }, }; static struct adreno_counter a5xx_counters_rb[] = { { REG_A5XX_RBBM_PERFCTR_RB_0_LO, REG_A5XX_RBBM_PERFCTR_RB_0_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_0 }, + REG_A5XX_RB_PERFCTR_RB_SEL_0, 80 }, { REG_A5XX_RBBM_PERFCTR_RB_1_LO, REG_A5XX_RBBM_PERFCTR_RB_1_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_1 }, + REG_A5XX_RB_PERFCTR_RB_SEL_1, 81 }, { REG_A5XX_RBBM_PERFCTR_RB_2_LO, REG_A5XX_RBBM_PERFCTR_RB_2_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_2 }, + REG_A5XX_RB_PERFCTR_RB_SEL_2, 82 }, { REG_A5XX_RBBM_PERFCTR_RB_3_LO, REG_A5XX_RBBM_PERFCTR_RB_3_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_3 }, + REG_A5XX_RB_PERFCTR_RB_SEL_3, 83 }, { REG_A5XX_RBBM_PERFCTR_RB_4_LO, REG_A5XX_RBBM_PERFCTR_RB_4_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_4 }, + REG_A5XX_RB_PERFCTR_RB_SEL_4, 84 }, { REG_A5XX_RBBM_PERFCTR_RB_5_LO, REG_A5XX_RBBM_PERFCTR_RB_5_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_5 }, + REG_A5XX_RB_PERFCTR_RB_SEL_5, 85 }, { REG_A5XX_RBBM_PERFCTR_RB_6_LO, REG_A5XX_RBBM_PERFCTR_RB_6_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_6 }, + REG_A5XX_RB_PERFCTR_RB_SEL_6, 86 }, { REG_A5XX_RBBM_PERFCTR_RB_7_LO, REG_A5XX_RBBM_PERFCTR_RB_7_HI, - REG_A5XX_RB_PERFCTR_RB_SEL_7 }, + REG_A5XX_RB_PERFCTR_RB_SEL_7, 87 }, }; static struct adreno_counter a5xx_counters_rbbm[] = { { REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, REG_A5XX_RBBM_PERFCTR_RBBM_0_HI, - REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0 }, + REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0, 8 }, { REG_A5XX_RBBM_PERFCTR_RBBM_1_LO, REG_A5XX_RBBM_PERFCTR_RBBM_1_HI, - REG_A5XX_RBBM_PERFCTR_RBBM_SEL_1 }, + REG_A5XX_RBBM_PERFCTR_RBBM_SEL_1, 9 }, { REG_A5XX_RBBM_PERFCTR_RBBM_2_LO, REG_A5XX_RBBM_PERFCTR_RBBM_2_HI, - REG_A5XX_RBBM_PERFCTR_RBBM_SEL_2 }, + REG_A5XX_RBBM_PERFCTR_RBBM_SEL_2, 10 }, { REG_A5XX_RBBM_PERFCTR_RBBM_3_LO, REG_A5XX_RBBM_PERFCTR_RBBM_3_HI, - REG_A5XX_RBBM_PERFCTR_RBBM_SEL_3 }, + REG_A5XX_RBBM_PERFCTR_RBBM_SEL_3, 11 }, }; static struct adreno_counter a5xx_counters_sp[] = { { REG_A5XX_RBBM_PERFCTR_SP_0_LO, REG_A5XX_RBBM_PERFCTR_SP_0_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_0 }, + REG_A5XX_SP_PERFCTR_SP_SEL_0, 68 }, { REG_A5XX_RBBM_PERFCTR_SP_1_LO, REG_A5XX_RBBM_PERFCTR_SP_1_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_1 }, + REG_A5XX_SP_PERFCTR_SP_SEL_1, 69 }, { REG_A5XX_RBBM_PERFCTR_SP_2_LO, REG_A5XX_RBBM_PERFCTR_SP_2_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_2 }, + REG_A5XX_SP_PERFCTR_SP_SEL_2, 70 }, { REG_A5XX_RBBM_PERFCTR_SP_3_LO, REG_A5XX_RBBM_PERFCTR_SP_3_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_3 }, + REG_A5XX_SP_PERFCTR_SP_SEL_3, 71 }, { REG_A5XX_RBBM_PERFCTR_SP_4_LO, REG_A5XX_RBBM_PERFCTR_SP_4_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_4 }, + REG_A5XX_SP_PERFCTR_SP_SEL_4, 72 }, { REG_A5XX_RBBM_PERFCTR_SP_5_LO, REG_A5XX_RBBM_PERFCTR_SP_5_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_5 }, + REG_A5XX_SP_PERFCTR_SP_SEL_5, 73 }, { REG_A5XX_RBBM_PERFCTR_SP_6_LO, REG_A5XX_RBBM_PERFCTR_SP_6_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_6 }, + REG_A5XX_SP_PERFCTR_SP_SEL_6, 74 }, { REG_A5XX_RBBM_PERFCTR_SP_7_LO, REG_A5XX_RBBM_PERFCTR_SP_7_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_7 }, + REG_A5XX_SP_PERFCTR_SP_SEL_7, 75 }, { REG_A5XX_RBBM_PERFCTR_SP_8_LO, REG_A5XX_RBBM_PERFCTR_SP_8_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_8 }, + REG_A5XX_SP_PERFCTR_SP_SEL_8, 76 }, { REG_A5XX_RBBM_PERFCTR_SP_9_LO, REG_A5XX_RBBM_PERFCTR_SP_9_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_9 }, + REG_A5XX_SP_PERFCTR_SP_SEL_9, 77 }, { REG_A5XX_RBBM_PERFCTR_SP_10_LO, REG_A5XX_RBBM_PERFCTR_SP_10_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_10 }, + REG_A5XX_SP_PERFCTR_SP_SEL_10, 78 }, { REG_A5XX_RBBM_PERFCTR_SP_11_LO, REG_A5XX_RBBM_PERFCTR_SP_11_HI, - REG_A5XX_SP_PERFCTR_SP_SEL_11 }, + REG_A5XX_SP_PERFCTR_SP_SEL_11, 79 }, }; static struct adreno_counter a5xx_counters_tp[] = { { REG_A5XX_RBBM_PERFCTR_TP_0_LO, REG_A5XX_RBBM_PERFCTR_TP_0_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_0 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_0, 60 }, { REG_A5XX_RBBM_PERFCTR_TP_1_LO, REG_A5XX_RBBM_PERFCTR_TP_1_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_1 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_1, 61 }, { REG_A5XX_RBBM_PERFCTR_TP_2_LO, REG_A5XX_RBBM_PERFCTR_TP_2_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_2 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_2, 62 }, { REG_A5XX_RBBM_PERFCTR_TP_3_LO, REG_A5XX_RBBM_PERFCTR_TP_3_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_3 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_3, 63 }, { REG_A5XX_RBBM_PERFCTR_TP_4_LO, REG_A5XX_RBBM_PERFCTR_TP_4_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_4 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_4, 64 }, { REG_A5XX_RBBM_PERFCTR_TP_5_LO, REG_A5XX_RBBM_PERFCTR_TP_5_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_5 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_5, 65 }, { REG_A5XX_RBBM_PERFCTR_TP_6_LO, REG_A5XX_RBBM_PERFCTR_TP_6_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_6 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_6, 66 }, { REG_A5XX_RBBM_PERFCTR_TP_7_LO, REG_A5XX_RBBM_PERFCTR_TP_7_HI, - REG_A5XX_TPL1_PERFCTR_TP_SEL_7 }, + REG_A5XX_TPL1_PERFCTR_TP_SEL_7, 67 }, }; static struct adreno_counter a5xx_counters_tse[] = { { REG_A5XX_RBBM_PERFCTR_TSE_0_LO, REG_A5XX_RBBM_PERFCTR_TSE_0_HI, - REG_A5XX_GRAS_PERFCTR_TSE_SEL_0 }, + REG_A5XX_GRAS_PERFCTR_TSE_SEL_0, 44 }, { REG_A5XX_RBBM_PERFCTR_TSE_1_LO, REG_A5XX_RBBM_PERFCTR_TSE_1_HI, - REG_A5XX_GRAS_PERFCTR_TSE_SEL_1 }, + REG_A5XX_GRAS_PERFCTR_TSE_SEL_1, 45 }, { REG_A5XX_RBBM_PERFCTR_TSE_2_LO, REG_A5XX_RBBM_PERFCTR_TSE_2_HI, - REG_A5XX_GRAS_PERFCTR_TSE_SEL_2 }, + REG_A5XX_GRAS_PERFCTR_TSE_SEL_2, 46 }, { REG_A5XX_RBBM_PERFCTR_TSE_3_LO, REG_A5XX_RBBM_PERFCTR_TSE_3_HI, - REG_A5XX_GRAS_PERFCTR_TSE_SEL_3 }, + REG_A5XX_GRAS_PERFCTR_TSE_SEL_3, 47 }, }; static struct adreno_counter a5xx_counters_uche[] = { { REG_A5XX_RBBM_PERFCTR_UCHE_0_LO, REG_A5XX_RBBM_PERFCTR_UCHE_0_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_0 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_0, 52 }, { REG_A5XX_RBBM_PERFCTR_UCHE_1_LO, REG_A5XX_RBBM_PERFCTR_UCHE_1_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_1 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_1, 53 }, { REG_A5XX_RBBM_PERFCTR_UCHE_2_LO, REG_A5XX_RBBM_PERFCTR_UCHE_2_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_2 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_2, 54 }, { REG_A5XX_RBBM_PERFCTR_UCHE_3_LO, REG_A5XX_RBBM_PERFCTR_UCHE_3_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_3 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_3, 55 }, { REG_A5XX_RBBM_PERFCTR_UCHE_4_LO, REG_A5XX_RBBM_PERFCTR_UCHE_4_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_4 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_4, 56 }, { REG_A5XX_RBBM_PERFCTR_UCHE_5_LO, REG_A5XX_RBBM_PERFCTR_UCHE_5_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_5 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_5, 57 }, { REG_A5XX_RBBM_PERFCTR_UCHE_6_LO, REG_A5XX_RBBM_PERFCTR_UCHE_6_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_6 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_6, 58 }, { REG_A5XX_RBBM_PERFCTR_UCHE_7_LO, REG_A5XX_RBBM_PERFCTR_UCHE_7_HI, - REG_A5XX_UCHE_PERFCTR_UCHE_SEL_7 }, + REG_A5XX_UCHE_PERFCTR_UCHE_SEL_7, 59 }, }; static struct adreno_counter a5xx_counters_vfd[] = { { REG_A5XX_RBBM_PERFCTR_VFD_0_LO, REG_A5XX_RBBM_PERFCTR_VFD_0_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_0 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_0, 20 }, { REG_A5XX_RBBM_PERFCTR_VFD_1_LO, REG_A5XX_RBBM_PERFCTR_VFD_1_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_1 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_1, 21 }, { REG_A5XX_RBBM_PERFCTR_VFD_2_LO, REG_A5XX_RBBM_PERFCTR_VFD_2_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_2 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_2, 22 }, { REG_A5XX_RBBM_PERFCTR_VFD_3_LO, REG_A5XX_RBBM_PERFCTR_VFD_3_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_3 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_3, 23 }, { REG_A5XX_RBBM_PERFCTR_VFD_4_LO, REG_A5XX_RBBM_PERFCTR_VFD_4_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_4 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_4, 24 }, { REG_A5XX_RBBM_PERFCTR_VFD_5_LO, REG_A5XX_RBBM_PERFCTR_VFD_5_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_5 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_5, 25 }, { REG_A5XX_RBBM_PERFCTR_VFD_6_LO, REG_A5XX_RBBM_PERFCTR_VFD_6_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_6 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_6, 26 }, { REG_A5XX_RBBM_PERFCTR_VFD_7_LO, REG_A5XX_RBBM_PERFCTR_VFD_7_HI, - REG_A5XX_VFD_PERFCTR_VFD_SEL_7 }, + REG_A5XX_VFD_PERFCTR_VFD_SEL_7, 27 }, }; static struct adreno_counter a5xx_counters_vpc[] = { { REG_A5XX_RBBM_PERFCTR_VPC_0_LO, REG_A5XX_RBBM_PERFCTR_VPC_0_HI, - REG_A5XX_VPC_PERFCTR_VPC_SEL_0 }, + REG_A5XX_VPC_PERFCTR_VPC_SEL_0, 36 }, { REG_A5XX_RBBM_PERFCTR_VPC_1_LO, REG_A5XX_RBBM_PERFCTR_VPC_1_HI, - REG_A5XX_VPC_PERFCTR_VPC_SEL_1 }, + REG_A5XX_VPC_PERFCTR_VPC_SEL_1, 37 }, { REG_A5XX_RBBM_PERFCTR_VPC_2_LO, REG_A5XX_RBBM_PERFCTR_VPC_2_HI, - REG_A5XX_VPC_PERFCTR_VPC_SEL_2 }, + REG_A5XX_VPC_PERFCTR_VPC_SEL_2, 38 }, { REG_A5XX_RBBM_PERFCTR_VPC_3_LO, REG_A5XX_RBBM_PERFCTR_VPC_3_HI, - REG_A5XX_VPC_PERFCTR_VPC_SEL_3 }, + REG_A5XX_VPC_PERFCTR_VPC_SEL_3, 39 }, }; static struct adreno_counter a5xx_counters_vsc[] = { { REG_A5XX_RBBM_PERFCTR_VSC_0_LO, REG_A5XX_RBBM_PERFCTR_VSC_0_HI, - REG_A5XX_VSC_PERFCTR_VSC_SEL_0 }, + REG_A5XX_VSC_PERFCTR_VSC_SEL_0, 88 }, { REG_A5XX_RBBM_PERFCTR_VSC_1_LO, REG_A5XX_RBBM_PERFCTR_VSC_1_HI, - REG_A5XX_VSC_PERFCTR_VSC_SEL_1 }, + REG_A5XX_VSC_PERFCTR_VSC_SEL_1, 89 }, }; static struct adreno_counter a5xx_counters_power_ccu[] = { { REG_A5XX_CCU_POWER_COUNTER_0_LO, REG_A5XX_CCU_POWER_COUNTER_0_HI, - REG_A5XX_RB_POWERCTR_CCU_SEL_0 }, + REG_A5XX_RB_POWERCTR_CCU_SEL_0, 40 }, { REG_A5XX_CCU_POWER_COUNTER_1_LO, REG_A5XX_CCU_POWER_COUNTER_1_HI, - REG_A5XX_RB_POWERCTR_CCU_SEL_1 }, + REG_A5XX_RB_POWERCTR_CCU_SEL_1, 41 }, }; static struct adreno_counter a5xx_counters_power_cp[] = { @@ -590,39 +686,47 @@ static struct adreno_counter a5xx_counters_alwayson_power[] = { REG_A5XX_GPMU_ALWAYS_ON_COUNTER_HI }, }; -#define DEFINE_COUNTER_GROUP(_name, _array, _get, _enable, _put) \ -static struct adreno_counter_group _name = { \ - .counters = _array, \ - .nr_counters = ARRAY_SIZE(_array), \ +#define DEFINE_COUNTER_GROUP(_n, _a, _get, _enable, _put, _save, _restore) \ +static struct adreno_counter_group _n = { \ + .counters = _a, \ + .nr_counters = ARRAY_SIZE(_a), \ .lock = __SPIN_LOCK_UNLOCKED(_name.lock), \ .funcs = { \ .get = _get, \ .enable = _enable, \ .read = a5xx_counter_read, \ .put = _put, \ + .save = _save, \ + .restore = _restore \ }, \ } -#define DEFAULT_COUNTER_GROUP(_name, _array) DEFINE_COUNTER_GROUP(_name, \ - _array, a5xx_counter_get, a5xx_counter_enable_cpu, a5xx_counter_put) +#define COUNTER_GROUP(_name, _array) DEFINE_COUNTER_GROUP(_name, \ + _array, a5xx_counter_get, a5xx_counter_enable_cpu, a5xx_counter_put, \ + a5xx_counter_save, a5xx_counter_restore) #define SPTP_COUNTER_GROUP(_name, _array) DEFINE_COUNTER_GROUP(_name, \ - _array, a5xx_counter_get, a5xx_counter_enable_pm4, a5xx_counter_put) + _array, a5xx_counter_get, a5xx_counter_enable_pm4, a5xx_counter_put, \ + a5xx_counter_save, a5xx_counter_restore) + +#define POWER_COUNTER_GROUP(_name, _array) DEFINE_COUNTER_GROUP(_name, \ + _array, a5xx_counter_get, a5xx_counter_enable_cpu, a5xx_counter_put, \ + NULL, NULL) /* "standard" counters */ -DEFAULT_COUNTER_GROUP(a5xx_counter_group_cp, a5xx_counters_cp); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_rbbm, a5xx_counters_rbbm); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_pc, a5xx_counters_pc); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_vfd, a5xx_counters_vfd); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_vpc, a5xx_counters_vpc); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_ccu, a5xx_counters_ccu); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_cmp, a5xx_counters_cmp); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_tse, a5xx_counters_tse); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_ras, a5xx_counters_ras); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_uche, a5xx_counters_uche); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_rb, a5xx_counters_rb); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_vsc, a5xx_counters_vsc); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_lrz, a5xx_counters_lrz); +COUNTER_GROUP(a5xx_counter_group_cp, a5xx_counters_cp); +COUNTER_GROUP(a5xx_counter_group_rbbm, a5xx_counters_rbbm); +COUNTER_GROUP(a5xx_counter_group_pc, a5xx_counters_pc); +COUNTER_GROUP(a5xx_counter_group_vfd, a5xx_counters_vfd); +COUNTER_GROUP(a5xx_counter_group_vpc, a5xx_counters_vpc); +COUNTER_GROUP(a5xx_counter_group_ccu, a5xx_counters_ccu); +COUNTER_GROUP(a5xx_counter_group_cmp, a5xx_counters_cmp); +COUNTER_GROUP(a5xx_counter_group_tse, a5xx_counters_tse); +COUNTER_GROUP(a5xx_counter_group_ras, a5xx_counters_ras); +COUNTER_GROUP(a5xx_counter_group_uche, a5xx_counters_uche); +COUNTER_GROUP(a5xx_counter_group_rb, a5xx_counters_rb); +COUNTER_GROUP(a5xx_counter_group_vsc, a5xx_counters_vsc); +COUNTER_GROUP(a5xx_counter_group_lrz, a5xx_counters_lrz); /* SP/TP counters */ SPTP_COUNTER_GROUP(a5xx_counter_group_hlsq, a5xx_counters_hlsq); @@ -630,24 +734,27 @@ SPTP_COUNTER_GROUP(a5xx_counter_group_tp, a5xx_counters_tp); SPTP_COUNTER_GROUP(a5xx_counter_group_sp, a5xx_counters_sp); /* Power counters */ -DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_ccu, a5xx_counters_power_ccu); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_cp, a5xx_counters_power_cp); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_rb, a5xx_counters_power_rb); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_sp, a5xx_counters_power_sp); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_tp, a5xx_counters_power_tp); -DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_uche, a5xx_counters_power_uche); +POWER_COUNTER_GROUP(a5xx_counter_group_power_ccu, a5xx_counters_power_ccu); +POWER_COUNTER_GROUP(a5xx_counter_group_power_cp, a5xx_counters_power_cp); +POWER_COUNTER_GROUP(a5xx_counter_group_power_rb, a5xx_counters_power_rb); +POWER_COUNTER_GROUP(a5xx_counter_group_power_sp, a5xx_counters_power_sp); +POWER_COUNTER_GROUP(a5xx_counter_group_power_tp, a5xx_counters_power_tp); +POWER_COUNTER_GROUP(a5xx_counter_group_power_uche, a5xx_counters_power_uche); DEFINE_COUNTER_GROUP(a5xx_counter_group_alwayson, a5xx_counters_alwayson, - a5xx_counter_get_fixed, NULL, NULL); + a5xx_counter_get_fixed, NULL, NULL, NULL, NULL); DEFINE_COUNTER_GROUP(a5xx_counter_group_vbif, a5xx_counters_vbif, - a5xx_counter_get, a5xx_counter_enable_vbif, a5xx_counter_put); + a5xx_counter_get, a5xx_counter_enable_vbif, a5xx_counter_put, + NULL, NULL); DEFINE_COUNTER_GROUP(a5xx_counter_group_gpmu, a5xx_counters_gpmu, - a5xx_counter_get, a5xx_counter_enable_gpmu, a5xx_counter_put); + a5xx_counter_get, a5xx_counter_enable_gpmu, a5xx_counter_put, + NULL, NULL); DEFINE_COUNTER_GROUP(a5xx_counter_group_vbif_power, a5xx_counters_vbif_power, - a5xx_counter_get_fixed, a5xx_counter_enable_vbif_power, NULL); + a5xx_counter_get_fixed, a5xx_counter_enable_vbif_power, NULL, NULL, + NULL); DEFINE_COUNTER_GROUP(a5xx_counter_group_alwayson_power, a5xx_counters_alwayson_power, a5xx_counter_get_fixed, - a5xx_counter_enable_alwayson_power, NULL); + a5xx_counter_enable_alwayson_power, NULL, NULL, NULL); static const struct adreno_counter_group *a5xx_counter_groups[] = { [MSM_COUNTER_GROUP_ALWAYSON] = &a5xx_counter_group_alwayson, @@ -680,6 +787,35 @@ static const struct adreno_counter_group *a5xx_counter_groups[] = { &a5xx_counter_group_alwayson_power, }; +void a5xx_counters_restore(struct msm_gpu *gpu) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(a5xx_counter_groups); i++) { + struct adreno_counter_group *group = + (struct adreno_counter_group *) a5xx_counter_groups[i]; + + if (group && group->funcs.restore) + group->funcs.restore(gpu, group); + + a5xx_counter_group_enable(gpu, group, true); + } +} + + +void a5xx_counters_save(struct msm_gpu *gpu) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(a5xx_counter_groups); i++) { + struct adreno_counter_group *group = + (struct adreno_counter_group *) a5xx_counter_groups[i]; + + if (group && group->funcs.save) + group->funcs.save(gpu, group); + } +} + int a5xx_counters_init(struct adreno_gpu *adreno_gpu) { adreno_gpu->counter_groups = a5xx_counter_groups; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 765c1c087c76..e493c2fee762 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -15,7 +15,6 @@ #include "msm_iommu.h" #include "msm_trace.h" #include "a5xx_gpu.h" -#include <linux/clk/msm-clk.h> #define SECURE_VA_START 0xc0000000 #define SECURE_VA_SIZE SZ_256M @@ -1170,25 +1169,14 @@ static int a5xx_pm_resume(struct msm_gpu *gpu) { int ret; - /* - * Between suspend/resumes the GPU clocks need to be turned off - * but not a complete power down, typically between frames. Set the - * memory retention flags on the GPU core clock to retain memory - * across clock toggles. - */ - if (gpu->core_clk) { - clk_set_flags(gpu->core_clk, CLKFLAG_RETAIN_PERIPH); - clk_set_flags(gpu->core_clk, CLKFLAG_RETAIN_MEM); - } - /* Turn on the core power */ ret = msm_gpu_pm_resume(gpu); if (ret) return ret; - /* If we are already up, don't mess with what works */ - if (gpu->active_cnt > 1) - return 0; + + /* Restore all the counters before turning on the GPMU */ + a5xx_counters_restore(gpu); /* Turn the RBCCU domain first to limit the chances of voltage droop */ gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000); @@ -1220,33 +1208,26 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - /* Turn off the memory retention flag when not necessary */ - if (gpu->core_clk) { - clk_set_flags(gpu->core_clk, CLKFLAG_NORETAIN_PERIPH); - clk_set_flags(gpu->core_clk, CLKFLAG_NORETAIN_MEM); - } - - /* Only do this next bit if we are about to go down */ - if (gpu->active_cnt == 1) { - /* Clear the VBIF pipe before shutting down */ - - gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); - spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) + /* Clear the VBIF pipe before shutting down */ + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); + spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) == 0xF); - gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); - /* - * Reset the VBIF before power collapse to avoid issue with FIFO - * entries - */ - if (adreno_is_a530(adreno_gpu)) { - /* These only need to be done for A530 */ - gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, + /* Save the counters before going down */ + a5xx_counters_save(gpu); + + /* + * Reset the VBIF before power collapse to avoid issue with FIFO + * entries + */ + if (adreno_is_a530(adreno_gpu)) { + /* These only need to be done for A530 */ + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x003C0000); - gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x00000000); - } } return msm_gpu_pm_suspend(gpu); @@ -1266,29 +1247,10 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) #ifdef CONFIG_DEBUG_FS static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m) { - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); - bool enabled = test_bit(A5XX_HWCG_ENABLED, &a5xx_gpu->flags); - - gpu->funcs->pm_resume(gpu); - seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A5XX_RBBM_STATUS)); - - /* - * Temporarily disable hardware clock gating before going into - * adreno_show to avoid issues while reading the registers - */ - - if (enabled) - a5xx_set_hwcg(gpu, false); - adreno_show(gpu, m); - if (enabled) - a5xx_set_hwcg(gpu, true); - - gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h index c30b65785ab6..9c62f861136d 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -194,5 +194,7 @@ static inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu) } int a5xx_counters_init(struct adreno_gpu *adreno_gpu); +void a5xx_counters_save(struct msm_gpu *gpu); +void a5xx_counters_restore(struct msm_gpu *gpu); #endif /* __A5XX_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 4e4709d6172f..4ecc3ad762ef 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -164,13 +164,10 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) if (gpu) { int ret; - mutex_lock(&dev->struct_mutex); - gpu->funcs->pm_resume(gpu); - mutex_unlock(&dev->struct_mutex); - disable_irq(gpu->irq); - - ret = gpu->funcs->hw_init(gpu); + pm_runtime_get_sync(&pdev->dev); + ret = msm_gpu_hw_init(gpu); + pm_runtime_put_sync_autosuspend(&pdev->dev); if (ret) { dev_err(dev->dev, "gpu hw init failed: %d\n", ret); mutex_lock(&dev->struct_mutex); @@ -178,10 +175,6 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); gpu->funcs->destroy(gpu); gpu = NULL; - } else { - enable_irq(gpu->irq); - /* give inactive pm a chance to kick in: */ - msm_gpu_retire(gpu); } } @@ -250,12 +243,35 @@ static const struct of_device_id dt_match[] = { {} }; +#ifdef CONFIG_PM +static int adreno_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct msm_gpu *gpu = platform_get_drvdata(pdev); + + return gpu->funcs->pm_resume(gpu); +} + +static int adreno_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct msm_gpu *gpu = platform_get_drvdata(pdev); + + return gpu->funcs->pm_suspend(gpu); +} +#endif + +static const struct dev_pm_ops adreno_pm_ops = { + SET_RUNTIME_PM_OPS(adreno_suspend, adreno_resume, NULL) +}; + static struct platform_driver adreno_driver = { .probe = adreno_probe, .remove = adreno_remove, .driver = { .name = "adreno", .of_match_table = dt_match, + .pm = &adreno_pm_ops, }, }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 04e0056f2a49..d397c44f1203 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -48,8 +48,15 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) *value = gpu->gpufreq[gpu->active_level]; return 0; case MSM_PARAM_TIMESTAMP: - if (adreno_gpu->funcs->get_timestamp) - return adreno_gpu->funcs->get_timestamp(gpu, value); + if (adreno_gpu->funcs->get_timestamp) { + int ret; + + pm_runtime_get_sync(&gpu->pdev->dev); + ret = adreno_gpu->funcs->get_timestamp(gpu, value); + pm_runtime_put_autosuspend(&gpu->pdev->dev); + + return ret; + } return -EINVAL; case MSM_PARAM_NR_RINGS: *value = gpu->nr_rings; @@ -68,14 +75,25 @@ int adreno_hw_init(struct msm_gpu *gpu) DBG("%s", gpu->name); for (i = 0; i < gpu->nr_rings; i++) { - int ret = msm_gem_get_iova(gpu->rb[i]->bo, gpu->aspace, - &gpu->rb[i]->iova); + struct msm_ringbuffer *ring = gpu->rb[i]; + + int ret = msm_gem_get_iova(ring->bo, gpu->aspace, + &ring->iova); if (ret) { - gpu->rb[i]->iova = 0; + ring->iova = 0; dev_err(gpu->dev->dev, "could not map ringbuffer %d: %d\n", i, ret); return ret; } + + /* reset ringbuffer(s): */ + /* No need for a lock here, nobody else is peeking in */ + ring->cur = ring->start; + ring->next = ring->start; + + /* reset completed fence seqno, discard anything pending: */ + ring->memptrs->fence = adreno_submitted_fence(gpu, ring); + ring->memptrs->rptr = 0; } /* @@ -133,35 +151,22 @@ uint32_t adreno_submitted_fence(struct msm_gpu *gpu, void adreno_recover(struct msm_gpu *gpu) { struct drm_device *dev = gpu->dev; - struct msm_ringbuffer *ring; - int ret, i; - - gpu->funcs->pm_suspend(gpu); - - /* reset ringbuffer(s): */ - - FOR_EACH_RING(gpu, ring, i) { - if (!ring) - continue; + int ret; - /* No need for a lock here, nobody else is peeking in */ - ring->cur = ring->start; - ring->next = ring->start; + /* + * XXX pm-runtime?? we *need* the device to be off after this + * so maybe continuing to call ->pm_suspend/resume() is better? + */ - /* reset completed fence seqno, discard anything pending: */ - ring->memptrs->fence = adreno_submitted_fence(gpu, ring); - ring->memptrs->rptr = 0; - } + gpu->funcs->pm_suspend(gpu); gpu->funcs->pm_resume(gpu); - disable_irq(gpu->irq); - ret = gpu->funcs->hw_init(gpu); + ret = msm_gpu_hw_init(gpu); if (ret) { dev_err(dev->dev, "gpu hw init failed: %d\n", ret); /* hmm, oh well? */ } - enable_irq(gpu->irq); } void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) @@ -520,6 +525,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, if (ret) return ret; + pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev); if (ret) { dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n", @@ -535,12 +544,18 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, return ret; } -void adreno_gpu_cleanup(struct adreno_gpu *gpu) +void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) { - release_firmware(gpu->pm4); - release_firmware(gpu->pfp); + struct msm_gpu *gpu = &adreno_gpu->base; + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; + + release_firmware(adreno_gpu->pm4); + release_firmware(adreno_gpu->pfp); - msm_gpu_cleanup(&gpu->base); + pm_runtime_disable(&pdev->dev); + msm_gpu_cleanup(gpu); } static void adreno_snapshot_os(struct msm_gpu *gpu, diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index c96189fb805b..462352f7fc9a 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -87,8 +87,10 @@ struct adreno_counter { u32 lo; u32 hi; u32 sel; + int load_bit; u32 countable; u32 refcount; + u64 value; }; struct adreno_counter_group { @@ -99,11 +101,15 @@ struct adreno_counter_group { int (*get)(struct msm_gpu *, struct adreno_counter_group *, u32, u32 *, u32 *); void (*enable)(struct msm_gpu *, - struct adreno_counter_group *, int); + struct adreno_counter_group *, int, bool); u64 (*read)(struct msm_gpu *, struct adreno_counter_group *, int); void (*put)(struct msm_gpu *, struct adreno_counter_group *, int); + void (*save)(struct msm_gpu *, + struct adreno_counter_group *); + void (*restore)(struct msm_gpu *, + struct adreno_counter_group *); } funcs; }; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index c98f4511d644..fa111d581529 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -2153,6 +2153,8 @@ int sde_hdmi_get_property(struct drm_connector *connector, mutex_lock(&hdmi_display->display_lock); if (property_index == CONNECTOR_PROP_PLL_ENABLE) *value = hdmi_display->pll_update_enable ? 1 : 0; + if (property_index == CONNECTOR_PROP_HDCP_VERSION) + *value = hdmi_display->sink_hdcp_ver; mutex_unlock(&hdmi_display->display_lock); return rc; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 672a9f188d27..865998c6a126 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -108,14 +108,34 @@ enum hdmi_tx_feature_type { * @mode: Current display mode. * @connected: If HDMI display is connected. * @is_tpg_enabled: TPG state. + * @hdmi_tx_version: HDMI TX version + * @hdmi_tx_major_version: HDMI TX major version + * @max_pclk_khz: Max pixel clock supported + * @hdcp1_use_sw_keys: If HDCP1 engine uses SW keys + * @hdcp14_present: If the sink supports HDCP 1.4 + * @hdcp22_present: If the sink supports HDCP 2.2 + * @hdcp_status: Current HDCP status + * @sink_hdcp_ver: HDCP version of the sink + * @enc_lvl: Current encryption level + * @curr_hdr_state: Current HDR state of the HDMI connector + * @auth_state: Current authentication state of HDCP + * @sink_hdcp22_support: If the sink supports HDCP 2.2 + * @src_hdcp22_support: If the source supports HDCP 2.2 + * @hdcp_data: Call back data registered by the client with HDCP lib + * @hdcp_feat_data: Handle to HDCP feature data + * @hdcp_ops: Function ops registered by the client with the HDCP lib + * @ddc_ctrl: Handle to HDMI DDC Controller * @hpd_work: HPD work structure. * @codec_ready: If audio codec is ready. * @client_notify_pending: If there is client notification pending. * @irq_domain: IRQ domain structure. + * @notifier: CEC notifider to convey physical address information. * @pll_update_enable: if it's allowed to update HDMI PLL ppm. * @dc_enable: If deep color is enabled. Only DC_30 so far. * @dc_feature_supported: If deep color feature is supported. - * @notifier: CEC notifider to convey physical address information. + * @bt2020_colorimetry: If BT2020 colorimetry is supported by sink + * @hdcp_cb_work: Callback function for HDCP + * @io: Handle to IO base addresses for HDMI * @root: Debug fs root entry. */ struct sde_hdmi { @@ -146,6 +166,7 @@ struct sde_hdmi { u32 hdcp14_present; u32 hdcp22_present; u8 hdcp_status; + u8 sink_hdcp_ver; u32 enc_lvl; u8 curr_hdr_state; bool auth_state; 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 e6b6d15b5fb7..3c470caec571 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -511,6 +511,11 @@ static void sde_hdmi_update_hdcp_info(struct drm_connector *connector) } } + if (display->sink_hdcp22_support) + display->sink_hdcp_ver = SDE_HDMI_HDCP_22; + else + display->sink_hdcp_ver = SDE_HDMI_HDCP_14; + /* update internal data about hdcp */ display->hdcp_data = fd; display->hdcp_ops = ops; @@ -543,6 +548,7 @@ static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) mutex_lock(&display->display_lock); display->pll_update_enable = false; + display->sink_hdcp_ver = SDE_HDMI_HDCP_NONE; mutex_unlock(&display->display_lock); } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 3c6b0f1b9dd4..421bdf7643ca 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -105,6 +105,10 @@ #define SDE_HDMI_USE_EXTENDED_COLORIMETRY 0x3 #define SDE_HDMI_BT2020_COLORIMETRY 0x6 +#define SDE_HDMI_HDCP_22 0x22 +#define SDE_HDMI_HDCP_14 0x14 +#define SDE_HDMI_HDCP_NONE 0x0 + /* * Bits 1:0 in HDMI_HW_DDC_CTRL that dictate how the HDCP 2.2 RxStatus will be * read by the hardware diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 7d660ba56594..9dbd86eff816 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -424,7 +424,7 @@ static struct hdmi_platform_config hdmi_tx_8994_config = { static struct hdmi_platform_config hdmi_tx_8996_config = { .phy_init = NULL, HDMI_CFG(pwr_reg, none), - HDMI_CFG(hpd_reg, none), + HDMI_CFG(hpd_reg, 8x74), HDMI_CFG(pwr_clk, 8x74), HDMI_CFG(hpd_clk, 8x74), .hpd_freq = hpd_clk_freq_8x74, diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 969af4c6f0c0..c61753311771 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -185,9 +185,14 @@ static void vblank_ctrl_worker(struct kthread_work *work) struct msm_kms *kms = priv->kms; struct vblank_event *vbl_ev, *tmp; unsigned long flags; + struct kthread_worker *worker = work->worker; + struct msm_drm_commit *commit = container_of(worker, + struct msm_drm_commit, worker); spin_lock_irqsave(&vbl_ctrl->lock, flags); list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) { + if (vbl_ev->crtc_id != commit->crtc_id) + continue; list_del(&vbl_ev->node); spin_unlock_irqrestore(&vbl_ctrl->lock, flags); @@ -280,6 +285,10 @@ static int msm_unload(struct drm_device *dev) if (gpu) { mutex_lock(&dev->struct_mutex); + /* + * XXX what do we do here? + * pm_runtime_enable(&pdev->dev); + */ gpu->funcs->pm_suspend(gpu); mutex_unlock(&dev->struct_mutex); gpu->funcs->destroy(gpu); @@ -669,10 +678,10 @@ static int msm_open(struct drm_device *dev, struct drm_file *file) if (IS_ERR(ctx)) return PTR_ERR(ctx); - if (ctx) + if (ctx) { INIT_LIST_HEAD(&ctx->counters); - - msm_submitqueue_init(ctx); + msm_submitqueue_init(ctx); + } file->driver_priv = ctx; @@ -906,7 +915,9 @@ static int msm_gpu_show(struct drm_device *dev, struct seq_file *m) if (gpu) { seq_printf(m, "%s Status:\n", gpu->name); + pm_runtime_get_sync(&gpu->pdev->dev); gpu->funcs->show(gpu, m); + pm_runtime_put_sync(&gpu->pdev->dev); } return 0; @@ -2140,7 +2151,9 @@ static int msm_pdev_probe(struct platform_device *pdev) #ifdef CONFIG_OF add_components(&pdev->dev, &match, "connectors"); +#ifndef CONFIG_QCOM_KGSL add_components(&pdev->dev, &match, "gpus"); +#endif #else /* For non-DT case, it kinda sucks. We don't actually have a way * to know whether or not we are waiting for certain devices (or if diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index ae3a930005b6..25dc5f9ef561 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -158,6 +158,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_DST_H, CONNECTOR_PROP_PLL_DELTA, CONNECTOR_PROP_PLL_ENABLE, + CONNECTOR_PROP_HDCP_VERSION, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 7c109fdab545..44d9784d1bd7 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -154,22 +154,9 @@ static int disable_axi(struct msm_gpu *gpu) int msm_gpu_pm_resume(struct msm_gpu *gpu) { - struct drm_device *dev = gpu->dev; - struct msm_drm_private *priv = dev->dev_private; - struct platform_device *pdev = priv->gpu_pdev; int ret; - DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); - - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - - if (gpu->active_cnt++ > 0) - return 0; - - if (WARN_ON(gpu->active_cnt <= 0)) - return -EINVAL; - - WARN_ON(pm_runtime_get_sync(&pdev->dev) < 0); + DBG("%s", gpu->name); ret = enable_pwrrail(gpu); if (ret) @@ -186,25 +173,16 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) if (gpu->aspace && gpu->aspace->mmu) msm_mmu_enable(gpu->aspace->mmu); + gpu->needs_hw_init = true; + return 0; } int msm_gpu_pm_suspend(struct msm_gpu *gpu) { - struct drm_device *dev = gpu->dev; - struct msm_drm_private *priv = dev->dev_private; - struct platform_device *pdev = priv->gpu_pdev; int ret; - DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); - - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - - if (--gpu->active_cnt > 0) - return 0; - - if (WARN_ON(gpu->active_cnt < 0)) - return -EINVAL; + DBG("%s", gpu->name); if (gpu->aspace && gpu->aspace->mmu) msm_mmu_disable(gpu->aspace->mmu); @@ -221,57 +199,23 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) if (ret) return ret; - pm_runtime_put(&pdev->dev); return 0; } -/* - * Inactivity detection (for suspend): - */ - -static void inactive_worker(struct work_struct *work) +int msm_gpu_hw_init(struct msm_gpu *gpu) { - struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work); - struct drm_device *dev = gpu->dev; - - if (gpu->inactive) - return; - - DBG("%s: inactive!\n", gpu->name); - mutex_lock(&dev->struct_mutex); - if (!(msm_gpu_active(gpu) || gpu->inactive)) { - disable_axi(gpu); - disable_clk(gpu); - gpu->inactive = true; - } - mutex_unlock(&dev->struct_mutex); -} - -static void inactive_handler(unsigned long data) -{ - struct msm_gpu *gpu = (struct msm_gpu *)data; - struct msm_drm_private *priv = gpu->dev->dev_private; + int ret; - queue_work(priv->wq, &gpu->inactive_work); -} + if (!gpu->needs_hw_init) + return 0; -/* cancel inactive timer and make sure we are awake: */ -static void inactive_cancel(struct msm_gpu *gpu) -{ - DBG("%s", gpu->name); - del_timer(&gpu->inactive_timer); - if (gpu->inactive) { - enable_clk(gpu); - enable_axi(gpu); - gpu->inactive = false; - } -} + disable_irq(gpu->irq); + ret = gpu->funcs->hw_init(gpu); + if (!ret) + gpu->needs_hw_init = false; + enable_irq(gpu->irq); -static void inactive_start(struct msm_gpu *gpu) -{ - DBG("%s", gpu->name); - mod_timer(&gpu->inactive_timer, - round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES)); + return ret; } static void retire_guilty_submit(struct msm_gpu *gpu, @@ -306,8 +250,6 @@ static void recover_worker(struct work_struct *work) struct msm_ringbuffer *ring; int i; - inactive_cancel(gpu); - /* Retire all events that have already passed */ FOR_EACH_RING(gpu, ring, i) retire_submits(gpu, ring, ring->memptrs->fence); @@ -316,6 +258,8 @@ static void recover_worker(struct work_struct *work) /* Recover the GPU */ gpu->funcs->recover(gpu); + /* Decrement the device usage count for the guilty submit */ + pm_runtime_put_sync_autosuspend(&gpu->pdev->dev); /* Replay the remaining on all rings, highest priority first */ for (i = 0; i < gpu->nr_rings; i++) { @@ -438,6 +382,8 @@ void msm_gpu_perfcntr_start(struct msm_gpu *gpu) { unsigned long flags; + pm_runtime_get_sync(&gpu->pdev->dev); + spin_lock_irqsave(&gpu->perf_lock, flags); /* we could dynamically enable/disable perfcntr registers too.. */ gpu->last_sample.active = msm_gpu_active(gpu); @@ -451,6 +397,7 @@ void msm_gpu_perfcntr_start(struct msm_gpu *gpu) void msm_gpu_perfcntr_stop(struct msm_gpu *gpu) { gpu->perfcntr_active = false; + pm_runtime_put_sync(&gpu->pdev->dev); } /* returns -errno or # of cntrs sampled */ @@ -505,6 +452,8 @@ static void retire_submits(struct msm_gpu *gpu, struct msm_ringbuffer *ring, trace_msm_retired(submit, ticks->started, ticks->retired); + pm_runtime_mark_last_busy(&gpu->pdev->dev); + pm_runtime_put_autosuspend(&gpu->pdev->dev); msm_gem_submit_free(submit); } } @@ -550,9 +499,6 @@ static void retire_worker(struct work_struct *work) _retire_ring(gpu, ring, ring->memptrs->fence); mutex_unlock(&dev->struct_mutex); } - - if (!msm_gpu_active(gpu)) - inactive_start(gpu); } /* call from irq handler to schedule work to retire bo's */ @@ -574,7 +520,9 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) submit->fence = FENCE(submit->ring, ++ring->seqno); - inactive_cancel(gpu); + pm_runtime_get_sync(&gpu->pdev->dev); + + msm_gpu_hw_init(gpu); list_add_tail(&submit->node, &ring->submits); @@ -863,23 +811,12 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, gpu->dev = drm; gpu->funcs = funcs; gpu->name = name; - /* - * Set the inactive flag to false, so that when the retire worker - * kicks in from the init path, it knows that it has to turn off the - * clocks. This should be fine to do since this is the init sequence - * and we have an init_lock in msm_open() to protect against bad things - * from happening. - */ - gpu->inactive = false; INIT_LIST_HEAD(&gpu->active_list); INIT_WORK(&gpu->retire_work, retire_worker); - INIT_WORK(&gpu->inactive_work, inactive_worker); INIT_WORK(&gpu->recover_work, recover_worker); - setup_timer(&gpu->inactive_timer, inactive_handler, - (unsigned long)gpu); setup_timer(&gpu->hangcheck_timer, hangcheck_handler, (unsigned long)gpu); @@ -909,8 +846,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, goto fail; } - pm_runtime_enable(&pdev->dev); - ret = get_clocks(pdev, gpu); if (ret) goto fail; @@ -979,6 +914,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, pm_qos_add_request(&gpu->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); + gpu->pdev = pdev; + platform_set_drvdata(pdev, gpu); bs_init(gpu); @@ -1000,7 +937,6 @@ fail: msm_gpu_destroy_address_space(gpu->aspace); msm_gpu_destroy_address_space(gpu->secure_aspace); - pm_runtime_disable(&pdev->dev); return ret; } @@ -1031,7 +967,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) } msm_snapshot_destroy(gpu, gpu->snapshot); - pm_runtime_disable(&pdev->dev); msm_gpu_destroy_address_space(gpu->aspace); msm_gpu_destroy_address_space(gpu->secure_aspace); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index eeebfb746f7f..deb12aed5b28 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -83,6 +83,7 @@ struct msm_gpu_funcs { struct msm_gpu { const char *name; struct drm_device *dev; + struct platform_device *pdev; const struct msm_gpu_funcs *funcs; /* performance counters (hw & sw): */ @@ -103,9 +104,8 @@ struct msm_gpu { /* list of GEM active objects: */ struct list_head active_list; - /* is gpu powered/active? */ - int active_cnt; - bool inactive; + /* does gpu need hw_init? */ + bool needs_hw_init; /* worker for handling active-list retiring: */ struct work_struct retire_work; @@ -139,9 +139,7 @@ struct msm_gpu { /* Hang and Inactivity Detection: */ #define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */ -#define DRM_MSM_INACTIVE_JIFFIES msecs_to_jiffies(DRM_MSM_INACTIVE_PERIOD) - struct timer_list inactive_timer; - struct work_struct inactive_work; + #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */ #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD) struct timer_list hangcheck_timer; @@ -255,6 +253,8 @@ static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val) int msm_gpu_pm_suspend(struct msm_gpu *gpu); int msm_gpu_pm_resume(struct msm_gpu *gpu); +int msm_gpu_hw_init(struct msm_gpu *gpu); + void msm_gpu_perfcntr_start(struct msm_gpu *gpu); void msm_gpu_perfcntr_stop(struct msm_gpu *gpu); int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime, diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 2ca91674a15a..6a741a7ce0f6 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -534,13 +534,7 @@ static int sde_connector_atomic_get_property(struct drm_connector *connector, idx = msm_property_index(&c_conn->property_info, property); if (idx == CONNECTOR_PROP_RETIRE_FENCE) - /* - * Set a fence offset if not a virtual connector, so that the - * fence signals after one additional commit rather than at the - * end of the current one. - */ - rc = sde_fence_create(&c_conn->retire_fence, val, - c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL); + rc = sde_fence_create(&c_conn->retire_fence, val, 0); else /* get cached property value */ rc = msm_property_atomic_get(&c_conn->property_info, @@ -933,6 +927,10 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, "PLL_ENABLE", 0x0, 0, 1, 0, CONNECTOR_PROP_PLL_ENABLE); + msm_property_install_volatile_range(&c_conn->property_info, + "HDCP_VERSION", 0x0, 0, U8_MAX, 0, + CONNECTOR_PROP_HDCP_VERSION); + /* enum/bitmask properties */ msm_property_install_enum(&c_conn->property_info, "topology_name", DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index f9b8c3966d74..0f563ac25da8 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -390,5 +390,22 @@ enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn); */ int sde_connector_get_dpms(struct drm_connector *connector); +/** + * sde_connector_needs_offset - adjust the output fence offset based on + * display type + * @connector: Pointer to drm connector object + * Returns: true if offset is required, false for all other cases. + */ +static inline bool sde_connector_needs_offset(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + + if (!connector) + return false; + + c_conn = to_sde_connector(connector); + return (c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL); +} + #endif /* _SDE_CONNECTOR_H_ */ diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index a0417a0dd12e..30e9d688396f 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -1674,19 +1674,28 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; int i, ret = -EINVAL; + bool conn_offset = 0; if (!crtc || !state) { SDE_ERROR("invalid argument(s)\n"); } else { sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(state); + + for (i = 0; i < cstate->num_connectors; ++i) { + conn_offset = sde_connector_needs_offset( + cstate->connectors[i]); + if (conn_offset) + break; + } + i = msm_property_index(&sde_crtc->property_info, property); if (i == CRTC_PROP_OUTPUT_FENCE) { int offset = sde_crtc_get_property(cstate, CRTC_PROP_OUTPUT_FENCE_OFFSET); - ret = sde_fence_create( - &sde_crtc->output_fence, val, offset); + ret = sde_fence_create(&sde_crtc->output_fence, val, + offset + conn_offset); if (ret) SDE_ERROR("fence create failed\n"); } else { diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 8d821e43afa5..34a32d79f22c 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -69,7 +69,7 @@ * * This is disabled by default. */ -static bool sdecustom; +static bool sdecustom = true; module_param(sdecustom, bool, 0400); MODULE_PARM_DESC(sdecustom, "Enable customizations for sde clients"); diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c index d08cf13c448d..c2d29a084c7f 100644 --- a/drivers/gpu/drm/msm/sde_hdcp_1x.c +++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c @@ -1201,9 +1201,16 @@ static int sde_hdcp_1x_authentication_part2(struct sde_hdcp_1x *hdcp) if (rc) goto error; - /* do not proceed further if no device connected */ - if (!hdcp->current_tp.dev_count) + /* + * Do not proceed further if no device connected + * If no downstream devices are attached to the repeater + * then part II fails. + */ + + if (!hdcp->current_tp.dev_count) { + rc = -EINVAL; goto error; + } rc = sde_hdcp_1x_write_ksv_fifo(hdcp); } while (--v_retry && rc); diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 3fb13c7a0814..78f74b883877 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -65,8 +65,8 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = { }; static void a5xx_irq_storm_worker(struct work_struct *work); -static int _read_fw2_block_header(uint32_t *header, uint32_t id, - uint32_t major, uint32_t minor); +static int _read_fw2_block_header(uint32_t *header, uint32_t remain, + uint32_t id, uint32_t major, uint32_t minor); static void a5xx_gpmu_reset(struct work_struct *work); static int a5xx_gpmu_init(struct adreno_device *adreno_dev); @@ -709,6 +709,7 @@ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) if (data[1] != GPMU_FIRMWARE_ID) goto err; ret = _read_fw2_block_header(&data[2], + data[0] - 2, GPMU_FIRMWARE_ID, adreno_dev->gpucore->gpmu_major, adreno_dev->gpucore->gpmu_minor); @@ -1231,8 +1232,8 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on) kgsl_regwrite(device, A5XX_RBBM_ISDB_CNT, on ? 0x00000182 : 0x00000180); } -static int _read_fw2_block_header(uint32_t *header, uint32_t id, - uint32_t major, uint32_t minor) +static int _read_fw2_block_header(uint32_t *header, uint32_t remain, + uint32_t id, uint32_t major, uint32_t minor) { uint32_t header_size; int i = 1; @@ -1242,7 +1243,8 @@ static int _read_fw2_block_header(uint32_t *header, uint32_t id, header_size = header[0]; /* Headers have limited size and always occur as pairs of words */ - if (header_size > MAX_HEADER_SIZE || header_size % 2) + if (header_size > MAX_HEADER_SIZE || header_size >= remain || + header_size % 2 || header_size == 0) return -EINVAL; /* Sequences must have an identifying id first thing in their header */ if (id == GPMU_SEQUENCE_ID) { @@ -1306,8 +1308,8 @@ static void _load_regfile(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); const struct firmware *fw; - uint32_t block_size = 0, block_total = 0, fw_size; - uint32_t *block; + uint64_t block_size = 0, block_total = 0; + uint32_t fw_size, *block; int ret = -EINVAL; if (!adreno_dev->gpucore->regfw_name) @@ -1329,7 +1331,8 @@ static void _load_regfile(struct adreno_device *adreno_dev) /* All offset numbers calculated from file description */ while (block_total < fw_size) { block_size = block[0]; - if (block_size >= fw_size || block_size < 2) + if (((block_total + block_size) >= fw_size) + || block_size < 5) goto err; if (block[1] != GPMU_SEQUENCE_ID) goto err; @@ -1337,6 +1340,7 @@ static void _load_regfile(struct adreno_device *adreno_dev) /* For now ignore blocks other than the LM sequence */ if (block[4] == LM_SEQUENCE_ID) { ret = _read_fw2_block_header(&block[2], + block_size - 2, GPMU_SEQUENCE_ID, adreno_dev->gpucore->lm_major, adreno_dev->gpucore->lm_minor); @@ -1344,6 +1348,9 @@ static void _load_regfile(struct adreno_device *adreno_dev) goto err; adreno_dev->lm_fw = fw; + + if (block[2] > (block_size - 2)) + goto err; adreno_dev->lm_sequence = block + block[2] + 3; adreno_dev->lm_size = block_size - block[2] - 2; } @@ -1356,7 +1363,7 @@ static void _load_regfile(struct adreno_device *adreno_dev) err: release_firmware(fw); KGSL_PWR_ERR(device, - "Register file failed to load sz=%d bsz=%d header=%d\n", + "Register file failed to load sz=%d bsz=%llu header=%d\n", fw_size, block_size, ret); return; } diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c index 496fc6a9248e..09effbd39a9c 100644 --- a/drivers/gpu/msm/adreno_a5xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c @@ -765,6 +765,8 @@ static void _a5xx_do_crashdump(struct kgsl_device *device) crash_dump_valid = false; + if (!device->snapshot_crashdumper) + return; if (capturescript.gpuaddr == 0 || registers.gpuaddr == 0) return; @@ -870,8 +872,7 @@ void a5xx_snapshot(struct adreno_device *adreno_dev, ARRAY_SIZE(a5xx_vbif_snapshot_registers)); /* Try to run the crash dumper */ - if (device->snapshot_crashdumper) - _a5xx_do_crashdump(device); + _a5xx_do_crashdump(device); kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, a5xx_snapshot_registers, NULL); diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index c46d5ee3c468..3f41b2b44924 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -3439,6 +3439,7 @@ long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv, return 0; } +/* entry->bind_lock must be held by the caller */ static int _sparse_add_to_bind_tree(struct kgsl_mem_entry *entry, uint64_t v_offset, struct kgsl_memdesc *memdesc, @@ -3467,10 +3468,16 @@ static int _sparse_add_to_bind_tree(struct kgsl_mem_entry *entry, parent = *node; this = rb_entry(parent, struct sparse_bind_object, node); - if (new->v_off < this->v_off) + if ((new->v_off < this->v_off) && + ((new->v_off + new->size) <= this->v_off)) node = &parent->rb_left; - else if (new->v_off > this->v_off) + else if ((new->v_off > this->v_off) && + (new->v_off >= (this->v_off + this->size))) node = &parent->rb_right; + else { + kfree(new); + return -EADDRINUSE; + } } rb_link_node(&new->node, parent, node); @@ -3691,8 +3698,11 @@ static int _sparse_bind(struct kgsl_process_private *process, return ret; } + spin_lock(&virt_entry->bind_lock); ret = _sparse_add_to_bind_tree(virt_entry, v_offset, memdesc, p_offset, size, flags); + spin_unlock(&virt_entry->bind_lock); + if (ret == 0) memdesc->cur_bindings += size / PAGE_SIZE; diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c index 28ab4e52dab5..b3aa73f1a5a1 100644 --- a/drivers/iio/adc/qcom-rradc.c +++ b/drivers/iio/adc/qcom-rradc.c @@ -22,6 +22,7 @@ #include <linux/regmap.h> #include <linux/delay.h> #include <linux/qpnp/qpnp-revid.h> +#include <linux/power_supply.h> #define FG_ADC_RR_EN_CTL 0x46 #define FG_ADC_RR_SKIN_TEMP_LSB 0x50 @@ -192,8 +193,7 @@ #define FG_RR_ADC_STS_CHANNEL_READING_MASK 0x3 #define FG_RR_ADC_STS_CHANNEL_STS 0x2 -#define FG_RR_CONV_CONTINUOUS_TIME_MIN_US 50000 -#define FG_RR_CONV_CONTINUOUS_TIME_MAX_US 51000 +#define FG_RR_CONV_CONTINUOUS_TIME_MIN_MS 50 #define FG_RR_CONV_MAX_RETRY_CNT 50 #define FG_RR_TP_REV_VERSION1 21 #define FG_RR_TP_REV_VERSION2 29 @@ -235,6 +235,7 @@ struct rradc_chip { struct device_node *revid_dev_node; struct pmic_revid_data *pmic_fab_id; int volt; + struct power_supply *usb_trig; }; struct rradc_channels { @@ -726,6 +727,24 @@ static int rradc_disable_continuous_mode(struct rradc_chip *chip) return rc; } +static bool rradc_is_usb_present(struct rradc_chip *chip) +{ + union power_supply_propval pval; + int rc; + bool usb_present = false; + + if (!chip->usb_trig) { + pr_debug("USB property not present\n"); + return usb_present; + } + + rc = power_supply_get_property(chip->usb_trig, + POWER_SUPPLY_PROP_PRESENT, &pval); + usb_present = (rc < 0) ? 0 : pval.intval; + + return usb_present; +} + static int rradc_check_status_ready_with_retry(struct rradc_chip *chip, struct rradc_chan_prop *prop, u8 *buf, u16 status) { @@ -745,8 +764,18 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip, (retry_cnt < FG_RR_CONV_MAX_RETRY_CNT)) { pr_debug("%s is not ready; nothing to read:0x%x\n", rradc_chans[prop->channel].datasheet_name, buf[0]); - usleep_range(FG_RR_CONV_CONTINUOUS_TIME_MIN_US, - FG_RR_CONV_CONTINUOUS_TIME_MAX_US); + + if (((prop->channel == RR_ADC_CHG_TEMP) || + (prop->channel == RR_ADC_SKIN_TEMP) || + (prop->channel == RR_ADC_USBIN_I) || + (prop->channel == RR_ADC_DIE_TEMP)) && + ((!rradc_is_usb_present(chip)))) { + pr_debug("USB not present for %d\n", prop->channel); + rc = -ENODATA; + break; + } + + msleep(FG_RR_CONV_CONTINUOUS_TIME_MIN_MS); retry_cnt++; rc = rradc_read(chip, status, buf, 1); if (rc < 0) { @@ -764,7 +793,7 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip, static int rradc_read_channel_with_continuous_mode(struct rradc_chip *chip, struct rradc_chan_prop *prop, u8 *buf) { - int rc = 0; + int rc = 0, ret = 0; u16 status = 0; rc = rradc_enable_continuous_mode(chip); @@ -777,23 +806,25 @@ static int rradc_read_channel_with_continuous_mode(struct rradc_chip *chip, rc = rradc_read(chip, status, buf, 1); if (rc < 0) { pr_err("status read failed:%d\n", rc); - return rc; + ret = rc; + goto disable; } rc = rradc_check_status_ready_with_retry(chip, prop, buf, status); if (rc < 0) { pr_err("Status read failed:%d\n", rc); - return rc; + ret = rc; } +disable: rc = rradc_disable_continuous_mode(chip); if (rc < 0) { pr_err("Failed to switch to non continuous mode\n"); - return rc; + ret = rc; } - return rc; + return ret; } static int rradc_enable_batt_id_channel(struct rradc_chip *chip, bool enable) @@ -1149,6 +1180,10 @@ static int rradc_probe(struct platform_device *pdev) indio_dev->channels = chip->iio_chans; indio_dev->num_channels = chip->nchannels; + chip->usb_trig = power_supply_get_by_name("usb"); + if (!chip->usb_trig) + pr_debug("Error obtaining usb power supply\n"); + return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index b30739de79e7..62230d30d101 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1956,10 +1956,20 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); - arm_smmu_tlb_inv_context(smmu_domain); - arm_smmu_disable_clocks(smmu_domain->smmu); + if (smmu_domain->pgtbl_ops) { + free_io_pgtable_ops(smmu_domain->pgtbl_ops); + /* unassign any freed page table memory */ + if (arm_smmu_is_master_side_secure(smmu_domain)) { + arm_smmu_secure_domain_lock(smmu_domain); + arm_smmu_secure_pool_destroy(smmu_domain); + arm_smmu_unassign_table(smmu_domain); + arm_smmu_secure_domain_unlock(smmu_domain); + } + smmu_domain->pgtbl_ops = NULL; + } + free_irqs: if (cfg->irptndx != INVALID_IRPTNDX) { irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx]; diff --git a/drivers/media/platform/msm/ais/msm.c b/drivers/media/platform/msm/ais/msm.c index ccfdfba2ceee..902e05b3329b 100644 --- a/drivers/media/platform/msm/ais/msm.c +++ b/drivers/media/platform/msm/ais/msm.c @@ -292,6 +292,7 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) return; while (1) { + unsigned long wl_flags; if (try_count > 5) { pr_err("%s : not able to delete stream %d\n", @@ -299,18 +300,20 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) break; } - write_lock(&session->stream_rwlock); + write_lock_irqsave(&session->stream_rwlock, wl_flags); try_count++; stream = msm_queue_find(&session->stream_q, struct msm_stream, list, __msm_queue_find_stream, &stream_id); if (!stream) { - write_unlock(&session->stream_rwlock); + write_unlock_irqrestore(&session->stream_rwlock, + wl_flags); return; } if (msm_vb2_get_stream_state(stream) != 1) { - write_unlock(&session->stream_rwlock); + write_unlock_irqrestore(&session->stream_rwlock, + wl_flags); continue; } @@ -320,7 +323,7 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) kfree(stream); stream = NULL; spin_unlock_irqrestore(&(session->stream_q.lock), flags); - write_unlock(&session->stream_rwlock); + write_unlock_irqrestore(&session->stream_rwlock, wl_flags); break; } diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c index 36aa3f62fbec..1cbc49c8485c 100644 --- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c @@ -47,22 +47,23 @@ static int msm_vb2_buf_init(struct vb2_buffer *vb) struct msm_session *session; struct msm_vb2_buffer *msm_vb2_buf; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + unsigned long rl_flags; session = msm_get_session_from_vb2q(vb->vb2_queue); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s: Couldn't find stream\n", __func__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); msm_vb2_buf->in_freeq = 0; - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return 0; } @@ -71,7 +72,7 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags; + unsigned long flags, rl_flags; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); @@ -84,19 +85,19 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) if (IS_ERR_OR_NULL(session)) return; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return; } spin_lock_irqsave(&stream->stream_lock, flags); list_add_tail(&msm_vb2->list, &stream->queued_list); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); } static void msm_vb2_buf_finish(struct vb2_buffer *vb) @@ -104,7 +105,7 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags; + unsigned long flags, rl_flags; struct msm_vb2_buffer *msm_vb2_entry, *temp; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -118,12 +119,12 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) if (IS_ERR_OR_NULL(session)) return; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return; } @@ -136,7 +137,7 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) } } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); } static void msm_vb2_stop_stream(struct vb2_queue *q) @@ -144,19 +145,19 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) struct msm_vb2_buffer *msm_vb2, *temp; struct msm_stream *stream; struct msm_session *session; - unsigned long flags; + unsigned long flags, rl_flags; struct vb2_v4l2_buffer *vb2_v4l2_buf; session = msm_get_session_from_vb2q(q); if (IS_ERR_OR_NULL(session)) return; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(q); if (!stream) { pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return; } @@ -176,7 +177,7 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); } int msm_vb2_get_stream_state(struct msm_stream *stream) @@ -255,17 +256,17 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags; + unsigned long flags, rl_flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return NULL; } @@ -291,7 +292,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return vb2_v4l2_buf; } @@ -302,18 +303,18 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags; + unsigned long flags, rl_flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return NULL; } @@ -337,7 +338,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return vb2_v4l2_buf; } @@ -349,17 +350,17 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, struct msm_vb2_buffer *msm_vb2; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; int rc = 0; - unsigned long flags; + unsigned long flags, rl_flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -374,6 +375,8 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n", vb, session_id, stream_id); spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock_irqrestore(&session->stream_rwlock, + rl_flags); return -EINVAL; } msm_vb2 = @@ -390,7 +393,7 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return rc; } @@ -398,7 +401,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, unsigned int stream_id, uint32_t sequence, struct timeval *ts, uint32_t reserved) { - unsigned long flags; + unsigned long flags, rl_flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; @@ -409,11 +412,11 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -428,6 +431,8 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n", session_id, stream_id, vb); spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock_irqrestore(&session->stream_rwlock, + rl_flags); return -EINVAL; } msm_vb2 = container_of(vb2_v4l2_buf, @@ -448,7 +453,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return rc; } @@ -459,18 +464,18 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags; + unsigned long flags, rl_flags; long rc = -EINVAL; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return rc; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -499,14 +504,14 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return rc; } EXPORT_SYMBOL(msm_vb2_return_buf_by_idx); static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) { - unsigned long flags; + unsigned long flags, rl_flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; @@ -516,11 +521,11 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -532,7 +537,7 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return 0; } diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c index f6d7f5fb8d32..8a49c7cf9f4a 100644 --- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c @@ -424,7 +424,7 @@ int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, curr_vreg = &cam_vreg[j]; reg_ptr[j] = regulator_get(dev, curr_vreg->reg_name); - if (IS_ERR(reg_ptr[j])) { + if (IS_ERR_OR_NULL(reg_ptr[j])) { pr_err("%s: %s get failed\n", __func__, curr_vreg->reg_name); @@ -531,7 +531,7 @@ int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, continue; } else j = i; - if (IS_ERR(reg_ptr[j])) { + if (IS_ERR_OR_NULL(reg_ptr[j])) { pr_err("%s: %s null regulator\n", __func__, cam_vreg[j].reg_name); goto disable_vreg; diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile index 872dc59d218e..b04560fe42bc 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/Makefile +++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile @@ -5,4 +5,5 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/ ir_cut/ +obj-$(CONFIG_MSMB_CAMERA) += laser_led/ obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index 3cb6b55ccc8c..f2c765a4649f 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -331,6 +331,9 @@ static int32_t msm_cci_addr_to_num_bytes( case MSM_CAMERA_I2C_3B_ADDR: retVal = 3; break; + case MSM_CAMERA_I2C_DWORD_ADDR: + retVal = 4; + break; default: pr_err("%s: %d failed: %d\n", __func__, __LINE__, addr_type); retVal = 1; diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c index 6d9b0e987d0d..fc6ceb1b590f 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c @@ -67,7 +67,8 @@ int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR - && client->addr_type != MSM_CAMERA_I2C_3B_ADDR) + && client->addr_type != MSM_CAMERA_I2C_3B_ADDR + && client->addr_type != MSM_CAMERA_I2C_DWORD_ADDR) || num_byte == 0) return rc; diff --git a/drivers/media/platform/msm/camera_v2/sensor/laser_led/Makefile b/drivers/media/platform/msm/camera_v2/sensor/laser_led/Makefile new file mode 100644 index 000000000000..e981fc2e1f9c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/laser_led/Makefile @@ -0,0 +1,5 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/common +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +obj-$(CONFIG_MSMB_CAMERA) += msm_laser_led.o diff --git a/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c new file mode 100644 index 000000000000..c368f081f97b --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c @@ -0,0 +1,573 @@ +/* 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 <linux/module.h> +#include "msm_laser_led.h" +#include "msm_camera_dt_util.h" +#include "msm_sd.h" +#include "msm_cci.h" + +#undef CDBG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) + +DEFINE_MSM_MUTEX(msm_laser_led_mutex); + +static struct v4l2_file_operations msm_laser_led_v4l2_subdev_fops; + +static const struct of_device_id msm_laser_led_dt_match[] = { + {.compatible = "qcom,laser-led", .data = NULL}, + {} +}; + +static long msm_laser_led_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg); + +static int32_t msm_laser_led_get_subdev_id( + struct msm_laser_led_ctrl_t *laser_led_ctrl, void __user *arg) +{ + int32_t __user *subdev_id = (int32_t __user *)arg; + + CDBG("Enter\n"); + if (!subdev_id) { + pr_err("subdevice ID is not valid\n"); + return -EINVAL; + } + + if (laser_led_ctrl->laser_led_device_type != + MSM_CAMERA_PLATFORM_DEVICE) { + pr_err("device type is not matching\n"); + return -EINVAL; + } + + if (copy_to_user(arg, &laser_led_ctrl->pdev->id, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + CDBG("Exit: subdev_id %d\n", laser_led_ctrl->pdev->id); + return 0; +} + +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; +#ifdef CONFIG_COMPAT +static int32_t msm_laser_led_init( + struct msm_laser_led_ctrl_t *laser_led_ctrl, + struct msm_laser_led_cfg_data_t32 __user *laser_led_data) +#else +static int32_t msm_laser_led_init( + struct msm_laser_led_ctrl_t *laser_led_ctrl, + struct msm_laser_led_cfg_data_t __user *laser_led_data) +#endif +{ + int32_t rc = -EFAULT; + struct msm_camera_cci_client *cci_client = NULL; + + CDBG("Enter\n"); + + if (laser_led_ctrl->laser_led_state == MSM_CAMERA_LASER_LED_INIT) { + pr_err("Invalid laser_led state = %d\n", + laser_led_ctrl->laser_led_state); + return 0; + } + + rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_util( + &laser_led_ctrl->i2c_client, MSM_CCI_INIT); + if (rc < 0) + pr_err("cci_init failed\n"); + + cci_client = laser_led_ctrl->i2c_client.cci_client; + + if (copy_from_user(&(cci_client->sid), + &(laser_led_data->i2c_addr), + sizeof(uint16_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + cci_client->sid = cci_client->sid >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + + if (copy_from_user(&(cci_client->i2c_freq_mode), + &(laser_led_data->i2c_freq_mode), + sizeof(enum i2c_freq_mode_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_INIT; + + CDBG("Exit\n"); + return 0; +} + +static int msm_laser_led_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_laser_led_ctrl_t *l_ctrl = v4l2_get_subdevdata(sd); + + CDBG("Enter\n"); + if (!l_ctrl) { + pr_err("failed: subdev data is null\n"); + return -EINVAL; + } + mutex_lock(l_ctrl->laser_led_mutex); + if (l_ctrl->laser_led_device_type == MSM_CAMERA_PLATFORM_DEVICE && + l_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_RELEASE) { + rc = l_ctrl->i2c_client.i2c_func_tbl->i2c_util( + &l_ctrl->i2c_client, MSM_CCI_RELEASE); + if (rc < 0) + pr_err("cci_init failed: %d\n", rc); + } + l_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE; + mutex_unlock(l_ctrl->laser_led_mutex); + CDBG("Exit\n"); + return rc; +} + +#ifdef CONFIG_COMPAT +static long msm_laser_led_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + int32_t rc = 0; + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + CDBG("Enter\n"); + switch (cmd) { + case VIDIOC_MSM_LASER_LED_CFG32: + cmd = VIDIOC_MSM_LASER_LED_CFG; + default: + rc = msm_laser_led_subdev_ioctl(sd, cmd, arg); + } + + CDBG("Exit\n"); + return rc; +} + +static long msm_laser_led_subdev_fops_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return msm_laser_led_subdev_do_ioctl(file, cmd, (void *)arg); +} + +static int32_t msm_laser_led_control32( + struct msm_laser_led_ctrl_t *laser_led_ctrl, + void __user *argp) +{ + struct msm_camera_i2c_reg_setting32 conf_array32; + struct msm_camera_i2c_reg_setting conf_array; + int32_t rc = 0; + struct msm_laser_led_cfg_data_t32 laser_led_data; + uint32_t *debug_reg; + int i; + uint16_t local_data; + + if (laser_led_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_INIT) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, laser_led_ctrl->laser_led_state); + return -EFAULT; + } + + if (copy_from_user(&laser_led_data, + argp, + sizeof(struct msm_laser_led_cfg_data_t32))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + if (copy_from_user(&conf_array32, + (compat_ptr)(laser_led_data.setting), + sizeof(struct msm_camera_i2c_reg_setting32))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + conf_array.addr_type = conf_array32.addr_type; + conf_array.data_type = conf_array32.data_type; + conf_array.delay = conf_array32.delay; + conf_array.size = conf_array32.size; + + if (!conf_array.size || + conf_array.size > I2C_REG_DATA_MAX) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + conf_array.reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!conf_array.reg_setting) + return -ENOMEM; + + if (copy_from_user(conf_array.reg_setting, + (compat_ptr)(conf_array32.reg_setting), + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(conf_array.reg_setting); + return -EFAULT; + } + + debug_reg = kzalloc(laser_led_data.debug_reg_size * + (sizeof(uint32_t)), GFP_KERNEL); + if (!debug_reg) { + kfree(conf_array.reg_setting); + return -ENOMEM; + } + + if (copy_from_user(debug_reg, + (void __user *)compat_ptr(laser_led_data.debug_reg), + laser_led_data.debug_reg_size * + sizeof(uint32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(conf_array.reg_setting); + kfree(debug_reg); + return -EFAULT; + } + + laser_led_ctrl->i2c_client.addr_type = conf_array.addr_type; + + rc = laser_led_ctrl->i2c_client.i2c_func_tbl-> + i2c_write_table(&(laser_led_ctrl->i2c_client), + &conf_array); + + for (i = 0; i < laser_led_data.debug_reg_size; i++) { + rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(laser_led_ctrl->i2c_client), + debug_reg[i], + &local_data, conf_array.data_type); + } + + kfree(conf_array.reg_setting); + kfree(debug_reg); + + return rc; +} +#endif + +static int32_t msm_laser_led_control( + struct msm_laser_led_ctrl_t *laser_led_ctrl, + void __user *argp) +{ + struct msm_camera_i2c_reg_setting conf_array; + struct msm_laser_led_cfg_data_t laser_led_data; + + uint32_t *debug_reg; + int i; + uint16_t local_data; + int32_t rc = 0; + + if (laser_led_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_INIT) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, laser_led_ctrl->laser_led_state); + return -EFAULT; + } + + if (copy_from_user(&laser_led_data, + argp, + sizeof(struct msm_laser_led_cfg_data_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + if (copy_from_user(&conf_array, + (laser_led_data.setting), + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + if (!conf_array.size || + conf_array.size > I2C_REG_DATA_MAX) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EFAULT; + } + + conf_array.reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!conf_array.reg_setting) + return -ENOMEM; + + if (copy_from_user(conf_array.reg_setting, (void __user *)( + conf_array.reg_setting), + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(conf_array.reg_setting); + return -EFAULT; + } + + debug_reg = kzalloc(laser_led_data.debug_reg_size * + (sizeof(uint32_t)), GFP_KERNEL); + if (!debug_reg) { + kfree(conf_array.reg_setting); + return -ENOMEM; + } + + if (copy_from_user(debug_reg, + (laser_led_data.debug_reg), + laser_led_data.debug_reg_size * + sizeof(uint32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(debug_reg); + kfree(conf_array.reg_setting); + return -EFAULT; + } + + laser_led_ctrl->i2c_client.addr_type = conf_array.addr_type; + + rc = laser_led_ctrl->i2c_client.i2c_func_tbl-> + i2c_write_table(&(laser_led_ctrl->i2c_client), + &conf_array); + + for (i = 0; i < laser_led_data.debug_reg_size; i++) { + rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(laser_led_ctrl->i2c_client), + debug_reg[i], + &local_data, conf_array.data_type); + } + + kfree(conf_array.reg_setting); + kfree(debug_reg); + + return rc; +} + +static int32_t msm_laser_led_config(struct msm_laser_led_ctrl_t *laser_led_ctrl, + void __user *argp) +{ + int32_t rc = -EINVAL; + enum msm_laser_led_cfg_type_t cfg_type; + +#ifdef CONFIG_COMPAT + struct msm_laser_led_cfg_data_t32 __user *laser_led_data = + (struct msm_laser_led_cfg_data_t32 __user *) argp; +#else + struct msm_laser_led_cfg_data_t __user *laser_led_data = + (struct msm_laser_led_cfg_data_t __user *) argp; +#endif + + mutex_lock(laser_led_ctrl->laser_led_mutex); + + if (copy_from_user(&(cfg_type), + &(laser_led_data->cfg_type), + sizeof(enum msm_laser_led_cfg_type_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + mutex_unlock(laser_led_ctrl->laser_led_mutex); + return -EFAULT; + } + + CDBG("type %d\n", cfg_type); + + switch (cfg_type) { + case CFG_LASER_LED_INIT: + rc = msm_laser_led_init(laser_led_ctrl, laser_led_data); + break; + case CFG_LASER_LED_CONTROL: +#ifdef CONFIG_COMPAT + if (is_compat_task()) + rc = msm_laser_led_control32(laser_led_ctrl, argp); + else +#endif + rc = msm_laser_led_control(laser_led_ctrl, argp); + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(laser_led_ctrl->laser_led_mutex); + + CDBG("Exit: type %d\n", cfg_type); + + return rc; +} + +static long msm_laser_led_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_laser_led_ctrl_t *lctrl = NULL; + void __user *argp = (void __user *)arg; + + CDBG("Enter\n"); + + if (!sd) { + pr_err(" v4l2 ir led subdevice is NULL\n"); + return -EINVAL; + } + lctrl = v4l2_get_subdevdata(sd); + if (!lctrl) { + pr_err("lctrl NULL\n"); + return -EINVAL; + } + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return msm_laser_led_get_subdev_id(lctrl, argp); + case VIDIOC_MSM_LASER_LED_CFG: + return msm_laser_led_config(lctrl, argp); + case MSM_SD_NOTIFY_FREEZE: + return 0; + case MSM_SD_SHUTDOWN: + if (!lctrl->i2c_client.i2c_func_tbl) { + pr_err("a_ctrl->i2c_client.i2c_func_tbl NULL\n"); + return -EINVAL; + } + return msm_laser_led_close(sd, NULL); + + default: + pr_err("invalid cmd %d\n", cmd); + return -ENOIOCTLCMD; + } + CDBG("Exit\n"); +} + +static struct v4l2_subdev_core_ops msm_laser_led_subdev_core_ops = { + .ioctl = msm_laser_led_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_laser_led_subdev_ops = { + .core = &msm_laser_led_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_laser_led_internal_ops = { + .close = msm_laser_led_close, +}; + +static int32_t msm_laser_led_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct msm_laser_led_ctrl_t *laser_led_ctrl = NULL; + struct msm_camera_cci_client *cci_client = NULL; + + CDBG("Enter\n"); + if (!pdev->dev.of_node) { + pr_err("IR LED device node is not present in device tree\n"); + return -EINVAL; + } + + laser_led_ctrl = devm_kzalloc(&pdev->dev, + sizeof(struct msm_laser_led_ctrl_t), GFP_KERNEL); + if (!laser_led_ctrl) + return -ENOMEM; + + laser_led_ctrl->pdev = pdev; + + rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index", + &pdev->id); + CDBG("cell-index %d, rc %d\n", pdev->id, rc); + if (rc < 0) { + kfree(laser_led_ctrl); + pr_err("reading cell index failed: rc %d\n", rc); + return rc; + } + + rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master", + &laser_led_ctrl->cci_master); + CDBG("qcom,cci-master %d, rc %d\n", laser_led_ctrl->cci_master, rc); + if (rc < 0 || laser_led_ctrl->cci_master >= MASTER_MAX) { + kfree(laser_led_ctrl); + pr_err("invalid cci master info: rc %d\n", rc); + return rc; + } + + laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE; + laser_led_ctrl->power_info.dev = &laser_led_ctrl->pdev->dev; + laser_led_ctrl->laser_led_device_type = MSM_CAMERA_PLATFORM_DEVICE; + laser_led_ctrl->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl; + laser_led_ctrl->laser_led_mutex = &msm_laser_led_mutex; + + laser_led_ctrl->i2c_client.cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!laser_led_ctrl->i2c_client.cci_client) + return -ENOMEM; + + cci_client = laser_led_ctrl->i2c_client.cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = laser_led_ctrl->cci_master; + + /* Initialize sub device */ + v4l2_subdev_init(&laser_led_ctrl->msm_sd.sd, &msm_laser_led_subdev_ops); + v4l2_set_subdevdata(&laser_led_ctrl->msm_sd.sd, laser_led_ctrl); + + laser_led_ctrl->msm_sd.sd.internal_ops = &msm_laser_led_internal_ops; + laser_led_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(laser_led_ctrl->msm_sd.sd.name, + ARRAY_SIZE(laser_led_ctrl->msm_sd.sd.name), + "msm_camera_laser_led"); + media_entity_init(&laser_led_ctrl->msm_sd.sd.entity, 0, NULL, 0); + laser_led_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + laser_led_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LASER_LED; + laser_led_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; + msm_sd_register(&laser_led_ctrl->msm_sd); + + laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE; + + CDBG("laser_led sd name = %s\n", + laser_led_ctrl->msm_sd.sd.entity.name); + msm_laser_led_v4l2_subdev_fops = v4l2_subdev_fops; +#ifdef CONFIG_COMPAT + msm_laser_led_v4l2_subdev_fops.compat_ioctl32 = + msm_laser_led_subdev_fops_ioctl; +#endif + laser_led_ctrl->msm_sd.sd.devnode->fops = + &msm_laser_led_v4l2_subdev_fops; + + CDBG("probe success\n"); + return rc; +} + +MODULE_DEVICE_TABLE(of, msm_laser_led_dt_match); + +static struct platform_driver msm_laser_led_platform_driver = { + .probe = msm_laser_led_platform_probe, + .driver = { + .name = "qcom,laser-led", + .owner = THIS_MODULE, + .of_match_table = msm_laser_led_dt_match, + }, +}; + +static int __init msm_laser_led_init_module(void) +{ + int32_t rc; + + CDBG("Enter\n"); + rc = platform_driver_register(&msm_laser_led_platform_driver); + if (!rc) { + CDBG("Exit\n"); + return rc; + } + pr_err("laser-led driver register failed: %d\n", rc); + + return rc; +} + +static void __exit msm_laser_led_exit_module(void) +{ + platform_driver_unregister(&msm_laser_led_platform_driver); +} + +module_init(msm_laser_led_init_module); +module_exit(msm_laser_led_exit_module); +MODULE_DESCRIPTION("MSM IR LED"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.h b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.h new file mode 100644 index 000000000000..d5cb8b435d12 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.h @@ -0,0 +1,57 @@ +/* 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 MSM_LASER_LED_H +#define MSM_LASER_LED_H + +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <soc/qcom/camera2.h> +#include <media/v4l2-subdev.h> +#include <media/msmb_camera.h> +#include <linux/platform_device.h> +#include <media/v4l2-ioctl.h> +#include <media/msm_cam_sensor.h> +#include "msm_camera_i2c.h" +#include "msm_camera_dt_util.h" +#include "msm_camera_io_util.h" +#include "msm_sd.h" + + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +enum msm_camera_laser_led_state_t { + MSM_CAMERA_LASER_LED_INIT, + MSM_CAMERA_LASER_LED_RELEASE, +}; + +struct msm_laser_led_ctrl_t; + +struct msm_laser_led_ctrl_t { + struct msm_sd_subdev msm_sd; + struct platform_device *pdev; + struct msm_laser_led_func_t *func_tbl; + struct msm_camera_power_ctrl_t power_info; + struct i2c_driver *i2c_driver; + struct platform_driver *pdriver; + struct msm_camera_i2c_client i2c_client; + enum msm_camera_device_type_t laser_led_device_type; + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *laser_led_v4l2_subdev_ops; + struct mutex *laser_led_mutex; + enum msm_camera_laser_led_state_t laser_led_state; + enum cci_i2c_master_t cci_master; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 57bc392f54fd..167ed5492088 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -297,6 +297,45 @@ static int32_t msm_sensor_fill_actuator_subdevid_by_name( return rc; } +static int32_t msm_sensor_fill_laser_led_subdevid_by_name( + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + struct device_node *src_node = NULL; + uint32_t val = 0; + int32_t *laser_led_subdev_id; + struct msm_sensor_info_t *sensor_info; + struct device_node *of_node = s_ctrl->of_node; + + if (!of_node) + return -EINVAL; + + sensor_info = s_ctrl->sensordata->sensor_info; + laser_led_subdev_id = &sensor_info->subdev_id[SUB_MODULE_LASER_LED]; + /* set sudev id to -1 and try to found new id */ + *laser_led_subdev_id = -1; + + + src_node = of_parse_phandle(of_node, "qcom,laserled-src", 0); + if (!src_node) { + CDBG("%s:%d src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,laser led cell index %d, rc %d\n", __func__, + val, rc); + of_node_put(src_node); + src_node = NULL; + if (rc < 0) { + pr_err("%s cell index not found %d\n", + __func__, __LINE__); + return -EINVAL; + } + *laser_led_subdev_id = val; + } + + return rc; +} + static int32_t msm_sensor_fill_flash_subdevid_by_name( struct msm_sensor_ctrl_t *s_ctrl) { @@ -981,6 +1020,11 @@ CSID_TG: pr_err("%s failed %d\n", __func__, __LINE__); goto free_camera_info; } + rc = msm_sensor_fill_laser_led_subdevid_by_name(s_ctrl); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto free_camera_info; + } rc = msm_sensor_fill_ois_subdevid_by_name(s_ctrl); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c index 302a7b16bc26..d3d48b0bbe4c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c @@ -33,6 +33,30 @@ static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl); static struct i2c_driver msm_ois_i2c_driver; +static int32_t data_type_to_num_bytes( + enum msm_camera_i2c_data_type data_type) +{ + int32_t ret_val; + + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + ret_val = 1; + break; + case MSM_CAMERA_I2C_WORD_DATA: + ret_val = 2; + break; + case MSM_CAMERA_I2C_DWORD_DATA: + ret_val = 4; + break; + default: + pr_err("unsupported data type: %d\n", + data_type); + ret_val = 1; + break; + } + return ret_val; +} + static int32_t msm_ois_download(struct msm_ois_ctrl_t *o_ctrl) { uint16_t bytes_in_tx = 0; @@ -155,7 +179,9 @@ static int32_t msm_ois_write_settings(struct msm_ois_ctrl_t *o_ctrl, uint16_t size, struct reg_settings_ois_t *settings) { int32_t rc = -EFAULT; - int32_t i = 0; + int32_t i = 0, num_byte_seq = 0; + uint8_t *reg_data_seq; + struct msm_camera_i2c_seq_reg_array *reg_setting; CDBG("Enter\n"); @@ -233,13 +259,51 @@ static int32_t msm_ois_write_settings(struct msm_ois_ctrl_t *o_ctrl, settings[i].data_type); break; } + break; } + case MSM_OIS_READ: { + switch (settings[i].data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + case MSM_CAMERA_I2C_DWORD_DATA: + + num_byte_seq = + data_type_to_num_bytes + (settings[i].data_type); + reg_data_seq = kzalloc(sizeof(uint32_t), + GFP_KERNEL); + if (!reg_data_seq) + return -ENOMEM; + + rc = msm_camera_cci_i2c_read_seq + (&o_ctrl->i2c_client, + settings[i].reg_addr, + reg_data_seq, + num_byte_seq); + + memcpy(&settings[i].reg_data, + reg_data_seq, sizeof(uint32_t)); + + CDBG("ois data read 0x%x from address 0x%x", + settings[i].reg_addr, + settings[i].reg_data); + + kfree(reg_data_seq); + reg_data_seq = NULL; + + break; + default: + pr_err("Unsupport data type for MSM_OIS_READ: %d\n", + settings[i].data_type); + break; + } + break; } if (rc < 0) break; + } } - CDBG("Exit\n"); return rc; } @@ -348,7 +412,7 @@ static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl, struct msm_ois_set_info_t *set_info) { struct reg_settings_ois_t *settings = NULL; - int32_t rc = 0; + int32_t rc = 0, i = 0; struct msm_camera_cci_client *cci_client = NULL; CDBG("Enter\n"); @@ -390,6 +454,18 @@ static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl, rc = msm_ois_write_settings(o_ctrl, set_info->ois_params.setting_size, settings); + + for (i = 0; i < set_info->ois_params.setting_size; i++) { + if (set_info->ois_params.settings[i].i2c_operation + == MSM_OIS_READ) { + set_info->ois_params.settings[i].reg_data = + settings[i].reg_data; + CDBG("ois_data at addr 0x%x is 0x%x", + set_info->ois_params.settings[i].reg_addr, + set_info->ois_params.settings[i].reg_data); + } + } + kfree(settings); if (rc < 0) { pr_err("Error\n"); @@ -402,7 +478,6 @@ static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl, return rc; } - static int32_t msm_ois_config(struct msm_ois_ctrl_t *o_ctrl, void __user *argp) { diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index 037c6f3b12ab..53de11d7abf1 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -2180,6 +2180,15 @@ int create_pkt_cmd_session_set_property( pkt->size += sizeof(u32) + sizeof(struct hfi_iframe_size); break; } + case HAL_PARAM_VENC_SEND_OUTPUT_FOR_SKIPPED_FRAME: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_SEND_OUTPUT_FOR_SKIPPED_FRAMES, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32) + sizeof(struct hfi_enable); + break; + } + /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ case HAL_CONFIG_BUFFER_REQUIREMENTS: case HAL_CONFIG_PRIORITY: diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 947ade9c99ed..ec6695a670b0 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1423,7 +1423,16 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { (1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED)), .qmenu = iframe_sizes, }, - + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME, + .name = "Send encoder output buffer for skipped frames", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME_DISABLE, + .maximum = V4L2_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME_ENABLE, + .default_value = + V4L2_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME_DISABLE, + .step = 1, + } }; #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls) @@ -3712,6 +3721,25 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) ctrl->val); pdata = &iframesize_type; break; + case V4L2_CID_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME: + property_id = HAL_PARAM_VENC_SEND_OUTPUT_FOR_SKIPPED_FRAME; + switch (ctrl->val) { + case V4L2_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME_ENABLE: + enable.enable = 1; + break; + case V4L2_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME_DISABLE: + enable.enable = 0; + break; + default: + dprintk(VIDC_ERR, + "Invalid send skipped frames control value %d\n", + ctrl->val); + rc = -ENOTSUPP; + break; + } + pdata = &enable; + break; + default: dprintk(VIDC_ERR, "Unsupported index: %x\n", ctrl->id); rc = -ENOTSUPP; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 6cc5f9f50ba1..d946b035b284 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -243,6 +243,7 @@ enum hal_property { HAL_PARAM_VENC_H264_TRANSFORM_8x8, HAL_PARAM_VENC_VIDEO_SIGNAL_INFO, HAL_PARAM_VENC_IFRAMESIZE_TYPE, + HAL_PARAM_VENC_SEND_OUTPUT_FOR_SKIPPED_FRAME }; enum hal_domain { diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 31af06cd88ef..1218f0a86bc4 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -388,6 +388,8 @@ struct hfi_buffer_info { (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x033) #define HFI_PROPERTY_PARAM_VENC_IFRAMESIZE \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x034) +#define HFI_PROPERTY_PARAM_VENC_SEND_OUTPUT_FOR_SKIPPED_FRAMES \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x035) #define HFI_PROPERTY_CONFIG_VENC_COMMON_START \ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index cf897947fff2..8c48a5c05bbe 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -3122,6 +3122,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, struct qseecom_send_cmd_req *req) { int ret = 0; + int ret2 = 0; u32 reqd_len_sb_in = 0; struct qseecom_client_send_data_ireq send_data_req = {0}; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0}; @@ -3220,32 +3221,38 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); - return ret; + goto exit; } if (qseecom.qsee_reentrancy_support) { ret = __qseecom_process_reentrancy(&resp, ptr_app, data); + if (ret) + goto exit; } else { if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { pr_err("process_incomplete_cmd failed err: %d\n", ret); - return ret; + goto exit; } } else { if (resp.result != QSEOS_RESULT_SUCCESS) { pr_err("Response result %d not supported\n", resp.result); ret = -EINVAL; + goto exit; } } } - ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, +exit: + ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_INV_CACHES); - if (ret) - pr_err("cache operation failed %d\n", ret); + if (ret2) { + pr_err("cache operation failed %d\n", ret2); + return ret2; + } return ret; } @@ -6566,6 +6573,7 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, bool found_app = false; unsigned long flags; int ret = 0; + int ret2 = 0; uint32_t reqd_len_sb_in = 0; void *cmd_buf = NULL; size_t cmd_len; @@ -6675,43 +6683,47 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); - return ret; + goto exit; } if (qseecom.qsee_reentrancy_support) { ret = __qseecom_process_reentrancy(&resp, ptr_app, data); + if (ret) + goto exit; } else { if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { pr_err("process_incomplete_cmd failed err: %d\n", ret); - return ret; + goto exit; } } else { if (resp.result != QSEOS_RESULT_SUCCESS) { pr_err("Response result %d not supported\n", resp.result); ret = -EINVAL; + goto exit; } } } - ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, +exit: + ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_INV_CACHES); - if (ret) { + if (ret2) { pr_err("cache operation failed %d\n", ret); - return ret; + return ret2; } if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { - ret = __qseecom_update_qteec_req_buf( + ret2 = __qseecom_update_qteec_req_buf( (struct qseecom_qteec_modfd_req *)req, data, true); - if (ret) - return ret; + if (ret2) + return ret2; } - return 0; + return ret; } static int qseecom_qteec_open_session(struct qseecom_dev_handle *data, diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c002fa5ff602..4ff6213f0e6e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1224,16 +1224,16 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ioc_err = __mmc_blk_ioctl_cmd(card, md, idata); - mmc_put_card(card); - - err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); - if (mmc_card_cmdq(card)) { if (mmc_cmdq_halt(card->host, false)) pr_err("%s: %s: cmdq unhalt failed\n", mmc_hostname(card->host), __func__); } + mmc_put_card(card); + + err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); + cmd_done: mmc_blk_put(md); cmd_err: diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0da9c5caea13..0a26a07e7aee 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -4165,6 +4165,18 @@ int mmc_detect_card_removed(struct mmc_host *host) } EXPORT_SYMBOL(mmc_detect_card_removed); +/* + * This should be called to make sure that detect work(mmc_rescan) + * is completed.Drivers may use this function from async schedule/probe + * contexts to make sure that the bootdevice detection is completed on + * completion of async_schedule. + */ +void mmc_flush_detect_work(struct mmc_host *host) +{ + flush_delayed_work(&host->detect); +} +EXPORT_SYMBOL(mmc_flush_detect_work); + void mmc_rescan(struct work_struct *work) { unsigned long flags; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index df3fce93b6d1..45d2f69f5f1a 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -4747,6 +4747,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) mmc_hostname(host->mmc), __func__, ret); device_remove_file(&pdev->dev, &msm_host->auto_cmd21_attr); } + if (sdhci_msm_is_bootdevice(&pdev->dev)) + mmc_flush_detect_work(host->mmc); + /* Successful initialization */ goto out; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4bb14d43e136..01175d94adca 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5479,7 +5479,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct cfg80211_scan_request *req = &hw_req->req; struct wmi_start_scan_arg arg; - int ret = 0; + const u8 *ptr; + int ret = 0, ie_skip_len = 0; int i; mutex_lock(&ar->conf_mutex); @@ -5511,8 +5512,16 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.scan_id = ATH10K_SCAN_ID; if (req->ie_len) { - arg.ie_len = req->ie_len; - memcpy(arg.ie, req->ie, arg.ie_len); + if (QCA_REV_WCN3990(ar)) { + ptr = req->ie; + while (ptr[0] == WLAN_EID_SUPP_RATES || + ptr[0] == WLAN_EID_EXT_SUPP_RATES) { + ie_skip_len = ptr[1] + 2; + ptr += ie_skip_len; + } + } + arg.ie_len = req->ie_len - ie_skip_len; + memcpy(arg.ie, req->ie + ie_skip_len, arg.ie_len); } if (req->n_ssids) { @@ -5521,6 +5530,11 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.ssids[i].len = req->ssids[i].ssid_len; arg.ssids[i].ssid = req->ssids[i].ssid; } + if (QCA_REV_WCN3990(ar)) { + arg.scan_ctrl_flags &= + ~(WMI_SCAN_ADD_BCAST_PROBE_REQ | + WMI_SCAN_CHAN_STAT_EVENT); + } } else { arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; } @@ -6419,7 +6433,13 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, arg.dwell_time_passive = scan_time_msec; arg.max_scan_time = scan_time_msec; arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; - arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + if (QCA_REV_WCN3990(ar)) { + arg.scan_ctrl_flags &= ~(WMI_SCAN_FILTER_PROBE_REQ | + WMI_SCAN_CHAN_STAT_EVENT | + WMI_SCAN_ADD_BCAST_PROBE_REQ); + } else { + arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + } arg.burst_duration_ms = duration; ret = ath10k_start_scan(ar, &arg); diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index f5aa88a76f17..c42d7eebf465 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -27,6 +27,8 @@ #include "qmi.h" #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> #define WCN3990_MAX_IRQ 12 @@ -48,6 +50,7 @@ const char *ce_name[WCN3990_MAX_IRQ] = { #define ATH10K_SNOC_TARGET_WAIT 3000 #define ATH10K_SNOC_NUM_WARM_RESET_ATTEMPTS 3 #define SNOC_HIF_POWER_DOWN_DELAY 30 +#define ATH10K_MAX_PROP_SIZE 32 static void ath10k_snoc_buffer_cleanup(struct ath10k *ar); static int ath10k_snoc_request_irq(struct ath10k *ar); @@ -1248,6 +1251,326 @@ int ath10k_snoc_pm_notifier(struct notifier_block *nb, return NOTIFY_DONE; } +static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev, + struct ath10k_wcn3990_vreg_info *vreg_info) +{ + int ret = 0; + char prop_name[ATH10K_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) { + ath10k_err(ar, "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) { + ath10k_err(ar, "Regulator %s doesn't exist: %d\n", + vreg_info->name, ret); + goto out; + } else { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Optional regulator %s doesn't exist: %d\n", + vreg_info->name, ret); + goto done; + } + } + + vreg_info->reg = reg; + + snprintf(prop_name, ATH10K_MAX_PROP_SIZE, + "qcom,%s-config", vreg_info->name); + + prop = of_get_property(dev->of_node, prop_name, &len); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Got regulator cfg,prop: %s, len: %d\n", + prop_name, len); + + if (!prop || len < (2 * sizeof(__be32))) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, "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: + ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s, ignoring val %d\n", + prop_name, i); + break; + } + } + +done: + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "vreg: %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 ath10k_get_clk_info(struct ath10k *ar, struct device *dev, + struct ath10k_wcn3990_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) { + ath10k_err(ar, "Clock %s isn't available: %d\n", + clk_info->name, ret); + goto out; + } else { + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Ignoring clk %s: %d\n", + clk_info->name, + ret); + ret = 0; + goto out; + } + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Clock: %s, freq: %u\n", + clk_info->name, clk_info->freq); + + clk_info->handle = handle; +out: + return ret; +} + +static int ath10k_wcn3990_vreg_on(struct ath10k *ar) +{ + int ret = 0; + struct ath10k_wcn3990_vreg_info *vreg_info; + int i; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + for (i = 0; i < ATH10K_WCN3990_VREG_INFO_SIZE; i++) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "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) { + ath10k_err(ar, + "vreg %s, set failed:min:%u,max:%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) { + ath10k_err(ar, + "Reg %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) { + ath10k_err(ar, "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 = &ar_snoc->vreg[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 ath10k_wcn3990_vreg_off(struct ath10k *ar) +{ + int ret = 0; + struct ath10k_wcn3990_vreg_info *vreg_info; + int i; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + for (i = ATH10K_WCN3990_VREG_INFO_SIZE - 1; i >= 0; i--) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Regulator %s being disabled\n", + vreg_info->name); + + ret = regulator_disable(vreg_info->reg); + if (ret) + ath10k_err(ar, "Regulator %s, can't disable: %d\n", + vreg_info->name, ret); + + ret = regulator_set_load(vreg_info->reg, 0); + if (ret < 0) + ath10k_err(ar, "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) + ath10k_err(ar, "Regulator %s, can't set voltage: %d\n", + vreg_info->name, ret); + } + + return ret; +} + +static int ath10k_wcn3990_clk_init(struct ath10k *ar) +{ + struct ath10k_wcn3990_clk_info *clk_info; + int i; + int ret = 0; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + for (i = 0; i < ATH10K_WCN3990_CLK_INFO_SIZE; i++) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Clock %s being enabled\n", + clk_info->name); + + if (clk_info->freq) { + ret = clk_set_rate(clk_info->handle, clk_info->freq); + + if (ret) { + ath10k_err(ar, "Clk %s,set err: %u,ret: %d\n", + clk_info->name, clk_info->freq, + ret); + break; + } + } + + ret = clk_prepare_enable(clk_info->handle); + if (ret) { + ath10k_err(ar, "Clock %s, can't enable: %d\n", + clk_info->name, ret); + break; + } + } + + if (ret == 0) + return 0; + + for (; i >= 0; i--) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + clk_disable_unprepare(clk_info->handle); + } + + return ret; +} + +static int ath10k_wcn3990_clk_deinit(struct ath10k *ar) +{ + struct ath10k_wcn3990_clk_info *clk_info; + int i; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + for (i = 0; i < ATH10K_WCN3990_CLK_INFO_SIZE; i++) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Clock %s being disabled\n", + clk_info->name); + + clk_disable_unprepare(clk_info->handle); + } + + return 0; +} + +static int ath10k_hw_power_on(struct ath10k *ar) +{ + int ret = 0; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "HW Power on\n"); + + ret = ath10k_wcn3990_vreg_on(ar); + if (ret) + goto out; + + ret = ath10k_wcn3990_clk_init(ar); + if (ret) + goto vreg_off; + + return ret; + +vreg_off: + ath10k_wcn3990_vreg_off(ar); +out: + return ret; +} + +static int ath10k_hw_power_off(struct ath10k *ar) +{ + int ret = 0; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "HW Power off\n"); + + ath10k_wcn3990_clk_deinit(ar); + + ret = ath10k_wcn3990_vreg_off(ar); + + return ret; +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .tx_sg = ath10k_snoc_hif_tx_sg, .start = ath10k_snoc_hif_start, @@ -1275,6 +1598,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) enum ath10k_hw_rev hw_rev; struct device *dev; u32 chip_id; + u32 i; dev = &pdev->dev; hw_rev = ATH10K_HW_WCN3990; @@ -1308,22 +1632,43 @@ static int ath10k_snoc_probe(struct platform_device *pdev) setup_timer(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, (unsigned long)ar); + memcpy(ar_snoc->vreg, vreg_cfg, sizeof(vreg_cfg)); + for (i = 0; i < ATH10K_WCN3990_VREG_INFO_SIZE; i++) { + ret = ath10k_get_vreg_info(ar, dev, &ar_snoc->vreg[i]); + if (ret) + goto err_core_destroy; + } + + memcpy(ar_snoc->clk, clk_cfg, sizeof(clk_cfg)); + for (i = 0; i < ATH10K_WCN3990_CLK_INFO_SIZE; i++) { + ret = ath10k_get_clk_info(ar, dev, &ar_snoc->clk[i]); + if (ret) + goto err_core_destroy; + } + + ret = ath10k_hw_power_on(ar); + if (ret) { + ath10k_err(ar, "failed to power on device: %d\n", ret); + goto err_stop_qmi_service; + } + ret = ath10k_snoc_claim(ar); if (ret) { ath10k_err(ar, "failed to claim device: %d\n", ret); - goto err_stop_qmi_service; + goto err_hw_power_off; } + ret = ath10k_snoc_bus_configure(ar); if (ret) { ath10k_err(ar, "failed to configure bus: %d\n", ret); - goto err_stop_qmi_service; + goto err_hw_power_off; } ret = ath10k_snoc_alloc_pipes(ar); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", ret); - goto err_stop_qmi_service; + goto err_hw_power_off; } netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll, @@ -1359,6 +1704,9 @@ err_free_irq: err_free_pipes: ath10k_snoc_free_pipes(ar); +err_hw_power_off: + ath10k_hw_power_off(ar); + err_stop_qmi_service: ath10k_snoc_stop_qmi_service(ar); @@ -1389,6 +1737,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_snoc_release_resource(ar); ath10k_snoc_free_pipes(ar); ath10k_snoc_stop_qmi_service(ar); + ath10k_hw_power_off(ar); ath10k_core_destroy(ar); return 0; diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index d6e05ba18cb8..a02cb2ad928e 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -17,6 +17,7 @@ #include "ce.h" #include "pci.h" #include "qmi.h" +#include <linux/kernel.h> #include <soc/qcom/service-locator.h> #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 @@ -112,6 +113,38 @@ struct ath10k_snoc_ce_irq { u32 irq_line; }; +struct ath10k_wcn3990_vreg_info { + struct regulator *reg; + const char *name; + u32 min_v; + u32 max_v; + u32 load_ua; + unsigned long settle_delay; + bool required; +}; + +struct ath10k_wcn3990_clk_info { + struct clk *handle; + const char *name; + u32 freq; + bool required; +}; + +static struct ath10k_wcn3990_vreg_info vreg_cfg[] = { + {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false}, + {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 ATH10K_WCN3990_VREG_INFO_SIZE ARRAY_SIZE(vreg_cfg) + +static struct ath10k_wcn3990_clk_info clk_cfg[] = { + {NULL, "cxo_ref_clk_pin", 0, false}, +}; + +#define ATH10K_WCN3990_CLK_INFO_SIZE ARRAY_SIZE(clk_cfg) + /* struct ath10k_snoc: SNOC info struct * @dev: device structure * @ar:ath10k base structure @@ -157,6 +190,8 @@ struct ath10k_snoc { atomic_t fw_crashed; atomic_t pm_ops_inprogress; struct ath10k_snoc_qmi_config qmi_cfg; + struct ath10k_wcn3990_vreg_info vreg[ATH10K_WCN3990_VREG_INFO_SIZE]; + struct ath10k_wcn3990_clk_info clk[ATH10K_WCN3990_CLK_INFO_SIZE]; }; struct ath10k_event_pd_down_data { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 07b15f4c1db4..f5360444a083 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1553,11 +1553,7 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, cmd->ie_len = __cpu_to_le32(arg->ie_len); cmd->num_probes = __cpu_to_le32(3); - if (QCA_REV_WCN3990(ar)) { - cmd->common.scan_ctrl_flags = ar->fw_flags->flags; - cmd->common.scan_ctrl_flags |= - __cpu_to_le32(WMI_SCAN_CHAN_STAT_EVENT); - } else { + if (!QCA_REV_WCN3990(ar)) { cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index d6ec0de63582..86aedff096f6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -6192,6 +6192,8 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar, | WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHANNEL | WMI_SCAN_EVENT_DEQUEUED; + if (QCA_REV_WCN3990(ar)) + arg->scan_ctrl_flags = ar->fw_flags->flags; arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT; arg->n_bssids = 1; arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7ae07a505c59..f59e5f86708b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2960,6 +2960,8 @@ struct wmi_start_scan_arg { /* Different FW scan engine may choose to bail out on errors. * Allow the driver to have influence over that. */ #define WMI_SCAN_CONTINUE_ON_ERROR 0x80 +/** add DS content in probe req frame */ +#define WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ 0x800 /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ #define WMI_SCAN_CLASS_MASK 0xFF000000 diff --git a/drivers/net/wireless/ath/wil6210/ftm.c b/drivers/net/wireless/ath/wil6210/ftm.c index 6891a38d7a59..d856e091a5de 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.c +++ b/drivers/net/wireless/ath/wil6210/ftm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -38,6 +38,9 @@ /* initial token to use on non-secure FTM measurement */ #define WIL_TOF_FTM_DEFAULT_INITIAL_TOKEN 2 +/* maximum AOA burst period, limited by FW */ +#define WIL_AOA_MAX_BURST_PERIOD 255 + #define WIL_TOF_FTM_MAX_LCI_LENGTH (240) #define WIL_TOF_FTM_MAX_LCR_LENGTH (240) @@ -62,6 +65,7 @@ nla_policy wil_nl80211_ftm_peer_policy[ [QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED }, [QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID] = { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD] = { .type = NLA_U16 }, [QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 }, }; @@ -311,8 +315,8 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil, struct wmi_tof_session_start_cmd *cmd; mutex_lock(&wil->ftm.lock); - if (wil->ftm.session_started) { - wil_err(wil, "FTM session already running\n"); + if (wil->ftm.session_started || wil->ftm.aoa_started) { + wil_err(wil, "FTM or AOA session already running\n"); rc = -EAGAIN; goto out; } @@ -356,6 +360,7 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil, } cmd->session_id = cpu_to_le32(WIL_FTM_FW_SESSION_ID); + cmd->aoa_type = request->aoa_type; cmd->num_of_dest = cpu_to_le16(request->n_peers); for (i = 0; i < request->n_peers; i++) { ether_addr_copy(cmd->ftm_dest_info[i].dst_mac, @@ -398,6 +403,8 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil, request->peers[i].params.burst_duration; cmd->ftm_dest_info[i].burst_period = cpu_to_le16(request->peers[i].params.burst_period); + cmd->ftm_dest_info[i].num_burst_per_aoa_meas = + request->peers[i].aoa_burst_period; } rc = wmi_send(wil, WMI_TOF_SESSION_START_CMDID, cmd, cmd_len); @@ -482,8 +489,8 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil, mutex_lock(&wil->ftm.lock); - if (wil->ftm.aoa_started) { - wil_err(wil, "AOA measurement already running\n"); + if (wil->ftm.aoa_started || wil->ftm.session_started) { + wil_err(wil, "AOA or FTM measurement already running\n"); rc = -EAGAIN; goto out; } @@ -524,8 +531,8 @@ void wil_aoa_cfg80211_meas_result(struct wil6210_priv *wil, mutex_lock(&wil->ftm.lock); - if (!wil->ftm.aoa_started) { - wil_info(wil, "AOA not started, not sending result\n"); + if (!wil->ftm.aoa_started && !wil->ftm.session_started) { + wil_info(wil, "AOA/FTM not started, not sending result\n"); goto out; } @@ -749,6 +756,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX + 1]; struct nlattr *peer; int rc, n_peers = 0, index = 0, tmp; + u32 aoa_type = 0; if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities)) return -ENOTSUPP; @@ -770,6 +778,14 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, return -EINVAL; } + if (tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]) { + aoa_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]); + if (aoa_type >= QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX) { + wil_err(wil, "invalid AOA type: %d\n", aoa_type); + return -EINVAL; + } + } + nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS], tmp) n_peers++; @@ -793,6 +809,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, request->session_cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE]); + request->aoa_type = aoa_type; request->n_peers = n_peers; nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS], tmp) { @@ -821,6 +838,18 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID]) request->peers[index].secure_token_id = nla_get_u8( tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID]); + if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD]) { + request->peers[index].aoa_burst_period = nla_get_u16( + tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD]); + if (request->peers[index].aoa_burst_period > + WIL_AOA_MAX_BURST_PERIOD) { + wil_err(wil, "Invalid AOA burst period at index: %d\n", + index); + rc = -EINVAL; + goto out; + } + } + rc = wil_ftm_parse_meas_params( wil, tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS], diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h index 8efa292d5ff4..21923c27ec06 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.h +++ b/drivers/net/wireless/ath/wil6210/ftm.h @@ -437,12 +437,14 @@ struct wil_ftm_meas_peer_info { u32 flags; /* enum qca_wlan_vendor_attr_ftm_peer_meas_flags */ struct wil_ftm_meas_params params; u8 secure_token_id; + u16 aoa_burst_period; /* 0 if no AOA, >0 every <value> bursts */ }; /* session request, passed to wil_ftm_cfg80211_start_session */ struct wil_ftm_session_request { u64 session_cookie; u32 n_peers; + u32 aoa_type; /* enum qca_wlan_vendor_attr_aoa_type */ /* keep last, variable size according to n_peers */ struct wil_ftm_meas_peer_info peers[0]; }; diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c index 35d7fe1c318c..916820ee4f5d 100644 --- a/drivers/net/wireless/cnss2/debug.c +++ b/drivers/net/wireless/cnss2/debug.c @@ -158,6 +158,7 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp, } else if (sysfs_streq(cmd, "enumerate")) { ret = cnss_pci_init(plat_priv); } else if (sysfs_streq(cmd, "download")) { + set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state); ret = cnss_pci_start_mhi(plat_priv->bus_priv); } else if (sysfs_streq(cmd, "linkup")) { ret = cnss_resume_pci_link(plat_priv->bus_priv); diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 23a81ff071ee..c033d843949f 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -1613,7 +1613,7 @@ int cnss_force_fw_assert(struct device *dev) if (plat_priv->device_id == QCA6174_DEVICE_ID) { cnss_pr_info("Forced FW assert is not supported\n"); - return -EINVAL; + return -EOPNOTSUPP; } if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { diff --git a/drivers/net/wireless/cnss_genl/cnss_nl.c b/drivers/net/wireless/cnss_genl/cnss_nl.c index fafd9ce4b4c4..29dd4c999f2d 100644 --- a/drivers/net/wireless/cnss_genl/cnss_nl.c +++ b/drivers/net/wireless/cnss_genl/cnss_nl.c @@ -64,6 +64,8 @@ static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX + 1] = { [CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED }, [CLD80211_ATTR_DATA] = { .type = NLA_BINARY, .len = CLD80211_MAX_NL_DATA }, + [CLD80211_ATTR_META_DATA] = { .type = NLA_BINARY, + .len = CLD80211_MAX_NL_DATA }, }; static int cld80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c index dc05d7108135..adf47fc32548 100644 --- a/drivers/platform/msm/gpio-usbdetect.c +++ b/drivers/platform/msm/gpio-usbdetect.c @@ -50,6 +50,7 @@ static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data) if (usb->vbus_state) { dev_dbg(&usb->pdev->dev, "setting vbus notification\n"); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_SPEED, 1); } else { dev_dbg(&usb->pdev->dev, "setting vbus removed notification\n"); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0); @@ -85,6 +86,7 @@ static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data) dev_dbg(&usb->pdev->dev, "starting usb HOST\n"); disable_irq(usb->vbus_det_irq); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_SPEED, 1); } return IRQ_HANDLED; } @@ -186,6 +188,14 @@ static int gpio_usbdetect_probe(struct platform_device *pdev) enable_irq_wake(usb->id_det_irq); dev_set_drvdata(&pdev->dev, usb); + if (usb->id_det_irq) { + gpio_usbdetect_id_irq(usb->id_det_irq, usb); + if (!usb->id_state) { + gpio_usbdetect_id_irq_thread(usb->id_det_irq, usb); + return 0; + } + } + /* Read and report initial VBUS state */ gpio_usbdetect_vbus_irq(usb->vbus_det_irq, usb); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index 4275e3d26157..8b8ed72c2076 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -812,10 +812,11 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, eq = true; } else { rt_tbl = ipa_id_find(entry->rule.rt_tbl_hdl); - if (rt_tbl) - rt_tbl_idx = rt_tbl->idx; + if (rt_tbl == NULL || + rt_tbl->cookie != IPA_RT_TBL_COOKIE) + rt_tbl_idx = ~0; else - rt_tbl_idx = ~0; + rt_tbl_idx = rt_tbl->idx; bitmap = entry->rule.attrib.attrib_mask; eq = false; } @@ -842,10 +843,11 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, eq = true; } else { rt_tbl = ipa_id_find(entry->rule.rt_tbl_hdl); - if (rt_tbl) - rt_tbl_idx = rt_tbl->idx; - else + if (rt_tbl == NULL || + rt_tbl->cookie != IPA_RT_TBL_COOKIE) rt_tbl_idx = ~0; + else + rt_tbl_idx = rt_tbl->idx; bitmap = entry->rule.attrib.attrib_mask; eq = false; } diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 5dbd43b44540..12b43882ed5b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -411,12 +411,15 @@ int copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 { int i, j; + /* prevent multi-threads accessing num_q6_rule */ + mutex_lock(&add_mux_channel_lock); if (rule_req->filter_spec_list_valid == true) { num_q6_rule = rule_req->filter_spec_list_len; IPAWANDBG("Received (%d) install_flt_req\n", num_q6_rule); } else { num_q6_rule = 0; IPAWANERR("got no UL rules from modem\n"); + mutex_unlock(&add_mux_channel_lock); return -EINVAL; } @@ -610,9 +613,11 @@ failure: num_q6_rule = 0; memset(ipa_qmi_ctx->q6_ul_filter_rule, 0, sizeof(ipa_qmi_ctx->q6_ul_filter_rule)); + mutex_unlock(&add_mux_channel_lock); return -EINVAL; success: + mutex_unlock(&add_mux_channel_lock); return 0; } @@ -1622,9 +1627,12 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* already got Q6 UL filter rules*/ if (ipa_qmi_ctx && ipa_qmi_ctx->modem_cfg_emb_pipe_flt - == false) + == false) { + /* protect num_q6_rule */ + mutex_lock(&add_mux_channel_lock); rc = wwan_add_ul_flt_rule_to_ipa(); - else + mutex_unlock(&add_mux_channel_lock); + } else rc = 0; egress_set = true; if (rc) @@ -2687,6 +2695,9 @@ int rmnet_ipa_set_data_quota(struct wan_ioctl_set_data_quota *data) enum ipa_upstream_type upstream_type; int rc = 0; + /* prevent string buffer overflows */ + data->interface_name[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->interface_name); @@ -2978,6 +2989,10 @@ int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, enum ipa_upstream_type upstream_type; int rc = 0; + /* prevent string buffer overflows */ + data->upstreamIface[IFNAMSIZ-1] = '\0'; + data->tetherIface[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->upstreamIface); @@ -3012,6 +3027,10 @@ int rmnet_ipa_query_tethering_stats_all( int rc = 0; memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + + /* prevent string buffer overflows */ + data->upstreamIface[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->upstreamIface); @@ -3055,6 +3074,9 @@ int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data) memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + /* prevent string buffer overflows */ + data->upstreamIface[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->upstreamIface); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index c7ab616cb5b8..c686dc6a407c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -867,10 +867,11 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, eq = true; } else { rt_tbl = ipa3_id_find(entry->rule.rt_tbl_hdl); - if (rt_tbl) - rt_tbl_idx = rt_tbl->idx; + if (rt_tbl == NULL || + rt_tbl->cookie != IPA_RT_TBL_COOKIE) + rt_tbl_idx = ~0; else - rt_tbl_idx = ~0; + rt_tbl_idx = rt_tbl->idx; bitmap = entry->rule.attrib.attrib_mask; eq = false; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index c2fb87ab757b..a03d8978c6c2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -1157,6 +1157,13 @@ int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules) goto bail; } + if (entry->cookie != IPA_FLT_COOKIE) { + IPAERR_RL("Invalid cookie value = %u flt hdl id = %d\n", + entry->cookie, rules->add_after_hdl); + result = -EINVAL; + goto bail; + } + if (entry->tbl != tbl) { IPAERR_RL("given entry does not match the table\n"); result = -EINVAL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index ff57e3bd48f0..b7ba04519a33 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -1152,6 +1152,13 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) goto bail; } + if (entry->cookie != IPA_RT_RULE_COOKIE) { + IPAERR_RL("Invalid cookie value = %u rule %d in rt tbls\n", + entry->cookie, rules->add_after_hdl); + ret = -EINVAL; + goto bail; + } + if (entry->tbl != tbl) { IPAERR_RL("given rt rule does not match the table\n"); ret = -EINVAL; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 8fbde6675070..8b0a4223e4d3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -423,6 +423,8 @@ int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 { int i, j; + /* prevent multi-threads accessing rmnet_ipa3_ctx->num_q6_rules */ + mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock); if (rule_req->filter_spec_ex_list_valid == true) { rmnet_ipa3_ctx->num_q6_rules = rule_req->filter_spec_ex_list_len; @@ -431,6 +433,8 @@ int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 } else { rmnet_ipa3_ctx->num_q6_rules = 0; IPAWANERR("got no UL rules from modem\n"); + mutex_unlock(&rmnet_ipa3_ctx-> + add_mux_channel_lock); return -EINVAL; } @@ -633,9 +637,13 @@ failure: rmnet_ipa3_ctx->num_q6_rules = 0; memset(ipa3_qmi_ctx->q6_ul_filter_rule, 0, sizeof(ipa3_qmi_ctx->q6_ul_filter_rule)); + mutex_unlock(&rmnet_ipa3_ctx-> + add_mux_channel_lock); return -EINVAL; success: + mutex_unlock(&rmnet_ipa3_ctx-> + add_mux_channel_lock); return 0; } @@ -1437,8 +1445,13 @@ static int handle3_egress_format(struct net_device *dev, if (rmnet_ipa3_ctx->num_q6_rules != 0) { /* already got Q6 UL filter rules*/ - if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) + if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) { + /* prevent multi-threads accessing num_q6_rules */ + mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock); rc = ipa3_wwan_add_ul_flt_rule_to_ipa(); + mutex_unlock(&rmnet_ipa3_ctx-> + add_mux_channel_lock); + } if (rc) IPAWANERR("install UL rules failed\n"); else @@ -2819,6 +2832,9 @@ int rmnet_ipa3_set_data_quota(struct wan_ioctl_set_data_quota *data) enum ipa_upstream_type upstream_type; int rc = 0; + /* prevent string buffer overflows */ + data->interface_name[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->interface_name); @@ -3111,6 +3127,10 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, enum ipa_upstream_type upstream_type; int rc = 0; + /* prevent string buffer overflows */ + data->upstreamIface[IFNAMSIZ-1] = '\0'; + data->tetherIface[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->upstreamIface); @@ -3145,6 +3165,10 @@ int rmnet_ipa3_query_tethering_stats_all( int rc = 0; memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + + /* prevent string buffer overflows */ + data->upstreamIface[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->upstreamIface); @@ -3188,6 +3212,9 @@ int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data) memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + /* prevent string buffer overflows */ + data->upstreamIface[IFNAMSIZ-1] = '\0'; + /* get IPA backhaul type */ upstream_type = find_upstream_type(data->upstreamIface); diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c index ea2a91bd2d06..8391dce4b5f0 100644 --- a/drivers/platform/msm/mhi/mhi_states.c +++ b/drivers/platform/msm/mhi/mhi_states.c @@ -18,26 +18,25 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +static const char * const mhi_states_transition_str[STATE_TRANSITION_MAX] = { + [STATE_TRANSITION_RESET] = "RESET", + [STATE_TRANSITION_READY] = "READY", + [STATE_TRANSITION_M0] = "M0", + [STATE_TRANSITION_M1] = "M1", + [STATE_TRANSITION_M2] = "M2", + [STATE_TRANSITION_M3] = "M3", + [STATE_TRANSITION_BHI] = "BHI", + [STATE_TRANSITION_SBL] = "SBL", + [STATE_TRANSITION_AMSS] = "AMSS", + [STATE_TRANSITION_LINK_DOWN] = "LINK_DOWN", + [STATE_TRANSITION_WAKE] = "WAKE", + [STATE_TRANSITION_BHIE] = "BHIE", + [STATE_TRANSITION_RDDM] = "RDDM", + [STATE_TRANSITION_SYS_ERR] = "SYS_ERR", +}; + const char *state_transition_str(enum STATE_TRANSITION state) { - static const char * const - mhi_states_transition_str[STATE_TRANSITION_MAX] = { - [STATE_TRANSITION_RESET] = "RESET", - [STATE_TRANSITION_READY] = "READY", - [STATE_TRANSITION_M0] = "M0", - [STATE_TRANSITION_M1] = "M1", - [STATE_TRANSITION_M2] = "M2", - [STATE_TRANSITION_M3] = "M3", - [STATE_TRANSITION_BHI] = "BHI", - [STATE_TRANSITION_SBL] = "SBL", - [STATE_TRANSITION_AMSS] = "AMSS", - [STATE_TRANSITION_LINK_DOWN] = "LINK_DOWN", - [STATE_TRANSITION_WAKE] = "WAKE", - [STATE_TRANSITION_BHIE] = "BHIE", - [STATE_TRANSITION_RDDM] = "RDDM", - [STATE_TRANSITION_SYS_ERR] = "SYS_ERR", - }; - return (state < STATE_TRANSITION_MAX) ? mhi_states_transition_str[state] : "Invalid"; } diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 5e8cc84fbfbf..cb26658e564e 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -291,7 +291,7 @@ static struct class_attribute pl_attributes[] = { * TAPER * ************/ #define MINIMUM_PARALLEL_FCC_UA 500000 -#define PL_TAPER_WORK_DELAY_MS 100 +#define PL_TAPER_WORK_DELAY_MS 500 #define TAPER_RESIDUAL_PCT 75 static void pl_taper_work(struct work_struct *work) { @@ -349,7 +349,7 @@ done: * FCC * **********/ #define EFFICIENCY_PCT 80 -static void split_fcc(struct pl_data *chip, int total_ua, +static void get_fcc_split(struct pl_data *chip, int total_ua, int *master_ua, int *slave_ua) { int rc, effective_total_ua, slave_limited_ua, hw_cc_delta_ua = 0, @@ -388,7 +388,6 @@ static void split_fcc(struct pl_data *chip, int total_ua, effective_total_ua = max(0, total_ua + hw_cc_delta_ua); slave_limited_ua = min(effective_total_ua, bcl_ua); *slave_ua = (slave_limited_ua * chip->slave_pct) / 100; - *slave_ua = (*slave_ua * chip->taper_pct) / 100; /* * In USBIN_USBIN configuration with internal rsense parallel * charger's current goes through main charger's BATFET, keep @@ -398,6 +397,8 @@ static void split_fcc(struct pl_data *chip, int total_ua, *master_ua = max(0, total_ua); else *master_ua = max(0, total_ua - *slave_ua); + + *slave_ua = (*slave_ua * chip->taper_pct) / 100; } static int pl_fcc_vote_callback(struct votable *votable, void *data, @@ -425,7 +426,8 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, } if (chip->pl_mode != POWER_SUPPLY_PL_NONE) { - split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); + get_fcc_split(chip, total_fcc_ua, + &master_fcc_ua, &slave_fcc_ua); pval.intval = slave_fcc_ua; rc = power_supply_set_property(chip->pl_psy, diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 232dd4ec8606..720a6c1945f6 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -403,6 +403,7 @@ struct fg_chip { struct mutex bus_lock; struct mutex sram_rw_lock; struct mutex charge_full_lock; + struct mutex qnovo_esr_ctrl_lock; u32 batt_soc_base; u32 batt_info_base; u32 mem_if_base; @@ -435,6 +436,7 @@ struct fg_chip { bool esr_flt_cold_temp_en; bool slope_limit_en; bool use_ima_single_mode; + bool qnovo_enable; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 626926e8b97d..ea01a38015f3 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3298,20 +3298,21 @@ static int fg_force_esr_meas(struct fg_chip *chip) int rc; int esr_uohms; + mutex_lock(&chip->qnovo_esr_ctrl_lock); /* force esr extraction enable */ rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0), FG_IMA_DEFAULT); if (rc < 0) { pr_err("failed to enable esr extn rc=%d\n", rc); - return rc; + goto out; } rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), LD_REG_CTRL_BIT, 0); if (rc < 0) { pr_err("Error in configuring qnovo_cfg rc=%d\n", rc); - return rc; + goto out; } rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip), @@ -3319,24 +3320,36 @@ static int fg_force_esr_meas(struct fg_chip *chip) ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT); if (rc < 0) { pr_err("Error in configuring force ESR rc=%d\n", rc); - return rc; + goto out; } + /* + * Release and grab the lock again after 1.5 seconds so that prepare + * callback can succeed if the request comes in between. + */ + mutex_unlock(&chip->qnovo_esr_ctrl_lock); + /* wait 1.5 seconds for hw to measure ESR */ msleep(1500); + + mutex_lock(&chip->qnovo_esr_ctrl_lock); rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip), ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT, 0); if (rc < 0) { pr_err("Error in restoring force ESR rc=%d\n", rc); - return rc; + goto out; } + /* If qnovo is disabled, then leave ESR extraction enabled */ + if (!chip->qnovo_enable) + goto done; + rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), LD_REG_CTRL_BIT, LD_REG_CTRL_BIT); if (rc < 0) { pr_err("Error in restoring qnovo_cfg rc=%d\n", rc); - return rc; + goto out; } /* force esr extraction disable */ @@ -3345,36 +3358,46 @@ static int fg_force_esr_meas(struct fg_chip *chip) FG_IMA_DEFAULT); if (rc < 0) { pr_err("failed to disable esr extn rc=%d\n", rc); - return rc; + goto out; } +done: fg_get_battery_resistance(chip, &esr_uohms); fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms); - +out: + mutex_unlock(&chip->qnovo_esr_ctrl_lock); return rc; } static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable) { - int rc; + int rc = 0; + mutex_lock(&chip->qnovo_esr_ctrl_lock); /* force esr extraction disable when qnovo enables */ rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), qnovo_enable ? 0 : BIT(0), FG_IMA_DEFAULT); - if (rc < 0) + if (rc < 0) { pr_err("Error in configuring esr extraction rc=%d\n", rc); + goto out; + } rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), LD_REG_CTRL_BIT, qnovo_enable ? LD_REG_CTRL_BIT : 0); if (rc < 0) { pr_err("Error in configuring qnovo_cfg rc=%d\n", rc); - return rc; + goto out; } - fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n"); - return 0; + + fg_dbg(chip, FG_STATUS, "%s for Qnovo\n", + qnovo_enable ? "Prepared" : "Unprepared"); + chip->qnovo_enable = qnovo_enable; +out: + mutex_unlock(&chip->qnovo_esr_ctrl_lock); + return rc; } static void ttf_work(struct work_struct *work) @@ -5006,6 +5029,7 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->cl.lock); mutex_init(&chip->ttf.lock); mutex_init(&chip->charge_full_lock); + mutex_init(&chip->qnovo_esr_ctrl_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index b3c2b67abfde..df7aabfd7e2e 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2224,12 +2224,6 @@ int smblib_get_prop_usb_voltage_max(struct smb_charger *chg, int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, union power_supply_propval *val) { - int rc = 0; - - rc = smblib_get_prop_usb_present(chg, val); - if (rc < 0 || !val->intval) - return rc; - if (!chg->iio.usbin_v_chan || PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER) chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v"); @@ -4063,6 +4057,14 @@ irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; chg->is_hdc = true; + /* + * Disable usb IRQs after the flag set and re-enable IRQs after + * the flag cleared in the delayed work queue, to avoid any IRQ + * storming during the delays + */ + if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq) + disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); + schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60)); return IRQ_HANDLED; @@ -4240,6 +4242,8 @@ static void clear_hdc_work(struct work_struct *work) clear_hdc_work.work); chg->is_hdc = 0; + if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq) + enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); } static void rdstd_cc2_detach_work(struct work_struct *work) diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c index 06ecc7ea6e8a..acc0d772d44d 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.c +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -356,11 +356,21 @@ static void status_change_work(struct work_struct *work) int reschedule_us; int reschedule_jeita_work_us = 0; int reschedule_step_work_us = 0; + union power_supply_propval pval = {0, }; + + if (!is_batt_available(chip)) { + __pm_relax(chip->step_chg_ws); + return; + } - if (!is_batt_available(chip)) + /* skip jeita and step if not charging */ + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &pval); + if (pval.intval != POWER_SUPPLY_STATUS_CHARGING) { + __pm_relax(chip->step_chg_ws); return; + } - /* skip elapsed_us debounce for handling battery temperature */ rc = handle_jeita(chip); if (rc > 0) reschedule_jeita_work_us = rc; diff --git a/drivers/pwm/pwm-qpnp.c b/drivers/pwm/pwm-qpnp.c index 2531b74b4588..5e808150a3dd 100644 --- a/drivers/pwm/pwm-qpnp.c +++ b/drivers/pwm/pwm-qpnp.c @@ -1475,7 +1475,7 @@ static void qpnp_pwm_disable(struct pwm_chip *pwm_chip, */ int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode) { - int rc; + int rc = 0; unsigned long flags; struct qpnp_pwm_chip *chip; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 523a2cff44a3..35575c071760 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -173,6 +173,9 @@ void ufshcd_update_query_stats(struct ufs_hba *hba, } #endif +#define PWR_INFO_MASK 0xF +#define PWR_RX_OFFSET 4 + #define UFSHCD_REQ_SENSE_SIZE 18 #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ @@ -4653,8 +4656,9 @@ int ufshcd_change_power_mode(struct ufs_hba *hba, int ret = 0; /* if already configured to the requested pwr_mode */ - if (pwr_mode->gear_rx == hba->pwr_info.gear_rx && - pwr_mode->gear_tx == hba->pwr_info.gear_tx && + if (!hba->restore_needed && + pwr_mode->gear_rx == hba->pwr_info.gear_rx && + pwr_mode->gear_tx == hba->pwr_info.gear_tx && pwr_mode->lane_rx == hba->pwr_info.lane_rx && pwr_mode->lane_tx == hba->pwr_info.lane_tx && pwr_mode->pwr_rx == hba->pwr_info.pwr_rx && @@ -6275,6 +6279,52 @@ static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist, reg_hist->pos = (reg_hist->pos + 1) % UIC_ERR_REG_HIST_LENGTH; } +static void ufshcd_rls_handler(struct work_struct *work) +{ + struct ufs_hba *hba; + int ret = 0; + u32 mode; + + hba = container_of(work, struct ufs_hba, rls_work); + ufshcd_scsi_block_requests(hba); + pm_runtime_get_sync(hba->dev); + ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX); + if (ret) { + dev_err(hba->dev, + "Timed out (%d) waiting for DB to clear\n", + ret); + goto out; + } + + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &mode); + if (hba->pwr_info.pwr_rx != ((mode >> PWR_RX_OFFSET) & PWR_INFO_MASK)) + hba->restore_needed = true; + + if (hba->pwr_info.pwr_tx != (mode & PWR_INFO_MASK)) + hba->restore_needed = true; + + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_RXGEAR), &mode); + if (hba->pwr_info.gear_rx != mode) + hba->restore_needed = true; + + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TXGEAR), &mode); + if (hba->pwr_info.gear_tx != mode) + hba->restore_needed = true; + + if (hba->restore_needed) + ret = ufshcd_config_pwr_mode(hba, &(hba->pwr_info)); + + if (ret) + dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", + __func__, ret); + else + hba->restore_needed = false; + +out: + ufshcd_scsi_unblock_requests(hba); + pm_runtime_put_sync(hba->dev); +} + /** * ufshcd_update_uic_error - check and set fatal UIC error flags. * @hba: per-adapter instance @@ -6314,6 +6364,8 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) hba->full_init_linereset = true; } } + if (!hba->full_init_linereset) + schedule_work(&hba->rls_work); } retval |= IRQ_HANDLED; } @@ -8708,6 +8760,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto enable_gating; } + flush_work(&hba->eeh_work); ret = ufshcd_link_state_transition(hba, req_link_state, 1); if (ret) goto set_dev_active; @@ -9921,6 +9974,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Initialize work queues */ INIT_WORK(&hba->eh_work, ufshcd_err_handler); INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler); + INIT_WORK(&hba->rls_work, ufshcd_rls_handler); /* Initialize UIC command mutex */ mutex_init(&hba->uic_cmd_mutex); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index da3ad78d3405..dbc80848ed8b 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -854,6 +854,7 @@ struct ufs_hba { /* Work Queues */ struct work_struct eh_work; struct work_struct eeh_work; + struct work_struct rls_work; /* HBA Errors */ u32 errors; @@ -950,9 +951,10 @@ struct ufs_hba { bool full_init_linereset; struct pinctrl *pctrl; - + int latency_hist_enabled; struct io_latency_state io_lat_s; + bool restore_needed; }; static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba) diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index f3debd14c27b..ad9bf3a2232d 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -1667,6 +1667,8 @@ void ch_purge_intent_lists(struct channel_ctx *ctx) &ctx->local_rx_intent_list, list) { ctx->notify_rx_abort(ctx, ctx->user_priv, ptr_intent->pkt_priv); + ctx->transport_ptr->ops->deallocate_rx_intent( + ctx->transport_ptr->ops, ptr_intent); list_del(&ptr_intent->list); kfree(ptr_intent); } @@ -3765,6 +3767,8 @@ static void glink_dummy_xprt_ctx_release(struct rwref_lock *xprt_st_lock) GLINK_INFO("%s: freeing transport [%s->%s]context\n", __func__, xprt_ctx->name, xprt_ctx->edge); + kfree(xprt_ctx->ops); + xprt_ctx->ops = NULL; kfree(xprt_ctx); } diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index 60d0f2a37026..7ede3e29dcf9 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -559,7 +559,7 @@ int pil_mss_reset_load_mba(struct pil_desc *pil) char *fw_name_p; void *mba_dp_virt; dma_addr_t mba_dp_phys, mba_dp_phys_end; - int ret, count; + int ret; const u8 *data; struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev; @@ -624,10 +624,9 @@ int pil_mss_reset_load_mba(struct pil_desc *pil) &mba_dp_phys, &mba_dp_phys_end, drv->mba_dp_size); /* Load the MBA image into memory */ - count = fw->size; - if (count <= SZ_1M) { + if (fw->size <= SZ_1M) { /* Ensures memcpy is done for max 1MB fw size */ - memcpy(mba_dp_virt, data, count); + memcpy(mba_dp_virt, data, fw->size); } else { dev_err(pil->dev, "%s fw image loading into memory is failed due to fw size overflow\n", __func__); diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index a49848808078..68199d9adb02 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -493,13 +493,10 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) ch->glink_state = event; - /* - * if spcom_notify_state() is called within glink_open() - * then ch->glink_handle is not updated yet. - */ - if (!ch->glink_handle) { - pr_debug("update glink_handle, ch [%s].\n", ch->name); - ch->glink_handle = handle; + if (!handle) { + pr_err("inavlid glink_handle, ch [%s].\n", ch->name); + mutex_unlock(&ch->lock); + return; } /* signal before unlock mutex & before calling glink */ @@ -512,8 +509,7 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) */ pr_debug("call glink_queue_rx_intent() ch [%s].\n", ch->name); - ret = glink_queue_rx_intent(ch->glink_handle, - ch, ch->rx_buf_size); + ret = glink_queue_rx_intent(handle, ch, ch->rx_buf_size); if (ret) { pr_err("glink_queue_rx_intent() err [%d]\n", ret); } else { @@ -1028,10 +1024,12 @@ static int spcom_get_next_request_size(struct spcom_channel *ch) ch->name, ch->actual_rx_size); goto exit_ready; } + mutex_unlock(&ch->lock); /* unlock while waiting */ pr_debug("Wait for Rx Done, ch [%s].\n", ch->name); wait_for_completion(&ch->rx_done); + mutex_lock(&ch->lock); /* re-lock after waiting */ /* Check Rx Abort on SP reset */ if (ch->rx_abort) { pr_err("rx aborted.\n"); diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 85c2b92f5474..ee88a8aaf850 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -634,6 +634,21 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, memcpy(&ch[i]->ch_cfg, payload, ch_cfg_size); payload += ch_cfg_size; + /* check ch name is valid string or not */ + for (j = 0; j < WDSP_CH_NAME_MAX_LEN; j++) { + if (ch[i]->ch_cfg.name[j] == '\0') + break; + } + + if (j == WDSP_CH_NAME_MAX_LEN) { + dev_err_ratelimited(wpriv->dev, "%s: Wrong channel name\n", + __func__); + kfree(ch[i]); + ch[i] = NULL; + ret = -EINVAL; + goto err_ch_mem; + } + mutex_init(&ch[i]->mutex); ch[i]->wpriv = wpriv; INIT_WORK(&ch[i]->lcl_ch_open_wrk, wdsp_glink_lcl_ch_open_wrk); @@ -906,8 +921,6 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, ret = -EINVAL; goto free_buf; } - dev_dbg(wpriv->dev, "%s: requested ch_name: %s, pkt_size: %zd\n", - __func__, cpkt->ch_name, pkt_max_size); for (i = 0; i < wpriv->no_of_channels; i++) { if (wpriv->ch && wpriv->ch[i] && (!strcmp(cpkt->ch_name, @@ -922,6 +935,8 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, ret = -EINVAL; goto free_buf; } + dev_dbg(wpriv->dev, "%s: requested ch_name: %s, pkt_size: %zd\n", + __func__, cpkt->ch_name, pkt_max_size); ret = wait_event_timeout(tx_buf->ch->ch_connect_wait, (tx_buf->ch->channel_state == diff --git a/drivers/staging/android/ion/ion_cma_secure_heap.c b/drivers/staging/android/ion/ion_cma_secure_heap.c index 90ae7eb65b65..6102b1765182 100644 --- a/drivers/staging/android/ion/ion_cma_secure_heap.c +++ b/drivers/staging/android/ion/ion_cma_secure_heap.c @@ -3,7 +3,7 @@ * * Copyright (C) Linaro 2012 * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson. - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -344,7 +344,8 @@ static void ion_secure_cma_free_chunk(struct ion_cma_secure_heap *sheap, } -void __ion_secure_cma_shrink_pool(struct ion_cma_secure_heap *sheap, int max_nr) +static unsigned long +__ion_secure_cma_shrink_pool(struct ion_cma_secure_heap *sheap, int max_nr) { struct list_head *entry, *_n; unsigned long drained_size = 0, skipped_size = 0; @@ -368,6 +369,7 @@ void __ion_secure_cma_shrink_pool(struct ion_cma_secure_heap *sheap, int max_nr) } trace_ion_secure_cma_shrink_pool_end(drained_size, skipped_size); + return drained_size; } int ion_secure_cma_drain_pool(struct ion_heap *heap, void *unused) @@ -385,6 +387,7 @@ int ion_secure_cma_drain_pool(struct ion_heap *heap, void *unused) static unsigned long ion_secure_cma_shrinker(struct shrinker *shrinker, struct shrink_control *sc) { + unsigned long freed; struct ion_cma_secure_heap *sheap = container_of(shrinker, struct ion_cma_secure_heap, shrinker); int nr_to_scan = sc->nr_to_scan; @@ -397,11 +400,11 @@ static unsigned long ion_secure_cma_shrinker(struct shrinker *shrinker, if (!mutex_trylock(&sheap->chunk_lock)) return -1; - __ion_secure_cma_shrink_pool(sheap, nr_to_scan); + freed = __ion_secure_cma_shrink_pool(sheap, nr_to_scan); mutex_unlock(&sheap->chunk_lock); - return atomic_read(&sheap->total_pool_size); + return freed; } static unsigned long ion_secure_cma_shrinker_count(struct shrinker *shrinker, diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 513d015a5ace..c19b87d10df0 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -183,7 +183,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, freed += (1 << pool->order); } - return ion_page_pool_total(pool, high); + return freed; } struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask, diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index b80e75fc3521..416006a3384c 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -218,6 +218,7 @@ struct msm_hs_wakeup { }; struct msm_hs_port { + bool startup_locked; struct uart_port uport; unsigned long imr_reg; /* shadow value of UARTDM_IMR */ struct clk *clk; @@ -292,6 +293,8 @@ static struct msm_hs_port *msm_hs_get_hs_port(int port_index); static void msm_hs_queue_rx_desc(struct msm_hs_port *msm_uport); static int disconnect_rx_endpoint(struct msm_hs_port *msm_uport); static int msm_hs_pm_resume(struct device *dev); +static void msm_hs_pm_suspend(struct device *dev); + #define UARTDM_TO_MSM(uart_port) \ container_of((uart_port), struct msm_hs_port, uport) @@ -392,6 +395,8 @@ static void msm_hs_resource_unvote(struct msm_hs_port *msm_uport) { struct uart_port *uport = &(msm_uport->uport); int rc = atomic_read(&msm_uport->resource_count); + struct msm_hs_tx *tx = &msm_uport->tx; + struct msm_hs_rx *rx = &msm_uport->rx; MSM_HS_DBG("%s(): power usage count %d", __func__, rc); if (rc <= 0) { @@ -400,8 +405,15 @@ static void msm_hs_resource_unvote(struct msm_hs_port *msm_uport) return; } atomic_dec(&msm_uport->resource_count); - pm_runtime_mark_last_busy(uport->dev); - pm_runtime_put_autosuspend(uport->dev); + + if (pm_runtime_enabled(uport->dev)) { + pm_runtime_mark_last_busy(uport->dev); + pm_runtime_put_autosuspend(uport->dev); + } else { + MSM_HS_DBG("%s():tx.flush:%d,in_flight:%d,rx.flush:%d\n", + __func__, tx->flush, tx->dma_in_flight, rx->flush); + msm_hs_pm_suspend(uport->dev); + } } /* Vote for resources before accessing them */ @@ -585,6 +597,8 @@ static void hex_dump_ipc(struct msm_hs_port *msm_uport, void *ipc_ctx, char buf[(BUF_DUMP_SIZE * 3) + 2]; int len = 0; + if (msm_uport->ipc_debug_mask == FATAL_LEV) + return; len = min(size, BUF_DUMP_SIZE); /* * Print upto 32 data bytes, 32 bytes per line, 1 byte at a time and @@ -635,6 +649,7 @@ static int msm_serial_loopback_enable_set(void *data, u64 val) unsigned long flags; int ret = 0; + msm_uport->startup_locked = true; msm_hs_resource_vote(msm_uport); if (val) { @@ -654,7 +669,7 @@ static int msm_serial_loopback_enable_set(void *data, u64 val) } /* Calling CLOCK API. Hence mb() requires here. */ mb(); - + msm_uport->startup_locked = false; msm_hs_resource_unvote(msm_uport); return 0; } @@ -666,11 +681,13 @@ static int msm_serial_loopback_enable_get(void *data, u64 *val) unsigned long flags; int ret = 0; + msm_uport->startup_locked = true; msm_hs_resource_vote(msm_uport); spin_lock_irqsave(&uport->lock, flags); ret = msm_hs_read(&msm_uport->uport, UART_DM_MR2); spin_unlock_irqrestore(&uport->lock, flags); + msm_uport->startup_locked = false; msm_hs_resource_unvote(msm_uport); @@ -828,6 +845,11 @@ static int msm_hs_spsconnect_rx(struct uart_port *uport) struct sps_register_event *sps_event = &rx->prod.event; unsigned long flags; + if (msm_uport->rx.pending_flag) { + MSM_HS_WARN("%s(): Buffers may be pending 0x%lx", + __func__, msm_uport->rx.pending_flag); + } + /* Establish connection between peripheral and memory endpoint */ ret = sps_connect(sps_pipe_handle, sps_config); if (ret) { @@ -843,9 +865,6 @@ static int msm_hs_spsconnect_rx(struct uart_port *uport) goto reg_event_err; } spin_lock_irqsave(&uport->lock, flags); - if (msm_uport->rx.pending_flag) - MSM_HS_WARN("%s(): Buffers may be pending 0x%lx", - __func__, msm_uport->rx.pending_flag); msm_uport->rx.queued_flag = 0; msm_uport->rx.pending_flag = 0; msm_uport->rx.rx_inx = 0; @@ -1284,6 +1303,8 @@ static int disconnect_rx_endpoint(struct msm_hs_port *msm_uport) int ret = 0; ret = sps_rx_disconnect(sps_pipe_handle); + if (ret) + MSM_HS_ERR("%s(): sps_disconnect failed\n", __func__); if (msm_uport->rx.pending_flag) MSM_HS_WARN("%s(): Buffers may be pending 0x%lx", @@ -1293,8 +1314,6 @@ static int disconnect_rx_endpoint(struct msm_hs_port *msm_uport) msm_uport->rx.pending_flag = 0; msm_uport->rx.rx_inx = 0; - if (ret) - MSM_HS_ERR("%s(): sps_disconnect failed\n", __func__); msm_uport->rx.flush = FLUSH_SHUTDOWN; MSM_HS_DBG("%s: Calling Completion\n", __func__); wake_up(&msm_uport->bam_disconnect_wait); @@ -1352,9 +1371,14 @@ static void msm_hs_stop_rx_locked(struct uart_port *uport) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - if (msm_uport->pm_state != MSM_HS_PM_ACTIVE) + if (msm_uport->pm_state != MSM_HS_PM_ACTIVE) { MSM_HS_WARN("%s(): Clocks are off\n", __func__); - else + /* Make sure resource_on doesn't get called */ + if (msm_hs_clk_bus_vote(msm_uport)) + MSM_HS_ERR("%s:Failed clock vote\n", __func__); + msm_hs_disable_rx(uport); + msm_hs_clk_bus_unvote(msm_uport); + } else msm_hs_disable_rx(uport); if (msm_uport->rx.flush == FLUSH_NONE) @@ -1364,11 +1388,19 @@ static void msm_hs_stop_rx_locked(struct uart_port *uport) static void msm_hs_disconnect_rx(struct uart_port *uport) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); + struct msm_hs_rx *rx = &msm_uport->rx; + struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle; + u32 prod_empty = 0; msm_hs_disable_rx(uport); /* Disconnect the BAM RX pipe */ if (msm_uport->rx.flush == FLUSH_NONE) msm_uport->rx.flush = FLUSH_STOP; + + if (sps_is_pipe_empty(sps_pipe_handle, &prod_empty)) { + MSM_HS_WARN("%s():Pipe Not Empty, ret=%d, flush=%d\n", + __func__, prod_empty, msm_uport->rx.flush); + } disconnect_rx_endpoint(msm_uport); MSM_HS_DBG("%s(): rx->flush %d", __func__, msm_uport->rx.flush); } @@ -1389,6 +1421,8 @@ void tx_timeout_handler(unsigned long arg) if (UARTDM_ISR_CURRENT_CTS_BMSK & isr) MSM_HS_WARN("%s(): CTS Disabled, ISR 0x%x", __func__, isr); dump_uart_hs_registers(msm_uport); + /* Stop further loging */ + MSM_HS_ERR("%s(): Stop IPC logging\n", __func__); } /* Transmit the next chunk of data */ @@ -1832,11 +1866,27 @@ static void msm_hs_start_tx_locked(struct uart_port *uport) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); struct msm_hs_tx *tx = &msm_uport->tx; + unsigned int isr; + + if (msm_uport->startup_locked) { + MSM_HS_DBG("%s(): No Tx Request, startup_locked=%d\n", + __func__, msm_uport->startup_locked); + return; + } /* Bail if transfer in progress */ if (tx->flush < FLUSH_STOP || tx->dma_in_flight) { MSM_HS_INFO("%s(): retry, flush %d, dma_in_flight %d\n", __func__, tx->flush, tx->dma_in_flight); + + if (msm_uport->pm_state == MSM_HS_PM_ACTIVE) { + isr = msm_hs_read(uport, UART_DM_ISR); + if (UARTDM_ISR_CURRENT_CTS_BMSK & isr) + MSM_HS_DBG("%s():CTS 1: Peer is Busy, ISR 0x%x", + __func__, isr); + } else + MSM_HS_WARN("%s(): Clocks are off\n", __func__); + return; } @@ -2269,16 +2319,34 @@ void msm_hs_resource_off(struct msm_hs_port *msm_uport) { struct uart_port *uport = &(msm_uport->uport); unsigned int data; + int ret = 0; MSM_HS_DBG("%s(): begin", __func__); msm_hs_disable_flow_control(uport, false); if (msm_uport->rx.flush == FLUSH_NONE) msm_hs_disconnect_rx(uport); + else if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { + MSM_HS_WARN("%s():Rx Flush=%d Not Expected\n", + __func__, msm_uport->rx.flush); + /* disable and disconnect rx */ + ret = wait_event_timeout(msm_uport->rx.wait, + !msm_uport->rx.pending_flag, 500); + if (!ret) + MSM_HS_WARN("%s(): rx disconnect not complete", + __func__); + msm_hs_disconnect_rx(uport); + } else + MSM_HS_DBG("%s():Rx Flush=%d In Proper State\n", + __func__, msm_uport->rx.flush); /* disable dlink */ - if (msm_uport->tx.flush == FLUSH_NONE) - wait_event_timeout(msm_uport->tx.wait, + if (msm_uport->tx.flush == FLUSH_NONE) { + ret = wait_event_timeout(msm_uport->tx.wait, msm_uport->tx.flush == FLUSH_STOP, 500); + if (!ret) + MSM_HS_WARN("%s(): tx disconnect not complete", + __func__); + } if (msm_uport->tx.flush != FLUSH_SHUTDOWN) { data = msm_hs_read(uport, UART_DM_DMEN); @@ -2296,21 +2364,29 @@ void msm_hs_resource_on(struct msm_hs_port *msm_uport) unsigned int data; unsigned long flags; + if (msm_uport->startup_locked) { + MSM_HS_WARN("%s(): startup_locked=%d\n", + __func__, msm_uport->startup_locked); + return; + } + if (msm_uport->rx.flush == FLUSH_SHUTDOWN || msm_uport->rx.flush == FLUSH_STOP) { msm_hs_write(uport, UART_DM_CR, RESET_RX); data = msm_hs_read(uport, UART_DM_DMEN); data |= UARTDM_RX_BAM_ENABLE_BMSK; msm_hs_write(uport, UART_DM_DMEN, data); - } + } else + MSM_HS_DBG("%s():rx.flush=%d, Rx is not enabled\n", + __func__, msm_uport->rx.flush); - msm_hs_spsconnect_tx(msm_uport); if (msm_uport->rx.flush == FLUSH_SHUTDOWN) { msm_hs_spsconnect_rx(uport); spin_lock_irqsave(&uport->lock, flags); msm_hs_start_rx_locked(uport); spin_unlock_irqrestore(&uport->lock, flags); } + msm_hs_spsconnect_tx(msm_uport); } /* Request to turn off uart clock once pending TX is flushed */ @@ -2603,6 +2679,7 @@ static int msm_hs_startup(struct uart_port *uport) struct sps_pipe *sps_pipe_handle_tx = tx->cons.pipe_handle; struct sps_pipe *sps_pipe_handle_rx = rx->prod.pipe_handle; + msm_uport->startup_locked = true; rfr_level = uport->fifosize; if (rfr_level > 16) rfr_level -= 16; @@ -2654,6 +2731,9 @@ static int msm_hs_startup(struct uart_port *uport) flush_kthread_worker(&msm_uport->rx.kworker); if (rx->flush != FLUSH_SHUTDOWN) disconnect_rx_endpoint(msm_uport); + else + MSM_HS_DBG("%s(): Rx Flush=%d In Proper state\n", + __func__, rx->flush); ret = msm_hs_spsconnect_rx(uport); if (ret) { MSM_HS_ERR("msm_serial_hs: SPS connect failed for RX"); @@ -2729,6 +2809,7 @@ static int msm_hs_startup(struct uart_port *uport) atomic_set(&msm_uport->client_req_state, 0); LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt, "%s: Client_Count 0\n", __func__); + msm_uport->startup_locked = false; msm_hs_start_rx_locked(uport); spin_unlock_irqrestore(&uport->lock, flags); @@ -3157,6 +3238,8 @@ static void msm_hs_pm_suspend(struct device *dev) msm_uport->pm_state = MSM_HS_PM_SUSPENDED; msm_hs_resource_off(msm_uport); obs_manage_irq(msm_uport, false); + if (!atomic_read(&msm_uport->client_req_state)) + enable_wakeup_interrupt(msm_uport); msm_hs_clk_bus_unvote(msm_uport); /* For OBS, don't use wakeup interrupt, set gpio to suspended state */ @@ -3168,8 +3251,6 @@ static void msm_hs_pm_suspend(struct device *dev) __func__); } - if (!atomic_read(&msm_uport->client_req_state)) - enable_wakeup_interrupt(msm_uport); LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt, "%s: PM State Suspended client_count %d\n", __func__, client_count); @@ -3691,9 +3772,14 @@ static void msm_hs_shutdown(struct uart_port *uport) MSM_HS_WARN("%s(): rx disconnect not complete", __func__); msm_hs_disconnect_rx(uport); + } else { + MSM_HS_DBG("%s(): Rx Flush is in Proper state=%d\n", + __func__, msm_uport->rx.flush); } - cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work); + if (cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work)) + MSM_HS_DBG("%s(): Work was pending, canceled it\n", + __func__); flush_workqueue(msm_uport->hsuart_wq); /* BAM Disconnect for TX */ diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 3c0f68deee34..96a16808b028 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -58,7 +58,7 @@ /* time out to wait for USB cable status notification (in ms)*/ #define SM_INIT_TIMEOUT 30000 - +#define DWC3_WAKEUP_SRC_TIMEOUT 5000 /* AHB2PHY register offsets */ #define PERIPH_SS_AHB2PHY_TOP_CFG 0x10 @@ -216,6 +216,7 @@ struct dwc3_msm { struct notifier_block usbdev_nb; bool hc_died; bool xhci_ss_compliance_enable; + bool no_wakeup_src_in_hostmode; struct extcon_dev *extcon_vbus; struct extcon_dev *extcon_id; @@ -2350,6 +2351,7 @@ static void dwc3_ext_event_notify(struct dwc3_msm *mdwc) clear_bit(B_SUSPEND, &mdwc->inputs); } + pm_stay_awake(mdwc->dev); schedule_delayed_work(&mdwc->sm_work, 0); } @@ -2638,6 +2640,7 @@ static int dwc3_msm_id_notifier(struct notifier_block *nb, if (mdwc->id_state != id) { mdwc->id_state = id; dbg_event(0xFF, "id_state", mdwc->id_state); + pm_stay_awake(mdwc->dev); queue_work(mdwc->dwc3_wq, &mdwc->resume_work); } @@ -2700,6 +2703,7 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, mdwc->vbus_active = event; if (dwc->is_drd && !mdwc->in_restart) { dbg_event(0xFF, "Q RW (vbus)", mdwc->vbus_active); + pm_stay_awake(mdwc->dev); queue_work(mdwc->dwc3_wq, &mdwc->resume_work); } done: @@ -3099,6 +3103,11 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->disable_host_mode_pm = of_property_read_bool(node, "qcom,disable-host-mode-pm"); + mdwc->no_wakeup_src_in_hostmode = of_property_read_bool(node, + "qcom,no-wakeup-src-in-hostmode"); + if (mdwc->no_wakeup_src_in_hostmode) + dev_dbg(&pdev->dev, "dwc3 host not using wakeup source\n"); + dwc3_set_notifier(&dwc3_msm_notify_event); /* Assumes dwc3 is the first DT child of dwc3-msm */ @@ -3892,12 +3901,14 @@ static void dwc3_otg_sm_work(struct work_struct *w) mdwc->otg_state = OTG_STATE_A_IDLE; goto ret; } + pm_wakeup_event(mdwc->dev, DWC3_WAKEUP_SRC_TIMEOUT); } break; case OTG_STATE_A_HOST: if (test_bit(ID, &mdwc->inputs) || mdwc->hc_died) { - dev_dbg(mdwc->dev, "id || hc_died\n"); + dbg_event(0xFF, "id || hc_died", 0); + dev_dbg(mdwc->dev, "%s state id || hc_died\n", state); dwc3_otg_start_host(mdwc, 0); mdwc->otg_state = OTG_STATE_B_IDLE; mdwc->vbus_retry_count = 0; @@ -3908,6 +3919,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) dbg_event(0xFF, "XHCIResume", 0); if (dwc) pm_runtime_resume(&dwc->xhci->dev); + pm_wakeup_event(mdwc->dev, DWC3_WAKEUP_SRC_TIMEOUT); } break; @@ -3923,6 +3935,34 @@ ret: return; } +static int dwc3_msm_pm_prepare(struct device *dev) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + struct usb_hcd *hcd; + struct xhci_hcd *xhci; + + dev_dbg(dev, "dwc3-msm PM prepare,lpm:%u\n", atomic_read(&dwc->in_lpm)); + dbg_event(0xFF, "PM Prep", 0); + if (!mdwc->in_host_mode || !mdwc->no_wakeup_src_in_hostmode) + return 0; + + hcd = dev_get_drvdata(&dwc->xhci->dev); + xhci = hcd_to_xhci(hcd); + flush_delayed_work(&mdwc->sm_work); + + /* If in lpm then prevent usb core to runtime_resume from pm_suspend */ + if (atomic_read(&dwc->in_lpm)) { + hcd_to_bus(hcd)->skip_resume = true; + hcd_to_bus(xhci->shared_hcd)->skip_resume = true; + } else { + hcd_to_bus(hcd)->skip_resume = false; + hcd_to_bus(xhci->shared_hcd)->skip_resume = false; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int dwc3_msm_pm_suspend(struct device *dev) { @@ -3934,7 +3974,7 @@ static int dwc3_msm_pm_suspend(struct device *dev) dbg_event(0xFF, "PM Sus", 0); flush_workqueue(mdwc->dwc3_wq); - if (!atomic_read(&dwc->in_lpm)) { + if (!atomic_read(&dwc->in_lpm) && !mdwc->no_wakeup_src_in_hostmode) { dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n"); return -EBUSY; } @@ -3958,8 +3998,13 @@ static int dwc3_msm_pm_resume(struct device *dev) flush_workqueue(mdwc->dwc3_wq); atomic_set(&mdwc->pm_suspended, 0); + /* Resume h/w in host mode as it may not be runtime suspended */ + if (mdwc->no_wakeup_src_in_hostmode && !test_bit(ID, &mdwc->inputs)) + dwc3_msm_resume(mdwc); + /* kick in otg state machine */ - queue_work(mdwc->dwc3_wq, &mdwc->resume_work); + if (mdwc->vbus_active || !mdwc->id_state) + queue_work(mdwc->dwc3_wq, &mdwc->resume_work); return 0; } @@ -3996,6 +4041,7 @@ static int dwc3_msm_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops dwc3_msm_dev_pm_ops = { + .prepare = dwc3_msm_pm_prepare, SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume) SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume, dwc3_msm_runtime_idle) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 1900870eee39..3b925d9b000e 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -885,8 +885,9 @@ static void gsi_ctrl_clear_cpkt_queues(struct f_gsi *gsi, bool skip_req_q) { struct gsi_ctrl_pkt *cpkt = NULL; struct list_head *act, *tmp; + unsigned long flags; - spin_lock(&gsi->c_port.lock); + spin_lock_irqsave(&gsi->c_port.lock, flags); if (skip_req_q) goto clean_resp_q; @@ -901,7 +902,7 @@ clean_resp_q: list_del(&cpkt->list); gsi_ctrl_pkt_free(cpkt); } - spin_unlock(&gsi->c_port.lock); + spin_unlock_irqrestore(&gsi->c_port.lock, flags); } static int gsi_ctrl_send_cpkt_tomodem(struct f_gsi *gsi, void *buf, size_t len) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 56a9cd62f2c4..c6998f086e12 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -325,6 +325,34 @@ static int xhci_plat_remove(struct platform_device *dev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int xhci_plat_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (!xhci) + return 0; + + dev_dbg(dev, "xhci-plat PM suspend\n"); + + return xhci_suspend(xhci, true); +} + +static int xhci_plat_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (!xhci) + return 0; + + dev_dbg(dev, "xhci-plat PM resume\n"); + + return xhci_resume(xhci, false); +} +#endif + #ifdef CONFIG_PM static int xhci_plat_runtime_idle(struct device *dev) { @@ -373,7 +401,7 @@ static int xhci_plat_runtime_resume(struct device *dev) } static const struct dev_pm_ops xhci_plat_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, NULL) + SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume) SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, xhci_plat_runtime_resume, xhci_plat_runtime_idle) }; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index aab1c7903288..641e0280ad5a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -918,7 +918,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; - if (!hcd->state) + if (!hcd->state || xhci->suspended) return 0; if (hcd->state != HC_STATE_SUSPENDED || @@ -988,6 +988,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) /* step 5: remove core well power */ /* synchronize irq when using MSI-X */ xhci_msix_sync_irqs(xhci); + xhci->suspended = true; return rc; } @@ -1007,7 +1008,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) int retval = 0; bool comp_timer_running = false; - if (!hcd->state) + if (!hcd->state || !xhci->suspended) return 0; /* Wait a bit if either of the roothubs need to settle from the @@ -1141,6 +1142,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Re-enable port polling. */ xhci_dbg(xhci, "%s: starting port polling.\n", __func__); + xhci->suspended = false; set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); usb_hcd_poll_rh_status(xhci->shared_hcd); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8fcec1be6b1a..7fc97d930657 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1667,6 +1667,7 @@ struct xhci_hcd { /* Compliance Mode Recovery Data */ struct timer_list comp_mode_recovery_timer; u32 port_status_u0; + bool suspended; /* Compliance Mode Timer Triggered every 2 seconds */ #define COMP_MODE_RCVRY_MSECS 2000 }; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 4c6a5e73406b..bc325a91a9bf 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -68,6 +68,7 @@ static int mdss_dp_process_phy_test_pattern_request( struct mdss_dp_drv_pdata *dp); static int mdss_dp_send_audio_notification( struct mdss_dp_drv_pdata *dp, int val); +static void mdss_dp_reset_sw_state(struct mdss_dp_drv_pdata *dp); static inline void mdss_dp_reset_sink_count(struct mdss_dp_drv_pdata *dp) { @@ -1489,7 +1490,12 @@ static int mdss_dp_setup_main_link(struct mdss_dp_drv_pdata *dp, bool train) pr_debug("enter\n"); mdss_dp_mainlink_ctrl(&dp->ctrl_io, true); - mdss_dp_aux_set_sink_power_state(dp, SINK_POWER_ON); + ret = mdss_dp_aux_send_psm_request(dp, false); + if (ret) { + pr_err("Failed to exit low power mode, rc=%d\n", ret); + goto end; + } + reinit_completion(&dp->video_comp); if (mdss_dp_is_phy_test_pattern_requested(dp)) @@ -1576,15 +1582,6 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv, bool lt_needed) dp_drv->power_on = true; - if (dp_drv->psm_enabled) { - ret = mdss_dp_aux_send_psm_request(dp_drv, false); - if (ret) { - pr_err("Failed to exit low power mode, rc=%d\n", - ret); - goto exit_loop; - } - } - ret = mdss_dp_setup_main_link(dp_drv, lt_needed); exit_loop: @@ -1653,15 +1650,6 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) mdss_dp_configure_source_params(dp_drv, ln_map); - if (dp_drv->psm_enabled) { - ret = mdss_dp_aux_send_psm_request(dp_drv, false); - if (ret) { - pr_err("Failed to exit low power mode, rc=%d\n", ret); - goto exit; - } - } - - link_training: dp_drv->power_on = true; @@ -2989,6 +2977,7 @@ static int mdss_dp_sysfs_create(struct mdss_dp_drv_pdata *dp, static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata) { + bool cable_connected; struct mdss_dp_drv_pdata *dp_drv = NULL; const int idle_pattern_completion_timeout_ms = 3 * HZ / 100; @@ -3009,6 +2998,14 @@ static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata) return; } + /* power down the sink if cable is still connected */ + mutex_lock(&dp_drv->attention_lock); + cable_connected = dp_drv->cable_connected; + mutex_unlock(&dp_drv->attention_lock); + if (cable_connected && dp_drv->alt_mode.dp_status.hpd_high) { + if (mdss_dp_aux_send_psm_request(dp_drv, true)) + pr_err("Failed to enter low power mode\n"); + } reinit_completion(&dp_drv->idle_comp); mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE); if (!wait_for_completion_timeout(&dp_drv->idle_comp, @@ -3129,6 +3126,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, pr_err("DP Controller not powered on\n"); break; } + if (!atomic_read(&dp->notification_pending)) { + pr_debug("blank when cable is connected\n"); + kthread_park(dp->ev_thread); + } if (dp_is_hdcp_enabled(dp)) { dp->hdcp_status = HDCP_STATE_INACTIVE; @@ -3168,8 +3169,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, * when you connect DP sink while the * device is in suspend state. */ - if ((!dp->power_on) && (dp->dp_initialized)) + if ((!dp->power_on) && (dp->dp_initialized)) { rc = mdss_dp_host_deinit(dp); + kthread_park(dp->ev_thread); + } /* * For DP suspend/resume use case, CHECK_PARAMS is @@ -3181,8 +3184,11 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, dp->suspend_vic = dp->vic; break; case MDSS_EVENT_RESUME: - if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN) + if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN) { dp_init_panel_info(dp, dp->suspend_vic); + mdss_dp_reset_sw_state(dp); + kthread_unpark(dp->ev_thread); + } break; default: pr_debug("unhandled event=%d\n", event); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index afa8e3db590f..983f5e34a515 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -218,10 +218,6 @@ struct dp_alt_mode { #define ST_SEND_VIDEO BIT(7) #define ST_PUSH_IDLE BIT(8) -/* sink power state */ -#define SINK_POWER_ON 1 -#define SINK_POWER_OFF 2 - #define DP_LINK_RATE_162 6 /* 1.62G = 270M * 6 */ #define DP_LINK_RATE_270 10 /* 2.70G = 270M * 10 */ #define DP_LINK_RATE_540 20 /* 5.40G = 270M * 20 */ @@ -1181,11 +1177,9 @@ void dp_aux_native_handler(struct mdss_dp_drv_pdata *dp, u32 isr); void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep); void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep); -void mdss_dp_sink_power_down(struct mdss_dp_drv_pdata *ep); void mdss_dp_lane_power_ctrl(struct mdss_dp_drv_pdata *ep, int up); void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep); char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp); -int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state); int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable); void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep); void *mdss_dp_get_hdcp_data(struct device *dev); diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index c0632e8241a0..86946adfeeb0 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -2556,15 +2556,6 @@ static int dp_link_rate_down_shift(struct mdss_dp_drv_pdata *ep) return ret; } -int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state) -{ - int ret; - - ret = dp_aux_write_buf(ep, 0x600, &state, 1, 0); - pr_debug("state=%d ret=%d\n", state, ret); - return ret; -} - static void dp_clear_training_pattern(struct mdss_dp_drv_pdata *ep) { int usleep_time; diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 5f7e7c6bcde0..7b6153503af5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -968,7 +968,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id) while (len >= sizeof(*dchdr)) { dchdr = (struct dsi_ctrl_hdr *)bp; dchdr->dlen = ntohs(dchdr->dlen); - if (dchdr->dlen > len) { + if (dchdr->dlen > len || dchdr->dlen < 0) { pr_err("%s: dtsi cmd=%x error, len=%d\n", __func__, dchdr->dtype, dchdr->dlen); kfree(buf); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index af95a4a6dccd..a5a407708334 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -113,6 +113,7 @@ static void hdmi_tx_fps_work(struct work_struct *work); static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, bool active); static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl); +static void hdmi_panel_clear_hdr_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl); static int hdmi_tx_audio_info_setup(struct platform_device *pdev, struct msm_ext_disp_audio_setup_params *params); static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev, @@ -1276,6 +1277,7 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev, { int ret = 0; struct hdmi_tx_ctrl *ctrl = NULL; + u8 hdr_op; ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev); if (!ctrl) { @@ -1296,36 +1298,43 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev, goto end; } - memcpy(&ctrl->hdr_data, buf, sizeof(struct mdp_hdr_stream)); + memcpy(&ctrl->hdr_ctrl, buf, sizeof(struct mdp_hdr_stream_ctrl)); pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", __func__, - ctrl->hdr_data.eotf, - ctrl->hdr_data.display_primaries_x[0], - ctrl->hdr_data.display_primaries_y[0], - ctrl->hdr_data.display_primaries_x[1], - ctrl->hdr_data.display_primaries_y[1], - ctrl->hdr_data.display_primaries_x[2], - ctrl->hdr_data.display_primaries_y[2]); + ctrl->hdr_ctrl.hdr_stream.eotf, + ctrl->hdr_ctrl.hdr_stream.display_primaries_x[0], + ctrl->hdr_ctrl.hdr_stream.display_primaries_y[0], + ctrl->hdr_ctrl.hdr_stream.display_primaries_x[1], + ctrl->hdr_ctrl.hdr_stream.display_primaries_y[1], + ctrl->hdr_ctrl.hdr_stream.display_primaries_x[2], + ctrl->hdr_ctrl.hdr_stream.display_primaries_y[2]); pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", __func__, - ctrl->hdr_data.white_point_x, - ctrl->hdr_data.white_point_y, - ctrl->hdr_data.max_luminance, - ctrl->hdr_data.min_luminance, - ctrl->hdr_data.max_content_light_level, - ctrl->hdr_data.max_average_light_level); + ctrl->hdr_ctrl.hdr_stream.white_point_x, + ctrl->hdr_ctrl.hdr_stream.white_point_y, + ctrl->hdr_ctrl.hdr_stream.max_luminance, + ctrl->hdr_ctrl.hdr_stream.min_luminance, + ctrl->hdr_ctrl.hdr_stream.max_content_light_level, + ctrl->hdr_ctrl.hdr_stream.max_average_light_level); pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", __func__, - ctrl->hdr_data.pixel_encoding, - ctrl->hdr_data.colorimetry, - ctrl->hdr_data.range, - ctrl->hdr_data.bits_per_component, - ctrl->hdr_data.content_type); + ctrl->hdr_ctrl.hdr_stream.pixel_encoding, + ctrl->hdr_ctrl.hdr_stream.colorimetry, + ctrl->hdr_ctrl.hdr_stream.range, + ctrl->hdr_ctrl.hdr_stream.bits_per_component, + ctrl->hdr_ctrl.hdr_stream.content_type); + hdr_op = hdmi_hdr_get_ops(ctrl->curr_hdr_state, + ctrl->hdr_ctrl.hdr_state); - hdmi_panel_set_hdr_infoframe(ctrl); + if (hdr_op == HDR_SEND_INFO) + hdmi_panel_set_hdr_infoframe(ctrl); + else if (hdr_op == HDR_CLEAR_INFO) + hdmi_panel_clear_hdr_infoframe(ctrl); + + ctrl->curr_hdr_state = ctrl->hdr_ctrl.hdr_state; ret = strnlen(buf, PAGE_SIZE); end: @@ -2113,6 +2122,8 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, goto err; } + /* reset HDR state */ + hdmi_ctrl->curr_hdr_state = HDR_DISABLE; return 0; err: hdmi_tx_deinit_features(hdmi_ctrl, deinit_features); @@ -2878,11 +2889,12 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) packet_header = type_code | (version << 8) | (length << 16); DSS_REG_W(io, HDMI_GENERIC0_HDR, packet_header); - packet_payload = (ctrl->hdr_data.eotf << 8); + packet_payload = (ctrl->hdr_ctrl.hdr_stream.eotf << 8); if (hdmi_tx_metadata_type_one(ctrl)) { - packet_payload |= (descriptor_id << 16) - | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[0]) - << 24); + packet_payload |= + (descriptor_id << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_x[0]) << 24); DSS_REG_W(io, HDMI_GENERIC0_0, packet_payload); } else { pr_debug("%s: Metadata Type 1 not supported\n", __func__); @@ -2891,44 +2903,56 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) } packet_payload = - (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[0])) - | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[0]) << 8) - | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[0]) << 16) - | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[1]) << 24); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[0])) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[0]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[0]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_x[1]) << 24); DSS_REG_W(io, HDMI_GENERIC0_1, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[1])) - | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[1]) << 8) - | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[1]) << 16) - | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[2]) << 24); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[1])) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[1]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[1]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_x[2]) << 24); DSS_REG_W(io, HDMI_GENERIC0_2, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[2])) - | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[2]) << 8) - | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[2]) << 16) - | (HDMI_GET_LSB(ctrl->hdr_data.white_point_x) << 24); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[2])) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[2]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[2]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.white_point_x) << 24); DSS_REG_W(io, HDMI_GENERIC0_3, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_data.white_point_x)) - | (HDMI_GET_LSB(ctrl->hdr_data.white_point_y) << 8) - | (HDMI_GET_MSB(ctrl->hdr_data.white_point_y) << 16) - | (HDMI_GET_LSB(ctrl->hdr_data.max_luminance) << 24); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.white_point_x)) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.white_point_y) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.white_point_y) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.max_luminance) << 24); DSS_REG_W(io, HDMI_GENERIC0_4, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_data.max_luminance)) - | (HDMI_GET_LSB(ctrl->hdr_data.min_luminance) << 8) - | (HDMI_GET_MSB(ctrl->hdr_data.min_luminance) << 16) - | (HDMI_GET_LSB(ctrl->hdr_data.max_content_light_level) << 24); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.max_luminance)) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.min_luminance) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.min_luminance) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + max_content_light_level) << 24); DSS_REG_W(io, HDMI_GENERIC0_5, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_data.max_content_light_level)) - | (HDMI_GET_LSB(ctrl->hdr_data.max_average_light_level) << 8) - | (HDMI_GET_MSB(ctrl->hdr_data.max_average_light_level) << 16); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + max_content_light_level)) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + max_average_light_level) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + max_average_light_level) << 16); DSS_REG_W(io, HDMI_GENERIC0_6, packet_payload); enable_packet_control: @@ -2943,6 +2967,32 @@ enable_packet_control: DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); } +static void hdmi_panel_clear_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) +{ + u32 packet_control = 0; + struct dss_io_data *io = NULL; + + if (!ctrl) { + pr_err("%s: invalid input\n", __func__); + return; + } + + if (!hdmi_tx_is_hdr_supported(ctrl)) { + pr_err("%s: Sink does not support HDR\n", __func__); + return; + } + + io = &ctrl->pdata.io[HDMI_TX_CORE_IO]; + if (!io->base) { + pr_err("%s: core io not inititalized\n", __func__); + return; + } + + packet_control = DSS_REG_R_ND(io, HDMI_GEN_PKT_CTRL); + packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK; + DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); +} + static int hdmi_tx_audio_info_setup(struct platform_device *pdev, struct msm_ext_disp_audio_setup_params *params) { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index 3469b8a5819f..ad02003631f6 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -21,6 +21,7 @@ #include "mdss_hdmi_audio.h" #define MAX_SWITCH_NAME_SIZE 5 +#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7 enum hdmi_tx_io_type { HDMI_TX_CORE_IO, @@ -90,7 +91,7 @@ struct hdmi_tx_ctrl { struct msm_ext_disp_audio_setup_params audio_params; struct msm_ext_disp_init_data ext_audio_data; struct work_struct fps_work; - struct mdp_hdr_stream hdr_data; + struct mdp_hdr_stream_ctrl hdr_ctrl; spinlock_t hpd_state_lock; @@ -116,6 +117,7 @@ struct hdmi_tx_ctrl { u8 hdcp_status; u8 spd_vendor_name[9]; u8 spd_product_description[17]; + u8 curr_hdr_state; bool hdcp_feature_on; bool hpd_disabled; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index 827013d06412..5bc46d8c8f92 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/delay.h> #include <linux/msm_mdp.h> +#include <linux/msm_mdp_ext.h> #include "mdss_hdmi_util.h" #define RESOLUTION_NAME_STR_LEN 30 @@ -1811,3 +1812,51 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl) return rc; } + +u8 hdmi_hdr_get_ops(u8 curr_state, u8 new_state) +{ + + /** There could be 3 valid state transitions: + * 1. HDR_DISABLE -> HDR_ENABLE + * + * In this transition, we shall start sending + * HDR metadata with metadata from the HDR clip + * + * 2. HDR_ENABLE -> HDR_RESET + * + * In this transition, we will keep sending + * HDR metadata but with EOTF and metadata as 0 + * + * 3. HDR_RESET -> HDR_ENABLE + * + * In this transition, we will start sending + * HDR metadata with metadata from the HDR clip + * + * 4. HDR_RESET -> HDR_DISABLE + * + * In this transition, we will stop sending + * metadata to the sink and clear PKT_CTRL register + * bits. + */ + + if ((curr_state == HDR_DISABLE) + && (new_state == HDR_ENABLE)) { + pr_debug("State changed HDR_DISABLE ---> HDR_ENABLE\n"); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_ENABLE) + && (new_state == HDR_RESET)) { + pr_debug("State changed HDR_ENABLE ---> HDR_RESET\n"); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_RESET) + && (new_state == HDR_ENABLE)) { + pr_debug("State changed HDR_RESET ---> HDR_ENABLE\n"); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_RESET) + && (new_state == HDR_DISABLE)) { + pr_debug("State changed HDR_RESET ---> HDR_DISABLE\n"); + return HDR_CLEAR_INFO; + } + + pr_debug("Unsupported OR no state change\n"); + return HDR_UNSUPPORTED_OP; +} diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index 4fd659616bcc..fe554f8e9e67 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.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 @@ -425,6 +425,12 @@ enum hdmi_tx_hdcp2p2_rxstatus_intr_mask { RXSTATUS_REAUTH_REQ = BIT(14), }; +enum hdmi_hdr_op { + HDR_UNSUPPORTED_OP, + HDR_SEND_INFO, + HDR_CLEAR_INFO +}; + struct hdmi_tx_hdcp2p2_ddc_data { enum hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask; u32 timeout_ms; @@ -518,5 +524,5 @@ void hdmi_hdcp2p2_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_utils_get_timeout_in_hysnc(struct msm_hdmi_mode_timing_info *timing, u32 timeout_ms); - +u8 hdmi_hdr_get_ops(u8 curr_state, u8 new_state); #endif /* __HDMI_UTIL_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 9796121bbabf..54b792305eb5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -995,6 +995,8 @@ struct mdss_overlay_private { struct task_struct *thread; u8 secure_transition_state; + + bool cache_null_commit; /* Cache if preceding commit was NULL */ }; struct mdss_mdp_set_ot_params { diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index b07ba82fde34..9e9f37ce0b23 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -1853,9 +1853,15 @@ static int __validate_secure_session(struct mdss_overlay_private *mdp5_data) pr_err("secure-camera cnt:%d secure video:%d secure display:%d\n", secure_cam_pipes, secure_vid_pipes, sd_pipes); return -EINVAL; - } else { - return 0; + } else if (mdp5_data->ctl->is_video_mode && + ((sd_pipes && !mdp5_data->sd_enabled) || + (!sd_pipes && mdp5_data->sd_enabled)) && + !mdp5_data->cache_null_commit) { + pr_err("NULL commit missing before display secure session entry/exit\n"); + return -EINVAL; } + + return 0; } /* diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 305fff6b5695..11c159630747 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -2375,6 +2375,8 @@ static void __overlay_set_secure_transition_state(struct msm_fb_data_type *mfd) /* Reset the secure transition state */ mdp5_data->secure_transition_state = SECURE_TRANSITION_NONE; + mdp5_data->cache_null_commit = list_empty(&mdp5_data->pipes_used); + /* * Secure transition would be NONE in two conditions: * 1. All the features are already disabled and state remains @@ -2584,6 +2586,7 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, ATRACE_BEGIN("sspp_programming"); ret = __overlay_queue_pipes(mfd); ATRACE_END("sspp_programming"); + mutex_unlock(&mdp5_data->list_lock); mdp5_data->kickoff_released = false; diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c index 2028222748c3..78bccdbfee3b 100644 --- a/drivers/video/fbdev/msm/mdss_rotator.c +++ b/drivers/video/fbdev/msm/mdss_rotator.c @@ -1124,6 +1124,7 @@ static void mdss_rotator_release_from_work_distribution( bool free_perf = false; u32 wb_idx = entry->queue->hw->wb_id; + mutex_lock(&mgr->lock); mutex_lock(&entry->perf->work_dis_lock); if (entry->perf->work_distribution[wb_idx]) entry->perf->work_distribution[wb_idx]--; @@ -1147,6 +1148,7 @@ static void mdss_rotator_release_from_work_distribution( mdss_rotator_clk_ctrl(mgr, false); entry->perf = NULL; } + mutex_unlock(&mgr->lock); } } @@ -2043,7 +2045,6 @@ static int mdss_rotator_close_session(struct mdss_rot_mgr *mgr, list_del_init(&perf->list); mutex_unlock(&perf->work_dis_lock); mutex_unlock(&private->perf_lock); - mutex_unlock(&mgr->lock); if (offload_release_work) goto done; @@ -2056,6 +2057,7 @@ static int mdss_rotator_close_session(struct mdss_rot_mgr *mgr, done: pr_debug("Closed session id:%u", id); ATRACE_END(__func__); + mutex_unlock(&mgr->lock); return 0; } diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 0065ffc9322b..08b3b8348fd7 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -170,6 +170,7 @@ extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable); extern int mmc_suspend_clk_scaling(struct mmc_host *host); +extern void mmc_flush_detect_work(struct mmc_host *); #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 60d15a080d7c..9d3eda39bcd2 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -37,7 +37,7 @@ void rcu_cpu_stall_reset(void); /* * Note a virtualization-based context switch. This is simply a * wrapper around rcu_note_context_switch(), which allows TINY_RCU - * to save a few bytes. + * to save a few bytes. The caller must have disabled interrupts. */ static inline void rcu_virt_note_context_switch(int cpu) { diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h index 0a34489a46b6..17a33f31bfa2 100644 --- a/include/linux/stacktrace.h +++ b/include/linux/stacktrace.h @@ -23,6 +23,8 @@ extern void print_stack_trace(struct stack_trace *trace, int spaces); extern int snprint_stack_trace(char *buf, size_t size, struct stack_trace *trace, int spaces); +#define BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM + #ifdef CONFIG_USER_STACKTRACE_SUPPORT extern void save_stack_trace_user(struct stack_trace *trace); #else diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 762f1c51620c..2c8b651147e0 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -84,6 +84,15 @@ struct msm_ir_cut_cfg_data_t32 { enum msm_ir_cut_cfg_type_t cfg_type; }; +struct msm_laser_led_cfg_data_t32 { + enum msm_laser_led_cfg_type_t cfg_type; + compat_uptr_t setting; + compat_uptr_t debug_reg; + uint32_t debug_reg_size; + uint16_t i2c_addr; + enum i2c_freq_mode_t i2c_freq_mode; +}; + struct eeprom_read_t32 { compat_uptr_t dbuffer; uint32_t num_bytes; @@ -276,7 +285,10 @@ struct msm_flash_cfg_data_t32 { #define VIDIOC_MSM_IR_CUT_CFG32 \ _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t32) -#endif + +#define VIDIOC_MSM_LASER_LED_CFG32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t32) #endif +#endif diff --git a/include/net/cnss_nl.h b/include/net/cnss_nl.h index 86c2fccc930e..b8a7cfdb7966 100644 --- a/include/net/cnss_nl.h +++ b/include/net/cnss_nl.h @@ -23,12 +23,16 @@ * @CLD80211_ATTR_VENDOR_DATA: Embed all other attributes in this nested * attribute. * @CLD80211_ATTR_DATA: Embed complete data in this attribute + * @CLD80211_ATTR_META_DATA: Embed meta data for above data. This will help + * wlan driver to peek into request message packet without opening up definition + * of complete request message. * * Any new message in future can be added as another attribute */ enum cld80211_attr { CLD80211_ATTR_VENDOR_DATA = 1, CLD80211_ATTR_DATA, + CLD80211_ATTR_META_DATA, /* add new attributes above here */ __CLD80211_ATTR_AFTER_LAST, diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index da9ee3bcc525..61b5f8eaa7f9 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -821,4 +821,26 @@ struct mdp_hdr_stream { uint32_t content_type; uint32_t reserved[5]; }; + +/* hdr hdmi state takes possible values of 1, 2 and 4 respectively */ +#define HDR_ENABLE (1 << 0) +#define HDR_DISABLE (1 << 1) +#define HDR_RESET (1 << 2) + +/* + * HDR Control + * This encapsulates the HDR metadata as well as a state control + * for the HDR metadata as required by the HDMI spec to send the + * relevant metadata depending on the state of the HDR playback. + * hdr_state: Controls HDR state, takes values HDR_ENABLE, HDR_DISABLE + * and HDR_RESET. + * hdr_meta: Metadata sent by the userspace for the HDR clip. + */ + +#define DRM_MSM_EXT_PANEL_HDR_CTRL +struct mdp_hdr_stream_ctrl { + __u8 hdr_state; /* HDR state */ + struct mdp_hdr_stream hdr_stream; /* HDR metadata */ +}; + #endif diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 0d87fa1e253c..25cb17ca6bf3 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1225,6 +1225,13 @@ enum v4l2_mpeg_vidc_video_au_delimiter { V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_ENABLED = 1 }; +#define V4L2_CID_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 103) +enum v4l2_mpeg_vidc_video_venc_send_skipped_frame { + V4L2_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME_DISABLE = 0, + V4L2_MPEG_VIDC_VIDEO_SEND_SKIPPED_FRAME_ENABLE = 1 +}; + /* Camera class control IDs */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index fa930a91b4aa..36e94588d1d9 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -2,7 +2,7 @@ * Video for Linux Two header file * * Copyright (C) 1999-2012 the contributors - * 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 as published by @@ -590,6 +590,11 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGBRG10DPCM6 v4l2_fourcc('b', 'G', 'A', '6') #define V4L2_PIX_FMT_SGRBG10DPCM6 v4l2_fourcc('B', 'D', '1', '6') #define V4L2_PIX_FMT_SRGGB10DPCM6 v4l2_fourcc('b', 'R', 'A', '6') + /* 10bit raw bayer, plain16 packed */ +#define V4L2_PIX_FMT_SBGGRPLAIN16 v4l2_fourcc('B', 'G', '1', '6') +#define V4L2_PIX_FMT_SGBRGPLAIN16 v4l2_fourcc('G', 'B', '1', '6') +#define V4L2_PIX_FMT_SGRBGPLAIN16 v4l2_fourcc('G', 'R', '1', '6') +#define V4L2_PIX_FMT_SRGGBPLAIN16 v4l2_fourcc('R', 'G', '1', '6') /* compressed formats */ #define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ diff --git a/include/uapi/media/msm_cam_sensor.h b/include/uapi/media/msm_cam_sensor.h index c6144cd8f355..0ec18d663cff 100644 --- a/include/uapi/media/msm_cam_sensor.h +++ b/include/uapi/media/msm_cam_sensor.h @@ -88,6 +88,7 @@ enum sensor_sub_module_t { SUB_MODULE_EXT, SUB_MODULE_IR_LED, SUB_MODULE_IR_CUT, + SUB_MODULE_LASER_LED, SUB_MODULE_MAX, }; @@ -301,6 +302,15 @@ struct msm_ir_cut_cfg_data_t { enum msm_ir_cut_cfg_type_t cfg_type; }; +struct msm_laser_led_cfg_data_t { + enum msm_laser_led_cfg_type_t cfg_type; + void __user *setting; + void __user *debug_reg; + uint32_t debug_reg_size; + uint16_t i2c_addr; + enum i2c_freq_mode_t i2c_freq_mode; +}; + struct msm_eeprom_cfg_data { enum eeprom_cfg_type_t cfgtype; uint8_t is_supported; @@ -381,7 +391,9 @@ enum msm_ois_cfg_download_type_t { enum msm_ois_i2c_operation { MSM_OIS_WRITE = 0, MSM_OIS_POLL, + MSM_OIS_READ, }; +#define MSM_OIS_READ MSM_OIS_READ struct reg_settings_ois_t { uint16_t reg_addr; @@ -616,5 +628,8 @@ struct sensor_init_cfg_data { #define VIDIOC_MSM_IR_CUT_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t) +#define VIDIOC_MSM_LASER_LED_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t) + #endif diff --git a/include/uapi/media/msm_camera.h b/include/uapi/media/msm_camera.h index 10ee4b7c9390..39e6927d9b7e 100644 --- a/include/uapi/media/msm_camera.h +++ b/include/uapi/media/msm_camera.h @@ -1541,7 +1541,9 @@ enum msm_camera_i2c_reg_addr_type { MSM_CAMERA_I2C_BYTE_ADDR = 1, MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_3B_ADDR, + MSM_CAMERA_I2C_DWORD_ADDR, }; +#define MSM_CAMERA_I2C_DWORD_ADDR MSM_CAMERA_I2C_DWORD_ADDR struct msm_camera_i2c_reg_array { uint16_t reg_addr; diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h index a92c144f712e..08605aca474d 100644 --- a/include/uapi/media/msm_camsensor_sdk.h +++ b/include/uapi/media/msm_camsensor_sdk.h @@ -85,8 +85,10 @@ enum msm_camera_i2c_reg_addr_type { MSM_CAMERA_I2C_BYTE_ADDR = 1, MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_3B_ADDR, + MSM_CAMERA_I2C_DWORD_ADDR, MSM_CAMERA_I2C_ADDR_TYPE_MAX, }; +#define MSM_CAMERA_I2C_DWORD_ADDR MSM_CAMERA_I2C_DWORD_ADDR enum msm_camera_i2c_data_type { MSM_CAMERA_I2C_BYTE_DATA = 1, @@ -206,6 +208,13 @@ enum msm_ir_led_cfg_type_t { #define CFG_IR_LED_OFF CFG_IR_LED_OFF #define CFG_IR_LED_ON CFG_IR_LED_ON +enum msm_laser_led_cfg_type_t { + CFG_LASER_LED_INIT, + CFG_LASER_LED_CONTROL, +}; +#define CFG_LASER_LED_INIT CFG_LASER_LED_INIT +#define CFG_LASER_LED_CONTROL CFG_LASER_LED_CONTROL + enum msm_ir_cut_cfg_type_t { CFG_IR_CUT_INIT = 0, CFG_IR_CUT_RELEASE, diff --git a/include/uapi/media/msmb_camera.h b/include/uapi/media/msmb_camera.h index df9807e72e47..4b23806071d4 100644 --- a/include/uapi/media/msmb_camera.h +++ b/include/uapi/media/msmb_camera.h @@ -52,6 +52,7 @@ #define MSM_CAMERA_SUBDEV_IR_CUT 18 #define MSM_CAMERA_SUBDEV_EXT 19 #define MSM_CAMERA_SUBDEV_TOF 20 +#define MSM_CAMERA_SUBDEV_LASER_LED 21 #define MSM_MAX_CAMERA_SENSORS 5 /* The below macro is defined to put an upper limit on maximum diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 077bb52e2d47..3fdb7545852e 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2799,6 +2799,7 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk) int retval = 0; mutex_lock(&cgroup_mutex); + percpu_down_write(&cgroup_threadgroup_rwsem); for_each_root(root) { struct cgroup *from_cgrp; @@ -2813,6 +2814,7 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk) if (retval) break; } + percpu_up_write(&cgroup_threadgroup_rwsem); mutex_unlock(&cgroup_mutex); return retval; @@ -4072,6 +4074,8 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from) mutex_lock(&cgroup_mutex); + percpu_down_write(&cgroup_threadgroup_rwsem); + /* all tasks in @from are being moved, all csets are source */ spin_lock_irq(&css_set_lock); list_for_each_entry(link, &from->cset_links, cset_link) @@ -4100,6 +4104,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from) } while (task && !ret); out_err: cgroup_migrate_finish(&preloaded_csets); + percpu_up_write(&cgroup_threadgroup_rwsem); mutex_unlock(&cgroup_mutex); return ret; } diff --git a/kernel/locking/osq_lock.c b/kernel/locking/osq_lock.c index 1e6a51cc25c4..99b8d991126f 100644 --- a/kernel/locking/osq_lock.c +++ b/kernel/locking/osq_lock.c @@ -106,32 +106,6 @@ bool osq_lock(struct optimistic_spin_queue *lock) prev = decode_cpu(old); node->prev = prev; - - /* - * We need to avoid reordering of link updation sequence of osq. - * A case in which the status of optimistic spin queue is - * CPU6->CPU2 in which CPU6 has acquired the lock. At this point - * if CPU0 comes in to acquire osq_lock, it will update the tail - * count. After tail count update if CPU2 starts to unqueue itself - * from optimistic spin queue, it will find updated tail count with - * CPU0 and update CPU2 node->next to NULL in osq_wait_next(). If - * reordering of following stores happen then prev->next where prev - * being CPU2 would be updated to point to CPU0 node: - * node->prev = prev; - * WRITE_ONCE(prev->next, node); - * - * At this point if next instruction - * WRITE_ONCE(next->prev, prev); - * in CPU2 path is committed before the update of CPU0 node->prev = - * prev then CPU0 node->prev will point to CPU6 node. At this point - * if CPU0 path's node->prev = prev is committed resulting in change - * of CPU0 prev back to CPU2 node. CPU2 node->next is NULL, so if - * CPU0 gets into unqueue path of osq_lock it will keep spinning - * in infinite loop as condition prev->next == node will never be - * true. - */ - smp_mb(); - WRITE_ONCE(prev->next, node); /* diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 2cb46d51d715..1ba183e7987c 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -248,24 +248,17 @@ static int rcu_gp_in_progress(struct rcu_state *rsp) */ void rcu_sched_qs(void) { - unsigned long flags; - - if (__this_cpu_read(rcu_sched_data.cpu_no_qs.s)) { - trace_rcu_grace_period(TPS("rcu_sched"), - __this_cpu_read(rcu_sched_data.gpnum), - TPS("cpuqs")); - __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false); - if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) - return; - local_irq_save(flags); - if (__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) { - __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false); - rcu_report_exp_rdp(&rcu_sched_state, - this_cpu_ptr(&rcu_sched_data), - true); - } - local_irq_restore(flags); - } + if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.s)) + return; + trace_rcu_grace_period(TPS("rcu_sched"), + __this_cpu_read(rcu_sched_data.gpnum), + TPS("cpuqs")); + __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false); + if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) + return; + __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false); + rcu_report_exp_rdp(&rcu_sched_state, + this_cpu_ptr(&rcu_sched_data), true); } void rcu_bh_qs(void) @@ -302,17 +295,16 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr); * We inform the RCU core by emulating a zero-duration dyntick-idle * period, which we in turn do by incrementing the ->dynticks counter * by two. + * + * The caller must have disabled interrupts. */ static void rcu_momentary_dyntick_idle(void) { - unsigned long flags; struct rcu_data *rdp; struct rcu_dynticks *rdtp; int resched_mask; struct rcu_state *rsp; - local_irq_save(flags); - /* * Yes, we can lose flag-setting operations. This is OK, because * the flag will be set again after some delay. @@ -342,13 +334,12 @@ static void rcu_momentary_dyntick_idle(void) smp_mb__after_atomic(); /* Later stuff after QS. */ break; } - local_irq_restore(flags); } /* * Note a context switch. This is a quiescent state for RCU-sched, * and requires special handling for preemptible RCU. - * The caller must have disabled preemption. + * The caller must have disabled interrupts. */ void rcu_note_context_switch(void) { @@ -378,9 +369,14 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch); */ void rcu_all_qs(void) { + unsigned long flags; + barrier(); /* Avoid RCU read-side critical sections leaking down. */ - if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) + if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) { + local_irq_save(flags); rcu_momentary_dyntick_idle(); + local_irq_restore(flags); + } this_cpu_inc(rcu_qs_ctr); barrier(); /* Avoid RCU read-side critical sections leaking up. */ } diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 32cbe72bf545..c6fc11d626f8 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -147,8 +147,8 @@ static void __init rcu_bootup_announce(void) * the corresponding expedited grace period will also be the end of the * normal grace period. */ -static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp, - unsigned long flags) __releases(rnp->lock) +static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp) + __releases(rnp->lock) /* But leaves rrupts disabled. */ { int blkd_state = (rnp->gp_tasks ? RCU_GP_TASKS : 0) + (rnp->exp_tasks ? RCU_EXP_TASKS : 0) + @@ -236,7 +236,7 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp, rnp->gp_tasks = &t->rcu_node_entry; if (!rnp->exp_tasks && (blkd_state & RCU_EXP_BLKD)) rnp->exp_tasks = &t->rcu_node_entry; - raw_spin_unlock(&rnp->lock); + raw_spin_unlock(&rnp->lock); /* rrupts remain disabled. */ /* * Report the quiescent state for the expedited GP. This expedited @@ -251,7 +251,6 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp, } else { WARN_ON_ONCE(t->rcu_read_unlock_special.b.exp_need_qs); } - local_irq_restore(flags); } /* @@ -286,12 +285,11 @@ static void rcu_preempt_qs(void) * predating the current grace period drain, in other words, until * rnp->gp_tasks becomes NULL. * - * Caller must disable preemption. + * Caller must disable interrupts. */ static void rcu_preempt_note_context_switch(void) { struct task_struct *t = current; - unsigned long flags; struct rcu_data *rdp; struct rcu_node *rnp; @@ -301,7 +299,7 @@ static void rcu_preempt_note_context_switch(void) /* Possibly blocking in an RCU read-side critical section. */ rdp = this_cpu_ptr(rcu_state_p->rda); rnp = rdp->mynode; - raw_spin_lock_irqsave(&rnp->lock, flags); + raw_spin_lock(&rnp->lock); smp_mb__after_unlock_lock(); t->rcu_read_unlock_special.b.blocked = true; t->rcu_blocked_node = rnp; @@ -318,7 +316,7 @@ static void rcu_preempt_note_context_switch(void) (rnp->qsmask & rdp->grpmask) ? rnp->gpnum : rnp->gpnum + 1); - rcu_preempt_ctxt_queue(rnp, rdp, flags); + rcu_preempt_ctxt_queue(rnp, rdp); } else if (t->rcu_read_lock_nesting < 0 && t->rcu_read_unlock_special.s) { diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4ecca604e64b..2dbe599d34d5 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -621,8 +621,7 @@ void resched_cpu(int cpu) struct rq *rq = cpu_rq(cpu); unsigned long flags; - if (!raw_spin_trylock_irqsave(&rq->lock, flags)) - return; + raw_spin_lock_irqsave(&rq->lock, flags); resched_curr(rq); raw_spin_unlock_irqrestore(&rq->lock, flags); } @@ -3512,7 +3511,6 @@ static void __sched notrace __schedule(bool preempt) cpu = smp_processor_id(); rq = cpu_rq(cpu); - rcu_note_context_switch(); prev = rq->curr; /* @@ -3531,13 +3529,16 @@ static void __sched notrace __schedule(bool preempt) if (sched_feat(HRTICK)) hrtick_clear(rq); + local_irq_disable(); + rcu_note_context_switch(); + /* * Make sure that signal_pending_state()->signal_pending() below * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE) * done by the caller to avoid the race with signal_wake_up(). */ smp_mb__before_spinlock(); - raw_spin_lock_irq(&rq->lock); + raw_spin_lock(&rq->lock); lockdep_pin_lock(&rq->lock); rq->clock_skip_update <<= 1; /* promote REQ to ACT */ diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index a71e94cecdb6..9c56841227cc 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -829,7 +829,6 @@ schedtune_boostgroup_init(struct schedtune *st) bg = &per_cpu(cpu_boost_groups, cpu); bg->group[st->idx].boost = 0; bg->group[st->idx].tasks = 0; - raw_spin_lock_init(&bg->lock); } return 0; diff --git a/mm/page_owner.c b/mm/page_owner.c index 3a9a358e7c63..10b7f196b005 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -129,7 +129,7 @@ static noinline depot_stack_handle_t save_stack(gfp_t flags) .nr_entries = 0, .entries = entries, .max_entries = PAGE_OWNER_STACK_DEPTH, - .skip = 0 + .skip = 2 }; depot_stack_handle_t handle; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index a8cabc876348..329ae3ccfa35 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1073,6 +1073,7 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, */ offset = skb_transport_offset(skb); skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + csum = skb->csum; skb->ip_summed = CHECKSUM_NONE; diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 8a2a489b2cd3..ede54061c554 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -237,7 +237,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, transparent = xt_socket_sk_is_transparent(sk); if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard && - transparent) + transparent && sk_fullsock(sk)) pskb->mark = sk->sk_mark; sock_gen_put(sk); @@ -419,7 +419,7 @@ socket_mt6_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par) transparent = xt_socket_sk_is_transparent(sk); if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard && - transparent) + transparent && sk_fullsock(sk)) pskb->mark = sk->sk_mark; if (sk != skb->sk) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 0727a6e9f780..86005410a22f 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -224,17 +224,16 @@ country BY: DFS-ETSI (5490 - 5710 @ 160), (30), DFS country BZ: - (2402 - 2482 @ 40), (36) - (5170 - 5330 @ 160), (27) - (5490 - 5730 @ 160), (36) - (5735 - 5835 @ 80), (36) + (2402 - 2482 @ 40), (20) + (5170 - 5330 @ 160), (23) + (5490 - 5730 @ 160), (30) + (5735 - 5835 @ 80), (30) country CA: DFS-FCC (2402 - 2472 @ 40), (30) (5170 - 5250 @ 80), (24), AUTO-BW (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5590 @ 80), (24), DFS - (5650 - 5730 @ 80), (24), DFS + (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -683,7 +682,13 @@ country IL: DFS-ETSI country IN: (2402 - 2482 @ 40), (20) (5170 - 5330 @ 160), (23) - (5735 - 5835 @ 80), (30) + (5735 - 5835 @ 80), (33) + +country IQ: DFS-ETSI + (2402 - 2482 @ 40), (20) + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5710 @ 160), (30), DFS country IS: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -737,7 +742,6 @@ country JO: country JP: DFS-JP (2402 - 2482 @ 40), (20) - (2474 - 2494 @ 20), (20), NO-OFDM (5170 - 5250 @ 80), (20), AUTO-BW, NO-OUTDOOR (5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (20), DFS @@ -759,7 +763,7 @@ country KH: DFS-ETSI country KN: DFS-FCC (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5250 - 5330 @ 80), (30), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS (5735 - 5815 @ 80), (30) @@ -1010,7 +1014,7 @@ country MY: DFS-FCC (5170 - 5250 @ 80), (24), AUTO-BW (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5650 @ 160), (24), DFS - (5735 - 5815 @ 80), (24) + (5735 - 5835 @ 80), (24) # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -1090,7 +1094,7 @@ country OM: DFS-ETSI (5490 - 5710 @ 160), (30), DFS country PA: - (2402 - 2472 @ 40), (30) + (2402 - 2472 @ 40), (36) (5170 - 5250 @ 80), (23), AUT0-BW (5250 - 5330 @ 80), (30), AUTO-BW (5735 - 5835 @ 80), (36) @@ -1375,9 +1379,9 @@ country TR: DFS-ETSI country TT: (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (27) - (5490 - 5730 @ 160), (36) - (5735 - 5835 @ 80), (36) + (5170 - 5330 @ 160), (24) + (5490 - 5730 @ 160), (24) + (5735 - 5835 @ 80), (30) # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1451,7 +1455,7 @@ country UY: DFS-FCC country UZ: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW country VC: DFS-ETSI (2402 - 2482 @ 40), (20) diff --git a/sound/core/info.c b/sound/core/info.c index 79dee33b5035..a04016c19f6d 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -754,8 +754,11 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent) INIT_LIST_HEAD(&entry->children); INIT_LIST_HEAD(&entry->list); entry->parent = parent; - if (parent) + if (parent) { + mutex_lock(&parent->access); list_add_tail(&entry->list, &parent->children); + mutex_unlock(&parent->access); + } return entry; } diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index a01c781acdf1..55eef61a01de 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -49,10 +49,10 @@ #define BUS_DOWN 1 /* - * 50 Milliseconds sufficient for DSP bring up in the lpass + * 200 Milliseconds sufficient for DSP bring up in the lpass * after Sub System Restart */ -#define ADSP_STATE_READY_TIMEOUT_MS 50 +#define ADSP_STATE_READY_TIMEOUT_MS 200 #define EAR_PMD 0 #define EAR_PMU 1 diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index 25c318c6c4e1..5f9dc9c0c392 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -215,6 +215,7 @@ static int msm_dig_cdc_codec_config_compander(struct snd_soc_codec *codec, { struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec); int comp_ch_bits_set = 0x03; + int comp_ch_value; dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n", __func__, event, interp_n, @@ -234,15 +235,40 @@ static int msm_dig_cdc_codec_config_compander(struct snd_soc_codec *codec, dig_cdc->set_compander_mode(dig_cdc->handle, 0x00); return 0; }; + comp_ch_value = snd_soc_read(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL); + if (interp_n == 0) { + if ((comp_ch_value & 0x02) == 0x02) { + dev_dbg(codec->dev, + "%s comp ch already enabled\n", + __func__); + return 0; + } + } + if (interp_n == 1) { + if ((comp_ch_value & 0x01) == 0x01) { + dev_dbg(codec->dev, + "%s comp ch already enabled\n", + __func__); + return 0; + } + } dig_cdc->set_compander_mode(dig_cdc->handle, 0x08); /* Enable Compander Clock */ snd_soc_update_bits(codec, MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09); snd_soc_update_bits(codec, MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B1_CTL, - 1 << interp_n, 1 << interp_n); + if (dig_cdc->comp_enabled[MSM89XX_RX1]) { + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 0x02, 0x02); + } + if (dig_cdc->comp_enabled[MSM89XX_RX2]) { + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 0x01, 0x01); + } snd_soc_update_bits(codec, MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01); snd_soc_update_bits(codec, diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c index 1613c5baa9c7..f995bf22c1c3 100644 --- a/sound/soc/codecs/wcd-dsp-mgr.c +++ b/sound/soc/codecs/wcd-dsp-mgr.c @@ -25,7 +25,8 @@ static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type); /* Component related macros */ -#define WDSP_GET_COMPONENT(wdsp, x) (&(wdsp->cmpnts[x])) +#define WDSP_GET_COMPONENT(wdsp, x) ((x >= WDSP_CMPNT_TYPE_MAX || x < 0) ? \ + NULL : (&(wdsp->cmpnts[x]))) #define WDSP_GET_CMPNT_TYPE_STR(x) wdsp_get_cmpnt_type_string(x) /* diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c index b1dff8764618..749f386852c6 100644 --- a/sound/soc/msm/apq8096-auto.c +++ b/sound/soc/msm/apq8096-auto.c @@ -61,6 +61,16 @@ static int msm_quat_mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_sec_mi2s_rate = SAMPLING_RATE_48KHZ; /* TDM default channels */ +static int msm_pri_tdm_tx_0_ch = 2; +static int msm_pri_tdm_tx_1_ch = 2; +static int msm_pri_tdm_tx_2_ch = 2; +static int msm_pri_tdm_tx_3_ch = 2; + +static int msm_pri_tdm_rx_0_ch = 2; +static int msm_pri_tdm_rx_1_ch = 2; +static int msm_pri_tdm_rx_2_ch = 2; +static int msm_pri_tdm_rx_3_ch = 2; + static int msm_sec_tdm_tx_0_ch = 2; /* STEREO MIC */ static int msm_sec_tdm_tx_1_ch = 2; static int msm_sec_tdm_tx_2_ch = 2; @@ -88,6 +98,16 @@ static int msm_quat_tdm_tx_2_ch = 2; /*ENT RECORD*/ static int msm_quat_tdm_tx_3_ch; /* TDM default bit format */ +static int msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; + +static int msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_rx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_rx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_rx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; + static int msm_sec_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_sec_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_sec_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; @@ -114,6 +134,10 @@ static int msm_quat_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_quat_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_quat_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_rate = SAMPLING_RATE_48KHZ; +static int msm_pri_tdm_slot_width = 32; +static int msm_pri_tdm_slot_num = 8; + /* EC Reference default values are set in mixer_paths.xml */ static int msm_ec_ref_ch = 4; static int msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE; @@ -174,11 +198,26 @@ enum { SECONDARY_TDM_TX_5, SECONDARY_TDM_TX_6, SECONDARY_TDM_TX_7, + PRIMARY_TDM_RX_0, + PRIMARY_TDM_RX_1, + PRIMARY_TDM_RX_2, + PRIMARY_TDM_RX_3, + PRIMARY_TDM_RX_4, + PRIMARY_TDM_RX_5, + PRIMARY_TDM_RX_6, + PRIMARY_TDM_RX_7, + PRIMARY_TDM_TX_0, + PRIMARY_TDM_TX_1, + PRIMARY_TDM_TX_2, + PRIMARY_TDM_TX_3, + PRIMARY_TDM_TX_4, + PRIMARY_TDM_TX_5, + PRIMARY_TDM_TX_6, + PRIMARY_TDM_TX_7, TDM_MAX, }; #define TDM_SLOT_OFFSET_MAX 8 - /* TDM default offset */ static unsigned int tdm_slot_offset[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { /* QUAT_TDM_RX */ @@ -235,6 +274,24 @@ static unsigned int tdm_slot_offset[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ + /* PRI_TDM_RX */ + {0, 4, 0xFFFF}, + {8, 12, 0xFFFF}, + {16, 20, 0xFFFF}, + {24, 28, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* PRI_TDM_TX */ + {0, 4, 0xFFFF}, + {8, 12, 0xFFFF}, + {16, 20, 0xFFFF}, + {24, 28, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ }; @@ -300,6 +357,24 @@ static unsigned int tdm_slot_offset_adp_mmxf[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ + /* PRI_TDM_RX */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* PRI_TDM_TX */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ }; static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { @@ -357,6 +432,24 @@ static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ + /* PRI_TDM_RX */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* PRI_TDM_TX */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ }; static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", @@ -389,6 +482,14 @@ static const char *const ec_ref_rate_text[] = {"0", "8000", "16000", static const char *const mi2s_rate_text[] = {"32000", "44100", "48000"}; +static const char *const pri_tdm_rate_text[] = {"8000", "16000", "48000"}; + +static const char *const pri_tdm_slot_num_text[] = {"One", "Two", "Four", + "Eight", "Sixteen", "Thirtytwo"}; + + +static const char *const pri_tdm_slot_width_text[] = {"16", "24", "32"}; + static struct afe_clk_set sec_mi2s_tx_clk = { AFE_API_VERSION_I2S_CONFIG, Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, @@ -698,6 +799,150 @@ static int msm_sec_mi2s_tx_bit_format_put(struct snd_kcontrol *kcontrol, return 0; } +static int msm_pri_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_tx_0_ch = %d\n", __func__, + msm_pri_tdm_tx_0_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_tx_0_ch - 1; + return 0; +} + +static int msm_pri_tdm_tx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_tx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_tx_0_ch = %d\n", __func__, + msm_pri_tdm_tx_0_ch); + return 0; +} + +static int msm_pri_tdm_tx_1_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: pri_tdm_tx_1_ch = %d\n", __func__, + msm_pri_tdm_tx_1_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_tx_1_ch - 1; + return 0; +} + +static int msm_pri_tdm_tx_1_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_tx_1_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_tx_1_ch = %d\n", __func__, + msm_pri_tdm_tx_1_ch); + return 0; +} + +static int msm_pri_tdm_tx_2_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_tx_2_ch = %d\n", __func__, + msm_pri_tdm_tx_2_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_tx_2_ch - 1; + return 0; +} + +static int msm_pri_tdm_tx_2_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_tx_2_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_tx_2_ch = %d\n", __func__, + msm_pri_tdm_tx_2_ch); + return 0; +} + +static int msm_pri_tdm_tx_3_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_tx_3_ch = %d\n", __func__, + msm_pri_tdm_tx_3_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_tx_3_ch - 1; + return 0; +} + +static int msm_pri_tdm_tx_3_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_tx_3_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_tx_3_ch = %d\n", __func__, + msm_pri_tdm_tx_3_ch); + return 0; +} + +static int msm_pri_tdm_rx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_rx_0_ch = %d\n", __func__, + msm_pri_tdm_rx_0_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_rx_0_ch - 1; + return 0; +} + +static int msm_pri_tdm_rx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_rx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_rx_0_ch = %d\n", __func__, + msm_pri_tdm_rx_0_ch); + return 0; +} + +static int msm_pri_tdm_rx_1_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_rx_1_ch = %d\n", __func__, + msm_pri_tdm_rx_1_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_rx_1_ch - 1; + return 0; +} + +static int msm_pri_tdm_rx_1_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_rx_1_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_rx_1_ch = %d\n", __func__, + msm_pri_tdm_rx_1_ch); + return 0; +} + +static int msm_pri_tdm_rx_2_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_rx_2_ch = %d\n", __func__, + msm_pri_tdm_rx_2_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_rx_2_ch - 1; + return 0; +} + +static int msm_pri_tdm_rx_2_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_rx_2_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_rx_2_ch = %d\n", __func__, + msm_pri_tdm_rx_2_ch); + return 0; +} + +static int msm_pri_tdm_rx_3_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_rx_3_ch = %d\n", __func__, + msm_pri_tdm_rx_3_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_rx_3_ch - 1; + return 0; +} + +static int msm_pri_tdm_rx_3_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_rx_3_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_rx_3_ch = %d\n", __func__, + msm_pri_tdm_rx_3_ch); + return 0; +} + static int msm_sec_mi2s_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -728,6 +973,174 @@ static int msm_sec_mi2s_rate_put(struct snd_kcontrol *kcontrol, return 0; } +static int msm_pri_tdm_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = msm_pri_tdm_rate; + pr_debug("%s: msm_pri_tdm_rate = %d\n", __func__, msm_pri_tdm_rate); + return 0; +} + +static int msm_pri_tdm_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_pri_tdm_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + msm_pri_tdm_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + msm_pri_tdm_rate = SAMPLING_RATE_48KHZ; + break; + default: + msm_pri_tdm_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("%s: msm_pri_tdm_rate = %d\n", + __func__, msm_pri_tdm_rate); + return 0; +} + +static int msm_pri_tdm_slot_width_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = msm_pri_tdm_slot_width; + pr_debug("%s: msm_pri_tdm_slot_width = %d\n", + __func__, msm_pri_tdm_slot_width); + return 0; +} + +static int msm_pri_tdm_slot_width_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_pri_tdm_slot_width = 16; + break; + case 1: + msm_pri_tdm_slot_width = 24; + break; + case 2: + msm_pri_tdm_slot_width = 32; + break; + default: + msm_pri_tdm_slot_width = 32; + break; + } + pr_debug("%s: msm_pri_tdm_slot_width= %d\n", + __func__, msm_pri_tdm_slot_width); + return 0; +} + +static int msm_pri_tdm_slot_num_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_slot_num) { + case 1: + ucontrol->value.integer.value[0] = 0; + break; + case 2: + ucontrol->value.integer.value[0] = 1; + break; + case 4: + ucontrol->value.integer.value[0] = 2; + break; + case 8: + ucontrol->value.integer.value[0] = 3; + break; + case 16: + ucontrol->value.integer.value[0] = 4; + break; + case 32: + default: + ucontrol->value.integer.value[0] = 5; + break; + } + + pr_debug("%s: msm_pri_tdm_slot_num = %d\n", + __func__, msm_pri_tdm_slot_num); + return 0; +} + +static int msm_pri_tdm_slot_num_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_pri_tdm_slot_num = 1; + break; + case 1: + msm_pri_tdm_slot_num = 2; + break; + case 2: + msm_pri_tdm_slot_num = 4; + break; + case 3: + msm_pri_tdm_slot_num = 8; + break; + case 4: + msm_pri_tdm_slot_num = 16; + break; + case 5: + msm_pri_tdm_slot_num = 32; + break; + default: + msm_pri_tdm_slot_num = 8; + break; + } + pr_debug("%s: msm_pri_tdm_slot_num = %d\n", + __func__, msm_pri_tdm_slot_num); + return 0; +} + +static int msm_tdm_slot_mapping_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_multi_mixer_control *mc = + (struct soc_multi_mixer_control *)kcontrol->private_value; + unsigned int *slot_offset; + int i; + + if (mc->shift >= TDM_MAX) { + pr_err("%s invalid port index %d\n", __func__, mc->shift); + return -EINVAL; + } + + slot_offset = tdm_slot_offset[mc->shift]; + for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) { + ucontrol->value.integer.value[i] = slot_offset[i]; + pr_debug("%s port index %d offset %d value %d\n", + __func__, mc->shift, i, slot_offset[i]); + } + + return 0; +} + +static int msm_tdm_slot_mapping_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_multi_mixer_control *mc = + (struct soc_multi_mixer_control *)kcontrol->private_value; + unsigned int *slot_offset; + int i; + + if (mc->shift >= TDM_MAX) { + pr_err("%s invalid port index %d\n", __func__, mc->shift); + return -EINVAL; + } + + slot_offset = tdm_slot_offset[mc->shift]; + + for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) { + slot_offset[i] = ucontrol->value.integer.value[i]; + pr_debug("%s port index %d offset %d value %d\n", + __func__, mc->shift, i, slot_offset[i]); + } + + return 0; +} static int msm_sec_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1107,6 +1520,278 @@ static int msm_quat_tdm_tx_3_ch_put(struct snd_kcontrol *kcontrol, return 0; } +static int msm_pri_tdm_tx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_0_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_tx_0_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_tx_0_bit_format = %d\n", + __func__, msm_pri_tdm_tx_0_bit_format); + return 0; +} + +static int msm_pri_tdm_tx_1_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_1_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_tx_1_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_1_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_tx_1_bit_format = %d\n", + __func__, msm_pri_tdm_tx_1_bit_format); + return 0; +} + +static int msm_pri_tdm_tx_2_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_2_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_tx_2_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_2_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_tx_2_bit_format = %d\n", + __func__, msm_pri_tdm_tx_2_bit_format); + return 0; +} + +static int msm_pri_tdm_tx_3_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_3_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_tx_3_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_3_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_tx_3_bit_format = %d\n", + __func__, msm_pri_tdm_tx_3_bit_format); + return 0; +} + +static int msm_pri_tdm_rx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_0_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_rx_0_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_rx_0_bit_format = %d\n", + __func__, msm_pri_tdm_rx_0_bit_format); + return 0; +} + +static int msm_pri_tdm_rx_1_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_1_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_rx_1_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_1_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_rx_1_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_rx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_rx_1_bit_format = %d\n", + __func__, msm_pri_tdm_rx_1_bit_format); + return 0; +} + +static int msm_pri_tdm_rx_2_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_2_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_rx_2_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_2_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_rx_2_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_rx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_rx_2_bit_format = %d\n", + __func__, msm_pri_tdm_rx_2_bit_format); + return 0; +} + +static int msm_pri_tdm_rx_3_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_3_bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_rx_3_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_3_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + msm_pri_tdm_rx_3_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_rx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_rx_3_bit_format = %d\n", + __func__, msm_pri_tdm_rx_3_bit_format); + return 0; +} + static int msm_sec_tdm_tx_0_bit_format_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2070,7 +2755,57 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + rate->min = rate->max = SAMPLING_RATE_48KHZ; + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_TX: + channels->min = channels->max = msm_pri_tdm_tx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_tx_0_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_1: + channels->min = channels->max = msm_pri_tdm_tx_1_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_tx_1_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_2: + channels->min = channels->max = msm_pri_tdm_tx_2_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_tx_2_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_3: + channels->min = channels->max = msm_pri_tdm_tx_3_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_tx_3_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX: + channels->min = channels->max = msm_pri_tdm_rx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_rx_0_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_1: + channels->min = channels->max = msm_pri_tdm_rx_1_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_rx_1_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_2: + channels->min = channels->max = msm_pri_tdm_rx_2_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_rx_2_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_3: + channels->min = channels->max = msm_pri_tdm_rx_3_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_rx_3_bit_format); + rate->min = rate->max = msm_pri_tdm_rate; + break; case AFE_PORT_ID_SECONDARY_TDM_TX: channels->min = channels->max = msm_sec_tdm_tx_0_ch; param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, @@ -2181,7 +2916,6 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, __func__, cpu_dai->id); return -EINVAL; } - rate->min = rate->max = SAMPLING_RATE_48KHZ; pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n", __func__, cpu_dai->id, channels->max, rate->max, @@ -2300,99 +3034,18 @@ static struct snd_soc_ops apq8096_mi2s_be_ops = { .shutdown = apq8096_mi2s_snd_shutdown, }; -static unsigned int tdm_param_set_slot_mask(u16 port_id, - int slot_width, int slots) +static unsigned int tdm_param_set_slot_mask(int slots) { unsigned int slot_mask = 0; - int upper, lower, i, j; - unsigned int *slot_offset; + unsigned int i = 0; - switch (port_id) { - case AFE_PORT_ID_SECONDARY_TDM_RX: - case AFE_PORT_ID_SECONDARY_TDM_RX_1: - case AFE_PORT_ID_SECONDARY_TDM_RX_2: - case AFE_PORT_ID_SECONDARY_TDM_RX_3: - case AFE_PORT_ID_SECONDARY_TDM_RX_4: - case AFE_PORT_ID_SECONDARY_TDM_RX_5: - case AFE_PORT_ID_SECONDARY_TDM_RX_6: - case AFE_PORT_ID_SECONDARY_TDM_RX_7: - lower = SECONDARY_TDM_RX_0; - upper = SECONDARY_TDM_RX_7; - break; - case AFE_PORT_ID_SECONDARY_TDM_TX: - case AFE_PORT_ID_SECONDARY_TDM_TX_1: - case AFE_PORT_ID_SECONDARY_TDM_TX_2: - case AFE_PORT_ID_SECONDARY_TDM_TX_3: - case AFE_PORT_ID_SECONDARY_TDM_TX_4: - case AFE_PORT_ID_SECONDARY_TDM_TX_5: - case AFE_PORT_ID_SECONDARY_TDM_TX_6: - case AFE_PORT_ID_SECONDARY_TDM_TX_7: - lower = SECONDARY_TDM_TX_0; - upper = SECONDARY_TDM_TX_7; - break; - case AFE_PORT_ID_TERTIARY_TDM_RX: - case AFE_PORT_ID_TERTIARY_TDM_RX_1: - case AFE_PORT_ID_TERTIARY_TDM_RX_2: - case AFE_PORT_ID_TERTIARY_TDM_RX_3: - case AFE_PORT_ID_TERTIARY_TDM_RX_4: - case AFE_PORT_ID_TERTIARY_TDM_RX_5: - case AFE_PORT_ID_TERTIARY_TDM_RX_6: - case AFE_PORT_ID_TERTIARY_TDM_RX_7: - lower = TERTIARY_TDM_RX_0; - upper = TERTIARY_TDM_RX_7; - break; - case AFE_PORT_ID_TERTIARY_TDM_TX: - case AFE_PORT_ID_TERTIARY_TDM_TX_1: - case AFE_PORT_ID_TERTIARY_TDM_TX_2: - case AFE_PORT_ID_TERTIARY_TDM_TX_3: - case AFE_PORT_ID_TERTIARY_TDM_TX_4: - case AFE_PORT_ID_TERTIARY_TDM_TX_5: - case AFE_PORT_ID_TERTIARY_TDM_TX_6: - case AFE_PORT_ID_TERTIARY_TDM_TX_7: - lower = TERTIARY_TDM_TX_0; - upper = TERTIARY_TDM_TX_7; - break; - case AFE_PORT_ID_QUATERNARY_TDM_RX: - case AFE_PORT_ID_QUATERNARY_TDM_RX_1: - case AFE_PORT_ID_QUATERNARY_TDM_RX_2: - case AFE_PORT_ID_QUATERNARY_TDM_RX_3: - case AFE_PORT_ID_QUATERNARY_TDM_RX_4: - case AFE_PORT_ID_QUATERNARY_TDM_RX_5: - case AFE_PORT_ID_QUATERNARY_TDM_RX_6: - case AFE_PORT_ID_QUATERNARY_TDM_RX_7: - lower = QUATERNARY_TDM_RX_0; - upper = QUATERNARY_TDM_RX_7; - break; - case AFE_PORT_ID_QUATERNARY_TDM_TX: - case AFE_PORT_ID_QUATERNARY_TDM_TX_1: - case AFE_PORT_ID_QUATERNARY_TDM_TX_2: - case AFE_PORT_ID_QUATERNARY_TDM_TX_3: - case AFE_PORT_ID_QUATERNARY_TDM_TX_4: - case AFE_PORT_ID_QUATERNARY_TDM_TX_5: - case AFE_PORT_ID_QUATERNARY_TDM_TX_6: - case AFE_PORT_ID_QUATERNARY_TDM_TX_7: - lower = QUATERNARY_TDM_TX_0; - upper = QUATERNARY_TDM_TX_7; - break; - default: - return slot_mask; - } - - for (i = lower; i <= upper; i++) { - slot_offset = tdm_slot_offset[i]; - for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) { - if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID) - /* - * set the mask of active slot according to - * the offset table for the group of devices - */ - slot_mask |= - (1 << ((slot_offset[j] * 8) / slot_width)); - else - break; - } + if ((slots != 16) && (slots != 8)) { + pr_err("%s: invalid slot number %d\n", __func__, slots); + return -EINVAL; } + for (i = 0; i < slots ; i++) + slot_mask |= 1 << i; return slot_mask; } @@ -2402,14 +3055,16 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; - int channels, slot_width, slots; + int channels, slot_width, slots, rate; unsigned int slot_mask; unsigned int *slot_offset; int offset_channels = 0; int i; + int clk_freq; pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + rate = params_rate(params); channels = params_channels(params); if (channels < 1 || channels > 8) { pr_err("%s: invalid param channels %d\n", @@ -2435,15 +3090,88 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, } slots = msm_tdm_num_slots; - slot_mask = tdm_param_set_slot_mask(cpu_dai->id, - slot_width, slots); - if (!slot_mask) { - pr_err("%s: invalid slot_mask 0x%x\n", - __func__, slot_mask); - return -EINVAL; - } switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_0]; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_1: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_1]; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_2: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_2]; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_3: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_3]; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_4: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_4]; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_5: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_5]; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_6: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_6]; + break; + case AFE_PORT_ID_PRIMARY_TDM_RX_7: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_7]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_0]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_1: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_1]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_2: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_2]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_3: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_3]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_4: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_4]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_5: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_5]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_6: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_6]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX_7: + slots = msm_pri_tdm_slot_num; + slot_width = msm_pri_tdm_slot_width; + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_7]; + break; case AFE_PORT_ID_SECONDARY_TDM_RX: slot_offset = tdm_slot_offset[SECONDARY_TDM_RX_0]; break; @@ -2613,6 +3341,13 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + slot_mask = tdm_param_set_slot_mask(slots); + if (!slot_mask) { + pr_err("%s: invalid slot_mask 0x%x\n", + __func__, slot_mask); + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask, slots, slot_width); @@ -2647,6 +3382,13 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, } } + clk_freq = rate * slot_width * slots; + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, clk_freq, SND_SOC_CLOCK_OUT); + if (ret < 0) { + pr_err("%s: failed to set tdm clk, err:%d\n", + __func__, ret); + } + end: return ret; } @@ -2668,6 +3410,9 @@ static const struct soc_enum msm_snd_enum[] = { SOC_ENUM_SINGLE_EXT(3, ec_ref_bit_format_text), SOC_ENUM_SINGLE_EXT(9, ec_ref_rate_text), SOC_ENUM_SINGLE_EXT(3, mi2s_rate_text), + SOC_ENUM_SINGLE_EXT(3, pri_tdm_rate_text), + SOC_ENUM_SINGLE_EXT(6, pri_tdm_slot_num_text), + SOC_ENUM_SINGLE_EXT(3, pri_tdm_slot_width_text), }; static const struct snd_kcontrol_new msm_snd_controls[] = { @@ -2681,6 +3426,22 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_proxy_rx_ch_get, msm_proxy_rx_ch_put), SOC_ENUM_EXT("HDMI_RX SampleRate", msm_snd_enum[4], hdmi_rx_sample_rate_get, hdmi_rx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", msm_snd_enum[5], + msm_pri_tdm_tx_0_ch_get, msm_pri_tdm_tx_0_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_1 Channels", msm_snd_enum[5], + msm_pri_tdm_tx_1_ch_get, msm_pri_tdm_tx_1_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_2 Channels", msm_snd_enum[5], + msm_pri_tdm_tx_2_ch_get, msm_pri_tdm_tx_2_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_3 Channels", msm_snd_enum[5], + msm_pri_tdm_tx_3_ch_get, msm_pri_tdm_tx_3_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", msm_snd_enum[5], + msm_pri_tdm_rx_0_ch_get, msm_pri_tdm_rx_0_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_1 Channels", msm_snd_enum[5], + msm_pri_tdm_rx_1_ch_get, msm_pri_tdm_rx_1_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_2 Channels", msm_snd_enum[5], + msm_pri_tdm_rx_2_ch_get, msm_pri_tdm_rx_2_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_3 Channels", msm_snd_enum[5], + msm_pri_tdm_rx_3_ch_get, msm_pri_tdm_rx_3_ch_put), SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", msm_snd_enum[5], msm_sec_tdm_tx_0_ch_get, msm_sec_tdm_tx_0_ch_put), SOC_ENUM_EXT("SEC_TDM_TX_1 Channels", msm_snd_enum[5], @@ -2723,6 +3484,30 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_quat_tdm_tx_2_ch_get, msm_quat_tdm_tx_2_ch_put), SOC_ENUM_EXT("QUAT_TDM_TX_3 Channels", msm_snd_enum[5], msm_quat_tdm_tx_3_ch_get, msm_quat_tdm_tx_3_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Bit Format", msm_snd_enum[6], + msm_pri_tdm_tx_0_bit_format_get, + msm_pri_tdm_tx_0_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_1 Bit Format", msm_snd_enum[6], + msm_pri_tdm_tx_1_bit_format_get, + msm_pri_tdm_tx_1_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_2 Bit Format", msm_snd_enum[6], + msm_pri_tdm_tx_2_bit_format_get, + msm_pri_tdm_tx_2_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_3 Bit Format", msm_snd_enum[6], + msm_pri_tdm_tx_3_bit_format_get, + msm_pri_tdm_tx_3_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Bit Format", msm_snd_enum[6], + msm_pri_tdm_rx_0_bit_format_get, + msm_pri_tdm_rx_0_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_1 Bit Format", msm_snd_enum[6], + msm_pri_tdm_rx_1_bit_format_get, + msm_pri_tdm_rx_1_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_2 Bit Format", msm_snd_enum[6], + msm_pri_tdm_rx_2_bit_format_get, + msm_pri_tdm_rx_2_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_3 Bit Format", msm_snd_enum[6], + msm_pri_tdm_rx_3_bit_format_get, + msm_pri_tdm_rx_3_bit_format_put), SOC_ENUM_EXT("SEC_TDM_TX_0 Bit Format", msm_snd_enum[6], msm_sec_tdm_tx_0_bit_format_get, msm_sec_tdm_tx_0_bit_format_put), @@ -2797,6 +3582,268 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_sec_mi2s_tx_bit_format_put), SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", msm_snd_enum[11], msm_sec_mi2s_rate_get, msm_sec_mi2s_rate_put), + SOC_ENUM_EXT("PRI_TDM SampleRate", msm_snd_enum[12], + msm_pri_tdm_rate_get, msm_pri_tdm_rate_put), + SOC_ENUM_EXT("PRI_TDM Slot Number", msm_snd_enum[13], + msm_pri_tdm_slot_num_get, msm_pri_tdm_slot_num_put), + SOC_ENUM_EXT("PRI_TDM Slot Width", msm_snd_enum[14], + msm_pri_tdm_slot_width_get, msm_pri_tdm_slot_width_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_RX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, + PRIMARY_TDM_TX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_RX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, + SECONDARY_TDM_TX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_RX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, + TERTIARY_TDM_TX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_RX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_0, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_1, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_2, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_3, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_4, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_5, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_6, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), + SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, + QUATERNARY_TDM_TX_7, 0xFFFF, + 0, 8, msm_tdm_slot_mapping_get, + msm_tdm_slot_mapping_put), SOC_ENUM_EXT("EC Reference Channels", msm_snd_enum[8], msm_ec_ref_ch_get, msm_ec_ref_ch_put), SOC_ENUM_EXT("EC Reference Bit Format", msm_snd_enum[9], @@ -3806,6 +4853,126 @@ static struct snd_soc_dai_link apq8096_auto_fe_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, + { + .name = "Primary TDM RX 0 Hostless", + .stream_name = "Primary TDM RX 0 Hostless", + .cpu_dai_name = "PRI_TDM_RX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM RX 1 Hostless", + .stream_name = "Primary TDM RX 1 Hostless", + .cpu_dai_name = "PRI_TDM_RX_1_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM RX 2 Hostless", + .stream_name = "Primary TDM RX 2 Hostless", + .cpu_dai_name = "PRI_TDM_RX_2_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM RX 3 Hostless", + .stream_name = "Primary TDM RX 3 Hostless", + .cpu_dai_name = "PRI_TDM_RX_3_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM TX 0 Hostless", + .stream_name = "Primary TDM TX 0 Hostless", + .cpu_dai_name = "PRI_TDM_TX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM TX 1 Hostless", + .stream_name = "Primary TDM TX 1 Hostless", + .cpu_dai_name = "PRI_TDM_TX_1_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM TX 2 Hostless", + .stream_name = "Primary TDM TX 2 Hostless", + .cpu_dai_name = "PRI_TDM_TX_2_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM TX 3 Hostless", + .stream_name = "Primary TDM TX 3 Hostless", + .cpu_dai_name = "PRI_TDM_TX_3_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + } }; static struct snd_soc_dai_link apq8096_custom_fe_dai_links[] = { @@ -4452,6 +5619,118 @@ static struct snd_soc_dai_link apq8096_auto_be_dai_links[] = { .ops = &apq8096_tdm_be_ops, .ignore_suspend = 1, }, + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = "Primary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36864", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_RX_1, + .stream_name = "Primary TDM1 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36866", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_1, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_RX_2, + .stream_name = "Primary TDM2 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36868", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_2, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_RX_3, + .stream_name = "Primary TDM3 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36870", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_3, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = "Primary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36865", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_1, + .stream_name = "Primary TDM1 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36867", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_1, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_2, + .stream_name = "Primary TDM2 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36869", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_2, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_3, + .stream_name = "Primary TDM3 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36871", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_3, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &apq8096_tdm_be_ops, + .ignore_suspend = 1, + } }; static struct snd_soc_dai_link apq8096_hdmi_dai_link[] = { @@ -4795,7 +6074,6 @@ static int apq8096_asoc_machine_probe(struct platform_device *pdev) goto err; } dev_info(&pdev->dev, "Sound card %s registered\n", card->name); - return 0; err: diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c index 35270e3340ec..ae6767d26921 100644 --- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c +++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c @@ -1167,7 +1167,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, case SNDRV_LSM_SET_FWK_MODE_CONFIG: { u32 mode; - if (copy_from_user(&mode, arg, sizeof(mode))) { + if (copy_from_user(&mode, (void __user *) arg, sizeof(mode))) { dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n", __func__, "LSM_SET_FWK_MODE_CONFIG"); return -EFAULT; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index b94eb6fbfeea..0d01803e634d 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -1448,12 +1448,13 @@ static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd) if (pdata) { if (!pdata->pcm) { pdata->pcm = rtd->pcm; - snd_soc_add_platform_controls(rtd->platform, - pcm_compress_control, - ARRAY_SIZE - (pcm_compress_control)); - pr_debug("%s: add control success plt = %pK\n", - __func__, rtd->platform); + ret = snd_soc_add_platform_controls(rtd->platform, + pcm_compress_control, + ARRAY_SIZE + (pcm_compress_control)); + if (ret < 0) + pr_err("%s: failed add ctl %s. err = %d\n", + __func__, mixer_str, ret); } } else { pr_err("%s: NULL pdata\n", __func__); @@ -1603,24 +1604,47 @@ done: return ret; } +static int msm_pcm_playback_pan_scale_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(struct asm_stream_pan_ctrl_params); + return 0; +} + static int msm_pcm_playback_pan_scale_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret = 0; int len = 0; int i = 0; - struct snd_pcm_usr *usr_info = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform; + struct msm_plat_data *pdata; struct snd_pcm_substream *substream; struct msm_audio *prtd; struct asm_stream_pan_ctrl_params pan_param; - + char *usr_value = NULL; + uint32_t *gain_ptr = NULL; if (!usr_info) { pr_err("%s: usr_info is null\n", __func__); ret = -EINVAL; goto done; } - substream = usr_info->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + platform = snd_soc_component_to_platform(usr_info); + if (!platform) { + pr_err("%s: platform is null\n", __func__); + ret = -EINVAL; + goto done; + } + pdata = dev_get_drvdata(platform->dev); + if (!pdata) { + pr_err("%s: pdata is null\n", __func__); + ret = -EINVAL; + goto done; + } + substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (!substream) { pr_err("%s substream not found\n", __func__); ret = -EINVAL; @@ -1637,54 +1661,71 @@ static int msm_pcm_playback_pan_scale_ctl_put(struct snd_kcontrol *kcontrol, ret = -EINVAL; goto done; } - pan_param.num_output_channels = - ucontrol->value.integer.value[len++]; + usr_value = (char *) ucontrol->value.bytes.data; + if (!usr_value) { + pr_err("%s ucontrol data is null\n", __func__); + ret = -EINVAL; + goto done; + } + memcpy(&pan_param.num_output_channels, &usr_value[len], + sizeof(pan_param.num_output_channels)); + len += sizeof(pan_param.num_output_channels); if (pan_param.num_output_channels > PCM_FORMAT_MAX_NUM_CHANNEL) { ret = -EINVAL; goto done; } - pan_param.num_input_channels = - ucontrol->value.integer.value[len++]; + memcpy(&pan_param.num_input_channels, &usr_value[len], + sizeof(pan_param.num_input_channels)); + len += sizeof(pan_param.num_input_channels); if (pan_param.num_input_channels > PCM_FORMAT_MAX_NUM_CHANNEL) { ret = -EINVAL; goto done; } - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < pan_param.num_output_channels; i++) { - pan_param.output_channel_map[i] = - ucontrol->value.integer.value[len++]; - } + if (usr_value[len++]) { + memcpy(pan_param.output_channel_map, &usr_value[len], + (pan_param.num_output_channels * + sizeof(pan_param.output_channel_map[0]))); + len += (pan_param.num_output_channels * + sizeof(pan_param.output_channel_map[0])); } - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < pan_param.num_input_channels; i++) { - pan_param.input_channel_map[i] = - ucontrol->value.integer.value[len++]; - } + if (usr_value[len++]) { + memcpy(pan_param.input_channel_map, &usr_value[len], + (pan_param.num_input_channels * + sizeof(pan_param.input_channel_map[0]))); + len += (pan_param.num_input_channels * + sizeof(pan_param.input_channel_map[0])); } - if (ucontrol->value.integer.value[len++]) { + if (usr_value[len++]) { + gain_ptr = (uint32_t *) &usr_value[len]; for (i = 0; i < pan_param.num_output_channels * pan_param.num_input_channels; i++) { pan_param.gain[i] = - !(ucontrol->value.integer.value[len++] > 0) ? + !(gain_ptr[i] > 0) ? 0 : 2 << 13; + len += sizeof(pan_param.gain[i]); } + len += (pan_param.num_input_channels * + pan_param.num_output_channels * sizeof(pan_param.gain[0])); } ret = q6asm_set_mfc_panning_params(prtd->audio_client, &pan_param); len -= pan_param.num_output_channels * - pan_param.num_input_channels; - for (i = 0; i < pan_param.num_output_channels * - pan_param.num_input_channels; i++) { - /* - * The data userspace passes is already in Q14 format. - * For volume gain is in Q28. - */ - pan_param.gain[i] = - ucontrol->value.integer.value[len++] << 14; + pan_param.num_input_channels * sizeof(pan_param.gain[0]); + if (gain_ptr) { + for (i = 0; i < pan_param.num_output_channels * + pan_param.num_input_channels; i++) { + /* + * The data userspace passes is already in Q14 format. + * For volume gain is in Q28. + */ + pan_param.gain[i] = + (gain_ptr[i]) << 14; + len += sizeof(pan_param.gain[i]); + } } ret = q6asm_set_vol_ctrl_gain_pair(prtd->audio_client, &pan_param); @@ -1701,40 +1742,60 @@ static int msm_pcm_playback_pan_scale_ctl_get(struct snd_kcontrol *kcontrol, static int msm_add_stream_pan_scale_controls(struct snd_soc_pcm_runtime *rtd) { - struct snd_pcm *pcm; - struct snd_pcm_usr *pan_ctl_info; - struct snd_kcontrol *kctl; const char *playback_mixer_ctl_name = "Audio Stream"; const char *deviceNo = "NN"; const char *suffix = "Pan Scale Control"; - int ctl_len, ret = 0; + char *mixer_str = NULL; + int ctl_len; + int ret = 0; + struct msm_plat_data *pdata; + struct snd_kcontrol_new pan_scale_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_pcm_playback_pan_scale_ctl_info, + .get = msm_pcm_playback_pan_scale_ctl_get, + .put = msm_pcm_playback_pan_scale_ctl_put, + .private_value = 0, + } + }; if (!rtd) { - pr_err("%s: rtd is NULL\n", __func__); - ret = -EINVAL; - goto done; + pr_err("%s: NULL rtd\n", __func__); + return -EINVAL; } - pcm = rtd->pcm; - ctl_len = strlen(playback_mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + - strlen(suffix) + 1; - - ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, - NULL, 1, ctl_len, rtd->dai_link->be_id, - &pan_ctl_info); - - if (ret < 0) { - pr_err("%s: failed add ctl %s. err = %d\n", - __func__, suffix, ret); + ctl_len = strlen(playback_mixer_ctl_name) + 1 + + strlen(deviceNo) + 1 + strlen(suffix) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; goto done; } - kctl = pan_ctl_info->kctl; - snprintf(kctl->id.name, ctl_len, "%s %d %s", playback_mixer_ctl_name, - rtd->pcm->device, suffix); - kctl->put = msm_pcm_playback_pan_scale_ctl_put; - kctl->get = msm_pcm_playback_pan_scale_ctl_get; - pr_debug("%s: Registering new mixer ctl = %s\n", __func__, - kctl->id.name); + + snprintf(mixer_str, ctl_len, "%s %d %s", + playback_mixer_ctl_name, rtd->pcm->device, suffix); + pan_scale_control[0].name = mixer_str; + pan_scale_control[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + pdata = dev_get_drvdata(rtd->platform->dev); + if (pdata) { + if (!pdata->pcm) + pdata->pcm = rtd->pcm; + ret = snd_soc_add_platform_controls(rtd->platform, + pan_scale_control, + ARRAY_SIZE + (pan_scale_control)); + if (ret < 0) + pr_err("%s: failed add ctl %s. err = %d\n", + __func__, mixer_str, ret); + } else { + pr_err("%s: NULL pdata\n", __func__); + ret = -EINVAL; + } + + kfree(mixer_str); done: return ret; @@ -1746,18 +1807,28 @@ static int msm_pcm_playback_dnmix_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +static int msm_pcm_playback_dnmix_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(struct asm_stream_pan_ctrl_params); + return 0; +} + static int msm_pcm_playback_dnmix_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret = 0; int len = 0; - int i = 0; - struct snd_pcm_usr *usr_info = snd_kcontrol_chip(kcontrol); + + struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform; + struct msm_plat_data *pdata; struct snd_pcm_substream *substream; struct msm_audio *prtd; struct asm_stream_pan_ctrl_params dnmix_param; - - int be_id = ucontrol->value.integer.value[len++]; + char *usr_value; + int be_id = 0; int stream_id = 0; if (!usr_info) { @@ -1765,7 +1836,19 @@ static int msm_pcm_playback_dnmix_ctl_put(struct snd_kcontrol *kcontrol, ret = -EINVAL; goto done; } - substream = usr_info->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + platform = snd_soc_component_to_platform(usr_info); + if (!platform) { + pr_err("%s platform is null\n", __func__); + ret = -EINVAL; + goto done; + } + pdata = dev_get_drvdata(platform->dev); + if (!pdata) { + pr_err("%s pdata is null\n", __func__); + ret = -EINVAL; + goto done; + } + substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (!substream) { pr_err("%s substream not found\n", __func__); ret = -EINVAL; @@ -1781,40 +1864,51 @@ static int msm_pcm_playback_dnmix_ctl_put(struct snd_kcontrol *kcontrol, ret = -EINVAL; goto done; } + usr_value = (char *) ucontrol->value.bytes.data; + if (!usr_value) { + pr_err("%s usrvalue is null\n", __func__); + goto done; + } + memcpy(&be_id, usr_value, sizeof(be_id)); + len += sizeof(be_id); stream_id = prtd->audio_client->session; - dnmix_param.num_output_channels = - ucontrol->value.integer.value[len++]; + memcpy(&dnmix_param.num_output_channels, &usr_value[len], + sizeof(dnmix_param.num_output_channels)); + len += sizeof(dnmix_param.num_output_channels); if (dnmix_param.num_output_channels > PCM_FORMAT_MAX_NUM_CHANNEL) { ret = -EINVAL; goto done; } - dnmix_param.num_input_channels = - ucontrol->value.integer.value[len++]; + memcpy(&dnmix_param.num_input_channels, &usr_value[len], + sizeof(dnmix_param.num_input_channels)); + len += sizeof(dnmix_param.num_input_channels); if (dnmix_param.num_input_channels > PCM_FORMAT_MAX_NUM_CHANNEL) { ret = -EINVAL; goto done; } - - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < dnmix_param.num_output_channels; i++) { - dnmix_param.output_channel_map[i] = - ucontrol->value.integer.value[len++]; - } - } - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < dnmix_param.num_input_channels; i++) { - dnmix_param.input_channel_map[i] = - ucontrol->value.integer.value[len++]; - } - } - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < dnmix_param.num_output_channels * - dnmix_param.num_input_channels; i++) { - dnmix_param.gain[i] = - ucontrol->value.integer.value[len++]; - } + if (usr_value[len++]) { + memcpy(dnmix_param.output_channel_map, &usr_value[len], + (dnmix_param.num_output_channels * + sizeof(dnmix_param.output_channel_map[0]))); + len += (dnmix_param.num_output_channels * + sizeof(dnmix_param.output_channel_map[0])); + } + if (usr_value[len++]) { + memcpy(dnmix_param.input_channel_map, &usr_value[len], + (dnmix_param.num_input_channels * + sizeof(dnmix_param.input_channel_map[0]))); + len += (dnmix_param.num_input_channels * + sizeof(dnmix_param.input_channel_map[0])); + } + if (usr_value[len++]) { + memcpy(dnmix_param.gain, (uint32_t *) &usr_value[len], + (dnmix_param.num_input_channels * + dnmix_param.num_output_channels * + sizeof(dnmix_param.gain[0]))); + len += (dnmix_param.num_input_channels * + dnmix_param.num_output_channels * sizeof(dnmix_param.gain[0])); } msm_routing_set_downmix_control_data(be_id, stream_id, @@ -1826,39 +1920,58 @@ done: static int msm_add_device_down_mix_controls(struct snd_soc_pcm_runtime *rtd) { - struct snd_pcm *pcm; - struct snd_pcm_usr *usr_info; - struct snd_kcontrol *kctl; const char *playback_mixer_ctl_name = "Audio Device"; const char *deviceNo = "NN"; const char *suffix = "Downmix Control"; - int ctl_len, ret = 0; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct msm_plat_data *pdata; + struct snd_kcontrol_new device_downmix_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_pcm_playback_dnmix_ctl_info, + .get = msm_pcm_playback_dnmix_ctl_get, + .put = msm_pcm_playback_dnmix_ctl_put, + .private_value = 0, + } + }; if (!rtd) { - pr_err("%s: rtd is NULL\n", __func__); + pr_err("%s NULL rtd\n", __func__); ret = -EINVAL; goto done; } - - pcm = rtd->pcm; ctl_len = strlen(playback_mixer_ctl_name) + 1 + - strlen(deviceNo) + 1 + strlen(suffix) + 1; - ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, - NULL, 1, ctl_len, rtd->dai_link->be_id, - &usr_info); - if (ret < 0) { - pr_err("%s: downmix control add failed: %d\n", - __func__, ret); + strlen(deviceNo) + 1 + strlen(suffix) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; goto done; } - kctl = usr_info->kctl; - snprintf(kctl->id.name, ctl_len, "%s %d %s", - playback_mixer_ctl_name, rtd->pcm->device, suffix); - kctl->put = msm_pcm_playback_dnmix_ctl_put; - kctl->get = msm_pcm_playback_dnmix_ctl_get; - pr_debug("%s: downmix control name = %s\n", - __func__, playback_mixer_ctl_name); + snprintf(mixer_str, ctl_len, "%s %d %s", + playback_mixer_ctl_name, rtd->pcm->device, suffix); + device_downmix_control[0].name = mixer_str; + device_downmix_control[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + pdata = dev_get_drvdata(rtd->platform->dev); + if (pdata) { + if (!pdata->pcm) + pdata->pcm = rtd->pcm; + ret = snd_soc_add_platform_controls(rtd->platform, + device_downmix_control, + ARRAY_SIZE + (device_downmix_control)); + if (ret < 0) + pr_err("%s: failed add ctl %s. err = %d\n", + __func__, mixer_str, ret); + } else { + pr_err("%s: NULL pdata\n", __func__); + ret = -EINVAL; + } + kfree(mixer_str); done: return ret; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 2114adae72d7..a45d89f80106 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -11119,7 +11119,7 @@ static int msm_routing_put_app_type_cfg_control(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new app_type_cfg_controls[] = { SOC_SINGLE_MULTI_EXT("App Type Config", SND_SOC_NOPM, 0, - 0xFFFFFFFF, 0, 128, msm_routing_get_app_type_cfg_control, + 0x7FFFFFFF, 0, 128, msm_routing_get_app_type_cfg_control, msm_routing_put_app_type_cfg_control), }; diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 14f9411104b3..c3d86e6cced2 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -44,7 +44,7 @@ #define TRUE 0x01 #define FALSE 0x00 -#define SESSION_MAX 8 +#define SESSION_MAX 9 #define ASM_MAX_CHANNELS 8 enum { ASM_TOPOLOGY_CAL = 0, @@ -1338,7 +1338,7 @@ int q6asm_audio_client_buf_alloc(unsigned int dir, pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session, bufsz, bufcnt); - if (ac->session <= 0 || ac->session > 8) { + if (ac->session <= 0 || ac->session > ASM_ACTIVE_STREAMS_ALLOWED) { pr_err("%s: Session ID is invalid, session = %d\n", __func__, ac->session); goto fail; @@ -1429,7 +1429,7 @@ int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir, __func__, ac->session, bufsz, bufcnt); - if (ac->session <= 0 || ac->session > 8) { + if (ac->session <= 0 || ac->session > ASM_ACTIVE_STREAMS_ALLOWED) { pr_err("%s: Session ID is invalid, session = %d\n", __func__, ac->session); goto fail; @@ -1738,7 +1738,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) return -EINVAL; } - if (ac->session <= 0 || ac->session > 8) { + if (ac->session <= 0 || ac->session > ASM_ACTIVE_STREAMS_ALLOWED) { pr_err("%s: Session ID is invalid, session = %d\n", __func__, ac->session); return -EINVAL; @@ -3368,6 +3368,15 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac, int bytes_to_alloc, rc; size_t len; + mutex_lock(&ac->cmd_lock); + + if (ac->port[dir].buf) { + pr_err("%s: Buffer already allocated\n", __func__); + rc = -EINVAL; + mutex_unlock(&ac->cmd_lock); + goto done; + } + buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL); if (!buf_circ) { @@ -3375,10 +3384,6 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac, goto done; } - mutex_lock(&ac->cmd_lock); - - ac->port[dir].buf = buf_circ; - bytes_to_alloc = bufsz * bufcnt; bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc); @@ -3390,11 +3395,12 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac, if (rc) { pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__, rc); - mutex_unlock(&ac->cmd_lock); kfree(buf_circ); + mutex_unlock(&ac->cmd_lock); goto done; } + ac->port[dir].buf = buf_circ; buf_circ->used = dir ^ 1; buf_circ->size = bytes_to_alloc; buf_circ->actual_size = bytes_to_alloc; @@ -3559,12 +3565,6 @@ int q6asm_open_shared_io(struct audio_client *ac, goto done; } - if (ac->port[dir].buf) { - pr_err("%s: Buffer already allocated\n", __func__); - rc = -EINVAL; - goto done; - } - rc = q6asm_set_shared_circ_buff(ac, open, bufsz, bufcnt, dir); if (rc) @@ -7215,10 +7215,9 @@ int q6asm_send_rtic_event_ack(struct audio_client *ac, goto done; } - q6asm_add_hdr_async(ac, &ack.hdr, + q6asm_stream_add_hdr_async(ac, &ack.hdr, sizeof(struct avs_param_rtic_event_ack) + - params_length, TRUE); - atomic_set(&ac->cmd_state, -1); + params_length, TRUE, ac->stream_id); ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2; ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK; ack.encdec.param_size = params_length; @@ -7228,31 +7227,11 @@ int q6asm_send_rtic_event_ack(struct audio_client *ac, memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack), param, params_length); rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); - if (rc < 0) { + if (rc < 0) pr_err("%s: apr pkt failed for rtic event ack\n", __func__); - rc = -EINVAL; - goto fail_send_param; - } - - rc = wait_event_timeout(ac->cmd_wait, - (atomic_read(&ac->cmd_state) >= 0), 1 * HZ); - if (!rc) { - pr_err("%s: timeout for rtic event ack cmd\n", __func__); - rc = -ETIMEDOUT; - goto fail_send_param; - } - - if (atomic_read(&ac->cmd_state) > 0) { - pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n", - __func__, adsp_err_get_err_str( - atomic_read(&ac->cmd_state))); - rc = adsp_err_get_lnx_err_code( - atomic_read(&ac->cmd_state)); - goto fail_send_param; - } - rc = 0; + else + rc = 0; -fail_send_param: kfree(asm_params); done: return rc; |