diff options
152 files changed, 6313 insertions, 3248 deletions
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index 9a9c045dbf6a..0d7034e20d8d 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -190,6 +190,7 @@ nodes to be present and contain the properties described below. "allwinner,sun6i-a31" "allwinner,sun8i-a23" "arm,psci" + "psci" "brcm,brahma-b15" "marvell,armada-375-smp" "marvell,armada-380-smp" diff --git a/Documentation/devicetree/bindings/arm/msm/android.txt b/Documentation/devicetree/bindings/arm/msm/android.txt new file mode 100644 index 000000000000..db52284892af --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/android.txt @@ -0,0 +1,54 @@ +Android firmware + +Node to specify early mount of vendor partition. + +Required properties + +-compatible: "android,firmware" + +Child nodes: +------------ + +fstab: +------------------------------ + +fstab entry to specify mount attributes of vendor partition. + +Required properties: + +-compatible: "android,fstab" + +Child nodes: +------------ + +vendor: +----------------- + +vendor partition specification. + +Required properties: + +-compatible: "android, vendor" +-dev: block device corresponding to vendor partition +-type: file system type of vendor partition +-mnt_flags: mount flags +-fsmgr_flags: fsmgr flags + +Example: + + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect"; + status = "ok"; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/msm/cec.txt b/Documentation/devicetree/bindings/display/msm/cec.txt new file mode 100644 index 000000000000..ba51b0d1dd18 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/cec.txt @@ -0,0 +1,73 @@ +Qualcomm Technologies, Inc. CEC device + +CEC is a protocol that provides high-level control functions between all of the +various audiovisual products in a user environment. + +Required properties: +- compatible: Must be "qcom,hdmi-cec". +- interrupt-parent: Must be the hdmi interrupt controller. +- interrupts: Interrupt associated with cec. +- reg: Physical base address and length of the controller's registers. +- reg-names: "hdmi_cec". +- clocks: List of Phandles for clock device nodes needed by the device. +- clock-names: List of clock names needed by the device. +- pinctrl-names: Should contain only two values: "cec_active" and "cec_sleep" which stands for the + active and sleep state of pinctrl used in this CEC driver. +- pinctrl-0: The active pinctrl state which is a list of phandles pointing to a pin configuration node. +- pinctrl-1: The sleep pinctrl state which is a list of phandles pointing to a pin configuration node. +- cec-gdsc-supply: Phandle for cec gdsc supply regulator device node. +- qcom,platform-supply-entries: A sub node that lists the elements of the supply. There can be more + than one instance of this binding, in which case the entry would be + appended with the supply entry index. e.g. qcom,platform-supply-entry@0. + -- reg: offset and length of the register set for the device. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio). + -- qcom,supply-min-voltage: minimum voltage level (uV). + -- qcom,supply-max-voltage: maximum voltage level (uV). + -- qcom,supply-enable-load: load drawn (uA) from enabled supply. + -- qcom,supply-disable-load: load drawn (uA) from disabled supply. + + +Optional properties: +- qcom,platform-supply-entries: A sub node that lists the elements of the supply. There can be more + than one instance of this binding, in which case the entry would be + appended with the supply entry index. e.g. qcom,platform-supply-entry@0. + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on. + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on. + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off. + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off. + +Example: + +sde_hdmi_cec: qcom,hdmi-cec@c9a0000 { + compatible = "qcom,hdmi-cec"; + label = "sde_hdmi_cec"; + interrupt-parent = <&sde_hdmi_tx>; + interrupts = <1 0>; + + reg = <0xc9a0000 0x50c>; + reg-names = "hdmi_cec"; + + clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_mdss_ahb_clk>, + <&clock_mmss clk_mmss_mdss_hdmi_clk>; + clock-names = "cec_mnoc_clk", "cec_iface_clk", "cec_core_clk"; + + pinctrl-names = "cec_active", "cec_sleep"; + pinctrl-0 = <&mdss_hdmi_cec_active>; + pinctrl-1 = <&mdss_hdmi_cec_suspend>; + + cec-gdsc-supply = <&gdsc_mdss>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "cec-gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 9e512d1ea763..c16084a89ccf 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -121,6 +121,12 @@ conditions. supported as we are directly comparing client SID with ID bits of SMR registers. +- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator + disable in ms. In case of unmap call, regulator is + enabled/disabled. This may introduce additional delay. For + clients who do not detach, it's not possible to keep regulator + vote while smmu is attached. Type is <u32>. + - clocks : List of clocks to be used during SMMU register access. See Documentation/devicetree/bindings/clock/clock-bindings.txt for information about the format. For each clock specified diff --git a/Documentation/devicetree/bindings/mhi/msm_mhi.txt b/Documentation/devicetree/bindings/mhi/msm_mhi.txt index 5f950604d186..9c5c2fee78d0 100644 --- a/Documentation/devicetree/bindings/mhi/msm_mhi.txt +++ b/Documentation/devicetree/bindings/mhi/msm_mhi.txt @@ -17,7 +17,7 @@ Main node properties: Definition: "qcom,mhi" - qcom,pci-dev_id - Usage: required + Usage: optional Value type: <u32> Definition: Device id reported by modem diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt index 12d32ec74369..012368275db3 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt @@ -145,22 +145,30 @@ First Level Node - FG Gen3 device - qcom,fg-esr-timer-charging Usage: optional - Value type: <u32> + Value type: <prop-encoded-array> Definition: Number of cycles between ESR pulses while the battery is - charging. + charging. Array of 2 elements if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-timer-awake Usage: optional - Value type: <u32> + Value type: <prop-encoded-array> Definition: Number of cycles between ESR pulses while the system is - awake and the battery is discharging. + awake and the battery is discharging. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-timer-asleep Usage: optional - Value type: <u32> + Value type: <prop-encoded-array> Definition: Number of cycles between ESR pulses while the system is asleep and the battery is discharging. This option requires - qcom,fg-esr-timer-awake to be defined. + qcom,fg-esr-timer-awake to be defined. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-pulse-thresh-ma Usage: optional diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index dec5442b33d6..38e056cdc0ee 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -182,6 +182,12 @@ Optional properties: - qcom,msm-pcm-loopback-low-latency : Flag indicating whether the device node is of type low latency. +* msm-transcode-loopback + +Required properties: + + - compatible : "qcom,msm-transcode-loopback" + * msm-dai-q6 [First Level Nodes] @@ -2401,14 +2407,15 @@ Example: qcom,tasha-mclk-clk-freq = <9600000>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>; + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&trans_loopback>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", - "msm-compr-dsp"; + "msm-compr-dsp","msm-transcode-loopback"; asoc-cpu = <&dai_hdmi>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi index ea8fc87c9b67..4081a21b3134 100644 --- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi +++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi @@ -339,6 +339,77 @@ &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; + qcom,sde-plane-id-map { + qcom,sde-plane-id@0 { + reg = <0x0>; + qcom,display-type = "primary"; + qcom,plane-name = "rgb0", "rgb1"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@1 { + reg = <0x1>; + qcom,display-type = "primary"; + qcom,plane-name = "vig0", "vig1"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@2 { + reg = <0x2>; + qcom,display-type = "primary"; + qcom,plane-name = "cursor0"; + qcom,plane-type = "cursor"; + }; + + qcom,sde-plane-id@3 { + reg = <0x3>; + qcom,display-type = "secondary"; + qcom,plane-name = "rgb2"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@4 { + reg = <0x4>; + qcom,display-type = "secondary"; + qcom,plane-name = "vig2"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@5 { + reg = <0x5>; + qcom,display-type = "secondary"; + qcom,plane-name = "dma0"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@6 { + reg = <0x6>; + qcom,display-type = "secondary"; + qcom,plane-name = "cursor1"; + qcom,plane-type = "cursor"; + }; + + qcom,sde-plane-id@7 { + reg = <0x7>; + qcom,display-type = "tertiary"; + qcom,plane-name = "rgb3"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@8 { + reg = <0x8>; + qcom,display-type = "tertiary"; + qcom,plane-name = "vig3"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@9 { + reg = <0x9>; + qcom,display-type = "tertiary"; + qcom,plane-name = "dma1"; + qcom,plane-type = "overlay"; + }; + }; }; &mdss_dsi { @@ -627,14 +698,14 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&compr>, + <&afe>, <&lsm>, <&routing>, <&pcmnoirq>, <&loopback1>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", - "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-routing", "msm-pcm-dsp-noirq", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, @@ -796,7 +867,7 @@ qcom,vin-sel = <2>; /* 1.8 */ qcom,out-strength = <1>; qcom,src-sel = <0>; /* GPIO */ - qcom,master-en = <1>; /* Enable GPIO */ + qcom,master-en = <0>; /* Disable GPIO */ status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts index 497f3f10fe24..840d82fa9084 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.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 @@ -22,7 +22,7 @@ model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP"; compatible = "qcom,apq8096-adp", "qcom,msm8996", "qcom,adp"; qcom,msm-id = <316 0x10001>; - qcom,board-id = <0x02010019 0>; + qcom,board-id = <0x02010019 0>, <0x00010001 0>; }; &spi_9 { diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts index 2c54dfe19e18..ecde7c667f9a 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.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 @@ -21,7 +21,7 @@ model = "Qualcomm Technologies, Inc. APQ 8096 pro v1.1 AUTO CDP"; compatible = "qcom,msm8996-cdp", "qcom,msm8996", "qcom,cdp"; qcom,msm-id = <316 0x10001>; - qcom,board-id = <0x03010001 0>; + qcom,board-id = <0x03010001 0>, <0x00010001 0>; }; &spi_9 { diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi index d4962df321ed..7fce7606720c 100644 --- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi @@ -85,6 +85,10 @@ compatible = "qcom,msm-pcm-loopback"; }; + trans_loopback: qcom,msm-transcode-loopback { + compatible = "qcom,msm-transcode-loopback"; + }; + qcom,msm-dai-mi2s { compatible = "qcom,msm-dai-mi2s"; dai_mi2s0: qcom,msm-dai-q6-mi2s-prim { diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi index 05225f7178e9..93aeef07cfe0 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -550,9 +550,9 @@ io-channel-names = "rradc_batt_id", "rradc_die_temp"; qcom,rradc-base = <0x4500>; - qcom,fg-esr-timer-awake = <96>; - qcom,fg-esr-timer-asleep = <256>; - qcom,fg-esr-timer-charging = <96>; + qcom,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; qcom,cycle-counter-en; status = "okay"; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index 2b0fcb77eaf2..684f6cf9b389 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -337,8 +337,9 @@ io-channels = <&pmi8998_rradc 0>; io-channel-names = "rradc_batt_id"; qcom,rradc-base = <0x4500>; - qcom,fg-esr-timer-awake = <96>; - qcom,fg-esr-timer-asleep = <256>; + qcom,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; qcom,cycle-counter-en; status = "okay"; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index d7d41153e754..a600008341c2 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -548,6 +548,77 @@ &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; + qcom,sde-plane-id-map { + qcom,sde-plane-id@0 { + reg = <0x0>; + qcom,display-type = "primary"; + qcom,plane-name = "rgb0", "rgb1"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@1 { + reg = <0x1>; + qcom,display-type = "primary"; + qcom,plane-name = "vig0", "vig1"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@2 { + reg = <0x2>; + qcom,display-type = "primary"; + qcom,plane-name = "cursor0"; + qcom,plane-type = "cursor"; + }; + + qcom,sde-plane-id@3 { + reg = <0x3>; + qcom,display-type = "secondary"; + qcom,plane-name = "rgb2"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@4 { + reg = <0x4>; + qcom,display-type = "secondary"; + qcom,plane-name = "vig2"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@5 { + reg = <0x5>; + qcom,display-type = "secondary"; + qcom,plane-name = "dma0"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@6 { + reg = <0x6>; + qcom,display-type = "secondary"; + qcom,plane-name = "cursor1"; + qcom,plane-type = "cursor"; + }; + + qcom,sde-plane-id@7 { + reg = <0x7>; + qcom,display-type = "tertiary"; + qcom,plane-name = "rgb3"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@8 { + reg = <0x8>; + qcom,display-type = "tertiary"; + qcom,plane-name = "vig3"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@9 { + reg = <0x9>; + qcom,display-type = "tertiary"; + qcom,plane-name = "dma1"; + qcom,plane-type = "overlay"; + }; + }; }; &dsi_adv_7533_1 { @@ -797,6 +868,13 @@ qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <1>; + + qcom,msm-bus,name = "ntn"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 207108 14432000>; }; i2c@75ba000 { @@ -919,14 +997,14 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&compr>, + <&afe>, <&lsm>, <&routing>, <&pcmnoirq>, <&loopback1>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", - "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-routing", "msm-pcm-dsp-noirq", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, @@ -1112,7 +1190,7 @@ qcom,vin-sel = <2>; /* 1.8 */ qcom,out-strength = <1>; qcom,src-sel = <0>; /* GPIO */ - qcom,master-en = <1>; /* Enable GPIO */ + qcom,master-en = <0>; /* Disable GPIO */ status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index a1299027ae18..7c07102a1fed 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -302,7 +302,7 @@ &mdss_hdmi_cec_suspend>; }; -#include "msm8996-mdss-panels.dtsi" +#include "msm8996-sde-display.dtsi" &pmx_mdss { mdss_dsi_active: mdss_dsi_active { @@ -335,32 +335,201 @@ &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; + qcom,sde-plane-id-map { + qcom,sde-plane-id@0 { + reg = <0x0>; + qcom,display-type = "primary"; + qcom,plane-name = "rgb0", "rgb1"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@1 { + reg = <0x1>; + qcom,display-type = "primary"; + qcom,plane-name = "vig0", "vig1"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@2 { + reg = <0x2>; + qcom,display-type = "primary"; + qcom,plane-name = "cursor0"; + qcom,plane-type = "cursor"; + }; + + qcom,sde-plane-id@3 { + reg = <0x3>; + qcom,display-type = "secondary"; + qcom,plane-name = "rgb2"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@4 { + reg = <0x4>; + qcom,display-type = "secondary"; + qcom,plane-name = "vig2"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@5 { + reg = <0x5>; + qcom,display-type = "secondary"; + qcom,plane-name = "dma0"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@6 { + reg = <0x6>; + qcom,display-type = "secondary"; + qcom,plane-name = "cursor1"; + qcom,plane-type = "cursor"; + }; + + qcom,sde-plane-id@7 { + reg = <0x7>; + qcom,display-type = "tertiary"; + qcom,plane-name = "rgb3"; + qcom,plane-type = "primary"; + }; + + qcom,sde-plane-id@8 { + reg = <0x8>; + qcom,display-type = "tertiary"; + qcom,plane-name = "vig3"; + qcom,plane-type = "overlay"; + }; + + qcom,sde-plane-id@9 { + reg = <0x9>; + qcom,display-type = "tertiary"; + qcom,plane-name = "dma1"; + qcom,plane-type = "overlay"; + }; + }; +}; + +&dsi_adv_7533_1 { + qcom,dsi-display-active; + qcom,dsi-panel = <&dsi_adv7533_1080p>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; +}; + +&dsi_adv_7533_2 { + qcom,dsi-display-active; + qcom,dsi-panel = <&dsi_adv7533_1080p>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; }; &mdss_dsi { - hw-config = "split_dsi"; + hw-config = "dual_dsi"; }; &mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>; + qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; - qcom,platform-enable-gpio = <&tlmm 70 0>; - qcom,platform-te-gpio = <&tlmm 10 0>; - qcom,platform-reset-gpio = <&tlmm 8 0>; - qcom,platform-bklight-en-gpio = <&pm8994_gpios 10 0>; + qcom,display-id = "primary"; + qcom,bridge-index = <0>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; }; &mdss_dsi1 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>; + qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; - qcom,platform-enable-gpio = <&tlmm 70 0>; - qcom,platform-te-gpio = <&tlmm 10 0>; - qcom,platform-reset-gpio = <&tlmm 8 0>; - qcom,platform-bklight-en-gpio = <&pm8994_gpios 10 0>; + qcom,display-id = "tertiary"; + qcom,bridge-index = <1>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; }; &dsi_dual_sharp_video { @@ -466,6 +635,13 @@ qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <1>; qcom,ntn-bus-num = <1>; + + qcom,msm-bus,name = "ntn"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 207108 14432000>; }; ntn2: ntn_avb@2 { /*Neutrino device on RC2*/ @@ -473,6 +649,13 @@ qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <2>; qcom,ntn-bus-num = <1>; + + qcom,msm-bus,name = "ntn"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <108 512 0 0>, + <108 512 207108 14432000>; }; i2c@75ba000 { @@ -517,9 +700,8 @@ pinctrl-1 = <&adv7533_0_int_suspend &adv7533_0_hpd_int_suspend &adv7533_0_switch_suspend>; - adi,irq-gpio = <&tlmm 106 0x2002>; - adi,hpd-irq-gpio = <&tlmm 106 0x2003>; - adi,switch-gpio = <&tlmm 105 0x1>; + adi,irq-gpio = <&tlmm 71 0x2002>; + adi,switch-gpio = <&tlmm 72 0x1>; }; adv7533@39 { @@ -538,9 +720,8 @@ pinctrl-1 = <&adv7533_1_int_suspend &adv7533_1_hpd_int_suspend &adv7533_1_switch_suspend>; - adi,irq-gpio = <&tlmm 108 0x2002>; - adi,hpd-irq-gpio = <&tlmm 106 0x2003>; - adi,switch-gpio = <&tlmm 107 0x0>; + adi,irq-gpio = <&tlmm 73 0x2002>; + adi,switch-gpio = <&tlmm 74 0x0>; }; }; @@ -639,14 +820,14 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&compr>, + <&afe>, <&lsm>, <&routing>, <&pcmnoirq>, <&loopback1>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", - "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-routing", "msm-pcm-dsp-noirq", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, @@ -835,7 +1016,7 @@ qcom,vin-sel = <2>; /* 1.8 */ qcom,out-strength = <1>; qcom,src-sel = <0>; /* GPIO */ - qcom,master-en = <1>; /* Enable GPIO */ + qcom,master-en = <0>; /* Disable GPIO */ status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi b/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi index f9c9d07c3078..b5f6232badfe 100644 --- a/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 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 @@ -12,36 +12,44 @@ &soc { tmc_etr: tmc@3028000 { - compatible = "arm,coresight-tmc"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + reg = <0x3028000 0x1000>, <0x3084000 0x15000>; reg-names = "tmc-base", "bam-base"; + interrupts = <0 270 0>; interrupt-names = "byte-cntr-irq"; - qcom,memory-size = <0x400000>; - qcom,tmc-flush-powerdown; - qcom,sg-enable; - qcom,force-reg-dump; + arm,buffer-size = <0x400000>; + arm,sg-enable; + + coresight-ctis = <&cti0 &cti8>; - coresight-id = <0>; coresight-name = "coresight-tmc-etr"; coresight-nr-inports = <1>; - coresight-ctis = <&cti0 &cti8>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; }; tpiu: tpiu@3020000 { - compatible = "arm,coresight-tpiu"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b912>; + reg = <0x3020000 0x1000>; reg-names = "tpiu-base"; - coresight-id = <1>; coresight-name = "coresight-tpiu"; - coresight-nr-inports = <1>; vdd-supply = <&pm8994_l21>; qcom,vdd-voltage-level = <2950000 2950000>; @@ -57,182 +65,443 @@ clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + tpiu_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tpiu>; + }; + }; }; replicator: replicator@3026000 { - compatible = "qcom,coresight-replicator"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + reg = <0x3026000 0x1000>; reg-names = "replicator-base"; - coresight-id = <2>; coresight-name = "coresight-replicator"; - coresight-nr-inports = <1>; - coresight-outports = <0 1>; - coresight-child-list = <&tmc_etr &tpiu>; - coresight-child-ports = <0 0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports{ + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_tmc_etr:endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + port@1 { + reg = <1>; + replicator_out_tpiu:endpoint { + remote-endpoint = + <&tpiu_in_replicator>; + }; + }; + port@2 { + reg = <0>; + replicator_in_tmc_etf:endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; }; tmc_etf: tmc@3027000 { - compatible = "arm,coresight-tmc"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + reg = <0x3027000 0x1000>; reg-names = "tmc-base"; - coresight-id = <3>; - coresight-name = "coresight-tmc-etf"; - coresight-nr-inports = <1>; - coresight-outports = <0>; - coresight-child-list = <&replicator>; - coresight-child-ports = <0>; - coresight-default-sink; coresight-ctis = <&cti0 &cti8>; + coresight-name = "coresight-tmc-etf"; + + arm,default-sink; + qcom,tmc-flush-powerdown; qcom,force-reg-dump; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports{ + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator:endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + port@1 { + reg = <0>; + tmc_etf_in_funnel_merg:endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; }; funnel_merg: funnel@3025000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x3025000 0x1000>; reg-names = "funnel-base"; - coresight-id = <4>; coresight-name = "coresight-funnel-merg"; - coresight-nr-inports = <2>; - coresight-outports = <0>; - coresight-child-list = <&tmc_etf>; - coresight-child-ports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf:endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0:endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1:endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + port@3 { + reg = <2>; + funnel_merg_in_funnel_in2:endpoint { + slave-mode; + remote-endpoint = + <&funnel_in2_out_funnel_merg>; + }; + }; + }; }; funnel_in0: funnel@3021000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x3021000 0x1000>; reg-names = "funnel-base"; - coresight-id = <5>; coresight-name = "coresight-funnel-in0"; - coresight-nr-inports = <8>; - coresight-outports = <0>; - coresight-child-list = <&funnel_merg>; - coresight-child-ports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + port@1 { + reg = <0>; + funnel_in0_in_rpm_etm0: endpoint { + slave-mode; + remote-endpoint = + <&rpm_etm0_out_funnel_in0>; + }; + }; + port@2 { + reg = <1>; + funnel_in0_in_funnel_mmss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_mmss_out_funnel_in0>; + }; + }; + port@3 { + reg = <2>; + funnel_in0_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_in0>; + }; + }; + port@4 { + reg = <3>; + funnel_in0_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_in0>; + }; + }; + port@5 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; }; funnel_in1: funnel@3022000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x3022000 0x1000>; reg-names = "funnel-base"; - coresight-id = <6>; coresight-name = "coresight-funnel-in1"; - coresight-nr-inports = <8>; - coresight-outports = <0>; - coresight-child-list = <&funnel_merg>; - coresight-child-ports = <1>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + port@1 { + reg = <6>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + }; }; funnel_in2: funnel@3023000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x3023000 0x1000>; reg-names = "funnel-base"; - coresight-id = <7>; coresight-name = "coresight-funnel-in2"; - coresight-nr-inports = <8>; - coresight-outports = <0>; - coresight-child-list = <&funnel_merg>; - coresight-child-ports = <2>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in2_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in2>; + }; + }; + port@1 { + reg = <0>; + funnel_in2_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in2>; + }; + }; + }; + }; funnel_apss_merge: funnel@3bc0000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x3bc0000 0x1000>; reg-names = "funnel-base"; - coresight-id = <8>; coresight-name = "coresight-funnel-apss-merge"; - coresight-nr-inports = <4>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in1>; - coresight-child-ports = <6>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merg>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss0_out_funnel_apss_merg>; + }; + }; + port@2 { + reg = <1>; + funnel_apss_merg_in_funnel_apss1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss1_out_funnel_apss_merg>; + }; + }; + port@3 { + reg = <2>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + }; }; funnel_apss0: funnel@39b0000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x39b0000 0x1000>; reg-names = "funnel-base"; - coresight-id = <9>; coresight-name = "coresight-funnel-apss0"; - coresight-nr-inports = <2>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss_merge>; - coresight-child-ports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss0_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss0>; + }; + }; + port@1 { + reg = <0>; + funnel_apss0_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss0>; + }; + }; + port@2 { + reg = <1>; + funnel_apss0_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss0>; + }; + }; + }; }; funnel_apss1: funnel@3bb0000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x3bb0000 0x1000>; reg-names = "funnel-base"; - coresight-id = <10>; coresight-name = "coresight-funnel-apss1"; - coresight-nr-inports = <2>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss_merge>; - coresight-child-ports = <1>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss1_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss1>; + }; + }; + port@1 { + reg = <0>; + funnel_apss1_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss1>; + }; + }; + port@2 { + reg = <1>; + funnel_apss1_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss1>; + }; + }; + }; }; funnel_mmss: funnel@3184000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x3184000 0x1000>; reg-names = "funnel-base"; - coresight-id = <11>; coresight-name = "coresight-funnel-mmss"; - coresight-nr-inports = <8>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <1>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + funnel_mmss_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_funnel_mmss>; + }; + }; }; tpda: tpda@3003000 { @@ -240,12 +509,7 @@ reg = <0x3003000 0x1000>; reg-names = "tpda-base"; - coresight-id = <13>; coresight-name = "coresight-tpda"; - coresight-nr-inports = <32>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <3>; qcom,tpda-atid = <65>; qcom,bc-elem-size = <3 32>, @@ -263,6 +527,66 @@ clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_tpda>; + }; + }; + port@1 { + reg = <0>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + port@2 { + reg = <1>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + port@3 { + reg = <2>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + port@4 { + reg = <3>; + tpda_in_tpdm_dsat: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dsat_out_tpda>; + }; + }; + port@5 { + reg = <6>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + port@6 { + reg = <7>; + tpda_in_tpdm_hwevents: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_hwevents_out_tpda>; + }; + }; + }; }; tpda_apss: tpda@39e0000 { @@ -270,12 +594,7 @@ reg = <0x39e0000 0x1000>; reg-names = "tpda-base"; - coresight-id = <14>; coresight-name = "coresight-tpda-apss"; - coresight-nr-inports = <32>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss_merge>; - coresight-child-ports = <2>; qcom,tpda-atid = <66>; qcom,bc-elem-size = <0 32>, @@ -285,6 +604,26 @@ clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + port@1 { + reg = <0>; + tpda_apss_in_tpdm_m4m: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_m4m_out_tpda_apss>; + }; + }; + }; }; tpdm_vsense: tpdm@3038000 { @@ -292,16 +631,17 @@ reg = <0x3038000 0x1000>; reg-names = "tpdm-base"; - coresight-id = <15>; coresight-name = "coresight-tpdm-vsense"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&tpda>; - coresight-child-ports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; }; tpdm_dcc: tpdm@3054000 { @@ -309,16 +649,17 @@ reg = <0x3054000 0x1000>; reg-names = "tpdm-base"; - coresight-id = <16>; coresight-name = "coresight-tpdm-dcc"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&tpda>; - coresight-child-ports = <1>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; }; tpdm_prng: tpdm@304c000 { @@ -326,16 +667,17 @@ reg = <0x304c000 0x1000>; reg-names = "tpdm-base"; - coresight-id = <17>; coresight-name = "coresight-tpdm-prng"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&tpda>; - coresight-child-ports = <2>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; }; tpdm_dsat: tpdm@3185000 { @@ -343,16 +685,17 @@ reg = <0x3185000 0x1000>; reg-names = "tpdm-base"; - coresight-id = <18>; coresight-name = "coresight-tpdm-dsat"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&tpda>; - coresight-child-ports = <3>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_dsat_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dsat>; + }; + }; }; tpdm_pimem: tpdm@3050000 { @@ -360,16 +703,17 @@ reg = <0x3050000 0x1000>; reg-names = "tpdm-base"; - coresight-id = <19>; coresight-name = "coresight-tpdm-pimem"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&tpda>; - coresight-child-ports = <6>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; }; tpdm_hwevents: tpdm@3004000 { @@ -377,16 +721,17 @@ reg = <0x3004000 0x1000>; reg-names = "tpdm-base"; - coresight-id = <20>; coresight-name = "coresight-tpdm-hwevents"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&tpda>; - coresight-child-ports = <7>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_hwevents_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_hwevents>; + }; + }; }; tpdm_m4m: tpdm@38e0000 { @@ -394,147 +739,163 @@ reg = <0x38e0000 0x1000>; reg-names = "tpdm-base"; - coresight-id = <21>; coresight-name = "coresight-tpdm-m4m"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&tpda_apss>; - coresight-child-ports = <0>; qcom,clk-enable; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_m4m_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_m4m>; + }; + }; }; stm: stm@3002000 { - compatible = "arm,coresight-stm"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + reg = <0x3002000 0x1000>, <0x8280000 0x180000>; reg-names = "stm-base", "stm-data-base"; - coresight-id = <23>; coresight-name = "coresight-stm"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <7>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; }; etm0: etm@3840000 { - compatible = "arm,coresight-etmv4"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + reg = <0x3840000 0x1000>; - reg-names = "etm-base"; + cpu = <&CPU0>; - coresight-id = <24>; coresight-name = "coresight-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss0>; - coresight-child-ports = <0>; - coresight-etm-cpu = <&CPU0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm0_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm0>; + }; + }; }; etm1: etm@3940000 { - compatible = "arm,coresight-etmv4"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + reg = <0x3940000 0x1000>; - reg-names = "etm-base"; + cpu = <&CPU1>; - coresight-id = <25>; coresight-name = "coresight-etm1"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss0>; - coresight-child-ports = <1>; - coresight-etm-cpu = <&CPU1>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm1_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm1>; + }; + }; }; etm2: etm@3a40000 { - compatible = "arm,coresight-etmv4"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + reg = <0x3a40000 0x1000>; - reg-names = "etm-base"; + cpu = <&CPU2>; - coresight-id = <26>; coresight-name = "coresight-etm2"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss1>; - coresight-child-ports = <0>; - coresight-etm-cpu = <&CPU2>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm2_out_funnel_apss1: endpoint { + remote-endpoint = <&funnel_apss1_in_etm2>; + }; + }; }; etm3: etm@3b40000 { - compatible = "arm,coresight-etmv4"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + reg = <0x3b40000 0x1000>; - reg-names = "etm-base"; + cpu = <&CPU3>; - coresight-id = <27>; coresight-name = "coresight-etm3"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss1>; - coresight-child-ports = <1>; - coresight-etm-cpu = <&CPU3>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm3_out_funnel_apss1: endpoint { + remote-endpoint = <&funnel_apss1_in_etm3>; + }; + }; }; audio_etm0 { compatible = "qcom,coresight-remote-etm"; - coresight-id = <28>; coresight-name = "coresight-audio-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <2>; qcom,inst-id = <5>; + + port{ + audio_etm0_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_audio_etm0>; + }; + }; + }; rpm_etm0 { compatible = "qcom,coresight-remote-etm"; - coresight-id = <29>; coresight-name = "coresight-rpm-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <0>; qcom,inst-id = <4>; + + port{ + rpm_etm0_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_rpm_etm0>; + }; + }; }; modem_etm0 { compatible = "qcom,coresight-remote-etm"; - coresight-id = <30>; coresight-name = "coresight-modem-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in2>; - coresight-child-ports = <0>; qcom,inst-id = <2>; + + port{ + modem_etm0_out_funnel_in2: endpoint { + remote-endpoint = <&funnel_in2_in_modem_etm0>; + }; + }; }; csr: csr@3001000 { @@ -542,9 +903,7 @@ reg = <0x3001000 0x1000>; reg-names = "csr-base"; - coresight-id = <31>; coresight-name = "coresight-csr"; - coresight-nr-inports = <0>; qcom,blk-size = <1>; }; @@ -554,9 +913,7 @@ reg = <0x3010000 0x1000>; reg-names = "cti-base"; - coresight-id = <32>; coresight-name = "coresight-cti0"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -568,9 +925,7 @@ reg = <0x3011000 0x1000>; reg-names = "cti-base"; - coresight-id = <33>; coresight-name = "coresight-cti1"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -582,9 +937,7 @@ reg = <0x3012000 0x1000>; reg-names = "cti-base"; - coresight-id = <34>; coresight-name = "coresight-cti2"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -596,9 +949,7 @@ reg = <0x3013000 0x1000>; reg-names = "cti-base"; - coresight-id = <35>; coresight-name = "coresight-cti3"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -610,9 +961,7 @@ reg = <0x3014000 0x1000>; reg-names = "cti-base"; - coresight-id = <36>; coresight-name = "coresight-cti4"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -624,9 +973,7 @@ reg = <0x3015000 0x1000>; reg-names = "cti-base"; - coresight-id = <37>; coresight-name = "coresight-cti5"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -638,9 +985,7 @@ reg = <0x3016000 0x1000>; reg-names = "cti-base"; - coresight-id = <38>; coresight-name = "coresight-cti6"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -656,9 +1001,7 @@ reg = <0x3017000 0x1000>; reg-names = "cti-base"; - coresight-id = <39>; coresight-name = "coresight-cti7"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -670,9 +1013,7 @@ reg = <0x3018000 0x1000>; reg-names = "cti-base"; - coresight-id = <40>; coresight-name = "coresight-cti8"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -684,9 +1025,7 @@ reg = <0x3019000 0x1000>; reg-names = "cti-base"; - coresight-id = <41>; coresight-name = "coresight-cti9"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -698,9 +1037,7 @@ reg = <0x301a000 0x1000>; reg-names = "cti-base"; - coresight-id = <42>; coresight-name = "coresight-cti10"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -712,9 +1049,7 @@ reg = <0x301b000 0x1000>; reg-names = "cti-base"; - coresight-id = <43>; coresight-name = "coresight-cti11"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -726,9 +1061,7 @@ reg = <0x301c000 0x1000>; reg-names = "cti-base"; - coresight-id = <44>; coresight-name = "coresight-cti12"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -740,9 +1073,7 @@ reg = <0x301d000 0x1000>; reg-names = "cti-base"; - coresight-id = <45>; coresight-name = "coresight-cti13"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -754,9 +1085,7 @@ reg = <0x301e000 0x1000>; reg-names = "cti-base"; - coresight-id = <46>; coresight-name = "coresight-cti14"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -768,10 +1097,8 @@ reg = <0x3820000 0x1000>; reg-names = "cti-base"; - coresight-id = <47>; coresight-name = "coresight-cti-cpu0"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU0>; + cpu = <&CPU0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -783,10 +1110,8 @@ reg = <0x3920000 0x1000>; reg-names = "cti-base"; - coresight-id = <48>; coresight-name = "coresight-cti-cpu1"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU1>; + cpu = <&CPU1>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -798,10 +1123,8 @@ reg = <0x3a20000 0x1000>; reg-names = "cti-base"; - coresight-id = <49>; coresight-name = "coresight-cti-cpu2"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU2>; + cpu = <&CPU2>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -813,10 +1136,8 @@ reg = <0x3b20000 0x1000>; reg-names = "cti-base"; - coresight-id = <50>; coresight-name = "coresight-cti-cpu3"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU3>; + cpu = <&CPU3>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -828,10 +1149,8 @@ reg = <0x38a0000 0x1000>; reg-names = "cti-base"; - coresight-id = <51>; coresight-name = "coresight-cti-pmu-cpu0"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU0>; + cpu = <&CPU0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -843,10 +1162,8 @@ reg = <0x39a0000 0x1000>; reg-names = "cti-base"; - coresight-id = <52>; coresight-name = "coresight-cti-pmu-cpu1"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU1>; + cpu = <&CPU1>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -858,10 +1175,8 @@ reg = <0x3aa0000 0x1000>; reg-names = "cti-base"; - coresight-id = <53>; coresight-name = "coresight-cti-pmu-cpu2"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU2>; + cpu = <&CPU2>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -873,10 +1188,8 @@ reg = <0x3ba0000 0x1000>; reg-names = "cti-base"; - coresight-id = <54>; coresight-name = "coresight-cti-pmu-cpu3"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU3>; + cpu = <&CPU3>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -888,9 +1201,7 @@ reg = <0x38b0000 0x1000>; reg-names = "cti-base"; - coresight-id = <55>; coresight-name = "coresight-cti-l2pmu-cluster0"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -902,9 +1213,7 @@ reg = <0x3ab0000 0x1000>; reg-names = "cti-base"; - coresight-id = <56>; coresight-name = "coresight-cti-l2pmu-cluster1"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -916,9 +1225,7 @@ reg = <0x3ad0000 0x1000>; reg-names = "cti-base"; - coresight-id = <57>; coresight-name = "coresight-cti-l3"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -930,9 +1237,7 @@ reg = <0x39c0000 0x1000>; reg-names = "cti-base"; - coresight-id = <58>; coresight-name = "coresight-cti-lm-cluster0"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -944,9 +1249,7 @@ reg = <0x39d0000 0x1000>; reg-names = "cti-base"; - coresight-id = <59>; coresight-name = "coresight-cti-lm-cluster1"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -958,9 +1261,7 @@ reg = <0x38d0000 0x1000>; reg-names = "cti-base"; - coresight-id = <60>; coresight-name = "coresight-cti-m4m"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -972,9 +1273,7 @@ reg = <0x39f0000 0x1000>; reg-names = "cti-base"; - coresight-id = <61>; coresight-name = "coresight-cti-tpda-apss"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -986,9 +1285,7 @@ reg = <0x3180000 0x1000>; reg-names = "cti-base"; - coresight-id = <64>; coresight-name = "coresight-cti-venus-cpu0"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -1000,9 +1297,7 @@ reg = <0x3044000 0x1000>; reg-names = "cti-base"; - coresight-id = <65>; coresight-name = "coresight-cti-audio-cpu0"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -1014,9 +1309,7 @@ reg = <0x3048000 0x1000>; reg-names = "cti-base"; - coresight-id = <66>; coresight-name = "coresight-cti-rpm-cpu0"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -1028,9 +1321,7 @@ reg = <0x3040000 0x1000>; reg-names = "cti-base"; - coresight-id = <67>; coresight-name = "coresight-cti-modem-cpu0"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; @@ -1057,9 +1348,7 @@ "pcie1-hwev", "pcie2-hwev", "tcsr-mux", "mss-mux0", "mss-mux1"; - coresight-id = <70>; coresight-name = "coresight-hwevent"; - coresight-nr-inports = <0>; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>, @@ -1075,9 +1364,7 @@ <0x76014 0x4>; reg-names = "fuse-base", "qpdi-fuse-base"; - coresight-id = <71>; coresight-name = "coresight-fuse"; - coresight-nr-inports = <0>; }; qpdi: qpdi@7a1000 { @@ -1085,9 +1372,7 @@ reg = <0x7a1000 0x4>; reg-names = "qpdi-base"; - coresight-id = <72>; coresight-name = "coresight-qpdi"; - coresight-nr-inports = <0>; vdd-supply = <&pm8994_l21>; qcom,vdd-voltage-level = <2950000 2950000>; diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi index 53c3c7e727bc..d3ea51268590 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi @@ -523,14 +523,14 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&compr>, + <&afe>, <&lsm>, <&routing>, <&pcmnoirq>, <&loopback1>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", - "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-routing", "msm-pcm-dsp-noirq", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, diff --git a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi index c4e6393997ec..9a263510b27d 100644 --- a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi @@ -89,7 +89,7 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, - <&pcm_noirq>, <&cpe3>; + <&pcm_noirq>, <&cpe3>, <&trans_loopback>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", @@ -97,7 +97,7 @@ "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", "msm-compr-dsp", "msm-pcm-dsp-noirq", - "msm-cpe-lsm.3"; + "msm-cpe-lsm.3", "msm-transcode-loopback"; asoc-cpu = <&dai_hdmi>, <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, @@ -222,14 +222,15 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, - <&pcm_noirq>; + <&pcm_noirq>, <&trans_loopback>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", - "msm-compr-dsp", "msm-pcm-dsp-noirq"; + "msm-compr-dsp", "msm-pcm-dsp-noirq", + "msm-transcode-loopback"; asoc-cpu = <&dai_hdmi>, <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index 318dc5d7c791..71593012148d 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -975,7 +975,7 @@ config { pins = "gpio26", "gpio126"; - bias-disable; + bias-pull-up; drive-strength = <2>; /* 2 MA */ }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 0fb84e024698..3dbb019443c4 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -282,6 +282,23 @@ compatible = "simple-bus"; }; + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect"; + status = "ok"; + }; + }; + }; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -2635,7 +2652,7 @@ 0x260 0x10 0x00 0x28c 0x06 0x00 0x504 0x03 0x00 - 0x500 0x1c 0x00 + 0x500 0x10 0x00 0x50c 0x14 0x00 0x4d4 0x0a 0x00 0x4d8 0x04 0x00 @@ -2657,7 +2674,7 @@ 0x9a8 0x00 0x00 0x8a4 0x01 0x00 0x8a8 0x73 0x00 - 0x9d8 0x99 0x00 + 0x9d8 0xaa 0x00 0x9b0 0x03 0x00 0x804 0x03 0x00 0x800 0x00 0x00 @@ -3205,6 +3222,7 @@ qcom,smmu-fast-map; qcom,smmu-coherent; qcom,smmu-mapping = <0x20000000 0xe0000000>; + qcom,keep-radio-on-during-sleep; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts index 99f17844e508..8ad7ca7f9743 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts @@ -63,14 +63,14 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&compr>, + <&afe>, <&lsm>, <&routing>, <&pcmnoirq>, <&loopback1>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", - "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-routing", "msm-pcm-dsp-noirq", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, @@ -78,14 +78,17 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, - <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, - <&dai_tert_tdm_tx_2>, <&dai_tert_tdm_tx_3>, - <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_rx_1>, - <&dai_quat_tdm_rx_2>, <&dai_quat_tdm_rx_3>, - <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, - <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>; + <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>, + <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>, + <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>, + <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>, + <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, + <&dai_quat_tdm_tx_3>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -93,14 +96,17 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", - "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", - "msm-dai-q6-tdm.36901", "msm-dai-q6-tdm.36903", - "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36914", - "msm-dai-q6-tdm.36916", "msm-dai-q6-tdm.36918", - "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36915", - "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919"; + "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901", + "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917", + "msm-dai-q6-tdm.36919"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; }; @@ -134,14 +140,16 @@ compatible = "qcom,msm-pcm-routing"; }; - compr: qcom,msm-compr-dsp { - compatible = "qcom,msm-compr-dsp"; - }; - compress: qcom,msm-compress-dsp { compatible = "qcom,msm-compress-dsp"; }; + pcmnoirq: qcom,msm-pcm-dsp-noirq { + compatible = "qcom,msm-pcm-dsp-noirq"; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + voip: qcom,msm-voip-dsp { compatible = "qcom,msm-voip-dsp"; }; @@ -280,8 +288,9 @@ qcom,msm-dai-tdm-tert-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37152>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 36902>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = + <36896 36898 36900 36902 36904>; qcom,msm-cpudai-tdm-clk-rate = <0>; dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; @@ -326,6 +335,16 @@ qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36904>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; qcom,msm-dai-tdm-tert-tx { @@ -481,6 +500,54 @@ }; }; + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36881 36883 36885 36887>; + qcom,msm-cpudai-tdm-clk-rate = <0>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_sec_tdm_tx_1: qcom,msm-dai-q6-tdm-sec-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36883>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_sec_tdm_tx_2: qcom,msm-dai-q6-tdm-sec-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36885>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_sec_tdm_tx_3: qcom,msm-dai-q6-tdm-sec-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36887>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + hostless: qcom,msm-pcm-hostless { compatible = "qcom,msm-pcm-hostless"; }; diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index 4f9dec489931..306c4f4e778e 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h @@ -26,4 +26,91 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs); (regs)->ARM_cpsr = SVC_MODE; \ } +static inline u32 armv8pmu_pmcr_read_reg(void) +{ + u32 val; + + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); + return val; +} + +static inline u32 armv8pmu_pmccntr_read_reg(void) +{ + u32 val; + + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); + return val; +} + +static inline u32 armv8pmu_pmxevcntr_read_reg(void) +{ + u32 val; + + asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); + return val; +} + +static inline u32 armv8pmu_pmovsclr_read_reg(void) +{ + u32 val; + + asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); + return val; +} + +static inline void armv8pmu_pmcr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val)); +} + +static inline void armv8pmu_pmselr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); +} + +static inline void armv8pmu_pmccntr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val)); +} + +static inline void armv8pmu_pmxevcntr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val)); +} + +static inline void armv8pmu_pmxevtyper_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); +} + +static inline void armv8pmu_pmcntenset_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); +} + +static inline void armv8pmu_pmcntenclr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); +} + +static inline void armv8pmu_pmintenset_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val)); +} + +static inline void armv8pmu_pmintenclr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val)); +} + +static inline void armv8pmu_pmovsclr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val)); +} + +static inline void armv8pmu_pmuserenr_write_reg(u32 val) +{ + asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r" (val)); +} + #endif /* __ARM_PERF_EVENT_H__ */ diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 81fa3afa8cca..c9dfe25b938a 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -10,6 +10,8 @@ CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=15 @@ -358,37 +360,13 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_MSM_CAMERA=y -CONFIG_MSM_CAMERA_DEBUG=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSMB_CAMERA_DEBUG=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI20_HEADER=y -CONFIG_MSM_CSI22_HEADER=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSI31_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_IMX134=y -CONFIG_IMX132=y -CONFIG_OV9724=y -CONFIG_OV5648=y -CONFIG_GC0339=y -CONFIG_OV8825=y -CONFIG_OV8865=y -CONFIG_s5k4e1=y -CONFIG_OV12830=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_AIS=y +CONFIG_MSM_AIS_DEBUG=y +CONFIG_MSM_AIS_CAMERA_SENSOR=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_MSM=y @@ -600,6 +578,7 @@ CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SINK_TPIU=y CONFIG_CORESIGHT_QCOM_REPLICATOR=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_HWEVENT=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index 70674f6043cf..7a139efa1455 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -8,6 +8,8 @@ CONFIG_TASKSTATS=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=15 @@ -362,37 +364,13 @@ CONFIG_VIDEO_ADV_DEBUG=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_MSM_CAMERA=y -CONFIG_MSM_CAMERA_DEBUG=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSMB_CAMERA_DEBUG=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI20_HEADER=y -CONFIG_MSM_CSI22_HEADER=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSI31_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_IMX134=y -CONFIG_IMX132=y -CONFIG_OV9724=y -CONFIG_OV5648=y -CONFIG_GC0339=y -CONFIG_OV8825=y -CONFIG_OV8865=y -CONFIG_s5k4e1=y -CONFIG_OV12830=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_AIS=y +CONFIG_MSM_AIS_DEBUG=y +CONFIG_MSM_AIS_CAMERA_SENSOR=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_MSM=y @@ -640,6 +618,7 @@ CONFIG_FREE_PAGES_RDONLY=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SINK_TPIU=y CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index 7bd3cdb533ea..da4397e14e0d 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -31,4 +31,91 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs); (regs)->pstate = PSR_MODE_EL1h; \ } +static inline u32 armv8pmu_pmcr_read_reg(void) +{ + u32 val; + + asm volatile("mrs %0, pmcr_el0" : "=r" (val)); + return val; +} + +static inline u32 armv8pmu_pmccntr_read_reg(void) +{ + u32 val; + + asm volatile("mrs %0, pmccntr_el0" : "=r" (val)); + return val; +} + +static inline u32 armv8pmu_pmxevcntr_read_reg(void) +{ + u32 val; + + asm volatile("mrs %0, pmxevcntr_el0" : "=r" (val)); + return val; +} + +static inline u32 armv8pmu_pmovsclr_read_reg(void) +{ + u32 val; + + asm volatile("mrs %0, pmovsclr_el0" : "=r" (val)); + return val; +} + +static inline void armv8pmu_pmcr_write_reg(u32 val) +{ + asm volatile("msr pmcr_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmselr_write_reg(u32 val) +{ + asm volatile("msr pmselr_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmccntr_write_reg(u32 val) +{ + asm volatile("msr pmccntr_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmxevcntr_write_reg(u32 val) +{ + asm volatile("msr pmxevcntr_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmxevtyper_write_reg(u32 val) +{ + asm volatile("msr pmxevtyper_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmcntenset_write_reg(u32 val) +{ + asm volatile("msr pmcntenset_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmcntenclr_write_reg(u32 val) +{ + asm volatile("msr pmcntenclr_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmintenset_write_reg(u32 val) +{ + asm volatile("msr pmintenset_el1, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmintenclr_write_reg(u32 val) +{ + asm volatile("msr pmintenclr_el1, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmovsclr_write_reg(u32 val) +{ + asm volatile("msr pmovsclr_el0, %0" :: "r" (val)); +} + +static inline void armv8pmu_pmuserenr_write_reg(u32 val) +{ + asm volatile("msr pmuserenr_el0, %0" :: "r" (val)); +} + #endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 99f4410833b4..bc1b1b0ed6ff 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -31,8 +31,7 @@ arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o -arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_debug.o \ - perf_trace_counters.o \ +arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_debug.o perf_trace_counters.o \ perf_trace_user.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 4748012a37cd..fb45af9c49d3 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1466,6 +1466,8 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc) struct siginfo info; struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; + struct pid *pid_struct = NULL; + struct task_struct *dci_task = NULL; memset(&info, 0, sizeof(struct siginfo)); info.si_code = SI_QUEUE; @@ -1483,20 +1485,32 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc) continue; if (entry->client_info.notification_list & peripheral_mask) { info.si_signo = entry->client_info.signal_type; - if (entry->client && - entry->tgid == entry->client->tgid) { - DIAG_LOG(DIAG_DEBUG_DCI, - "entry tgid = %d, dci client tgid = %d\n", - entry->tgid, entry->client->tgid); - stat = send_sig_info( - entry->client_info.signal_type, - &info, entry->client); - if (stat) - pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n", + pid_struct = find_get_pid(entry->tgid); + if (pid_struct) { + dci_task = get_pid_task(pid_struct, + PIDTYPE_PID); + if (!dci_task) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: dci client with pid = %d Exited..\n", + entry->tgid); + mutex_unlock(&driver->dci_mutex); + return; + } + if (entry->client && + entry->tgid == dci_task->tgid) { + DIAG_LOG(DIAG_DEBUG_DCI, + "entry tgid = %d, dci client tgid = %d\n", + entry->tgid, dci_task->tgid); + stat = send_sig_info( + entry->client_info.signal_type, + &info, dci_task); + if (stat) + pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n", info.si_int, stat); - } else - pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n", + } else + pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n", info.si_int, stat); + } } } mutex_unlock(&driver->dci_mutex); @@ -2230,9 +2244,26 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid) { struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; + struct pid *pid_struct = NULL; + struct task_struct *task_s = NULL; + list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); - if (entry->client && entry->tgid == entry->client->tgid) + pid_struct = find_get_pid(entry->tgid); + if (!pid_struct) { + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: valid pid doesn't exist for pid = %d\n", + entry->tgid); + continue; + } + task_s = get_pid_task(pid_struct, PIDTYPE_PID); + if (!task_s) { + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: valid task doesn't exist for pid = %d\n", + entry->tgid); + continue; + } + if (task_s == entry->client) if (entry->client->tgid == tgid) return entry; } diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index ca7dd88048ac..c963e4658c07 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -80,7 +80,8 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, "Time Sync Enabled: %d\n" "MD session mode: %d\n" "MD session mask: %d\n" - "Uses Time API: %d\n", + "Uses Time API: %d\n" + "Supports PD buffering: %d\n", chk_config_get_id(), chk_polling_response(), driver->polling_reg_flag, @@ -95,11 +96,12 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, driver->time_sync_enabled, driver->md_session_mode, driver->md_session_mask, - driver->uses_time_api); + driver->uses_time_api, + driver->supports_pd_buffering); for (i = 0; i < NUM_PERIPHERALS; i++) { ret += scnprintf(buf+ret, buf_size-ret, - "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c|\n", + "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c%c|\n", PERIPHERAL_STRING(i), driver->feature[i].feature_mask[0], driver->feature[i].feature_mask[1], @@ -108,6 +110,7 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, driver->feature[i].separate_cmd_rsp ? 'C':'c', driver->feature[i].encode_hdlc ? 'H':'h', driver->feature[i].mask_centralization ? 'M':'m', + driver->feature[i].pd_buffering ? 'P':'p', driver->feature[i].stm_support ? 'Q':'q', driver->feature[i].sockets_enabled ? 'S':'s', driver->feature[i].sent_feature_mask ? 'T':'t', @@ -273,8 +276,10 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, struct list_head *temp; struct diag_cmd_reg_t *item = NULL; + mutex_lock(&driver->cmd_reg_mutex); if (diag_dbgfs_table_index == driver->cmd_reg_count) { diag_dbgfs_table_index = 0; + mutex_unlock(&driver->cmd_reg_mutex); return 0; } @@ -283,6 +288,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL); if (ZERO_OR_NULL_PTR(buf)) { pr_err("diag: %s, Error allocating memory\n", __func__); + mutex_unlock(&driver->cmd_reg_mutex); return -ENOMEM; } buf_size = ksize(buf); @@ -327,6 +333,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, break; } diag_dbgfs_table_index = i; + mutex_unlock(&driver->cmd_reg_mutex); *ppos = 0; ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 4047a2c42bb7..73296b573436 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -478,6 +478,7 @@ struct diag_feature_t { uint8_t encode_hdlc; uint8_t untag_header; uint8_t peripheral_buffering; + uint8_t pd_buffering; uint8_t mask_centralization; uint8_t stm_support; uint8_t sockets_enabled; @@ -509,6 +510,7 @@ struct diagchar_dev { int supports_separate_cmdrsp; int supports_apps_hdlc_encoding; int supports_apps_header_untagging; + int supports_pd_buffering; int peripheral_untag[NUM_PERIPHERALS]; int supports_sockets; /* The state requested in the STM command */ @@ -561,8 +563,8 @@ struct diagchar_dev { struct diagfwd_info *diagfwd_cmd[NUM_PERIPHERALS]; struct diagfwd_info *diagfwd_dci_cmd[NUM_PERIPHERALS]; struct diag_feature_t feature[NUM_PERIPHERALS]; - struct diag_buffering_mode_t buffering_mode[NUM_PERIPHERALS]; - uint8_t buffering_flag[NUM_PERIPHERALS]; + struct diag_buffering_mode_t buffering_mode[NUM_MD_SESSIONS]; + uint8_t buffering_flag[NUM_MD_SESSIONS]; struct mutex mode_lock; unsigned char *user_space_data_buf; uint8_t user_space_data_busy; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 60bfb2af49d0..5c1094b48e92 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1908,12 +1908,33 @@ static int diag_ioctl_get_real_time(unsigned long ioarg) static int diag_ioctl_set_buffering_mode(unsigned long ioarg) { struct diag_buffering_mode_t params; + int peripheral = 0; + uint8_t diag_id = 0; if (copy_from_user(¶ms, (void __user *)ioarg, sizeof(params))) return -EFAULT; - if (params.peripheral >= NUM_PERIPHERALS) - return -EINVAL; + diag_map_pd_to_diagid(params.peripheral, &diag_id, &peripheral); + + if ((peripheral < 0) || + peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + peripheral); + return -EIO; + } + + if (params.peripheral > NUM_PERIPHERALS && + !driver->feature[peripheral].pd_buffering) { + pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n", + __func__, peripheral); + return -EIO; + } + + if (!driver->feature[peripheral].peripheral_buffering) { + pr_err("diag: In %s, peripheral %d doesn't support buffering\n", + __func__, peripheral); + return -EIO; + } mutex_lock(&driver->mode_lock); driver->buffering_flag[params.peripheral] = 1; @@ -1924,24 +1945,29 @@ static int diag_ioctl_set_buffering_mode(unsigned long ioarg) static int diag_ioctl_peripheral_drain_immediate(unsigned long ioarg) { - uint8_t peripheral; + uint8_t pd, diag_id = 0; + int peripheral = 0; - if (copy_from_user(&peripheral, (void __user *)ioarg, sizeof(uint8_t))) + if (copy_from_user(&pd, (void __user *)ioarg, sizeof(uint8_t))) return -EFAULT; - if (peripheral >= NUM_PERIPHERALS) { + diag_map_pd_to_diagid(pd, &diag_id, &peripheral); + + if ((peripheral < 0) || + peripheral >= NUM_PERIPHERALS) { pr_err("diag: In %s, invalid peripheral %d\n", __func__, peripheral); return -EINVAL; } - if (!driver->feature[peripheral].peripheral_buffering) { - pr_err("diag: In %s, peripheral %d doesn't support buffering\n", - __func__, peripheral); + if (pd > NUM_PERIPHERALS && + !driver->feature[peripheral].pd_buffering) { + pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n", + __func__, peripheral); return -EIO; } - return diag_send_peripheral_drain_immediate(peripheral); + return diag_send_peripheral_drain_immediate(pd, diag_id, peripheral); } static int diag_ioctl_dci_support(unsigned long ioarg) diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 8fb724305c03..019bf1946ac3 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1601,6 +1601,7 @@ int diagfwd_init(void) driver->supports_separate_cmdrsp = 1; driver->supports_apps_hdlc_encoding = 1; driver->supports_apps_header_untagging = 1; + driver->supports_pd_buffering = 1; for (i = 0; i < NUM_PERIPHERALS; i++) driver->peripheral_untag[i] = 0; mutex_init(&driver->diag_hdlc_mutex); @@ -1631,12 +1632,16 @@ int diagfwd_init(void) driver->feature[i].stm_support = DISABLE_STM; driver->feature[i].rcvd_feature_mask = 0; driver->feature[i].peripheral_buffering = 0; + driver->feature[i].pd_buffering = 0; driver->feature[i].encode_hdlc = 0; driver->feature[i].untag_header = DISABLE_PKT_HEADER_UNTAGGING; driver->feature[i].mask_centralization = 0; driver->feature[i].log_on_demand = 0; driver->feature[i].sent_feature_mask = 0; + } + + for (i = 0; i < NUM_MD_SESSIONS; i++) { driver->buffering_mode[i].peripheral = i; driver->buffering_mode[i].mode = DIAG_BUFFERING_MODE_STREAMING; driver->buffering_mode[i].high_wm_val = DEFAULT_HIGH_WM_VAL; diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 729fbf4fc145..4ae2158b5a6b 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -418,6 +418,8 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len, driver->feature[peripheral].mask_centralization = 1; if (FEATURE_SUPPORTED(F_DIAG_PERIPHERAL_BUFFERING)) driver->feature[peripheral].peripheral_buffering = 1; + if (FEATURE_SUPPORTED(F_DIAG_PD_BUFFERING)) + driver->feature[peripheral].pd_buffering = 1; if (FEATURE_SUPPORTED(F_DIAG_SOCKETS_ENABLED)) enable_socket_feature(peripheral); } @@ -792,32 +794,54 @@ static int diag_compute_real_time(int idx) } static void diag_create_diag_mode_ctrl_pkt(unsigned char *dest_buf, - int real_time) + uint8_t diag_id, int real_time) { struct diag_ctrl_msg_diagmode diagmode; + struct diag_ctrl_msg_diagmode_v2 diagmode_v2; int msg_size = sizeof(struct diag_ctrl_msg_diagmode); + int msg_size_2 = sizeof(struct diag_ctrl_msg_diagmode_v2); if (!dest_buf) return; - diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; - diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN; - diagmode.version = 1; - diagmode.sleep_vote = real_time ? 1 : 0; - /* - * 0 - Disables real-time logging (to prevent - * frequent APPS wake-ups, etc.). - * 1 - Enable real-time logging - */ - diagmode.real_time = real_time; - diagmode.use_nrt_values = 0; - diagmode.commit_threshold = 0; - diagmode.sleep_threshold = 0; - diagmode.sleep_time = 0; - diagmode.drain_timer_val = 0; - diagmode.event_stale_timer_val = 0; - - memcpy(dest_buf, &diagmode, msg_size); + if (diag_id) { + diagmode_v2.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; + diagmode_v2.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN_V2; + diagmode_v2.version = 2; + diagmode_v2.sleep_vote = real_time ? 1 : 0; + /* + * 0 - Disables real-time logging (to prevent + * frequent APPS wake-ups, etc.). + * 1 - Enable real-time logging + */ + diagmode_v2.real_time = real_time; + diagmode_v2.use_nrt_values = 0; + diagmode_v2.commit_threshold = 0; + diagmode_v2.sleep_threshold = 0; + diagmode_v2.sleep_time = 0; + diagmode_v2.drain_timer_val = 0; + diagmode_v2.event_stale_timer_val = 0; + diagmode_v2.diag_id = diag_id; + memcpy(dest_buf, &diagmode_v2, msg_size_2); + } else { + diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; + diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN; + diagmode.version = 1; + diagmode.sleep_vote = real_time ? 1 : 0; + /* + * 0 - Disables real-time logging (to prevent + * frequent APPS wake-ups, etc.). + * 1 - Enable real-time logging + */ + diagmode.real_time = real_time; + diagmode.use_nrt_values = 0; + diagmode.commit_threshold = 0; + diagmode.sleep_threshold = 0; + diagmode.sleep_time = 0; + diagmode.drain_timer_val = 0; + diagmode.event_stale_timer_val = 0; + memcpy(dest_buf, &diagmode, msg_size); + } } void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index) @@ -902,7 +926,7 @@ static void diag_send_diag_mode_update_remote(int token, int real_time) memcpy(buf + write_len, &dci_header, dci_header_size); write_len += dci_header_size; - diag_create_diag_mode_ctrl_pkt(buf + write_len, real_time); + diag_create_diag_mode_ctrl_pkt(buf + write_len, 0, real_time); write_len += msg_size; *(buf + write_len) = CONTROL_CHAR; /* End Terminator */ write_len += sizeof(uint8_t); @@ -1008,14 +1032,18 @@ void diag_real_time_work_fn(struct work_struct *work) } #endif -static int __diag_send_real_time_update(uint8_t peripheral, int real_time) +static int __diag_send_real_time_update(uint8_t peripheral, int real_time, + uint8_t diag_id) { - char buf[sizeof(struct diag_ctrl_msg_diagmode)]; - int msg_size = sizeof(struct diag_ctrl_msg_diagmode); + char buf[sizeof(struct diag_ctrl_msg_diagmode_v2)]; + int msg_size = 0; int err = 0; - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + peripheral); return -EINVAL; + } if (!driver->diagfwd_cntl[peripheral] || !driver->diagfwd_cntl[peripheral]->ch_open) { @@ -1030,12 +1058,17 @@ static int __diag_send_real_time_update(uint8_t peripheral, int real_time) return -EINVAL; } - diag_create_diag_mode_ctrl_pkt(buf, real_time); + msg_size = (diag_id ? sizeof(struct diag_ctrl_msg_diagmode_v2) : + sizeof(struct diag_ctrl_msg_diagmode)); + + diag_create_diag_mode_ctrl_pkt(buf, diag_id, real_time); mutex_lock(&driver->diag_cntl_mutex); + err = diagfwd_write(peripheral, TYPE_CNTL, buf, msg_size); + if (err && err != -ENODEV) { - pr_err("diag: In %s, unable to write to smd, peripheral: %d, type: %d, len: %d, err: %d\n", + pr_err("diag: In %s, unable to write, peripheral: %d, type: %d, len: %d, err: %d\n", __func__, peripheral, TYPE_CNTL, msg_size, err); } else { @@ -1061,27 +1094,79 @@ int diag_send_real_time_update(uint8_t peripheral, int real_time) return -EINVAL; } - return __diag_send_real_time_update(peripheral, real_time); + return __diag_send_real_time_update(peripheral, real_time, 0); +} + +void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral) +{ + switch (pd) { + case UPD_WLAN: + *diag_id = DIAG_ID_WLAN; + *peripheral = PERIPHERAL_MODEM; + break; + case UPD_AUDIO: + *diag_id = DIAG_ID_AUDIO; + *peripheral = PERIPHERAL_LPASS; + break; + case UPD_SENSORS: + *diag_id = DIAG_ID_SENSORS; + *peripheral = PERIPHERAL_LPASS; + break; + case PERIPHERAL_MODEM: + *diag_id = DIAG_ID_MPSS; + *peripheral = PERIPHERAL_MODEM; + break; + case PERIPHERAL_LPASS: + *diag_id = DIAG_ID_LPASS; + *peripheral = PERIPHERAL_LPASS; + break; + case PERIPHERAL_CDSP: + *diag_id = DIAG_ID_CDSP; + *peripheral = PERIPHERAL_CDSP; + break; + default: + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + pd); + *peripheral = -EINVAL; + break; + } + + if (*peripheral > 0) + if (!driver->feature[*peripheral].pd_buffering) + *diag_id = 0; } int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params) { int err = 0; int mode = MODE_REALTIME; - uint8_t peripheral = 0; + int peripheral = 0; + uint8_t diag_id = 0; if (!params) return -EIO; - peripheral = params->peripheral; - if (peripheral >= NUM_PERIPHERALS) { + diag_map_pd_to_diagid(params->peripheral, + &diag_id, &peripheral); + + if ((peripheral < 0) || + peripheral >= NUM_PERIPHERALS) { pr_err("diag: In %s, invalid peripheral %d\n", __func__, peripheral); return -EINVAL; } - if (!driver->buffering_flag[peripheral]) + if (!driver->buffering_flag[params->peripheral]) { + pr_err("diag: In %s, buffering flag not set for %d\n", __func__, + params->peripheral); return -EINVAL; + } + + if (!driver->feature[peripheral].peripheral_buffering) { + pr_err("diag: In %s, peripheral %d doesn't support buffering\n", + __func__, peripheral); + return -EIO; + } switch (params->mode) { case DIAG_BUFFERING_MODE_STREAMING: @@ -1100,7 +1185,7 @@ int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params) if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", __func__, peripheral); - driver->buffering_flag[peripheral] = 0; + driver->buffering_flag[params->peripheral] = 0; return -EIO; } @@ -1115,35 +1200,39 @@ int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params) (params->low_wm_val != DIAG_MIN_WM_VAL))) { pr_err("diag: In %s, invalid watermark values, high: %d, low: %d, peripheral: %d\n", __func__, params->high_wm_val, params->low_wm_val, - peripheral); + params->peripheral); return -EINVAL; } mutex_lock(&driver->mode_lock); - err = diag_send_buffering_tx_mode_pkt(peripheral, params); + err = diag_send_buffering_tx_mode_pkt(peripheral, diag_id, params); if (err) { pr_err("diag: In %s, unable to send buffering mode packet to peripheral %d, err: %d\n", __func__, peripheral, err); goto fail; } - err = diag_send_buffering_wm_values(peripheral, params); + err = diag_send_buffering_wm_values(peripheral, diag_id, params); if (err) { pr_err("diag: In %s, unable to send buffering wm value packet to peripheral %d, err: %d\n", __func__, peripheral, err); goto fail; } - err = __diag_send_real_time_update(peripheral, mode); + err = __diag_send_real_time_update(peripheral, mode, diag_id); if (err) { pr_err("diag: In %s, unable to send mode update to peripheral %d, mode: %d, err: %d\n", __func__, peripheral, mode, err); goto fail; } - driver->buffering_mode[peripheral].peripheral = peripheral; - driver->buffering_mode[peripheral].mode = params->mode; - driver->buffering_mode[peripheral].low_wm_val = params->low_wm_val; - driver->buffering_mode[peripheral].high_wm_val = params->high_wm_val; + driver->buffering_mode[params->peripheral].peripheral = + params->peripheral; + driver->buffering_mode[params->peripheral].mode = + params->mode; + driver->buffering_mode[params->peripheral].low_wm_val = + params->low_wm_val; + driver->buffering_mode[params->peripheral].high_wm_val = + params->high_wm_val; if (params->mode == DIAG_BUFFERING_MODE_STREAMING) - driver->buffering_flag[peripheral] = 0; + driver->buffering_flag[params->peripheral] = 0; fail: mutex_unlock(&driver->mode_lock); return err; @@ -1182,10 +1271,12 @@ int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data) return err; } -int diag_send_peripheral_drain_immediate(uint8_t peripheral) +int diag_send_peripheral_drain_immediate(uint8_t pd, + uint8_t diag_id, int peripheral) { int err = 0; struct diag_ctrl_drain_immediate ctrl_pkt; + struct diag_ctrl_drain_immediate_v2 ctrl_pkt_v2; if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", @@ -1200,32 +1291,57 @@ int diag_send_peripheral_drain_immediate(uint8_t peripheral) return -ENODEV; } - ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM; - /* The length of the ctrl pkt is size of version and stream id */ - ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t); - ctrl_pkt.version = 1; - ctrl_pkt.stream_id = 1; - - err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, sizeof(ctrl_pkt)); - if (err && err != -ENODEV) { - pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n", - peripheral, err); + if (diag_id && driver->feature[peripheral].pd_buffering) { + ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM; + /* + * The length of the ctrl pkt is size of version, + * diag_id and stream id + */ + ctrl_pkt_v2.len = sizeof(uint32_t) + (2 * sizeof(uint8_t)); + ctrl_pkt_v2.version = 2; + ctrl_pkt_v2.diag_id = diag_id; + ctrl_pkt_v2.stream_id = 1; + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2, + sizeof(ctrl_pkt_v2)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + } + } else { + ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM; + /* + * The length of the ctrl pkt is + * size of version and stream id + */ + ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t); + ctrl_pkt.version = 1; + ctrl_pkt.stream_id = 1; + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, + sizeof(ctrl_pkt)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + } } return err; } int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, - struct diag_buffering_mode_t *params) + uint8_t diag_id, struct diag_buffering_mode_t *params) { int err = 0; struct diag_ctrl_peripheral_tx_mode ctrl_pkt; + struct diag_ctrl_peripheral_tx_mode_v2 ctrl_pkt_v2; if (!params) return -EIO; - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + peripheral); return -EINVAL; + } if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", @@ -1233,9 +1349,6 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, return -EINVAL; } - if (params->peripheral != peripheral) - return -EINVAL; - switch (params->mode) { case DIAG_BUFFERING_MODE_STREAMING: case DIAG_BUFFERING_MODE_THRESHOLD: @@ -1247,36 +1360,67 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, return -EINVAL; } - ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE; - /* Control packet length is size of version, stream_id and tx_mode */ - ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t)); - ctrl_pkt.version = 1; - ctrl_pkt.stream_id = 1; - ctrl_pkt.tx_mode = params->mode; + if (diag_id && + driver->feature[peripheral].pd_buffering) { - err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, sizeof(ctrl_pkt)); - if (err && err != -ENODEV) { - pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n", - peripheral, err); - goto fail; + ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE; + /* + * Control packet length is size of version, diag_id, + * stream_id and tx_mode + */ + ctrl_pkt_v2.len = sizeof(uint32_t) + (3 * sizeof(uint8_t)); + ctrl_pkt_v2.version = 2; + ctrl_pkt_v2.diag_id = diag_id; + ctrl_pkt_v2.stream_id = 1; + ctrl_pkt_v2.tx_mode = params->mode; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2, + sizeof(ctrl_pkt_v2)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + goto fail; + } + } else { + ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE; + /* + * Control packet length is size of version, + * stream_id and tx_mode + */ + ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t)); + ctrl_pkt.version = 1; + ctrl_pkt.stream_id = 1; + ctrl_pkt.tx_mode = params->mode; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, + sizeof(ctrl_pkt)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + goto fail; + } } - driver->buffering_mode[peripheral].mode = params->mode; + driver->buffering_mode[params->peripheral].mode = params->mode; fail: return err; } int diag_send_buffering_wm_values(uint8_t peripheral, - struct diag_buffering_mode_t *params) + uint8_t diag_id, struct diag_buffering_mode_t *params) { int err = 0; struct diag_ctrl_set_wq_val ctrl_pkt; + struct diag_ctrl_set_wq_val_v2 ctrl_pkt_v2; if (!params) return -EIO; - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + peripheral); return -EINVAL; + } if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", @@ -1291,9 +1435,6 @@ int diag_send_buffering_wm_values(uint8_t peripheral, return -ENODEV; } - if (params->peripheral != peripheral) - return -EINVAL; - switch (params->mode) { case DIAG_BUFFERING_MODE_STREAMING: case DIAG_BUFFERING_MODE_THRESHOLD: @@ -1305,21 +1446,45 @@ int diag_send_buffering_wm_values(uint8_t peripheral, return -EINVAL; } - ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL; - /* Control packet length is size of version, stream_id and wmq values */ - ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t)); - ctrl_pkt.version = 1; - ctrl_pkt.stream_id = 1; - ctrl_pkt.high_wm_val = params->high_wm_val; - ctrl_pkt.low_wm_val = params->low_wm_val; - - err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, - sizeof(ctrl_pkt)); - if (err && err != -ENODEV) { - pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n", - peripheral, err); + if (diag_id && + driver->feature[peripheral].pd_buffering) { + ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL; + /* + * Control packet length is size of version, diag_id, + * stream_id and wmq values + */ + ctrl_pkt_v2.len = sizeof(uint32_t) + (4 * sizeof(uint8_t)); + ctrl_pkt_v2.version = 2; + ctrl_pkt_v2.diag_id = diag_id; + ctrl_pkt_v2.stream_id = 1; + ctrl_pkt_v2.high_wm_val = params->high_wm_val; + ctrl_pkt_v2.low_wm_val = params->low_wm_val; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2, + sizeof(ctrl_pkt_v2)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n", + peripheral, err); + } + } else { + ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL; + /* + * Control packet length is size of version, + * stream_id and wmq values + */ + ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t)); + ctrl_pkt.version = 1; + ctrl_pkt.stream_id = 1; + ctrl_pkt.high_wm_val = params->high_wm_val; + ctrl_pkt.low_wm_val = params->low_wm_val; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, + sizeof(ctrl_pkt)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n", + peripheral, err); + } } - return err; } diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h index e8608f47ff14..86442d838471 100644 --- a/drivers/char/diag/diagfwd_cntl.h +++ b/drivers/char/diag/diagfwd_cntl.h @@ -68,6 +68,7 @@ #define F_DIAG_SOCKETS_ENABLED 13 #define F_DIAG_DCI_EXTENDED_HEADER_SUPPORT 14 #define F_DIAG_PKT_HEADER_UNTAG 16 +#define F_DIAG_PD_BUFFERING 17 #define ENABLE_SEPARATE_CMDRSP 1 #define DISABLE_SEPARATE_CMDRSP 0 @@ -85,7 +86,8 @@ #define ENABLE_PKT_HEADER_UNTAGGING 1 #define DISABLE_PKT_HEADER_UNTAGGING 0 -#define DIAG_MODE_PKT_LEN 36 +#define DIAG_MODE_PKT_LEN 36 +#define DIAG_MODE_PKT_LEN_V2 37 struct diag_ctrl_pkt_header_t { uint32_t pkt_id; @@ -171,6 +173,21 @@ struct diag_ctrl_msg_diagmode { uint32_t event_stale_timer_val; } __packed; +struct diag_ctrl_msg_diagmode_v2 { + uint32_t ctrl_pkt_id; + uint32_t ctrl_pkt_data_len; + uint32_t version; + uint32_t sleep_vote; + uint32_t real_time; + uint32_t use_nrt_values; + uint32_t commit_threshold; + uint32_t sleep_threshold; + uint32_t sleep_time; + uint32_t drain_timer_val; + uint32_t event_stale_timer_val; + uint8_t diag_id; +} __packed; + struct diag_ctrl_msg_stm { uint32_t ctrl_pkt_id; uint32_t ctrl_pkt_data_len; @@ -249,6 +266,15 @@ struct diag_ctrl_peripheral_tx_mode { uint8_t tx_mode; } __packed; +struct diag_ctrl_peripheral_tx_mode_v2 { + uint32_t pkt_id; + uint32_t len; + uint32_t version; + uint8_t diag_id; + uint8_t stream_id; + uint8_t tx_mode; +} __packed; + struct diag_ctrl_drain_immediate { uint32_t pkt_id; uint32_t len; @@ -256,6 +282,14 @@ struct diag_ctrl_drain_immediate { uint8_t stream_id; } __packed; +struct diag_ctrl_drain_immediate_v2 { + uint32_t pkt_id; + uint32_t len; + uint32_t version; + uint8_t diag_id; + uint8_t stream_id; +} __packed; + struct diag_ctrl_set_wq_val { uint32_t pkt_id; uint32_t len; @@ -265,6 +299,16 @@ struct diag_ctrl_set_wq_val { uint8_t low_wm_val; } __packed; +struct diag_ctrl_set_wq_val_v2 { + uint32_t pkt_id; + uint32_t len; + uint32_t version; + uint8_t diag_id; + uint8_t stream_id; + uint8_t high_wm_val; + uint8_t low_wm_val; +} __packed; + int diagfwd_cntl_init(void); void diagfwd_cntl_channel_init(void); void diagfwd_cntl_exit(void); @@ -273,14 +317,16 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info); void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf, int len); int diag_send_real_time_update(uint8_t peripheral, int real_time); +void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral); int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params); void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index); void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index); void diag_real_time_work_fn(struct work_struct *work); int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data); -int diag_send_peripheral_drain_immediate(uint8_t peripheral); +int diag_send_peripheral_drain_immediate(uint8_t pd, + uint8_t diag_id, int peripheral); int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, - struct diag_buffering_mode_t *params); + uint8_t diag_id, struct diag_buffering_mode_t *params); int diag_send_buffering_wm_values(uint8_t peripheral, - struct diag_buffering_mode_t *params); + uint8_t diag_id, struct diag_buffering_mode_t *params); #endif diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 8b0e1f32bdc5..03133a5a89aa 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -553,6 +553,8 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) struct mhi_result *result = NULL; struct diag_mhi_ch_t *ch = NULL; void *buf = NULL; + struct diag_mhi_info *mhi_info = NULL; + unsigned long flags; if (!cb_info) return; @@ -604,13 +606,6 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].open_work)); break; - case MHI_CB_MHI_DISABLED: - DIAG_LOG(DIAG_DEBUG_BRIDGE, - "received mhi disabled notifiation port: %d ch: %d\n", - index, ch->type); - atomic_set(&(ch->opened), 0); - __mhi_close(&diag_mhi[index], CHANNELS_CLOSED); - break; case MHI_CB_XFER: /* * If the channel is a read channel, this is a read @@ -637,6 +632,24 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) result->bytes_xferd, diag_mhi[index].id); break; + case MHI_CB_MHI_DISABLED: + case MHI_CB_SYS_ERROR: + case MHI_CB_MHI_SHUTDOWN: + DIAG_LOG(DIAG_DEBUG_BRIDGE, + "received mhi link down cb: %d port: %d ch: %d\n", + cb_info->cb_reason, index, ch->type); + mhi_info = &diag_mhi[index]; + if (!mhi_info->enabled) + return; + spin_lock_irqsave(&mhi_info->lock, flags); + mhi_info->enabled = 0; + spin_unlock_irqrestore(&mhi_info->lock, flags); + atomic_set(&(mhi_info->read_ch.opened), 0); + atomic_set(&(mhi_info->write_ch.opened), 0); + flush_workqueue(mhi_info->mhi_wq); + mhi_buf_tbl_clear(mhi_info); + diag_remote_dev_close(mhi_info->dev_id); + break; default: pr_err("diag: In %s, invalid cb reason 0x%x\n", __func__, cb_info->cb_reason); diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c index adb07cdb7e8d..076ead6aaf34 100644 --- a/drivers/clk/msm/clock-local2.c +++ b/drivers/clk/msm/clock-local2.c @@ -1339,34 +1339,6 @@ static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */ {0, 0}, }; -static bool is_same_rcg_config(struct rcg_clk *rcg, struct clk_freq_tbl *freq, - bool has_mnd) -{ - u32 cfg; - - /* RCG update pending */ - if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_CONFIG_DIRTY_MASK) - return false; - if (has_mnd) - if (readl_relaxed(M_REG(rcg)) != freq->m_val || - readl_relaxed(N_REG(rcg)) != freq->n_val || - readl_relaxed(D_REG(rcg)) != freq->d_val) - return false; - /* - * Both 0 and 1 represent same divider value in HW. - * Always use 0 to simplify comparison. - */ - if ((freq->div_src_val & CFG_RCGR_DIV_MASK) == 1) - freq->div_src_val &= ~CFG_RCGR_DIV_MASK; - cfg = readl_relaxed(CFG_RCGR_REG(rcg)); - if ((cfg & CFG_RCGR_DIV_MASK) == 1) - cfg &= ~CFG_RCGR_DIV_MASK; - if (cfg != freq->div_src_val) - return false; - - return true; -} - static int set_rate_edp_pixel(struct clk *clk, unsigned long rate) { struct rcg_clk *rcg = to_rcg_clk(clk); @@ -1404,8 +1376,7 @@ static int set_rate_edp_pixel(struct clk *clk, unsigned long rate) pixel_freq->d_val = ~frac->den; } spin_lock_irqsave(&local_clock_reg_lock, flags); - if (!is_same_rcg_config(rcg, pixel_freq, true)) - __set_rate_mnd(rcg, pixel_freq); + __set_rate_mnd(rcg, pixel_freq); spin_unlock_irqrestore(&local_clock_reg_lock, flags); return 0; } @@ -1466,8 +1437,7 @@ static int set_rate_byte(struct clk *clk, unsigned long rate) byte_freq->div_src_val |= BVAL(4, 0, div); spin_lock_irqsave(&local_clock_reg_lock, flags); - if (!is_same_rcg_config(rcg, byte_freq, false)) - __set_rate_hid(rcg, byte_freq); + __set_rate_hid(rcg, byte_freq); spin_unlock_irqrestore(&local_clock_reg_lock, flags); return 0; @@ -1788,8 +1758,7 @@ static int rcg_clk_set_rate_dp(struct clk *clk, unsigned long rate) } spin_lock_irqsave(&local_clock_reg_lock, flags); - if (!is_same_rcg_config(rcg, freq_tbl, true)) - __set_rate_mnd(rcg, freq_tbl); + __set_rate_mnd(rcg, freq_tbl); spin_unlock_irqrestore(&local_clock_reg_lock, flags); return 0; } diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 4224b594f1b8..b69e59eeeae1 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -363,6 +363,24 @@ static int lpm_cpu_callback(struct notifier_block *cpu_nb, return NOTIFY_OK; } +#ifdef CONFIG_ARM_PSCI + +static int __init set_cpuidle_ops(void) +{ + int ret = 0, cpu; + + for_each_possible_cpu(cpu) { + ret = arm_cpuidle_init(cpu); + if (ret) + goto exit; + } + +exit: + return ret; +} + +#endif + static enum hrtimer_restart lpm_hrtimer_cb(struct hrtimer *h) { return HRTIMER_NORESTART; @@ -1954,6 +1972,14 @@ static int __init lpm_levels_module_init(void) goto fail; } +#ifdef CONFIG_ARM_PSCI + rc = set_cpuidle_ops(); + if (rc) { + pr_err("%s(): Failed to set cpuidle ops\n", __func__); + goto fail; + } +#endif + fail: return rc; } diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index d04ca6f28f90..beeb99e479c7 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1741,6 +1741,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&hash_access_lock); return err; } + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); + return -EINVAL; + } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], @@ -1777,6 +1783,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&hash_access_lock); return err; } + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); + return -EINVAL; + } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index de21a231b73f..f31089d63e0c 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -534,8 +534,6 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data) (devfreq->profile), struct msm_adreno_extended_profile, profile); - BUG_ON(devfreq == NULL); - switch (event) { case DEVFREQ_GOV_START: result = tz_start(devfreq); diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index af0060d6a22a..d652f3b53635 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -230,6 +230,13 @@ static int __init psci_features(u32 psci_func_id) #ifdef CONFIG_CPU_IDLE static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); +#ifdef CONFIG_ARM_PSCI +static int psci_cpu_init(struct device_node *cpu_node, int cpu) +{ + return 0; +} +#endif + static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) { int i, ret, count = 0; @@ -333,10 +340,14 @@ int psci_cpu_suspend_enter(unsigned long state_id) #ifdef CONFIG_ARM static struct cpuidle_ops psci_cpuidle_ops __initdata = { .suspend = psci_cpu_suspend_enter, +#ifdef CONFIG_ARM_PSCI + .init = psci_cpu_init, +#else .init = psci_dt_cpu_init_idle, +#endif }; -CPUIDLE_METHOD_OF_DECLARE(psci, "arm,psci", &psci_cpuidle_ops); +CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops); #endif #endif diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 4bee797da746..8f2a0eea4c4e 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -113,13 +113,15 @@ static struct page **get_pages(struct drm_gem_object *obj) return p; } + msm_obj->pages = p; + msm_obj->sgt = drm_prime_pages_to_sg(p, npages); if (IS_ERR(msm_obj->sgt)) { - dev_err(dev->dev, "failed to allocate sgt\n"); - return ERR_CAST(msm_obj->sgt); - } + void *ptr = ERR_CAST(msm_obj->sgt); - msm_obj->pages = p; + msm_obj->sgt = NULL; + return ptr; + } /* * Make sure to flush the CPU cache for newly allocated memory @@ -157,7 +159,8 @@ static void put_pages(struct drm_gem_object *obj) msm_obj->flags &= ~MSM_BO_LOCKED; } - sg_free_table(msm_obj->sgt); + if (msm_obj->sgt) + sg_free_table(msm_obj->sgt); kfree(msm_obj->sgt); if (use_pages(obj)) { diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 12cc28acec18..6d88eb374f69 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -34,11 +34,15 @@ static inline void __user *to_user_ptr(u64 address) } static struct msm_gem_submit *submit_create(struct drm_device *dev, - struct msm_gem_address_space *aspace, int nr_bos, int nr_cmds) + struct msm_gem_address_space *aspace, + uint32_t nr_bos, uint32_t nr_cmds) { struct msm_gem_submit *submit; - int sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) + - (nr_cmds * sizeof(*submit->cmd)); + uint64_t sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) + + (nr_cmds * sizeof(submit->cmd[0])); + + if (sz > SIZE_MAX) + return NULL; submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (submit) { diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index c2dd5f96521e..a6efb22b5ed4 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -120,16 +120,30 @@ static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); + struct iommu_domain *domain; int ret; - if (priv) - ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents, - DMA_BIDIRECTIONAL, priv); - else - ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, - DMA_BIDIRECTIONAL); + if (!client || !sgt) + return -EINVAL; + + if (iova != 0) { + if (!client->mmu_mapping || !client->mmu_mapping->domain) + return -EINVAL; + + domain = client->mmu_mapping->domain; + + return iommu_map_sg(domain, iova, sgt->sgl, + sgt->nents, flags); + } else { + if (priv) + ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, + sgt->nents, DMA_BIDIRECTIONAL, priv); + else + ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, + DMA_BIDIRECTIONAL); - return (ret != sgt->nents) ? -ENOMEM : 0; + return (ret != sgt->nents) ? -ENOMEM : 0; + } } static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, @@ -137,13 +151,27 @@ static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); - - if (priv) - msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, - DMA_BIDIRECTIONAL, priv); - else - dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, - DMA_BIDIRECTIONAL); + struct iommu_domain *domain = client->mmu_mapping->domain; + struct scatterlist *sg; + size_t len = 0; + int unmapped, i = 0; + + if (iova != 0) { + for_each_sg(sgt->sgl, sg, sgt->nents, i) + len += sg->length; + + unmapped = iommu_unmap(domain, iova, len); + if (unmapped < len) + dev_warn(mmu->dev, + "could not unmap iova@%llx\n", iova); + } else { + if (priv) + msm_dma_unmap_sg(client->dev, sgt->sgl, + sgt->nents, DMA_BIDIRECTIONAL, priv); + else + dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, + DMA_BIDIRECTIONAL); + } } static void msm_smmu_destroy(struct msm_mmu *mmu) diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index fa95b4dfe718..7f4a5a3b251f 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -623,6 +623,9 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size, unsigned int op) { void *addr = NULL; + struct sg_table *sgt = NULL; + struct scatterlist *sg; + unsigned int i, pos = 0; int ret = 0; if (size == 0 || size > UINT_MAX) @@ -650,40 +653,38 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset, * If the buffer is not to mapped to kernel, perform cache * operations after mapping to kernel. */ - if (memdesc->sgt != NULL) { - struct scatterlist *sg; - unsigned int i, pos = 0; + if (memdesc->sgt != NULL) + sgt = memdesc->sgt; + else { + if (memdesc->pages == NULL) + return ret; + + sgt = kgsl_alloc_sgt_from_pages(memdesc); + if (IS_ERR(sgt)) + return PTR_ERR(sgt); + } - for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) { - uint64_t sg_offset, sg_left; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + uint64_t sg_offset, sg_left; - if (offset >= (pos + sg->length)) { - pos += sg->length; - continue; - } - sg_offset = offset > pos ? offset - pos : 0; - sg_left = (sg->length - sg_offset > size) ? size : - sg->length - sg_offset; - ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset, - sg_left, op); - size -= sg_left; - if (size == 0) - break; + if (offset >= (pos + sg->length)) { pos += sg->length; + continue; } - } else if (memdesc->pages != NULL) { - addr = vmap(memdesc->pages, memdesc->page_count, - VM_IOREMAP, pgprot_writecombine(PAGE_KERNEL)); - if (addr == NULL) - return -ENOMEM; + sg_offset = offset > pos ? offset - pos : 0; + sg_left = (sg->length - sg_offset > size) ? size : + sg->length - sg_offset; + ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset, + sg_left, op); + size -= sg_left; + if (size == 0) + break; + pos += sg->length; + } - /* Make sure the offset + size do not overflow the address */ - if (addr + ((size_t) offset + (size_t) size) < addr) - return -ERANGE; + if (memdesc->sgt == NULL) + kgsl_free_sgt(sgt); - ret = kgsl_do_cache_op(NULL, addr, offset, size, op); - vunmap(addr); - } return ret; } EXPORT_SYMBOL(kgsl_cache_range_op); diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 11500fccc770..d85bcd8e121a 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -866,7 +866,6 @@ err: coresight_unregister(drvdata->csdev); return ret; err1: - pm_runtime_put(&adev->dev); return -EPERM; } diff --git a/drivers/input/touchscreen/synaptics_dsx/Kconfig b/drivers/input/touchscreen/synaptics_dsx/Kconfig index 86263fddacea..18d473969261 100644 --- a/drivers/input/touchscreen/synaptics_dsx/Kconfig +++ b/drivers/input/touchscreen/synaptics_dsx/Kconfig @@ -50,17 +50,6 @@ config TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21 To compile this driver as a module, choose M here: the module will be called synaptics_dsx_core. -config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21 - tristate "Synaptics DSX touchscreen RMI device module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21 - help - Say Y here to enable support for direct RMI register access. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_rmi_dev. - config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21 tristate "Synaptics DSX touchscreen firmware update module" depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21 @@ -72,15 +61,4 @@ config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21 To compile this driver as a module, choose M here: the module will be called synaptics_dsx_fw_update. -config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v21 - tristate "Synaptics DSX touchscreen proximity module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21 - help - Say Y here to enable support for proximity functionalities. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_proximity. - endif diff --git a/drivers/input/touchscreen/synaptics_dsx/Makefile b/drivers/input/touchscreen/synaptics_dsx/Makefile index b35b222d5ae2..0bffb8da94ea 100644 --- a/drivers/input/touchscreen/synaptics_dsx/Makefile +++ b/drivers/input/touchscreen/synaptics_dsx/Makefile @@ -7,6 +7,4 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21) += synaptics_dsx_i2c.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v21) += synaptics_dsx_spi.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21) += synaptics_dsx_core.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21) += synaptics_dsx_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21) += synaptics_dsx_fw_update.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v21) += synaptics_dsx_proximity.o diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c deleted file mode 100755 index 99c05e6845c0..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c +++ /dev/null @@ -1,671 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012 Synaptics Incorporated - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2.h> -#include "synaptics_dsx_core.h" - -#define PROX_PHYS_NAME "synaptics_dsx/input1" - -#define HOVER_Z_MAX (255) - -#define HOVERING_FINGER_EN (1 << 4) - -static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static struct device_attribute attrs[] = { - __ATTR(hover_finger_en, (S_IRUGO | S_IWUGO), - synaptics_rmi4_hover_finger_en_show, - synaptics_rmi4_hover_finger_en_store), -}; - -struct synaptics_rmi4_f12_query_5 { - union { - struct { - unsigned char size_of_query6; - struct { - unsigned char ctrl0_is_present:1; - unsigned char ctrl1_is_present:1; - unsigned char ctrl2_is_present:1; - unsigned char ctrl3_is_present:1; - unsigned char ctrl4_is_present:1; - unsigned char ctrl5_is_present:1; - unsigned char ctrl6_is_present:1; - unsigned char ctrl7_is_present:1; - } __packed; - struct { - unsigned char ctrl8_is_present:1; - unsigned char ctrl9_is_present:1; - unsigned char ctrl10_is_present:1; - unsigned char ctrl11_is_present:1; - unsigned char ctrl12_is_present:1; - unsigned char ctrl13_is_present:1; - unsigned char ctrl14_is_present:1; - unsigned char ctrl15_is_present:1; - } __packed; - struct { - unsigned char ctrl16_is_present:1; - unsigned char ctrl17_is_present:1; - unsigned char ctrl18_is_present:1; - unsigned char ctrl19_is_present:1; - unsigned char ctrl20_is_present:1; - unsigned char ctrl21_is_present:1; - unsigned char ctrl22_is_present:1; - unsigned char ctrl23_is_present:1; - } __packed; - }; - unsigned char data[4]; - }; -}; - -struct synaptics_rmi4_f12_query_8 { - union { - struct { - unsigned char size_of_query9; - struct { - unsigned char data0_is_present:1; - unsigned char data1_is_present:1; - unsigned char data2_is_present:1; - unsigned char data3_is_present:1; - unsigned char data4_is_present:1; - unsigned char data5_is_present:1; - unsigned char data6_is_present:1; - unsigned char data7_is_present:1; - } __packed; - }; - unsigned char data[2]; - }; -}; - -struct prox_finger_data { - union { - struct { - unsigned char object_type_and_status; - unsigned char x_lsb; - unsigned char x_msb; - unsigned char y_lsb; - unsigned char y_msb; - unsigned char z; - } __packed; - unsigned char proximity_data[6]; - }; -}; - -struct synaptics_rmi4_prox_handle { - bool hover_finger_present; - bool hover_finger_en; - unsigned char intr_mask; - unsigned short query_base_addr; - unsigned short control_base_addr; - unsigned short data_base_addr; - unsigned short command_base_addr; - unsigned short hover_finger_en_addr; - unsigned short hover_finger_data_addr; - struct input_dev *prox_dev; - struct prox_finger_data *finger_data; - struct synaptics_rmi4_data *rmi4_data; -}; - -static struct synaptics_rmi4_prox_handle *prox; - -DECLARE_COMPLETION(prox_remove_complete); - -static void prox_hover_finger_lift(void) -{ - input_report_key(prox->prox_dev, BTN_TOUCH, 0); - input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 0); - input_sync(prox->prox_dev); - prox->hover_finger_present = false; - - return; -} - -static void prox_hover_finger_report(void) -{ - int retval; - int x; - int y; - int z; - struct prox_finger_data *data; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - data = prox->finger_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->hover_finger_data_addr, - data->proximity_data, - sizeof(data->proximity_data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read hovering finger data\n", - __func__); - return; - } - - if (data->object_type_and_status != F12_HOVERING_FINGER_STATUS) { - if (prox->hover_finger_present) - prox_hover_finger_lift(); - - return; - } - - x = (data->x_msb << 8) | (data->x_lsb); - y = (data->y_msb << 8) | (data->y_lsb); - z = HOVER_Z_MAX - data->z; - - input_report_key(prox->prox_dev, BTN_TOUCH, 0); - input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 1); - input_report_abs(prox->prox_dev, ABS_X, x); - input_report_abs(prox->prox_dev, ABS_Y, y); - input_report_abs(prox->prox_dev, ABS_DISTANCE, z); - - input_sync(prox->prox_dev); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: x = %d y = %d z = %d\n", - __func__, x, y, z); - - prox->hover_finger_present = true; - - return; -} - -static int prox_set_hover_finger_en(void) -{ - int retval; - unsigned char object_report_enable; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->hover_finger_en_addr, - &object_report_enable, - sizeof(object_report_enable)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read from object report enable register\n", - __func__); - return retval; - } - - if (prox->hover_finger_en) - object_report_enable |= HOVERING_FINGER_EN; - else - object_report_enable &= ~HOVERING_FINGER_EN; - - retval = synaptics_rmi4_reg_write(rmi4_data, - prox->hover_finger_en_addr, - &object_report_enable, - sizeof(object_report_enable)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write to object report enable register\n", - __func__); - return retval; - } - - return 0; -} - -static void prox_set_params(void) -{ - input_set_abs_params(prox->prox_dev, ABS_X, 0, - prox->rmi4_data->sensor_max_x, 0, 0); - input_set_abs_params(prox->prox_dev, ABS_Y, 0, - prox->rmi4_data->sensor_max_y, 0, 0); - input_set_abs_params(prox->prox_dev, ABS_DISTANCE, 0, - HOVER_Z_MAX, 0, 0); - - return; -} - -static int prox_reg_init(void) -{ - int retval; - unsigned char ctrl_23_offset; - unsigned char data_1_offset; - struct synaptics_rmi4_f12_query_5 query_5; - struct synaptics_rmi4_f12_query_8 query_8; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->query_base_addr + 5, - query_5.data, - sizeof(query_5.data)); - if (retval < 0) - return retval; - - ctrl_23_offset = query_5.ctrl0_is_present + - query_5.ctrl1_is_present + - query_5.ctrl2_is_present + - query_5.ctrl3_is_present + - query_5.ctrl4_is_present + - query_5.ctrl5_is_present + - query_5.ctrl6_is_present + - query_5.ctrl7_is_present + - query_5.ctrl8_is_present + - query_5.ctrl9_is_present + - query_5.ctrl10_is_present + - query_5.ctrl11_is_present + - query_5.ctrl12_is_present + - query_5.ctrl13_is_present + - query_5.ctrl14_is_present + - query_5.ctrl15_is_present + - query_5.ctrl16_is_present + - query_5.ctrl17_is_present + - query_5.ctrl18_is_present + - query_5.ctrl19_is_present + - query_5.ctrl20_is_present + - query_5.ctrl21_is_present + - query_5.ctrl22_is_present; - - prox->hover_finger_en_addr = prox->control_base_addr + ctrl_23_offset; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->query_base_addr + 8, - query_8.data, - sizeof(query_8.data)); - if (retval < 0) - return retval; - - data_1_offset = query_8.data0_is_present; - prox->hover_finger_data_addr = prox->data_base_addr + data_1_offset; - - return retval; -} - -static int prox_scan_pdt(void) -{ - int retval; - unsigned char ii; - unsigned char page; - unsigned char intr_count = 0; - unsigned char intr_off; - unsigned char intr_src; - unsigned short addr; - struct synaptics_rmi4_fn_desc fd; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - for (page = 0; page < PAGES_TO_SERVICE; page++) { - for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { - addr |= (page << 8); - - retval = synaptics_rmi4_reg_read(rmi4_data, - addr, - (unsigned char *)&fd, - sizeof(fd)); - if (retval < 0) - return retval; - - addr &= ~(MASK_8BIT << 8); - - if (fd.fn_number) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Found F%02x\n", - __func__, fd.fn_number); - switch (fd.fn_number) { - case SYNAPTICS_RMI4_F12: - goto f12_found; - break; - } - } else { - break; - } - - intr_count += (fd.intr_src_count & MASK_3BIT); - } - } - - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F12\n", - __func__); - return -EINVAL; - -f12_found: - prox->query_base_addr = fd.query_base_addr | (page << 8); - prox->control_base_addr = fd.ctrl_base_addr | (page << 8); - prox->data_base_addr = fd.data_base_addr | (page << 8); - prox->command_base_addr = fd.cmd_base_addr | (page << 8); - - retval = prox_reg_init(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to initialize proximity registers\n", - __func__); - return retval; - } - - prox->intr_mask = 0; - intr_src = fd.intr_src_count; - intr_off = intr_count % 8; - for (ii = intr_off; - ii < ((intr_src & MASK_3BIT) + - intr_off); - ii++) { - prox->intr_mask |= 1 << ii; - } - - rmi4_data->intr_mask[0] |= prox->intr_mask; - - addr = rmi4_data->f01_ctrl_base_addr + 1; - - retval = synaptics_rmi4_reg_write(rmi4_data, - addr, - &(rmi4_data->intr_mask[0]), - sizeof(rmi4_data->intr_mask[0])); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set interrupt enable bit\n", - __func__); - return retval; - } - - return 0; -} - -static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - if (!prox) - return -ENODEV; - - return snprintf(buf, PAGE_SIZE, "%u\n", - prox->hover_finger_en); -} - -static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - if (!prox) - return -ENODEV; - - if (sscanf(buf, "%x", &input) != 1) - return -EINVAL; - - if (input == 1) - prox->hover_finger_en = true; - else if (input == 0) - prox->hover_finger_en = false; - else - return -EINVAL; - - retval = prox_set_hover_finger_en(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change hovering finger enable setting\n", - __func__); - return retval; - } - - return count; -} - -int synaptics_rmi4_prox_hover_finger_en(bool enable) -{ - int retval; - - if (!prox) - return -ENODEV; - - prox->hover_finger_en = enable; - - retval = prox_set_hover_finger_en(); - if (retval < 0) - return retval; - - return 0; -} -EXPORT_SYMBOL(synaptics_rmi4_prox_hover_finger_en); - -static void synaptics_rmi4_prox_attn(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask) -{ - if (!prox) - return; - - if (prox->intr_mask & intr_mask) - prox_hover_finger_report(); - - return; -} - -static int synaptics_rmi4_prox_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char attr_count; - - prox = kzalloc(sizeof(*prox), GFP_KERNEL); - if (!prox) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for prox\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - prox->finger_data = kzalloc(sizeof(*(prox->finger_data)), GFP_KERNEL); - if (!prox->finger_data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for finger_data\n", - __func__); - retval = -ENOMEM; - goto exit_free_prox; - } - - prox->rmi4_data = rmi4_data; - - retval = prox_scan_pdt(); - if (retval < 0) - goto exit_free_finger_data; - - prox->hover_finger_en = true; - - retval = prox_set_hover_finger_en(); - if (retval < 0) - return retval; - - prox->prox_dev = input_allocate_device(); - if (prox->prox_dev == NULL) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate proximity device\n", - __func__); - retval = -ENOMEM; - goto exit_free_finger_data; - } - - prox->prox_dev->name = PLATFORM_DRIVER_NAME; - prox->prox_dev->phys = PROX_PHYS_NAME; - prox->prox_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT; - prox->prox_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION; - prox->prox_dev->dev.parent = rmi4_data->pdev->dev.parent; - input_set_drvdata(prox->prox_dev, rmi4_data); - - set_bit(EV_KEY, prox->prox_dev->evbit); - set_bit(EV_ABS, prox->prox_dev->evbit); - set_bit(BTN_TOUCH, prox->prox_dev->keybit); - set_bit(BTN_TOOL_FINGER, prox->prox_dev->keybit); -#ifdef INPUT_PROP_DIRECT - set_bit(INPUT_PROP_DIRECT, prox->prox_dev->propbit); -#endif - - prox_set_params(); - - retval = input_register_device(prox->prox_dev); - if (retval) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to register proximity device\n", - __func__); - goto exit_free_input_device; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - goto exit_free_sysfs; - } - } - - return 0; - -exit_free_sysfs: - for (attr_count--; attr_count >= 0; attr_count--) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - input_unregister_device(prox->prox_dev); - prox->prox_dev = NULL; - -exit_free_input_device: - if (prox->prox_dev) - input_free_device(prox->prox_dev); - -exit_free_finger_data: - kfree(prox->finger_data); - -exit_free_prox: - kfree(prox); - prox = NULL; - -exit: - return retval; -} - -static void synaptics_rmi4_prox_remove(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char attr_count; - - if (!prox) - goto exit; - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - input_unregister_device(prox->prox_dev); - kfree(prox->finger_data); - kfree(prox); - prox = NULL; - -exit: - complete(&prox_remove_complete); - - return; -} - -static void synaptics_rmi4_prox_reset(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) - return; - - prox_hover_finger_lift(); - - prox_scan_pdt(); - - prox_set_hover_finger_en(); - - prox_set_params(); - - return; -} - -static void synaptics_rmi4_prox_reinit(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) - return; - - prox_hover_finger_lift(); - - prox_set_hover_finger_en(); - - return; -} - -static void synaptics_rmi4_prox_e_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) - return; - - prox_hover_finger_lift(); - - return; -} - -static void synaptics_rmi4_prox_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) - return; - - prox_hover_finger_lift(); - - return; -} - -static struct synaptics_rmi4_exp_fn proximity_module = { - .fn_type = RMI_PROXIMITY, - .init = synaptics_rmi4_prox_init, - .remove = synaptics_rmi4_prox_remove, - .reset = synaptics_rmi4_prox_reset, - .reinit = synaptics_rmi4_prox_reinit, - .early_suspend = synaptics_rmi4_prox_e_suspend, - .suspend = synaptics_rmi4_prox_suspend, - .resume = NULL, - .late_resume = NULL, - .attn = synaptics_rmi4_prox_attn, -}; - -static int __init rmi4_proximity_module_init(void) -{ - synaptics_rmi4_dsx_new_function(&proximity_module, true); - - return 0; -} - -static void __exit rmi4_proximity_module_exit(void) -{ - synaptics_rmi4_dsx_new_function(&proximity_module, false); - - wait_for_completion(&prox_remove_complete); - - return; -} - -module_init(rmi4_proximity_module_init); -module_exit(rmi4_proximity_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX Proximity Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c deleted file mode 100644 index c1cbec81d7d6..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c +++ /dev/null @@ -1,810 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012 Synaptics Incorporated - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/gpio.h> -#include <linux/uaccess.h> -#include <linux/cdev.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2.h> -#include "synaptics_dsx_core.h" - -#define CHAR_DEVICE_NAME "rmi" -#define DEVICE_CLASS_NAME "rmidev" -#define SYSFS_FOLDER_NAME "rmidev" -#define DEV_NUMBER 1 -#define REG_ADDR_LIMIT 0xFFFF - -static ssize_t rmidev_sysfs_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t rmidev_sysfs_data_store(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t rmidev_sysfs_open_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t rmidev_sysfs_release_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t rmidev_sysfs_attn_state_show(struct device *dev, - struct device_attribute *attr, char *buf); - -struct rmidev_handle { - dev_t dev_no; - struct device dev; - struct synaptics_rmi4_data *rmi4_data; - struct kobject *sysfs_dir; - void *data; - bool irq_enabled; -}; - -struct rmidev_data { - int ref_count; - struct cdev main_dev; - struct class *device_class; - struct mutex file_mutex; - struct rmidev_handle *rmi_dev; -}; - -static struct bin_attribute attr_data = { - .attr = { - .name = "data", - .mode = (S_IRUGO | S_IWUSR), - }, - .size = 0, - .read = rmidev_sysfs_data_show, - .write = rmidev_sysfs_data_store, -}; - -static struct device_attribute attrs[] = { - __ATTR(open, S_IWUSR | S_IWGRP, - NULL, - rmidev_sysfs_open_store), - __ATTR(release, S_IWUSR | S_IWGRP, - NULL, - rmidev_sysfs_release_store), - __ATTR(attn_state, S_IRUGO, - rmidev_sysfs_attn_state_show, - synaptics_rmi4_store_error), -}; - -static int rmidev_major_num; - -static struct class *rmidev_device_class; - -static struct rmidev_handle *rmidev; - -DECLARE_COMPLETION(rmidev_remove_complete); - -static irqreturn_t rmidev_sysfs_irq(int irq, void *data) -{ - struct synaptics_rmi4_data *rmi4_data = data; - - sysfs_notify(&rmi4_data->input_dev->dev.kobj, - SYSFS_FOLDER_NAME, "attn_state"); - - return IRQ_HANDLED; -} - -static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - int retval = 0; - unsigned char intr_status[MAX_INTR_REGISTERS]; - unsigned long irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; - - if (enable) { - if (rmidev->irq_enabled) - return retval; - - /* Clear interrupts first */ - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_data_base_addr + 1, - intr_status, - rmi4_data->num_of_intr_regs); - if (retval < 0) - return retval; - - retval = request_threaded_irq(rmi4_data->irq, NULL, - rmidev_sysfs_irq, irq_flags, - "synaptics_dsx_rmidev", rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create irq thread\n", - __func__); - return retval; - } - - rmidev->irq_enabled = true; - } else { - if (rmidev->irq_enabled) { - disable_irq(rmi4_data->irq); - free_irq(rmi4_data->irq, rmi4_data); - rmidev->irq_enabled = false; - } - } - - return retval; -} - -static ssize_t rmidev_sysfs_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - unsigned int length = (unsigned int)count; - unsigned short address = (unsigned short)pos; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (length > (REG_ADDR_LIMIT - address)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Out of register map limit\n", - __func__); - return -EINVAL; - } - - if (length) { - retval = synaptics_rmi4_reg_read(rmi4_data, - address, - (unsigned char *)buf, - length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read data\n", - __func__); - return retval; - } - } else { - return -EINVAL; - } - - return length; -} - -static ssize_t rmidev_sysfs_data_store(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - unsigned int length = (unsigned int)count; - unsigned short address = (unsigned short)pos; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (length > (REG_ADDR_LIMIT - address)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Out of register map limit\n", - __func__); - return -EINVAL; - } - - if (length) { - retval = synaptics_rmi4_reg_write(rmi4_data, - address, - (unsigned char *)buf, - length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write data\n", - __func__); - return retval; - } - } else { - return -EINVAL; - } - - return length; -} - -static ssize_t rmidev_sysfs_open_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input != 1) - return -EINVAL; - - rmi4_data->irq_enable(rmi4_data, false); - rmidev_sysfs_irq_enable(rmi4_data, true); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt disabled\n", - __func__); - - return count; -} - -static ssize_t rmidev_sysfs_release_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input != 1) - return -EINVAL; - - rmi4_data->reset_device(rmi4_data); - - rmidev_sysfs_irq_enable(rmi4_data, false); - rmi4_data->irq_enable(rmi4_data, true); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt enabled\n", - __func__); - - return count; -} - -static ssize_t rmidev_sysfs_attn_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int attn_state; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - attn_state = gpio_get_value(bdata->irq_gpio); - - return snprintf(buf, PAGE_SIZE, "%u\n", attn_state); -} - -/* - * rmidev_llseek - used to set up register address - * - * @filp: file structure for seek - * @off: offset - * if whence == SEEK_SET, - * high 16 bits: page address - * low 16 bits: register address - * if whence == SEEK_CUR, - * offset from current position - * if whence == SEEK_END, - * offset from end position (0xFFFF) - * @whence: SEEK_SET, SEEK_CUR, or SEEK_END - */ -static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence) -{ - loff_t newpos; - struct rmidev_data *dev_data = filp->private_data; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (IS_ERR(dev_data)) { - pr_err("%s: Pointer of char device data is invalid", __func__); - return -EBADF; - } - - mutex_lock(&(dev_data->file_mutex)); - - switch (whence) { - case SEEK_SET: - newpos = off; - break; - case SEEK_CUR: - newpos = filp->f_pos + off; - break; - case SEEK_END: - newpos = REG_ADDR_LIMIT + off; - break; - default: - newpos = -EINVAL; - goto clean_up; - } - - if (newpos < 0 || newpos > REG_ADDR_LIMIT) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: New position 0x%04x is invalid\n", - __func__, (unsigned int)newpos); - newpos = -EINVAL; - goto clean_up; - } - - filp->f_pos = newpos; - -clean_up: - mutex_unlock(&(dev_data->file_mutex)); - - return newpos; -} - -/* - * rmidev_read: - use to read data from rmi device - * - * @filp: file structure for read - * @buf: user space buffer pointer - * @count: number of bytes to read - * @f_pos: offset (starting register address) - */ -static ssize_t rmidev_read(struct file *filp, char __user *buf, - size_t count, loff_t *f_pos) -{ - ssize_t retval; - unsigned char *tmpbuf; - struct rmidev_data *dev_data = filp->private_data; - - if (IS_ERR(dev_data)) { - pr_err("%s: Pointer of char device data is invalid", __func__); - return -EBADF; - } - - mutex_lock(&(dev_data->file_mutex)); - - if (count > (REG_ADDR_LIMIT - *f_pos)) - count = REG_ADDR_LIMIT - *f_pos; - - if (count == 0) { - retval = 0; - goto unlock; - } - - if (*f_pos > REG_ADDR_LIMIT) { - retval = -EFAULT; - goto unlock; - } - tmpbuf = kzalloc(count + 1, GFP_KERNEL); - if (!tmpbuf) { - retval = -ENOMEM; - goto unlock; - } - retval = synaptics_rmi4_reg_read(rmidev->rmi4_data, - *f_pos, - tmpbuf, - count); - if (retval < 0) - goto clean_up; - - if (copy_to_user(buf, tmpbuf, count)) - retval = -EFAULT; - else - *f_pos += retval; - -clean_up: - kfree(tmpbuf); -unlock: - mutex_unlock(&(dev_data->file_mutex)); - return retval; -} - -/* - * rmidev_write: - used to write data to rmi device - * - * @filep: file structure for write - * @buf: user space buffer pointer - * @count: number of bytes to write - * @f_pos: offset (starting register address) - */ -static ssize_t rmidev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *f_pos) -{ - ssize_t retval; - unsigned char *tmpbuf; - struct rmidev_data *dev_data = filp->private_data; - - if (IS_ERR(dev_data)) { - pr_err("%s: Pointer of char device data is invalid", __func__); - return -EBADF; - } - - mutex_lock(&(dev_data->file_mutex)); - - if (*f_pos > REG_ADDR_LIMIT) { - retval = -EFAULT; - goto unlock; - } - - if (count > (REG_ADDR_LIMIT - *f_pos)) - count = REG_ADDR_LIMIT - *f_pos; - - if (count == 0) { - retval = 0; - goto unlock; - } - - tmpbuf = kzalloc(count + 1, GFP_KERNEL); - if (!tmpbuf) { - retval = -ENOMEM; - goto unlock; - } - - if (copy_from_user(tmpbuf, buf, count)) { - retval = -EFAULT; - goto clean_up; - } - - retval = synaptics_rmi4_reg_write(rmidev->rmi4_data, - *f_pos, - tmpbuf, - count); - if (retval >= 0) - *f_pos += retval; - -clean_up: - kfree(tmpbuf); -unlock: - mutex_unlock(&(dev_data->file_mutex)); - return retval; -} - -/* - * rmidev_open: enable access to rmi device - * @inp: inode struture - * @filp: file structure - */ -static int rmidev_open(struct inode *inp, struct file *filp) -{ - int retval = 0; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - struct rmidev_data *dev_data = - container_of(inp->i_cdev, struct rmidev_data, main_dev); - - if (!dev_data) - return -EACCES; - - filp->private_data = dev_data; - - mutex_lock(&(dev_data->file_mutex)); - - rmi4_data->irq_enable(rmi4_data, false); - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt disabled\n", - __func__); - - if (dev_data->ref_count < 1) - dev_data->ref_count++; - else - retval = -EACCES; - - mutex_unlock(&(dev_data->file_mutex)); - - return retval; -} - -/* - * rmidev_release: - release access to rmi device - * @inp: inode structure - * @filp: file structure - */ -static int rmidev_release(struct inode *inp, struct file *filp) -{ - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - struct rmidev_data *dev_data = - container_of(inp->i_cdev, struct rmidev_data, main_dev); - - if (!dev_data) - return -EACCES; - - rmi4_data->reset_device(rmi4_data); - - mutex_lock(&(dev_data->file_mutex)); - - dev_data->ref_count--; - if (dev_data->ref_count < 0) - dev_data->ref_count = 0; - - rmi4_data->irq_enable(rmi4_data, true); - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt enabled\n", - __func__); - - mutex_unlock(&(dev_data->file_mutex)); - - return 0; -} - -static const struct file_operations rmidev_fops = { - .owner = THIS_MODULE, - .llseek = rmidev_llseek, - .read = rmidev_read, - .write = rmidev_write, - .open = rmidev_open, - .release = rmidev_release, -}; - -static void rmidev_device_cleanup(struct rmidev_data *dev_data) -{ - dev_t devno; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (dev_data) { - devno = dev_data->main_dev.dev; - - if (dev_data->device_class) - device_destroy(dev_data->device_class, devno); - - cdev_del(&dev_data->main_dev); - - unregister_chrdev_region(devno, 1); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: rmidev device removed\n", - __func__); - } - - return; -} - -static char *rmi_char_devnode(struct device *dev, umode_t *mode) -{ - if (!mode) - return NULL; - - *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - - return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev)); -} - -static int rmidev_create_device_class(void) -{ - rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME); - - if (IS_ERR(rmidev_device_class)) { - pr_err("%s: Failed to create /dev/%s\n", - __func__, CHAR_DEVICE_NAME); - return -ENODEV; - } - - rmidev_device_class->devnode = rmi_char_devnode; - - return 0; -} - -static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - dev_t dev_no; - unsigned char attr_count; - struct rmidev_data *dev_data; - struct device *device_ptr; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL); - if (!rmidev) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for rmidev\n", - __func__); - retval = -ENOMEM; - goto err_rmidev; - } - - rmidev->rmi4_data = rmi4_data; - - retval = rmidev_create_device_class(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create device class\n", - __func__); - goto err_device_class; - } - - if (rmidev_major_num) { - dev_no = MKDEV(rmidev_major_num, DEV_NUMBER); - retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME); - } else { - retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate char device region\n", - __func__); - goto err_device_region; - } - - rmidev_major_num = MAJOR(dev_no); - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Major number of rmidev = %d\n", - __func__, rmidev_major_num); - } - - dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); - if (!dev_data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for dev_data\n", - __func__); - retval = -ENOMEM; - goto err_dev_data; - } - - mutex_init(&dev_data->file_mutex); - dev_data->rmi_dev = rmidev; - rmidev->data = dev_data; - - cdev_init(&dev_data->main_dev, &rmidev_fops); - - retval = cdev_add(&dev_data->main_dev, dev_no, 1); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to add rmi char device\n", - __func__); - goto err_char_device; - } - - dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no)); - dev_data->device_class = rmidev_device_class; - - device_ptr = device_create(dev_data->device_class, NULL, dev_no, - NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no)); - if (IS_ERR(device_ptr)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create rmi char device\n", - __func__); - retval = -ENODEV; - goto err_char_device; - } - - retval = gpio_export(bdata->irq_gpio, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to export attention gpio\n", - __func__); - } else { - retval = gpio_export_link(&(rmi4_data->input_dev->dev), - "attn", bdata->irq_gpio); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s Failed to create gpio symlink\n", - __func__); - } else { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Exported attention gpio %d\n", - __func__, bdata->irq_gpio); - } - } - - rmidev->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME, - &rmi4_data->input_dev->dev.kobj); - if (!rmidev->sysfs_dir) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs directory\n", - __func__); - retval = -ENODEV; - goto err_sysfs_dir; - } - - retval = sysfs_create_bin_file(rmidev->sysfs_dir, - &attr_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs bin file\n", - __func__); - goto err_sysfs_bin; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(rmidev->sysfs_dir, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - retval = -ENODEV; - goto err_sysfs_attrs; - } - } - - return 0; - -err_sysfs_attrs: - for (attr_count--; attr_count >= 0; attr_count--) - sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr); - - sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data); - -err_sysfs_bin: - kobject_put(rmidev->sysfs_dir); - -err_sysfs_dir: -err_char_device: - rmidev_device_cleanup(dev_data); - kfree(dev_data); - -err_dev_data: - unregister_chrdev_region(dev_no, 1); - -err_device_region: - class_destroy(rmidev_device_class); - -err_device_class: - kfree(rmidev); - rmidev = NULL; - -err_rmidev: - return retval; -} - -static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char attr_count; - struct rmidev_data *dev_data; - - if (!rmidev) - goto exit; - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) - sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr); - - sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data); - - kobject_put(rmidev->sysfs_dir); - - dev_data = rmidev->data; - if (dev_data) { - rmidev_device_cleanup(dev_data); - kfree(dev_data); - } - - unregister_chrdev_region(rmidev->dev_no, 1); - - class_destroy(rmidev_device_class); - - kfree(rmidev); - rmidev = NULL; - -exit: - complete(&rmidev_remove_complete); - - return; -} - -static struct synaptics_rmi4_exp_fn rmidev_module = { - .fn_type = RMI_DEV, - .init = rmidev_init_device, - .remove = rmidev_remove_device, - .reset = NULL, - .reinit = NULL, - .early_suspend = NULL, - .suspend = NULL, - .resume = NULL, - .late_resume = NULL, - .attn = NULL, -}; - -static int __init rmidev_module_init(void) -{ - synaptics_rmi4_dsx_new_function(&rmidev_module, true); - - return 0; -} - -static void __exit rmidev_module_exit(void) -{ - synaptics_rmi4_dsx_new_function(&rmidev_module, false); - - wait_for_completion(&rmidev_remove_complete); - - return; -} - -module_init(rmidev_module_init); -module_exit(rmidev_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX RMI Dev Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index dc44b40a85f3..f14812fdee6c 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -404,6 +404,7 @@ struct arm_smmu_device { struct msm_bus_scale_pdata *bus_pdata; enum tz_smmu_device_id sec_id; + int regulator_defer; }; struct arm_smmu_cfg { @@ -497,6 +498,19 @@ struct static_cbndx_entry { u8 type; }; +struct arm_iommus_node { + struct device_node *master; + struct list_head list; + struct list_head iommuspec_list; +}; + +struct arm_iommus_spec { + struct of_phandle_args iommu_spec; + struct list_head list; +}; + +static LIST_HEAD(iommus_nodes); + static int arm_smmu_enable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_disable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_prepare_pgtable(void *addr, void *cookie); @@ -683,39 +697,40 @@ static int register_smmu_master(struct arm_smmu_device *smmu, return insert_smmu_master(smmu, master); } -static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu, - int *num_masters) +static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu) { - struct of_phandle_args iommuspec; - struct device_node *master; - - *num_masters = 0; + struct arm_iommus_node *node, *nex; - for_each_node_with_property(master, "iommus") { - int arg_ind = 0; - struct iommus_entry *entry, *n; + list_for_each_entry_safe(node, nex, &iommus_nodes, list) { + struct iommus_entry *entry, *next; + struct arm_iommus_spec *iommuspec_node, *n; LIST_HEAD(iommus); + int node_found = 0; - while (!of_parse_phandle_with_args( - master, "iommus", "#iommu-cells", - arg_ind, &iommuspec)) { - if (iommuspec.np != smmu->dev->of_node) { - arg_ind++; + list_for_each_entry_safe(iommuspec_node, n, + &node->iommuspec_list, list) { + if (iommuspec_node->iommu_spec.np != smmu->dev->of_node) continue; - } + + /* + * Since each master node will have iommu spec(s) of the + * same device, we can delete this master node after + * the devices are registered. + */ + node_found = 1; list_for_each_entry(entry, &iommus, list) - if (entry->node == master) + if (entry->node == node->master) break; if (&entry->list == &iommus) { entry = devm_kzalloc(smmu->dev, sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; - entry->node = master; + entry->node = node->master; list_add(&entry->list, &iommus); } - switch (iommuspec.args_count) { + switch (iommuspec_node->iommu_spec.args_count) { case 0: /* * For pci-e devices the SIDs are provided @@ -725,25 +740,29 @@ static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu, case 1: entry->num_sids++; entry->streamids[entry->num_sids - 1] - = iommuspec.args[0]; + = iommuspec_node->iommu_spec.args[0]; break; default: BUG(); } - arg_ind++; + list_del(&iommuspec_node->list); + kfree(iommuspec_node); } - list_for_each_entry_safe(entry, n, &iommus, list) { + list_for_each_entry_safe(entry, next, &iommus, list) { int rc = register_smmu_master(smmu, entry); - if (rc) { + + if (rc) dev_err(smmu->dev, "Couldn't register %s\n", - entry->node->name); - } else { - (*num_masters)++; - } + entry->node->name); list_del(&entry->list); devm_kfree(smmu->dev, entry); } + + if (node_found) { + list_del(&node->list); + kfree(node); + } } return 0; @@ -932,7 +951,8 @@ static int arm_smmu_disable_regulators(struct arm_smmu_device *smmu) arm_smmu_unprepare_clocks(smmu); arm_smmu_unrequest_bus(smmu); if (smmu->gdsc) { - ret = regulator_disable(smmu->gdsc); + ret = regulator_disable_deferred(smmu->gdsc, + smmu->regulator_defer); WARN(ret, "%s: Regulator disable failed\n", dev_name(smmu->dev)); } @@ -3592,6 +3612,12 @@ static int arm_smmu_init_regulators(struct arm_smmu_device *smmu) if (!of_get_property(dev->of_node, "vdd-supply", NULL)) return 0; + if (!of_property_read_u32(dev->of_node, + "qcom,deferred-regulator-disable-delay", + &(smmu->regulator_defer))) + dev_info(dev, "regulator defer delay %d\n", + smmu->regulator_defer); + smmu->gdsc = devm_regulator_get(dev, "vdd"); if (IS_ERR(smmu->gdsc)) return PTR_ERR(smmu->gdsc); @@ -3973,7 +3999,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; struct rb_node *node; - int num_irqs, i, err, num_masters; + int num_irqs, i, err; smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); if (!smmu) { @@ -4036,33 +4062,33 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) } i = 0; - smmu->masters = RB_ROOT; - err = arm_smmu_parse_iommus_properties(smmu, &num_masters); - if (err) - goto out_put_masters; - - dev_dbg(dev, "registered %d master devices\n", num_masters); err = arm_smmu_parse_impl_def_registers(smmu); if (err) - goto out_put_masters; + goto out; err = arm_smmu_init_regulators(smmu); if (err) - goto out_put_masters; + goto out; err = arm_smmu_init_clocks(smmu); if (err) - goto out_put_masters; + goto out; err = arm_smmu_init_bus_scaling(pdev, smmu); if (err) - goto out_put_masters; + goto out; parse_driver_options(smmu); err = arm_smmu_enable_clocks(smmu); if (err) + goto out; + + /* No probe deferral occurred! Proceed with iommu property parsing. */ + smmu->masters = RB_ROOT; + err = arm_smmu_parse_iommus_properties(smmu); + if (err) goto out_put_masters; smmu->sec_id = msm_dev_to_device_id(dev); @@ -4122,7 +4148,7 @@ out_put_masters: = container_of(node, struct arm_smmu_master, node); of_node_put(master->of_node); } - +out: return err; } @@ -4173,6 +4199,58 @@ static int arm_smmu_device_remove(struct platform_device *pdev) return 0; } +static void arm_smmu_free_master_nodes(void) +{ + struct arm_iommus_node *node, *nex; + struct arm_iommus_spec *entry, *n; + + list_for_each_entry_safe(node, nex, &iommus_nodes, list) { + list_for_each_entry_safe(entry, n, + &node->iommuspec_list, list) { + list_del(&entry->list); + kfree(entry); + } + list_del(&node->list); + kfree(node); + } +} + +static int arm_smmu_get_master_nodes(void) +{ + struct arm_iommus_node *node; + struct device_node *master; + struct of_phandle_args iommuspec; + struct arm_iommus_spec *entry; + + for_each_node_with_property(master, "iommus") { + int arg_ind = 0; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + goto release_memory; + node->master = master; + list_add(&node->list, &iommus_nodes); + + INIT_LIST_HEAD(&node->iommuspec_list); + + while (!of_parse_phandle_with_args(master, "iommus", + "#iommu-cells", arg_ind, &iommuspec)) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + goto release_memory; + entry->iommu_spec = iommuspec; + list_add(&entry->list, &node->iommuspec_list); + arg_ind++; + } + } + + return 0; + +release_memory: + arm_smmu_free_master_nodes(); + return -ENOMEM; +} + static struct platform_driver arm_smmu_driver = { .driver = { .name = "arm-smmu", @@ -4198,10 +4276,15 @@ static int __init arm_smmu_init(void) of_node_put(np); - ret = platform_driver_register(&arm_smmu_driver); + ret = arm_smmu_get_master_nodes(); if (ret) return ret; + ret = platform_driver_register(&arm_smmu_driver); + if (ret) { + arm_smmu_free_master_nodes(); + return ret; + } /* Oh, for a proper bus abstraction */ if (!iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, &arm_smmu_ops); diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 776e06facc11..c21846c1f8d5 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -28,6 +28,7 @@ #include <linux/dma-mapping.h> #include <asm/cacheflush.h> #include <asm/dma-iommu.h> +#include "iommu-debug.h" #if defined(CONFIG_IOMMU_DEBUG_TRACKING) || defined(CONFIG_IOMMU_TESTS) @@ -84,371 +85,58 @@ static const char *iommu_debug_attr_to_string(enum iommu_attr attr) static DEFINE_MUTEX(iommu_debug_attachments_lock); static LIST_HEAD(iommu_debug_attachments); -static struct dentry *debugfs_attachments_dir; +/* + * Each group may have more than one domain; but each domain may + * only have one group. + * Used by debug tools to display the name of the device(s) associated + * with a particular domain. + */ struct iommu_debug_attachment { struct iommu_domain *domain; - struct device *dev; - struct dentry *dentry; + struct iommu_group *group; struct list_head list; - unsigned long reg_offset; }; -static int iommu_debug_attachment_info_show(struct seq_file *s, void *ignored) -{ - struct iommu_debug_attachment *attach = s->private; - phys_addr_t pt_phys; - int secure_vmid; - - seq_printf(s, "Domain: 0x%p\n", attach->domain); - if (iommu_domain_get_attr(attach->domain, DOMAIN_ATTR_PT_BASE_ADDR, - &pt_phys)) { - seq_puts(s, "PT_BASE_ADDR: (Unknown)\n"); - } else { - void *pt_virt = phys_to_virt(pt_phys); - - seq_printf(s, "PT_BASE_ADDR: virt=0x%p phys=%pa\n", - pt_virt, &pt_phys); - } - - seq_puts(s, "SECURE_VMID: "); - if (iommu_domain_get_attr(attach->domain, - DOMAIN_ATTR_SECURE_VMID, - &secure_vmid)) - seq_puts(s, "(Unknown)\n"); - else - seq_printf(s, "%s (0x%x)\n", - msm_secure_vmid_to_string(secure_vmid), secure_vmid); - - return 0; -} - -static int iommu_debug_attachment_info_open(struct inode *inode, - struct file *file) -{ - return single_open(file, iommu_debug_attachment_info_show, - inode->i_private); -} - -static const struct file_operations iommu_debug_attachment_info_fops = { - .open = iommu_debug_attachment_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static ssize_t iommu_debug_attachment_trigger_fault_write( - struct file *file, const char __user *ubuf, size_t count, - loff_t *offset) -{ - struct iommu_debug_attachment *attach = file->private_data; - unsigned long flags; - - if (kstrtoul_from_user(ubuf, count, 0, &flags)) { - pr_err("Invalid flags format\n"); - return -EFAULT; - } - - iommu_trigger_fault(attach->domain, flags); - - return count; -} - -static const struct file_operations -iommu_debug_attachment_trigger_fault_fops = { - .open = simple_open, - .write = iommu_debug_attachment_trigger_fault_write, -}; - -static ssize_t iommu_debug_attachment_reg_offset_write( - struct file *file, const char __user *ubuf, size_t count, - loff_t *offset) -{ - struct iommu_debug_attachment *attach = file->private_data; - unsigned long reg_offset; - - if (kstrtoul_from_user(ubuf, count, 0, ®_offset)) { - pr_err("Invalid reg_offset format\n"); - return -EFAULT; - } - - attach->reg_offset = reg_offset; - - return count; -} - -static const struct file_operations iommu_debug_attachment_reg_offset_fops = { - .open = simple_open, - .write = iommu_debug_attachment_reg_offset_write, -}; - -static ssize_t iommu_debug_attachment_reg_read_read( - struct file *file, char __user *ubuf, size_t count, loff_t *offset) -{ - struct iommu_debug_attachment *attach = file->private_data; - unsigned long val; - char *val_str; - ssize_t val_str_len; - - if (*offset) - return 0; - - val = iommu_reg_read(attach->domain, attach->reg_offset); - val_str = kasprintf(GFP_KERNEL, "0x%lx\n", val); - if (!val_str) - return -ENOMEM; - val_str_len = strlen(val_str); - - if (copy_to_user(ubuf, val_str, val_str_len)) { - pr_err("copy_to_user failed\n"); - val_str_len = -EFAULT; - goto out; - } - *offset = 1; /* non-zero means we're done */ - -out: - kfree(val_str); - return val_str_len; -} - -static const struct file_operations iommu_debug_attachment_reg_read_fops = { - .open = simple_open, - .read = iommu_debug_attachment_reg_read_read, -}; - -static ssize_t iommu_debug_attachment_reg_write_write( - struct file *file, const char __user *ubuf, size_t count, - loff_t *offset) -{ - struct iommu_debug_attachment *attach = file->private_data; - unsigned long val; - - if (kstrtoul_from_user(ubuf, count, 0, &val)) { - pr_err("Invalid val format\n"); - return -EFAULT; - } - - iommu_reg_write(attach->domain, attach->reg_offset, val); - - return count; -} - -static const struct file_operations iommu_debug_attachment_reg_write_fops = { - .open = simple_open, - .write = iommu_debug_attachment_reg_write_write, -}; - -/* should be called with iommu_debug_attachments_lock locked */ -static int iommu_debug_attach_add_debugfs( - struct iommu_debug_attachment *attach) -{ - const char *attach_name; - struct device *dev = attach->dev; - struct iommu_domain *domain = attach->domain; - int is_dynamic; - - if (iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &is_dynamic)) - is_dynamic = 0; - - if (is_dynamic) { - uuid_le uuid; - - uuid_le_gen(&uuid); - attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev), - uuid.b); - if (!attach_name) - return -ENOMEM; - } else { - attach_name = dev_name(dev); - } - - attach->dentry = debugfs_create_dir(attach_name, - debugfs_attachments_dir); - if (!attach->dentry) { - pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n", - attach_name, domain); - if (is_dynamic) - kfree(attach_name); - return -EIO; - } - - if (is_dynamic) - kfree(attach_name); - - if (!debugfs_create_file( - "info", S_IRUSR, attach->dentry, attach, - &iommu_debug_attachment_info_fops)) { - pr_err("Couldn't create iommu/attachments/%s/info debugfs file for domain 0x%p\n", - dev_name(dev), domain); - goto err_rmdir; - } - - if (!debugfs_create_file( - "trigger_fault", S_IRUSR, attach->dentry, attach, - &iommu_debug_attachment_trigger_fault_fops)) { - pr_err("Couldn't create iommu/attachments/%s/trigger_fault debugfs file for domain 0x%p\n", - dev_name(dev), domain); - goto err_rmdir; - } - - if (!debugfs_create_file( - "reg_offset", S_IRUSR, attach->dentry, attach, - &iommu_debug_attachment_reg_offset_fops)) { - pr_err("Couldn't create iommu/attachments/%s/reg_offset debugfs file for domain 0x%p\n", - dev_name(dev), domain); - goto err_rmdir; - } - - if (!debugfs_create_file( - "reg_read", S_IRUSR, attach->dentry, attach, - &iommu_debug_attachment_reg_read_fops)) { - pr_err("Couldn't create iommu/attachments/%s/reg_read debugfs file for domain 0x%p\n", - dev_name(dev), domain); - goto err_rmdir; - } - - if (!debugfs_create_file( - "reg_write", S_IRUSR, attach->dentry, attach, - &iommu_debug_attachment_reg_write_fops)) { - pr_err("Couldn't create iommu/attachments/%s/reg_write debugfs file for domain 0x%p\n", - dev_name(dev), domain); - goto err_rmdir; - } - - return 0; - -err_rmdir: - debugfs_remove_recursive(attach->dentry); - return -EIO; -} - -void iommu_debug_domain_add(struct iommu_domain *domain) +void iommu_debug_attach_device(struct iommu_domain *domain, + struct device *dev) { struct iommu_debug_attachment *attach; + struct iommu_group *group; - mutex_lock(&iommu_debug_attachments_lock); + group = iommu_group_get(dev); + if (!group) + return; - attach = kmalloc(sizeof(*attach), GFP_KERNEL); + attach = kzalloc(sizeof(*attach), GFP_KERNEL); if (!attach) - goto out_unlock; + return; attach->domain = domain; - attach->dev = NULL; - list_add(&attach->list, &iommu_debug_attachments); + attach->group = group; + INIT_LIST_HEAD(&attach->list); -out_unlock: + mutex_lock(&iommu_debug_attachments_lock); + list_add(&attach->list, &iommu_debug_attachments); mutex_unlock(&iommu_debug_attachments_lock); } void iommu_debug_domain_remove(struct iommu_domain *domain) { - struct iommu_debug_attachment *it; + struct iommu_debug_attachment *it, *tmp; mutex_lock(&iommu_debug_attachments_lock); - list_for_each_entry(it, &iommu_debug_attachments, list) - if (it->domain == domain && it->dev == NULL) - break; - - if (&it->list == &iommu_debug_attachments) { - WARN(1, "Couldn't find debug attachment for domain=0x%p", - domain); - } else { + list_for_each_entry_safe(it, tmp, &iommu_debug_attachments, list) { + if (it->domain != domain) + continue; list_del(&it->list); + iommu_group_put(it->group); kfree(it); } - mutex_unlock(&iommu_debug_attachments_lock); -} - -void iommu_debug_attach_device(struct iommu_domain *domain, - struct device *dev) -{ - struct iommu_debug_attachment *attach; - - mutex_lock(&iommu_debug_attachments_lock); - - list_for_each_entry(attach, &iommu_debug_attachments, list) - if (attach->domain == domain && attach->dev == NULL) - break; - - if (&attach->list == &iommu_debug_attachments) { - WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s", - domain, dev_name(dev)); - } else { - attach->dev = dev; - - /* - * we might not init until after other drivers start calling - * iommu_attach_device. Only set up the debugfs nodes if we've - * already init'd to avoid polluting the top-level debugfs - * directory (by calling debugfs_create_dir with a NULL - * parent). These will be flushed out later once we init. - */ - - if (debugfs_attachments_dir) - iommu_debug_attach_add_debugfs(attach); - } - - mutex_unlock(&iommu_debug_attachments_lock); -} - -void iommu_debug_detach_device(struct iommu_domain *domain, - struct device *dev) -{ - struct iommu_debug_attachment *it; - - mutex_lock(&iommu_debug_attachments_lock); - list_for_each_entry(it, &iommu_debug_attachments, list) - if (it->domain == domain && it->dev == dev) - break; - - if (&it->list == &iommu_debug_attachments) { - WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s", - domain, dev_name(dev)); - } else { - /* - * Just remove debugfs entry and mark dev as NULL on - * iommu_detach call. We would remove the actual - * attachment entry from the list only on domain_free call. - * This is to ensure we keep track of unattached domains too. - */ - - debugfs_remove_recursive(it->dentry); - it->dev = NULL; - } - mutex_unlock(&iommu_debug_attachments_lock); -} - -static int iommu_debug_init_tracking(void) -{ - int ret = 0; - struct iommu_debug_attachment *attach; - - mutex_lock(&iommu_debug_attachments_lock); - debugfs_attachments_dir = debugfs_create_dir("attachments", - iommu_debugfs_top); - if (!debugfs_attachments_dir) { - pr_err("Couldn't create iommu/attachments debugfs directory\n"); - ret = -ENODEV; - goto out_unlock; - } - - /* set up debugfs entries for attachments made during early boot */ - list_for_each_entry(attach, &iommu_debug_attachments, list) - if (attach->dev) - iommu_debug_attach_add_debugfs(attach); -out_unlock: mutex_unlock(&iommu_debug_attachments_lock); - return ret; } -static void iommu_debug_destroy_tracking(void) -{ - debugfs_remove_recursive(debugfs_attachments_dir); -} -#else -static inline int iommu_debug_init_tracking(void) { return 0; } -static inline void iommu_debug_destroy_tracking(void) { } #endif #ifdef CONFIG_IOMMU_TESTS @@ -479,6 +167,8 @@ struct iommu_debug_device { u64 phys; size_t len; struct list_head list; + struct mutex clk_lock; + unsigned int clk_count; }; static int iommu_debug_build_phoney_sg_table(struct device *dev, @@ -1518,6 +1208,7 @@ static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev, return -ENOMEM; } + val = VMID_CP_CAMERA; if (is_secure && iommu_domain_set_attr(ddev->domain, DOMAIN_ATTR_SECURE_VMID, &val)) { @@ -1800,6 +1491,10 @@ static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf, ssize_t retval; size_t buflen; + if (kptr_restrict != 0) { + pr_err("kptr_restrict needs to be disabled.\n"); + return -EPERM; + } if (!dev->archdata.mapping) { pr_err("No mapping. Did you already attach?\n"); return -EINVAL; @@ -1867,6 +1562,10 @@ static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf, ssize_t retval; size_t buflen; + if (kptr_restrict != 0) { + pr_err("kptr_restrict needs to be disabled.\n"); + return -EPERM; + } if (!ddev->domain) { pr_err("No domain. Did you already attach?\n"); return -EINVAL; @@ -1915,6 +1614,10 @@ static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf, ssize_t retval; size_t buflen; + if (kptr_restrict != 0) { + pr_err("kptr_restrict needs to be disabled.\n"); + return -EPERM; + } if (!dev->archdata.mapping) { pr_err("No mapping. Did you already attach?\n"); return -EINVAL; @@ -2355,20 +2058,34 @@ static ssize_t iommu_debug_config_clocks_write(struct file *file, return -EFAULT; } + mutex_lock(&ddev->clk_lock); switch (buf) { case '0': + if (ddev->clk_count == 0) { + dev_err(dev, "Config clocks already disabled\n"); + break; + } + + if (--ddev->clk_count > 0) + break; + dev_err(dev, "Disabling config clocks\n"); iommu_disable_config_clocks(ddev->domain); break; case '1': + if (ddev->clk_count++ > 0) + break; + dev_err(dev, "Enabling config clocks\n"); if (iommu_enable_config_clocks(ddev->domain)) dev_err(dev, "Failed!\n"); break; default: dev_err(dev, "Invalid value. Should be 0 or 1.\n"); + mutex_unlock(&ddev->clk_lock); return -EINVAL; } + mutex_unlock(&ddev->clk_lock); return count; } @@ -2394,6 +2111,7 @@ static int snarf_iommu_devices(struct device *dev, const char *name) ddev = kzalloc(sizeof(*ddev), GFP_KERNEL); if (!ddev) return -ENODEV; + mutex_init(&ddev->clk_lock); ddev->dev = dev; dir = debugfs_create_dir(name, debugfs_tests_dir); if (!dir) { @@ -2547,6 +2265,9 @@ err: static int pass_iommu_devices(struct device *dev, void *ignored) { + if (!of_device_is_compatible(dev->of_node, "iommu-debug-test")) + return 0; + if (!of_find_property(dev->of_node, "iommus", NULL)) return 0; @@ -2560,6 +2281,9 @@ static int iommu_debug_populate_devices(void) const char *cb_name; for_each_compatible_node(np, NULL, "qcom,msm-smmu-v2-ctx") { + if (!of_device_is_compatible(np, "iommu-debug-test")) + continue; + ret = of_property_read_string(np, "label", &cb_name); if (ret) return ret; @@ -2625,9 +2349,6 @@ static struct platform_driver iommu_debug_driver = { static int iommu_debug_init(void) { - if (iommu_debug_init_tracking()) - return -ENODEV; - if (iommu_debug_init_tests()) return -ENODEV; @@ -2637,7 +2358,6 @@ static int iommu_debug_init(void) static void iommu_debug_exit(void) { platform_driver_unregister(&iommu_debug_driver); - iommu_debug_destroy_tracking(); iommu_debug_destroy_tests(); } diff --git a/drivers/iommu/iommu-debug.h b/drivers/iommu/iommu-debug.h index 3dc87032f2a0..91c418d9e37f 100644 --- a/drivers/iommu/iommu-debug.h +++ b/drivers/iommu/iommu-debug.h @@ -1,11 +1,21 @@ +/* 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 + * 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 IOMMU_DEBUG_H #define IOMMU_DEBUG_H #ifdef CONFIG_IOMMU_DEBUG_TRACKING void iommu_debug_attach_device(struct iommu_domain *domain, struct device *dev); -void iommu_debug_detach_device(struct iommu_domain *domain, struct device *dev); -void iommu_debug_domain_add(struct iommu_domain *domain); void iommu_debug_domain_remove(struct iommu_domain *domain); #else /* !CONFIG_IOMMU_DEBUG_TRACKING */ @@ -15,15 +25,6 @@ static inline void iommu_debug_attach_device(struct iommu_domain *domain, { } -static inline void iommu_debug_detach_device(struct iommu_domain *domain, - struct device *dev) -{ -} - -static inline void iommu_debug_domain_add(struct iommu_domain *domain) -{ -} - static inline void iommu_debug_domain_remove(struct iommu_domain *domain) { } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index b831796b5b7d..33176a4aa6ef 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1118,8 +1118,6 @@ static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, domain->ops = bus->iommu_ops; domain->type = type; - iommu_debug_domain_add(domain); - return domain; } @@ -1186,7 +1184,6 @@ static void __iommu_detach_device(struct iommu_domain *domain, if (unlikely(domain->ops->detach_dev == NULL)) return; - iommu_debug_detach_device(domain, dev); domain->ops->detach_dev(domain, dev); trace_detach_device_from_domain(dev); } diff --git a/drivers/media/platform/msm/ais/common/cam_soc_api.c b/drivers/media/platform/msm/ais/common/cam_soc_api.c index 09d470ed6eb0..118d665a44d3 100644 --- a/drivers/media/platform/msm/ais/common/cam_soc_api.c +++ b/drivers/media/platform/msm/ais/common/cam_soc_api.c @@ -379,13 +379,13 @@ int msm_camera_clk_enable(struct device *dev, clk_info[i].clk_name); goto cam_clk_set_err; } - rc = clk_set_rate(clk_ptr[i], - clk_rate); - if (rc < 0) { - pr_err("%s set rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } + } + rc = clk_set_rate(clk_ptr[i], + clk_rate); + if (rc < 0) { + pr_err("%s set rate failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; } } rc = clk_prepare_enable(clk_ptr[i]); diff --git a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c index 675bf6b24b03..073b91a6d2d9 100644 --- a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c +++ b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c @@ -561,8 +561,8 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, sizeof(struct msm_buf_mngr_info))) { return -EFAULT; } - MSM_CAM_GET_IOCTL_ARG_PTR(&k_ioctl.ioctl_ptr, - &buf_info, sizeof(void *)); + k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; + argp = &k_ioctl; rc = msm_cam_buf_mgr_ops(cmd, argp); } diff --git a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c index c9cb0080436a..811ac98beead 100644 --- a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c @@ -2889,6 +2889,8 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, case MSM_SD_SHUTDOWN: case MSM_SD_NOTIFY_FREEZE: case MSM_SD_UNNOTIFY_FREEZE: + case VIDIOC_MSM_CPP_IOMMU_ATTACH: + case VIDIOC_MSM_CPP_IOMMU_DETACH: break; default: { if (ioctl_ptr == NULL) { @@ -2897,8 +2899,9 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, } *ioctl_ptr = arg; - if ((*ioctl_ptr == NULL) || - (*ioctl_ptr)->ioctl_ptr == NULL) { + if (((*ioctl_ptr) == NULL) || + ((*ioctl_ptr)->ioctl_ptr == NULL) || + ((*ioctl_ptr)->len == 0)) { pr_err("Error invalid ioctl argument cmd %u", cmd); return -EINVAL; } diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c index 345fac905074..d146cc3d28a5 100644 --- a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c @@ -787,6 +787,25 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 1); + if (rc < 0) { + pr_err("%s:%d csiphy config_vreg failed\n", + __func__, __LINE__); + goto csiphy_vreg_config_fail; + } + rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 1); + if (rc < 0) { + pr_err("%s:%d csiphy enable_vreg failed\n", + __func__, __LINE__); + goto top_vreg_enable_failed; + } + rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev, csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk, csiphy_dev->num_clk, true); @@ -795,7 +814,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) if (rc < 0) { pr_err("%s: csiphy clk enable failed\n", __func__); csiphy_dev->ref_count--; - goto csiphy_resource_fail; + goto csiphy_enable_clk_fail; } CDBG("%s:%d called\n", __func__, __LINE__); @@ -823,7 +842,17 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) csiphy_dev->csiphy_state = CSIPHY_POWER_UP; return 0; -csiphy_resource_fail: +csiphy_enable_clk_fail: + msm_camera_enable_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 0); +top_vreg_enable_failed: + msm_camera_config_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 0); +csiphy_vreg_config_fail: if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, CAM_AHB_SUSPEND_VOTE) < 0) pr_err("%s: failed to vote for AHB\n", __func__); @@ -862,14 +891,34 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) return rc; } + rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 1); + if (rc < 0) { + pr_err("%s:%d csiphy config_vreg failed\n", + __func__, __LINE__); + goto csiphy_vreg_config_fail; + } + rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 1); + if (rc < 0) { + pr_err("%s:%d csiphy enable_vreg failed\n", + __func__, __LINE__); + goto top_vreg_enable_failed; + } + rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev, csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk, csiphy_dev->num_clk, true); if (rc < 0) { pr_err("%s: csiphy clk enable failed\n", __func__); csiphy_dev->ref_count--; - goto csiphy_resource_fail; + goto csiphy_enable_clk_fail; } + CDBG("%s:%d clk enable success\n", __func__, __LINE__); if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) msm_csiphy_3ph_reset(csiphy_dev); @@ -890,7 +939,17 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) csiphy_dev->csiphy_state = CSIPHY_POWER_UP; return 0; -csiphy_resource_fail: +csiphy_enable_clk_fail: + msm_camera_enable_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 0); +top_vreg_enable_failed: + msm_camera_config_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 0); +csiphy_vreg_config_fail: if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, CAM_AHB_SUSPEND_VOTE) < 0) pr_err("%s: failed to vote for AHB\n", __func__); @@ -999,6 +1058,14 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) csiphy_dev->csiphy_3p_clk, 2, false); } + msm_camera_enable_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, + csiphy_dev->regulator_count, NULL, 0, + &csiphy_dev->csiphy_reg_ptr[0], 0); + msm_camera_config_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count, + NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0); + csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, @@ -1105,6 +1172,13 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) csiphy_dev->csiphy_3p_clk, 2, false); } + msm_camera_enable_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count, + NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0); + msm_camera_config_vreg(&csiphy_dev->pdev->dev, + csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count, + NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0); + csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, @@ -1463,6 +1537,14 @@ static int csiphy_probe(struct platform_device *pdev) goto csiphy_no_resource; } + rc = msm_camera_get_dt_vreg_data(pdev->dev.of_node, + &(new_csiphy_dev->csiphy_vreg), + &(new_csiphy_dev->regulator_count)); + if (rc < 0) { + pr_err("%s: get vreg data from dtsi fail\n", __func__); + rc = -EFAULT; + goto csiphy_no_resource; + } /* ToDo: Enable 3phase clock for dynamic clock enable/disable */ rc = msm_csiphy_get_clk_info(new_csiphy_dev, pdev); if (rc < 0) { diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h index 9b38fa50ce98..025ce0d3e05a 100644 --- a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h +++ b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h @@ -20,6 +20,7 @@ #include <media/ais/msm_ais_sensor.h> #include "msm_sd.h" #include "msm_camera_io_util.h" +#include "msm_camera_dt_util.h" #include "cam_soc_api.h" #define MAX_CSIPHY 3 @@ -169,6 +170,9 @@ struct csiphy_device { uint32_t csiphy_sof_debug; uint32_t csiphy_sof_debug_count; uint32_t is_combo_mode; + struct camera_vreg_t *csiphy_vreg; + struct regulator *csiphy_reg_ptr[MAX_REGULATOR]; + int32_t regulator_count; struct msm_camera_csiphy_params csiphy_params; }; diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c index 9cdcabb762c0..2030755d59d0 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c @@ -24,6 +24,7 @@ #include <linux/dma-mapping.h> #include <linux/msm_dma_iommu_mapping.h> #include <linux/workqueue.h> +#include <linux/sizes.h> #include <soc/qcom/scm.h> #include <soc/qcom/secure_buffer.h> #include <msm_camera_tz_util.h> @@ -98,6 +99,7 @@ struct scratch_mapping { struct cam_context_bank_info { struct device *dev; struct dma_iommu_mapping *mapping; + enum iommu_attr attr; dma_addr_t va_start; size_t va_len; const char *name; @@ -108,9 +110,8 @@ struct cam_context_bank_info { struct mutex lock; int handle; enum cam_smmu_ops_param state; - void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *, - struct device *, unsigned long, - int, void*); + client_handler handler[CAM_SMMU_CB_MAX]; + client_reset_handler hw_reset_handler[CAM_SMMU_CB_MAX]; void *token[CAM_SMMU_CB_MAX]; int cb_count; int ref_cnt; @@ -354,9 +355,9 @@ static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr) } void cam_smmu_reg_client_page_fault_handler(int handle, - void (*client_page_fault_handler)(struct iommu_domain *, - struct device *, unsigned long, - int, void*), void *token) + client_handler page_fault_handler, + client_reset_handler hw_reset_handler, + void *token) { int idx, i = 0; @@ -380,7 +381,7 @@ void cam_smmu_reg_client_page_fault_handler(int handle, return; } - if (client_page_fault_handler) { + if (page_fault_handler) { if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) { pr_err("%s Should not regiester more handlers\n", iommu_cb_set.cb_info[idx].name); @@ -392,7 +393,9 @@ void cam_smmu_reg_client_page_fault_handler(int handle, if (iommu_cb_set.cb_info[idx].token[i] == NULL) { iommu_cb_set.cb_info[idx].token[i] = token; iommu_cb_set.cb_info[idx].handler[i] = - client_page_fault_handler; + page_fault_handler; + iommu_cb_set.cb_info[idx].hw_reset_handler[i] = + hw_reset_handler; break; } } @@ -420,6 +423,7 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, { char *cb_name; int idx; + int j; struct cam_smmu_work_payload *payload; if (!token) { @@ -453,6 +457,18 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, payload->token = token; payload->idx = idx; + /* trigger hw reset handler */ + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + for (j = 0; j < CAM_SMMU_CB_MAX; j++) { + if ((iommu_cb_set.cb_info[idx].hw_reset_handler[j])) { + iommu_cb_set.cb_info[idx].hw_reset_handler[j]( + payload->domain, + payload->dev, + iommu_cb_set.cb_info[idx].token[j]); + } + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + mutex_lock(&iommu_cb_set.payload_list_lock); list_add_tail(&payload->list, &iommu_cb_set.payload_list); mutex_unlock(&iommu_cb_set.payload_list_lock); @@ -876,6 +892,13 @@ static int cam_smmu_detach_device(int idx) { struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) { + pr_err("Client %s buffer list is not clean!\n", + iommu_cb_set.cb_info[idx].name); + cam_smmu_print_list(idx); + cam_smmu_clean_buffer_list(idx); + } + /* detach the mapping to device */ arm_iommu_detach_device(cb->dev); iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH; @@ -1031,7 +1054,8 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, buf = dma_buf_get(ion_fd); if (IS_ERR_OR_NULL(buf)) { rc = PTR_ERR(buf); - pr_err("Error: dma get buf failed. fd = %d\n", ion_fd); + pr_err("Error: dma get buf failed. fd = %d rc = %d\n", + ion_fd, rc); goto err_out; } @@ -1096,7 +1120,9 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, rc = -ENOSPC; goto err_mapping_info; } - CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd, + CDBG("name %s ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", + iommu_cb_set.cb_info[idx].name, + ion_fd, (void *)iommu_cb_set.cb_info[idx].dev, (void *)*paddr_ptr, (unsigned int)*len_ptr); @@ -1305,6 +1331,47 @@ int cam_smmu_get_handle(char *identifier, int *handle_ptr) } EXPORT_SYMBOL(cam_smmu_get_handle); + +int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data) +{ + int ret = 0, idx; + struct cam_context_bank_info *cb = NULL; + struct iommu_domain *domain = NULL; + + CDBG("E: set_attr\n"); + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) { + domain = iommu_cb_set.cb_info[idx].mapping->domain; + cb = &iommu_cb_set.cb_info[idx]; + cb->attr |= flags; + /* set attributes */ + ret = iommu_domain_set_attr(domain, cb->attr, (void *)data); + if (ret < 0) { + pr_err("Error: set attr\n"); + return -ENODEV; + } + } else { + return -EINVAL; + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return ret; +} +EXPORT_SYMBOL(cam_smmu_set_attr); + + int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops) { int ret = 0, idx; @@ -2226,7 +2293,7 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, } } else { cb->va_start = SZ_128K; - cb->va_len = VA_SPACE_END - SZ_128K; + cb->va_len = VA_SPACE_END - SZ_128M; } /* create a virtual mapping */ diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h index 3b8481f8bf7e..189ab2488e65 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h +++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -49,6 +49,13 @@ enum cam_smmu_map_dir { CAM_SMMU_MAP_INVALID }; +typedef void (*client_handler)(struct iommu_domain *, + struct device *, unsigned long, + int, void*); + +typedef void (*client_reset_handler)(struct iommu_domain *, + struct device *, void*); + /** * @param identifier: Unique identifier to be used by clients which they * should get from device tree. CAM SMMU driver will @@ -61,6 +68,16 @@ enum cam_smmu_map_dir { */ int cam_smmu_get_handle(char *identifier, int *handle_ptr); + +/** + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param flags : SMMU attribute type + * @data : Value of attribute + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data); + + /** * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) * @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH @@ -215,11 +232,12 @@ int cam_smmu_find_index_by_handle(int hdl); /** * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) * @param client_page_fault_handler: It is triggered in IOMMU page fault + * @param client_hw_reset_handler: It is triggered in IOMMU page fault * @param token: It is input param when trigger page fault handler */ void cam_smmu_reg_client_page_fault_handler(int handle, - void (*client_page_fault_handler)(struct iommu_domain *, - struct device *, unsigned long, - int, void*), void *token); + client_handler page_fault_handler, + client_reset_handler hw_reset_handler, + void *token); #endif /* _CAM_SMMU_API_H_ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index f9809615b407..08a8135ea9f4 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -2480,6 +2480,12 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) rc = -1; return rc; } + if (ab_ib_vote->num_src >= VFE_AXI_SRC_MAX) { + pr_err("%s: ab_ib_vote num_src is exceeding limit\n", + __func__); + rc = -1; + return rc; + } if (ab_ib_vote->lpm_mode) { for (i = 0; i < ab_ib_vote->num_src; i++) { stream_info = diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 2f8134bc3efb..f19e6dd1cb01 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -2318,7 +2318,9 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) cam_smmu_reg_client_page_fault_handler( vfe_dev->buf_mgr->iommu_hdl, - msm_vfe_iommu_fault_handler, vfe_dev); + msm_vfe_iommu_fault_handler, + NULL, + vfe_dev); mutex_unlock(&vfe_dev->core_mutex); mutex_unlock(&vfe_dev->realtime_mutex); return 0; @@ -2367,7 +2369,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) /* Unregister page fault handler */ cam_smmu_reg_client_page_fault_handler( vfe_dev->buf_mgr->iommu_hdl, - NULL, vfe_dev); + NULL, NULL, vfe_dev); rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); if (rc <= 0) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index b7feb126f707..25fc34b26bc1 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -424,7 +424,17 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, list_for_each_entry_safe(buff, save, buff_head, entry) { if (buff->map_info.buff_info.index == buffer_info->index) { - pr_err("error buffer index already queued\n"); + pr_err("error buf index already queued\n"); + pr_err("error buf, fd %d idx %d native %d ssid %d %d\n", + buffer_info->fd, buffer_info->index, + buffer_info->native_buff, + buff_queue->session_id, + buff_queue->stream_id); + pr_err("existing buf,fd %d idx %d native %d id %x\n", + buff->map_info.buff_info.fd, + buff->map_info.buff_info.index, + buff->map_info.buff_info.native_buff, + buff->map_info.buff_info.identity); goto error; } } @@ -439,6 +449,11 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, buff->map_info.buff_info = *buffer_info; buff->map_info.buf_fd = buffer_info->fd; + trace_printk("fd %d index %d native_buff %d ssid %d %d\n", + buffer_info->fd, buffer_info->index, + buffer_info->native_buff, buff_queue->session_id, + buff_queue->stream_id); + if (buff_queue->security_mode == SECURE_MODE) rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl, buffer_info->fd, CAM_SMMU_MAP_RW, @@ -469,6 +484,11 @@ static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, { int ret = -1; + trace_printk("fd %d index %d native_buf %d ssid %d %d\n", + buff->map_info.buf_fd, buff->map_info.buff_info.index, + buff->map_info.buff_info.native_buff, buff_queue->session_id, + buff_queue->stream_id); + if (buff_queue->security_mode == SECURE_MODE) ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl, buff->map_info.buf_fd); @@ -770,6 +790,36 @@ static int msm_cpp_dump_addr(struct cpp_device *cpp_dev, return 0; } +static void msm_cpp_iommu_fault_reset_handler( + struct iommu_domain *domain, struct device *dev, + void *token) +{ + struct cpp_device *cpp_dev = NULL; + + if (!token) { + pr_err("Invalid token\n"); + return; + } + + cpp_dev = token; + + if (cpp_dev->fault_status != CPP_IOMMU_FAULT_NONE) { + pr_err("fault already detected %d\n", cpp_dev->fault_status); + return; + } + + cpp_dev->fault_status = CPP_IOMMU_FAULT_DETECTED; + + /* mask IRQ status */ + msm_camera_io_w(0xB, cpp_dev->cpp_hw_base + 0xC); + + pr_err("Issue CPP HALT %d\n", cpp_dev->fault_status); + + /* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/ + msm_camera_io_w(0x1, cpp_dev->cpp_hw_base + 0x16C); + +} + static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, void *token) { @@ -777,50 +827,94 @@ static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain, struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME]; int32_t i = 0, queue_len = 0; struct msm_device_queue *queue = NULL; - int32_t rc = 0; + int32_t ifd, ofd, dfd, t0fd, t1fd; + int counter = 0; + u32 result; if (token) { cpp_dev = token; + + if (cpp_dev->fault_status != CPP_IOMMU_FAULT_DETECTED) { + pr_err("fault recovery already done %d\n", + cpp_dev->fault_status); + return; + } + disable_irq(cpp_dev->irq->start); if (atomic_read(&cpp_timer.used)) { atomic_set(&cpp_timer.used, 0); del_timer_sync(&cpp_timer.cpp_timer); } - mutex_lock(&cpp_dev->mutex); tasklet_kill(&cpp_dev->cpp_tasklet); - rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); - if (rc < 0) { - pr_err("load fw failure %d-retry\n", rc); - rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev); - if (rc < 0) { - msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8); - mutex_unlock(&cpp_dev->mutex); - return; - } + + pr_err("in recovery, HALT status = 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10)); + + while (counter < MSM_CPP_POLL_RETRIES) { + result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); + if (result & 0x2) + break; + usleep_range(100, 200); + counter++; } + /* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */ + pr_err("counter %d HALT status later = 0x%x\n", + counter, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10)); + + /* MMSS_A_CPP_RST_CMD_0 = 0x8 firmware reset = 0x3FFFF */ + msm_camera_io_w(0x3FFFF, cpp_dev->cpp_hw_base + 0x8); + + counter = 0; + while (counter < MSM_CPP_POLL_RETRIES) { + result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); + if (result & 0x1) + break; + usleep_range(100, 200); + counter++; + } + + /* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */ + pr_err("counter %d after reset IRQ_STATUS_0 = 0x%x\n", + counter, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10)); + + /* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/ + msm_camera_io_w(0x0, cpp_dev->cpp_hw_base + 0x16C); + queue = &cpp_timer.data.cpp_dev->processing_q; queue_len = queue->len; if (!queue_len) { pr_err("%s:%d: Invalid queuelen\n", __func__, __LINE__); - msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8); - mutex_unlock(&cpp_dev->mutex); - return; } + for (i = 0; i < queue_len; i++) { if (cpp_timer.data.processed_frame[i]) { processed_frame[i] = cpp_timer.data.processed_frame[i]; - pr_err("Fault on identity=0x%x, frame_id=%03d\n", + ifd = processed_frame[i]->input_buffer_info.fd; + ofd = processed_frame[i]-> + output_buffer_info[0].fd; + dfd = processed_frame[i]-> + duplicate_buffer_info.fd; + t0fd = processed_frame[i]-> + tnr_scratch_buffer_info[0].fd; + t1fd = processed_frame[i]-> + tnr_scratch_buffer_info[1].fd; + pr_err("Fault on identity=0x%x, frame_id=%03d\n", processed_frame[i]->identity, processed_frame[i]->frame_id); + pr_err("ifd %d ofd %d dfd %d t0fd %d t1fd %d\n", + ifd, ofd, dfd, t0fd, t1fd); msm_cpp_dump_addr(cpp_dev, processed_frame[i]); msm_cpp_dump_frame_cmd(processed_frame[i]); } } msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len); - msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8); - mutex_unlock(&cpp_dev->mutex); + cpp_dev->fault_status = CPP_IOMMU_FAULT_RECOVERED; + pr_err("fault recovery successful\n"); } + return; } static int cpp_init_mem(struct cpp_device *cpp_dev) @@ -842,7 +936,9 @@ static int cpp_init_mem(struct cpp_device *cpp_dev) cpp_dev->iommu_hdl = iommu_hdl; cam_smmu_reg_client_page_fault_handler( cpp_dev->iommu_hdl, - msm_cpp_iommu_fault_handler, cpp_dev); + msm_cpp_iommu_fault_handler, + msm_cpp_iommu_fault_reset_handler, + cpp_dev); return 0; } @@ -981,6 +1077,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) int rc = 0; uint32_t vbif_version; cpp_dev->turbo_vote = 0; + cpp_dev->fault_status = CPP_IOMMU_FAULT_NONE; rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, true); @@ -1115,7 +1212,7 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev) rc = msm_cpp_update_bandwidth_setting(cpp_dev, 0, 0); } cpp_dev->stream_cnt = 0; - + pr_info("cpp hw release done\n"); } static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) @@ -2536,6 +2633,16 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, return -EINVAL; } + if (cpp_dev->fault_status == CPP_IOMMU_FAULT_RECOVERED) { + pr_err("Error, page fault occurred %d\n", + cpp_dev->fault_status); + return -EINVAL; + } else if (cpp_dev->fault_status == CPP_IOMMU_FAULT_DETECTED) { + pr_err("drop frame, page fault occurred %d\n", + cpp_dev->fault_status); + return -EFAULT; + } + if (cpp_frame_msg[new_frame->msg_len - 1] != MSM_CPP_MSG_ID_TRAILER) { pr_err("Invalid frame message\n"); @@ -3523,6 +3630,7 @@ STREAM_BUFF_END: break; case VIDIOC_MSM_CPP_IOMMU_ATTACH: { if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { + int32_t stall_disable; struct msm_camera_smmu_attach_type cpp_attach_info; if (ioctl_ptr->len != @@ -3540,7 +3648,10 @@ STREAM_BUFF_END: } cpp_dev->security_mode = cpp_attach_info.attach; - + stall_disable = 1; + /* disable smmu stall on fault */ + cam_smmu_set_attr(cpp_dev->iommu_hdl, + DOMAIN_ATTR_CB_STALL_DISABLE, &stall_disable); if (cpp_dev->security_mode == SECURE_MODE) { rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_ATTACH_SEC_CPP); diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index a05448091e42..f2c544785f46 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -130,6 +130,12 @@ enum cpp_iommu_state { CPP_IOMMU_STATE_ATTACHED, }; +enum cpp_iommu_fault_state { + CPP_IOMMU_FAULT_NONE, + CPP_IOMMU_FAULT_DETECTED, + CPP_IOMMU_FAULT_RECOVERED, +}; + enum msm_queue { MSM_CAM_Q_CTRL, /* control command or control command status */ MSM_CAM_Q_VFE_EVT, /* adsp event */ @@ -287,6 +293,7 @@ struct cpp_device { struct msm_cpp_vbif_data *vbif_data; bool turbo_vote; struct cx_ipeak_client *cpp_cx_ipeak; + enum cpp_iommu_fault_state fault_status; }; int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev); diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h index 9120a4cc85ca..5dbcbd219732 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h @@ -100,6 +100,8 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_1_3ph = { {0x38, 0xFE}, {0x81c, 0x2}, {0x700, 0x80}, + {0x724, 0x04}, + {0x024, 0x04}, }; struct csiphy_settings_t csiphy_combo_mode_v5_0_1 = { diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h index 8591f0646080..98d0b933bba2 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h @@ -101,6 +101,8 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_3ph = { {0x38, 0xFE}, {0x81c, 0x6}, {0x700, 0x80}, + {0x724, 0x04}, + {0x024, 0x04}, }; struct csiphy_settings_t csiphy_combo_mode_v5_0 = { diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 214dd6f3406d..8d091320cbca 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -684,14 +684,20 @@ static int msm_csiphy_2phase_lane_config_v50( csiphybase + csiphy_dev->ctrl_reg-> csiphy_3ph_reg. mipi_csiphy_2ph_lnn_ctrl15.addr + offset); - if (mask == CLOCK_LANE) + if (mask == CLOCK_LANE) { msm_camera_io_w(csiphy_dev->ctrl_reg-> csiphy_3ph_reg. mipi_csiphy_2ph_lnck_ctrl0.data, csiphybase + csiphy_dev->ctrl_reg-> csiphy_3ph_reg. mipi_csiphy_2ph_lnck_ctrl0.addr); - else + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl9.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl9.addr); + } else { msm_camera_io_w(csiphy_dev->ctrl_reg-> csiphy_3ph_reg. mipi_csiphy_2ph_lnn_ctrl0.data, @@ -699,6 +705,14 @@ static int msm_csiphy_2phase_lane_config_v50( csiphy_3ph_reg. mipi_csiphy_2ph_lnn_ctrl0.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl9.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl9.addr + + offset); + } msm_camera_io_w(csiphy_dev->ctrl_reg-> csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg1.data, diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h index c1a9748e8af5..c33f183963cc 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h @@ -142,6 +142,8 @@ struct csiphy_reg_3ph_parms_t { struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl14; struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl7_cphy; struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl0; + struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl9; + struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl9; }; struct csiphy_ctrl_t { diff --git a/drivers/media/platform/msm/sde/Kconfig b/drivers/media/platform/msm/sde/Kconfig index 85f5f4257ddb..c0e73813ab06 100644 --- a/drivers/media/platform/msm/sde/Kconfig +++ b/drivers/media/platform/msm/sde/Kconfig @@ -15,3 +15,14 @@ config MSM_SDE_ROTATOR_EVTLOG_DEBUG features to: Dump rotator registers during driver errors, panic driver during fatal errors and enable some rotator driver logging into an internal buffer (this avoids logging overhead). + +config MSM_SDE_HDMI_CEC + bool "QTI SDE HDMI CEC Driver" + depends on DRM_SDE_HDMI + select MEDIA_CEC_SUPPORT + select MEDIA_CEC_EDID + ---help--- + The HDMI CEC driver provides support to enable HDMI CEC features + which allows various audiovisual products to communicate using HDMI + CEC links. CEC is a protocol defined in HDMI spec which consists of + both low-level and high-level protocol definition. diff --git a/drivers/media/platform/msm/sde/Makefile b/drivers/media/platform/msm/sde/Makefile index fe55d5044c3b..f39000a15993 100644 --- a/drivers/media/platform/msm/sde/Makefile +++ b/drivers/media/platform/msm/sde/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_MSM_SDE_ROTATOR) += rotator/ +obj-$(CONFIG_MSM_SDE_HDMI_CEC) += cec/ diff --git a/drivers/media/platform/msm/sde/cec/Makefile b/drivers/media/platform/msm/sde/cec/Makefile new file mode 100644 index 000000000000..2a9c30980512 --- /dev/null +++ b/drivers/media/platform/msm/sde/cec/Makefile @@ -0,0 +1,3 @@ +obj-y := \ + sde_hdmi_cec.o \ + sde_hdmi_cec_util.o diff --git a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c new file mode 100644 index 000000000000..0fed19a01d5b --- /dev/null +++ b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c @@ -0,0 +1,399 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/cec.h> +#include <media/cec.h> + +#include "sde_hdmi_cec_util.h" + +#define CEC_NAME "sde-hdmi-cec" + +/* CEC Register Definition */ +#define CEC_INTR_MASK (BIT(1) | BIT(3) | BIT(7)) +#define CEC_SUPPORTED_HW_VERSION 0x30000001 + +#define HDMI_CEC_WR_RANGE (0x000002DC) +#define HDMI_CEC_RD_RANGE (0x000002E0) +#define HDMI_VERSION (0x000002E4) +#define HDMI_CEC_CTRL (0x0000028C) +#define HDMI_CEC_WR_DATA (0x00000290) +#define HDMI_CEC_RETRANSMIT (0x00000294) +#define HDMI_CEC_STATUS (0x00000298) +#define HDMI_CEC_INT (0x0000029C) +#define HDMI_CEC_ADDR (0x000002A0) +#define HDMI_CEC_TIME (0x000002A4) +#define HDMI_CEC_REFTIMER (0x000002A8) +#define HDMI_CEC_RD_DATA (0x000002AC) +#define HDMI_CEC_RD_FILTER (0x000002B0) +#define HDMI_CEC_COMPL_CTL (0x00000360) +#define HDMI_CEC_RD_START_RANGE (0x00000364) +#define HDMI_CEC_RD_TOTAL_RANGE (0x00000368) +#define HDMI_CEC_RD_ERR_RESP_LO (0x0000036C) +#define HDMI_CEC_WR_CHECK_CONFIG (0x00000370) + +enum cec_irq_status { + CEC_IRQ_FRAME_WR_DONE = 1 << 0, + CEC_IRQ_FRAME_RD_DONE = 1 << 1, + CEC_IRQ_FRAME_ERROR = 1 << 2, +}; + +struct sde_hdmi_cec { + struct cec_adapter *adap; + struct device *dev; + struct cec_hw_resource hw_res; + int irq; + enum cec_irq_status irq_status; +}; + +static int sde_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct sde_hdmi_cec *cec = adap->priv; + struct cec_hw_resource *hw = &cec->hw_res; + u32 hdmi_hw_version, reg_val; + + pr_debug("adap enable %d\n", enable); + + if (enable) { + pm_runtime_get_sync(cec->dev); + + /* 19.2Mhz * 0.00005 us = 950 = 0x3B6 */ + CEC_REG_WRITE(hw, HDMI_CEC_REFTIMER, (0x3B6 & 0xFFF) | BIT(16)); + + hdmi_hw_version = CEC_REG_READ(hw, HDMI_VERSION); + if (hdmi_hw_version >= CEC_SUPPORTED_HW_VERSION) { + CEC_REG_WRITE(hw, HDMI_CEC_RD_RANGE, 0x30AB9888); + CEC_REG_WRITE(hw, HDMI_CEC_WR_RANGE, 0x888AA888); + + CEC_REG_WRITE(hw, HDMI_CEC_RD_START_RANGE, 0x88888888); + CEC_REG_WRITE(hw, HDMI_CEC_RD_TOTAL_RANGE, 0x99); + CEC_REG_WRITE(hw, HDMI_CEC_COMPL_CTL, 0xF); + CEC_REG_WRITE(hw, HDMI_CEC_WR_CHECK_CONFIG, 0x4); + } else { + pr_err("CEC version %d is not supported.\n", + hdmi_hw_version); + return -EPERM; + } + + CEC_REG_WRITE(hw, HDMI_CEC_RD_FILTER, BIT(0) | (0x7FF << 4)); + CEC_REG_WRITE(hw, HDMI_CEC_TIME, BIT(0) | ((7 * 0x30) << 7)); + + /* Enable CEC interrupts */ + CEC_REG_WRITE(hw, HDMI_CEC_INT, CEC_INTR_MASK); + + /* Enable Engine */ + CEC_REG_WRITE(hw, HDMI_CEC_CTRL, BIT(0)); + } else { + /* Disable Engine */ + CEC_REG_WRITE(hw, HDMI_CEC_CTRL, 0); + + /* Disable CEC interrupts */ + reg_val = CEC_REG_READ(hw, HDMI_CEC_INT); + CEC_REG_WRITE(hw, HDMI_CEC_INT, reg_val & ~CEC_INTR_MASK); + + pm_runtime_put(cec->dev); + } + + return 0; +} + +static int sde_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct sde_hdmi_cec *cec = adap->priv; + struct cec_hw_resource *hw = &cec->hw_res; + + pr_debug("set log addr %d\n", logical_addr); + + CEC_REG_WRITE(hw, HDMI_CEC_ADDR, logical_addr & 0xF); + + return 0; +} + +static int sde_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct sde_hdmi_cec *cec = adap->priv; + struct cec_hw_resource *hw = &cec->hw_res; + u32 frame_type; + int i; + u32 line_check_retry = 10; + + pr_debug("transmit msg [%d]->[%d]: len = %d, attampts=%d, signal_free_time=%d\n", + cec_msg_initiator(msg), cec_msg_destination(msg), msg->len, + attempts, signal_free_time); + + /* toggle cec in order to flush out bad hw state, if any */ + CEC_REG_WRITE(hw, HDMI_CEC_CTRL, 0); + CEC_REG_WRITE(hw, HDMI_CEC_CTRL, BIT(0)); + + /* make sure state is cleared */ + wmb(); + + CEC_REG_WRITE(hw, HDMI_CEC_RETRANSMIT, + ((attempts & 0xF) << 4) | BIT(0)); + + frame_type = cec_msg_is_broadcast(msg) ? BIT(0) : 0; + + /* header block */ + CEC_REG_WRITE(hw, HDMI_CEC_WR_DATA, + (((cec_msg_initiator(msg) << 4) | + cec_msg_destination(msg)) << 8) | frame_type); + + /* data block 0 : opcode */ + CEC_REG_WRITE(hw, HDMI_CEC_WR_DATA, + ((msg->len < 2 ? 0 : cec_msg_opcode(msg)) << 8) | frame_type); + + /* data block 1-14 : operand 0-13 */ + for (i = 2; i < msg->len; i++) + CEC_REG_WRITE(hw, HDMI_CEC_WR_DATA, + (msg->msg[i] << 8) | frame_type); + + /* check line status */ + while ((CEC_REG_READ(hw, HDMI_CEC_STATUS) & BIT(0)) && + line_check_retry) { + line_check_retry--; + pr_debug("CEC line is busy(%d)\n", line_check_retry); + schedule(); + } + + if (!line_check_retry && (CEC_REG_READ(hw, HDMI_CEC_STATUS) & BIT(0))) { + pr_err("CEC line is busy. Retry failed\n"); + return -EBUSY; + } + + /* start transmission */ + CEC_REG_WRITE(hw, HDMI_CEC_CTRL, BIT(0) | BIT(1) | + ((msg->len & 0x1F) << 4) | BIT(9)); + + return 0; +} + +static void sde_hdmi_cec_handle_rx_done(struct sde_hdmi_cec *cec) +{ + struct cec_hw_resource *hw = &cec->hw_res; + struct cec_msg msg = {}; + u32 data; + int i; + + pr_debug("rx done\n"); + + data = CEC_REG_READ(hw, HDMI_CEC_RD_DATA); + msg.len = (data & 0x1F00) >> 8; + if (msg.len < 1 || msg.len > CEC_MAX_MSG_SIZE) { + pr_err("invalid message size %d", msg.len); + return; + } + msg.msg[0] = data & 0xFF; + + for (i = 1; i < msg.len; i++) + msg.msg[i] = CEC_REG_READ(hw, HDMI_CEC_RD_DATA) & 0xFF; + + cec_received_msg(cec->adap, &msg); +} + +static void sde_hdmi_cec_handle_tx_done(struct sde_hdmi_cec *cec) +{ + pr_debug("tx done\n"); + cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); +} + +static void sde_hdmi_cec_handle_tx_error(struct sde_hdmi_cec *cec) +{ + struct cec_hw_resource *hw = &cec->hw_res; + u32 cec_status = CEC_REG_READ(hw, HDMI_CEC_STATUS); + + pr_debug("tx error status %x\n", cec_status); + + if ((cec_status & 0xF0) == 0x10) + cec_transmit_done(cec->adap, + CEC_TX_STATUS_NACK, 0, 1, 0, 0); + else if ((cec_status & 0xF0) == 0x30) + cec_transmit_done(cec->adap, + CEC_TX_STATUS_ARB_LOST, 1, 0, 0, 0); + else + cec_transmit_done(cec->adap, + CEC_TX_STATUS_ERROR | CEC_TX_STATUS_MAX_RETRIES, + 0, 0, 0, 1); +} + +static irqreturn_t sde_hdmi_cec_irq_handler_thread(int irq, void *priv) +{ + struct sde_hdmi_cec *cec = priv; + + pr_debug("irq thread: status %x\n", cec->irq_status); + + if (cec->irq_status & CEC_IRQ_FRAME_WR_DONE) + sde_hdmi_cec_handle_tx_done(cec); + + if (cec->irq_status & CEC_IRQ_FRAME_ERROR) + sde_hdmi_cec_handle_tx_error(cec); + + if (cec->irq_status & CEC_IRQ_FRAME_RD_DONE) + sde_hdmi_cec_handle_rx_done(cec); + + cec->irq_status = 0; + + return IRQ_HANDLED; +} + +static irqreturn_t sde_hdmi_cec_irq_handler(int irq, void *priv) +{ + struct sde_hdmi_cec *cec = priv; + struct cec_hw_resource *hw = &cec->hw_res; + u32 data = CEC_REG_READ(hw, HDMI_CEC_INT); + + CEC_REG_WRITE(hw, HDMI_CEC_INT, data); + + pr_debug("irq handler: %x\n", data); + + if ((data & BIT(0)) && (data & BIT(1))) + cec->irq_status |= CEC_IRQ_FRAME_WR_DONE; + + if ((data & BIT(2)) && (data & BIT(3))) + cec->irq_status |= CEC_IRQ_FRAME_ERROR; + + if ((data & BIT(6)) && (data & BIT(7))) + cec->irq_status |= CEC_IRQ_FRAME_RD_DONE; + + return cec->irq_status ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +static const struct cec_adap_ops sde_hdmi_cec_adap_ops = { + .adap_enable = sde_hdmi_cec_adap_enable, + .adap_log_addr = sde_hdmi_cec_adap_log_addr, + .adap_transmit = sde_hdmi_cec_adap_transmit, +}; + +static int sde_hdmi_cec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sde_hdmi_cec *cec; + int ret; + + cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); + if (!cec) + return -ENOMEM; + + cec->dev = dev; + + cec->irq = of_irq_get(dev->of_node, 0); + if (cec->irq < 0) { + pr_err("failed to get irq\n"); + return cec->irq; + } + + ret = devm_request_threaded_irq(dev, cec->irq, sde_hdmi_cec_irq_handler, + sde_hdmi_cec_irq_handler_thread, 0, + pdev->name, cec); + if (ret) + return ret; + + ret = sde_hdmi_cec_init_resource(pdev, &cec->hw_res); + if (ret) + return ret; + + cec->adap = cec_allocate_adapter(&sde_hdmi_cec_adap_ops, cec, + CEC_NAME, + CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | + CEC_CAP_PHYS_ADDR | CEC_CAP_TRANSMIT, 1); + ret = PTR_ERR_OR_ZERO(cec->adap); + if (ret) + return ret; + + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) { + cec_delete_adapter(cec->adap); + return ret; + } + + platform_set_drvdata(pdev, cec); + + pm_runtime_enable(dev); + + pr_debug("probe done\n"); + + return 0; +} + +static int sde_hdmi_cec_remove(struct platform_device *pdev) +{ + struct sde_hdmi_cec *cec = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + + cec_unregister_adapter(cec->adap); + + devm_free_irq(&pdev->dev, cec->irq, cec); + sde_hdmi_cec_deinit_resource(pdev, &cec->hw_res); + + pr_debug("remove done\n"); + + return 0; +} + +static int __maybe_unused sde_hdmi_cec_runtime_suspend(struct device *dev) +{ + struct sde_hdmi_cec *cec = dev_get_drvdata(dev); + struct cec_hw_resource *hw = &cec->hw_res; + + pr_debug("runtime suspend\n"); + + return sde_hdmi_cec_enable_power(hw, false); +} + +static int __maybe_unused sde_hdmi_cec_runtime_resume(struct device *dev) +{ + struct sde_hdmi_cec *cec = dev_get_drvdata(dev); + struct cec_hw_resource *hw = &cec->hw_res; + + pr_debug("runtime resume\n"); + + return sde_hdmi_cec_enable_power(hw, true); +} + +static const struct dev_pm_ops sde_hdmi_cec_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(sde_hdmi_cec_runtime_suspend, + sde_hdmi_cec_runtime_resume, NULL) +}; + +static const struct of_device_id sde_hdmi_cec_match[] = { + { + .compatible = "qcom,hdmi-cec", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, sde_hdmi_cec_match); + +static struct platform_driver sde_hdmi_cec_pdrv = { + .probe = sde_hdmi_cec_probe, + .remove = sde_hdmi_cec_remove, + .driver = { + .name = CEC_NAME, + .of_match_table = sde_hdmi_cec_match, + .pm = &sde_hdmi_cec_pm_ops, + }, +}; + +module_platform_driver(sde_hdmi_cec_pdrv); +MODULE_DESCRIPTION("MSM SDE HDMI CEC driver"); diff --git a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.c b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.c new file mode 100644 index 000000000000..323e0805c886 --- /dev/null +++ b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.c @@ -0,0 +1,743 @@ +/* Copyright (c) 2012, 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> + +#include "sde_hdmi_cec_util.h" + +void sde_hdmi_cec_reg_w(struct cec_io_data *io, + u32 offset, u32 value, bool debug) +{ + u32 in_val; + + if (!io || !io->base) { + pr_err("invalid input\n"); + return; + } + + if (offset > io->len) { + pr_err("offset out of range\n"); + return; + } + + writel_relaxed(value, io->base + offset); + if (debug) { + in_val = readl_relaxed(io->base + offset); + pr_debug("[%08x] => %08x [%08x]\n", + (u32)(unsigned long)(io->base + offset), + value, in_val); + } +} + +u32 sde_hdmi_cec_reg_r(struct cec_io_data *io, u32 offset, bool debug) +{ + u32 value; + + if (!io || !io->base) { + pr_err("invalid input\n"); + return -EINVAL; + } + + if (offset > io->len) { + pr_err("offset out of range\n"); + return -EINVAL; + } + + value = readl_relaxed(io->base + offset); + if (debug) + pr_debug("[%08x] <= %08x\n", + (u32)(unsigned long)(io->base + offset), value); + + return value; +} + +void sde_hdmi_cec_reg_dump(void __iomem *base, u32 length, const char *prefix, + bool debug) +{ + if (debug) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4, + __io_virt(base), length, false); +} + +static int sde_hdmi_cec_config_vreg(struct device *dev, + struct cec_vreg *in_vreg, int num_vreg, bool config) +{ + int i = 0, rc = 0; + struct cec_vreg *curr_vreg = NULL; + enum cec_vreg_type type; + + if (!in_vreg || !num_vreg) + return rc; + + if (config) { + for (i = 0; i < num_vreg; i++) { + curr_vreg = &in_vreg[i]; + curr_vreg->vreg = regulator_get(dev, + curr_vreg->vreg_name); + rc = PTR_RET(curr_vreg->vreg); + if (rc) { + pr_err("%s get failed. rc=%d\n", + curr_vreg->vreg_name, rc); + curr_vreg->vreg = NULL; + goto vreg_get_fail; + } + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? CEC_REG_LDO : CEC_REG_VS; + if (type == CEC_REG_LDO) { + rc = regulator_set_voltage( + curr_vreg->vreg, + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + pr_err("%s set vltg fail\n", + curr_vreg->vreg_name); + goto vreg_set_voltage_fail; + } + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + if (curr_vreg->vreg) { + type = (regulator_count_voltages( + curr_vreg->vreg) > 0) + ? CEC_REG_LDO : CEC_REG_VS; + if (type == CEC_REG_LDO) { + regulator_set_voltage(curr_vreg->vreg, + 0, curr_vreg->max_voltage); + } + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (type == CEC_REG_LDO) + regulator_set_load(curr_vreg->vreg, 0); + +vreg_set_voltage_fail: + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? CEC_REG_LDO : CEC_REG_VS; + goto vreg_unconfig; + } + return rc; +} + +static int sde_hdmi_cec_enable_vreg(struct cec_hw_resource *hw, int enable) +{ + int i = 0, rc = 0; + bool need_sleep; + struct cec_vreg *in_vreg = hw->vreg_config; + int num_vreg = hw->num_vreg; + + if (enable) { + for (i = 0; i < num_vreg; i++) { + rc = PTR_RET(in_vreg[i].vreg); + if (rc) { + pr_err("%s regulator error. rc=%d\n", + in_vreg[i].vreg_name, rc); + goto vreg_set_opt_mode_fail; + } + need_sleep = !regulator_is_enabled(in_vreg[i].vreg); + if (in_vreg[i].pre_on_sleep && need_sleep) + usleep_range(in_vreg[i].pre_on_sleep * 1000, + in_vreg[i].pre_on_sleep * 1000); + rc = regulator_set_load(in_vreg[i].vreg, + in_vreg[i].enable_load); + if (rc < 0) { + pr_err("%s set opt m fail\n", + in_vreg[i].vreg_name); + goto vreg_set_opt_mode_fail; + } + rc = regulator_enable(in_vreg[i].vreg); + if (in_vreg[i].post_on_sleep && need_sleep) + usleep_range(in_vreg[i].post_on_sleep * 1000, + in_vreg[i].post_on_sleep * 1000); + if (rc < 0) { + pr_err("%s enable failed\n", + in_vreg[i].vreg_name); + goto disable_vreg; + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + in_vreg[i].pre_off_sleep * 1000); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + in_vreg[i].post_off_sleep * 1000); + } + } + return rc; + +disable_vreg: + regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); + +vreg_set_opt_mode_fail: + for (i--; i >= 0; i--) { + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + in_vreg[i].pre_off_sleep * 1000); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + in_vreg[i].post_off_sleep * 1000); + } + + return rc; +} + +static void sde_hdmi_cec_put_clk(struct cec_clk *clk_arry, int num_clk) +{ + int i; + + for (i = num_clk - 1; i >= 0; i--) { + if (clk_arry[i].clk) + clk_put(clk_arry[i].clk); + clk_arry[i].clk = NULL; + } +} + +static int sde_hdmi_cec_get_clk(struct device *dev, + struct cec_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + for (i = 0; i < num_clk; i++) { + clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name); + rc = PTR_RET(clk_arry[i].clk); + if (rc) { + pr_err("'%s' get failed. rc=%d\n", + clk_arry[i].clk_name, rc); + goto error; + } + } + + return rc; + +error: + sde_hdmi_cec_put_clk(clk_arry, num_clk); + + return rc; +} + +static int sde_hdmi_cec_enable_clk(struct cec_hw_resource *hw, int enable) +{ + int i, rc = 0; + struct cec_clk *clk_arry = hw->clk_config; + int num_clk = hw->num_clk; + + if (enable) { + for (i = 0; i < num_clk; i++) { + pr_debug("enable %s\n", clk_arry[i].clk_name); + if (clk_arry[i].clk) { + rc = clk_prepare_enable(clk_arry[i].clk); + if (rc) + pr_err("%s enable fail. rc=%d\n", + clk_arry[i].clk_name, rc); + } else { + pr_err("%s is not available\n", + clk_arry[i].clk_name); + rc = -EPERM; + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + pr_debug("disable %s\n", clk_arry[i].clk_name); + + if (clk_arry[i].clk) + clk_disable_unprepare(clk_arry[i].clk); + else + pr_err("%s is not available\n", + clk_arry[i].clk_name); + } + } + + return rc; +} + +static int sde_hdmi_cec_pinctrl_enable(struct cec_hw_resource *hw, + bool enable) +{ + struct pinctrl_state *pin_state = NULL; + int rc = 0; + + if (!hw) { + pr_err("invalid input param hw:%pK\n", hw); + return -EINVAL; + } + + pr_debug("set cec pinctrl state %d\n", enable); + + pin_state = enable ? hw->pin_res.state_active : hw->pin_res.state_sleep; + + if (!IS_ERR_OR_NULL(hw->pin_res.pinctrl)) + rc = pinctrl_select_state(hw->pin_res.pinctrl, + pin_state); + else + pr_err("pinstate not found\n"); + + return rc; +} + +static void sde_hdmi_cec_put_dt_clock(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return; + } + + if (hw->clk_config) { + sde_hdmi_cec_put_clk(hw->clk_config, hw->num_clk); + devm_kfree(&pdev->dev, hw->clk_config); + hw->clk_config = NULL; + } + hw->num_clk = 0; + + pr_debug("put dt clock\n"); +} + +static int sde_hdmi_cec_get_dt_clock(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + int i = 0; + int num_clk = 0; + const char *clock_name; + int rc = 0; + + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return -EINVAL; + } + + hw->num_clk = 0; + num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names"); + if (num_clk <= 0) { + pr_debug("clocks are not defined\n"); + return 0; + } + + hw->num_clk = num_clk; + hw->clk_config = devm_kzalloc(&pdev->dev, + sizeof(struct cec_clk) * num_clk, GFP_KERNEL); + if (!hw->clk_config) { + hw->num_clk = 0; + return -ENOMEM; + } + + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(pdev->dev.of_node, "clock-names", + i, &clock_name); + strlcpy(hw->clk_config[i].clk_name, clock_name, + sizeof(hw->clk_config[i].clk_name)); + } + + rc = sde_hdmi_cec_get_clk(&pdev->dev, hw->clk_config, hw->num_clk); + if (rc) { + sde_hdmi_cec_put_dt_clock(pdev, hw); + return rc; + } + + pr_debug("get dt clock\n"); + + return 0; +} + +static int sde_hdmi_cec_get_dt_supply(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + int i = 0, rc = 0; + u32 tmp = 0; + struct device_node *of_node = NULL, *supply_root_node = NULL; + struct device_node *supply_node = NULL; + + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return -EINVAL; + } + + of_node = pdev->dev.of_node; + + hw->num_vreg = 0; + supply_root_node = of_get_child_by_name(of_node, + "qcom,platform-supply-entries"); + if (!supply_root_node) { + pr_debug("no supply entry present\n"); + return rc; + } + + hw->num_vreg = of_get_available_child_count(supply_root_node); + if (hw->num_vreg == 0) { + pr_debug("no vreg present\n"); + return rc; + } + + pr_debug("vreg found. count=%d\n", hw->num_vreg); + hw->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct cec_vreg) * + hw->num_vreg, GFP_KERNEL); + if (!hw->vreg_config) { + rc = -ENOMEM; + return rc; + } + + for_each_available_child_of_node(supply_root_node, supply_node) { + const char *st = NULL; + + rc = of_property_read_string(supply_node, + "qcom,supply-name", &st); + if (rc) { + pr_err("error reading name. rc=%d\n", rc); + goto error; + } + + strlcpy(hw->vreg_config[i].vreg_name, st, + sizeof(hw->vreg_config[i].vreg_name)); + + rc = of_property_read_u32(supply_node, + "qcom,supply-min-voltage", &tmp); + if (rc) { + pr_err("error reading min volt. rc=%d\n", rc); + goto error; + } + hw->vreg_config[i].min_voltage = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-max-voltage", &tmp); + if (rc) { + pr_err("error reading max volt. rc=%d\n", rc); + goto error; + } + hw->vreg_config[i].max_voltage = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-enable-load", &tmp); + if (rc) { + pr_err("error reading enable load. rc=%d\n", rc); + goto error; + } + hw->vreg_config[i].enable_load = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-disable-load", &tmp); + if (rc) { + pr_err("error reading disable load. rc=%d\n", rc); + goto error; + } + hw->vreg_config[i].disable_load = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-on-sleep", &tmp); + if (rc) + pr_debug("no supply pre sleep value. rc=%d\n", rc); + + hw->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-off-sleep", &tmp); + if (rc) + pr_debug("no supply pre sleep value. rc=%d\n", rc); + + hw->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-on-sleep", &tmp); + if (rc) + pr_debug("no supply post sleep value. rc=%d\n", rc); + + hw->vreg_config[i].post_on_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-off-sleep", &tmp); + if (rc) + pr_debug("no supply post sleep value. rc=%d\n", rc); + + hw->vreg_config[i].post_off_sleep = (!rc ? tmp : 0); + + pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n", + hw->vreg_config[i].vreg_name, + hw->vreg_config[i].min_voltage, + hw->vreg_config[i].max_voltage, + hw->vreg_config[i].enable_load, + hw->vreg_config[i].disable_load, + hw->vreg_config[i].pre_on_sleep, + hw->vreg_config[i].post_on_sleep, + hw->vreg_config[i].pre_off_sleep, + hw->vreg_config[i].post_off_sleep); + ++i; + + rc = 0; + } + + rc = sde_hdmi_cec_config_vreg(&pdev->dev, + hw->vreg_config, hw->num_vreg, true); + if (rc) + goto error; + + pr_debug("get dt supply\n"); + + return rc; + +error: + if (hw->vreg_config) { + devm_kfree(&pdev->dev, hw->vreg_config); + hw->vreg_config = NULL; + hw->num_vreg = 0; + } + + return rc; +} + +static void sde_hdmi_cec_put_dt_supply(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return; + } + + sde_hdmi_cec_config_vreg(&pdev->dev, + hw->vreg_config, hw->num_vreg, false); + + if (hw->vreg_config) { + devm_kfree(&pdev->dev, hw->vreg_config); + hw->vreg_config = NULL; + } + hw->num_vreg = 0; + + pr_debug("put dt supply\n"); +} + +static int sde_hdmi_cec_get_dt_pinres(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return -EINVAL; + } + + hw->pin_res.pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(hw->pin_res.pinctrl)) { + pr_err("failed to get pinctrl\n"); + return PTR_ERR(hw->pin_res.pinctrl); + } + + hw->pin_res.state_active = + pinctrl_lookup_state(hw->pin_res.pinctrl, "cec_active"); + if (IS_ERR_OR_NULL(hw->pin_res.state_active)) + pr_debug("cannot get active pinstate\n"); + + hw->pin_res.state_sleep = + pinctrl_lookup_state(hw->pin_res.pinctrl, "cec_sleep"); + if (IS_ERR_OR_NULL(hw->pin_res.state_sleep)) + pr_debug("cannot get sleep pinstate\n"); + + pr_debug("get dt pinres data\n"); + + return 0; +} + +static void sde_hdmi_cec_put_dt_pinres(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return; + } + + if (!IS_ERR_OR_NULL(hw->pin_res.pinctrl)) + devm_pinctrl_put(hw->pin_res.pinctrl); +} + +static void sde_hdmi_cec_deinit_power(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return; + } + + sde_hdmi_cec_put_dt_supply(pdev, hw); + sde_hdmi_cec_put_dt_clock(pdev, hw); + sde_hdmi_cec_put_dt_pinres(pdev, hw); + + pr_debug("put dt power data\n"); +} + +static int sde_hdmi_cec_init_power(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + int rc = 0; + + if (!pdev || !hw) { + pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw); + return -EINVAL; + } + + /* VREG */ + rc = sde_hdmi_cec_get_dt_supply(pdev, hw); + if (rc) { + pr_err("get_dt_supply failed. rc=%d\n", rc); + goto error; + } + + /* Clock */ + rc = sde_hdmi_cec_get_dt_clock(pdev, hw); + if (rc) { + pr_err("get_dt_clock failed. rc=%d\n", rc); + goto error; + } + + /* Pinctrl */ + rc = sde_hdmi_cec_get_dt_pinres(pdev, hw); + if (rc) { + pr_err("get_dt_pinres failed. rc=%d\n", rc); + goto error; + } + + pr_debug("get dt power data\n"); + + return rc; + +error: + sde_hdmi_cec_deinit_power(pdev, hw); + return rc; +} + +static int sde_hdmi_cec_init_io(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + struct resource *res = NULL; + struct cec_io_data *io_data = NULL; + const char *reg_name; + + if (!pdev || !hw) { + pr_err("invalid input\n"); + return -EINVAL; + } + + if (of_property_read_string(pdev->dev.of_node, "reg-names", + ®_name)) { + pr_err("cec reg not defined\n"); + return -ENODEV; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name); + if (!res) { + pr_err("%s get_res_byname failed\n", reg_name); + return -ENODEV; + } + + io_data = &hw->io_res; + io_data->len = (u32)resource_size(res); + io_data->base = ioremap(res->start, io_data->len); + if (!io_data->base) { + pr_err("%s ioremap failed\n", reg_name); + return -EIO; + } + + return 0; +} + +static void sde_hdmi_cec_deinit_io(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + struct cec_io_data *io_data = NULL; + + if (!pdev || !hw) { + pr_err("invalid input\n"); + return; + } + + io_data = &hw->io_res; + + if (io_data->base) { + iounmap(io_data->base); + io_data->base = NULL; + } + io_data->len = 0; +} + +int sde_hdmi_cec_init_resource(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + int rc = 0; + + /* power */ + rc = sde_hdmi_cec_init_power(pdev, hw); + if (rc) + return rc; + + /* io */ + rc = sde_hdmi_cec_init_io(pdev, hw); + if (rc) + goto io_error; + + pr_debug("cec init resource\n"); + + return rc; + +io_error: + sde_hdmi_cec_deinit_power(pdev, hw); + return rc; +} + +void sde_hdmi_cec_deinit_resource(struct platform_device *pdev, + struct cec_hw_resource *hw) +{ + sde_hdmi_cec_deinit_power(pdev, hw); + sde_hdmi_cec_deinit_io(pdev, hw); + + pr_debug("cec deinit resource\n"); +} + +int sde_hdmi_cec_enable_power(struct cec_hw_resource *hw, bool enable) +{ + int rc = 0; + + rc = sde_hdmi_cec_enable_vreg(hw, enable); + if (rc) + return rc; + + rc = sde_hdmi_cec_pinctrl_enable(hw, enable); + if (rc) + return rc; + + rc = sde_hdmi_cec_enable_clk(hw, enable); + if (rc) + return rc; + + pr_debug("cec power enable = %d\n", enable); + + return rc; +} diff --git a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.h b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.h new file mode 100644 index 000000000000..f92c43ea3288 --- /dev/null +++ b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2012, 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 + * 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 __SDE_HDMI_CEC_UTIL_H__ +#define __SDE_HDMI_CEC_UTIL_H__ + +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/pinctrl/consumer.h> +#include <linux/types.h> + +#ifdef DEBUG +#define CEC_REG_WRITE(hw, off, val) \ + sde_hdmi_cec_reg_w(&(hw)->io_res, (off), (val), true) +#define CEC_REG_READ(hw, off) \ + sde_hdmi_cec_reg_r(&(hw)->io_res, (off), true) +#else +#define CEC_REG_WRITE(hw, off, val) \ + sde_hdmi_cec_reg_w(&(hw)->io_res, (off), (val), false) +#define CEC_REG_READ(hw, off) \ + sde_hdmi_cec_reg_r(&(hw)->io_res, (off), false) +#endif + +struct cec_io_data { + u32 len; + void __iomem *base; +}; + +enum cec_vreg_type { + CEC_REG_LDO, + CEC_REG_VS, +}; + +struct cec_vreg { + struct regulator *vreg; /* vreg handle */ + char vreg_name[32]; + int min_voltage; + int max_voltage; + int enable_load; + int disable_load; + int pre_on_sleep; + int post_on_sleep; + int pre_off_sleep; + int post_off_sleep; +}; + +struct cec_clk { + struct clk *clk; /* clk handle */ + char clk_name[32]; +}; + +struct cec_pin_res { + struct pinctrl *pinctrl; + struct pinctrl_state *state_active; + struct pinctrl_state *state_sleep; +}; + +struct cec_hw_resource { + /* power */ + unsigned num_vreg; + struct cec_vreg *vreg_config; + unsigned num_clk; + struct cec_clk *clk_config; + struct cec_pin_res pin_res; + + /* io */ + struct cec_io_data io_res; +}; + +void sde_hdmi_cec_reg_w(struct cec_io_data *io, + u32 offset, u32 value, bool debug); +u32 sde_hdmi_cec_reg_r(struct cec_io_data *io, u32 offset, bool debug); +void sde_hdmi_cec_reg_dump(void __iomem *base, u32 length, const char *prefix, + bool debug); + +int sde_hdmi_cec_init_resource(struct platform_device *pdev, + struct cec_hw_resource *hw); +void sde_hdmi_cec_deinit_resource(struct platform_device *pdev, + struct cec_hw_resource *hw); +int sde_hdmi_cec_enable_power(struct cec_hw_resource *hw, bool enable); + +#endif /* __SDE_HDMI_CEC_UTIL_H__ */ + diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c index 58cb160f118e..9273c0e95230 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c @@ -486,11 +486,8 @@ int sde_smmu_secure_ctrl(int enable) mdata->iommu_attached = true; } else { rc = sde_smmu_detach(mdata); - /* - * keep iommu_attached equal to true, - * so that driver does not attemp to attach - * while in secure state - */ + if (!rc) + mdata->iommu_attached = false; } mutex_unlock(&sde_smmu_ref_cnt_lock); diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 953780e3c220..8ac84ece2c2a 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -872,7 +872,7 @@ int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "Core %pK in bad state, ignoring prepare buf\n", inst->core); - goto exit; + return -EINVAL; } switch (b->type) { @@ -925,7 +925,7 @@ int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type); break; } -exit: + return rc; } @@ -1767,6 +1767,7 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count) struct msm_vidc_inst *inst; int rc = 0; struct hfi_device *hdev; + struct vb2_buffer *vb; struct vb2_buf_entry *temp, *next; if (!q || !q->drv_priv) { dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q); @@ -1777,6 +1778,12 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count) dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); return -EINVAL; } + + if (inst->state == MSM_VIDC_CORE_INVALID || + inst->core->state == VIDC_CORE_INVALID || + inst->core->state == VIDC_CORE_UNINIT) + return -EINVAL; + hdev = inst->core->device; dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n", q->type, inst); @@ -1791,8 +1798,7 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count) break; default: dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type); - rc = -EINVAL; - goto stream_start_failed; + return -EINVAL; } if (rc) { dprintk(VIDC_ERR, @@ -1811,12 +1817,15 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count) stream_start_failed: if (rc) { + list_for_each_entry(vb, &q->queued_list, queued_entry) { + if (vb->type == q->type && + vb->state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED); + } mutex_lock(&inst->pendingq.lock); - list_for_each_entry_safe(temp, next, &inst->pendingq.list, - list) { + list_for_each_entry_safe(temp, next, + &inst->pendingq.list, list) { if (temp->vb->type == q->type) { - vb2_buffer_done(temp->vb, - VB2_BUF_STATE_QUEUED); list_del(&temp->list); kfree(temp); } diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 30726354164b..cdf91dd80ed3 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -54,12 +54,12 @@ * 3x3 transformation matrix coefficients in s4.9 fixed point format */ static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = { - 470, 8170, 8148, 0, 490, 50, 0, 34, 483 + 440, 8140, 8098, 0, 460, 52, 0, 34, 463 }; /* offset coefficients in s9 fixed point format */ static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = { - 34, 0, 4 + 53, 0, 4 }; /* clamping value for Y/U/V([min,max] for Y/U/V) */ @@ -1897,12 +1897,20 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count) { struct msm_vidc_inst *inst; int rc = 0; + struct vb2_buffer *vb; struct vb2_buf_entry *temp, *next; + if (!q || !q->drv_priv) { dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q); return -EINVAL; } inst = q->drv_priv; + + if (inst->state == MSM_VIDC_CORE_INVALID || + inst->core->state == VIDC_CORE_INVALID || + inst->core->state == VIDC_CORE_UNINIT) + return -EINVAL; + dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n", q->type, inst); switch (q->type) { @@ -1916,8 +1924,7 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count) break; default: dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type); - rc = -EINVAL; - goto stream_start_failed; + return -EINVAL; } if (rc) { dprintk(VIDC_ERR, @@ -1936,12 +1943,15 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count) stream_start_failed: if (rc) { + list_for_each_entry(vb, &q->queued_list, queued_entry) { + if (vb->type == q->type && + vb->state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED); + } mutex_lock(&inst->pendingq.lock); - list_for_each_entry_safe(temp, next, &inst->pendingq.list, - list) { + list_for_each_entry_safe(temp, next, + &inst->pendingq.list, list) { if (temp->vb->type == q->type) { - vb2_buffer_done(temp->vb, - VB2_BUF_STATE_QUEUED); list_del(&temp->list); kfree(temp); } @@ -4425,7 +4435,7 @@ int msm_venc_prepare_buf(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "Core %pK in bad state, ignoring prepare buf\n", inst->core); - goto exit; + return -EINVAL; } switch (b->type) { @@ -4473,7 +4483,7 @@ int msm_venc_prepare_buf(struct msm_vidc_inst *inst, "Buffer type not recognized: %d\n", b->type); break; } -exit: + return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 1ff2ca4cb91f..f09c28fed6d2 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1362,7 +1362,6 @@ static void cleanup_instance(struct msm_vidc_inst *inst) int msm_vidc_destroy(struct msm_vidc_inst *inst) { struct msm_vidc_core *core; - int i = 0; if (!inst || !inst->core) return -EINVAL; @@ -1386,9 +1385,6 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst) v4l2_fh_del(&inst->event_handler); v4l2_fh_exit(&inst->event_handler); - for (i = 0; i < MAX_PORT_NUM; i++) - vb2_queue_release(&inst->bufq[i].vb2_bufq); - mutex_destroy(&inst->sync_lock); mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); @@ -1412,7 +1408,7 @@ int msm_vidc_close(void *instance) struct msm_vidc_inst *inst = instance; struct buffer_info *bi, *dummy; - int rc = 0; + int rc = 0, i = 0; if (!inst || !inst->core) return -EINVAL; @@ -1449,6 +1445,12 @@ int msm_vidc_close(void *instance) msm_comm_session_clean(inst); msm_smem_delete_client(inst->mem_client); + for (i = 0; i < MAX_PORT_NUM; i++) { + mutex_lock(&inst->bufq[i].lock); + vb2_queue_release(&inst->bufq[i].vb2_bufq); + mutex_unlock(&inst->bufq[i].lock); + } + kref_put(&inst->kref, close_helper); return 0; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index a9b367d6fe93..885e61f8bf01 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -12,6 +12,7 @@ */ #define CREATE_TRACE_POINTS +#define MAX_SSR_STRING_LEN 10 #include "msm_vidc_debug.h" #include "vidc_hfi_api.h" @@ -136,17 +137,33 @@ static int trigger_ssr_open(struct inode *inode, struct file *file) static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { - u32 ssr_trigger_val; - int rc; + unsigned long ssr_trigger_val = 0; + int rc = 0; struct msm_vidc_core *core = filp->private_data; - rc = sscanf(buf, "%d", &ssr_trigger_val); - if (rc < 0) { + size_t size = MAX_SSR_STRING_LEN; + char kbuf[MAX_SSR_STRING_LEN + 1] = {0}; + + if (!count) + goto exit; + + if (count < size) + size = count; + + if (copy_from_user(kbuf, buf, size)) { + dprintk(VIDC_WARN, "%s User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoul(kbuf, 0, &ssr_trigger_val); + if (rc) { dprintk(VIDC_WARN, "returning error err %d\n", rc); rc = -EINVAL; } else { msm_vidc_trigger_ssr(core, ssr_trigger_val); rc = count; } +exit: return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index 4cc977e568ee..59783dc87e5b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1137,8 +1137,11 @@ int read_platform_resources_from_dt( "qcom,max-secure-instances", &res->max_secure_inst_count); - res->cx_ipeak_context = cx_ipeak_register(pdev->dev.of_node, - "qcom,cx-ipeak-data"); + if (of_find_property(pdev->dev.of_node, + "qcom,cx-ipeak-data", NULL)) { + res->cx_ipeak_context = cx_ipeak_register( + pdev->dev.of_node, "qcom,cx-ipeak-data"); + } if (IS_ERR(res->cx_ipeak_context)) { rc = PTR_ERR(res->cx_ipeak_context); diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c index 856179b96f37..43c6b0651064 100644 --- a/drivers/mfd/wcd9xxx-irq.c +++ b/drivers/mfd/wcd9xxx-irq.c @@ -290,7 +290,7 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data) static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1); struct wcd9xxx_core_resource *wcd9xxx_res = data; int num_irq_regs = wcd9xxx_res->num_irq_regs; - u8 status[num_irq_regs], status1[num_irq_regs]; + u8 status[4], status1[4] = {0}, unmask_status[4] = {0}; if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) { dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n"); @@ -314,6 +314,23 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data) "Failed to read interrupt status: %d\n", ret); goto err_disable_irq; } + /* + * If status is 0 return without clearing. + * status contains: HW status - masked interrupts + * status1 contains: unhandled interrupts - masked interrupts + * unmasked_status contains: unhandled interrupts + */ + if (unlikely(!memcmp(status, status1, sizeof(status)))) { + pr_debug("%s: status is 0\n", __func__); + wcd9xxx_unlock_sleep(wcd9xxx_res); + return IRQ_HANDLED; + } + + /* + * Copy status to unmask_status before masking, otherwise SW may miss + * to clear masked interrupt in corner case. + */ + memcpy(unmask_status, status, sizeof(unmask_status)); /* Apply masking */ for (i = 0; i < num_irq_regs; i++) @@ -337,6 +354,8 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data) wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata); status1[BIT_BYTE(irqdata.intr_num)] &= ~BYTE_BIT_MASK(irqdata.intr_num); + unmask_status[BIT_BYTE(irqdata.intr_num)] &= + ~BYTE_BIT_MASK(irqdata.intr_num); } } @@ -358,12 +377,13 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data) linebuf, sizeof(linebuf), false); pr_warn("%s: status1 : %s\n", __func__, linebuf); } - - memset(status, 0xff, num_irq_regs); - + /* + * unmask_status contains unhandled interrupts, hence clear all + * unhandled interrupts. + */ ret = regmap_bulk_write(wcd9xxx_res->wcd_core_regmap, wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE], - status, num_irq_regs); + unmask_status, num_irq_regs); if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) regmap_write(wcd9xxx_res->wcd_core_regmap, wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT], diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c index e3f23caac5b8..5419bd1655c1 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c @@ -140,7 +140,8 @@ static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr, list) { if (addr >= region_elt->vaddr && addr < region_elt->vaddr + region_elt->len && - addr + len <= region_elt->vaddr + region_elt->len) + addr + len <= region_elt->vaddr + region_elt->len && + addr + len > addr) pr_err("\t%s[%pK]:%pK, %ld --> %pK\n", __func__, audio, region_elt->vaddr, diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 015dc3c1493f..b4faf8212348 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -80,6 +80,8 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil) wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); wil_unmask_irq(wil); + wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend); + /* Send WMI resume request to the device */ rc = wmi_resume(wil); if (rc) { @@ -96,8 +98,6 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil) } } - wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend); - out: if (rc) set_bit(wil_status_suspended, wil->status); @@ -175,38 +175,35 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) /* Disable device reset on PERST */ wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); - /* Save the current bus request to return to the same in resume */ - wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps; - wil6210_bus_request(wil, 0); - if (wil->platform_ops.suspend) { rc = wil->platform_ops.suspend(wil->platform_handle, true); if (rc) { wil_err(wil, "platform device failed to suspend (%d)\n", rc); wil->suspend_stats.failed_suspends++; - clear_bit(wil_status_suspending, wil->status); - rc = wil_resume_keep_radio_on(wil); - /* if resume succeeded, reject the suspend */ - if (!rc) - rc = -EBUSY; - goto out; + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_unmask_irq(wil); + goto resume_after_fail; } } + /* Save the current bus request to return to the same in resume */ + wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps; + wil6210_bus_request(wil, 0); + set_bit(wil_status_suspended, wil->status); clear_bit(wil_status_suspending, wil->status); return rc; resume_after_fail: + set_bit(wil_status_resuming, wil->status); clear_bit(wil_status_suspending, wil->status); rc = wmi_resume(wil); /* if resume succeeded, reject the suspend */ if (!rc) rc = -EBUSY; -out: return rc; reject_suspend: diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index acd2397ded94..14a13007a973 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ARM_PMU) += arm_pmu.o +obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_armv8.o diff --git a/arch/arm64/kernel/perf_event.c b/drivers/perf/perf_event_armv8.c index eccd8c49ad69..443538a16aea 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/drivers/perf/perf_event_armv8.c @@ -20,6 +20,7 @@ */ #include <asm/irq_regs.h> +#include <asm/perf_event.h> #include <linux/of.h> #include <linux/perf/arm_pmu.h> @@ -239,16 +240,14 @@ struct arm_pmu_and_idle_nb { static inline u32 armv8pmu_pmcr_read(void) { - u32 val; - asm volatile("mrs %0, pmcr_el0" : "=r" (val)); - return val; + return armv8pmu_pmcr_read_reg(); } inline void armv8pmu_pmcr_write(u32 val) { val &= ARMV8_PMCR_MASK; isb(); - asm volatile("msr pmcr_el0, %0" :: "r" (val)); + armv8pmu_pmcr_write_reg(val); } static inline int armv8pmu_has_overflowed(u32 pmovsr) @@ -270,7 +269,7 @@ static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx) static inline int armv8pmu_select_counter(int idx) { u32 counter = ARMV8_IDX_TO_COUNTER(idx); - asm volatile("msr pmselr_el0, %0" :: "r" (counter)); + armv8pmu_pmselr_write_reg(counter); isb(); return idx; @@ -287,9 +286,9 @@ static inline u32 armv8pmu_read_counter(struct perf_event *event) pr_err("CPU%u reading wrong counter %d\n", smp_processor_id(), idx); else if (idx == ARMV8_IDX_CYCLE_COUNTER) - asm volatile("mrs %0, pmccntr_el0" : "=r" (value)); + value = armv8pmu_pmccntr_read_reg(); else if (armv8pmu_select_counter(idx) == idx) - asm volatile("mrs %0, pmxevcntr_el0" : "=r" (value)); + value = armv8pmu_pmxevcntr_read_reg(); return value; } @@ -304,47 +303,47 @@ static inline void armv8pmu_write_counter(struct perf_event *event, u32 value) pr_err("CPU%u writing wrong counter %d\n", smp_processor_id(), idx); else if (idx == ARMV8_IDX_CYCLE_COUNTER) - asm volatile("msr pmccntr_el0, %0" :: "r" (value)); + armv8pmu_pmccntr_write_reg(value); else if (armv8pmu_select_counter(idx) == idx) - asm volatile("msr pmxevcntr_el0, %0" :: "r" (value)); + armv8pmu_pmxevcntr_write_reg(value); } inline void armv8pmu_write_evtype(int idx, u32 val) { if (armv8pmu_select_counter(idx) == idx) { val &= ARMV8_EVTYPE_MASK; - asm volatile("msr pmxevtyper_el0, %0" :: "r" (val)); + armv8pmu_pmxevtyper_write_reg(val); } } inline int armv8pmu_enable_counter(int idx) { u32 counter = ARMV8_IDX_TO_COUNTER(idx); - asm volatile("msr pmcntenset_el0, %0" :: "r" (BIT(counter))); + armv8pmu_pmcntenset_write_reg(BIT(counter)); return idx; } inline int armv8pmu_disable_counter(int idx) { u32 counter = ARMV8_IDX_TO_COUNTER(idx); - asm volatile("msr pmcntenclr_el0, %0" :: "r" (BIT(counter))); + armv8pmu_pmcntenclr_write_reg(BIT(counter)); return idx; } inline int armv8pmu_enable_intens(int idx) { u32 counter = ARMV8_IDX_TO_COUNTER(idx); - asm volatile("msr pmintenset_el1, %0" :: "r" (BIT(counter))); + armv8pmu_pmintenset_write_reg(BIT(counter)); return idx; } inline int armv8pmu_disable_intens(int idx) { u32 counter = ARMV8_IDX_TO_COUNTER(idx); - asm volatile("msr pmintenclr_el1, %0" :: "r" (BIT(counter))); + armv8pmu_pmintenclr_write_reg(BIT(counter)); isb(); /* Clear the overflow flag in case an interrupt is pending. */ - asm volatile("msr pmovsclr_el0, %0" :: "r" (BIT(counter))); + armv8pmu_pmovsclr_write_reg(BIT(counter)); isb(); return idx; @@ -355,11 +354,11 @@ inline u32 armv8pmu_getreset_flags(void) u32 value; /* Read */ - asm volatile("mrs %0, pmovsclr_el0" : "=r" (value)); + value = armv8pmu_pmovsclr_read_reg(); /* Write to clear flags */ value &= ARMV8_OVSR_MASK; - asm volatile("msr pmovsclr_el0, %0" :: "r" (value)); + armv8pmu_pmovsclr_write_reg(value); return value; } @@ -566,14 +565,14 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event, static void armv8pmu_init_usermode(void) { /* Enable access from userspace. */ - asm volatile("msr pmuserenr_el0, %0" :: "r" (0xF)); + armv8pmu_pmuserenr_write_reg(0xF); } #else static inline void armv8pmu_init_usermode(void) { /* Disable access from userspace. */ - asm volatile("msr pmuserenr_el0, %0" :: "r" (0)); + armv8pmu_pmuserenr_write_reg(0); } #endif diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c index 3fe41ee4c3c1..e383f4b42599 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpi.c @@ -414,8 +414,10 @@ static int lpi_notifier_service_cb(struct notifier_block *this, switch (opcode) { case AUDIO_NOTIFIER_SERVICE_DOWN: - if (initial_boot) + if (initial_boot) { + initial_boot = false; break; + } lpi_dev_up = false; break; case AUDIO_NOTIFIER_SERVICE_UP: @@ -463,6 +465,7 @@ static void lpi_gpio_dbg_show_one(struct seq_file *s, "pull up" }; + pctldev = pctldev ? : to_gpio_state(chip)->ctrl; pindesc = pctldev->desc->pins[offset]; pad = pctldev->desc->pins[offset].drv_data; ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_DIR_CTL); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 0629d6bca49a..0d17fa58a853 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -1836,6 +1836,7 @@ static int ipa_q6_clean_q6_tables(void) struct ipa_mem_buffer mem = { 0 }; u32 *entry; u32 max_cmds = ipa_get_max_flt_rt_cmds(ipa_ctx->ipa_num_pipes); + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); mem.base = dma_alloc_coherent(ipa_ctx->pdev, 4, &mem.phys_base, GFP_ATOMIC); @@ -1856,7 +1857,7 @@ static int ipa_q6_clean_q6_tables(void) } cmd = kcalloc(max_cmds, sizeof(struct ipa_hw_imm_cmd_dma_shared_mem), - GFP_KERNEL); + flag); if (!cmd) { IPAERR("failed to allocate memory\n"); retval = -ENOMEM; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index 23c8a5059c3b..826d449edbd2 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -420,15 +420,17 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, int i = 0; int j; int result; - int fail_dma_wrap = 0; uint size = num_desc * sizeof(struct sps_iovec); - u32 mem_flag = GFP_ATOMIC; + gfp_t mem_flag = GFP_ATOMIC; struct sps_iovec iov; int ret; + gfp_t flag; if (unlikely(!in_atomic)) mem_flag = GFP_KERNEL; + flag = mem_flag | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); + if (num_desc == IPA_NUM_DESC_PER_SW_TX) { transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag, &dma_addr); @@ -437,7 +439,7 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, return -EFAULT; } } else { - transfer.iovec = kmalloc(size, mem_flag); + transfer.iovec = kmalloc(size, flag); if (!transfer.iovec) { IPAERR("fail to alloc mem for sps xfr buff "); IPAERR("num_desc = %d size = %d\n", num_desc, size); @@ -457,7 +459,6 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, spin_lock_bh(&sys->spinlock); for (i = 0; i < num_desc; i++) { - fail_dma_wrap = 0; tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag); if (!tx_pkt) { @@ -493,15 +494,6 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, tx_pkt->mem.base, tx_pkt->mem.size, DMA_TO_DEVICE); - - if (dma_mapping_error(ipa_ctx->pdev, - tx_pkt->mem.phys_base)) { - IPAERR("dma_map_single "); - IPAERR("failed\n"); - fail_dma_wrap = 1; - goto failure; - } - } else { tx_pkt->mem.phys_base = desc[i].dma_address; tx_pkt->no_unmap_dma = true; @@ -522,10 +514,9 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, } } - if (!tx_pkt->mem.phys_base) { - IPAERR("failed to alloc tx wrapper\n"); - fail_dma_wrap = 1; - goto failure; + if (dma_mapping_error(ipa_ctx->pdev, tx_pkt->mem.phys_base)) { + IPAERR("dma_map_single failed\n"); + goto failure_dma_map; } tx_pkt->sys = sys; @@ -580,27 +571,30 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, spin_unlock_bh(&sys->spinlock); return 0; +failure_dma_map: + kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt); + failure: tx_pkt = transfer.user; for (j = 0; j < i; j++) { next_pkt = list_next_entry(tx_pkt, link); list_del(&tx_pkt->link); - if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) { - dma_unmap_single(ipa_ctx->pdev, tx_pkt->mem.phys_base, - tx_pkt->mem.size, - DMA_TO_DEVICE); - } else { - dma_unmap_page(ipa_ctx->pdev, tx_pkt->mem.phys_base, - tx_pkt->mem.size, - DMA_TO_DEVICE); + if (!tx_pkt->no_unmap_dma) { + if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) { + dma_unmap_single(ipa_ctx->pdev, + tx_pkt->mem.phys_base, + tx_pkt->mem.size, + DMA_TO_DEVICE); + } else { + dma_unmap_page(ipa_ctx->pdev, + tx_pkt->mem.phys_base, + tx_pkt->mem.size, + DMA_TO_DEVICE); + } } kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt); tx_pkt = next_pkt; } - if (j < num_desc) - /* last desc failed */ - if (fail_dma_wrap) - kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt); if (transfer.iovec_phys) { if (num_desc == IPA_NUM_DESC_PER_SW_TX) { dma_pool_free(ipa_ctx->dma_pool, transfer.iovec, @@ -1659,6 +1653,7 @@ int ipa2_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, struct ipa_sys_context *sys; int src_ep_idx; int num_frags, f; + gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); if (unlikely(!ipa_ctx)) { IPAERR("IPA driver was not initialized\n"); @@ -1724,7 +1719,7 @@ int ipa2_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, if (dst_ep_idx != -1) { /* SW data path */ - cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC); + cmd = kzalloc(sizeof(struct ipa_ip_packet_init), flag); if (!cmd) { IPAERR("failed to alloc immediate command object\n"); goto fail_gen; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c index d94e8f9f0e12..80514f6c738e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c @@ -653,6 +653,7 @@ int __ipa_commit_flt_v1_1(enum ipa_ip_type ip) struct ipa_ip_v6_filter_init *v6; u16 avail; u16 size; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); mem = kmalloc(sizeof(struct ipa_mem_buffer), GFP_KERNEL); if (!mem) { @@ -669,7 +670,7 @@ int __ipa_commit_flt_v1_1(enum ipa_ip_type ip) IPA_MEM_PART(v6_flt_size_ddr); size = sizeof(struct ipa_ip_v6_filter_init); } - cmd = kmalloc(size, GFP_KERNEL); + cmd = kmalloc(size, flag); if (!cmd) { IPAERR("failed to alloc immediate command object\n"); goto fail_alloc_cmd; @@ -842,6 +843,7 @@ int __ipa_commit_flt_v2(enum ipa_ip_type ip) int num_desc = 0; int i; u16 avail; + gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); desc = kzalloc(16 * sizeof(*desc), GFP_ATOMIC); if (desc == NULL) { @@ -850,7 +852,7 @@ int __ipa_commit_flt_v2(enum ipa_ip_type ip) goto fail_desc; } - cmd = kzalloc(16 * sizeof(*cmd), GFP_ATOMIC); + cmd = kzalloc(16 * sizeof(*cmd), flag); if (cmd == NULL) { IPAERR("fail to alloc cmd blob ip %d\n", ip); rc = -ENOMEM; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index f43981f15c31..40c1971dfe96 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c @@ -176,6 +176,7 @@ int __ipa_commit_hdr_v1_1(void) struct ipa_mem_buffer *mem; struct ipa_hdr_init_local *cmd; u16 len; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); mem = kmalloc(sizeof(struct ipa_mem_buffer), GFP_KERNEL); if (!mem) { @@ -190,7 +191,7 @@ int __ipa_commit_hdr_v1_1(void) * we can use init_local ptr for init_system due to layout of the * struct */ - cmd = kmalloc(len, GFP_KERNEL); + cmd = kmalloc(len, flag); if (!cmd) { IPAERR("failed to alloc immediate command object\n"); goto fail_alloc_cmd; @@ -663,6 +664,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl; int id; int mem_size; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); if (hdr->hdr_len == 0 || hdr->hdr_len > IPA_HDR_MAX_SIZE) { IPAERR("bad parm\n"); @@ -674,7 +676,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) goto error; } - entry = kmem_cache_zalloc(ipa_ctx->hdr_cache, GFP_KERNEL); + entry = kmem_cache_zalloc(ipa_ctx->hdr_cache, flag); if (!entry) { IPAERR("failed to alloc hdr object\n"); goto error; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c index 314b09593026..5dd8b225217d 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -325,6 +325,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) int result; u32 offset = 0; size_t tmp; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); IPADBG("\n"); if (init->table_entries == 0) { @@ -406,7 +407,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) memset(&desc, 0, sizeof(desc)); /* NO-OP IC for ensuring that IPA pipeline is empty */ - reg_write_nop = kzalloc(sizeof(*reg_write_nop), GFP_KERNEL); + reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag); if (!reg_write_nop) { IPAERR("no mem\n"); result = -ENOMEM; @@ -424,7 +425,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) desc[0].pyld = (void *)reg_write_nop; desc[0].len = sizeof(*reg_write_nop); - cmd = kmalloc(size, GFP_KERNEL); + cmd = kmalloc(size, flag); if (!cmd) { IPAERR("Failed to alloc immediate command object\n"); result = -ENOMEM; @@ -569,6 +570,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) struct ipa_desc *desc = NULL; u16 size = 0, cnt = 0; int ret = 0; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); IPADBG("\n"); if (dma->entries <= 0) { @@ -652,7 +654,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) } size = sizeof(struct ipa_nat_dma); - cmd = kzalloc(size, GFP_KERNEL); + cmd = kzalloc(size, flag); if (cmd == NULL) { IPAERR("Failed to alloc memory\n"); ret = -ENOMEM; @@ -660,7 +662,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) } /* NO-OP IC for ensuring that IPA pipeline is empty */ - reg_write_nop = kzalloc(sizeof(*reg_write_nop), GFP_KERNEL); + reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag); if (!reg_write_nop) { IPAERR("Failed to alloc memory\n"); ret = -ENOMEM; @@ -754,6 +756,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del) u8 mem_type = IPA_NAT_SHARED_MEMORY; u32 base_addr = IPA_NAT_PHYS_MEM_OFFSET; int result; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); IPADBG("\n"); if (ipa_ctx->nat_mem.is_tmp_mem) { @@ -770,7 +773,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del) memset(&desc, 0, sizeof(desc)); /* NO-OP IC for ensuring that IPA pipeline is empty */ - reg_write_nop = kzalloc(sizeof(*reg_write_nop), GFP_KERNEL); + reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag); if (!reg_write_nop) { IPAERR("no mem\n"); result = -ENOMEM; @@ -788,7 +791,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del) desc[0].pyld = (void *)reg_write_nop; desc[0].len = sizeof(*reg_write_nop); - cmd = kmalloc(size, GFP_KERNEL); + cmd = kmalloc(size, flag); if (cmd == NULL) { IPAERR("Failed to alloc immediate command object\n"); result = -ENOMEM; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index 4b6bc5b61bfc..2214dfe89df3 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -525,6 +525,7 @@ int __ipa_commit_rt_v1_1(enum ipa_ip_type ip) struct ipa_ip_v6_routing_init *v6; u16 avail; u16 size; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); mem = kmalloc(sizeof(struct ipa_mem_buffer), GFP_KERNEL); if (!mem) { @@ -541,7 +542,7 @@ int __ipa_commit_rt_v1_1(enum ipa_ip_type ip) IPA_MEM_PART(v6_rt_size_ddr); size = sizeof(struct ipa_ip_v6_routing_init); } - cmd = kmalloc(size, GFP_KERNEL); + cmd = kmalloc(size, flag); if (!cmd) { IPAERR("failed to alloc immediate command object\n"); goto fail_alloc_cmd; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index be3c890db25c..9943095abe30 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -4507,6 +4507,7 @@ int ipa_tag_process(struct ipa_desc desc[], int res; struct ipa_tag_completion *comp; int ep_idx; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); /* Not enough room for the required descriptors for the tag process */ if (IPA_TAG_MAX_DESC - descs_num < REQUIRED_TAG_PROCESS_DESCRIPTORS) { @@ -4524,7 +4525,7 @@ int ipa_tag_process(struct ipa_desc desc[], } sys = ipa_ctx->ep[ep_idx].sys; - tag_desc = kzalloc(sizeof(*tag_desc) * IPA_TAG_MAX_DESC, GFP_KERNEL); + tag_desc = kzalloc(sizeof(*tag_desc) * IPA_TAG_MAX_DESC, flag); if (!tag_desc) { IPAERR("failed to allocate memory\n"); res = -ENOMEM; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 0492fa27c5b7..6a3a89e2cf8d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -356,7 +356,7 @@ int ipa3_send_one(struct ipa3_sys_context *sys, struct ipa3_desc *desc, dma_address = desc->dma_address; tx_pkt->no_unmap_dma = true; } - if (!dma_address) { + if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) { IPAERR("failed to DMA wrap\n"); goto fail_dma_map; } @@ -471,7 +471,6 @@ int ipa3_send(struct ipa3_sys_context *sys, int i = 0; int j; int result; - int fail_dma_wrap = 0; uint size; u32 mem_flag = GFP_ATOMIC; int ipa_ep_idx; @@ -527,7 +526,7 @@ int ipa3_send(struct ipa3_sys_context *sys, } dma_addr = dma_map_single(ipa3_ctx->pdev, transfer.iovec, size, DMA_TO_DEVICE); - if (!dma_addr) { + if (dma_mapping_error(ipa3_ctx->pdev, dma_addr)) { IPAERR("dma_map_single failed\n"); kfree(transfer.iovec); return -EFAULT; @@ -540,7 +539,6 @@ int ipa3_send(struct ipa3_sys_context *sys, spin_lock_bh(&sys->spinlock); for (i = 0; i < num_desc; i++) { - fail_dma_wrap = 0; tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache, mem_flag); if (!tx_pkt) { @@ -563,7 +561,7 @@ int ipa3_send(struct ipa3_sys_context *sys, if (ipa_populate_tag_field(&desc[i], tx_pkt, &tag_pyld_ret)) { IPAERR("Failed to populate tag field\n"); - goto failure; + goto failure_dma_map; } } @@ -579,11 +577,6 @@ int ipa3_send(struct ipa3_sys_context *sys, tx_pkt->mem.base, tx_pkt->mem.size, DMA_TO_DEVICE); - if (!tx_pkt->mem.phys_base) { - IPAERR("failed to do dma map.\n"); - fail_dma_wrap = 1; - goto failure; - } } else { tx_pkt->mem.phys_base = desc[i].dma_address; @@ -599,17 +592,17 @@ int ipa3_send(struct ipa3_sys_context *sys, desc[i].frag, 0, tx_pkt->mem.size, DMA_TO_DEVICE); - if (!tx_pkt->mem.phys_base) { - IPAERR("dma map failed\n"); - fail_dma_wrap = 1; - goto failure; - } } else { tx_pkt->mem.phys_base = desc[i].dma_address; tx_pkt->no_unmap_dma = true; } } + if (dma_mapping_error(ipa3_ctx->pdev, tx_pkt->mem.phys_base)) { + IPAERR("failed to do dma map.\n"); + goto failure_dma_map; + } + tx_pkt->sys = sys; tx_pkt->callback = desc[i].callback; tx_pkt->user1 = desc[i].user1; @@ -704,29 +697,31 @@ int ipa3_send(struct ipa3_sys_context *sys, spin_unlock_bh(&sys->spinlock); return 0; +failure_dma_map: + kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt); + failure: ipahal_destroy_imm_cmd(tag_pyld_ret); tx_pkt = tx_pkt_first; for (j = 0; j < i; j++) { next_pkt = list_next_entry(tx_pkt, link); list_del(&tx_pkt->link); - if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) { - dma_unmap_single(ipa3_ctx->pdev, tx_pkt->mem.phys_base, - tx_pkt->mem.size, - DMA_TO_DEVICE); - } else { - dma_unmap_page(ipa3_ctx->pdev, tx_pkt->mem.phys_base, - tx_pkt->mem.size, - DMA_TO_DEVICE); + + if (!tx_pkt->no_unmap_dma) { + if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) { + dma_unmap_single(ipa3_ctx->pdev, + tx_pkt->mem.phys_base, + tx_pkt->mem.size, DMA_TO_DEVICE); + } else { + dma_unmap_page(ipa3_ctx->pdev, + tx_pkt->mem.phys_base, + tx_pkt->mem.size, + DMA_TO_DEVICE); + } } kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt); tx_pkt = next_pkt; } - if (j < num_desc) - /* last desc failed */ - if (fail_dma_wrap) - kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt); - if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) { kfree(gsi_xfer_elem_array); } else { @@ -1973,8 +1968,7 @@ begin: rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr, sys->rx_buff_sz, DMA_FROM_DEVICE); - if (rx_pkt->data.dma_addr == 0 || - rx_pkt->data.dma_addr == ~0) { + if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) { pr_err_ratelimited("%s dma map fail %p for %p sys=%p\n", __func__, (void *)rx_pkt->data.dma_addr, ptr, sys); @@ -2141,8 +2135,7 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size) ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ); rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr, IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE); - if (rx_pkt->data.dma_addr == 0 || - rx_pkt->data.dma_addr == ~0) { + if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; @@ -2213,8 +2206,7 @@ static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys) rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr, sys->rx_buff_sz, DMA_FROM_DEVICE); - if (rx_pkt->data.dma_addr == 0 || - rx_pkt->data.dma_addr == ~0) { + if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; @@ -2304,8 +2296,8 @@ static void ipa3_replenish_rx_cache_recycle(struct ipa3_sys_context *sys) ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz); rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr, sys->rx_buff_sz, DMA_FROM_DEVICE); - if (rx_pkt->data.dma_addr == 0 || - rx_pkt->data.dma_addr == ~0) { + if (dma_mapping_error(ipa3_ctx->pdev, + rx_pkt->data.dma_addr)) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; @@ -2320,8 +2312,8 @@ static void ipa3_replenish_rx_cache_recycle(struct ipa3_sys_context *sys) ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz); rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr, sys->rx_buff_sz, DMA_FROM_DEVICE); - if (rx_pkt->data.dma_addr == 0 || - rx_pkt->data.dma_addr == ~0) { + if (dma_mapping_error(ipa3_ctx->pdev, + rx_pkt->data.dma_addr)) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index 69dca7666346..e197ee8b06dd 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -494,6 +494,10 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) entry->hdr, entry->hdr_len, DMA_TO_DEVICE); + if (dma_mapping_error(ipa3_ctx->pdev, entry->phys_base)) { + IPAERR("dma_map_single failure for entry\n"); + goto fail_dma_mapping; + } } else { entry->is_hdr_proc_ctx = false; if (list_empty(&htbl->head_free_offset_list[bin])) { @@ -569,6 +573,9 @@ fail_add_proc_ctx: list_del(&entry->link); dma_unmap_single(ipa3_ctx->pdev, entry->phys_base, entry->hdr_len, DMA_TO_DEVICE); +fail_dma_mapping: + entry->is_hdr_proc_ctx = false; + bad_hdr_len: entry->cookie = 0; kmem_cache_free(ipa3_ctx->hdr_cache, entry); diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c index 5b05270b1e66..e1c50e1273ac 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.c +++ b/drivers/platform/msm/mhi/mhi_bhi.c @@ -598,6 +598,7 @@ void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt) dma_free_coherent(dev, bhie_mem_info->alloc_size, bhie_mem_info->pre_aligned, bhie_mem_info->dma_handle); + kfree(fw_table->bhie_mem_info); fw_table->bhie_mem_info = NULL; /* vector table is the last entry in bhie_mem_info */ fw_table->bhi_vec_entry = NULL; @@ -613,6 +614,7 @@ void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt) dma_free_coherent(dev, bhie_mem_info->alloc_size, bhie_mem_info->pre_aligned, bhie_mem_info->dma_handle); + kfree(rddm_table->bhie_mem_info); rddm_table->bhie_mem_info = NULL; rddm_table->bhi_vec_entry = NULL; } diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c index 64a09a2f9fbb..a5936ea5a6aa 100644 --- a/drivers/platform/msm/mhi/mhi_iface.c +++ b/drivers/platform/msm/mhi/mhi_iface.c @@ -153,16 +153,19 @@ static int mhi_pci_probe(struct pci_dev *pcie_device, u32 slot = PCI_SLOT(pcie_device->devfn); unsigned long msi_requested, msi_required; struct msm_pcie_register_event *mhi_pci_link_event; + struct pcie_core_info *core; + int i; + char node[32]; /* Find correct device context based on bdf & dev_id */ mutex_lock(&mhi_device_drv->lock); list_for_each_entry(itr, &mhi_device_drv->head, node) { - struct pcie_core_info *core = &itr->core; - - if (core->domain == domain && - core->bus == bus && - core->dev_id == dev_id && + core = &itr->core; + if (core->domain == domain && core->bus == bus && + (core->dev_id == PCI_ANY_ID || (core->dev_id == dev_id)) && core->slot == slot) { + /* change default dev_id to actual dev_id */ + core->dev_id = dev_id; mhi_dev_ctxt = itr; break; } @@ -171,6 +174,11 @@ static int mhi_pci_probe(struct pci_dev *pcie_device, if (!mhi_dev_ctxt) return -EPROBE_DEFER; + snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u", + core->dev_id, core->domain, core->bus, core->slot); + mhi_dev_ctxt->mhi_ipc_log = + ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Processing Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n", domain, bus, dev_id, slot); @@ -280,9 +288,22 @@ static int mhi_pci_probe(struct pci_dev *pcie_device, mutex_lock(&mhi_dev_ctxt->pm_lock); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->mhi_pm_state = MHI_PM_POR; - ret_val = set_mhi_base_state(mhi_dev_ctxt); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + /* notify all registered clients we probed */ + for (i = 0; i < MHI_MAX_CHANNELS; i++) { + struct mhi_client_handle *client_handle = + mhi_dev_ctxt->client_handle_list[i]; + + if (!client_handle) + continue; + client_handle->dev_id = core->dev_id; + mhi_notify_client(client_handle, MHI_CB_MHI_PROBED); + } + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + ret_val = set_mhi_base_state(mhi_dev_ctxt); write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + if (ret_val) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, @@ -344,7 +365,6 @@ static int mhi_plat_probe(struct platform_device *pdev) int r = 0, len; struct mhi_device_ctxt *mhi_dev_ctxt; struct pcie_core_info *core; - char node[32]; struct device_node *of_node = pdev->dev.of_node; u64 address_window[2]; @@ -377,7 +397,7 @@ static int mhi_plat_probe(struct platform_device *pdev) core = &mhi_dev_ctxt->core; r = of_property_read_u32(of_node, "qcom,pci-dev_id", &core->dev_id); if (r) - return r; + core->dev_id = PCI_ANY_ID; r = of_property_read_u32(of_node, "qcom,pci-slot", &core->slot); if (r) @@ -391,14 +411,6 @@ static int mhi_plat_probe(struct platform_device *pdev) if (r) return r; - snprintf(node, sizeof(node), - "mhi_%04x_%02u.%02u.%02u", - core->dev_id, core->domain, core->bus, core->slot); - mhi_dev_ctxt->mhi_ipc_log = - ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0); - if (!mhi_dev_ctxt->mhi_ipc_log) - pr_err("%s: Error creating ipc_log buffer\n", __func__); - r = of_property_read_u32(of_node, "qcom,mhi-ready-timeout", &mhi_dev_ctxt->poll_reset_timeout_ms); if (r) @@ -407,10 +419,6 @@ static int mhi_plat_probe(struct platform_device *pdev) mhi_dev_ctxt->dev_space.start_win_addr = address_window[0]; mhi_dev_ctxt->dev_space.end_win_addr = address_window[1]; - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Start Addr:0x%llx End_Addr:0x%llx\n", - mhi_dev_ctxt->dev_space.start_win_addr, - mhi_dev_ctxt->dev_space.end_win_addr); r = of_property_read_u32(of_node, "qcom,bhi-alignment", &mhi_dev_ctxt->bhi_ctxt.alignment); @@ -471,7 +479,6 @@ static int mhi_plat_probe(struct platform_device *pdev) mutex_lock(&mhi_device_drv->lock); list_add_tail(&mhi_dev_ctxt->node, &mhi_device_drv->head); mutex_unlock(&mhi_device_drv->lock); - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); return 0; } diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c index 78aa1beb870d..739915c4af6f 100644 --- a/drivers/platform/msm/mhi/mhi_main.c +++ b/drivers/platform/msm/mhi/mhi_main.c @@ -508,6 +508,7 @@ int mhi_register_channel(struct mhi_client_handle **client_handle, struct mhi_client_config *client_config; const char *node_name; enum MHI_CLIENT_CHANNEL chan; + struct mhi_chan_info chan_info = {0}; int ret; if (!client_info || client_info->dev->of_node == NULL) @@ -537,6 +538,14 @@ int mhi_register_channel(struct mhi_client_handle **client_handle, mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Registering channel 0x%x for client\n", chan); + /* check if it's a supported channel by endpoint */ + ret = get_chan_props(mhi_dev_ctxt, chan, &chan_info); + if (ret) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Client try to register unsupported chan:%d\n", chan); + return -EINVAL; + } + *client_handle = kzalloc(sizeof(struct mhi_client_handle), GFP_KERNEL); if (NULL == *client_handle) return -ENOMEM; @@ -553,6 +562,7 @@ int mhi_register_channel(struct mhi_client_handle **client_handle, (*client_handle)->domain = mhi_dev_ctxt->core.domain; (*client_handle)->bus = mhi_dev_ctxt->core.bus; (*client_handle)->slot = mhi_dev_ctxt->core.slot; + (*client_handle)->enabled = false; client_config = (*client_handle)->client_config; client_config->mhi_dev_ctxt = mhi_dev_ctxt; client_config->user_data = client_info->user_data; @@ -567,7 +577,7 @@ int mhi_register_channel(struct mhi_client_handle **client_handle, if (MHI_CLIENT_IP_HW_0_IN == chan) client_config->intmod_t = 10; - get_chan_props(mhi_dev_ctxt, chan, &client_config->chan_info); + client_config->chan_info = chan_info; ret = enable_bb_ctxt(mhi_dev_ctxt, &mhi_dev_ctxt->chan_bb_list[chan], client_config->chan_info.max_desc, chan, client_config->client_info.max_payload); @@ -579,11 +589,8 @@ int mhi_register_channel(struct mhi_client_handle **client_handle, } if (mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_AMSS && - mhi_dev_ctxt->flags.mhi_initialized) { - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Exec env is AMSS notify client now chan:%u\n", chan); - mhi_notify_client(*client_handle, MHI_CB_MHI_ENABLED); - } + mhi_dev_ctxt->flags.mhi_initialized) + (*client_handle)->enabled = true; mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Successfuly registered chan:%u\n", chan); @@ -1780,6 +1787,8 @@ int mhi_register_device(struct mhi_device *mhi_device, u32 dev_id = pci_dev->device; u32 slot = PCI_SLOT(pci_dev->devfn); int ret, i; + char node[32]; + struct pcie_core_info *core; of_node = of_parse_phandle(mhi_device->dev->of_node, node_name, 0); if (!of_node) @@ -1792,13 +1801,13 @@ int mhi_register_device(struct mhi_device *mhi_device, mutex_lock(&mhi_device_drv->lock); list_for_each_entry(itr, &mhi_device_drv->head, node) { struct platform_device *pdev = itr->plat_dev; - struct pcie_core_info *core = &itr->core; - if (pdev->dev.of_node == of_node && - core->domain == domain && - core->bus == bus && - core->dev_id == dev_id && - core->slot == slot) { + core = &itr->core; + if (pdev->dev.of_node == of_node && core->domain == domain && + core->bus == bus && core->slot == slot && + (core->dev_id == PCI_ANY_ID || (core->dev_id == dev_id))) { + /* change default dev_id to current dev_id */ + core->dev_id = dev_id; mhi_dev_ctxt = itr; break; } @@ -1809,6 +1818,11 @@ int mhi_register_device(struct mhi_device *mhi_device, if (!mhi_dev_ctxt) return -EPROBE_DEFER; + snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u", + core->dev_id, core->domain, core->bus, core->slot); + mhi_dev_ctxt->mhi_ipc_log = + ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Registering Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n", domain, bus, dev_id, slot); @@ -1890,6 +1904,17 @@ int mhi_register_device(struct mhi_device *mhi_device, mhi_dev_ctxt->bhi_ctxt.rddm_size); } + /* notify all the registered clients we probed */ + for (i = 0; i < MHI_MAX_CHANNELS; i++) { + struct mhi_client_handle *client_handle = + mhi_dev_ctxt->client_handle_list[i]; + + if (!client_handle) + continue; + client_handle->dev_id = core->dev_id; + mhi_notify_client(client_handle, MHI_CB_MHI_PROBED); + } + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n"); return 0; } diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c index c0c23c4e0756..e38355841c22 100644 --- a/drivers/platform/msm/mhi/mhi_states.c +++ b/drivers/platform/msm/mhi/mhi_states.c @@ -590,26 +590,26 @@ static int process_reset_transition( } static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt, - enum MHI_EXEC_ENV exec_env) + enum MHI_EXEC_ENV exec_env) { struct mhi_client_handle *client_handle = NULL; - struct mhi_cb_info cb_info; - int i = 0, r = 0; - struct mhi_chan_info chan_info; - - cb_info.cb_reason = MHI_CB_MHI_ENABLED; + struct mhi_chan_info *chan_info; + int i = 0; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enabling Clients, exec env %d.\n", exec_env); + for (i = 0; i < MHI_MAX_CHANNELS; ++i) { - if (!VALID_CHAN_NR(i)) + if (!mhi_dev_ctxt->client_handle_list[i]) continue; + client_handle = mhi_dev_ctxt->client_handle_list[i]; - r = get_chan_props(mhi_dev_ctxt, i, &chan_info); - if (!r && client_handle && - exec_env == GET_CHAN_PROPS(CHAN_BRINGUP_STAGE, - chan_info.flags)) + chan_info = &client_handle->client_config->chan_info; + if (exec_env == GET_CHAN_PROPS(CHAN_BRINGUP_STAGE, + chan_info->flags)) { + client_handle->enabled = true; mhi_notify_client(client_handle, MHI_CB_MHI_ENABLED); + } } mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done.\n"); diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c index 3191ec065a95..4563810d7e5b 100644 --- a/drivers/platform/msm/mhi_uci/mhi_uci.c +++ b/drivers/platform/msm/mhi_uci/mhi_uci.c @@ -122,6 +122,7 @@ struct uci_client { atomic_t out_pkt_pend_ack; atomic_t completion_ack; struct mhi_uci_ctxt_t *uci_ctxt; + struct cdev cdev; bool enabled; void *uci_ipc_log; }; @@ -132,7 +133,6 @@ struct mhi_uci_ctxt_t { struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT]; dev_t dev_t; struct mutex ctrl_mutex; - struct cdev cdev[MHI_SOFTWARE_CLIENT_LIMIT]; struct uci_client *ctrl_client; }; @@ -246,6 +246,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait); static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static int mhi_uci_create_device(struct uci_client *uci_client); static struct mhi_uci_drv_ctxt mhi_uci_drv_ctxt; @@ -1174,6 +1175,14 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info) uci_handle = cb_info->result->user_data; switch (cb_info->cb_reason) { + case MHI_CB_MHI_PROBED: + /* If it's outbound channel create the node */ + mutex_lock(&uci_handle->client_lock); + if (!uci_handle->dev && + cb_info->chan == uci_handle->out_attr.chan_id) + mhi_uci_create_device(uci_handle); + mutex_unlock(&uci_handle->client_lock); + break; case MHI_CB_MHI_ENABLED: uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "MHI enabled CB received for chan %d\n", @@ -1295,17 +1304,65 @@ static const struct file_operations mhi_uci_client_fops = { .unlocked_ioctl = mhi_uci_ctl_ioctl, }; +static int mhi_uci_create_device(struct uci_client *uci_client) +{ + struct mhi_uci_ctxt_t *uci_ctxt = uci_client->uci_ctxt; + char node_name[32]; + int index = uci_client - uci_ctxt->client_handles; + int ret; + + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, + "Creating dev node %04x_%02u.%02u.%02u_pipe%d\n", + uci_client->out_attr.mhi_handle->dev_id, + uci_client->out_attr.mhi_handle->domain, + uci_client->out_attr.mhi_handle->bus, + uci_client->out_attr.mhi_handle->slot, + uci_client->out_attr.chan_id); + + cdev_init(&uci_client->cdev, &mhi_uci_client_fops); + uci_client->cdev.owner = THIS_MODULE; + ret = cdev_add(&uci_client->cdev, uci_ctxt->dev_t + index, 1); + if (ret) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR, + "Failed to add cdev %d, ret:%d\n", index, ret); + return ret; + } + uci_client->dev = device_create(mhi_uci_drv_ctxt.mhi_uci_class, NULL, + uci_ctxt->dev_t + index, NULL, + DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d", + uci_client->out_attr.mhi_handle->dev_id, + uci_client->out_attr.mhi_handle->domain, + uci_client->out_attr.mhi_handle->bus, + uci_client->out_attr.mhi_handle->slot, + "_pipe_", + uci_client->out_attr.chan_id); + if (IS_ERR(uci_client->dev)) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR, + "Failed to add cdev %d\n", IS_ERR(uci_client->dev)); + cdev_del(&uci_client->cdev); + return -EIO; + } + + /* dev node created successfully, create logging buffer */ + snprintf(node_name, sizeof(node_name), "mhi_uci_%04x_%02u.%02u.%02u_%d", + uci_client->out_attr.mhi_handle->dev_id, + uci_client->out_attr.mhi_handle->domain, + uci_client->out_attr.mhi_handle->bus, + uci_client->out_attr.mhi_handle->slot, + uci_client->out_attr.chan_id); + uci_client->uci_ipc_log = ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES, + node_name, 0); + + return 0; +} + static int mhi_uci_probe(struct platform_device *pdev) { struct mhi_uci_ctxt_t *uci_ctxt; int ret_val; int i; - char node_name[32]; - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_INFO, - "Entered with pdev:%p\n", - pdev); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, "Entered\n"); if (mhi_is_device_ready(&pdev->dev, "qcom,mhi") == false) return -EPROBE_DEFER; @@ -1326,128 +1383,67 @@ static int mhi_uci_probe(struct platform_device *pdev) uci_ctxt->pdev = pdev; mutex_init(&uci_ctxt->ctrl_mutex); - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_INFO, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, "Setting up channel attributes\n"); ret_val = uci_init_client_attributes(uci_ctxt, pdev->dev.of_node); if (ret_val) { - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_ERROR, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR, "Failed to init client attributes\n"); return -EIO; } - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_INFO, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, + "Allocating char devices\n"); + ret_val = alloc_chrdev_region(&uci_ctxt->dev_t, 0, + MHI_SOFTWARE_CLIENT_LIMIT, + DEVICE_NAME); + if (IS_ERR_VALUE(ret_val)) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR, + "Failed to alloc char devs, ret 0x%x\n", ret_val); + return ret_val; + } + + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, "Registering for MHI events\n"); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) { struct uci_client *uci_client = &uci_ctxt->client_handles[i]; uci_client->uci_ctxt = uci_ctxt; mutex_init(&uci_client->client_lock); - if (uci_client->in_attr.uci_ownership) { - ret_val = mhi_register_client(uci_client, - &pdev->dev); + if (!uci_client->in_attr.uci_ownership) + continue; + ret_val = mhi_register_client(uci_client, &pdev->dev); + if (ret_val) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_CRITICAL, + "Failed to reg client %d ret %d\n", + ret_val, i); + return -EIO; + } + + mutex_lock(&uci_client->client_lock); + /* If we have device id, create the node now */ + if (uci_client->out_attr.mhi_handle->dev_id != PCI_ANY_ID) { + ret_val = mhi_uci_create_device(uci_client); if (ret_val) { uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_CRITICAL, - "Failed to reg client %d ret %d\n", - ret_val, - i); - + "Failed to create device node, ret:%d\n", + ret_val); + mutex_unlock(&uci_client->client_lock); return -EIO; } - snprintf(node_name, - sizeof(node_name), - "mhi_uci_%04x_%02u.%02u.%02u_%d", - uci_client->out_attr.mhi_handle->dev_id, - uci_client->out_attr.mhi_handle->domain, - uci_client->out_attr.mhi_handle->bus, - uci_client->out_attr.mhi_handle->slot, - uci_client->out_attr.chan_id); - uci_client->uci_ipc_log = ipc_log_context_create - (MHI_UCI_IPC_LOG_PAGES, - node_name, - 0); } + mutex_unlock(&uci_client->client_lock); } - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_INFO, - "Allocating char devices\n"); - ret_val = alloc_chrdev_region(&uci_ctxt->dev_t, - 0, - MHI_SOFTWARE_CLIENT_LIMIT, - DEVICE_NAME); - if (IS_ERR_VALUE(ret_val)) { - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_ERROR, - "Failed to alloc char devs, ret 0x%x\n", ret_val); - goto failed_char_alloc; - } - - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_INFO, - "Setting up device nodes. for dev_t: 0x%x major:0x%x\n", - uci_ctxt->dev_t, - MAJOR(uci_ctxt->dev_t)); - for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) { - struct uci_client *uci_client = &uci_ctxt->client_handles[i]; - - if (uci_client->in_attr.uci_ownership) { - cdev_init(&uci_ctxt->cdev[i], &mhi_uci_client_fops); - uci_ctxt->cdev[i].owner = THIS_MODULE; - ret_val = cdev_add(&uci_ctxt->cdev[i], - uci_ctxt->dev_t + i, 1); - if (IS_ERR_VALUE(ret_val)) { - uci_log(uci_client->uci_ipc_log, - UCI_DBG_ERROR, - "Failed to add cdev %d, ret 0x%x\n", - i, ret_val); - goto failed_char_add; - } - uci_client->dev = - device_create(mhi_uci_drv_ctxt.mhi_uci_class, - NULL, - uci_ctxt->dev_t + i, - NULL, - DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d", - uci_client->out_attr.mhi_handle->dev_id, - uci_client->out_attr.mhi_handle->domain, - uci_client->out_attr.mhi_handle->bus, - uci_client->out_attr.mhi_handle->slot, - "_pipe_", - uci_client->out_attr.chan_id); - if (IS_ERR(uci_client->dev)) { - uci_log(uci_client->uci_ipc_log, - UCI_DBG_ERROR, - "Failed to add cdev %d\n", i); - cdev_del(&uci_ctxt->cdev[i]); - ret_val = -EIO; - goto failed_device_create; - } - } - } platform_set_drvdata(pdev, uci_ctxt); mutex_lock(&mhi_uci_drv_ctxt.list_lock); list_add_tail(&uci_ctxt->node, &mhi_uci_drv_ctxt.head); mutex_unlock(&mhi_uci_drv_ctxt.list_lock); - return 0; - -failed_char_add: -failed_device_create: - while (--i >= 0) { - cdev_del(&uci_ctxt->cdev[i]); - device_destroy(mhi_uci_drv_ctxt.mhi_uci_class, - MKDEV(MAJOR(uci_ctxt->dev_t), i)); - }; - - unregister_chrdev_region(MAJOR(uci_ctxt->dev_t), - MHI_SOFTWARE_CLIENT_LIMIT); -failed_char_alloc: - return ret_val; + return 0; }; static int mhi_uci_remove(struct platform_device *pdev) @@ -1462,7 +1458,7 @@ static int mhi_uci_remove(struct platform_device *pdev) if (uci_client->in_attr.uci_ownership) { mhi_deregister_channel(uci_client->out_attr.mhi_handle); mhi_deregister_channel(uci_client->in_attr.mhi_handle); - cdev_del(&uci_ctxt->cdev[i]); + cdev_del(&uci_client->cdev); device_destroy(mhi_uci_drv_ctxt.mhi_uci_class, MKDEV(MAJOR(uci_ctxt->dev_t), i)); } diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 8b4067b17103..38f9f762ccc7 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -551,7 +551,7 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); /* wait for ICL change */ - msleep(100); + msleep(20); } /* set the effective ICL */ @@ -559,9 +559,6 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); - if (rerun_aicl) - /* wait for ICL change */ - msleep(100); vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 25c9d0251cf1..c5346babf310 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -219,6 +219,12 @@ enum slope_limit_status { SLOPE_LIMIT_NUM_COEFFS, }; +enum esr_timer_config { + TIMER_RETRY = 0, + TIMER_MAX, + NUM_ESR_TIMERS, +}; + /* DT parameters for FG device */ struct fg_dt_props { bool force_load_profile; @@ -234,9 +240,9 @@ struct fg_dt_props { int recharge_soc_thr; int recharge_volt_thr_mv; int rsense_sel; - int esr_timer_charging; - int esr_timer_awake; - int esr_timer_asleep; + int esr_timer_charging[NUM_ESR_TIMERS]; + int esr_timer_awake[NUM_ESR_TIMERS]; + int esr_timer_asleep[NUM_ESR_TIMERS]; int rconn_mohms; int esr_clamp_mohms; int cl_start_soc; @@ -385,6 +391,7 @@ struct fg_chip { int maint_soc; int delta_soc; int last_msoc; + int esr_timer_charging_default[NUM_ESR_TIMERS]; enum slope_limit_status slope_limit_sts; bool profile_available; bool profile_loaded; diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 26648595c55c..36ac1960a176 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -1025,12 +1025,15 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val) *val <<= ESR_PULL_DOWN_IVAL_SHIFT; } -static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, - int flags) +static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init, + int cycles_max, bool charging, int flags) { u8 buf[2]; int rc, timer_max, timer_init; + if (cycles_init < 0 || cycles_max < 0) + return 0; + if (charging) { timer_max = FG_SRAM_ESR_TIMER_CHG_MAX; timer_init = FG_SRAM_ESR_TIMER_CHG_INIT; @@ -1039,7 +1042,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT; } - fg_encode(chip->sp, timer_max, cycles, buf); + fg_encode(chip->sp, timer_max, cycles_max, buf); rc = fg_sram_write(chip, chip->sp[timer_max].addr_word, chip->sp[timer_max].addr_byte, buf, @@ -1050,7 +1053,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, return rc; } - fg_encode(chip->sp, timer_init, cycles, buf); + fg_encode(chip->sp, timer_init, cycles_init, buf); rc = fg_sram_write(chip, chip->sp[timer_init].addr_word, chip->sp[timer_init].addr_byte, buf, @@ -1061,6 +1064,8 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, return rc; } + fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n", + charging ? "charging" : "discharging", cycles_init, cycles_max); return 0; } @@ -2039,6 +2044,50 @@ static int fg_esr_fcc_config(struct fg_chip *chip) return 0; } +static int fg_esr_timer_config(struct fg_chip *chip, bool sleep) +{ + int rc, cycles_init, cycles_max; + bool end_of_charge = false; + + end_of_charge = is_input_present(chip) && chip->charge_done; + fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge); + + /* ESR discharging timer configuration */ + cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] : + chip->dt.esr_timer_awake[TIMER_RETRY]; + if (end_of_charge) + cycles_init = 0; + + cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] : + chip->dt.esr_timer_awake[TIMER_MAX]; + + rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false, + sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; + } + + /* ESR charging timer configuration */ + cycles_init = cycles_max = -EINVAL; + if (end_of_charge || sleep) { + cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY]; + cycles_max = chip->dt.esr_timer_charging[TIMER_MAX]; + } else if (is_input_present(chip)) { + cycles_init = chip->esr_timer_charging_default[TIMER_RETRY]; + cycles_max = chip->esr_timer_charging_default[TIMER_MAX]; + } + + rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true, + sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; + } + + return 0; +} + static void fg_batt_avg_update(struct fg_chip *chip) { if (chip->charge_status == chip->prev_charge_status) @@ -2112,6 +2161,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); + rc = fg_esr_timer_config(chip, false); + if (rc < 0) + pr_err("Error in configuring ESR timer, rc=%d\n", rc); + rc = fg_get_battery_temp(chip, &batt_temp); if (!rc) { rc = fg_slope_limit_config(chip, batt_temp); @@ -3115,6 +3168,8 @@ static const struct power_supply_desc fg_psy_desc = { /* INIT FUNCTIONS STAY HERE */ +#define DEFAULT_ESR_CHG_TIMER_RETRY 8 +#define DEFAULT_ESR_CHG_TIMER_MAX 16 static int fg_hw_init(struct fg_chip *chip) { int rc; @@ -3283,22 +3338,29 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - if (chip->dt.esr_timer_charging > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging, true, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in setting ESR timer, rc=%d\n", rc); - return rc; - } + if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) { + chip->esr_timer_charging_default[TIMER_RETRY] = + DEFAULT_ESR_CHG_TIMER_RETRY; + chip->esr_timer_charging_default[TIMER_MAX] = + DEFAULT_ESR_CHG_TIMER_MAX; + } else { + /* We don't need this for pm660 at present */ + chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL; + chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL; } - if (chip->dt.esr_timer_awake > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in setting ESR timer, rc=%d\n", rc); - return rc; - } + rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY], + chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; + } + + rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY], + chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; } if (chip->cyc_ctr.en) @@ -3778,6 +3840,32 @@ static int fg_register_interrupts(struct fg_chip *chip) return 0; } +static int fg_parse_dt_property_u32_array(struct device_node *node, + const char *prop_name, int *buf, int len) +{ + int rc; + + rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32)); + if (rc < 0) { + if (rc == -EINVAL) + return 0; + else + return rc; + } else if (rc != len) { + pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name, + rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(node, prop_name, buf, len); + if (rc < 0) { + pr_err("Error in reading %s, rc=%d\n", prop_name, rc); + return rc; + } + + return 0; +} + static int fg_parse_slope_limit_coefficients(struct fg_chip *chip) { struct device_node *node = chip->dev->of_node; @@ -3788,17 +3876,10 @@ static int fg_parse_slope_limit_coefficients(struct fg_chip *chip) if (rc < 0) return 0; - rc = of_property_count_elems_of_size(node, "qcom,slope-limit-coeffs", - sizeof(u32)); - if (rc != SLOPE_LIMIT_NUM_COEFFS) - return -EINVAL; - - rc = of_property_read_u32_array(node, "qcom,slope-limit-coeffs", - chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS); - if (rc < 0) { - pr_err("Error in reading qcom,slope-limit-coeffs, rc=%d\n", rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs", + chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS); + if (rc < 0) return rc; - } for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) { if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX || @@ -3817,44 +3898,20 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip) struct device_node *node = chip->dev->of_node; int rc, i; - rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-soc-dischg", - sizeof(u32)); - if (rc != KI_COEFF_SOC_LEVELS) - return 0; - - rc = of_property_read_u32_array(node, "qcom,ki-coeff-soc-dischg", - chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS); - if (rc < 0) { - pr_err("Error in reading ki-coeff-soc-dischg, rc=%d\n", - rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg", + chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS); + if (rc < 0) return rc; - } - - rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-med-dischg", - sizeof(u32)); - if (rc != KI_COEFF_SOC_LEVELS) - return 0; - rc = of_property_read_u32_array(node, "qcom,ki-coeff-med-dischg", - chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS); - if (rc < 0) { - pr_err("Error in reading ki-coeff-med-dischg, rc=%d\n", - rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg", + chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS); + if (rc < 0) return rc; - } - - rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-hi-dischg", - sizeof(u32)); - if (rc != KI_COEFF_SOC_LEVELS) - return 0; - rc = of_property_read_u32_array(node, "qcom,ki-coeff-hi-dischg", - chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS); - if (rc < 0) { - pr_err("Error in reading ki-coeff-hi-dischg, rc=%d\n", - rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg", + chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS); + if (rc < 0) return rc; - } for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) { if (chip->dt.ki_coeff_soc[i] < 0 || @@ -4099,23 +4156,26 @@ static int fg_parse_dt(struct fg_chip *chip) rc); } - rc = of_property_read_u32(node, "qcom,fg-esr-timer-charging", &temp); - if (rc < 0) - chip->dt.esr_timer_charging = -EINVAL; - else - chip->dt.esr_timer_charging = temp; + rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging", + chip->dt.esr_timer_charging, NUM_ESR_TIMERS); + if (rc < 0) { + chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL; + } - rc = of_property_read_u32(node, "qcom,fg-esr-timer-awake", &temp); - if (rc < 0) - chip->dt.esr_timer_awake = -EINVAL; - else - chip->dt.esr_timer_awake = temp; + rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake", + chip->dt.esr_timer_awake, NUM_ESR_TIMERS); + if (rc < 0) { + chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL; + } - rc = of_property_read_u32(node, "qcom,fg-esr-timer-asleep", &temp); - if (rc < 0) - chip->dt.esr_timer_asleep = -EINVAL; - else - chip->dt.esr_timer_asleep = temp; + rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep", + chip->dt.esr_timer_asleep, NUM_ESR_TIMERS); + if (rc < 0) { + chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL; + } chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en"); if (chip->cyc_ctr.en) @@ -4453,15 +4513,9 @@ static int fg_gen3_suspend(struct device *dev) struct fg_chip *chip = dev_get_drvdata(dev); int rc; - if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_asleep, false, - FG_IMA_NO_WLOCK); - if (rc < 0) { - pr_err("Error in setting ESR timer during suspend, rc=%d\n", - rc); - return rc; - } - } + rc = fg_esr_timer_config(chip, true); + if (rc < 0) + pr_err("Error in configuring ESR timer, rc=%d\n", rc); cancel_delayed_work_sync(&chip->batt_avg_work); if (fg_sram_dump) @@ -4474,15 +4528,9 @@ static int fg_gen3_resume(struct device *dev) struct fg_chip *chip = dev_get_drvdata(dev); int rc; - if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in setting ESR timer during resume, rc=%d\n", - rc); - return rc; - } - } + rc = fg_esr_timer_config(chip, false); + if (rc < 0) + pr_err("Error in configuring ESR timer, rc=%d\n", rc); fg_circ_buf_clr(&chip->ibatt_circ_buf); fg_circ_buf_clr(&chip->vbatt_circ_buf); diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index d3abfbfbbc43..803851d2b3ef 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -432,6 +432,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_CTM_CURRENT_MAX, POWER_SUPPLY_PROP_HW_CURRENT_MAX, POWER_SUPPLY_PROP_REAL_TYPE, + POWER_SUPPLY_PROP_PR_SWAP, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -454,8 +455,7 @@ static int smb2_usb_get_prop(struct power_supply *psy, if (!val->intval) break; - rc = smblib_get_prop_typec_mode(chg, val); - if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || + if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || chg->micro_usb_mode) && chg->real_charger_type == POWER_SUPPLY_TYPE_USB) val->intval = 0; @@ -492,7 +492,7 @@ static int smb2_usb_get_prop(struct power_supply *psy, else if (chip->bad_part) val->intval = POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; else - rc = smblib_get_prop_typec_mode(chg, val); + val->intval = chg->typec_mode; break; case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: if (chg->micro_usb_mode) @@ -536,6 +536,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_HW_CURRENT_MAX: rc = smblib_get_charge_current(chg, &val->intval); break; + case POWER_SUPPLY_PROP_PR_SWAP: + rc = smblib_get_prop_pr_swap_in_progress(chg, val); + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -594,6 +597,9 @@ static int smb2_usb_set_prop(struct power_supply *psy, rc = vote(chg->usb_icl_votable, CTM_VOTER, val->intval >= 0, val->intval); break; + case POWER_SUPPLY_PROP_PR_SWAP: + rc = smblib_set_prop_pr_swap_in_progress(chg, val); + break; default: pr_err("set prop %d is not supported\n", psp); rc = -EINVAL; @@ -671,8 +677,7 @@ static int smb2_usb_port_get_prop(struct power_supply *psy, if (!val->intval) break; - rc = smblib_get_prop_typec_mode(chg, val); - if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || + if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || chg->micro_usb_mode) && chg->real_charger_type == POWER_SUPPLY_TYPE_USB) val->intval = 1; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 4c66bc500ab4..7848ca4396d9 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -841,7 +841,6 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) { int rc = 0; bool override; - union power_supply_propval pval; /* suspend and return if 25mA or less is requested */ if (icl_ua < USBIN_25MA) @@ -851,14 +850,8 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) if (icl_ua == INT_MAX) goto override_suspend_config; - rc = smblib_get_prop_typec_mode(chg, &pval); - if (rc < 0) { - smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc); - goto enable_icl_changed_interrupt; - } - /* configure current */ - if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT + if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) { rc = set_sdp_current(chg, icl_ua); if (rc < 0) { @@ -880,7 +873,7 @@ override_suspend_config: if (icl_ua == INT_MAX) { /* remove override if no voters - hw defaults is desired */ override = false; - } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) { + } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) { if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) /* For std cable with type = SDP never override */ override = false; @@ -920,15 +913,8 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua) int rc = 0; u8 load_cfg; bool override; - union power_supply_propval pval; - rc = smblib_get_prop_typec_mode(chg, &pval); - if (rc < 0) { - smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc); - return rc; - } - - if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT + if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || chg->micro_usb_mode) && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) { rc = get_sdp_current(chg, icl_ua); @@ -2219,8 +2205,6 @@ static const char * const smblib_typec_mode_name[] = { static int smblib_get_prop_ufp_mode(struct smb_charger *chg) { switch (chg->typec_status[0]) { - case 0: - return POWER_SUPPLY_TYPEC_NONE; case UFP_TYPEC_RDSTD_BIT: return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; case UFP_TYPEC_RD1P5_BIT: @@ -2231,7 +2215,7 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg) break; } - return POWER_SUPPLY_TYPEC_NON_COMPLIANT; + return POWER_SUPPLY_TYPEC_NONE; } static int smblib_get_prop_dfp_mode(struct smb_charger *chg) @@ -2245,8 +2229,6 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg) return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE; case DFP_RD_OPEN_BIT: return POWER_SUPPLY_TYPEC_SINK; - case DFP_RA_OPEN_BIT: - return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY; default: break; } @@ -2254,20 +2236,12 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg) return POWER_SUPPLY_TYPEC_NONE; } -int smblib_get_prop_typec_mode(struct smb_charger *chg, - union power_supply_propval *val) +static int smblib_get_prop_typec_mode(struct smb_charger *chg) { - if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) { - val->intval = POWER_SUPPLY_TYPEC_NONE; - return 0; - } - if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) - val->intval = smblib_get_prop_dfp_mode(chg); + return smblib_get_prop_dfp_mode(chg); else - val->intval = smblib_get_prop_ufp_mode(chg); - - return 0; + return smblib_get_prop_ufp_mode(chg); } int smblib_get_prop_typec_power_role(struct smb_charger *chg, @@ -2555,24 +2529,12 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val) { int rc; - bool orientation, cc_debounced, sink_attached, hvdcp; + bool orientation, sink_attached, hvdcp; u8 stat; if (!get_effective_result(chg->pd_allowed_votable)) return -EINVAL; - rc = smblib_read(chg, APSD_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc); - return rc; - } - - cc_debounced = (bool) - (chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT); - sink_attached = (bool) - (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT); - hvdcp = stat & QC_CHARGER_BIT; - chg->pd_active = val->intval; if (chg->pd_active) { vote(chg->apsd_disable_votable, PD_VOTER, true, 0); @@ -2624,6 +2586,14 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, if (rc < 0) smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc); } else { + rc = smblib_read(chg, APSD_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read APSD status rc=%d\n", + rc); + return rc; + } + + hvdcp = stat & QC_CHARGER_BIT; vote(chg->apsd_disable_votable, PD_VOTER, false, 0); vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); @@ -2643,8 +2613,8 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, * and data could be interrupted. Non-legacy DCP could also draw * more, but it may impact compliance. */ - if (!chg->typec_legacy_valid && cc_debounced && - !sink_attached && hvdcp) + sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT; + if (!chg->typec_legacy_valid && !sink_attached && hvdcp) schedule_work(&chg->legacy_detection_work); } @@ -2766,6 +2736,7 @@ static int smblib_cc2_sink_removal_enter(struct smb_charger *chg) smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return rc; } + ccout = (stat & CC_ATTACHED_BIT) ? (!!(stat & CC_ORIENTATION_BIT) + 1) : 0; ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ? @@ -3669,12 +3640,22 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc); + mutex_lock(&chg->vconn_oc_lock); + if (!chg->vconn_en) + goto unlock; + + smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + VCONN_EN_VALUE_BIT, 0); + chg->vconn_en = false; + +unlock: + mutex_unlock(&chg->vconn_oc_lock); + typec_sink_removal(chg); smblib_update_usb_type(chg); } -static void smblib_handle_typec_insertion(struct smb_charger *chg, - bool sink_attached) +static void smblib_handle_typec_insertion(struct smb_charger *chg) { int rc; @@ -3686,45 +3667,37 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg, smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", rc); - if (sink_attached) + if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) typec_sink_insertion(chg); else typec_sink_removal(chg); } -static void smblib_handle_typec_debounce_done(struct smb_charger *chg, - bool rising, bool sink_attached) +static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) { - int rc; - union power_supply_propval pval = {0, }; + if (chg->pr_swap_in_progress) + return; - if (rising) { - if (!chg->typec_present) { - chg->typec_present = true; - smblib_dbg(chg, PR_MISC, "TypeC insertion\n"); - smblib_handle_typec_insertion(chg, sink_attached); - } - } else { - if (chg->typec_present) { - chg->typec_present = false; - smblib_dbg(chg, PR_MISC, "TypeC removal\n"); - smblib_handle_typec_removal(chg); - } + chg->typec_mode = smblib_get_prop_typec_mode(chg); + if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) { + chg->typec_present = true; + smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n", + smblib_typec_mode_name[chg->typec_mode]); + smblib_handle_typec_insertion(chg); + } else if (chg->typec_present && + chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) { + chg->typec_present = false; + smblib_dbg(chg, PR_MISC, "TypeC removal\n"); + smblib_handle_typec_removal(chg); } - rc = smblib_get_prop_typec_mode(chg, &pval); - if (rc < 0) - smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc); - - smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n", - rising ? "rising" : "falling", - smblib_typec_mode_name[pval.intval]); + smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", + smblib_typec_mode_name[chg->typec_mode]); } static void smblib_usb_typec_change(struct smb_charger *chg) { int rc; - bool debounce_done, sink_attached; rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG, chg->typec_status, 5); @@ -3733,12 +3706,7 @@ static void smblib_usb_typec_change(struct smb_charger *chg) return; } - debounce_done = - (bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT); - sink_attached = - (bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT); - - smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached); + smblib_handle_typec_cc_state_change(chg); if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT) smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); @@ -3841,6 +3809,30 @@ irqreturn_t smblib_handle_wdog_bark(int irq, void *data) return IRQ_HANDLED; } +/************** + * Additional USB PSY getters/setters + * that call interrupt functions +***************/ + +int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = chg->pr_swap_in_progress; + return 0; +} + +int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, + const union power_supply_propval *val) +{ + chg->pr_swap_in_progress = val->intval; + /* + * call the cc changed irq to handle real removals while + * PR_SWAP was in progress + */ + smblib_usb_typec_change(chg); + return 0; +} + /*************** * Work Queues * ***************/ @@ -4229,8 +4221,7 @@ static void smblib_legacy_detection_work(struct work_struct *work) chg->typec_legacy_valid = true; vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; - rp_high = smblib_get_prop_ufp_mode(chg) == - POWER_SUPPLY_TYPEC_SOURCE_HIGH; + rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH; if (!legacy || !rp_high) vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, false, 0); diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 41015d49b31e..8ba0a1dfe19f 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -321,6 +321,8 @@ struct smb_charger { u8 typec_status[5]; bool typec_legacy_valid; int fake_input_current_limited; + bool pr_swap_in_progress; + int typec_mode; /* workaround flag */ u32 wa_flags; @@ -452,8 +454,6 @@ int smblib_get_prop_usb_current_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_typec_mode(struct smb_charger *chg, - union power_supply_propval *val); int smblib_get_prop_typec_power_role(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_pd_allowed(struct smb_charger *chg, @@ -506,6 +506,10 @@ int smblib_rerun_aicl(struct smb_charger *chg); int smblib_set_icl_current(struct smb_charger *chg, int icl_ua); int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua); int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua); +int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index 167666a8c548..d8671ab1fd06 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -486,11 +486,11 @@ enum { #define UFP_TYPEC_OPEN_OPEN_BIT BIT(0) #define TYPE_C_STATUS_2_REG (USBIN_BASE + 0x0C) -#define DFP_TYPEC_MASK 0x8F #define DFP_RA_OPEN_BIT BIT(7) #define TIMER_STAGE_BIT BIT(6) #define EXIT_UFP_MODE_BIT BIT(5) #define EXIT_DFP_MODE_BIT BIT(4) +#define DFP_TYPEC_MASK GENMASK(3, 0) #define DFP_RD_OPEN_BIT BIT(3) #define DFP_RD_RA_VCONN_BIT BIT(2) #define DFP_RD_RD_BIT BIT(1) diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c index 7014fd706d9e..f5c8252b5e41 100644 --- a/drivers/power/supply/qcom/smb1351-charger.c +++ b/drivers/power/supply/qcom/smb1351-charger.c @@ -1416,6 +1416,7 @@ static enum power_supply_property smb1351_parallel_properties[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_PARALLEL_MODE, + POWER_SUPPLY_PROP_INPUT_SUSPEND, }; static int smb1351_parallel_set_chg_suspend(struct smb1351_charger *chip, @@ -1702,6 +1703,9 @@ static int smb1351_parallel_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_PARALLEL_MODE: val->intval = chip->parallel_mode; break; + case POWER_SUPPLY_PROP_INPUT_SUSPEND: + val->intval = chip->parallel_charger_suspended; + break; default: return -EINVAL; } diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 694591c3ec56..335b160e24a5 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -248,7 +248,7 @@ static int smb138x_usb_get_prop(struct power_supply *psy, val->intval = chg->usb_psy_desc.type; break; case POWER_SUPPLY_PROP_TYPEC_MODE: - rc = smblib_get_prop_typec_mode(chg, val); + val->intval = chg->typec_mode; break; case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: rc = smblib_get_prop_typec_power_role(chg, val); @@ -941,13 +941,6 @@ static int smb138x_init_slave_hw(struct smb138x *chip) return rc; } - rc = smblib_write(chg, THERMREG_SRC_CFG_REG, - THERMREG_SKIN_ADC_SRC_EN_BIT); - if (rc < 0) { - pr_err("Couldn't enable connector thermreg source rc=%d\n", rc); - return rc; - } - return 0; } diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c index bd706658348d..08e991fa7db3 100644 --- a/drivers/regulator/qpnp-regulator.c +++ b/drivers/regulator/qpnp-regulator.c @@ -127,6 +127,9 @@ enum qpnp_common_regulator_registers { QPNP_COMMON_REG_ENABLE = 0x46, QPNP_COMMON_REG_PULL_DOWN = 0x48, QPNP_COMMON_REG_STEP_CTRL = 0x61, + QPNP_COMMON_REG_UL_LL_CTRL = 0x68, + QPNP_COMMON_REG_VOLTAGE_ULS_VALID = 0x6A, + QPNP_COMMON_REG_VOLTAGE_LLS_VALID = 0x6C, }; /* @@ -139,6 +142,8 @@ enum qpnp_common2_regulator_registers { QPNP_COMMON2_REG_VOLTAGE_MSB = 0x41, QPNP_COMMON2_REG_MODE = 0x45, QPNP_COMMON2_REG_STEP_CTRL = 0x61, + QPNP_COMMON2_REG_VOLTAGE_ULS_LSB = 0x68, + QPNP_COMMON2_REG_VOLTAGE_ULS_MSB = 0x69, }; enum qpnp_ldo_registers { @@ -205,6 +210,10 @@ enum qpnp_common2_control_register_index { /* Common regulator pull down control register layout */ #define QPNP_COMMON_PULL_DOWN_ENABLE_MASK 0x80 +/* Common regulator UL & LL limits control register layout */ +#define QPNP_COMMON_UL_EN_MASK 0x80 +#define QPNP_COMMON_LL_EN_MASK 0x40 + /* LDO regulator current limit control register layout */ #define QPNP_LDO_CURRENT_LIMIT_ENABLE_MASK 0x80 @@ -1749,6 +1758,89 @@ static int qpnp_regulator_match(struct qpnp_regulator *vreg) return rc; } +static int qpnp_regulator_check_constraints(struct qpnp_regulator *vreg, + struct qpnp_regulator_platform_data *pdata) +{ + struct qpnp_voltage_range *range = NULL; + int i, rc = 0, limit_min_uV, limit_max_uV, max_uV; + u8 reg[2]; + + limit_min_uV = 0; + limit_max_uV = INT_MAX; + + if (vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS) { + max_uV = pdata->init_data.constraints.max_uV; + /* Find the range which max_uV is inside of. */ + for (i = vreg->set_points->count - 1; i > 0; i--) { + range = &vreg->set_points->range[i]; + if (range->set_point_max_uV > 0 + && max_uV >= range->set_point_min_uV + && max_uV <= range->set_point_max_uV) + break; + } + + if (i < 0 || range == NULL) { + vreg_err(vreg, "max_uV doesn't fit in any voltage range\n"); + return -EINVAL; + } + + rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_UL_LL_CTRL, + ®[0], 1); + if (rc) { + vreg_err(vreg, "UL_LL register read failed, rc=%d\n", + rc); + return rc; + } + + if (reg[0] & QPNP_COMMON_UL_EN_MASK) { + rc = qpnp_vreg_read(vreg, + QPNP_COMMON_REG_VOLTAGE_ULS_VALID, + ®[1], 1); + if (rc) { + vreg_err(vreg, "ULS_VALID register read failed, rc=%d\n", + rc); + return rc; + } + + limit_max_uV = range->step_uV * reg[1] + range->min_uV; + } + + if (reg[0] & QPNP_COMMON_LL_EN_MASK) { + rc = qpnp_vreg_read(vreg, + QPNP_COMMON_REG_VOLTAGE_LLS_VALID, + ®[1], 1); + if (rc) { + vreg_err(vreg, "LLS_VALID register read failed, rc=%d\n", + rc); + return rc; + } + + limit_min_uV = range->step_uV * reg[1] + range->min_uV; + } + } else if (vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS2) { + rc = qpnp_vreg_read(vreg, QPNP_COMMON2_REG_VOLTAGE_ULS_LSB, + reg, 2); + if (rc) { + vreg_err(vreg, "ULS registers read failed, rc=%d\n", + rc); + return rc; + } + + limit_max_uV = (((int)reg[1] << 8) | (int)reg[0]) * 1000; + } + + if (pdata->init_data.constraints.min_uV < limit_min_uV + || pdata->init_data.constraints.max_uV > limit_max_uV) { + vreg_err(vreg, "regulator min/max(%d/%d) constraints do not fit within HW configured min/max(%d/%d) constraints\n", + pdata->init_data.constraints.min_uV, + pdata->init_data.constraints.max_uV, + limit_min_uV, limit_max_uV); + return -EINVAL; + } + + return 0; +} + static int qpnp_regulator_ftsmps_init_slew_rate(struct qpnp_regulator *vreg) { int rc; @@ -2282,6 +2374,13 @@ static int qpnp_regulator_probe(struct platform_device *pdev) } } + rc = qpnp_regulator_check_constraints(vreg, pdata); + if (rc) { + vreg_err(vreg, "regulator constraints check failed, rc=%d\n", + rc); + goto bail; + } + rc = qpnp_regulator_init_registers(vreg, pdata); if (rc) { vreg_err(vreg, "common initialization failed, rc=%d\n", rc); diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index ed8006cacc08..ace2bc4f30b6 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -39,6 +39,8 @@ #include <asm/uaccess.h> #include <asm/setup.h> #include <asm-generic/io-64-nonatomic-lo-hi.h> +#define CREATE_TRACE_POINTS +#include <trace/events/trace_msm_pil_event.h> #include "peripheral-loader.h" @@ -835,6 +837,7 @@ int pil_boot(struct pil_desc *desc) goto release_fw; } + trace_pil_event("before_init_image", desc); if (desc->ops->init_image) ret = desc->ops->init_image(desc, fw->data, fw->size); if (ret) { @@ -843,6 +846,7 @@ int pil_boot(struct pil_desc *desc) goto err_boot; } + trace_pil_event("before_mem_setup", desc); if (desc->ops->mem_setup) ret = desc->ops->mem_setup(desc, priv->region_start, priv->region_end - priv->region_start); @@ -858,6 +862,7 @@ int pil_boot(struct pil_desc *desc) * Also for secure boot devices, modem memory has to be released * after MBA is booted */ + trace_pil_event("before_assign_mem", desc); if (desc->modem_ssr) { ret = pil_assign_mem_to_linux(desc, priv->region_start, (priv->region_end - priv->region_start)); @@ -876,6 +881,7 @@ int pil_boot(struct pil_desc *desc) hyp_assign = true; } + trace_pil_event("before_load_seg", desc); list_for_each_entry(seg, &desc->priv->segs, list) { ret = pil_load_seg(desc, seg); if (ret) @@ -883,6 +889,7 @@ int pil_boot(struct pil_desc *desc) } if (desc->subsys_vmid > 0) { + trace_pil_event("before_reclaim_mem", desc); ret = pil_reclaim_mem(desc, priv->region_start, (priv->region_end - priv->region_start), desc->subsys_vmid); @@ -894,12 +901,14 @@ int pil_boot(struct pil_desc *desc) hyp_assign = false; } + trace_pil_event("before_auth_reset", desc); ret = desc->ops->auth_and_reset(desc); if (ret) { pil_err(desc, "Failed to bring out of reset(rc:%d)\n", ret); subsys_set_error(desc->subsys_dev, firmware_error_msg); goto err_auth_and_reset; } + trace_pil_event("reset_done", desc); pil_info(desc, "Brought out of reset\n"); desc->modem_ssr = false; err_auth_and_reset: diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index 988b6e8c9fd9..5fcb0f95733c 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -26,6 +26,7 @@ #include <linux/highmem.h> #include <soc/qcom/scm.h> #include <soc/qcom/secure_buffer.h> +#include <trace/events/trace_msm_pil_event.h> #include "peripheral-loader.h" #include "pil-q6v5.h" @@ -462,6 +463,7 @@ static int pil_mss_reset(struct pil_desc *pil) phys_addr_t start_addr = pil_get_entry_addr(pil); int ret; + trace_pil_func(__func__); if (drv->mba_dp_phys) start_addr = drv->mba_dp_phys; @@ -555,6 +557,7 @@ int pil_mss_reset_load_mba(struct pil_desc *pil) const u8 *data; struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev; + trace_pil_func(__func__); fw_name_p = drv->non_elf_image ? fw_name_legacy : fw_name; ret = request_firmware(&fw, fw_name_p, pil->dev); if (ret) { @@ -685,6 +688,7 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata, DEFINE_DMA_ATTRS(attrs); + trace_pil_func(__func__); dma_dev->coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8); dma_set_attr(DMA_ATTR_SKIP_ZEROING, &attrs); dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs); diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c index 34228f072b28..15415e78f98e 100644 --- a/drivers/soc/qcom/pil-q6v5.c +++ b/drivers/soc/qcom/pil-q6v5.c @@ -22,6 +22,7 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/rpm-smd-regulator.h> #include <linux/clk/msm-clk.h> +#include <trace/events/trace_msm_pil_event.h> #include "peripheral-loader.h" #include "pil-q6v5.h" @@ -360,6 +361,7 @@ static int __pil_q6v55_reset(struct pil_desc *pil) u32 val; int i; + trace_pil_func(__func__); /* Override the ACC value if required */ if (drv->override_acc) writel_relaxed(QDSP6SS_ACC_OVERRIDE_VAL, diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index 6e7d34ac9163..d14e82415c5a 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -145,18 +145,17 @@ static int get_cmd_rsp_buffers(struct qseecom_handle *hdl, uint32_t *rsp_len) { /* 64 bytes alignment for QSEECOM */ - *cmd_len = ALIGN(*cmd_len, 64); - *rsp_len = ALIGN(*rsp_len, 64); + uint64_t aligned_cmd_len = ALIGN((uint64_t)*cmd_len, 64); + uint64_t aligned_rsp_len = ALIGN((uint64_t)*rsp_len, 64); - if (((uint64_t)*rsp_len + (uint64_t)*cmd_len) - > (uint64_t)g_app_buf_size) { - pr_err("buffer too small to hold cmd=%d and rsp=%d\n", - *cmd_len, *rsp_len); + if ((aligned_rsp_len + aligned_cmd_len) > (uint64_t)g_app_buf_size) return -ENOMEM; - } *cmd = hdl->sbuf; + *cmd_len = aligned_cmd_len; *rsp = hdl->sbuf + *cmd_len; + *rsp_len = aligned_rsp_len; + return 0; } diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index 2da8731c5753..eca992ec17e4 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -886,8 +886,10 @@ static int apr_notifier_service_cb(struct notifier_block *this, * recovery notifications during initial boot * up since everything is expected to be down. */ - if (is_initial_boot) + if (is_initial_boot) { + is_initial_boot = false; break; + } if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN) apr_modem_down(opcode); else @@ -907,7 +909,12 @@ done: return NOTIFY_OK; } -static struct notifier_block service_nb = { +static struct notifier_block adsp_service_nb = { + .notifier_call = apr_notifier_service_cb, + .priority = 0, +}; + +static struct notifier_block modem_service_nb = { .notifier_call = apr_notifier_service_cb, .priority = 0, }; @@ -937,9 +944,9 @@ static int __init apr_init(void) is_initial_boot = true; subsys_notif_register("apr_adsp", AUDIO_NOTIFIER_ADSP_DOMAIN, - &service_nb); + &adsp_service_nb); subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN, - &service_nb); + &modem_service_nb); return 0; } diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c index 04b043fbd8ec..34b46d25a823 100644 --- a/drivers/soc/qcom/smp2p_sleepstate.c +++ b/drivers/soc/qcom/smp2p_sleepstate.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,6 +46,7 @@ static int sleepstate_pm_notifier(struct notifier_block *nb, static struct notifier_block sleepstate_pm_nb = { .notifier_call = sleepstate_pm_notifier, + .priority = INT_MAX, }; static int smp2p_sleepstate_probe(struct platform_device *pdev) diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 0e1e4ae975b0..d1f300e6afb7 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -718,8 +718,10 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec) /* only one client/server may use the channel */ if (ch->ref_count) { - pr_err("channel [%s] already in use.\n", name); - goto exit_err; + pr_err("channel [%s] is BUSY, already in use by pid [%d].\n", + name, ch->pid); + mutex_unlock(&ch->lock); + return -EBUSY; } pr_debug("ch [%s] opened by PID [%d], count [%d]\n", diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 6afe2fb8cd75..ae249f382339 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -35,6 +35,7 @@ #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> #include <soc/qcom/sysmon.h> +#include <trace/events/trace_msm_pil_event.h> #include <asm/current.h> @@ -539,8 +540,10 @@ static void notify_each_subsys_device(struct subsys_device **list, notif_data.no_auth = dev->desc->no_auth; notif_data.pdev = pdev; + trace_pil_notif("before_send_notif", notif, dev->desc->fw_name); subsys_notif_queue_notification(dev->notify, notif, ¬if_data); + trace_pil_notif("after_send_notif", notif, dev->desc->fw_name); } } diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index ab7441fcf66f..46be62b737f1 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -1050,8 +1050,14 @@ static struct usb_function_instance *audio_source_alloc_inst(void) config_group_init_type_name(&fi_audio->func_inst.group, "", &audio_source_func_type); - snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH, + if (!count) { + snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH, + "f_audio_source"); + count++; + } else { + snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH, "f_audio_source%d", count++); + } dev = create_function_device(device_name); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 7d893c5815e2..d46e21bd2c68 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -187,6 +187,8 @@ static void *usbpd_ipc_log; #define PD_MAX_MSG_ID 7 +#define PD_MAX_DATA_OBJ 7 + #define PD_MSG_HDR(type, dr, pr, id, cnt, rev) \ (((type) & 0xF) | ((dr) << 5) | (rev << 6) | \ ((pr) << 8) | ((id) << 9) | ((cnt) << 12)) @@ -308,7 +310,7 @@ struct usbpd { struct list_head rx_q; spinlock_t rx_lock; - u32 received_pdos[7]; + u32 received_pdos[PD_MAX_DATA_OBJ]; u16 src_cap_id; u8 selected_pdo; u8 requested_pdo; @@ -547,6 +549,7 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua) static int pd_eval_src_caps(struct usbpd *pd) { + int obj_cnt; union power_supply_propval val; u32 first_pdo = pd->received_pdos[0]; @@ -563,6 +566,13 @@ static int pd_eval_src_caps(struct usbpd *pd) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val); + for (obj_cnt = 1; obj_cnt < PD_MAX_DATA_OBJ; obj_cnt++) { + if ((PD_SRC_PDO_TYPE(pd->received_pdos[obj_cnt]) == + PD_SRC_PDO_TYPE_AUGMENTED) && + !PD_APDO_PPS(pd->received_pdos[obj_cnt])) + pd->spec_rev = USBPD_REV_30; + } + /* Select the first PDO (vSafe5V) immediately. */ pd_select_pdo(pd, 1, 0, 0); @@ -653,12 +663,6 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, return; } - /* if spec rev differs (i.e. is older), update PHY */ - if (PD_MSG_HDR_REV(header) < pd->spec_rev) { - pd->spec_rev = PD_MSG_HDR_REV(header); - pd_phy_update_spec_rev(pd->spec_rev); - } - rx_msg = kzalloc(sizeof(*rx_msg), GFP_KERNEL); if (!rx_msg) return; @@ -701,7 +705,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) .shutdown_cb = phy_shutdown, .frame_filter_val = FRAME_FILTER_EN_SOP | FRAME_FILTER_EN_HARD_RESET, - .spec_rev = USBPD_REV_20, }; union power_supply_propval val = {0}; unsigned long flags; @@ -723,6 +726,15 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) break; /* Source states */ + case PE_SRC_DISABLED: + /* are we still connected? */ + if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) { + pd->current_pr = PR_NONE; + kick_sm(pd, 0); + } + + break; + case PE_SRC_STARTUP: if (pd->current_dr == DR_NONE) { pd->current_dr = DR_DFP; @@ -739,8 +751,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val); - /* support only PD 2.0 as a source */ - pd->spec_rev = USBPD_REV_20; pd_reset_protocol(pd); if (!pd->in_pr_swap) { @@ -751,7 +761,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) phy_params.data_role = pd->current_dr; phy_params.power_role = pd->current_pr; - phy_params.spec_rev = pd->spec_rev; ret = pd_phy_open(&phy_params); if (ret) { @@ -763,8 +772,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } pd->pd_phy_opened = true; - } else { - pd_phy_update_spec_rev(pd->spec_rev); } pd->current_state = PE_SRC_SEND_CAPABILITIES; @@ -853,6 +860,10 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SRC_HARD_RESET: case PE_SNK_HARD_RESET: + /* are we still connected? */ + if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) + pd->current_pr = PR_NONE; + /* hard reset may sleep; handle it in the workqueue */ kick_sm(pd, 0); break; @@ -896,11 +907,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) if (!val.intval) break; - /* - * support up to PD 3.0 as a sink; if source is 2.0, - * phy_msg_received() will handle the downgrade. - */ - pd->spec_rev = USBPD_REV_30; pd_reset_protocol(pd); if (!pd->in_pr_swap) { @@ -911,7 +917,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) phy_params.data_role = pd->current_dr; phy_params.power_role = pd->current_pr; - phy_params.spec_rev = pd->spec_rev; ret = pd_phy_open(&phy_params); if (ret) { @@ -923,8 +928,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } pd->pd_phy_opened = true; - } else { - pd_phy_update_spec_rev(pd->spec_rev); } pd->current_voltage = pd->requested_voltage = 5000000; @@ -1725,14 +1728,8 @@ static void usbpd_sm(struct work_struct *w) case PE_SRC_READY: if (IS_CTRL(rx_msg, MSG_GET_SOURCE_CAP)) { - ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES, - default_src_caps, - ARRAY_SIZE(default_src_caps), SOP_MSG); - if (ret) { - usbpd_err(&pd->dev, "Error sending SRC CAPs\n"); - usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); - break; - } + pd->current_state = PE_SRC_SEND_CAPABILITIES; + kick_sm(pd, 0); } else if (IS_CTRL(rx_msg, MSG_GET_SINK_CAP)) { ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, pd->sink_caps, pd->num_sink_caps, @@ -2308,6 +2305,14 @@ static void usbpd_sm(struct work_struct *w) sm_done: kfree(rx_msg); + spin_lock_irqsave(&pd->rx_lock, flags); + ret = list_empty(&pd->rx_q); + spin_unlock_irqrestore(&pd->rx_lock, flags); + + /* requeue if there are any new/pending RX messages */ + if (!ret) + kick_sm(pd, 0); + if (!pd->sm_queued) pm_relax(&pd->dev); } @@ -3299,6 +3304,8 @@ struct usbpd *usbpd_create(struct device *parent) pd->dual_role->drv_data = pd; } + /* default support as PD 2.0 source or sink */ + pd->spec_rev = USBPD_REV_20; pd->current_pr = PR_NONE; pd->current_dr = DR_NONE; list_add_tail(&pd->instance, &_usbpd); diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index 588af94db6cd..fa3b71d6ce08 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -334,15 +334,6 @@ int pd_phy_update_roles(enum data_role dr, enum power_role pr) } EXPORT_SYMBOL(pd_phy_update_roles); -int pd_phy_update_spec_rev(enum pd_spec_rev rev) -{ - struct usb_pdphy *pdphy = __pdphy; - - return pdphy_masked_write(pdphy, USB_PDPHY_MSG_CONFIG, - MSG_CONFIG_SPEC_REV_MASK, rev); -} -EXPORT_SYMBOL(pd_phy_update_spec_rev); - int pd_phy_open(struct pd_phy_params *params) { int ret; @@ -377,7 +368,9 @@ int pd_phy_open(struct pd_phy_params *params) if (ret) return ret; - ret = pd_phy_update_spec_rev(params->spec_rev); + /* PD 2.0 phy */ + ret = pdphy_masked_write(pdphy, USB_PDPHY_MSG_CONFIG, + MSG_CONFIG_SPEC_REV_MASK, USBPD_REV_20); if (ret) return ret; diff --git a/drivers/usb/pd/usbpd.h b/drivers/usb/pd/usbpd.h index b2663add7f3c..108701739f89 100644 --- a/drivers/usb/pd/usbpd.h +++ b/drivers/usb/pd/usbpd.h @@ -68,7 +68,6 @@ struct pd_phy_params { enum data_role data_role; enum power_role power_role; u8 frame_filter_val; - u8 spec_rev; }; #if IS_ENABLED(CONFIG_QPNP_USB_PDPHY) @@ -77,7 +76,6 @@ int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms); int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_msg_type type, unsigned int timeout_ms); int pd_phy_update_roles(enum data_role dr, enum power_role pr); -int pd_phy_update_spec_rev(enum pd_spec_rev rev); void pd_phy_close(void); #else static inline int pd_phy_open(struct pd_phy_params *params) @@ -101,11 +99,6 @@ static inline int pd_phy_update_roles(enum data_role dr, enum power_role pr) return -ENODEV; } -static inline int pd_phy_update_spec_rev(enum pd_spec_rev rev) -{ - return -ENODEV; -} - static inline void pd_phy_close(void) { } diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 797c8b4a2eb1..d5caf0e6bb1c 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1815,7 +1815,7 @@ static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata) return 0; } -irqreturn_t test_hw_vsync_handler(int irq, void *data) +static irqreturn_t test_hw_vsync_handler(int irq, void *data) { struct mdss_panel_data *pdata = (struct mdss_panel_data *)data; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index fc5243c331c4..420f623e3441 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1518,6 +1518,9 @@ struct reclaim_param reclaim_task_anon(struct task_struct *task, if (vma->vm_file) continue; + if (vma->vm_flags & VM_LOCKED) + continue; + if (!rp.nr_to_reclaim) break; diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h index c01cb1af4231..01fe2e78b9d5 100644 --- a/include/linux/msm_mhi.h +++ b/include/linux/msm_mhi.h @@ -81,6 +81,7 @@ enum MHI_CB_REASON { MHI_CB_MHI_SHUTDOWN, MHI_CB_SYS_ERROR, MHI_CB_RDDM, + MHI_CB_MHI_PROBED, }; enum MHI_FLAGS { @@ -119,6 +120,7 @@ struct mhi_client_handle { u32 domain; u32 bus; u32 slot; + bool enabled; struct mhi_client_config *client_config; }; @@ -168,6 +170,7 @@ enum mhi_rddm_segment { MHI_RDDM_RD_SEGMENT, }; +#if defined(CONFIG_MSM_MHI) /** * mhi_is_device_ready - Check if MHI is ready to register clients * @@ -187,11 +190,23 @@ bool mhi_is_device_ready(const struct device * const dev, * @userdata: cb data for client * @Return 0 on success */ -int mhi_register_device(struct mhi_device *mhi_device, - const char *node_name, +int mhi_register_device(struct mhi_device *mhi_device, const char *node_name, void *user_data); /** + * mhi_register_channel - Client must call this function to obtain a handle for + * any MHI operations + * + * @client_handle: Handle populated by MHI, opaque to client + * @client_info: Channel\device information provided by client to + * which the handle maps to. + * + * @Return errno + */ +int mhi_register_channel(struct mhi_client_handle **client_handle, + struct mhi_client_info_t *client_info); + +/** * mhi_pm_control_device - power management control api * @mhi_device: registered device structure * @ctrl: specific command @@ -219,19 +234,6 @@ int mhi_xfer_rddm(struct mhi_device *mhi_device, enum mhi_rddm_segment seg, int mhi_deregister_channel(struct mhi_client_handle *client_handle); /** - * mhi_register_channel - Client must call this function to obtain a handle for - * any MHI operations - * - * @client_handle: Handle populated by MHI, opaque to client - * @client_info: Channel\device information provided by client to - * which the handle maps to. - * - * @Return errno - */ -int mhi_register_channel(struct mhi_client_handle **client_handle, - struct mhi_client_info_t *client_info); - -/** * mhi_open_channel - Client must call this function to open a channel * * @client_handle: Handle populated by MHI, opaque to client @@ -258,8 +260,8 @@ int mhi_open_channel(struct mhi_client_handle *client_handle); * * @Return errno */ -int mhi_queue_xfer(struct mhi_client_handle *client_handle, - void *buf, size_t buf_len, enum MHI_FLAGS mhi_flags); +int mhi_queue_xfer(struct mhi_client_handle *client_handle, void *buf, + size_t buf_len, enum MHI_FLAGS mhi_flags); /** * mhi_close_channel - Client can request channel to be closed and handle freed @@ -300,7 +302,7 @@ int mhi_get_free_desc(struct mhi_client_handle *client_handle); * @Return non negative on success */ int mhi_poll_inbound(struct mhi_client_handle *client_handle, - struct mhi_result *result); + struct mhi_result *result); /** * mhi_get_max_desc - Get the maximum number of descriptors @@ -311,12 +313,107 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle, */ int mhi_get_max_desc(struct mhi_client_handle *client_handle); -/* RmNET Reserved APIs, This APIs are reserved for use by the linux network -* stack only. Use by other clients will introduce system wide issues -*/ +/* following APIs meant to be used by rmnet interface only */ int mhi_set_lpm(struct mhi_client_handle *client_handle, bool enable_lpm); int mhi_get_epid(struct mhi_client_handle *mhi_handle); struct mhi_result *mhi_poll(struct mhi_client_handle *client_handle); void mhi_mask_irq(struct mhi_client_handle *client_handle); void mhi_unmask_irq(struct mhi_client_handle *client_handle); + +#else +static inline bool mhi_is_device_ready(const struct device * const dev, + const char *node_name) +{ + return false; +}; + +static inline int mhi_register_device(struct mhi_device *mhi_device, + const char *node_name, void *user_data) +{ + return -EINVAL; +}; + +static inline int mhi_register_channel(struct mhi_client_handle **client_handle, + struct mhi_client_info_t *client_info) +{ + return -EINVAL; +}; + +static inline int mhi_pm_control_device(struct mhi_device *mhi_device, + enum mhi_dev_ctrl ctrl) +{ + return -EINVAL; +}; + +static inline int mhi_xfer_rddm(struct mhi_device *mhi_device, + enum mhi_rddm_segment seg, + struct scatterlist **sg_list) +{ + return -EINVAL; +}; + +static inline int mhi_deregister_channel(struct mhi_client_handle + *client_handle) +{ + return -EINVAL; +}; + +static inline int mhi_open_channel(struct mhi_client_handle *client_handle) +{ + return -EINVAL; +}; + +static inline int mhi_queue_xfer(struct mhi_client_handle *client_handle, + void *buf, size_t buf_len, + enum MHI_FLAGS mhi_flags) +{ + return -EINVAL; +}; + +static inline void mhi_close_channel(struct mhi_client_handle *client_handle) +{ +}; + +static inline int mhi_get_free_desc(struct mhi_client_handle *client_handle) +{ + return -EINVAL; +}; + +static inline int mhi_poll_inbound(struct mhi_client_handle *client_handle, + struct mhi_result *result) +{ + return -EINVAL; +}; + +static inline int mhi_get_max_desc(struct mhi_client_handle *client_handle) +{ + return -EINVAL; +}; + +static inline int mhi_set_lpm(struct mhi_client_handle *client_handle, + bool enable_lpm) +{ + return -EINVAL; +}; + +static inline int mhi_get_epid(struct mhi_client_handle *mhi_handle) +{ + return -EINVAL; +}; + +static inline struct mhi_result *mhi_poll(struct mhi_client_handle + *client_handle) +{ + return NULL; +}; + +static inline void mhi_mask_irq(struct mhi_client_handle *client_handle) +{ +}; + +static inline void mhi_unmask_irq(struct mhi_client_handle *client_handle) +{ +}; + +#endif #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index c71978453864..138fcf72508a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -178,7 +178,9 @@ extern u64 nr_running_integral(unsigned int cpu); #endif extern void sched_update_nr_prod(int cpu, long delta, bool inc); -extern void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg); +extern void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg, + unsigned int *max_nr, + unsigned int *big_max_nr); extern void calc_global_load(unsigned long ticks); diff --git a/include/linux/sde_io_util.h b/include/linux/sde_io_util.h index 6bd5c168ecd8..da4a50722984 100644 --- a/include/linux/sde_io_util.h +++ b/include/linux/sde_io_util.h @@ -58,6 +58,8 @@ struct dss_vreg { int post_on_sleep; int pre_off_sleep; int post_off_sleep; + bool lp_disable_allowed; + bool disabled; }; struct dss_gpio { diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 1f19ff2210f8..74995a0cdbad 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -44,6 +44,8 @@ struct param_outband { #define ADM_MATRIX_ID_COMPRESSED_AUDIO_RX 2 +#define ADM_MATRIX_ID_COMPRESSED_AUDIO_TX 3 + #define ADM_MATRIX_ID_LISTEN_TX 4 /* Enumeration for an audio Tx matrix ID.*/ #define ADM_MATRIX_ID_AUDIOX 1 @@ -446,6 +448,9 @@ struct adm_param_data_v5 { #define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213 #define ASM_STREAM_PP_EVENT 0x00013214 +#define ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE 0x13333 +#define ASM_IEC_61937_MEDIA_FMT_EVENT 0x13334 + #define DSP_STREAM_CMD "ADSP Stream Cmd" #define DSP_STREAM_CALLBACK "ADSP Stream Callback Event" #define DSP_STREAM_CALLBACK_QUEUE_SIZE 1024 diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h index caabb66bd0b4..900d2455993a 100644 --- a/include/sound/q6adm-v2.h +++ b/include/sound/q6adm-v2.h @@ -17,6 +17,7 @@ #define ADM_PATH_LIVE_REC 0x2 #define ADM_PATH_NONLIVE_REC 0x3 #define ADM_PATH_COMPRESSED_RX 0x5 +#define ADM_PATH_COMPRESSED_TX 0x6 #include <linux/qdsp6v2/rtac.h> #include <sound/q6afe-v2.h> #include <sound/q6audio-v2.h> diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 0b92317f6263..9a1ff42a377e 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -1312,24 +1312,30 @@ TRACE_EVENT(sched_wake_idle_without_ipi, TRACE_EVENT(sched_get_nr_running_avg, - TP_PROTO(int avg, int big_avg, int iowait_avg), + TP_PROTO(int avg, int big_avg, int iowait_avg, + unsigned int max_nr, unsigned int big_max_nr), - TP_ARGS(avg, big_avg, iowait_avg), + TP_ARGS(avg, big_avg, iowait_avg, max_nr, big_max_nr), TP_STRUCT__entry( __field( int, avg ) __field( int, big_avg ) __field( int, iowait_avg ) + __field( unsigned int, max_nr ) + __field( unsigned int, big_max_nr ) ), TP_fast_assign( __entry->avg = avg; __entry->big_avg = big_avg; __entry->iowait_avg = iowait_avg; + __entry->max_nr = max_nr; + __entry->big_max_nr = big_max_nr; ), - TP_printk("avg=%d big_avg=%d iowait_avg=%d", - __entry->avg, __entry->big_avg, __entry->iowait_avg) + TP_printk("avg=%d big_avg=%d iowait_avg=%d max_nr=%u big_max_nr=%u", + __entry->avg, __entry->big_avg, __entry->iowait_avg, + __entry->max_nr, __entry->big_max_nr) ); TRACE_EVENT(core_ctl_eval_need, diff --git a/include/trace/events/trace_msm_pil_event.h b/include/trace/events/trace_msm_pil_event.h new file mode 100644 index 000000000000..4795dc5e0b2e --- /dev/null +++ b/include/trace/events/trace_msm_pil_event.h @@ -0,0 +1,88 @@ +/* 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. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM msm_pil_event + +#if !defined(_TRACE_MSM_PIL_EVENT_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MSM_PIL_EVENT_H_ + +#include <linux/tracepoint.h> +#include <../drivers/soc/qcom/peripheral-loader.h> + +TRACE_EVENT(pil_event, + + TP_PROTO(const char *event_name, struct pil_desc *desc), + + TP_ARGS(event_name, desc), + + TP_STRUCT__entry( + __string(event_name, event_name) + __string(fw_name, desc->fw_name) + ), + + TP_fast_assign( + __assign_str(event_name, event_name); + __assign_str(fw_name, desc->fw_name); + ), + + TP_printk("event_name=%s fw_name=%s", + __get_str(event_name), + __get_str(fw_name)) +); + +TRACE_EVENT(pil_notif, + + TP_PROTO(const char *event_name, unsigned long code, + const char *fw_name), + + TP_ARGS(event_name, code, fw_name), + + TP_STRUCT__entry( + __string(event_name, event_name) + __field(unsigned long, code) + __string(fw_name, fw_name) + ), + + TP_fast_assign( + __assign_str(event_name, event_name); + __entry->code = code; + __assign_str(fw_name, fw_name); + ), + + TP_printk("event_name=%s code=%lu fw=%s", + __get_str(event_name), + __entry->code, + __get_str(fw_name)) +); + +TRACE_EVENT(pil_func, + + TP_PROTO(const char *func_name), + + TP_ARGS(func_name), + + TP_STRUCT__entry( + __string(func_name, func_name) + ), + + TP_fast_assign( + __assign_str(func_name, func_name); + ), + + TP_printk("func_name=%s", + __get_str(func_name)) +); + +#endif +#define TRACE_INCLUDE_FILE trace_msm_pil_event +#include <trace/define_trace.h> diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index 0b5f2dea18a1..ce15ae7fe76b 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -39,11 +39,13 @@ struct cluster_data { cpumask_t cpu_mask; unsigned int need_cpus; unsigned int task_thres; + unsigned int max_nr; s64 need_ts; struct list_head lru; bool pending; spinlock_t pending_lock; bool is_big_cluster; + bool enable; int nrrun; bool nrrun_changed; struct task_struct *core_ctl_thread; @@ -60,6 +62,7 @@ struct cpu_data { struct cluster_data *cluster; struct list_head sib; bool isolated_by_us; + unsigned int max_nr; }; static DEFINE_PER_CPU(struct cpu_data, cpu_state); @@ -244,6 +247,29 @@ static ssize_t show_is_big_cluster(const struct cluster_data *state, char *buf) return snprintf(buf, PAGE_SIZE, "%u\n", state->is_big_cluster); } +static ssize_t store_enable(struct cluster_data *state, + const char *buf, size_t count) +{ + unsigned int val; + bool bval; + + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + + bval = !!val; + if (bval != state->enable) { + state->enable = bval; + apply_need(state); + } + + return count; +} + +static ssize_t show_enable(const struct cluster_data *state, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%u\n", state->enable); +} + static ssize_t show_need_cpus(const struct cluster_data *state, char *buf) { return snprintf(buf, PAGE_SIZE, "%u\n", state->need_cpus); @@ -372,6 +398,7 @@ core_ctl_attr_ro(need_cpus); core_ctl_attr_ro(active_cpus); core_ctl_attr_ro(global_state); core_ctl_attr_rw(not_preferred); +core_ctl_attr_rw(enable); static struct attribute *default_attrs[] = { &min_cpus.attr, @@ -381,6 +408,7 @@ static struct attribute *default_attrs[] = { &busy_down_thres.attr, &task_thres.attr, &is_big_cluster.attr, + &enable.attr, &need_cpus.attr, &active_cpus.attr, &global_state.attr, @@ -429,7 +457,6 @@ static struct kobj_type ktype_core_ctl = { #define RQ_AVG_TOLERANCE 2 #define RQ_AVG_DEFAULT_MS 20 -#define NR_RUNNING_TOLERANCE 5 static unsigned int rq_avg_period_ms = RQ_AVG_DEFAULT_MS; static s64 rq_avg_timestamp_ms; @@ -437,6 +464,7 @@ static s64 rq_avg_timestamp_ms; static void update_running_avg(bool trigger_update) { int avg, iowait_avg, big_avg, old_nrrun; + int old_max_nr, max_nr, big_max_nr; s64 now; unsigned long flags; struct cluster_data *cluster; @@ -450,40 +478,23 @@ static void update_running_avg(bool trigger_update) return; } rq_avg_timestamp_ms = now; - sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg); + sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg, + &max_nr, &big_max_nr); spin_unlock_irqrestore(&state_lock, flags); - /* - * Round up to the next integer if the average nr running tasks - * is within NR_RUNNING_TOLERANCE/100 of the next integer. - * If normal rounding up is used, it will allow a transient task - * to trigger online event. By the time core is onlined, the task - * has finished. - * Rounding to closest suffers same problem because scheduler - * might only provide running stats per jiffy, and a transient - * task could skew the number for one jiffy. If core control - * samples every 2 jiffies, it will observe 0.5 additional running - * average which rounds up to 1 task. - */ - avg = (avg + NR_RUNNING_TOLERANCE) / 100; - big_avg = (big_avg + NR_RUNNING_TOLERANCE) / 100; - for_each_cluster(cluster, index) { if (!cluster->inited) continue; + old_nrrun = cluster->nrrun; - /* - * Big cluster only need to take care of big tasks, but if - * there are not enough big cores, big tasks need to be run - * on little as well. Thus for little's runqueue stat, it - * has to use overall runqueue average, or derive what big - * tasks would have to be run on little. The latter approach - * is not easy to get given core control reacts much slower - * than scheduler, and can't predict scheduler's behavior. - */ + old_max_nr = cluster->max_nr; cluster->nrrun = cluster->is_big_cluster ? big_avg : avg; - if (cluster->nrrun != old_nrrun) { + cluster->max_nr = cluster->is_big_cluster ? big_max_nr : max_nr; + + if (cluster->nrrun != old_nrrun || + cluster->max_nr != old_max_nr) { + if (trigger_update) apply_need(cluster); else @@ -493,6 +504,7 @@ static void update_running_avg(bool trigger_update) return; } +#define MAX_NR_THRESHOLD 4 /* adjust needed CPUs based on current runqueue information */ static unsigned int apply_task_need(const struct cluster_data *cluster, unsigned int new_need) @@ -503,7 +515,15 @@ static unsigned int apply_task_need(const struct cluster_data *cluster, /* only unisolate more cores if there are tasks to run */ if (cluster->nrrun > new_need) - return new_need + 1; + new_need = new_need + 1; + + /* + * We don't want tasks to be overcrowded in a cluster. + * If any CPU has more than MAX_NR_THRESHOLD in the last + * window, bring another CPU to help out. + */ + if (cluster->max_nr > MAX_NR_THRESHOLD) + new_need = new_need + 1; return new_need; } @@ -549,7 +569,7 @@ static bool eval_need(struct cluster_data *cluster) spin_lock_irqsave(&state_lock, flags); - if (cluster->boost) { + if (cluster->boost || !cluster->enable) { need_cpus = cluster->max_cpus; } else { cluster->active_cpus = get_active_cpu_count(cluster); @@ -1046,6 +1066,7 @@ static int cluster_init(const struct cpumask *mask) cluster->offline_delay_ms = 100; cluster->task_thres = UINT_MAX; cluster->nrrun = cluster->num_cpus; + cluster->enable = true; INIT_LIST_HEAD(&cluster->lru); spin_lock_init(&cluster->pending_lock); diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index df47c26ab6d2..37d24bb17c76 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -1602,7 +1602,7 @@ unsigned int nr_eligible_big_tasks(int cpu) int nr_big = rq->hmp_stats.nr_big_tasks; int nr = rq->nr_running; - if (cpu_max_possible_capacity(cpu) != max_possible_capacity) + if (!is_max_capacity_cpu(cpu)) return nr_big; return nr; @@ -4303,8 +4303,20 @@ void note_task_waking(struct task_struct *p, u64 wallclock) { u64 sleep_time = wallclock - p->last_switch_out_ts; - p->last_wake_ts = wallclock; + /* + * When a short burst and short sleeping task goes for a long + * sleep, the task's avg_sleep_time gets boosted. It will not + * come below short_sleep threshold for a lot of time and it + * results in incorrect packing. The idead behind tracking + * avg_sleep_time is to detect if a task is short sleeping + * or not. So limit the sleep time to twice the short sleep + * threshold. For regular long sleeping tasks, the avg_sleep_time + * would be higher than threshold, and packing happens correctly. + */ + sleep_time = min_t(u64, sleep_time, 2 * sysctl_sched_short_sleep); update_avg(&p->ravg.avg_sleep_time, sleep_time); + + p->last_wake_ts = wallclock; } #ifdef CONFIG_CGROUP_SCHED diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 276a2387f06f..2beda41af443 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1225,6 +1225,11 @@ static inline bool hmp_capable(void) return max_possible_capacity != min_max_possible_capacity; } +static inline bool is_max_capacity_cpu(int cpu) +{ + return cpu_max_possible_capacity(cpu) == max_possible_capacity; +} + /* * 'load' is in reference to "best cpu" at its best frequency. * Scale that in reference to a given cpu, accounting for how bad it is @@ -1601,6 +1606,8 @@ static inline unsigned int nr_eligible_big_tasks(int cpu) return 0; } +static inline bool is_max_capacity_cpu(int cpu) { return true; } + static inline int pct_task_load(struct task_struct *p) { return 0; } static inline int cpu_capacity(int cpu) diff --git a/kernel/sched/sched_avg.c b/kernel/sched/sched_avg.c index 29d8a26a78ed..ba5a326a9fd8 100644 --- a/kernel/sched/sched_avg.c +++ b/kernel/sched/sched_avg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012, 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 @@ -26,11 +26,13 @@ static DEFINE_PER_CPU(u64, nr_prod_sum); static DEFINE_PER_CPU(u64, last_time); static DEFINE_PER_CPU(u64, nr_big_prod_sum); static DEFINE_PER_CPU(u64, nr); +static DEFINE_PER_CPU(u64, nr_max); static DEFINE_PER_CPU(unsigned long, iowait_prod_sum); static DEFINE_PER_CPU(spinlock_t, nr_lock) = __SPIN_LOCK_UNLOCKED(nr_lock); static s64 last_get_time; +#define DIV64_U64_ROUNDUP(X, Y) div64_u64((X) + (Y - 1), Y) /** * sched_get_nr_running_avg * @return: Average nr_running, iowait and nr_big_tasks value since last poll. @@ -40,7 +42,8 @@ static s64 last_get_time; * Obtains the average nr_running value since the last poll. * This function may not be called concurrently with itself */ -void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg) +void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg, + unsigned int *max_nr, unsigned int *big_max_nr) { int cpu; u64 curr_time = sched_clock(); @@ -50,6 +53,8 @@ void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg) *avg = 0; *iowait_avg = 0; *big_avg = 0; + *max_nr = 0; + *big_max_nr = 0; if (!diff) return; @@ -78,17 +83,35 @@ void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg) per_cpu(nr_big_prod_sum, cpu) = 0; per_cpu(iowait_prod_sum, cpu) = 0; + if (*max_nr < per_cpu(nr_max, cpu)) + *max_nr = per_cpu(nr_max, cpu); + + if (is_max_capacity_cpu(cpu)) { + if (*big_max_nr < per_cpu(nr_max, cpu)) + *big_max_nr = per_cpu(nr_max, cpu); + } + + per_cpu(nr_max, cpu) = per_cpu(nr, cpu); spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags); } diff = curr_time - last_get_time; last_get_time = curr_time; - *avg = (int)div64_u64(tmp_avg * 100, diff); - *big_avg = (int)div64_u64(tmp_big_avg * 100, diff); - *iowait_avg = (int)div64_u64(tmp_iowait * 100, diff); - - trace_sched_get_nr_running_avg(*avg, *big_avg, *iowait_avg); + /* + * Any task running on BIG cluster and BIG tasks running on little + * cluster contributes to big_avg. Small or medium tasks can also + * run on BIG cluster when co-location and scheduler boost features + * are activated. We don't want these tasks to downmigrate to little + * cluster when BIG CPUs are available but isolated. Round up the + * average values so that core_ctl aggressively unisolate BIG CPUs. + */ + *avg = (int)DIV64_U64_ROUNDUP(tmp_avg, diff); + *big_avg = (int)DIV64_U64_ROUNDUP(tmp_big_avg, diff); + *iowait_avg = (int)DIV64_U64_ROUNDUP(tmp_iowait, diff); + + trace_sched_get_nr_running_avg(*avg, *big_avg, *iowait_avg, + *max_nr, *big_max_nr); BUG_ON(*avg < 0 || *big_avg < 0 || *iowait_avg < 0); pr_debug("%s - avg:%d big_avg:%d iowait_avg:%d\n", @@ -121,6 +144,9 @@ void sched_update_nr_prod(int cpu, long delta, bool inc) BUG_ON((s64)per_cpu(nr, cpu) < 0); + if (per_cpu(nr, cpu) > per_cpu(nr_max, cpu)) + per_cpu(nr_max, cpu) = per_cpu(nr, cpu); + per_cpu(nr_prod_sum, cpu) += nr_running * diff; per_cpu(nr_big_prod_sum, cpu) += nr_eligible_big_tasks(cpu) * diff; per_cpu(iowait_prod_sum, cpu) += nr_iowait_cpu(cpu) * diff; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index b855352167b1..5474dc7c125a 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1200,12 +1200,7 @@ tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int enable_flow) qdisc_len = q->q.qlen; if (q->ops->change(q, &req.attr) != 0) pr_err("%s(): qdisc change failed", __func__); - } else { - WARN_ONCE(1, "%s(): called on queue which does %s", - __func__, "not support change() operation"); } - } else { - WARN_ONCE(1, "%s(): called on bad queue", __func__); } return qdisc_len; } diff --git a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c index 4cbdb728ef41..1b51805bb92e 100644 --- a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c +++ b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c @@ -220,3 +220,100 @@ const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER] = { [MSM_SDW_TOP_I2S_RESET] = 1, [MSM_SDW_TOP_BLOCKS_RESET] = 1, }; + +const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER] = { + [MSM_SDW_PAGE_REGISTER] = 1, + [MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 1, + [MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 1, + [MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 1, + [MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 1, + [MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 1, + [MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 1, + [MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 1, + [MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 1, + [MSM_SDW_COMPANDER7_CTL0] = 1, + [MSM_SDW_COMPANDER7_CTL1] = 1, + [MSM_SDW_COMPANDER7_CTL2] = 1, + [MSM_SDW_COMPANDER7_CTL3] = 1, + [MSM_SDW_COMPANDER7_CTL4] = 1, + [MSM_SDW_COMPANDER7_CTL5] = 1, + [MSM_SDW_COMPANDER7_CTL7] = 1, + [MSM_SDW_COMPANDER8_CTL0] = 1, + [MSM_SDW_COMPANDER8_CTL1] = 1, + [MSM_SDW_COMPANDER8_CTL2] = 1, + [MSM_SDW_COMPANDER8_CTL3] = 1, + [MSM_SDW_COMPANDER8_CTL4] = 1, + [MSM_SDW_COMPANDER8_CTL5] = 1, + [MSM_SDW_COMPANDER8_CTL7] = 1, + [MSM_SDW_RX7_RX_PATH_CTL] = 1, + [MSM_SDW_RX7_RX_PATH_CFG0] = 1, + [MSM_SDW_RX7_RX_PATH_CFG1] = 1, + [MSM_SDW_RX7_RX_PATH_CFG2] = 1, + [MSM_SDW_RX7_RX_VOL_CTL] = 1, + [MSM_SDW_RX7_RX_PATH_MIX_CTL] = 1, + [MSM_SDW_RX7_RX_PATH_MIX_CFG] = 1, + [MSM_SDW_RX7_RX_VOL_MIX_CTL] = 1, + [MSM_SDW_RX7_RX_PATH_SEC0] = 1, + [MSM_SDW_RX7_RX_PATH_SEC1] = 1, + [MSM_SDW_RX7_RX_PATH_SEC2] = 1, + [MSM_SDW_RX7_RX_PATH_SEC3] = 1, + [MSM_SDW_RX7_RX_PATH_SEC5] = 1, + [MSM_SDW_RX7_RX_PATH_SEC6] = 1, + [MSM_SDW_RX7_RX_PATH_SEC7] = 1, + [MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 1, + [MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 1, + [MSM_SDW_RX8_RX_PATH_CTL] = 1, + [MSM_SDW_RX8_RX_PATH_CFG0] = 1, + [MSM_SDW_RX8_RX_PATH_CFG1] = 1, + [MSM_SDW_RX8_RX_PATH_CFG2] = 1, + [MSM_SDW_RX8_RX_VOL_CTL] = 1, + [MSM_SDW_RX8_RX_PATH_MIX_CTL] = 1, + [MSM_SDW_RX8_RX_PATH_MIX_CFG] = 1, + [MSM_SDW_RX8_RX_VOL_MIX_CTL] = 1, + [MSM_SDW_RX8_RX_PATH_SEC0] = 1, + [MSM_SDW_RX8_RX_PATH_SEC1] = 1, + [MSM_SDW_RX8_RX_PATH_SEC2] = 1, + [MSM_SDW_RX8_RX_PATH_SEC3] = 1, + [MSM_SDW_RX8_RX_PATH_SEC5] = 1, + [MSM_SDW_RX8_RX_PATH_SEC6] = 1, + [MSM_SDW_RX8_RX_PATH_SEC7] = 1, + [MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 1, + [MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 1, + [MSM_SDW_BOOST0_BOOST_PATH_CTL] = 1, + [MSM_SDW_BOOST0_BOOST_CTL] = 1, + [MSM_SDW_BOOST0_BOOST_CFG1] = 1, + [MSM_SDW_BOOST0_BOOST_CFG2] = 1, + [MSM_SDW_BOOST1_BOOST_PATH_CTL] = 1, + [MSM_SDW_BOOST1_BOOST_CTL] = 1, + [MSM_SDW_BOOST1_BOOST_CFG1] = 1, + [MSM_SDW_BOOST1_BOOST_CFG2] = 1, + [MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 1, + [MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 1, + [MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 1, + [MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 1, + [MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 1, + [MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 1, + [MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 1, + [MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 1, + [MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 1, + [MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 1, + [MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 1, + [MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 1, + [MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 1, + [MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 1, + [MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 1, + [MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 1, + [MSM_SDW_TOP_TOP_CFG0] = 1, + [MSM_SDW_TOP_TOP_CFG1] = 1, + [MSM_SDW_TOP_RX_I2S_CTL] = 1, + [MSM_SDW_TOP_TX_I2S_CTL] = 1, + [MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 1, + [MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 1, + [MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 1, + [MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 1, + [MSM_SDW_TOP_FREQ_MCLK] = 1, + [MSM_SDW_TOP_DEBUG_BUS_SEL] = 1, + [MSM_SDW_TOP_DEBUG_EN] = 1, + [MSM_SDW_TOP_I2S_RESET] = 1, + [MSM_SDW_TOP_BLOCKS_RESET] = 1, +}; diff --git a/sound/soc/codecs/msm_sdw/msm_sdw.h b/sound/soc/codecs/msm_sdw/msm_sdw.h index 8e7612c85455..db991481e07d 100644 --- a/sound/soc/codecs/msm_sdw/msm_sdw.h +++ b/sound/soc/codecs/msm_sdw/msm_sdw.h @@ -21,6 +21,7 @@ extern const struct regmap_config msm_sdw_regmap_config; extern const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER]; extern const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER]; +extern const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER]; enum { MSM_SDW_RX4 = 0, diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c index db723e5ec1f4..b91d13c8e010 100644 --- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c +++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c @@ -1668,8 +1668,10 @@ static int msm_sdw_notifier_service_cb(struct notifier_block *nb, mutex_lock(&msm_sdw->codec_mutex); switch (opcode) { case AUDIO_NOTIFIER_SERVICE_DOWN: - if (initial_boot) + if (initial_boot) { + initial_boot = false; break; + } msm_sdw->int_mclk1_enabled = false; msm_sdw->dev_up = false; for (i = 0; i < msm_sdw->nr; i++) diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c index e79db0ab17be..22663384ec35 100644 --- a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c +++ b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -115,6 +115,11 @@ static bool msm_sdw_is_readable_register(struct device *dev, unsigned int reg) return msm_sdw_reg_readable[reg]; } +static bool msm_sdw_is_writeable_register(struct device *dev, unsigned int reg) +{ + return msm_sdw_reg_writeable[reg]; +} + static bool msm_sdw_is_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { @@ -150,6 +155,7 @@ const struct regmap_config msm_sdw_regmap_config = { .reg_defaults = msm_sdw_defaults, .num_reg_defaults = ARRAY_SIZE(msm_sdw_defaults), .max_register = MSM_SDW_MAX_REGISTER, + .writeable_reg = msm_sdw_is_writeable_register, .volatile_reg = msm_sdw_is_volatile_register, .readable_reg = msm_sdw_is_readable_register, }; diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index 9eaf6cc7b89b..00f2aa766363 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -3813,8 +3813,10 @@ static int sdm660_cdc_notifier_service_cb(struct notifier_block *nb, switch (opcode) { case AUDIO_NOTIFIER_SERVICE_DOWN: - if (initial_boot) + if (initial_boot) { + initial_boot = false; break; + } dev_dbg(codec->dev, "ADSP is about to power down. teardown/reset codec\n"); msm_anlg_cdc_device_down(codec); diff --git a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h index 7a63a71ceeb1..5d5cee124bca 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h +++ b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* 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 @@ -19,6 +19,7 @@ extern struct reg_default msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE]; bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg); +bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg); bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg); enum { diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index 6c702c8fc35f..4249ada17c87 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -77,8 +77,8 @@ static int msm_digcdc_clock_control(bool flag) pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card); - mutex_lock(&pdata->cdc_int_mclk0_mutex); if (flag) { + mutex_lock(&pdata->cdc_int_mclk0_mutex); if (atomic_read(&pdata->int_mclk0_enabled) == false) { pdata->digital_cdc_core_clk.enable = 1; ret = afe_set_lpass_clock_v2( @@ -93,7 +93,6 @@ static int msm_digcdc_clock_control(bool flag) */ if (ret == -ENODEV) msm_dig_cdc->regmap->cache_only = true; - mutex_unlock(&pdata->cdc_int_mclk0_mutex); return ret; } pr_debug("enabled digital codec core clk\n"); @@ -102,10 +101,10 @@ static int msm_digcdc_clock_control(bool flag) 50); } } else { + mutex_unlock(&pdata->cdc_int_mclk0_mutex); dev_dbg(registered_digcodec->dev, "disable MCLK, workq to disable set already\n"); } - mutex_unlock(&pdata->cdc_int_mclk0_mutex); return 0; } @@ -116,6 +115,7 @@ static void enable_digital_callback(void *flag) static void disable_digital_callback(void *flag) { + msm_digcdc_clock_control(false); pr_debug("disable mclk happens in workq\n"); } @@ -982,6 +982,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block, struct snd_soc_codec *codec = registered_digcodec; struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec); struct msm_asoc_mach_data *pdata = NULL; + int ret = -EINVAL; pdata = snd_soc_card_get_drvdata(codec->component.card); @@ -1073,7 +1074,28 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block, case DIG_CDC_EVENT_SSR_UP: regcache_cache_only(msm_dig_cdc->regmap, false); regcache_mark_dirty(msm_dig_cdc->regmap); + + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 1; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_INT0_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s:failed to enable the MCLK\n", + __func__); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + break; + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + regcache_sync(msm_dig_cdc->regmap); + + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2( + AFE_PORT_ID_INT0_MI2S_RX, + &pdata->digital_cdc_core_clk); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); break; case DIG_CDC_EVENT_INVALID: default: @@ -2033,6 +2055,7 @@ const struct regmap_config msm_digital_regmap_config = { .cache_type = REGCACHE_FLAT, .reg_defaults = msm89xx_cdc_core_defaults, .num_reg_defaults = MSM89XX_CDC_CORE_MAX_REGISTER, + .writeable_reg = msm89xx_cdc_core_writeable_reg, .readable_reg = msm89xx_cdc_core_readable_reg, .volatile_reg = msm89xx_cdc_core_volatile_reg, .reg_format_endian = REGMAP_ENDIAN_NATIVE, diff --git a/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c index c9babac8ffaf..7d8ac6df14bb 100644 --- a/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c +++ b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c @@ -12,6 +12,7 @@ */ #include <linux/regmap.h> +#include "msm-cdc-common.h" #include "sdm660-cdc-registers.h" /* @@ -444,11 +445,147 @@ static const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = { [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1, }; +static const u8 msm89xx_cdc_core_reg_writeable[MSM89XX_CDC_CORE_CACHE_SIZE] = { + [MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_SD_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1, + [MSM89XX_CDC_CORE_TOP_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1, + [MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B3_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX5_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX5_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX5_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1, +}; + bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg) { return msm89xx_cdc_core_reg_readable[reg]; } +bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg) +{ + return msm89xx_cdc_core_reg_writeable[reg]; +} + bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 12a4d348d9a9..26320fd01a5a 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -123,6 +123,7 @@ static const struct snd_kcontrol_new name##_mux = \ #define WCD934X_DEC_PWR_LVL_DF 0x00 #define WCD934X_STRING_LEN 100 +#define WCD934X_CDC_SIDETONE_IIR_COEFF_MAX 5 #define WCD934X_DIG_CORE_REG_MIN WCD934X_CDC_ANC0_CLK_RESET_CTL #define WCD934X_DIG_CORE_REG_MAX 0xFFF @@ -654,6 +655,8 @@ struct tavil_priv { struct tavil_idle_detect_config idle_det_cfg; int power_active_ref; + int sidetone_coeff_array[IIR_MAX][BAND_MAX] + [WCD934X_CDC_SIDETONE_IIR_COEFF_MAX]; }; static const struct tavil_reg_mask_val tavil_spkr_default[] = { @@ -5162,10 +5165,12 @@ static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); int iir_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->reg; int band_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->shift; + int coeff_idx; /* * Mask top bit it is reserved @@ -5175,16 +5180,15 @@ static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); - set_iir_band_coeff(codec, iir_idx, band_idx, - ucontrol->value.integer.value[0]); - set_iir_band_coeff(codec, iir_idx, band_idx, - ucontrol->value.integer.value[1]); - set_iir_band_coeff(codec, iir_idx, band_idx, - ucontrol->value.integer.value[2]); - set_iir_band_coeff(codec, iir_idx, band_idx, - ucontrol->value.integer.value[3]); - set_iir_band_coeff(codec, iir_idx, band_idx, - ucontrol->value.integer.value[4]); + /* Store the coefficients in sidetone coeff array */ + for (coeff_idx = 0; coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + tavil->sidetone_coeff_array[iir_idx][band_idx][coeff_idx] = + ucontrol->value.integer.value[coeff_idx]; + set_iir_band_coeff(codec, iir_idx, band_idx, + tavil->sidetone_coeff_array[iir_idx][band_idx] + [coeff_idx]); + } pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n" "%s: IIR #%d band #%d b1 = 0x%x\n" @@ -5204,6 +5208,26 @@ static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, return 0; } +static void tavil_restore_iir_coeff(struct tavil_priv *tavil, int iir_idx) +{ + int band_idx = 0, coeff_idx = 0; + struct snd_soc_codec *codec = tavil->codec; + + for (band_idx = 0; band_idx < BAND_MAX; band_idx++) { + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + for (coeff_idx = 0; + coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + set_iir_band_coeff(codec, iir_idx, band_idx, + tavil->sidetone_coeff_array[iir_idx][band_idx] + [coeff_idx]); + } + } +} + static int tavil_compander_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -8156,6 +8180,8 @@ static int tavil_dig_core_remove_power_collapse(struct tavil_priv *tavil) WCD934X_DIG_CORE_REG_MIN, WCD934X_DIG_CORE_REG_MAX); + tavil_restore_iir_coeff(tavil, IIR0); + tavil_restore_iir_coeff(tavil, IIR1); return 0; } diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c index be6a6a710dc1..b6121d75c148 100644 --- a/sound/soc/msm/apq8096-auto.c +++ b/sound/soc/msm/apq8096-auto.c @@ -3149,10 +3149,10 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10, }, { - .name = "MSM8996 Compr8", - .stream_name = "COMPR8", + .name = "MSM8996 ULL NOIRQ", + .stream_name = "MM_NOIRQ", .cpu_dai_name = "MultiMedia8", - .platform_name = "msm-compr-dsp", + .platform_name = "msm-pcm-dsp-noirq", .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index 509574faebf8..24dbbedf0be7 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -2582,7 +2582,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index f6a5d1344568..15c596f54926 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -5498,6 +5498,37 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, + { + .name = MSM_DAILINK_NAME(Transcode Loopback Playback), + .stream_name = "Transcode Loopback Playback", + .cpu_dai_name = "MultiMedia14", + .platform_name = "msm-transcode-loopback", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14, + }, + { + .name = MSM_DAILINK_NAME(Transcode Loopback Capture), + .stream_name = "Transcode Loopback Capture", + .cpu_dai_name = "MultiMedia18", + .platform_name = "msm-transcode-loopback", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA18, + }, }; static struct snd_soc_dai_link msm_common_be_dai_links[] = { diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile index 219892a85da2..98c52a4db51f 100644 --- a/sound/soc/msm/qdsp6v2/Makefile +++ b/sound/soc/msm/qdsp6v2/Makefile @@ -4,7 +4,7 @@ snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \ msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \ msm-lsm-client.o msm-pcm-host-voice-v2.o \ msm-audio-effects-q6-v2.o msm-pcm-loopback-v2.o \ - msm-dai-slim.o \ + msm-dai-slim.o msm-transcode-loopback-q6-v2.o \ adsp_err.o obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \ msm-dai-stub-v2.o diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 32f68fedcd3b..8744eb166261 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -1077,7 +1077,10 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode, port_type = MSM_AFE_PORT_TYPE_RX; } else if (stream_type == SNDRV_PCM_STREAM_CAPTURE) { session_type = SESSION_TYPE_TX; - path_type = ADM_PATH_LIVE_REC; + if (passthr_mode != LEGACY_PCM) + path_type = ADM_PATH_COMPRESSED_TX; + else + path_type = ADM_PATH_LIVE_REC; port_type = MSM_AFE_PORT_TYPE_TX; } else { pr_err("%s: invalid stream type %d\n", __func__, stream_type); @@ -1514,7 +1517,10 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) path_type = ADM_PATH_PLAYBACK; } else { session_type = SESSION_TYPE_TX; - path_type = ADM_PATH_LIVE_REC; + if (passthr_mode != LEGACY_PCM) + path_type = ADM_PATH_COMPRESSED_TX; + else + path_type = ADM_PATH_LIVE_REC; } is_lsm = (val >= MSM_FRONTEND_DAI_LSM1) && (val <= MSM_FRONTEND_DAI_LSM8); @@ -6449,6 +6455,9 @@ static const struct snd_kcontrol_new mmul18_mixer_controls[] = { SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), @@ -11913,6 +11922,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia18 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, diff --git a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c new file mode 100644 index 000000000000..dbda90c3616d --- /dev/null +++ b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c @@ -0,0 +1,971 @@ +/* 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/init.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/time.h> +#include <linux/math64.h> +#include <linux/wait.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/msm_audio_ion.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/pcm.h> +#include <sound/initval.h> +#include <sound/control.h> +#include <sound/q6asm-v2.h> +#include <sound/pcm_params.h> +#include <sound/timer.h> +#include <sound/tlv.h> +#include <sound/apr_audio-v2.h> +#include <sound/compress_params.h> +#include <sound/compress_offload.h> +#include <sound/compress_driver.h> +#include <linux/msm_audio.h> + +#include "msm-pcm-routing-v2.h" +#include "msm-qti-pp-config.h" + +#define LOOPBACK_SESSION_MAX_NUM_STREAMS 2 + +static DEFINE_MUTEX(transcode_loopback_session_lock); + +struct trans_loopback_pdata { + struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX]; +}; + +struct loopback_stream { + struct snd_compr_stream *cstream; + uint32_t codec_format; + bool start; +}; + +enum loopback_session_state { + /* One or both streams not opened */ + LOOPBACK_SESSION_CLOSE = 0, + /* Loopback streams opened */ + LOOPBACK_SESSION_READY, + /* Loopback streams opened and formats configured */ + LOOPBACK_SESSION_START, + /* Trigger issued on either of streams when in START state */ + LOOPBACK_SESSION_RUN +}; + +struct msm_transcode_loopback { + struct loopback_stream source; + struct loopback_stream sink; + + struct snd_compr_caps source_compr_cap; + struct snd_compr_caps sink_compr_cap; + + uint32_t instance; + uint32_t num_streams; + int session_state; + + struct mutex lock; + + int session_id; + struct audio_client *audio_client; +}; + +/* Transcode loopback global info struct */ +static struct msm_transcode_loopback transcode_info; + +static void loopback_event_handler(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv) +{ + struct msm_transcode_loopback *trans = + (struct msm_transcode_loopback *)priv; + struct snd_soc_pcm_runtime *rtd; + struct snd_compr_stream *cstream; + struct audio_client *ac; + int stream_id; + int ret; + + if (!trans || !payload) { + pr_err("%s: rtd or payload is NULL\n", __func__); + return; + } + + cstream = trans->source.cstream; + ac = trans->audio_client; + + /* + * Token for rest of the compressed commands use to set + * session id, stream id, dir etc. + */ + stream_id = q6asm_get_stream_id_from_token(token); + + switch (opcode) { + case ASM_STREAM_CMD_ENCDEC_EVENTS: + case ASM_IEC_61937_MEDIA_FMT_EVENT: + pr_debug("%s: ASM_IEC_61937_MEDIA_FMT_EVENT\n", __func__); + rtd = cstream->private_data; + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + return; + } + + ret = msm_adsp_inform_mixer_ctl(rtd, payload); + if (ret) { + pr_err("%s: failed to inform mixer ctrl. err = %d\n", + __func__, ret); + return; + } + break; + case APR_BASIC_RSP_RESULT: { + switch (payload[0]) { + case ASM_SESSION_CMD_RUN_V2: + pr_debug("%s: ASM_SESSION_CMD_RUN_V2:", __func__); + pr_debug("token 0x%x, stream id %d\n", token, + stream_id); + break; + case ASM_STREAM_CMD_CLOSE: + pr_debug("%s: ASM_DATA_CMD_CLOSE:", __func__); + pr_debug("token 0x%x, stream id %d\n", token, + stream_id); + break; + default: + break; + } + break; + } + default: + pr_debug("%s: Not Supported Event opcode[0x%x]\n", + __func__, opcode); + break; + } +} + +static void populate_codec_list(struct msm_transcode_loopback *trans, + struct snd_compr_stream *cstream) +{ + struct snd_compr_caps compr_cap; + + pr_debug("%s\n", __func__); + + memset(&compr_cap, 0, sizeof(struct snd_compr_caps)); + + if (cstream->direction == SND_COMPRESS_CAPTURE) { + compr_cap.direction = SND_COMPRESS_CAPTURE; + compr_cap.num_codecs = 3; + compr_cap.codecs[0] = SND_AUDIOCODEC_PCM; + compr_cap.codecs[1] = SND_AUDIOCODEC_AC3; + compr_cap.codecs[2] = SND_AUDIOCODEC_EAC3; + memcpy(&trans->source_compr_cap, &compr_cap, + sizeof(struct snd_compr_caps)); + } + + if (cstream->direction == SND_COMPRESS_PLAYBACK) { + compr_cap.direction = SND_COMPRESS_PLAYBACK; + compr_cap.num_codecs = 1; + compr_cap.codecs[0] = SND_AUDIOCODEC_PCM; + memcpy(&trans->sink_compr_cap, &compr_cap, + sizeof(struct snd_compr_caps)); + } +} + +static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) +{ + int ret = 0; + struct snd_compr_runtime *runtime; + struct snd_soc_pcm_runtime *rtd; + struct msm_transcode_loopback *trans = &transcode_info; + struct trans_loopback_pdata *pdata; + + if (cstream == NULL) { + pr_err("%s: Invalid substream\n", __func__); + return -EINVAL; + } + runtime = cstream->runtime; + rtd = snd_pcm_substream_chip(cstream); + pdata = snd_soc_platform_get_drvdata(rtd->platform); + pdata->cstream[rtd->dai_link->be_id] = cstream; + + mutex_lock(&trans->lock); + if (trans->num_streams > LOOPBACK_SESSION_MAX_NUM_STREAMS) { + pr_err("msm_transcode_open failed..invalid stream\n"); + ret = -EINVAL; + goto exit; + } + + if (cstream->direction == SND_COMPRESS_CAPTURE) { + if (trans->source.cstream == NULL) { + trans->source.cstream = cstream; + trans->num_streams++; + } else { + pr_err("%s: capture stream already opened\n", + __func__); + ret = -EINVAL; + goto exit; + } + } else if (cstream->direction == SND_COMPRESS_PLAYBACK) { + if (trans->sink.cstream == NULL) { + trans->sink.cstream = cstream; + trans->num_streams++; + } else { + pr_debug("%s: playback stream already opened\n", + __func__); + ret = -EINVAL; + goto exit; + } + } + + pr_debug("%s: num stream%d, stream name %s\n", __func__, + trans->num_streams, cstream->name); + + populate_codec_list(trans, cstream); + + if (trans->num_streams == LOOPBACK_SESSION_MAX_NUM_STREAMS) { + pr_debug("%s: Moving loopback session to READY state %d\n", + __func__, trans->session_state); + trans->session_state = LOOPBACK_SESSION_READY; + } + + runtime->private_data = trans; + if (trans->num_streams == 1) + msm_adsp_init_mixer_ctl_pp_event_queue(rtd); +exit: + mutex_unlock(&trans->lock); + return ret; +} + +static void stop_transcoding(struct msm_transcode_loopback *trans) +{ + struct snd_soc_pcm_runtime *soc_pcm_rx; + struct snd_soc_pcm_runtime *soc_pcm_tx; + + if (trans->audio_client != NULL) { + q6asm_cmd(trans->audio_client, CMD_CLOSE); + + if (trans->sink.cstream != NULL) { + soc_pcm_rx = trans->sink.cstream->private_data; + msm_pcm_routing_dereg_phy_stream( + soc_pcm_rx->dai_link->be_id, + SND_COMPRESS_PLAYBACK); + } + if (trans->source.cstream != NULL) { + soc_pcm_tx = trans->source.cstream->private_data; + msm_pcm_routing_dereg_phy_stream( + soc_pcm_tx->dai_link->be_id, + SND_COMPRESS_CAPTURE); + } + q6asm_audio_client_free(trans->audio_client); + trans->audio_client = NULL; + } +} + +static int msm_transcode_loopback_free(struct snd_compr_stream *cstream) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct msm_transcode_loopback *trans = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(cstream); + int ret = 0; + + mutex_lock(&trans->lock); + + pr_debug("%s: Transcode loopback end:%d, streams %d\n", __func__, + cstream->direction, trans->num_streams); + trans->num_streams--; + stop_transcoding(trans); + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + memset(&trans->sink, 0, sizeof(struct loopback_stream)); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + memset(&trans->source, 0, sizeof(struct loopback_stream)); + + trans->session_state = LOOPBACK_SESSION_CLOSE; + if (trans->num_streams == 1) + msm_adsp_clean_mixer_ctl_pp_event_queue(rtd); + mutex_unlock(&trans->lock); + return ret; +} + +static int msm_transcode_loopback_trigger(struct snd_compr_stream *cstream, + int cmd) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct msm_transcode_loopback *trans = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + + if (trans->session_state == LOOPBACK_SESSION_START) { + pr_debug("%s: Issue Loopback session %d RUN\n", + __func__, trans->instance); + q6asm_run_nowait(trans->audio_client, 0, 0, 0); + trans->session_state = LOOPBACK_SESSION_RUN; + } + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + pr_debug("%s: Issue Loopback session %d STOP\n", __func__, + trans->instance); + if (trans->session_state == LOOPBACK_SESSION_RUN) + q6asm_cmd_nowait(trans->audio_client, CMD_PAUSE); + trans->session_state = LOOPBACK_SESSION_START; + break; + + default: + break; + } + return 0; +} + +static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *codec_param) +{ + + struct snd_compr_runtime *runtime = cstream->runtime; + struct msm_transcode_loopback *trans = runtime->private_data; + struct snd_soc_pcm_runtime *soc_pcm_rx; + struct snd_soc_pcm_runtime *soc_pcm_tx; + uint32_t bit_width = 16; + int ret = 0; + + if (trans == NULL) { + pr_err("%s: Invalid param\n", __func__); + return -EINVAL; + } + + mutex_lock(&trans->lock); + + if (cstream->direction == SND_COMPRESS_PLAYBACK) { + if (codec_param->codec.id == SND_AUDIOCODEC_PCM) { + trans->sink.codec_format = + FORMAT_LINEAR_PCM; + switch (codec_param->codec.format) { + case SNDRV_PCM_FORMAT_S32_LE: + bit_width = 32; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bit_width = 24; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + bit_width = 24; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bit_width = 16; + break; + } + } else { + pr_debug("%s: unknown sink codec\n", __func__); + ret = -EINVAL; + goto exit; + } + trans->sink.start = true; + } + + if (cstream->direction == SND_COMPRESS_CAPTURE) { + switch (codec_param->codec.id) { + case SND_AUDIOCODEC_PCM: + pr_debug("Source SND_AUDIOCODEC_PCM\n"); + trans->source.codec_format = + FORMAT_LINEAR_PCM; + break; + case SND_AUDIOCODEC_AC3: + pr_debug("Source SND_AUDIOCODEC_AC3\n"); + trans->source.codec_format = + FORMAT_AC3; + break; + case SND_AUDIOCODEC_EAC3: + pr_debug("Source SND_AUDIOCODEC_EAC3\n"); + trans->source.codec_format = + FORMAT_EAC3; + break; + default: + pr_debug("%s: unknown source codec\n", __func__); + ret = -EINVAL; + goto exit; + } + trans->source.start = true; + } + + pr_debug("%s: trans->source.start %d trans->sink.start %d trans->source.cstream %pK trans->sink.cstream %pK trans->session_state %d\n", + __func__, trans->source.start, trans->sink.start, + trans->source.cstream, trans->sink.cstream, + trans->session_state); + + if ((trans->session_state == LOOPBACK_SESSION_READY) && + trans->source.start && trans->sink.start) { + pr_debug("%s: Moving loopback session to start state\n", + __func__); + trans->session_state = LOOPBACK_SESSION_START; + } + + if (trans->session_state == LOOPBACK_SESSION_START) { + if (trans->audio_client != NULL) { + pr_debug("%s: ASM client already opened, closing\n", + __func__); + stop_transcoding(trans); + } + + trans->audio_client = q6asm_audio_client_alloc( + (app_cb)loopback_event_handler, trans); + if (!trans->audio_client) { + pr_err("%s: Could not allocate memory\n", __func__); + ret = -EINVAL; + goto exit; + } + pr_debug("%s: ASM client allocated, callback %pK\n", __func__, + loopback_event_handler); + trans->session_id = trans->audio_client->session; + trans->audio_client->perf_mode = false; + ret = q6asm_open_transcode_loopback(trans->audio_client, + bit_width, + trans->source.codec_format, + trans->sink.codec_format); + if (ret < 0) { + pr_err("%s: Session transcode loopback open failed\n", + __func__); + q6asm_audio_client_free(trans->audio_client); + trans->audio_client = NULL; + goto exit; + } + + pr_debug("%s: Starting ADM open for loopback\n", __func__); + soc_pcm_rx = trans->sink.cstream->private_data; + soc_pcm_tx = trans->source.cstream->private_data; + if (trans->source.codec_format != FORMAT_LINEAR_PCM) + msm_pcm_routing_reg_phy_compr_stream( + soc_pcm_tx->dai_link->be_id, + trans->audio_client->perf_mode, + trans->session_id, + SNDRV_PCM_STREAM_CAPTURE, + true); + else + msm_pcm_routing_reg_phy_stream( + soc_pcm_tx->dai_link->be_id, + trans->audio_client->perf_mode, + trans->session_id, + SNDRV_PCM_STREAM_CAPTURE); + + msm_pcm_routing_reg_phy_stream( + soc_pcm_rx->dai_link->be_id, + trans->audio_client->perf_mode, + trans->session_id, + SNDRV_PCM_STREAM_PLAYBACK); + pr_debug("%s: Successfully opened ADM sessions\n", __func__); + } +exit: + mutex_unlock(&trans->lock); + return ret; +} + +static int msm_transcode_loopback_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *arg) +{ + struct snd_compr_runtime *runtime; + struct msm_transcode_loopback *trans; + + if (!arg || !cstream) { + pr_err("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + runtime = cstream->runtime; + trans = runtime->private_data; + pr_debug("%s\n", __func__); + if (cstream->direction == SND_COMPRESS_CAPTURE) + memcpy(arg, &trans->source_compr_cap, + sizeof(struct snd_compr_caps)); + else + memcpy(arg, &trans->sink_compr_cap, + sizeof(struct snd_compr_caps)); + return 0; +} + +static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct msm_transcode_loopback *prtd; + int ret = 0; + struct msm_adsp_event_data *event_data = NULL; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received invalid fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + cstream = pdata->cstream[fe_id]; + if (cstream == NULL) { + pr_err("%s cstream is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: prtd is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + if (prtd->audio_client == NULL) { + pr_err("%s: audio_client is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data; + if ((event_data->event_type < ADSP_STREAM_PP_EVENT) || + (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) { + pr_err("%s: invalid event_type=%d", + __func__, event_data->event_type); + ret = -EINVAL; + goto done; + } + + if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >= + sizeof(ucontrol->value.bytes.data)) { + pr_err("%s param length=%d exceeds limit", + __func__, event_data->payload_len); + ret = -EINVAL; + goto done; + } + + ret = q6asm_send_stream_cmd(prtd->audio_client, event_data); + if (ret < 0) + pr_err("%s: failed to send stream event cmd, err = %d\n", + __func__, ret); +done: + return ret; +} + +static int msm_transcode_ion_fd_map_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct msm_transcode_loopback *prtd; + int fd; + int ret = 0; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds invalid fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + cstream = pdata->cstream[fe_id]; + if (cstream == NULL) { + pr_err("%s cstream is null\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: prtd is null\n", __func__); + ret = -EINVAL; + goto done; + } + + if (prtd->audio_client == NULL) { + pr_err("%s: audio_client is null\n", __func__); + ret = -EINVAL; + goto done; + } + + memcpy(&fd, ucontrol->value.bytes.data, sizeof(fd)); + ret = q6asm_send_ion_fd(prtd->audio_client, fd); + if (ret < 0) + pr_err("%s: failed to register ion fd\n", __func__); +done: + return ret; +} + +static int msm_transcode_rtic_event_ack_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct msm_transcode_loopback *prtd; + int ret = 0; + int param_length = 0; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received invalid fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + cstream = pdata->cstream[fe_id]; + if (cstream == NULL) { + pr_err("%s cstream is null\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: prtd is null\n", __func__); + ret = -EINVAL; + goto done; + } + + if (prtd->audio_client == NULL) { + pr_err("%s: audio_client is null\n", __func__); + ret = -EINVAL; + goto done; + } + + memcpy(¶m_length, ucontrol->value.bytes.data, + sizeof(param_length)); + if ((param_length + sizeof(param_length)) + >= sizeof(ucontrol->value.bytes.data)) { + pr_err("%s param length=%d exceeds limit", + __func__, param_length); + ret = -EINVAL; + goto done; + } + + ret = q6asm_send_rtic_event_ack(prtd->audio_client, + ucontrol->value.bytes.data + sizeof(param_length), + param_length); + if (ret < 0) + pr_err("%s: failed to send rtic event ack, err = %d\n", + __func__, ret); +done: + return ret; +} + +static int msm_transcode_stream_cmd_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CMD; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_loopback_stream_cmd_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_transcode_stream_cmd_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_loopback_stream_cmd_config_control[0].name = mixer_str; + fe_loopback_stream_cmd_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_loopback_stream_cmd_config_control, + ARRAY_SIZE(fe_loopback_stream_cmd_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_transcode_stream_callback_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol *kctl; + + struct snd_kcontrol_new fe_loopback_callback_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_callback_info, + .get = msm_adsp_stream_callback_get, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_loopback_callback_config_control[0].name = mixer_str; + fe_loopback_callback_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_loopback_callback_config_control, + ARRAY_SIZE(fe_loopback_callback_config_control)); + if (ret < 0) { + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl->private_data = NULL; +free_mixer_str: + kfree(mixer_str); +done: + return ret; +} + +static int msm_transcode_add_ion_fd_cmd_control(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Playback ION FD"; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_ion_fd_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_transcode_ion_fd_map_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_ion_fd_config_control[0].name = mixer_str; + fe_ion_fd_config_control[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_ion_fd_config_control, + ARRAY_SIZE(fe_ion_fd_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s\n", __func__, mixer_str); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_transcode_add_event_ack_cmd_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Playback Event Ack"; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_event_ack_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_transcode_rtic_event_ack_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_event_ack_config_control[0].name = mixer_str; + fe_event_ack_config_control[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_event_ack_config_control, + ARRAY_SIZE(fe_event_ack_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s\n", __func__, mixer_str); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd) +{ + int rc; + + rc = msm_transcode_stream_cmd_control(rtd); + if (rc) + pr_err("%s: ADSP Stream Cmd Control open failed\n", __func__); + + rc = msm_transcode_stream_callback_control(rtd); + if (rc) + pr_err("%s: ADSP Stream callback Control open failed\n", + __func__); + + rc = msm_transcode_add_ion_fd_cmd_control(rtd); + if (rc) + pr_err("%s: Could not add transcode ion fd Control\n", + __func__); + + rc = msm_transcode_add_event_ack_cmd_control(rtd); + if (rc) + pr_err("%s: Could not add transcode event ack Control\n", + __func__); + + return 0; +} + +static struct snd_compr_ops msm_transcode_loopback_ops = { + .open = msm_transcode_loopback_open, + .free = msm_transcode_loopback_free, + .trigger = msm_transcode_loopback_trigger, + .set_params = msm_transcode_loopback_set_params, + .get_caps = msm_transcode_loopback_get_caps, +}; + + +static int msm_transcode_loopback_probe(struct snd_soc_platform *platform) +{ + struct trans_loopback_pdata *pdata = NULL; + + pr_debug("%s\n", __func__); + pdata = (struct trans_loopback_pdata *) + kzalloc(sizeof(struct trans_loopback_pdata), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + snd_soc_platform_set_drvdata(platform, pdata); + return 0; +} + +static struct snd_soc_platform_driver msm_soc_platform = { + .probe = msm_transcode_loopback_probe, + .compr_ops = &msm_transcode_loopback_ops, + .pcm_new = msm_transcode_loopback_new, +}; + +static int msm_transcode_dev_probe(struct platform_device *pdev) +{ + + pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev)); + if (pdev->dev.of_node) + dev_set_name(&pdev->dev, "%s", "msm-transcode-loopback"); + + return snd_soc_register_platform(&pdev->dev, + &msm_soc_platform); +} + +static int msm_transcode_remove(struct platform_device *pdev) +{ + snd_soc_unregister_platform(&pdev->dev); + return 0; +} + +static const struct of_device_id msm_transcode_loopback_dt_match[] = { + {.compatible = "qcom,msm-transcode-loopback"}, + {} +}; +MODULE_DEVICE_TABLE(of, msm_transcode_loopback_dt_match); + +static struct platform_driver msm_transcode_loopback_driver = { + .driver = { + .name = "msm-transcode-loopback", + .owner = THIS_MODULE, + .of_match_table = msm_transcode_loopback_dt_match, + }, + .probe = msm_transcode_dev_probe, + .remove = msm_transcode_remove, +}; + +static int __init msm_soc_platform_init(void) +{ + memset(&transcode_info, 0, sizeof(struct msm_transcode_loopback)); + mutex_init(&transcode_info.lock); + return platform_driver_register(&msm_transcode_loopback_driver); +} +module_init(msm_soc_platform_init); + +static void __exit msm_soc_platform_exit(void) +{ + mutex_destroy(&transcode_info.lock); + platform_driver_unregister(&msm_transcode_loopback_driver); +} +module_exit(msm_soc_platform_exit); + +MODULE_DESCRIPTION("Transcode loopback platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index 9f00e1bc4a3d..7cf19a9ed335 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -2156,7 +2156,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, (topology == SRS_TRUMEDIA_TOPOLOGY_ID)) topology = DEFAULT_COPP_TOPOLOGY; } else { - if (path == ADM_PATH_COMPRESSED_RX) + if ((path == ADM_PATH_COMPRESSED_RX) || + (path == ADM_PATH_COMPRESSED_TX)) flags = 0; else flags = ADM_LEGACY_DEVICE_SESSION; @@ -2193,7 +2194,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, acdb_id); set_bit(ADM_STATUS_CALIBRATION_REQUIRED, (void *)&this_adm.copp.adm_status[port_idx][copp_idx]); - if (path != ADM_PATH_COMPRESSED_RX) + if ((path != ADM_PATH_COMPRESSED_RX) && + (path != ADM_PATH_COMPRESSED_TX)) send_adm_custom_topology(); } } @@ -2465,6 +2467,10 @@ static void route_set_opcode_matrix_id( route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5; route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX; break; + case ADM_PATH_COMPRESSED_TX: + route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5; + route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_TX; + break; default: pr_err("%s: Wrong path set[%d]\n", __func__, path); break; diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 0d142f77db50..da156bf61610 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -155,12 +155,37 @@ static int out_cold_index; static char *out_buffer; static char *in_buffer; -static uint32_t adsp_reg_event_opcode[] = {ASM_STREAM_CMD_REGISTER_PP_EVENTS, - ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS}; +static uint32_t adsp_reg_event_opcode[] = { + ASM_STREAM_CMD_REGISTER_PP_EVENTS, + ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS, + ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE }; -static uint32_t adsp_raise_event_opcode[] = {ASM_STREAM_PP_EVENT, - ASM_STREAM_CMD_ENCDEC_EVENTS}; +static uint32_t adsp_raise_event_opcode[] = { + ASM_STREAM_PP_EVENT, + ASM_STREAM_CMD_ENCDEC_EVENTS, + ASM_IEC_61937_MEDIA_FMT_EVENT }; +static int is_adsp_reg_event(uint32_t cmd) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(adsp_reg_event_opcode); i++) { + if (cmd == adsp_reg_event_opcode[i]) + return i; + } + return -EINVAL; +} + +static int is_adsp_raise_event(uint32_t cmd) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) { + if (cmd == adsp_raise_event_opcode[i]) + return i; + } + return -EINVAL; +} static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token, int flag, int flag_offset) @@ -1794,6 +1819,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_STREAM_CMD_SET_ENCDEC_PARAM: case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2: case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS: + case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE: case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS: @@ -1807,10 +1833,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pr_err("%s: cmd = 0x%x returned error = 0x%x\n", __func__, payload[0], payload[1]); if (wakeup_flag) { - if (payload[0] == - ASM_STREAM_CMD_SET_PP_PARAMS_V2 - || payload[0] == - ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS) + if ((is_adsp_reg_event(payload[0]) >= 0) + || (payload[0] == + ASM_STREAM_CMD_SET_PP_PARAMS_V2)) atomic_set(&ac->cmd_state_pp, payload[1]); else @@ -1820,9 +1845,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } return 0; } - if (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2 || - payload[0] == - ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS) { + if ((is_adsp_reg_event(payload[0]) >= 0) || + (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2)) { if (atomic_read(&ac->cmd_state_pp) && wakeup_flag) { atomic_set(&ac->cmd_state_pp, 0); @@ -2063,13 +2087,11 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) break; case ASM_STREAM_PP_EVENT: case ASM_STREAM_CMD_ENCDEC_EVENTS: - pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]", + case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE: + pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]", __func__, payload[0], payload[1]); - for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) - if (adsp_raise_event_opcode[i] == data->opcode) - break; - - if (i >= ARRAY_SIZE(adsp_raise_event_opcode)) + i = is_adsp_raise_event(data->opcode); + if (i < 0) return 0; /* repack payload for asm_stream_pp_event |