diff options
217 files changed, 7383 insertions, 1432 deletions
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index f9b9ad7894f5..02431aeca15f 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -136,6 +136,7 @@ !Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt !Finclude/net/cfg80211.h cfg80211_ibss_joined !Finclude/net/cfg80211.h cfg80211_connect_result +!Finclude/net/cfg80211.h cfg80211_connect_bss !Finclude/net/cfg80211.h cfg80211_roamed !Finclude/net/cfg80211.h cfg80211_disconnected !Finclude/net/cfg80211.h cfg80211_ready_on_channel diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 42daa8a61e4c..7b1c081ef586 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -92,6 +92,9 @@ SoCs: - MSMFALCON compatible = "qcom,msmfalcon" +- MSMTRITON + compatible = "qcom,msmtriton" + - MSM8952 compatible = "qcom,msm8952" @@ -259,6 +262,7 @@ compatible = "qcom,msmhamster-cdp" compatible = "qcom,msmhamster-mtp" compatible = "qcom,msmfalcon-sim" compatible = "qcom,msmfalcon-rumi" +compatible = "qcom,msmtriton-rumi" compatible = "qcom,msm8952-rumi" compatible = "qcom,msm8952-sim" compatible = "qcom,msm8952-qrd" diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt index cee9b942a9e3..518cc6f85f95 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt @@ -9,19 +9,22 @@ Properties: - compatible Usage: required Value type: <string> - Definition: must be "qcom,cpu-clock-osm". + Definition: must be "qcom,cpu-clock-osm-msmcobalt-v1" or + "qcom,cpu-clock-osm-msmcobalt-v2". - reg Usage: required Value type: <prop-encoded-array> Definition: Addresses and sizes for the memory of the OSM controller, cluster PLL management, and APCS common register regions. - + Optionally, the address of the efuse registers used to + determine the pwrcl or perfcl speed-bins. - reg-names Usage: required Value type: <stringlist> Definition: Address names. Must be "osm", "pwrcl_pll", "perfcl_pll", - and "apcs_common". + "apcs_common" and "debug". Optionally, "pwrcl_efuse" or + "perfcl_efuse". Must be specified in the same order as the corresponding addresses are specified in the reg property. @@ -297,13 +300,14 @@ Properties: Example: clock_cpu: qcom,cpu-clock-cobalt@179c0000 { - compatible = "qcom,cpu-clock-osm"; + compatible = "qcom,cpu-clock-osm-msmcobalt-v1"; reg = <0x179C0000 0x4000>, <0x17916000 0x1000>, <0x17816000 0x1000>, - <0x179D1000 0x1000>; + <0x179D1000 0x1000>, + <0x1791101c 0x8>; reg-names = "osm", "pwrcl_pll", "perfcl_pll", - "apcs_common"; + "apcs_common", "debug"; vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; vdd-perfcl-supply = <&apc1_perfcl_vreg>; diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt index da4cdf253b2c..628b4df9fd7d 100644 --- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt +++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt @@ -53,23 +53,29 @@ Optional properties: - "secondary" - "tertiary" -[Optional child nodes]: These nodes are for devices which are -dependent on HDMI Tx controller. If HDMI Tx controller is disabled then -these devices will be disabled as well. Ex. HDMI Audio Codec device. - -- qcom,msm-hdmi-audio-rx: Node for HDMI audio codec. -Required properties: -- compatible : "msm-hdmi-audio-codec-rx"; - msm_ext_disp is a device which manages the interaction between external displays (HDMI and Display Port) and the audio and display frameworks. Required properties: - compatible: Must be "qcom,msm-ext-disp" +[Required child nodes]: These nodes are for devices which are +dependent on msm_ext_disp. If msm_ext_disp is disabled then +these devices will be disabled as well. Ex. Audio Codec device. + +- ext_disp_audio_codec: Node for Audio Codec. + +Required properties: +- compatible : "qcom,msm-ext-disp-audio-codec-rx"; + Example: msm_ext_disp: qcom,msm_ext_disp { compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + qcom,msm_ext_disp = <&msm_ext_disp>; + }; }; mdss_hdmi_tx: qcom,hdmi_tx@fd922100 { @@ -109,9 +115,6 @@ Example: qcom,pluggable; qcom,display-id = "secondary"; - qcom,msm-hdmi-audio-rx { - compatible = "qcom,msm-hdmi-audio-codec-rx"; - }; pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", "hdmi_active", "hdmi_sleep"; diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt index 8e2f0908562a..f7494c4c6e2b 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt @@ -71,6 +71,10 @@ Optional properties: - focaltech,fw-name : specify the firmware file name - focaltech,psensor-support : specify whether support the proximity sensor - focaltech,gesture-support : specify whether support gesture feature + - focaltech,resume-in-workqueue : specifiy whether to defer the resume to workqueue + - clock-names: : Clock names used for secure touch. They are: "iface_clk", "core_clk" + - clocks : Defined if 'clock-names' DT property is defined. These clocks + are associated with the underlying I2C bus. Example: i2c@f9923000{ @@ -108,5 +112,9 @@ Example: focaltech,fw-auto-cal; focaltech,psensor-support; focaltech,gesture-support; + /* Underlying clocks used by secure touch */ + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; }; }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt index 1ae63c0acd40..8198a13081b8 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt @@ -16,6 +16,9 @@ PMIC's from Qualcomm. "qcom,pm8941-gpio" "qcom,pma8084-gpio" + And must contain either "qcom,spmi-gpio" or "qcom,ssbi-gpio" + if the device is on an spmi bus or an ssbi bus respectively + - reg: Usage: required Value type: <prop-encoded-array> @@ -86,14 +89,18 @@ to specify in a pin configuration subnode: Value type: <string> Definition: Specify the alternative function to be configured for the specified pins. Valid values are: - "normal", - "paired", - "func1", - "func2", - "dtest1", - "dtest2", - "dtest3", - "dtest4" + "normal", + "paired", + "func1", + "func2", + "dtest1", + "dtest2", + "dtest3", + "dtest4", + And following values are supported by LV/MV GPIO subtypes: + "func3", + "func4", + "analog" - bias-disable: Usage: optional @@ -178,10 +185,33 @@ to specify in a pin configuration subnode: Value type: <none> Definition: The specified pins are configured in open-source mode. +- qcom,atest: + Usage: optional + Value type: <u32> + Definition: Selects ATEST rail to route to GPIO when it's configured + in analog-pass-through mode by specifying "analog" function. + Valid values are 0-3 corresponding to PMIC_GPIO_AOUT_ATESTx + defined in <dt-bindings/pinctrl/qcom,pmic-gpio.h>. + +- qcom,dtest-buffer: + Usage: optional + Value type: <u32> + Definition: Selects DTEST rail to route to GPIO when it's configured + as a digital input. + For LV/MV GPIO subtypes, the valid values are 0-3 + corresponding to PMIC_GPIO_DIN_DTESTx defined in + <dt-bindings/pinctrl/qcom,pmic-gpio.h>. Only one + DTEST rail can be selected at a time. + For 4CH/8CH GPIO subtypes, supported values are 1-15. + 4 DTEST rails are supported in total and more than 1 DTEST + rail can be selected simultaneously. Each bit of the + 4 LSBs represent one DTEST rail, such as [3:0] = 0101 + means both DTEST1 and DTEST3 are selected. + Example: pm8921_gpio: gpio@150 { - compatible = "qcom,pm8921-gpio"; + compatible = "qcom,pm8921-gpio", "qcom,ssbi-gpio"; reg = <0x150 0x160>; interrupts = <192 1>, <193 1>, <194 1>, <195 1>, <196 1>, <197 1>, diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index d7803a2a94e9..42e504a27fa0 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -17,6 +17,9 @@ of PMIC's from Qualcomm. "qcom,pm8941-mpp", "qcom,pma8084-mpp", + And must contain either "qcom,spmi-mpp" or "qcom,ssbi-mpp" + if the device is on an spmi bus or an ssbi bus respectively. + - reg: Usage: required Value type: <prop-encoded-array> @@ -139,7 +142,7 @@ to specify in a pin configuration subnode: - qcom,dtest: Usage: optional Value type: <u32> - Definition: Selects which dtest rail to be routed in the various functions. + Definition: Selects which dtest rail to be routed for digital output. Valid values are 1-4 - qcom,amux-route: @@ -153,10 +156,20 @@ to specify in a pin configuration subnode: Value type: <none> Definition: Indicates that the pin should be operating in paired mode. +- qcom,dtest-buffer: + Usage: optional + Value type: <u32> + Definition: Selects which dtest rail to be routed for digital input. + It's also valid when the pin is configured as digital + input and output. + 4 dtest rails supported in total and more than one rail + could be selected simultaneously. Each bit of the 4 LSBs + represent one dtest rail, such as [3:0] = 0101 means both + dtest1 and dtest3 are selected. Valid values are 1-15. Example: mpps@a000 { - compatible = "qcom,pm8841-mpp"; + compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; reg = <0xa000>; gpio-controller; #gpio-cells = <2>; diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt index 38f2cfe1d649..510a824fda79 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt @@ -80,6 +80,22 @@ Charger specific properties: offset of charging current in uA, from -3100000 to 3200000. If the array is not present, step charging is disabled. +- io-channels + Usage: optional + Value type: List of <phandle u32> + Definition: List of phandle and IIO specifier pairs, one pair + for each IIO input to the device. Note: if the + IIO provider specifies '0' for #io-channel-cells, + then only the phandle portion of the pair will appear. + +- io-channel-names + Usage: optional + Value type: List of <string> + Definition: List of IIO input name strings sorted in the same + order as the io-channels property. Consumer drivers + will use io-channel-names to match IIO input names + with IIO specifiers. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= @@ -110,6 +126,9 @@ pmicobalt_charger: qcom,qpnp-smb2 { #address-cells = <1>; #size-cells = <1>; + io-channels = <&pmic_rradc 0>; + io-channel-names = "rradc_batt_id"; + qcom,suspend-input; dpdm-supply = <&qusb_phy0>; diff --git a/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt b/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt index 0549c439460c..0244f910017a 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt @@ -52,6 +52,22 @@ Charger specific properties: Value type: <u32> Definition: Specifies the DC input current limit in micro-amps. +- io-channels + Usage: optional + Value type: List of <phandle u32> + Definition: List of phandle and IIO specifier pairs, one pair + for each IIO input to the device. Note: if the + IIO provider specifies '0' for #io-channel-cells, + then only the phandle portion of the pair will appear. + +- io-channel-names + Usage: optional + Value type: List of <string> + Definition: List of IIO input name strings sorted in the same + order as the io-channels property. Consumer drivers + will use io-channel-names to match IIO input names + with IIO specifiers. + ================================================ Second Level Nodes - SMB138X Charger Peripherals ================================================ diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt index 7d88e9fbd9c6..af53e59cd87f 100644 --- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt @@ -35,13 +35,15 @@ Platform independent properties: - reg Usage: required Value type: <prop-encoded-array> - Definition: Addresses and sizes for the memory of the CPR3 controller - and the first fuse row + Definition: Addresses and sizes for the memory of the CPR3 controller, + the first fuse row, and optionally a register used to check + if aging measurements are possible. - reg-names Usage: required Value type: <stringlist> - Definition: Address names. Must be "cpr_ctrl" and "fuse_base". Must be + Definition: Address names. Must include "cpr_ctrl" and "fuse_base". + "aging_allowed" may also be specified. The strings must be specified in the same order as the corresponding addresses are specified in the reg property. @@ -183,6 +185,17 @@ Platform independent properties: This is the voltage that vdd-supply must be set to when performing an aging measurement. +- qcom,cpr-aging-allowed-reg-mask + Usage: required if "aging_allowed" register is specified + Value type: <u32> + Definition: Bitmask used to mask off the "aging_allowed" register. + +- qcom,cpr-aging-allowed-reg-value + Usage: required if "aging_allowed" register is specified + Value type: <u32> + Definition: Value required in the masked off "aging_allowed" register + bits in order for a CPR aging measurement to be possible. + - qcom,cpr-panic-reg-addr-list Usage: optional Value type: <prop-encoded-array> diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index f6dadb738175..a01bd451c577 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -470,6 +470,11 @@ Example: qcom,msm-dai-q6-dev-id = <8>; }; + dai_dp: qcom,msm-dai-q6-dp { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <24608>; + }; + qcom,msm-dai-q6 { compatible = "qcom,msm-dai-q6"; qcom,msm-dai-q6-sb-0-rx { @@ -784,7 +789,7 @@ Example: "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-pcm-lpa"; - asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, + asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, @@ -793,6 +798,7 @@ Example: <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music_2_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", + "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", @@ -1157,7 +1163,7 @@ Example: <&bt_sco_tx>,<&int_fm_rx>,<&int_fm_tx>,<&afe_pcm_rx>, <&afe_pcm_tx>,<&afe_proxy_rx>,<&afe_proxy_tx>, <&incall_record_rx>,<&incall_record_tx>,<&incall_music_rx>, - <&incall_music2_rx>; + <&incall_music2_rx>,<&dai_dp>; asoc-cpu-names = "msm-dai-q6-auxpcm.1","msm-dai-q6-auxpcm.2", "msm-dai-q6-hdmi.8","msm-dai-q6-mi2s.0", "msm-dai-q6-dev.16384","msm-dai-q6-dev.16385", @@ -1171,7 +1177,7 @@ Example: "msm-dai-q6-dev.225","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-dev.32770","msm-dai-q6-dp.24608"; asoc-codec = <&stub>; asoc-codec-names = "msm-stub-codec.1"; }; diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index 0af26ca1f380..b45ee910258e 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -118,6 +118,10 @@ Required properties: USB3_PHY_POWER_DOWN_CONTROL, USB3_PHY_SW_RESET, USB3_PHY_START +- resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. +- reset-names: reset signal name strings sorted in the same order as the resets + property. Optional properties: - reg: Additional register set of address and length to control QMP PHY are: @@ -126,7 +130,7 @@ Optional properties: - clocks: a list of phandles to the PHY clocks. Use as per Documentation/devicetree/bindings/clock/clock-bindings.txt - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" - property. Required clocks are "cfg_ahb_clk", "phy_reset" and "phy_phy_reset". + property. "cfg_ahb_clk" is an optional clock. - qcom,vbus-valid-override: If present, indicates VBUS pin is not connected to the USB PHY and the controller must rely on external VBUS notification in order to manually relay the notification to the SSPHY. @@ -150,13 +154,17 @@ Example: clocks = <&clock_gcc clk_gcc_usb3_phy_aux_clk>, <&clock_gcc clk_gcc_usb3_phy_pipe_clk>, <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, - <&clock_gcc clk_gcc_usb3_phy_reset>, - <&clock_gcc clk_gcc_usb3phy_phy_reset>, <&clock_gcc clk_ln_bb_clk1>, <&clock_gcc clk_gcc_usb3_clkref_clk>; - clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", "phy_reset", - "phy_phy_reset", "ref_clk_src", "ref_clk"; + clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", + "ref_clk_src", "ref_clk"; + + resets = <&clock_gcc GCC_USB3_PHY_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy_reset", + "phy_phy_reset"; + }; QUSB2 High-Speed PHY @@ -173,11 +181,11 @@ Required properties: - qcom,vdd-voltage-level: This property must be a list of three integer values (no, min, max) where each value represents either a voltage in microvolts or a value corresponding to voltage corner - - clocks: a list of phandles to the PHY clocks. Use as per - Documentation/devicetree/bindings/clock/clock-bindings.txt - - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" - property. Required clock is "phy_reset". - phy_type: Should be one of "ulpi" or "utmi". ChipIdea core uses "ulpi" mode. + - resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. + - reset-names: reset signal name strings sorted in the same order as the resets + property. Optional properties: - reg-names: Additional registers corresponding with the following: @@ -218,7 +226,8 @@ Example: clocks = <&clock_rpm clk_ln_bb_clk>, <&clock_gcc clk_gcc_rx2_usb1_clkref_clk>, - <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, - <&clock_gcc clk_gcc_qusb2_phy_reset>; - clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk", "phy_reset"; + <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>; + clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk"; + resets = <&clock_gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; }; diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index c5e5f1851fc2..f4d10908f4ff 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -15,6 +15,10 @@ Required properties : - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" property. Required clocks are "xo", "iface_clk", "core_clk", "sleep_clk" and "utmi_clk". +- resets: reset specifier pair consists of phandle for the reset provider + and reset lines used by this controller. +- reset-names: reset signal name strings sorted in the same order as the resets + property. Optional properties : - reg: Additional registers @@ -99,6 +103,9 @@ Example MSM USB3.0 controller device node : clock-names = "core_clk", "iface_clk", "bus_aggr_clk", "utmi_clk", "sleep_clk", "cfg_ahb_clk", "xo"; + resets = <&clock_gcc GCC_USB_30_BCR>; + reset-names = "core_reset"; + dwc3@f9200000 { compatible = "synopsys,dwc3"; reg = <0xf9200000 0xfc000>; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 6b94608ee2c7..bffa21a06462 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -113,6 +113,7 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ msmcobalt-v2-cdp.dtb \ msmcobalt-v2-qrd.dtb \ msmcobalt-qrd-skuk.dtb \ + msmcobalt-qrd-vr1.dtb \ apqcobalt-mtp.dtb \ apqcobalt-cdp.dtb \ apqcobalt-v2-mtp.dtb \ @@ -120,13 +121,18 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ apqcobalt-v2-qrd.dtb \ msmcobalt-v2.1-mtp.dtb \ msmcobalt-v2.1-cdp.dtb \ - msmcobalt-v2.1-qrd.dtb + msmcobalt-v2.1-qrd.dtb \ + apqcobalt-v2.1-mtp.dtb \ + apqcobalt-v2.1-cdp.dtb \ + apqcobalt-v2.1-qrd.dtb dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb \ msmfalcon-rumi.dtb +dtb-$(CONFIG_ARCH_MSMTRITON) += msmtriton-rumi.dtb + ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1-cdp.dts b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-cdp.dts new file mode 100644 index 000000000000..f0ab8e0afc78 --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-cdp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apqcobalt-v2.1.dtsi" +#include "msmcobalt-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1 CDP"; + compatible = "qcom,apqcobalt-cdp", "qcom,apqcobalt", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1-mtp.dts b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-mtp.dts new file mode 100644 index 000000000000..e23134f8897b --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-mtp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apqcobalt-v2.1.dtsi" +#include "msmcobalt-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1 MTP"; + compatible = "qcom,apqcobalt-mtp", "qcom,apqcobalt", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1-qrd.dts b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-qrd.dts new file mode 100644 index 000000000000..8da6f90958d2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-qrd.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apqcobalt-v2.1.dtsi" +#include "msmcobalt-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1 QRD"; + compatible = "qcom,apqcobalt-qrd", "qcom,apqcobalt", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1.dtsi b/arch/arm/boot/dts/qcom/apqcobalt-v2.1.dtsi new file mode 100644 index 000000000000..5a49afecd60b --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1.dtsi @@ -0,0 +1,18 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msmcobalt-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1"; + qcom,msm-id = <319 0x20001>; +}; diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi index f3233948d457..41b6f50c520b 100644 --- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi @@ -76,6 +76,11 @@ qcom,msm-dai-q6-dev-id = <8>; }; + dai_dp: qcom,msm-dai-q6-dp { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <24608>; + }; + loopback: qcom,msm-pcm-loopback { compatible = "qcom,msm-pcm-loopback"; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index d99749a01f6c..f0c13096cf37 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -145,6 +145,15 @@ qcom,pmic-revid = <&pmicobalt_revid>; + io-channels = <&pmicobalt_rradc 8>, + <&pmicobalt_rradc 10>, + <&pmicobalt_rradc 3>, + <&pmicobalt_rradc 4>; + io-channel-names = "charger_temp", + "charger_temp_max", + "usbin_i", + "usbin_v"; + dpdm-supply = <&qusb_phy0>; qcom,thermal-mitigation @@ -262,7 +271,7 @@ reg = <0x1700 0x100>; vdd-pdphy-supply = <&pmcobalt_l24>; vbus-supply = <&smb2_vbus>; - vcon-supply = <&smb2_vconn>; + vconn-supply = <&smb2_vconn>; interrupts = <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>, <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>, <0x2 0x17 0x2 IRQ_TYPE_EDGE_RISING>, diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index aa973e4ee3d6..e0d84e423e88 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -1934,6 +1934,9 @@ clock-names = "core_clk", "iface_clk", "bus_aggr_clk", "utmi_clk", "sleep_clk", "xo", "cfg_ahb_clk"; + resets = <&clock_gcc USB_30_BCR>; + reset-names = "core_reset"; + dwc3@6a00000 { compatible = "snps,dwc3"; reg = <0x06a00000 0xc8d0>; @@ -2039,6 +2042,8 @@ <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>; clock-names = "core_clk", "iface_clk", "utmi_clk", "sleep_clk", "xo", "cfg_ahb_clk"; + resets = <&clock_gcc USB_20_BCR>; + reset-names = "core_reset"; dwc3@7600000 { compatible = "snps,dwc3"; @@ -2088,10 +2093,11 @@ qcom,major-rev = <1>; clocks = <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, - <&clock_gcc clk_gcc_qusb2phy_prim_reset>, <&clock_gcc clk_ln_bb_clk>; + clock-names = "cfg_ahb_clk", "ref_clk_src"; - clock-names = "cfg_ahb_clk", "phy_reset", "ref_clk_src"; + resets = <&clock_gcc QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; }; qusb_phy1: qusb@7412000 { @@ -2124,10 +2130,11 @@ qcom,hold-reset; clocks = <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, - <&clock_gcc clk_gcc_qusb2phy_sec_reset>, - <&clock_gcc clk_ln_bb_clk>; + <&clock_gcc clk_ln_bb_clk>; + clock-names = "cfg_ahb_clk", "ref_clk_src"; - clock-names = "cfg_ahb_clk", "phy_reset", "ref_clk_src"; + resets = <&clock_gcc QUSB2PHY_SEC_BCR>; + reset-names = "phy_reset"; }; ssphy: ssphy@7410000 { @@ -2209,13 +2216,15 @@ clocks = <&clock_gcc clk_gcc_usb3_phy_aux_clk>, <&clock_gcc clk_gcc_usb3_phy_pipe_clk>, <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, - <&clock_gcc clk_gcc_usb3_phy_reset>, - <&clock_gcc clk_gcc_usb3phy_phy_reset>, <&clock_gcc clk_ln_bb_clk>, <&clock_gcc clk_gcc_usb3_clkref_clk>; - clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", "phy_reset", - "phy_phy_reset", "ref_clk_src", "ref_clk"; + clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", + "ref_clk_src", "ref_clk"; + + resets = <&clock_gcc USB3_PHY_BCR>, + <&clock_gcc USB3PHY_PHY_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; }; usb_nop_phy: usb_nop_phy { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi index 05328a0f29dc..ec69d7ac895d 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi @@ -34,7 +34,7 @@ sound-9335 { compatible = "qcom,msmcobalt-asoc-snd-tasha"; qcom,model = "msmcobalt-tasha-snd-card"; - qcom,hdmi-audio-rx; + qcom,ext-disp-audio-rx; qcom,audio-routing = "AIF4 VI", "MCLK", @@ -80,7 +80,7 @@ "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", "msm-compr-dsp", "msm-pcm-dsp-noirq"; - asoc-cpu = <&dai_hdmi>, + asoc-cpu = <&dai_hdmi>, <&dai_dp>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, @@ -90,7 +90,7 @@ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&usb_audio_rx>, <&usb_audio_tx>; - asoc-cpu-names = "msm-dai-q6-hdmi.8", + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", @@ -104,9 +104,9 @@ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673"; - asoc-codec = <&stub_codec>, <&hdmi_audio>; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; asoc-codec-names = "msm-stub-codec.1", - "msm-hdmi-audio-codec-rx"; + "msm-ext-disp-audio-codec-rx"; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, <&wsa881x_213>, <&wsa881x_214>; @@ -117,6 +117,7 @@ sound-tavil { compatible = "qcom,msmcobalt-asoc-snd-tavil"; qcom,model = "msmcobalt-tavil-snd-card"; + qcom,ext-disp-audio-rx; qcom,audio-routing = "RX_BIAS", "MCLK", @@ -160,7 +161,7 @@ "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", "msm-compr-dsp", "msm-pcm-dsp-noirq"; - asoc-cpu = <&dai_hdmi>, + asoc-cpu = <&dai_hdmi>, <&dai_dp>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, @@ -169,7 +170,7 @@ <&incall_record_tx>, <&incall_music_rx>, <&incall_music_2_rx>, <&sb_5_rx>, <&usb_audio_rx>, <&usb_audio_tx>, <&sb_6_rx>; - asoc-cpu-names = "msm-dai-q6-hdmi.8", + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", @@ -182,8 +183,9 @@ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", "msm-dai-q6-dev.16396"; - asoc-codec = <&stub_codec>; - asoc-codec-names = "msm-stub-codec.1"; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, <&wsa881x_0213>, <&wsa881x_0214>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi index def8ed6e07a7..b4516f381c0c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi @@ -752,7 +752,7 @@ <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_mmss_camss_jpeg0_clk>, + <&clock_mmss clk_mmss_camss_jpeg0_vote_clk>, <&clock_mmss clk_mmss_camss_jpeg_ahb_clk>, <&clock_mmss clk_mmss_camss_jpeg_axi_clk>; qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0>; @@ -766,7 +766,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 666675 666675>; + <62 512 1920000 2880000>; status = "ok"; }; @@ -796,7 +796,7 @@ <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_mmss_camss_jpeg0_clk>, + <&clock_mmss clk_mmss_camss_jpeg0_dma_vote_clk>, <&clock_mmss clk_mmss_camss_jpeg_ahb_clk>, <&clock_mmss clk_mmss_camss_jpeg_axi_clk>; qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0>; @@ -808,7 +808,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 666675 666675>; + <62 512 1920000 2880000>; qcom,max-ds-factor = <128>; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi index 85d6b1d5fba3..fd930d3d1644 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi @@ -451,8 +451,9 @@ msm_ext_disp: qcom,msm_ext_disp { compatible = "qcom,msm-ext-disp"; - hdmi_audio: qcom,msm-hdmi-audio-rx { - compatible = "qcom,msm-hdmi-audio-codec-rx"; + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + qcom,msm_ext_disp = <&msm_ext_disp>; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi index 1d64cefaeb4a..70755ec1b8f5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi @@ -285,6 +285,11 @@ compatible = "qcom,smb138x-parallel-slave"; qcom,pmic-revid = <&smb138x_revid>; reg = <0x1000 0x700>; + + io-channels = <&smb138x_tadc 2>, + <&smb138x_tadc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts new file mode 100644 index 000000000000..e53912071502 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "msmcobalt.dtsi" +#include "msmcobalt-qrd-vr1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM COBALT VR1 Board"; + compatible = "qcom,msmcobalt-qrd", "qcom,msmcobalt", "qcom,qrd"; + qcom,board-id = <0x02000b 0x80>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi new file mode 100644 index 000000000000..c028ea0eeab3 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi @@ -0,0 +1,102 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include "msmcobalt-pinctrl.dtsi" + +&blsp1_uart3_hs { + status = "ok"; +}; + +&ufsphy1 { + vdda-phy-supply = <&pmcobalt_l1>; + vdda-pll-supply = <&pmcobalt_l2>; + vddp-ref-clk-supply = <&pmcobalt_l26>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14600>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pmcobalt_l20>; + vccq-supply = <&pmcobalt_l26>; + vccq2-supply = <&pmcobalt_s4>; + vcc-max-microamp = <750000>; + vccq-max-microamp = <560000>; + vccq2-max-microamp = <750000>; + status = "ok"; +}; + +&ufs_ice { + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pmcobalt_l21>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pmcobalt_l13>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + cd-gpios = <&tlmm 95 0x1>; + + status = "ok"; +}; + +&uartblsp2dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&pmcobalt_gpios { + /* GPIO 6 for Vol+ Key */ + gpio@c500 { + status = "okay"; + qcom,mode = <0>; + qcom,pull = <0>; + qcom,vin-sel = <0>; + qcom,src-sel = <0>; + qcom,out-strength = <1>; + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + status = "okay"; + + vol_up { + label = "volume_up"; + gpios = <&pmcobalt_gpios 6 0x1>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi index 425a902568ae..e0ae9a8873a7 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi @@ -69,3 +69,16 @@ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; + +&soc { + sound-tavil { + qcom,msm-mbhc-hphl-swh = <1>; + /delete-property/ qcom,us-euro-gpios; + }; + + sound-9335 { + qcom,msm-mbhc-hphl-swh = <1>; + /delete-property/ qcom,us-euro-gpios; + }; +}; + diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 256c404bb972..86bc048adeb5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -900,8 +900,10 @@ gfx_cpr: cpr4-ctrl@5061000 { compatible = "qcom,cpr4-msmcobalt-v1-mmss-regulator"; - reg = <0x05061000 0x4000>, <0x00784000 0x1000>; - reg-names = "cpr_ctrl", "fuse_base"; + reg = <0x05061000 0x4000>, + <0x00784000 0x1000>, + <0x05065204 0x4>; + reg-names = "cpr_ctrl", "fuse_base", "aging_allowed"; clocks = <&clock_gpu clk_gpucc_rbcpr_clk>, <&clock_gcc clk_cnoc_clk>; clock-names = "core_clk", "bus_clk"; @@ -912,14 +914,16 @@ qcom,cpr-sensor-time = <1000>; qcom,cpr-loop-time = <5000000>; qcom,cpr-idle-cycles = <15>; - qcom,cpr-step-quot-init-min = <10>; - qcom,cpr-step-quot-init-max = <13>; + qcom,cpr-step-quot-init-min = <8>; + qcom,cpr-step-quot-init-max = <12>; qcom,cpr-count-mode = <0>; /* All-at-once min */ vdd-supply = <&pm8005_s1>; qcom,voltage-step = <4000>; mem-acc-supply = <&gfx_mem_acc_vreg>; qcom,cpr-aging-ref-voltage = <1032000>; + qcom,cpr-aging-allowed-reg-mask = <0x00000003>; + qcom,cpr-aging-allowed-reg-value = <0x00000003>; qcom,cpr-enable; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi index 38cfd58f7f2d..48a23b44b5b2 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi @@ -24,6 +24,8 @@ }; &clock_cpu { + compatible = "qcom,cpu-clock-osm-msmcobalt-v2"; + /delete-property/ qcom,llm-sw-overr; qcom,pwrcl-speedbin0-v0 = < 300000000 0x0004000f 0x01200020 0x1 >, < 364800000 0x05040013 0x01200020 0x1 >, @@ -79,6 +81,34 @@ < 2342400000 0x0404007a 0x0a620062 0x3 >, < 2419200000 0x0404007e 0x0a650065 0x3 >, < 2496000000 0x04040082 0x0a680068 0x3 >; + + qcom,perfcl-speedbin1-v0 = + < 300000000 0x0004000f 0x01200020 0x1 >, + < 345600000 0x05040012 0x01200020 0x1 >, + < 422400000 0x05040016 0x02200020 0x1 >, + < 499200000 0x0504001a 0x02200020 0x1 >, + < 576000000 0x0504001e 0x02200020 0x1 >, + < 652800000 0x05040022 0x03200020 0x1 >, + < 729600000 0x05040026 0x03200020 0x1 >, + < 806400000 0x0504002a 0x03220022 0x1 >, + < 902400000 0x0404002f 0x04260026 0x1 >, + < 979200000 0x04040033 0x04290029 0x1 >, + < 1056000000 0x04040037 0x052c002c 0x1 >, + < 1132800000 0x0404003b 0x052f002f 0x1 >, + < 1190400000 0x0404003e 0x05320032 0x2 >, + < 1267200000 0x04040042 0x06350035 0x2 >, + < 1344000000 0x04040046 0x06380038 0x2 >, + < 1420800000 0x0404004a 0x063b003b 0x2 >, + < 1497600000 0x0404004e 0x073e003e 0x2 >, + < 1574400000 0x04040052 0x07420042 0x2 >, + < 1651200000 0x04040056 0x07450045 0x2 >, + < 1728000000 0x0404005a 0x08480048 0x2 >, + < 1804800000 0x0404005e 0x084b004b 0x2 >, + < 1881600000 0x04040062 0x094e004e 0x2 >, + < 1958400000 0x04040066 0x09520052 0x2 >, + < 2035200000 0x0404006a 0x09550055 0x3 >, + < 2112000000 0x0404006e 0x0a580058 0x3 >, + < 2208000000 0x04040073 0x0a5c005c 0x3 >; }; &msm_cpufreq { @@ -194,28 +224,64 @@ &apc0_cpr { compatible = "qcom,cprh-msmcobalt-v2-kbss-regulator"; + qcom,cpr-corner-switch-delay-time = <1042>; }; &apc0_pwrcl_vreg { regulator-max-microvolt = <23>; - qcom,cpr-corners = <22>; - qcom,cpr-corner-fmax-map = <8 11 18 22>; + + qcom,cpr-fuse-combos = <16>; + qcom,cpr-speed-bins = <2>; + qcom,cpr-speed-bin-corners = <22 22>; + qcom,cpr-corners = + /* Speed bin 0 */ + <22 22 22 22 22 22 22 22>, + /* Speed bin 1 */ + <22 22 22 22 22 22 22 22>; + + qcom,cpr-corner-fmax-map = + /* Speed bin 0 */ + <8 11 18 22>, + /* Speed bin 1 */ + <8 11 18 22>; qcom,cpr-voltage-ceiling = - <688000 688000 688000 688000 688000 - 688000 688000 688000 756000 756000 - 756000 828000 828000 828000 828000 + /* Speed bin 0 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 828000 828000 828000 952000 952000 - 1024000 1024000>; + 1056000 1056000>, + /* Speed bin 1 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 952000 952000 + 1056000 1056000>; qcom,cpr-voltage-floor = + /* Speed bin 0 */ <568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 632000 632000 632000 632000 632000 632000 632000 712000 712000 - 756000 756000>; + 772000 772000>, + /* Speed bin 1 */ + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 632000 632000 632000 632000 + 632000 632000 632000 712000 712000 + 772000 772000>; qcom,cpr-floor-to-ceiling-max-range = + /* Speed bin 0 */ + <55000 55000 55000 55000 + 55000 55000 55000 55000 + 55000 55000 55000 65000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000>, + /* Speed bin 1 */ <55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 65000 @@ -224,6 +290,16 @@ 65000 65000>; qcom,corner-frequencies = + /* Speed bin 0 */ + <300000000 364800000 441600000 + 518400000 595200000 672000000 + 748800000 825600000 883200000 + 960000000 1036800000 1094400000 + 1171200000 1248000000 1324800000 + 1401600000 1478400000 1555200000 + 1670400000 1747200000 1824000000 + 1900800000>, + /* Speed bin 1 */ <300000000 364800000 441600000 518400000 595200000 672000000 748800000 825600000 883200000 @@ -248,6 +324,16 @@ 1559 1392>; qcom,cpr-open-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + /* Speed bin 1 */ <40000 24000 0 0>, <40000 24000 0 0>, <40000 24000 0 0>, @@ -258,6 +344,16 @@ <40000 24000 0 0>; qcom,cpr-closed-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + /* Speed bin 1 */ <20000 26000 0 0>, <20000 26000 0 0>, <20000 26000 0 0>, @@ -274,30 +370,61 @@ &apc1_cpr { compatible = "qcom,cprh-msmcobalt-v2-kbss-regulator"; + qcom,cpr-corner-switch-delay-time = <1042>; }; &apc1_perfcl_vreg { regulator-max-microvolt = <31>; - qcom,cpr-corners = <30>; - qcom,cpr-corner-fmax-map = <8 12 20 30>; + + qcom,cpr-fuse-combos = <16>; + qcom,cpr-speed-bins = <2>; + qcom,cpr-speed-bin-corners = <30 26>; + qcom,cpr-corners = + /* Speed bin 0 */ + <30 30 30 30 30 30 30 30>, + /* Speed bin 1 */ + <26 26 26 26 26 26 26 26>; + + qcom,cpr-corner-fmax-map = + /* Speed bin 0 */ + <8 12 20 30>, + /* Speed bin 1 */ + <8 12 20 26>; qcom,cpr-voltage-ceiling = - <688000 688000 688000 688000 688000 - 688000 688000 688000 756000 756000 - 756000 756000 828000 828000 828000 + /* Speed bin 0 */ + <828000 828000 828000 828000 828000 828000 828000 828000 828000 828000 - 952000 952000 952000 1024000 1024000 - 1024000 1024000 1024000 1024000 1024000>; + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 952000 952000 952000 1056000 1056000 + 1056000 1056000 1056000 1056000 1056000>, + /* Speed bin 1 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 952000 952000 952000 1056000 1056000 + 1056000>; qcom,cpr-voltage-floor = + /* Speed bin 0 */ <568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 632000 632000 632000 632000 632000 632000 632000 632000 - 712000 712000 712000 756000 756000 - 756000 756000 756000 756000 756000>; + 712000 712000 712000 772000 772000 + 772000 772000 772000 772000 772000>, + /* Speed bin 1 */ + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 568000 632000 632000 632000 + 632000 632000 632000 632000 632000 + 712000 712000 712000 772000 772000 + 772000>; qcom,cpr-floor-to-ceiling-max-range = + /* Speed bin 0 */ <55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 @@ -305,9 +432,18 @@ 65000 65000 65000 65000 65000 65000 65000 65000 65000 65000 65000 65000 + 65000 65000>, + /* Speed bin 1 */ + <55000 55000 55000 55000 + 55000 55000 55000 55000 + 55000 55000 55000 55000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 65000 65000>; qcom,corner-frequencies = + /* Speed bin 0 */ <300000000 345600000 422400000 499200000 576000000 652800000 729600000 806400000 902400000 @@ -317,7 +453,17 @@ 1651200000 1728000000 1804800000 1881600000 1958400000 2035200000 2112000000 2188800000 2265600000 - 2342400000 2419200000 2496000000>; + 2342400000 2419200000 2496000000>, + /* Speed bin 1 */ + <300000000 345600000 422400000 + 499200000 576000000 652800000 + 729600000 806400000 902400000 + 979200000 1056000000 1132800000 + 1190400000 1267200000 1344000000 + 1420800000 1497600000 1574400000 + 1651200000 1728000000 1804800000 + 1881600000 1958400000 2035200000 + 2112000000 2208000000>; qcom,cpr-ro-scaling-factor = <4001 4019 3747 3758 3564 3480 2336 @@ -334,6 +480,16 @@ 1559 1392>; qcom,cpr-open-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + /* Speed bin 1 */ <8000 0 0 52000>, <8000 0 0 52000>, <8000 0 0 52000>, @@ -344,6 +500,16 @@ <8000 0 0 52000>; qcom,cpr-closed-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + /* Speed bin 1 */ <0 0 0 50000>, <0 0 0 50000>, <0 0 0 50000>, @@ -373,8 +539,8 @@ qcom,cpr-corner-fmax-map = <1 3 5 8>; qcom,cpr-voltage-ceiling = - <616000 676000 740000 800000 828000 - 884000 952000 1024000>; + <656000 716000 772000 880000 908000 + 948000 1016000 1088000>; qcom,cpr-voltage-floor = <516000 516000 532000 584000 632000 diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 4ea1cf31c4dc..0a3eb6f70644 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -803,13 +803,15 @@ }; clock_cpu: qcom,cpu-clock-cobalt@179c0000 { - compatible = "qcom,cpu-clock-osm"; - reg = <0x179C0000 0x4000>, + compatible = "qcom,cpu-clock-osm-msmcobalt-v1"; + reg = <0x179c0000 0x4000>, <0x17916000 0x1000>, <0x17816000 0x1000>, - <0x179D1000 0x1000>; + <0x179d1000 0x1000>, + <0x00784130 0x8>, + <0x1791101c 0x8>; reg-names = "osm", "pwrcl_pll", "perfcl_pll", - "apcs_common"; + "apcs_common", "perfcl_efuse", "debug"; vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; vdd-perfcl-supply = <&apc1_perfcl_vreg>; @@ -942,10 +944,11 @@ reg = <0x162000 0x4>; reg-names = "cc_base"; clock-names = "debug_gpu_clk", "debug_gfx_clk", - "debug_mmss_clk"; + "debug_mmss_clk", "debug_cpu_clk"; clocks = <&clock_gpu clk_gpucc_gcc_dbg_clk>, <&clock_gfx clk_gfxcc_dbg_clk>, - <&clock_mmss clk_mmss_debug_mux>; + <&clock_mmss clk_mmss_debug_mux>, + <&clock_cpu clk_cpu_debug_mux>; #clock-cells = <1>; }; @@ -1398,6 +1401,27 @@ qcom,glinkpkt-ch-name = "DATA40_CNTL"; qcom,glinkpkt-dev-name = "smdcntl8"; }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; }; pcie0: qcom,pcie@01c00000 { @@ -1804,6 +1828,10 @@ "utmi_clk", "sleep_clk", "xo"; qcom,core-clk-rate = <120000000>; + + resets = <&clock_gcc USB_30_BCR>; + reset-names = "core_reset"; + dwc3@a800000 { compatible = "snps,dwc3"; reg = <0x0a800000 0xcd00>; @@ -1870,10 +1898,11 @@ phy_type= "utmi"; clocks = <&clock_gcc clk_ln_bb_clk1>, - <&clock_gcc clk_gcc_rx1_usb2_clkref_clk>, - <&clock_gcc clk_gcc_qusb2phy_prim_reset>; + <&clock_gcc clk_gcc_rx1_usb2_clkref_clk>; + clock-names = "ref_clk_src", "ref_clk"; - clock-names = "ref_clk_src", "ref_clk", "phy_reset"; + resets = <&clock_gcc QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; }; ssphy: ssphy@c010000 { @@ -2021,13 +2050,15 @@ clocks = <&clock_gcc clk_gcc_usb3_phy_aux_clk>, <&clock_gcc clk_gcc_usb3_phy_pipe_clk>, - <&clock_gcc clk_gcc_usb3_phy_reset>, - <&clock_gcc clk_gcc_usb3phy_phy_reset>, <&clock_gcc clk_ln_bb_clk1>, <&clock_gcc clk_gcc_usb3_clkref_clk>; - clock-names = "aux_clk", "pipe_clk", "phy_reset", - "phy_phy_reset", "ref_clk_src", "ref_clk"; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk"; + + resets = <&clock_gcc USB3_PHY_BCR>, + <&clock_gcc USB3PHY_PHY_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; }; usb_audio_qmi_dev { @@ -2575,7 +2606,12 @@ "iface_clk", "noc_axi_clk", "bus_clk", "maxi_clk"; qcom,pas-id = <9>; - qcom,proxy-timeout-ms = <10000>; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; qcom,firmware-name = "venus"; memory-region = <&pil_video_mem>; status = "ok"; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi new file mode 100644 index 000000000000..2c09774c1391 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi @@ -0,0 +1,358 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* Stub regulators */ + +/ { + /* PM660A S1 - VDD_APC0 supply */ + pm660_s1a: regulator-pm660-s1a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s1a"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <565000>; + regulator-max-microvolt = <1170000>; + }; + + /* PM660A S2 + S3 = VDD_APC1 supply */ + pm660_s2a: regulator-pm660-s2a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s2a"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <565000>; + regulator-max-microvolt = <1170000>; + }; + + pm660_s4a: regulator-pm660-s4a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s4a"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1805000>; + regulator-max-microvolt = <2040000>; + }; + + pm660_s5a: regulator-pm660-s5a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s5a"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + }; + + pm660_s6a: regulator-pm660-s6a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s6a"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <504000>; + regulator-max-microvolt = <992000>; + }; + + pm660_s1b: regulator-pm660-s1b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s1b"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1125000>; + regulator-max-microvolt = <1125000>; + }; + + pm660_s2b: regulator-pm660-s2b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s2b"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + /* PM660B S3 + S4 - VDD_CX supply */ + pm660_s3b_level: regulator-pm660-s3b-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s3b_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + pm660_s3b_floor_level: regulator-pm660-s3b-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s3b_floor_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + pm660_s3b_level_ao: regulator-pm660-s3b-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s3b_level_ao"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + /* PM660B S5 - VDD_MX supply */ + pm660_s5b_level: regulator-pm660-s5b-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s5b_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + pm660_s5b_floor_level: regulator-pm660-s5b-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s5b_floor_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + pm660_s5b_level_ao: regulator-pm660-s5b-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s5b_level_ao"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + pm660_l1a: regulator-pm660-l1a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l1a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1250000>; + }; + + pm660_l2a: regulator-pm660-l2a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l2a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + }; + + pm660_l3a: regulator-pm660-l3a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l3a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + }; + + /* TODO: remove if ADRASTEA CX/MX not voted from APPS */ + pm660_l5a: regulator-pm660-l5a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l5a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <525000>; + regulator-max-microvolt = <950000>; + }; + + pm660_l6a: regulator-pm660-l6a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l6a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1370000>; + }; + + pm660_l7a: regulator-pm660-l7a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l7a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm660_l8a: regulator-pm660-l8a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l8a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + }; + + pm660_l9a: regulator-pm660-l9a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l9a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + }; + + pm660_l10a: regulator-pm660-l10a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l10a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + }; + + pm660_l11a: regulator-pm660-l11a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l11a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + }; + + pm660_l12a: regulator-pm660-l12a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l12a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + }; + + pm660_l13a: regulator-pm660-l13a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l13a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1950000>; + }; + + pm660_l14a: regulator-pm660-l14a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l14a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1900000>; + }; + + pm660_l15a: regulator-pm660-l15a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l15a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2950000>; + }; + + pm660_l17a: regulator-pm660-l17a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l17a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2950000>; + }; + + pm660_l19a: regulator-pm660-l19a { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l19a"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + }; + + pm660_l1b: regulator-pm660-l1b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l1b"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <925000>; + }; + + pm660_l2b: regulator-pm660-l2b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l2b"; + qcom,hpm-min-load = <5000>; + regulator-min-microvolt = <350000>; + regulator-max-microvolt = <3100000>; + }; + + pm660_l3b: regulator-pm660-l3b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l3b"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <3600000>; + }; + + pm660_l4b: regulator-pm660-l4b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l4b"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2950000>; + }; + + pm660_l5b: regulator-pm660-l5b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l5b"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1721000>; + regulator-max-microvolt = <3600000>; + }; + + pm660_l6b: regulator-pm660-l6b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l6b"; + qcom,hpm-min-load = <5000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3300000>; + }; + + pm660_l7b: regulator-pm660-l7b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l7b"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3125000>; + }; + + pm660_l8b: regulator-pm660-l8b { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l8b"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + }; + + /* PM660B L9 = VDD_SSC_CX supply */ + pm660_l9b_level: regulator-pm660-l9b-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l9b_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + pm660_l9b_floor_level: regulator-pm660-l9b-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l9b_floor_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + /* PM660B L10 = VDD_SSC_MX supply */ + pm660_l10b_level: regulator-pm660-l10b-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l10b_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + pm660_l10b_floor_level: regulator-pm660-l10b-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l10b_floor_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>; + regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>; + }; + + /* GFX Supply */ + gfx_vreg_corner: regulator-gfx-corner { + compatible = "qcom,stub-regulator"; + regulator-name = "gfx_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts index 6631d31bac6d..0d694a6cd9fa 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts @@ -22,7 +22,7 @@ qcom,board-id = <15 0>; }; -&uartblsp2dm1 { +&uartblsp1dm1 { status = "ok"; pinctrl-names = "default"; pinctrl-0 = <&uart_console_active>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts index 9840343fc3a7..eaaa1b407425 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts @@ -22,7 +22,7 @@ qcom,board-id = <16 0>; }; -&uartblsp2dm1 { +&uartblsp1dm1 { status = "ok"; pinctrl-names = "default"; pinctrl-0 = <&uart_console_active>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index e46041cdd501..7c4e7f0ee55a 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -15,6 +15,7 @@ #include <dt-bindings/clock/qcom,gpu-msmfalcon.h> #include <dt-bindings/clock/qcom,mmcc-msmfalcon.h> #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h> / { model = "Qualcomm Technologies, Inc. MSM FALCON"; @@ -23,7 +24,7 @@ interrupt-parent = <&intc>; aliases { - serial0 = &uartblsp2dm1; + serial0 = &uartblsp1dm1; }; chosen { @@ -246,6 +247,16 @@ 3200 3200 3200 3200 3200 3200>; }; + uartblsp1dm1: serial@0c170000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xc170000 0x1000>; + interrupts = <0 108 0>; + status = "disabled"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + }; + uartblsp2dm1: serial@0c1b0000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xc1b0000 0x1000>; @@ -472,6 +483,27 @@ qcom,glinkpkt-ch-name = "DATA40_CNTL"; qcom,glinkpkt-dev-name = "smdcntl8"; }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; }; qcom,ipc_router { @@ -511,3 +543,102 @@ }; #include "msmfalcon-ion.dtsi" +#include "msmfalcon-regulator.dtsi" +#include "msm-gdsc-cobalt.dtsi" + +&gdsc_usb30 { + clock-names = "core_clk"; + clocks = <&clock_gcc GCC_USB30_MASTER_CLK>; + status = "ok"; +}; + +&gdsc_ufs { + clock-names = "bus_clk", "ice_clk", "unipro_clk"; + clocks = <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_UFS_ICE_CORE_CLK>, + <&clock_gcc GCC_UFS_UNIPRO_CORE_CLK>; + status = "ok"; +}; + +&gdsc_bimc_smmu { + clock-names = "bus_clk"; + clocks = <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>; + proxy-supply = <&gdsc_bimc_smmu>; + qcom,proxy-consumer-enable; + status = "ok"; +}; + +&gdsc_hlos1_vote_lpass_adsp { + status = "ok"; +}; + +&gdsc_hlos1_vote_lpass_core { + status = "ok"; +}; + +&gdsc_venus { + clock-names = "bus_clk", "core_clk"; + clocks = <&clock_mmss MMSS_VIDEO_AXI_CLK>, + <&clock_mmss MMSS_VIDEO_CORE_CLK>; + status = "ok"; +}; + +&gdsc_venus_core0 { + clock-names = "core0_clk"; + clocks = <&clock_mmss MMSS_VIDEO_SUBCORE0_CLK>; + qcom,support-hw-trigger; + status = "ok"; +}; + +&gdsc_camss_top { + clock-names = "bus_clk", "vfe_axi"; + clocks = <&clock_mmss MMSS_CAMSS_CPP_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>; + status = "ok"; +}; + +&gdsc_vfe0 { + clock-names = "core0_clk" , "core0_stream_clk"; + clocks = <&clock_mmss MMSS_CAMSS_VFE0_CLK>, + <&clock_mmss MMSS_CAMSS_VFE0_STREAM_CLK>; + parent-supply = <&gdsc_camss_top>; + status = "ok"; +}; + +&gdsc_vfe1 { + clock-names = "core1_clk" , "core1_stream_clk"; + clocks = <&clock_mmss MMSS_CAMSS_VFE1_CLK>, + <&clock_mmss MMSS_CAMSS_VFE1_STREAM_CLK>; + parent-supply = <&gdsc_camss_top>; + status = "ok"; +}; + +&gdsc_cpp { + clock-names = "core_clk"; + clocks = <&clock_mmss MMSS_CAMSS_CPP_CLK>; + parent-supply = <&gdsc_camss_top>; + status = "ok"; +}; + +&gdsc_mdss { + clock-names = "bus_clk", "rot_clk"; + clocks = <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_MDSS_ROT_CLK>; + proxy-supply = <&gdsc_mdss>; + qcom,proxy-consumer-enable; + status = "ok"; +}; + +&gdsc_gpu_gx { + clock-names = "bimc_core_clk", "core_clk", "core_root_clk"; + clocks = <&clock_gcc GCC_GPU_BIMC_GFX_CLK>, + <&clock_gfx GPUCC_GFX3D_CLK>, + <&clock_gfx GFX3D_CLK_SRC>; + qcom,force-enable-root-clk; + parent-supply = <&gfx_vreg_corner>; + status = "ok"; +}; + +&gdsc_gpu_cx { + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts new file mode 100644 index 000000000000..d3c62dbf99f2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "msmtriton.dtsi" +#include "msmfalcon-pinctrl.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM TRITON RUMI"; + compatible = "qcom,msmtriton-rumi", "qcom,msmtriton", "qcom,rumi"; + qcom,board-id = <15 0>; +}; + +&uartblsp1dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi new file mode 100644 index 000000000000..7b7501dceff3 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi @@ -0,0 +1,263 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "skeleton64.dtsi" +#include <dt-bindings/clock/qcom,gcc-msmfalcon.h> +#include <dt-bindings/clock/qcom,gpu-msmfalcon.h> +#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +/ { + model = "Qualcomm Technologies, Inc. MSMTRITON"; + compatible = "qcom,msmtriton"; + qcom,msm-id = <318 0x0>; + interrupt-parent = <&intc>; + + aliases { + serial0 = &uartblsp1dm1; + }; + + chosen { + stdout-path = "serial0"; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x101>; + enable-method = "psci"; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x102>; + enable-method = "psci"; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x103>; + enable-method = "psci"; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + }; + }; + + soc: soc { }; + +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17b00000 0x100000>; /* GICR * 8 */ + #interrupt-cells = <3>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + interrupts = <1 9 4>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + uartblsp1dm1: serial@0c170000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xc170000 0x1000>; + interrupts = <0 108 0>; + status = "disabled"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + }; + + uartblsp2dm1: serial@0c1b0000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xc1b0000 0x1000>; + interrupts = <0 114 0>; + status = "disabled"; + clocks = <&clock_gcc GCC_BLSP2_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; + clock-names = "core", "iface"; + }; + + timer@17920000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17920000 0x1000>; + clock-frequency = <19200000>; + + frame@17921000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 7 0x4>; + reg = <0x17921000 0x1000>, + <0x17922000 0x1000>; + }; + + frame@17923000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0x17923000 0x1000>; + status = "disabled"; + }; + + frame@17924000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0x17924000 0x1000>; + status = "disabled"; + }; + + frame@17925000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0x17925000 0x1000>; + status = "disabled"; + }; + + frame@17926000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0x17926000 0x1000>; + status = "disabled"; + }; + + frame@17927000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0x17927000 0x1000>; + status = "disabled"; + }; + + frame@17928000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0x17928000 0x1000>; + status = "disabled"; + }; + }; + + clock_gcc: qcom,dummycc { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + }; + + clock_mmss: qcom,dummycc { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + }; + + clock_gfx: qcom,dummycc { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + }; +}; diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index 1e6a1c66ed82..0a20c52bd3b2 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -460,6 +460,7 @@ CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_QCOM_REMOTEQDSS=y CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig index 1e6a1c66ed82..0a20c52bd3b2 100644 --- a/arch/arm/configs/msmfalcon_defconfig +++ b/arch/arm/configs/msmfalcon_defconfig @@ -460,6 +460,7 @@ CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_QCOM_REMOTEQDSS=y CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index 69261c70e1dd..d6ed9ac56bf1 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -16,6 +16,7 @@ config ARCH_MSMFALCON select MULTI_IRQ_HANDLER select HAVE_ARM_ARCH_TIMER select MAY_HAVE_SPARSE_IRQ + select COMMON_CLK_MSM select PINCTRL_MSM_TLMM select USE_PINCTRL_IRQ select MSM_PM if PM diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index eb02bc09b63d..ee4efe58d0c8 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -95,6 +95,15 @@ config ARCH_MSMFALCON If you do not wish to build a kernel that runs on this chipset,say 'N' here. +config ARCH_MSMTRITON + bool "Enable Support for Qualcomm Technologies Inc MSMTRITON" + depends on ARCH_QCOM + select COMMON_CLK_MSM + help + This enables support for the MSMTRITON chipset. + If you do not wish to build a kernel that runs + on this chipset,say 'N' here. + config ARCH_ROCKCHIP bool "Rockchip Platforms" select ARCH_HAS_RESET_CONTROLLER diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 3adda1fc4109..5d76e41d4fed 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -380,6 +380,7 @@ CONFIG_MSM_VIDC_V4L2=m CONFIG_MSM_VIDC_VMEM=m CONFIG_MSM_VIDC_GOVERNORS=m CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_ARMCLCD=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 686e1c22c5ae..367822dd0a94 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -383,6 +383,7 @@ CONFIG_MSM_VIDC_V4L2=m CONFIG_MSM_VIDC_VMEM=m CONFIG_MSM_VIDC_GOVERNORS=m CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y @@ -523,6 +524,7 @@ CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_IRQ_HELPER=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y CONFIG_MSM_GLADIATOR_ERP_V2=y CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y diff --git a/arch/arm64/configs/msmfalcon-perf_defconfig b/arch/arm64/configs/msmfalcon-perf_defconfig index f2eafd610cac..39c2d3f71c5a 100644 --- a/arch/arm64/configs/msmfalcon-perf_defconfig +++ b/arch/arm64/configs/msmfalcon-perf_defconfig @@ -44,6 +44,7 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSMCOBALT=y CONFIG_ARCH_MSMHAMSTER=y CONFIG_ARCH_MSMFALCON=y +CONFIG_ARCH_MSMTRITON=y CONFIG_PCI=y CONFIG_PCI_MSM=y CONFIG_SCHED_MC=y diff --git a/arch/arm64/configs/msmfalcon_defconfig b/arch/arm64/configs/msmfalcon_defconfig index 3742fe210dc2..a277038b3fc3 100644 --- a/arch/arm64/configs/msmfalcon_defconfig +++ b/arch/arm64/configs/msmfalcon_defconfig @@ -45,6 +45,7 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSMCOBALT=y CONFIG_ARCH_MSMHAMSTER=y CONFIG_ARCH_MSMFALCON=y +CONFIG_ARCH_MSMTRITON=y CONFIG_PCI=y CONFIG_PCI_MSM=y CONFIG_SCHED_MC=y diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index d925715c822f..30cf6f5961ef 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -172,8 +172,8 @@ static inline void gic_write_sre(u32 val) isb(); } -#define gic_read_typer(c) readq_relaxed(c) -#define gic_write_irouter(v, c) writeq_relaxed(v, c) +#define gic_read_typer(c) readq_relaxed_no_log(c) +#define gic_write_irouter(v, c) writeq_relaxed_no_log(v, c) #endif /* __ASSEMBLY__ */ #endif /* __ASM_ARCH_GICV3_H */ diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c index aeb0f25c9289..471fb3cb8c5f 100644 --- a/arch/arm64/kernel/io.c +++ b/arch/arm64/kernel/io.c @@ -28,21 +28,21 @@ void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) { while (count && (!IS_ALIGNED((unsigned long)from, 8) || !IS_ALIGNED((unsigned long)to, 8))) { - *(u8 *)to = __raw_readb(from); + *(u8 *)to = __raw_readb_no_log(from); from++; to++; count--; } while (count >= 8) { - *(u64 *)to = __raw_readq(from); + *(u64 *)to = __raw_readq_no_log(from); from += 8; to += 8; count -= 8; } while (count) { - *(u8 *)to = __raw_readb(from); + *(u8 *)to = __raw_readb_no_log(from); from++; to++; count--; @@ -57,21 +57,21 @@ void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) { while (count && (!IS_ALIGNED((unsigned long)to, 8) || !IS_ALIGNED((unsigned long)from, 8))) { - __raw_writeb(*(volatile u8 *)from, to); + __raw_writeb_no_log(*(volatile u8 *)from, to); from++; to++; count--; } while (count >= 8) { - __raw_writeq(*(volatile u64 *)from, to); + __raw_writeq_no_log(*(volatile u64 *)from, to); from += 8; to += 8; count -= 8; } while (count) { - __raw_writeb(*(volatile u8 *)from, to); + __raw_writeb_no_log(*(volatile u8 *)from, to); from++; to++; count--; @@ -91,19 +91,19 @@ void __memset_io(volatile void __iomem *dst, int c, size_t count) qc |= qc << 32; while (count && !IS_ALIGNED((unsigned long)dst, 8)) { - __raw_writeb(c, dst); + __raw_writeb_no_log(c, dst); dst++; count--; } while (count >= 8) { - __raw_writeq(qc, dst); + __raw_writeq_no_log(qc, dst); dst += 8; count -= 8; } while (count) { - __raw_writeb(c, dst); + __raw_writeb_no_log(c, dst); dst++; count--; } diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 176b59f5bc47..bd70f8db469b 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -117,6 +117,26 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) EXPORT_SYMBOL_GPL(platform_get_irq); /** + * platform_irq_count - Count the number of IRQs a platform device uses + * @dev: platform device + * + * Return: Number of IRQs a platform device uses or EPROBE_DEFER + */ +int platform_irq_count(struct platform_device *dev) +{ + int ret, nr = 0; + + while ((ret = platform_get_irq(dev, nr)) >= 0) + nr++; + + if (ret == -EPROBE_DEFER) + return ret; + + return nr; +} +EXPORT_SYMBOL_GPL(platform_irq_count); + +/** * platform_get_resource_byname - get a resource for a device by name * @dev: platform device * @type: resource type diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 7cb64e012f1f..a1721a3b80cc 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1780,6 +1780,15 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + mutex_lock(&driver->diag_maskclear_mutex); + if (driver->mask_clear) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag:%s: count = %zu\n", __func__, count); + mutex_unlock(&driver->diag_maskclear_mutex); + return -EIO; + } + mutex_unlock(&driver->diag_maskclear_mutex); + mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)(mask_info->ptr); for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index eb715cc8501c..ca54b24ec604 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -215,6 +215,12 @@ static void usb_connect_work_fn(struct work_struct *work) */ static void usb_disconnect(struct diag_usb_info *ch) { + if (!ch) + return; + + if (!atomic_read(&ch->connected) && driver->usb_connected) + diag_clear_masks(NULL); + if (ch && ch->ops && ch->ops->close) ch->ops->close(ch->ctxt, DIAG_USB_MODE); } diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index dccaa6a0d9c4..2aef98f4fe04 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -467,6 +467,8 @@ struct diagchar_dev { struct class *diagchar_class; struct device *diag_dev; int ref_count; + int mask_clear; + struct mutex diag_maskclear_mutex; struct mutex diagchar_mutex; struct mutex diag_file_mutex; wait_queue_head_t wait_q; @@ -625,6 +627,7 @@ void diag_cmd_remove_reg(struct diag_cmd_reg_entry_t *entry, uint8_t proc); void diag_cmd_remove_reg_by_pid(int pid); void diag_cmd_remove_reg_by_proc(int proc); int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry); +void diag_clear_masks(struct diag_md_session_t *info); void diag_record_stats(int type, int flag); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index a39e4929d999..9ed43cdc3845 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -389,6 +389,27 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask) return ret; } +void diag_clear_masks(struct diag_md_session_t *info) +{ + int ret; + char cmd_disable_log_mask[] = { 0x73, 0, 0, 0, 0, 0, 0, 0}; + char cmd_disable_msg_mask[] = { 0x7D, 0x05, 0, 0, 0, 0, 0, 0}; + char cmd_disable_event_mask[] = { 0x60, 0}; + + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: %s: masks clear request upon %s\n", __func__, + ((info) ? "ODL exit" : "USB Disconnection")); + + ret = diag_process_apps_masks(cmd_disable_log_mask, + sizeof(cmd_disable_log_mask), info); + ret = diag_process_apps_masks(cmd_disable_msg_mask, + sizeof(cmd_disable_msg_mask), info); + ret = diag_process_apps_masks(cmd_disable_event_mask, + sizeof(cmd_disable_event_mask), info); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag:%s: masks cleared successfully\n", __func__); +} + static void diag_close_logging_process(const int pid) { int i; @@ -400,6 +421,12 @@ static void diag_close_logging_process(const int pid) if (!session_info) return; + diag_clear_masks(session_info); + + mutex_lock(&driver->diag_maskclear_mutex); + driver->mask_clear = 1; + mutex_unlock(&driver->diag_maskclear_mutex); + session_peripheral_mask = session_info->peripheral_mask; diag_md_session_close(session_info); for (i = 0; i < NUM_MD_SESSIONS; i++) @@ -475,9 +502,14 @@ static int diag_remove_client_entry(struct file *file) } static int diagchar_close(struct inode *inode, struct file *file) { + int ret; DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag: process exit %s\n", current->comm); - return diag_remove_client_entry(file); + ret = diag_remove_client_entry(file); + mutex_lock(&driver->diag_maskclear_mutex); + driver->mask_clear = 0; + mutex_unlock(&driver->diag_maskclear_mutex); + return ret; } void diag_record_stats(int type, int flag) @@ -3358,6 +3390,7 @@ static int __init diagchar_init(void) non_hdlc_data.len = 0; mutex_init(&driver->hdlc_disable_mutex); mutex_init(&driver->diagchar_mutex); + mutex_init(&driver->diag_maskclear_mutex); mutex_init(&driver->diag_file_mutex); mutex_init(&driver->delayed_rsp_mutex); mutex_init(&apps_data_mutex); diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 8205e5b05d85..0111b02634c8 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1232,8 +1232,6 @@ static int diagfwd_mux_open(int id, int mode) static int diagfwd_mux_close(int id, int mode) { - uint8_t i; - switch (mode) { case DIAG_USB_MODE: driver->usb_connected = 0; @@ -1248,15 +1246,16 @@ static int diagfwd_mux_close(int id, int mode) driver->md_session_mode == DIAG_MD_NONE) || (driver->md_session_mode == DIAG_MD_PERIPHERAL)) { /* - * In this case the channel must not be closed. This case - * indicates that the USB is removed but there is a client - * running in background with Memory Device mode + * This case indicates that the USB is removed + * but there is a client running in background + * with Memory Device mode. */ } else { - for (i = 0; i < NUM_PERIPHERALS; i++) { - diagfwd_close(i, TYPE_DATA); - diagfwd_close(i, TYPE_CMD); - } + /* + * With clearing of masks on ODL exit and + * USB disconnection, closing of the channel is + * not needed.This enables read and drop of stale packets. + */ /* Re enable HDLC encoding */ pr_debug("diag: In %s, re-enabling HDLC encoding\n", __func__); diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig index d94678e9e4fc..650a23ea1ead 100644 --- a/drivers/clk/msm/Kconfig +++ b/drivers/clk/msm/Kconfig @@ -2,6 +2,7 @@ config COMMON_CLK_MSM tristate "Support for MSM clock controllers" depends on OF depends on ARCH_QCOM + select RATIONAL help This support clock controller used by MSM devices which support global, mmss and gpu clock controller. diff --git a/drivers/clk/msm/clock-gcc-cobalt.c b/drivers/clk/msm/clock-gcc-cobalt.c index e469c61cc3db..71c5541d0c0d 100644 --- a/drivers/clk/msm/clock-gcc-cobalt.c +++ b/drivers/clk/msm/clock-gcc-cobalt.c @@ -2354,11 +2354,13 @@ static struct mux_clk gcc_debug_mux = { &gpu_gcc_debug_clk.c, &gfx_gcc_debug_clk.c, &debug_mmss_clk.c, + &debug_cpu_clk.c, ), MUX_SRC_LIST( { &gpu_gcc_debug_clk.c, 0x013d }, { &gfx_gcc_debug_clk.c, 0x013d }, { &debug_mmss_clk.c, 0x0022 }, + { &debug_cpu_clk.c, 0x00c0 }, { &snoc_clk.c, 0x0000 }, { &cnoc_clk.c, 0x000e }, { &bimc_clk.c, 0x00a9 }, @@ -2853,6 +2855,7 @@ static struct clk_lookup msm_clocks_measure_cobalt[] = { CLK_LIST(gpu_gcc_debug_clk), CLK_LIST(gfx_gcc_debug_clk), CLK_LIST(debug_mmss_clk), + CLK_LIST(debug_cpu_clk), CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"), }; @@ -2889,6 +2892,9 @@ static int msm_clock_debug_cobalt_probe(struct platform_device *pdev) debug_mmss_clk.dev = &pdev->dev; debug_mmss_clk.clk_id = "debug_mmss_clk"; + debug_cpu_clk.dev = &pdev->dev; + debug_cpu_clk.clk_id = "debug_cpu_clk"; + ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_measure_cobalt, ARRAY_SIZE(msm_clocks_measure_cobalt)); diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index 9d605503520f..8ae6a4e994f0 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -48,6 +48,7 @@ enum clk_osm_bases { OSM_BASE, PLL_BASE, + EFUSE_BASE, NUM_BASES, }; @@ -76,6 +77,7 @@ enum clk_osm_trace_packet_id { #define MEM_ACC_SEQ_CONST(n) (n) #define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40)) #define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n))) +#define SEQ_REG1_MSMCOBALT_V2 0x1048 #define OSM_TABLE_SIZE 40 #define MAX_CLUSTER_CNT 2 @@ -115,7 +117,7 @@ enum clk_osm_trace_packet_id { #define PLL_TEST_CTL_HI 0x1C #define PLL_STATUS 0x2C #define PLL_LOCK_DET_MASK BIT(16) -#define PLL_WAIT_LOCK_TIME_US 5 +#define PLL_WAIT_LOCK_TIME_US 10 #define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000) #define PLL_MIN_LVAL 43 @@ -164,7 +166,8 @@ enum clk_osm_trace_packet_id { #define DCVS_DROOP_EN_MASK BIT(5) #define LMH_PS_EN_MASK BIT(6) #define IGNORE_PLL_LOCK_MASK BIT(15) -#define SAFE_FREQ_WAIT_NS 1000 +#define SAFE_FREQ_WAIT_NS 5000 +#define DEXT_DECREMENT_WAIT_NS 1000 #define DCVS_BOOST_TIMER_REG0 0x1084 #define DCVS_BOOST_TIMER_REG1 0x1088 #define DCVS_BOOST_TIMER_REG2 0x108C @@ -173,7 +176,8 @@ enum clk_osm_trace_packet_id { #define PS_BOOST_TIMER_REG2 0x109C #define BOOST_PROG_SYNC_DELAY_REG 0x10A0 #define DROOP_CTRL_REG 0x10A4 -#define DROOP_PROG_SYNC_DELAY_REG 0x10B8 +#define DROOP_RELEASE_TIMER_CTRL 0x10A8 +#define DROOP_PROG_SYNC_DELAY_REG 0x10BC #define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC #define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0 #define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4 @@ -208,7 +212,13 @@ enum clk_osm_trace_packet_id { #define PLL_DD_D0_USER_CTL_LO 0x17916208 #define PLL_DD_D1_USER_CTL_LO 0x17816208 +#define PWRCL_EFUSE_SHIFT 0 +#define PWRCL_EFUSE_MASK 0 +#define PERFCL_EFUSE_SHIFT 29 +#define PERFCL_EFUSE_MASK 0x7 + static void __iomem *virt_base; +static void __iomem *debug_base; #define lmh_lite_clk_src_source_val 1 @@ -335,6 +345,9 @@ struct clk_osm { bool trace_en; }; +static bool msmcobalt_v1; +static bool msmcobalt_v2; + static inline void clk_osm_masked_write_reg(struct clk_osm *c, u32 val, u32 offset, u32 mask) { @@ -525,14 +538,45 @@ static struct clk_osm perfcl_clk = { }, }; +static struct clk_ops clk_ops_cpu_dbg_mux; + +static struct mux_clk cpu_debug_mux = { + .offset = 0x0, + .mask = 0x3, + .shift = 8, + .ops = &mux_reg_ops, + MUX_SRC_LIST( + { &pwrcl_clk.c, 0x00 }, + { &perfcl_clk.c, 0x01 }, + ), + .base = &debug_base, + .c = { + .dbg_name = "cpu_debug_mux", + .ops = &clk_ops_cpu_dbg_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(cpu_debug_mux.c), + }, +}; + static struct clk_lookup cpu_clocks_osm[] = { CLK_LIST(pwrcl_clk), CLK_LIST(perfcl_clk), CLK_LIST(sys_apcsaux_clk_gcc), CLK_LIST(xo_ao), CLK_LIST(osm_clk_src), + CLK_LIST(cpu_debug_mux), }; +static unsigned long cpu_dbg_mux_get_rate(struct clk *clk) +{ + /* Account for the divider between the clock and the debug mux */ + if (!strcmp(clk->parent->dbg_name, "pwrcl_clk")) + return clk->rate/4; + else if (!strcmp(clk->parent->dbg_name, "perfcl_clk")) + return clk->rate/8; + return clk->rate; +} + static void clk_osm_print_osm_table(struct clk_osm *c) { int i; @@ -901,6 +945,22 @@ static int clk_osm_resources_init(struct platform_device *pdev) } } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug"); + if (!res) { + dev_err(&pdev->dev, "Failed to get debug mux base\n"); + return -EINVAL; + } + + debug_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!debug_base) { + dev_err(&pdev->dev, "Unable to map in debug mux base\n"); + return -ENOMEM; + } + + clk_ops_cpu_dbg_mux = clk_ops_gen_mux; + clk_ops_cpu_dbg_mux.get_rate = cpu_dbg_mux_get_rate; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_common"); if (!res) { dev_err(&pdev->dev, "Failed to get apcs common base\n"); @@ -913,6 +973,35 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } + /* efuse speed bin fuses are optional */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pwrcl_efuse"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in pwrcl_efuse base\n"); + return -ENOMEM; + } + pwrcl_clk.pbases[EFUSE_BASE] = pbase; + pwrcl_clk.vbases[EFUSE_BASE] = vbase; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "perfcl_efuse"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in perfcl_efuse base\n"); + return -ENOMEM; + } + perfcl_clk.pbases[EFUSE_BASE] = pbase; + perfcl_clk.vbases[EFUSE_BASE] = vbase; + } + vdd_pwrcl = devm_regulator_get(&pdev->dev, "vdd-pwrcl"); if (IS_ERR(vdd_pwrcl)) { rc = PTR_ERR(vdd_pwrcl); @@ -1582,6 +1671,9 @@ static void clk_osm_setup_osm_was(struct clk_osm *c) u32 cc_hyst; u32 val; + if (msmcobalt_v2) + return; + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); val |= IGNORE_PLL_LOCK_MASK; cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS); @@ -1673,19 +1765,19 @@ static void clk_osm_setup_fsms(struct clk_osm *c) if (c->boost_fsm_en) { val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); clk_osm_write_reg(c, val | CC_BOOST_EN_MASK, PDN_FSM_CTRL_REG); + val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG0); val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); - val |= BVAL(31, 16, clk_osm_count_ns(c, - SAFE_FREQ_WAIT_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG0); val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG1); val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); - val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG1); val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG2); - val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG2); } @@ -1696,12 +1788,19 @@ static void clk_osm_setup_fsms(struct clk_osm *c) PDN_FSM_CTRL_REG); val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG0); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG0); val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG1); val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG1); + + val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG2); + val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); + clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG2); + } /* PS FSM */ @@ -1709,13 +1808,19 @@ static void clk_osm_setup_fsms(struct clk_osm *c) val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); clk_osm_write_reg(c, val | PS_BOOST_EN_MASK, PDN_FSM_CTRL_REG); - val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG0) | - BVAL(31, 16, clk_osm_count_ns(c, 1000)); + val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG0); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG0); - val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG1) | - clk_osm_count_ns(c, 1000); + val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG1); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG1); + + val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG2); + val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); + clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG2); } /* PLL signal timing control */ @@ -1728,15 +1833,15 @@ static void clk_osm_setup_fsms(struct clk_osm *c) val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); clk_osm_write_reg(c, val | WFX_DROOP_EN_MASK, PDN_FSM_CTRL_REG); - val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG) | - BVAL(31, 16, clk_osm_count_ns(c, 1000)); + val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG); + val |= BVAL(31, 16, clk_osm_count_ns(c, 500)); clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG); val = clk_osm_read_reg(c, - DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG) | - BVAL(31, 16, clk_osm_count_ns(c, 1000)); + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); + val |= BVAL(31, 16, clk_osm_count_ns(c, 500)); clk_osm_write_reg(c, val, - DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); } /* PC/RET FSM */ @@ -1745,9 +1850,15 @@ static void clk_osm_setup_fsms(struct clk_osm *c) clk_osm_write_reg(c, val | PC_RET_EXIT_DROOP_EN_MASK, PDN_FSM_CTRL_REG); - val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG) | - BVAL(15, 0, clk_osm_count_ns(c, 5000)); + val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG); + val |= BVAL(15, 0, clk_osm_count_ns(c, 500)); clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG); + + val = clk_osm_read_reg(c, + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); + val |= BVAL(15, 0, clk_osm_count_ns(c, 500)); + clk_osm_write_reg(c, val, + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); } /* DCVS droop FSM - only if RCGwRC is not used for di/dt control */ @@ -1758,14 +1869,14 @@ static void clk_osm_setup_fsms(struct clk_osm *c) } if (c->wfx_fsm_en || c->ps_fsm_en || c->droop_fsm_en) { - val = clk_osm_read_reg(c, - DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG) | - BVAL(15, 0, clk_osm_count_ns(c, 1000)); - clk_osm_write_reg(c, val, - DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); clk_osm_write_reg(c, 0x1, DROOP_PROG_SYNC_DELAY_REG); - val = clk_osm_read_reg(c, DROOP_CTRL_REG) | - BVAL(22, 16, 0x2); + clk_osm_write_reg(c, clk_osm_count_ns(c, 250), + DROOP_RELEASE_TIMER_CTRL); + clk_osm_write_reg(c, clk_osm_count_ns(c, 500), + DCVS_DROOP_TIMER_CTRL); + val = clk_osm_read_reg(c, DROOP_CTRL_REG); + val |= BIT(31) | BVAL(22, 16, 0x2) | + BVAL(6, 0, 0x8); clk_osm_write_reg(c, val, DROOP_CTRL_REG); } } @@ -1803,6 +1914,9 @@ static void clk_osm_do_additional_setup(struct clk_osm *c, clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(84)); clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(85)); + /* ITM to OSM handoff */ + clk_osm_setup_itm_to_osm_handoff(); + pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr), ARRAY_SIZE(seq_br_instr)); clk_osm_setup_sequencer(&pwrcl_clk); @@ -1835,18 +1949,22 @@ static void clk_osm_apm_vc_setup(struct clk_osm *c) /* Ensure writes complete before returning */ mb(); } else { - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1), - c->apm_threshold_vc); + if (msmcobalt_v1) { + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1), + c->apm_threshold_vc); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73), + 0x3b | c->apm_threshold_vc << 6); + } else if (msmcobalt_v2) { + clk_osm_write_reg(c, c->apm_threshold_vc, + SEQ_REG1_MSMCOBALT_V2); + } scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72), c->apm_crossover_vc); - /* SEQ_REG(8) = address of SEQ_REG(1) init by TZ */ clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(15)); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31), c->apm_threshold_vc != 0 ? c->apm_threshold_vc - 1 : 0xff); - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73), - 0x3b | c->apm_threshold_vc << 6); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76), 0x39 | c->apm_threshold_vc << 6); } @@ -2441,13 +2559,23 @@ static unsigned long osm_clk_init_rate = 200000000; static int cpu_clock_osm_driver_probe(struct platform_device *pdev) { - char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0"; - char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; int rc, cpu; + int speedbin = 0, pvs_ver = 0; + u32 pte_efuse; + char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; + char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0"; struct cpu_cycle_counter_cb cb = { .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter, }; + if (of_find_compatible_node(NULL, NULL, + "qcom,cpu-clock-osm-msmcobalt-v1")) { + msmcobalt_v1 = true; + } else if (of_find_compatible_node(NULL, NULL, + "qcom,cpu-clock-osm-msmcobalt-v2")) { + msmcobalt_v2 = true; + } + rc = clk_osm_resources_init(pdev); if (rc) { if (rc != -EPROBE_DEFER) @@ -2462,6 +2590,24 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return rc; } + if ((pwrcl_clk.secure_init || perfcl_clk.secure_init) && + msmcobalt_v2) { + pr_err("unsupported configuration for msmcobalt v2\n"); + return -EINVAL; + } + + if (pwrcl_clk.vbases[EFUSE_BASE]) { + /* Multiple speed-bins are supported */ + pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]); + speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) & + PWRCL_EFUSE_MASK); + snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr), + "qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver); + } + + dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n", + speedbin, pvs_ver); + rc = clk_osm_get_lut(pdev, &pwrcl_clk, pwrclspeedbinstr); if (rc) { @@ -2470,6 +2616,18 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return rc; } + if (perfcl_clk.vbases[EFUSE_BASE]) { + /* Multiple speed-bins are supported */ + pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]); + speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) & + PERFCL_EFUSE_MASK); + snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr), + "qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver); + } + + dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n", + speedbin, pvs_ver); + rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr); if (rc) { dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n", @@ -2509,10 +2667,6 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) clk_osm_print_osm_table(&pwrcl_clk); clk_osm_print_osm_table(&perfcl_clk); - /* Program the minimum PLL frequency */ - clk_osm_write_reg(&pwrcl_clk, PLL_MIN_LVAL, SEQ_REG(27)); - clk_osm_write_reg(&perfcl_clk, PLL_MIN_LVAL, SEQ_REG(27)); - rc = clk_osm_setup_hw_table(&pwrcl_clk); if (rc) { dev_err(&pdev->dev, "failed to setup power cluster hardware table\n"); @@ -2531,8 +2685,6 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) goto exit; } - clk_osm_setup_itm_to_osm_handoff(); - /* LLM Freq Policy Tuning */ rc = clk_osm_set_llm_freq_policy(pdev); if (rc < 0) { @@ -2666,7 +2818,8 @@ exit: } static struct of_device_id match_table[] = { - { .compatible = "qcom,cpu-clock-osm" }, + { .compatible = "qcom,cpu-clock-osm-msmcobalt-v1" }, + { .compatible = "qcom,cpu-clock-osm-msmcobalt-v2" }, {} }; diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c index e0f75b0022fc..b997e79e3d73 100644 --- a/drivers/devfreq/governor_bw_hwmon.c +++ b/drivers/devfreq/governor_bw_hwmon.c @@ -67,8 +67,6 @@ struct hwmon_node { unsigned long hyst_en; unsigned long above_low_power; unsigned long prev_req; - unsigned long up_wake_mbps; - unsigned long down_wake_mbps; unsigned int wake; unsigned int down_cnt; ktime_t prev_ts; @@ -191,7 +189,7 @@ static unsigned int mbps_to_bytes(unsigned long mbps, unsigned int ms) return mbps; } -static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) +static int __bw_hwmon_sw_sample_end(struct bw_hwmon *hwmon) { struct devfreq *df; struct hwmon_node *node; @@ -220,9 +218,9 @@ static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) * bandwidth usage and do the bandwidth calculation based on just * this micro sample. */ - if (mbps > node->up_wake_mbps) { + if (mbps > node->hw->up_wake_mbps) { wake = UP_WAKE; - } else if (mbps < node->down_wake_mbps) { + } else if (mbps < node->hw->down_wake_mbps) { if (node->down_cnt) node->down_cnt--; if (node->down_cnt <= 0) @@ -241,6 +239,50 @@ static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) return wake; } +static int __bw_hwmon_hw_sample_end(struct bw_hwmon *hwmon) +{ + struct devfreq *df; + struct hwmon_node *node; + unsigned long bytes, mbps; + int wake = 0; + + df = hwmon->df; + node = df->data; + + /* + * If this read is in response to an IRQ, the HW monitor should + * return the measurement in the micro sample that triggered the IRQ. + * Otherwise, it should return the maximum measured value in any + * micro sample since the last time we called get_bytes_and_clear() + */ + bytes = hwmon->get_bytes_and_clear(hwmon); + mbps = bytes_to_mbps(bytes, node->sample_ms * USEC_PER_MSEC); + node->max_mbps = mbps; + + if (mbps > node->hw->up_wake_mbps) + wake = UP_WAKE; + else if (mbps < node->hw->down_wake_mbps) + wake = DOWN_WAKE; + + node->wake = wake; + node->sampled = true; + + trace_bw_hwmon_meas(dev_name(df->dev.parent), + mbps, + node->sample_ms * USEC_PER_MSEC, + wake); + + return 1; +} + +static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) +{ + if (hwmon->set_hw_events) + return __bw_hwmon_hw_sample_end(hwmon); + else + return __bw_hwmon_sw_sample_end(hwmon); +} + int bw_hwmon_sample_end(struct bw_hwmon *hwmon) { unsigned long flags; @@ -275,12 +317,14 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, struct bw_hwmon *hw = node->hw; unsigned int new_bw, io_percent; ktime_t ts; - unsigned int ms; + unsigned int ms = 0; spin_lock_irqsave(&irq_lock, flags); - ts = ktime_get(); - ms = ktime_to_ms(ktime_sub(ts, node->prev_ts)); + if (!hw->set_hw_events) { + ts = ktime_get(); + ms = ktime_to_ms(ktime_sub(ts, node->prev_ts)); + } if (!node->sampled || ms >= node->sample_ms) __bw_hwmon_sample_end(node->hw); node->sampled = false; @@ -388,9 +432,10 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, /* Stretch the short sample window size, if the traffic is too low */ if (meas_mbps < MIN_MBPS) { - node->up_wake_mbps = (max(MIN_MBPS, req_mbps) + hw->up_wake_mbps = (max(MIN_MBPS, req_mbps) * (100 + node->up_thres)) / 100; - node->down_wake_mbps = 0; + hw->down_wake_mbps = 0; + hw->undo_over_req_mbps = 0; thres = mbps_to_bytes(max(MIN_MBPS, req_mbps / 2), node->sample_ms); } else { @@ -401,13 +446,22 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, * reduce the vote based on the measured mbps being less than * the previous measurement that caused the "over request". */ - node->up_wake_mbps = (req_mbps * (100 + node->up_thres)) / 100; - node->down_wake_mbps = (meas_mbps * node->down_thres) / 100; + hw->up_wake_mbps = (req_mbps * (100 + node->up_thres)) / 100; + hw->down_wake_mbps = (meas_mbps * node->down_thres) / 100; + if (node->wake == UP_WAKE) + hw->undo_over_req_mbps = min(req_mbps, meas_mbps_zone); + else + hw->undo_over_req_mbps = 0; thres = mbps_to_bytes(meas_mbps, node->sample_ms); } - node->down_cnt = node->down_count; - node->bytes = hw->set_thres(hw, thres); + if (hw->set_hw_events) { + hw->down_cnt = node->down_count; + hw->set_hw_events(hw, node->sample_ms); + } else { + node->down_cnt = node->down_count; + node->bytes = hw->set_thres(hw, thres); + } node->wake = 0; node->prev_req = req_mbps; @@ -432,8 +486,8 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, trace_bw_hwmon_update(dev_name(node->hw->df->dev.parent), new_bw, *freq, - node->up_wake_mbps, - node->down_wake_mbps); + hw->up_wake_mbps, + hw->down_wake_mbps); return req_mbps; } @@ -503,6 +557,9 @@ static int start_monitor(struct devfreq *df, bool init) node->resume_freq = 0; node->resume_ab = 0; mbps = (df->previous_freq * node->io_percent) / 100; + hw->up_wake_mbps = mbps; + hw->down_wake_mbps = MIN_MBPS; + hw->undo_over_req_mbps = 0; ret = hw->start_hwmon(hw, mbps); } else { ret = hw->resume_hwmon(hw); diff --git a/drivers/devfreq/governor_bw_hwmon.h b/drivers/devfreq/governor_bw_hwmon.h index 59bf48ac5af7..7578399cfb88 100644 --- a/drivers/devfreq/governor_bw_hwmon.h +++ b/drivers/devfreq/governor_bw_hwmon.h @@ -48,6 +48,8 @@ struct bw_hwmon { int (*suspend_hwmon)(struct bw_hwmon *hw); int (*resume_hwmon)(struct bw_hwmon *hw); unsigned long (*set_thres)(struct bw_hwmon *hw, unsigned long bytes); + unsigned long (*set_hw_events)(struct bw_hwmon *hw, + unsigned int sample_ms); unsigned long (*get_bytes_and_clear)(struct bw_hwmon *hw); int (*set_throttle_adj)(struct bw_hwmon *hw, uint adj); u32 (*get_throttle_adj)(struct bw_hwmon *hw); @@ -55,6 +57,11 @@ struct bw_hwmon { struct device_node *of_node; struct devfreq_governor *gov; + unsigned long up_wake_mbps; + unsigned long undo_over_req_mbps; + unsigned long down_wake_mbps; + unsigned int down_cnt; + struct devfreq *df; }; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 18fdd400ac7a..362493118670 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1193,7 +1193,8 @@ static int adreno_init(struct kgsl_device *device) if (!adreno_is_a3xx(adreno_dev)) { int r = kgsl_allocate_global(device, - &adreno_dev->cmdbatch_profile_buffer, PAGE_SIZE, 0, 0); + &adreno_dev->cmdbatch_profile_buffer, PAGE_SIZE, + 0, 0, "alwayson"); adreno_dev->cmdbatch_profile_index = 0; @@ -1279,7 +1280,7 @@ static void _setup_throttling_counters(struct adreno_device *adreno_dev) static uint64_t _read_throttling_counters(struct adreno_device *adreno_dev) { - int i; + int i, adj; uint32_t th[ADRENO_GPMU_THROTTLE_COUNTERS]; struct adreno_busy_data *busy = &adreno_dev->busy_data; @@ -1300,8 +1301,14 @@ static uint64_t _read_throttling_counters(struct adreno_device *adreno_dev) adreno_dev->gpmu_throttle_counters[i], &busy->throttle_cycles[i]); } - i = th[CRC_MORE50PCT] - th[IDLE_10PCT]; - return th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + (i < 0 ? 0 : i) * 3; + adj = th[CRC_MORE50PCT] - th[IDLE_10PCT]; + adj = th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + (adj < 0 ? 0 : adj) * 3; + + trace_kgsl_clock_throttling( + th[IDLE_10PCT], th[CRC_50PCT], + th[CRC_MORE50PCT], th[CRC_LESS50PCT], + adj); + return adj; } static void _update_threshold_count(struct adreno_device *adreno_dev, diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 2accbe5c5764..97e71464c2df 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -174,7 +174,7 @@ static int _a3xx_pwron_fixup(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &adreno_dev->pwron_fixup, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, 0, "pwron_fixup"); if (ret) return ret; diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c index b15d23cfbe0a..7a691667e59f 100644 --- a/drivers/gpu/msm/adreno_a4xx.c +++ b/drivers/gpu/msm/adreno_a4xx.c @@ -1360,7 +1360,7 @@ static int _a4xx_pwron_fixup(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &adreno_dev->pwron_fixup, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, 0, "pwron_fixup"); if (ret) return ret; diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 3252bfb764f2..583de85678fc 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -244,7 +244,8 @@ static int a5xx_critical_packet_construct(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, + 0, "crit_pkts"); if (ret) return ret; @@ -258,19 +259,19 @@ static int a5xx_critical_packet_construct(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts_refbuf1, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "crit_pkts_refbuf1"); if (ret) return ret; ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts_refbuf2, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "crit_pkts_refbuf2"); if (ret) return ret; ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts_refbuf3, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "crit_pkts_refbuf3"); if (ret) return ret; @@ -2366,7 +2367,7 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, } ret = kgsl_allocate_global(device, ucode, fw->size - 4, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, 0, "ucode"); if (ret) goto done; diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index c1463b824c67..ffd7acbbe1f9 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -490,7 +490,8 @@ static int a5xx_preemption_ringbuffer_init(struct adreno_device *adreno_dev, int ret; ret = kgsl_allocate_global(device, &rb->preemption_desc, - A5XX_CP_CTXRECORD_SIZE_IN_BYTES, 0, KGSL_MEMDESC_PRIVILEGED); + A5XX_CP_CTXRECORD_SIZE_IN_BYTES, 0, KGSL_MEMDESC_PRIVILEGED, + "preemption_desc"); if (ret) return ret; @@ -525,7 +526,8 @@ static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) /* Allocate mem for storing preemption smmu record */ return kgsl_allocate_global(device, &iommu->smmu_info, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED); + KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED, + "smmu_info"); } #else static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) @@ -555,7 +557,8 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) /* Allocate mem for storing preemption counters */ ret = kgsl_allocate_global(device, &preempt->counters, adreno_dev->num_ringbuffers * - A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0); + A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, + "preemption_counters"); if (ret) return ret; diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c index 04d82844a5e9..aeffeab2f6dc 100644 --- a/drivers/gpu/msm/adreno_a5xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c @@ -1033,11 +1033,11 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev) /* The script buffers needs 2 extra qwords on the end */ if (kgsl_allocate_global(device, &capturescript, script_size + 16, KGSL_MEMFLAGS_GPUREADONLY, - KGSL_MEMDESC_PRIVILEGED)) + KGSL_MEMDESC_PRIVILEGED, "capturescript")) return; if (kgsl_allocate_global(device, ®isters, data_size, 0, - KGSL_MEMDESC_PRIVILEGED)) { + KGSL_MEMDESC_PRIVILEGED, "capturescript_regs")) { kgsl_free_global(KGSL_DEVICE(adreno_dev), &capturescript); return; } diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c index c4fab8a5528a..d8af520b2fe6 100644 --- a/drivers/gpu/msm/adreno_profile.c +++ b/drivers/gpu/msm/adreno_profile.c @@ -1071,7 +1071,8 @@ void adreno_profile_init(struct adreno_device *adreno_dev) /* allocate shared_buffer, which includes pre_ib and post_ib */ profile->shared_size = ADRENO_PROFILE_SHARED_BUF_SIZE_DWORDS; ret = kgsl_allocate_global(device, &profile->shared_buffer, - profile->shared_size * sizeof(unsigned int), 0, 0); + profile->shared_size * sizeof(unsigned int), + 0, 0, "profile"); if (ret) { profile->shared_size = 0; diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 5ffb0b2513f3..07ef09034d7c 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -250,12 +250,12 @@ static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev, * switch pagetable */ ret = kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &rb->pagetable_desc, - PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED); + PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED, "pagetable_desc"); if (ret) return ret; - return kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &rb->buffer_desc, - KGSL_RB_SIZE, KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_RB_SIZE, KGSL_MEMFLAGS_GPUREADONLY, + 0, "ringbuffer"); } int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 691f687cd839..f9eb080d903b 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4474,13 +4474,13 @@ int kgsl_device_platform_probe(struct kgsl_device *device) goto error_close_mmu; status = kgsl_allocate_global(device, &device->memstore, - KGSL_MEMSTORE_SIZE, 0, KGSL_MEMDESC_CONTIG); + KGSL_MEMSTORE_SIZE, 0, KGSL_MEMDESC_CONTIG, "memstore"); if (status != 0) goto error_close_mmu; status = kgsl_allocate_global(device, &device->scratch, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "scratch"); if (status != 0) goto error_free_memstore; diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index df9eb9ebd779..2f293e4da398 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -280,6 +280,29 @@ static const struct file_operations process_sparse_mem_fops = { .release = process_mem_release, }; +static int globals_print(struct seq_file *s, void *unused) +{ + kgsl_print_global_pt_entries(s); + return 0; +} + +static int globals_open(struct inode *inode, struct file *file) +{ + return single_open(file, globals_print, NULL); +} + +static int globals_release(struct inode *inode, struct file *file) +{ + return single_release(inode, file); +} + +static const struct file_operations global_fops = { + .open = globals_open, + .read = seq_read, + .llseek = seq_lseek, + .release = globals_release, +}; + /** * kgsl_process_init_debugfs() - Initialize debugfs for a process * @private: Pointer to process private structure created for the process @@ -336,6 +359,9 @@ void kgsl_core_debugfs_init(void) kgsl_debugfs_dir = debugfs_create_dir("kgsl", NULL); + debugfs_create_file("globals", 0444, kgsl_debugfs_dir, NULL, + &global_fops); + debug_dir = debugfs_create_dir("debug", kgsl_debugfs_dir); debugfs_create_file("strict_memory", 0644, debug_dir, NULL, diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 166bb68e64a1..71b6086423d6 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -38,6 +38,10 @@ #define _IOMMU_PRIV(_mmu) (&((_mmu)->priv.iommu)) +#define ADDR_IN_GLOBAL(_a) \ + (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE) && \ + ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE + KGSL_IOMMU_GLOBAL_MEM_SIZE))) + static struct kgsl_mmu_pt_ops iommu_pt_ops; static bool need_iommu_sync; @@ -92,19 +96,41 @@ static struct kmem_cache *addr_entry_cache; #define GLOBAL_PT_ENTRIES 32 -static struct kgsl_memdesc *global_pt_entries[GLOBAL_PT_ENTRIES]; +struct global_pt_entry { + struct kgsl_memdesc *memdesc; + char name[32]; +}; + +static struct global_pt_entry global_pt_entries[GLOBAL_PT_ENTRIES]; static struct kgsl_memdesc *kgsl_global_secure_pt_entry; static int global_pt_count; uint64_t global_pt_alloc; static struct kgsl_memdesc gpu_qdss_desc; +void kgsl_print_global_pt_entries(struct seq_file *s) +{ + int i; + + for (i = 0; i < global_pt_count; i++) { + struct kgsl_memdesc *memdesc = global_pt_entries[i].memdesc; + + if (memdesc == NULL) + continue; + + seq_printf(s, "0x%16.16llX-0x%16.16llX %16llu %s\n", + memdesc->gpuaddr, memdesc->gpuaddr + memdesc->size - 1, + memdesc->size, global_pt_entries[i].name); + } +} + static void kgsl_iommu_unmap_globals(struct kgsl_pagetable *pagetable) { unsigned int i; for (i = 0; i < global_pt_count; i++) { - if (global_pt_entries[i] != NULL) - kgsl_mmu_unmap(pagetable, global_pt_entries[i]); + if (global_pt_entries[i].memdesc != NULL) + kgsl_mmu_unmap(pagetable, + global_pt_entries[i].memdesc); } } @@ -113,8 +139,9 @@ static void kgsl_iommu_map_globals(struct kgsl_pagetable *pagetable) unsigned int i; for (i = 0; i < global_pt_count; i++) { - if (global_pt_entries[i] != NULL) { - int ret = kgsl_mmu_map(pagetable, global_pt_entries[i]); + if (global_pt_entries[i].memdesc != NULL) { + int ret = kgsl_mmu_map(pagetable, + global_pt_entries[i].memdesc); BUG_ON(ret); } @@ -152,17 +179,17 @@ static void kgsl_iommu_remove_global(struct kgsl_mmu *mmu, return; for (i = 0; i < global_pt_count; i++) { - if (global_pt_entries[i] == memdesc) { + if (global_pt_entries[i].memdesc == memdesc) { memdesc->gpuaddr = 0; memdesc->priv &= ~KGSL_MEMDESC_GLOBAL; - global_pt_entries[i] = NULL; + global_pt_entries[i].memdesc = NULL; return; } } } static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, - struct kgsl_memdesc *memdesc) + struct kgsl_memdesc *memdesc, const char *name) { if (memdesc->gpuaddr != 0) return; @@ -174,7 +201,10 @@ static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, memdesc->priv |= KGSL_MEMDESC_GLOBAL; global_pt_alloc += memdesc->size; - global_pt_entries[global_pt_count++] = memdesc; + global_pt_entries[global_pt_count].memdesc = memdesc; + strlcpy(global_pt_entries[global_pt_count].name, name, + sizeof(global_pt_entries[global_pt_count].name)); + global_pt_count++; } void kgsl_add_global_secure_entry(struct kgsl_device *device, @@ -220,7 +250,7 @@ static void kgsl_setup_qdss_desc(struct kgsl_device *device) return; } - kgsl_mmu_add_global(device, &gpu_qdss_desc); + kgsl_mmu_add_global(device, &gpu_qdss_desc, "gpu-qdss"); } static inline void kgsl_cleanup_qdss_desc(struct kgsl_mmu *mmu) @@ -493,8 +523,62 @@ struct _mem_entry { unsigned int priv; int pending_free; pid_t pid; + char name[32]; }; +static void _get_global_entries(uint64_t faultaddr, + struct _mem_entry *prev, + struct _mem_entry *next) +{ + int i; + uint64_t prevaddr = 0; + struct global_pt_entry *p = NULL; + + uint64_t nextaddr = (uint64_t) -1; + struct global_pt_entry *n = NULL; + + for (i = 0; i < global_pt_count; i++) { + uint64_t addr; + + if (global_pt_entries[i].memdesc == NULL) + continue; + + addr = global_pt_entries[i].memdesc->gpuaddr; + if ((addr < faultaddr) && (addr > prevaddr)) { + prevaddr = addr; + p = &global_pt_entries[i]; + } + + if ((addr > faultaddr) && (addr < nextaddr)) { + nextaddr = addr; + n = &global_pt_entries[i]; + } + } + + if (p != NULL) { + prev->gpuaddr = p->memdesc->gpuaddr; + prev->size = p->memdesc->size; + prev->flags = p->memdesc->flags; + prev->priv = p->memdesc->priv; + prev->pid = 0; + strlcpy(prev->name, p->name, sizeof(prev->name)); + } + + if (n != NULL) { + next->gpuaddr = n->memdesc->gpuaddr; + next->size = n->memdesc->size; + next->flags = n->memdesc->flags; + next->priv = n->memdesc->priv; + next->pid = 0; + strlcpy(next->name, n->name, sizeof(next->name)); + } +} + +void __kgsl_get_memory_usage(struct _mem_entry *entry) +{ + kgsl_get_memory_usage(entry->name, sizeof(entry->name), entry->flags); +} + static void _get_entries(struct kgsl_process_private *private, uint64_t faultaddr, struct _mem_entry *prev, struct _mem_entry *next) @@ -529,6 +613,7 @@ static void _get_entries(struct kgsl_process_private *private, prev->priv = p->memdesc.priv; prev->pending_free = p->pending_free; prev->pid = private->pid; + __kgsl_get_memory_usage(prev); } if (n != NULL) { @@ -538,6 +623,7 @@ static void _get_entries(struct kgsl_process_private *private, next->priv = n->memdesc.priv; next->pending_free = n->pending_free; next->pid = private->pid; + __kgsl_get_memory_usage(next); } } @@ -553,7 +639,9 @@ static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, /* Set the maximum possible size as an initial value */ nextentry->gpuaddr = (uint64_t) -1; - if (context) { + if (ADDR_IN_GLOBAL(faultaddr)) { + _get_global_entries(faultaddr, preventry, nextentry); + } else if (context) { private = context->proc_priv; spin_lock(&private->mem_lock); _get_entries(private, faultaddr, preventry, nextentry); @@ -563,18 +651,13 @@ static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, static void _print_entry(struct kgsl_device *device, struct _mem_entry *entry) { - char name[32]; - memset(name, 0, sizeof(name)); - - kgsl_get_memory_usage(name, sizeof(name) - 1, entry->flags); - KGSL_LOG_DUMP(device, "[%016llX - %016llX] %s %s (pid = %d) (%s)\n", entry->gpuaddr, entry->gpuaddr + entry->size, entry->priv & KGSL_MEMDESC_GUARD_PAGE ? "(+guard)" : "", entry->pending_free ? "(pending free)" : "", - entry->pid, name); + entry->pid, entry->name); } static void _check_if_freed(struct kgsl_iommu_context *ctx, @@ -1395,7 +1478,7 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) } } - kgsl_iommu_add_global(mmu, &iommu->setstate); + kgsl_iommu_add_global(mmu, &iommu->setstate, "setstate"); kgsl_setup_qdss_desc(device); done: @@ -2220,10 +2303,6 @@ static uint64_t kgsl_iommu_find_svm_region(struct kgsl_pagetable *pagetable, return addr; } -#define ADDR_IN_GLOBAL(_a) \ - (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE) && \ - ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE + KGSL_IOMMU_GLOBAL_MEM_SIZE))) - static int kgsl_iommu_set_svm_region(struct kgsl_pagetable *pagetable, uint64_t gpuaddr, uint64_t size) { diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 10f6b8049d36..4371c9a1b87e 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -543,12 +543,12 @@ void kgsl_mmu_remove_global(struct kgsl_device *device, EXPORT_SYMBOL(kgsl_mmu_remove_global); void kgsl_mmu_add_global(struct kgsl_device *device, - struct kgsl_memdesc *memdesc) + struct kgsl_memdesc *memdesc, const char *name) { struct kgsl_mmu *mmu = &device->mmu; if (MMU_OP_VALID(mmu, mmu_add_global)) - mmu->mmu_ops->mmu_add_global(mmu, memdesc); + mmu->mmu_ops->mmu_add_global(mmu, memdesc, name); } EXPORT_SYMBOL(kgsl_mmu_add_global); @@ -620,7 +620,7 @@ static struct kgsl_mmu_pt_ops nommu_pt_ops = { }; static void nommu_add_global(struct kgsl_mmu *mmu, - struct kgsl_memdesc *memdesc) + struct kgsl_memdesc *memdesc, const char *name) { memdesc->gpuaddr = (uint64_t) sg_phys(memdesc->sgt->sgl); } diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 53645cc1741c..acbc0e784cf2 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -75,7 +75,7 @@ struct kgsl_mmu_ops { (struct kgsl_mmu *mmu); int (*mmu_init_pt)(struct kgsl_mmu *mmu, struct kgsl_pagetable *); void (*mmu_add_global)(struct kgsl_mmu *mmu, - struct kgsl_memdesc *memdesc); + struct kgsl_memdesc *memdesc, const char *name); void (*mmu_remove_global)(struct kgsl_mmu *mmu, struct kgsl_memdesc *memdesc); struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu, @@ -174,6 +174,7 @@ struct kgsl_pagetable *kgsl_mmu_getpagetable_ptbase(struct kgsl_mmu *, void kgsl_add_global_secure_entry(struct kgsl_device *device, struct kgsl_memdesc *memdesc); +void kgsl_print_global_pt_entries(struct seq_file *s); void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable); int kgsl_mmu_get_gpuaddr(struct kgsl_pagetable *pagetable, @@ -198,7 +199,7 @@ int kgsl_mmu_find_region(struct kgsl_pagetable *pagetable, uint64_t *gpuaddr, uint64_t size, unsigned int align); void kgsl_mmu_add_global(struct kgsl_device *device, - struct kgsl_memdesc *memdesc); + struct kgsl_memdesc *memdesc, const char *name); void kgsl_mmu_remove_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc); diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 565ae4c39fdd..9e6817c76df8 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -279,7 +279,7 @@ kgsl_memdesc_footprint(const struct kgsl_memdesc *memdesc) */ static inline int kgsl_allocate_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc, uint64_t size, uint64_t flags, - unsigned int priv) + unsigned int priv, const char *name) { int ret; @@ -297,7 +297,7 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, } if (ret == 0) - kgsl_mmu_add_global(device, memdesc); + kgsl_mmu_add_global(device, memdesc, name); return ret; } diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h index 1b51eb591036..4ef9f80177d6 100644 --- a/drivers/gpu/msm/kgsl_trace.h +++ b/drivers/gpu/msm/kgsl_trace.h @@ -1192,6 +1192,41 @@ TRACE_EVENT(sparse_unbind, ); +TRACE_EVENT(kgsl_clock_throttling, + TP_PROTO( + int idle_10pct, + int crc_50pct, + int crc_more50pct, + int crc_less50pct, + int adj + ), + TP_ARGS( + idle_10pct, + crc_50pct, + crc_more50pct, + crc_less50pct, + adj + ), + TP_STRUCT__entry( + __field(int, idle_10pct) + __field(int, crc_50pct) + __field(int, crc_more50pct) + __field(int, crc_less50pct) + __field(int, adj) + ), + TP_fast_assign( + __entry->idle_10pct = idle_10pct; + __entry->crc_50pct = crc_50pct; + __entry->crc_more50pct = crc_more50pct; + __entry->crc_less50pct = crc_less50pct; + __entry->adj = adj; + ), + TP_printk("idle_10=%d crc_50=%d crc_more50=%d crc_less50=%d adj=%d", + __entry->idle_10pct, __entry->crc_50pct, __entry->crc_more50pct, + __entry->crc_less50pct, __entry->adj + ) +); + #endif /* _KGSL_TRACE_H */ /* This part must be outside protection */ diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index bc5126a08ecb..b02abfc58aea 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1195,4 +1195,14 @@ config TOUCHSCREEN_FT5X06 To compile this driver as a module, choose M here: the module will be called ft5x06_ts. +config FT_SECURE_TOUCH + bool "Secure Touch support for Focaltech Touchscreen" + depends on TOUCHSCREEN_FT5X06 + help + Say Y here + -Focaltech touch driver is connected + -To enable secure touch for Focaltech touch driver + + If unsure, say N. + endif diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index b02e8ecf8608..499ba692d53c 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -47,6 +47,14 @@ #define FT_SUSPEND_LEVEL 1 #endif +#if defined(CONFIG_FT_SECURE_TOUCH) +#include <linux/completion.h> +#include <linux/atomic.h> +#include <linux/clk.h> +#include <linux/pm_runtime.h> +static irqreturn_t ft5x06_ts_interrupt(int irq, void *data); +#endif + #define FT_DRIVER_VERSION 0x02 #define FT_META_REGS 3 @@ -148,9 +156,6 @@ #define FT_FW_FILE_MAJ_VER_FT6X36(x) ((x)->data[0x10a]) #define FT_FW_FILE_VENDOR_ID_FT6X36(x) ((x)->data[0x108]) -#define FT_SYSFS_TS_INFO "ts_info" - - /** * Application data verification will be run before upgrade flow. * Firmware image stores some flags with negative and positive value @@ -202,6 +207,8 @@ #define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" #define PINCTRL_STATE_RELEASE "pmx_ts_release" +static irqreturn_t ft5x06_ts_interrupt(int irq, void *data); + enum { FT_BLOADER_VERSION_LZ4 = 0, FT_BLOADER_VERSION_Z7 = 1, @@ -215,8 +222,17 @@ enum { FT_FT5336_FAMILY_ID_0x14 = 0x14, }; -#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \ - fw_name, fw_maj, fw_min, fw_sub_min) \ +#define FT_STORE_TS_INFO(buf, id, fw_maj, fw_min, fw_sub_min) \ + snprintf(buf, FT_INFO_MAX_LEN, \ + "vendor name = Focaltech\n" \ + "model = 0x%x\n" \ + "fw_version = %d.%d.%d\n", \ + id, fw_maj, fw_min, fw_sub_min) +#define FT_TS_INFO_SYSFS_DIR_NAME "ts_info" +static char *ts_info_buff; + +#define FT_STORE_TS_DBG_INFO(buf, id, name, max_tch, group_id, \ + fw_vkey_support, fw_name, fw_maj, fw_min, fw_sub_min) \ snprintf(buf, FT_INFO_MAX_LEN, \ "controller\t= focaltech\n" \ "model\t\t= 0x%x\n" \ @@ -240,6 +256,7 @@ struct ft5x06_ts_data { struct ft5x06_gesture_platform_data *gesture_pdata; struct regulator *vdd; struct regulator *vcc_i2c; + struct mutex ft_clk_io_ctrl_mutex; char fw_name[FT_FW_NAME_MAX_LEN]; bool loading_fw; u8 family_id; @@ -251,8 +268,9 @@ struct ft5x06_ts_data { u32 tch_data_len; u8 fw_ver[3]; u8 fw_vendor_id; - struct kobject ts_info_kobj; + struct kobject *ts_info_kobj; #if defined(CONFIG_FB) + struct work_struct fb_notify_work; struct notifier_block fb_notif; #elif defined(CONFIG_HAS_EARLYSUSPEND) struct early_suspend early_suspend; @@ -261,11 +279,255 @@ struct ft5x06_ts_data { struct pinctrl_state *pinctrl_state_active; struct pinctrl_state *pinctrl_state_suspend; struct pinctrl_state *pinctrl_state_release; +#if defined(CONFIG_FT_SECURE_TOUCH) + atomic_t st_enabled; + atomic_t st_pending_irqs; + struct completion st_powerdown; + struct completion st_irq_processed; + bool st_initialized; + struct clk *core_clk; + struct clk *iface_clk; +#endif }; static int ft5x06_ts_start(struct device *dev); static int ft5x06_ts_stop(struct device *dev); +#if defined(CONFIG_FT_SECURE_TOUCH) +static void ft5x06_secure_touch_init(struct ft5x06_ts_data *data) +{ + data->st_initialized = 0; + + init_completion(&data->st_powerdown); + init_completion(&data->st_irq_processed); + + /* Get clocks */ + data->core_clk = devm_clk_get(&data->client->dev, "core_clk"); + if (IS_ERR(data->core_clk)) { + data->core_clk = NULL; + dev_warn(&data->client->dev, + "%s: core_clk is not defined\n", __func__); + } + + data->iface_clk = devm_clk_get(&data->client->dev, "iface_clk"); + if (IS_ERR(data->iface_clk)) { + data->iface_clk = NULL; + dev_warn(&data->client->dev, + "%s: iface_clk is not defined", __func__); + } + data->st_initialized = 1; +} + +static void ft5x06_secure_touch_notify(struct ft5x06_ts_data *data) +{ + sysfs_notify(&data->input_dev->dev.kobj, NULL, "secure_touch"); +} + +static irqreturn_t ft5x06_filter_interrupt(struct ft5x06_ts_data *data) +{ + if (atomic_read(&data->st_enabled)) { + if (atomic_cmpxchg(&data->st_pending_irqs, 0, 1) == 0) { + reinit_completion(&data->st_irq_processed); + ft5x06_secure_touch_notify(data); + wait_for_completion_interruptible( + &data->st_irq_processed); + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +/* + * 'blocking' variable will have value 'true' when we want to prevent the driver + * from accessing the xPU/SMMU protected HW resources while the session is + * active. + */ +static void ft5x06_secure_touch_stop(struct ft5x06_ts_data *data, bool blocking) +{ + if (atomic_read(&data->st_enabled)) { + atomic_set(&data->st_pending_irqs, -1); + ft5x06_secure_touch_notify(data); + if (blocking) + wait_for_completion_interruptible( + &data->st_powerdown); + } +} + +static int ft5x06_clk_prepare_enable(struct ft5x06_ts_data *data) +{ + int ret; + + ret = clk_prepare_enable(data->iface_clk); + if (ret) { + dev_err(&data->client->dev, + "error on clk_prepare_enable(iface_clk):%d\n", ret); + return ret; + } + + ret = clk_prepare_enable(data->core_clk); + if (ret) { + clk_disable_unprepare(data->iface_clk); + dev_err(&data->client->dev, + "error clk_prepare_enable(core_clk):%d\n", ret); + } + return ret; +} + +static void ft5x06_clk_disable_unprepare(struct ft5x06_ts_data *data) +{ + clk_disable_unprepare(data->core_clk); + clk_disable_unprepare(data->iface_clk); +} + +static int ft5x06_bus_get(struct ft5x06_ts_data *data) +{ + int retval; + + mutex_lock(&data->ft_clk_io_ctrl_mutex); + retval = pm_runtime_get_sync(data->client->adapter->dev.parent); + if (retval >= 0 && data->core_clk != NULL && data->iface_clk != NULL) { + retval = ft5x06_clk_prepare_enable(data); + if (retval) + pm_runtime_put_sync(data->client->adapter->dev.parent); + } + mutex_unlock(&data->ft_clk_io_ctrl_mutex); + return retval; +} + +static void ft5x06_bus_put(struct ft5x06_ts_data *data) +{ + mutex_lock(&data->ft_clk_io_ctrl_mutex); + if (data->core_clk != NULL && data->iface_clk != NULL) + ft5x06_clk_disable_unprepare(data); + pm_runtime_put_sync(data->client->adapter->dev.parent); + mutex_unlock(&data->ft_clk_io_ctrl_mutex); +} + +static ssize_t ft5x06_secure_touch_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d", atomic_read(&data->st_enabled)); +} + +/* + * Accept only "0" and "1" valid values. + * "0" will reset the st_enabled flag, then wake up the reading process and + * the interrupt handler. + * The bus driver is notified via pm_runtime that it is not required to stay + * awake anymore. + * It will also make sure the queue of events is emptied in the controller, + * in case a touch happened in between the secure touch being disabled and + * the local ISR being ungated. + * "1" will set the st_enabled flag and clear the st_pending_irqs flag. + * The bus driver is requested via pm_runtime to stay awake. + */ +static ssize_t ft5x06_secure_touch_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + unsigned long value; + int err = 0; + + if (count > 2) + return -EINVAL; + err = kstrtoul(buf, 10, &value); + if (err != 0) + return err; + + if (!data->st_initialized) + return -EIO; + + err = count; + switch (value) { + case 0: + if (atomic_read(&data->st_enabled) == 0) + break; + ft5x06_bus_put(data); + atomic_set(&data->st_enabled, 0); + ft5x06_secure_touch_notify(data); + complete(&data->st_irq_processed); + ft5x06_ts_interrupt(data->client->irq, data); + complete(&data->st_powerdown); + break; + + case 1: + if (atomic_read(&data->st_enabled)) { + err = -EBUSY; + break; + } + synchronize_irq(data->client->irq); + if (ft5x06_bus_get(data) < 0) { + dev_err(&data->client->dev, "ft5x06_bus_get failed\n"); + err = -EIO; + break; + } + reinit_completion(&data->st_powerdown); + reinit_completion(&data->st_irq_processed); + atomic_set(&data->st_enabled, 1); + atomic_set(&data->st_pending_irqs, 0); + break; + + default: + dev_err(&data->client->dev, "unsupported value: %lu\n", value); + err = -EINVAL; + break; + } + return err; +} + +/* + * This function returns whether there are pending interrupts, or + * other error conditions that need to be signaled to the userspace library, + * according tot he following logic: + * - st_enabled is 0 if secure touch is not enabled, returning -EBADF + * - st_pending_irqs is -1 to signal that secure touch is in being stopped, + * returning -EINVAL + * - st_pending_irqs is 1 to signal that there is a pending irq, returning + * the value "1" to the sysfs read operation + * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt + * has been processed, so the interrupt handler can be allowed to continue. + */ +static ssize_t ft5x06_secure_touch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + int val = 0; + + if (atomic_read(&data->st_enabled) == 0) + return -EBADF; + if (atomic_cmpxchg(&data->st_pending_irqs, -1, 0) == -1) + return -EINVAL; + if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) == 1) + val = 1; + else + complete(&data->st_irq_processed); + return scnprintf(buf, PAGE_SIZE, "%u", val); +} +#else +static void ft5x06_secure_touch_init(struct ft5x06_ts_data *data) +{ +} +static irqreturn_t ft5x06_filter_interrupt(struct ft5x06_ts_data *data) +{ + return IRQ_NONE; +} +static void ft5x06_secure_touch_stop(struct ft5x06_ts_data *data, bool blocking) +{ +} +#endif + +static struct device_attribute attrs[] = { +#if defined(CONFIG_FT_SECURE_TOUCH) + __ATTR(secure_touch_enable, (S_IRUGO | S_IWUSR | S_IWGRP), + ft5x06_secure_touch_enable_show, + ft5x06_secure_touch_enable_store), + __ATTR(secure_touch, S_IRUGO, + ft5x06_secure_touch_show, NULL), +#endif +}; + static inline bool ft5x06_gesture_support_enabled(void) { return config_enabled(CONFIG_TOUCHSCREEN_FT5X06_GESTURE); @@ -592,6 +854,9 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } + if (ft5x06_filter_interrupt(data) == IRQ_HANDLED) + return IRQ_HANDLED; + ip_dev = data->input_dev; buf = data->tch_data; @@ -619,6 +884,10 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) } for (i = 0; i < data->pdata->num_max_touches; i++) { + /* + * Getting the finger ID of the touch event incase of + * multiple touch events + */ id = (buf[FT_TOUCH_ID_POS + FT_ONE_TCH_LEN * i]) >> 4; if (id >= FT_MAX_ID) break; @@ -1056,6 +1325,8 @@ static int ft5x06_ts_suspend(struct device *dev) return 0; } + ft5x06_secure_touch_stop(data, true); + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support && device_may_wakeup(dev) && data->gesture_pdata->gesture_enable_to_set) { @@ -1082,6 +1353,8 @@ static int ft5x06_ts_resume(struct device *dev) return 0; } + ft5x06_secure_touch_stop(data, true); + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support && device_may_wakeup(dev) && !(data->gesture_pdata->in_pocket) && @@ -1137,6 +1410,13 @@ static int ft5x06_ts_resume(struct device *dev) #endif #if defined(CONFIG_FB) +static void fb_notify_resume_work(struct work_struct *work) +{ + struct ft5x06_ts_data *ft5x06_data = + container_of(work, struct ft5x06_ts_data, fb_notify_work); + ft5x06_ts_resume(&ft5x06_data->client->dev); +} + static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { @@ -1145,13 +1425,27 @@ static int fb_notifier_callback(struct notifier_block *self, struct ft5x06_ts_data *ft5x06_data = container_of(self, struct ft5x06_ts_data, fb_notif); - if (evdata && evdata->data && event == FB_EVENT_BLANK && - ft5x06_data && ft5x06_data->client) { + if (evdata && evdata->data && ft5x06_data && ft5x06_data->client) { blank = evdata->data; - if (*blank == FB_BLANK_UNBLANK) - ft5x06_ts_resume(&ft5x06_data->client->dev); - else if (*blank == FB_BLANK_POWERDOWN) - ft5x06_ts_suspend(&ft5x06_data->client->dev); + if (ft5x06_data->pdata->resume_in_workqueue) { + if (event == FB_EARLY_EVENT_BLANK && + *blank == FB_BLANK_UNBLANK) + schedule_work(&ft5x06_data->fb_notify_work); + else if (event == FB_EVENT_BLANK && + *blank == FB_BLANK_POWERDOWN) { + flush_work(&ft5x06_data->fb_notify_work); + ft5x06_ts_suspend(&ft5x06_data->client->dev); + } + } else { + if (event == FB_EVENT_BLANK) { + if (*blank == FB_BLANK_UNBLANK) + ft5x06_ts_resume( + &ft5x06_data->client->dev); + else if (*blank == FB_BLANK_POWERDOWN) + ft5x06_ts_suspend( + &ft5x06_data->client->dev); + } + } } return 0; @@ -1163,6 +1457,13 @@ static void ft5x06_ts_early_suspend(struct early_suspend *handler) struct ft5x06_ts_data, early_suspend); + /* + * During early suspend/late resume, the driver doesn't access xPU/SMMU + * protected HW resources. So, there is no compelling need to block, + * but notifying the userspace that a power event has occurred is + * enough. Hence 'blocking' variable can be set to false. + */ + ft5x06_secure_touch_stop(data, false); ft5x06_ts_suspend(&data->client->dev); } @@ -1172,6 +1473,7 @@ static void ft5x06_ts_late_resume(struct early_suspend *handler) struct ft5x06_ts_data, early_suspend); + ft5x06_secure_touch_stop(data, false); ft5x06_ts_resume(&data->client->dev); } #endif @@ -1488,11 +1790,13 @@ static int ft5x06_fw_upgrade(struct device *dev, bool force) ft5x06_update_fw_ver(data); - FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name, + FT_STORE_TS_DBG_INFO(data->ts_info, data->family_id, data->pdata->name, data->pdata->num_max_touches, data->pdata->group_id, data->pdata->fw_vkey_support ? "yes" : "no", data->pdata->fw_name, data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]); + FT_STORE_TS_INFO(ts_info_buff, data->family_id, data->fw_ver[0], + data->fw_ver[1], data->fw_ver[2]); rel_fw: release_firmware(fw); return rc; @@ -1595,22 +1899,13 @@ static ssize_t ft5x06_fw_name_store(struct device *dev, static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store); - -static ssize_t ft5x06_ts_info_show(struct kobject *kobj, +static ssize_t ts_info_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - struct ft5x06_ts_data *data = container_of(kobj, - struct ft5x06_ts_data, ts_info_kobj); - return snprintf(buf, FT_INFO_MAX_LEN, - "vendor name = Focaltech\n" - "model = 0x%x\n" - "fw_verion = %d.%d.%d\n", - data->family_id, data->fw_ver[0], - data->fw_ver[1], data->fw_ver[2]); + strlcpy(buf, ts_info_buff, FT_INFO_MAX_LEN); + return strnlen(buf, FT_INFO_MAX_LEN); } - -static struct kobj_attribute ts_info_attribute = __ATTR(ts_info, - 0664, ft5x06_ts_info_show, NULL); +static struct kobj_attribute ts_info_attr = __ATTR_RO(ts_info); static bool ft5x06_debug_addr_is_valid(int addr) { @@ -1918,6 +2213,9 @@ static int ft5x06_parse_dt(struct device *dev, pdata->gesture_support = of_property_read_bool(np, "focaltech,gesture-support"); + pdata->resume_in_workqueue = of_property_read_bool(np, + "focaltech,resume-in-workqueue"); + rc = of_property_read_u32(np, "focaltech,family-id", &temp_val); if (!rc) pdata->family_id = temp_val; @@ -1959,7 +2257,8 @@ static int ft5x06_ts_probe(struct i2c_client *client, struct dentry *temp; u8 reg_value; u8 reg_addr; - int err, len; + int err, len, retval, attr_count; + if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, sizeof(struct ft5x06_ts_platform_data), GFP_KERNEL); @@ -2246,29 +2545,52 @@ static int ft5x06_ts_probe(struct i2c_client *client, dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4); /*creation touch panel info kobj*/ - data->ts_info_kobj = *(kobject_create_and_add(FT_SYSFS_TS_INFO, - kernel_kobj)); - if (!&(data->ts_info_kobj)) { - dev_err(&client->dev, "kob creation failed .\n"); + data->ts_info_kobj = kobject_create_and_add(FT_TS_INFO_SYSFS_DIR_NAME, + kernel_kobj); + if (!data->ts_info_kobj) { + dev_err(&client->dev, "kobject creation failed.\n"); } else { - err = sysfs_create_file(&(data->ts_info_kobj), - &ts_info_attribute.attr); + err = sysfs_create_file(data->ts_info_kobj, &ts_info_attr.attr); if (err) { - kobject_put(&(data->ts_info_kobj)); - dev_err(&client->dev, "sysfs create fail .\n"); + kobject_put(data->ts_info_kobj); + dev_err(&client->dev, "sysfs creation failed.\n"); + } else { + ts_info_buff = devm_kzalloc(&client->dev, + FT_INFO_MAX_LEN, GFP_KERNEL); + if (!ts_info_buff) + goto free_debug_dir; + } + } + + /*Initialize secure touch */ + ft5x06_secure_touch_init(data); + ft5x06_secure_touch_stop(data, true); + mutex_init(&(data->ft_clk_io_ctrl_mutex)); + + /* Creation of secure touch sysfs files */ + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + retval = sysfs_create_file(&data->input_dev->dev.kobj, + &attrs[attr_count].attr); + if (retval < 0) { + dev_err(&client->dev, + "%s: Failed to create sysfs attributes\n", + __func__); + goto free_secure_touch_sysfs; } } ft5x06_update_fw_ver(data); ft5x06_update_fw_vendor_id(data); - FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name, + FT_STORE_TS_DBG_INFO(data->ts_info, data->family_id, data->pdata->name, data->pdata->num_max_touches, data->pdata->group_id, data->pdata->fw_vkey_support ? "yes" : "no", data->pdata->fw_name, data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]); - + FT_STORE_TS_INFO(ts_info_buff, data->family_id, data->fw_ver[0], + data->fw_ver[1], data->fw_ver[2]); #if defined(CONFIG_FB) + INIT_WORK(&data->fb_notify_work, fb_notify_resume_work); data->fb_notif.notifier_call = fb_notifier_callback; err = fb_register_client(&data->fb_notif); @@ -2285,6 +2607,11 @@ static int ft5x06_ts_probe(struct i2c_client *client, #endif return 0; +free_secure_touch_sysfs: + for (attr_count--; attr_count >= 0; attr_count--) { + sysfs_remove_file(&data->input_dev->dev.kobj, + &attrs[attr_count].attr); + } free_debug_dir: debugfs_remove_recursive(data->dir); free_force_update_fw_sys: @@ -2345,7 +2672,7 @@ unreg_inputdev: static int ft5x06_ts_remove(struct i2c_client *client) { struct ft5x06_ts_data *data = i2c_get_clientdata(client); - int retval; + int retval, attr_count; if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) { device_init_wakeup(&client->dev, 0); @@ -2388,6 +2715,11 @@ static int ft5x06_ts_remove(struct i2c_client *client) } } + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + sysfs_remove_file(&data->input_dev->dev.kobj, + &attrs[attr_count].attr); + } + if (data->pdata->power_on) data->pdata->power_on(false); else @@ -2399,7 +2731,7 @@ static int ft5x06_ts_remove(struct i2c_client *client) ft5x06_power_init(data, false); input_unregister_device(data->input_dev); - kobject_put(&(data->ts_info_kobj)); + kobject_put(data->ts_info_kobj); return 0; } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 190d294197a7..0608e08b4427 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -96,7 +96,7 @@ static void gic_do_wait_for_rwp(void __iomem *base) { u32 count = 1000000; /* 1s! */ - while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) { + while (readl_relaxed_no_log(base + GICD_CTLR) & GICD_CTLR_RWP) { count--; if (!count) { pr_err_ratelimited("RWP timeout, gone fishing\n"); @@ -182,7 +182,7 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) else base = gic_data.dist_base; - return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); + return !!(readl_relaxed_no_log(base + offset + (gic_irq(d) / 32) * 4) & mask); } static void gic_poke_irq(struct irq_data *d, u32 offset) 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 572e3c637c7b..39a0845a886f 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 @@ -951,7 +951,7 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, spin_unlock_irqrestore(&vfe_dev->common_data-> common_dev_data_lock, flags); } else { - if (frame_src == VFE_PIX_0) { + if (frame_src <= VFE_RAW_2) { msm_isp_check_for_output_error(vfe_dev, ts, &event_data.u.sof_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 fdee3cabd097..a4eb80f31984 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 @@ -370,9 +370,6 @@ void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, struct msm_vfe_fetch_engine_info *fetch_engine_info) { struct msm_isp_event_data fe_rd_done_event; - if (!fetch_engine_info->is_busy) - return; - memset(&fe_rd_done_event, 0, sizeof(struct msm_isp_event_data)); fe_rd_done_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c index 2af70b2ee1bf..3b38882c4c45 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c @@ -1390,7 +1390,7 @@ int msm_jpegdma_hw_get_max_downscale(struct msm_jpegdma_device *dma) */ int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma) { - int i; + int i, j; int ret; unsigned int cnt; const void *property; @@ -1401,32 +1401,37 @@ int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma) dev_dbg(dma->dev, "Missing qos settings\n"); return 0; } + cnt /= 4; + if (cnt % 2) + return -EINVAL; + + dma->qos_regs_num = cnt / 2; - dma->qos_regs = kzalloc((sizeof(*dma->qos_regs) * cnt), GFP_KERNEL); + dma->qos_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) * + dma->qos_regs_num), GFP_KERNEL); if (!dma->qos_regs) return -ENOMEM; - for (i = 0; i < cnt; i = i + 2) { + for (i = 0, j = 0; i < cnt; i += 2, j++) { ret = of_property_read_u32_index(dma->dev->of_node, "qcom,qos-reg-settings", i, - &dma->qos_regs[i].reg); + &dma->qos_regs[j].reg); if (ret < 0) { - dev_err(dma->dev, "can not read qos reg %d\n", i); + dev_err(dma->dev, "can not read qos reg %d\n", j); goto error; } ret = of_property_read_u32_index(dma->dev->of_node, "qcom,qos-reg-settings", i + 1, - &dma->qos_regs[i].val); + &dma->qos_regs[j].val); if (ret < 0) { - dev_err(dma->dev, "can not read qos setting %d\n", i); + dev_err(dma->dev, "can not read qos setting %d\n", j); goto error; } - dev_dbg(dma->dev, "Qos idx %d, reg %x val %x\n", i, - dma->qos_regs[i].reg, dma->qos_regs[i].val); + dev_dbg(dma->dev, "Qos idx %d, reg %x val %x\n", j, + dma->qos_regs[j].reg, dma->qos_regs[j].val); } - dma->qos_regs_num = cnt; return 0; error: @@ -1452,7 +1457,7 @@ void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma) */ int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma) { - int i; + int i, j; int ret; unsigned int cnt; const void *property; @@ -1463,33 +1468,38 @@ int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma) dev_dbg(dma->dev, "Missing vbif settings\n"); return 0; } + cnt /= 4; + if (cnt % 2) + return -EINVAL; - dma->vbif_regs = kzalloc((sizeof(*dma->vbif_regs) * cnt), GFP_KERNEL); + dma->vbif_regs_num = cnt / 2; + + dma->vbif_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) * + dma->vbif_regs_num), GFP_KERNEL); if (!dma->vbif_regs) return -ENOMEM; - for (i = 0; i < cnt; i = i + 2) { + for (i = 0, j = 0; i < cnt; i += 2, j++) { ret = of_property_read_u32_index(dma->dev->of_node, "qcom,vbif-reg-settings", i, - &dma->vbif_regs[i].reg); + &dma->vbif_regs[j].reg); if (ret < 0) { - dev_err(dma->dev, "can not read vbif reg %d\n", i); + dev_err(dma->dev, "can not read vbif reg %d\n", j); goto error; } ret = of_property_read_u32_index(dma->dev->of_node, "qcom,vbif-reg-settings", i + 1, - &dma->vbif_regs[i].val); + &dma->vbif_regs[j].val); if (ret < 0) { - dev_err(dma->dev, "can not read vbif setting %d\n", i); + dev_err(dma->dev, "can not read vbif setting %d\n", j); goto error; } - dev_dbg(dma->dev, "Vbif idx %d, reg %x val %x\n", i, - dma->vbif_regs[i].reg, dma->vbif_regs[i].val); + dev_dbg(dma->dev, "Vbif idx %d, reg %x val %x\n", j, + dma->vbif_regs[j].reg, dma->vbif_regs[j].val); } - dma->vbif_regs_num = cnt; return 0; error: @@ -1515,7 +1525,7 @@ void msm_jpegdma_hw_put_vbif(struct msm_jpegdma_device *dma) */ int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma) { - int i; + int i, j; int ret; unsigned int cnt; const void *property; @@ -1526,35 +1536,39 @@ int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma) dev_dbg(dma->dev, "Missing prefetch settings\n"); return 0; } + cnt /= 4; + if (cnt % 2) + return -EINVAL; + + dma->prefetch_regs_num = cnt / 2; - dma->prefetch_regs = kcalloc(cnt, sizeof(*dma->prefetch_regs), - GFP_KERNEL); + dma->prefetch_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) * + dma->prefetch_regs_num), GFP_KERNEL); if (!dma->prefetch_regs) return -ENOMEM; - for (i = 0; i < cnt; i = i + 2) { + for (i = 0, j = 0; i < cnt; i += 2, j++) { ret = of_property_read_u32_index(dma->dev->of_node, "qcom,prefetch-reg-settings", i, - &dma->prefetch_regs[i].reg); + &dma->prefetch_regs[j].reg); if (ret < 0) { - dev_err(dma->dev, "can not read prefetch reg %d\n", i); + dev_err(dma->dev, "can not read prefetch reg %d\n", j); goto error; } ret = of_property_read_u32_index(dma->dev->of_node, "qcom,prefetch-reg-settings", i + 1, - &dma->prefetch_regs[i].val); + &dma->prefetch_regs[j].val); if (ret < 0) { dev_err(dma->dev, "can not read prefetch setting %d\n", - i); + j); goto error; } - dev_dbg(dma->dev, "Prefetch idx %d, reg %x val %x\n", i, - dma->prefetch_regs[i].reg, dma->prefetch_regs[i].val); + dev_dbg(dma->dev, "Prefetch idx %d, reg %x val %x\n", j, + dma->prefetch_regs[j].reg, dma->prefetch_regs[j].val); } - dma->prefetch_regs_num = cnt; return 0; error: 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 c2b928d2b5d3..198d130b24fc 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,4 +101,61 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_3ph = { {0x38, 0xFE}, {0x81c, 0x6}, }; + +struct csiphy_settings_t csiphy_combo_mode_v5_0 = { + { + {0x818, 0x1}, + {0x81c, 0x2}, + {0x004, 0x08}, + {0x704, 0x08}, + {0x204, 0x08}, + {0x404, 0x08}, + {0x604, 0x08}, + {0x02c, 0x1}, + {0x22c, 0x1}, + {0x42c, 0x1}, + {0x62c, 0x1}, + {0x72c, 0x1}, + {0x034, 0x0f}, + {0x234, 0x0f}, + {0x434, 0x0f}, + {0x634, 0x0f}, + {0x734, 0x0f}, + {0x01c, 0x0a}, + {0x21c, 0x0a}, + {0x41c, 0x0a}, + {0x61c, 0x0a}, + {0x71c, 0x0a}, + {0x014, 0x60}, + {0x214, 0x60}, + {0x414, 0x60}, + {0x614, 0x60}, + {0x714, 0x60}, + {0x728, 0x4}, + {0x428, 0x0a}, + {0x628, 0x0e}, + {0x03c, 0xb8}, + {0x73c, 0xb8}, + {0x23c, 0xb8}, + {0x43c, 0xb8}, + {0x63c, 0xb8}, + {0x000, 0x91}, + {0x700, 0x80}, + {0x200, 0x91}, + {0x400, 0x91}, + {0x600, 0x80}, + {0x70c, 0xA5}, + {0x60c, 0xA5}, + {0x010, 0x52}, + {0x710, 0x52}, + {0x210, 0x52}, + {0x410, 0x52}, + {0x610, 0x52}, + {0x038, 0xfe}, + {0x738, 0x1f}, + {0x238, 0xfe}, + {0x438, 0xfe}, + {0x638, 0x1f}, + } +}; #endif 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 30af06dc64f5..bdee620e8d45 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 @@ -46,7 +46,7 @@ #define NUM_LANES_OFFSET 4 #define CSI_3PHASE_HW 1 -#define MAX_LANES 4 +#define MAX_DPHY_DATA_LN 4 #define CLOCK_OFFSET 0x700 #define CSIPHY_SOF_DEBUG_COUNT 2 @@ -55,6 +55,22 @@ static struct v4l2_file_operations msm_csiphy_v4l2_subdev_fops; +static void msm_csiphy_write_settings( + struct csiphy_device *csiphy_dev, + struct csiphy_settings_t csiphy_settings) +{ + int i = 0; + + for (i = 0; i < MAX_CSIPHY_SETTINGS; i++) { + if (csiphy_settings.settings[i].addr == 0 && + csiphy_settings.settings[i].data == 0) + break; + + msm_camera_io_w(csiphy_settings.settings[i].data, + csiphy_dev->base + csiphy_settings.settings[i].addr); + } +} + static void msm_csiphy_cphy_irq_config( struct csiphy_device *csiphy_dev, struct msm_camera_csiphy_params *csiphy_params) @@ -418,7 +434,7 @@ static int msm_csiphy_2phase_lane_config( csiphybase = csiphy_dev->base; lane_mask = csiphy_params->lane_mask & 0x1f; - for (i = 0; i < MAX_LANES; i++) { + for (i = 0; i < MAX_DPHY_DATA_LN; i++) { if (mask == 0x2) { if (lane_mask & mask) lane_enable |= 0x80; @@ -437,7 +453,7 @@ static int msm_csiphy_2phase_lane_config( csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_3ph_cmn_ctrl6.addr); - for (i = 0, mask = 0x1; i < MAX_LANES; i++) { + for (i = 0, mask = 0x1; i < MAX_DPHY_DATA_LN; i++) { if (!(lane_mask & mask)) { if (mask == 0x2) i--; @@ -562,112 +578,134 @@ static int msm_csiphy_2phase_lane_config_v50( struct csiphy_device *csiphy_dev, struct msm_camera_csiphy_params *csiphy_params) { - uint32_t val = 0, lane_enable = 0, clk_lane, mask = 1; + uint32_t lane_enable = 0, mask = 1; uint16_t lane_mask = 0, i = 0, offset; void __iomem *csiphybase; csiphybase = csiphy_dev->base; lane_mask = csiphy_params->lane_mask & 0x1f; - for (i = 0; i < MAX_LANES; i++) { + + lane_enable = msm_camera_io_r(csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_3ph_cmn_ctrl5.addr); + + /* write settle count and lane_enable */ + for (i = 0; i < MAX_DPHY_DATA_LN; i++) { if (mask == 0x2) { if (lane_mask & mask) lane_enable |= 0x80; i--; - } else if (lane_mask & mask) + offset = CLOCK_OFFSET; + } else if (lane_mask & mask) { lane_enable |= 0x1 << (i<<1); + offset = 0x200*i; + } + + if (lane_mask & mask) + msm_camera_io_w((csiphy_params->settle_cnt & 0xFF), + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg2.addr + offset); mask <<= 1; } - CDBG("%s:%d lane_enable: %d\n", __func__, __LINE__, lane_enable); + CDBG("%s:%d lane_enable: 0x%x\n", __func__, __LINE__, lane_enable); msm_camera_io_w(lane_enable, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_3ph_cmn_ctrl5.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl7.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl7.addr); - - for (i = 0, mask = 0x1; i < MAX_LANES; i++) { - if (!(lane_mask & mask)) { - if (mask == 0x2) - i--; - mask <<= 0x1; - continue; - } - if (mask == 0x2) { - val = 4; - offset = CLOCK_OFFSET; - clk_lane = 1; - i--; - } else { - offset = 0x200*i; - val = 0; - clk_lane = 0; - } - if (csiphy_params->combo_mode == 1) { - val |= 0xA; - if (mask == csiphy_dev->ctrl_reg-> - csiphy_reg.combo_clk_mask) { - val |= 0x4; - clk_lane = 1; - } - } - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl11.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl11.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl13.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl13.addr + offset); + /* write mode specific settings */ + if (csiphy_params->combo_mode == 1) + msm_csiphy_write_settings(csiphy_dev, + csiphy_dev->ctrl_reg->csiphy_combo_mode_settings); + else { msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg7.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg7.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg5.data, + mipi_csiphy_3ph_cmn_ctrl6.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg5.addr + offset); - if (clk_lane == 1) - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl10.data, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl10.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl15.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl15.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl0.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl0.addr + offset); + mipi_csiphy_3ph_cmn_ctrl6.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg1.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg1.addr + offset); - msm_camera_io_w((csiphy_params->settle_cnt & 0xFF), + mipi_csiphy_3ph_cmn_ctrl7.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg2.addr + offset); - if (clk_lane == 1) - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl3.data, csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl3.addr); + mipi_csiphy_3ph_cmn_ctrl7.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg4.data, csiphybase + + mipi_csiphy_2ph_lnck_ctrl10.data, + csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg4.addr + offset); + mipi_csiphy_2ph_lnck_ctrl10.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl14.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl14.addr + offset); - mask <<= 1; + mipi_csiphy_2ph_lnck_ctrl3.data, csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl3.addr); + + for (i = 0, mask = 0x1; i < MAX_DPHY_DATA_LN; i++) { + if (!(lane_mask & mask)) { + if (mask == 0x2) + i--; + mask <<= 0x1; + continue; + } + if (mask == 0x2) { + offset = CLOCK_OFFSET; + i--; + } else { + offset = 0x200*i; + } + + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl11.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl11.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl13.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl13.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg7.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg7.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg5.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg5.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl15.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl15.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl0.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl0.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg1.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg1.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg4.data, csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg4.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl14.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl14.addr + offset); + mask <<= 1; + } } msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params); return 0; @@ -986,19 +1024,20 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) } CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { pr_err("%s: csiphy invalid state %d\n", __func__, csiphy_dev->csiphy_state); rc = -EINVAL; return rc; } - CDBG("%s:%d called\n", __func__, __LINE__); - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } CDBG("%s:%d called\n", __func__, __LINE__); rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, @@ -1063,6 +1102,14 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) return rc; } csiphy_dev->csiphy_sof_debug_count = 0; + + CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { pr_err("%s: csiphy invalid state %d\n", __func__, @@ -1070,13 +1117,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) rc = -EINVAL; return rc; } - CDBG("%s:%d called\n", __func__, __LINE__); - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } CDBG("%s:%d called\n", __func__, __LINE__); rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, CAM_AHB_SVS_VOTE); @@ -1651,6 +1692,8 @@ static int csiphy_probe(struct platform_device *pdev) new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v5_0; new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V50; new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW; + new_csiphy_dev->ctrl_reg->csiphy_combo_mode_settings = + csiphy_combo_mode_v5_0; } else { pr_err("%s:%d, invalid hw version : 0x%x\n", __func__, __LINE__, new_csiphy_dev->hw_dts_version); 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 4944ac606bc8..aba88da1157e 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 @@ -24,12 +24,17 @@ #define MAX_CSIPHY 3 #define CSIPHY_NUM_CLK_MAX 16 +#define MAX_CSIPHY_SETTINGS 120 struct csiphy_reg_t { uint32_t addr; uint32_t data; }; +struct csiphy_settings_t { + struct csiphy_reg_t settings[MAX_CSIPHY_SETTINGS]; +}; + struct csiphy_reg_parms_t { /*MIPI CSI PHY registers*/ uint32_t mipi_csiphy_lnn_cfg1_addr; @@ -140,6 +145,7 @@ struct csiphy_reg_3ph_parms_t { struct csiphy_ctrl_t { struct csiphy_reg_parms_t csiphy_reg; struct csiphy_reg_3ph_parms_t csiphy_3ph_reg; + struct csiphy_settings_t csiphy_combo_mode_settings; }; enum msm_csiphy_state_t { diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index 3124fd8a1777..5f749bd46273 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -631,11 +631,6 @@ static int32_t msm_flash_release( struct msm_flash_ctrl_t *flash_ctrl) { int32_t rc = 0; - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_RELEASE) { - pr_err("%s:%d Invalid flash state = %d", - __func__, __LINE__, flash_ctrl->flash_state); - return 0; - } rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, NULL); if (rc < 0) { @@ -663,24 +658,49 @@ static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl, rc = msm_flash_init(flash_ctrl, flash_data); break; case CFG_FLASH_RELEASE: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if (flash_ctrl->flash_state != MSM_CAMERA_FLASH_RELEASE) { rc = flash_ctrl->func_tbl->camera_flash_release( flash_ctrl); + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; case CFG_FLASH_OFF: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if ((flash_ctrl->flash_state != MSM_CAMERA_FLASH_RELEASE) && + (flash_ctrl->flash_state != MSM_CAMERA_FLASH_OFF)) { rc = flash_ctrl->func_tbl->camera_flash_off( flash_ctrl, flash_data); + if (!rc) + flash_ctrl->flash_state = MSM_CAMERA_FLASH_OFF; + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; case CFG_FLASH_LOW: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) || + (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) { rc = flash_ctrl->func_tbl->camera_flash_low( flash_ctrl, flash_data); + if (!rc) + flash_ctrl->flash_state = MSM_CAMERA_FLASH_LOW; + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; case CFG_FLASH_HIGH: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) || + (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) { rc = flash_ctrl->func_tbl->camera_flash_high( flash_ctrl, flash_data); + if (!rc) + flash_ctrl->flash_state = MSM_CAMERA_FLASH_HIGH; + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; default: rc = -EFAULT; diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h index f6ac16f57080..ad619fa4eb63 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h @@ -27,6 +27,9 @@ enum msm_camera_flash_state_t { MSM_CAMERA_FLASH_INIT, + MSM_CAMERA_FLASH_OFF, + MSM_CAMERA_FLASH_LOW, + MSM_CAMERA_FLASH_HIGH, MSM_CAMERA_FLASH_RELEASE, }; diff --git a/drivers/media/platform/msm/sde/Kconfig b/drivers/media/platform/msm/sde/Kconfig index fcd461bb1167..85f5f4257ddb 100644 --- a/drivers/media/platform/msm/sde/Kconfig +++ b/drivers/media/platform/msm/sde/Kconfig @@ -5,4 +5,13 @@ config MSM_SDE_ROTATOR select VIDEOBUF2_CORE select SW_SYNC if SYNC ---help--- - Enable support of V4L2 rotator driver.
\ No newline at end of file + Enable support of V4L2 rotator driver. + +config MSM_SDE_ROTATOR_EVTLOG_DEBUG + depends on MSM_SDE_ROTATOR + bool "Enable sde rotator debugging" + ---help--- + The SDE rotator debugging provides support to enable rotator debugging + 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). diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h index b3e81705bdf4..67c6b11329d8 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h @@ -92,6 +92,12 @@ enum sde_bus_clients { SDE_MAX_BUS_CLIENTS }; +enum sde_rot_regdump_access { + SDE_ROT_REGDUMP_READ, + SDE_ROT_REGDUMP_WRITE, + SDE_ROT_REGDUMP_MAX +}; + struct reg_bus_client { char name[MAX_CLIENT_NAME_LEN]; short usecase_ndx; @@ -107,6 +113,21 @@ struct sde_smmu_client { bool domain_attached; }; +struct sde_rot_vbif_debug_bus { + u32 disable_bus_addr; + u32 block_bus_addr; + u32 bit_offset; + u32 block_cnt; + u32 test_pnt_cnt; +}; + +struct sde_rot_regdump { + char *name; + u32 offset; + u32 len; + enum sde_rot_regdump_access access; +}; + struct sde_rot_data_type { u32 mdss_version; @@ -140,6 +161,14 @@ struct sde_rot_data_type { int iommu_attached; int iommu_ref_cnt; + + struct sde_rot_vbif_debug_bus *nrt_vbif_dbg_bus; + u32 nrt_vbif_dbg_bus_size; + + struct sde_rot_regdump *regdump; + u32 regdump_size; + + void *sde_rot_hw; }; int sde_rotator_base_init(struct sde_rot_data_type **pmdata, diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index e3e71936b8e4..3e5cbdecfba4 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -35,6 +35,7 @@ #include "sde_rotator_r1.h" #include "sde_rotator_r3.h" #include "sde_rotator_trace.h" +#include "sde_rotator_debug.h" /* waiting for hw time out, 3 vsync for 30fps*/ #define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100 @@ -127,6 +128,7 @@ static int sde_rotator_bus_scale_set_quota(struct sde_rot_bus_data_type *bus, bus->curr_bw_uc_idx = new_uc_idx; bus->curr_quota_val = quota; + SDEROT_EVTLOG(new_uc_idx, quota); SDEROT_DBG("uc_idx=%d quota=%llu\n", new_uc_idx, quota); ATRACE_BEGIN("msm_bus_scale_req_rot"); ret = msm_bus_scale_client_update_request(bus->bus_hdl, @@ -274,6 +276,7 @@ static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on) return; } + SDEROT_EVTLOG(on); SDEROT_DBG("%s: rotator regulators", on ? "Enable" : "Disable"); ret = sde_rot_enable_vreg(mgr->module_power.vreg_config, mgr->module_power.num_vreg, on); @@ -307,6 +310,7 @@ static int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable) } if (changed) { + SDEROT_EVTLOG(enable); SDEROT_DBG("Rotator clk %s\n", enable ? "enable" : "disable"); for (i = 0; i < mgr->num_rot_clk; i++) { clk = mgr->rot_clk[i].clk; @@ -394,6 +398,7 @@ static bool sde_rotator_is_work_pending(struct sde_rot_mgr *mgr, static void sde_rotator_clear_fence(struct sde_rot_entry *entry) { if (entry->input_fence) { + SDEROT_EVTLOG(entry->input_fence, 1111); SDEROT_DBG("sys_fence_put i:%p\n", entry->input_fence); sde_rotator_put_sync_fence(entry->input_fence); entry->input_fence = NULL; @@ -404,6 +409,7 @@ static void sde_rotator_clear_fence(struct sde_rot_entry *entry) if (entry->fenceq && entry->fenceq->timeline) sde_rotator_resync_timeline(entry->fenceq->timeline); + SDEROT_EVTLOG(entry->output_fence, 2222); SDEROT_DBG("sys_fence_put o:%p\n", entry->output_fence); sde_rotator_put_sync_fence(entry->output_fence); entry->output_fence = NULL; @@ -565,6 +571,7 @@ static struct sde_rot_perf *sde_rotator_find_session( static void sde_rotator_release_data(struct sde_rot_entry *entry) { + SDEROT_EVTLOG(entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr); sde_mdp_data_free(&entry->src_buf, true, DMA_TO_DEVICE); sde_mdp_data_free(&entry->dst_buf, true, DMA_FROM_DEVICE); } @@ -719,6 +726,10 @@ static struct sde_rot_hw_resource *sde_rotator_get_hw_resource( } } atomic_inc(&hw->num_active); + SDEROT_EVTLOG(atomic_read(&hw->num_active), hw->pending_count, + mgr->rdot_limit, entry->perf->rdot_limit, + mgr->wrot_limit, entry->perf->wrot_limit, + entry->item.session_id, entry->item.sequence_id); SDEROT_DBG("active=%d pending=%d rdot=%u/%u wrot=%u/%u s:%d.%d\n", atomic_read(&hw->num_active), hw->pending_count, mgr->rdot_limit, entry->perf->rdot_limit, @@ -766,6 +777,8 @@ static void sde_rotator_put_hw_resource(struct sde_rot_queue *queue, if (hw_res) wake_up(&hw_res->wait_queue); } + SDEROT_EVTLOG(atomic_read(&hw->num_active), hw->pending_count, + entry->item.session_id, entry->item.sequence_id); SDEROT_DBG("active=%d pending=%d s:%d.%d\n", atomic_read(&hw->num_active), hw->pending_count, entry->item.session_id, entry->item.sequence_id); @@ -1125,6 +1138,15 @@ static void sde_rotator_commit_handler(struct work_struct *work) mgr = entry->private->mgr; + SDEROT_EVTLOG( + entry->item.session_id, entry->item.sequence_id, + entry->item.src_rect.x, entry->item.src_rect.y, + entry->item.src_rect.w, entry->item.src_rect.h, + entry->item.dst_rect.x, entry->item.dst_rect.y, + entry->item.dst_rect.w, entry->item.dst_rect.h, + entry->item.flags, + entry->dnsc_factor_w, entry->dnsc_factor_h); + SDEDEV_DBG(mgr->device, "commit handler s:%d.%u src:(%d,%d,%d,%d) dst:(%d,%d,%d,%d) f:0x%x dnsc:%u/%u\n", entry->item.session_id, entry->item.sequence_id, @@ -1233,11 +1255,13 @@ static void sde_rotator_done_handler(struct work_struct *work) entry->item.flags, entry->dnsc_factor_w, entry->dnsc_factor_h); + SDEROT_EVTLOG(entry->item.session_id, 0); ret = mgr->ops_wait_for_entry(hw, entry); if (ret) { SDEROT_ERR("fail to wait for completion %d\n", ret); atomic_inc(&request->failed_count); } + SDEROT_EVTLOG(entry->item.session_id, 1); if (entry->item.ts) entry->item.ts[SDE_ROTATOR_TS_DONE] = ktime_get(); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c index dae1b51bfaa8..c609dbd2036e 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c @@ -22,6 +22,619 @@ #include "sde_rotator_core.h" #include "sde_rotator_dev.h" +#ifdef CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG +#define SDE_EVTLOG_DEFAULT_ENABLE 1 +#else +#define SDE_EVTLOG_DEFAULT_ENABLE 0 +#endif +#define SDE_EVTLOG_DEFAULT_PANIC 1 +#define SDE_EVTLOG_DEFAULT_REGDUMP SDE_ROT_DBG_DUMP_IN_MEM +#define SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM + +/* + * evtlog will print this number of entries when it is called through + * sysfs node or panic. This prevents kernel log from evtlog message + * flood. + */ +#define SDE_ROT_EVTLOG_PRINT_ENTRY 256 + +/* + * evtlog keeps this number of entries in memory for debug purpose. This + * number must be greater than print entry to prevent out of bound evtlog + * entry array access. + */ +#define SDE_ROT_EVTLOG_ENTRY (SDE_ROT_EVTLOG_PRINT_ENTRY * 4) +#define SDE_ROT_EVTLOG_MAX_DATA 15 +#define SDE_ROT_EVTLOG_BUF_MAX 512 +#define SDE_ROT_EVTLOG_BUF_ALIGN 32 +#define SDE_ROT_DEBUG_BASE_MAX 10 + +static DEFINE_SPINLOCK(sde_rot_xlock); + +/* + * tlog - EVTLOG entry structure + * @counter - EVTLOG entriy counter + * @time - timestamp of EVTLOG entry + * @name - function name of EVTLOG entry + * @line - line number of EVTLOG entry + * @data - EVTLOG data contents + * @data_cnt - number of data contents + * @pid - pid of current calling thread + */ +struct tlog { + u32 counter; + s64 time; + const char *name; + int line; + u32 data[SDE_ROT_EVTLOG_MAX_DATA]; + u32 data_cnt; + int pid; +}; + +/* + * sde_rot_dbg_evtlog - EVTLOG debug data structure + * @logs - EVTLOG entries + * @first - first entry index in the EVTLOG + * @last - last entry index in the EVTLOG + * @curr - curr entry index in the EVTLOG + * @evtlog - EVTLOG debugfs handle + * @evtlog_enable - boolean indicates EVTLOG enable/disable + * @panic_on_err - boolean indicates issue panic after EVTLOG dump + * @enable_reg_dump - control in-log/memory dump for rotator registers + * @enable_vbif_dbgbus_dump - control in-log/memory dump for VBIF debug bus + * @evtlog_dump_work - schedule work strucutre for timeout handler + * @work_dump_reg - storage for register dump control in schedule work + * @work_panic - storage for panic control in schedule work + * @work_vbif_dbgbus - storage for VBIF debug bus control in schedule work + * @nrt_vbif_dbgbus_dump - memory buffer for VBIF debug bus dumping + * @reg_dump_array - memory buffer for rotator registers dumping + */ +struct sde_rot_dbg_evtlog { + struct tlog logs[SDE_ROT_EVTLOG_ENTRY]; + u32 first; + u32 last; + u32 curr; + struct dentry *evtlog; + u32 evtlog_enable; + u32 panic_on_err; + u32 enable_reg_dump; + u32 enable_vbif_dbgbus_dump; + struct work_struct evtlog_dump_work; + bool work_dump_reg; + bool work_panic; + bool work_vbif_dbgbus; + u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */ + u32 *reg_dump_array[SDE_ROT_DEBUG_BASE_MAX]; +} sde_rot_dbg_evtlog; + +/* + * sde_rot_evtlog_is_enabled - helper function for checking EVTLOG + * enable/disable + * @flag - EVTLOG option flag + */ +static inline bool sde_rot_evtlog_is_enabled(u32 flag) +{ + return (flag & sde_rot_dbg_evtlog.evtlog_enable) || + (flag == SDE_ROT_EVTLOG_ALL && + sde_rot_dbg_evtlog.evtlog_enable); +} + +/* + * __vbif_debug_bus - helper function for VBIF debug bus dump + * @head - VBIF debug bus data structure + * @vbif_base - VBIF IO mapped address + * @dump_addr - output buffer for memory dump option + * @in_log - boolean indicates in-log dump option + */ +static void __vbif_debug_bus(struct sde_rot_vbif_debug_bus *head, + void __iomem *vbif_base, u32 *dump_addr, bool in_log) +{ + int i, j; + u32 val; + + if (!dump_addr && !in_log) + return; + + for (i = 0; i < head->block_cnt; i++) { + writel_relaxed(1 << (i + head->bit_offset), + vbif_base + head->block_bus_addr); + /* make sure that current bus blcok enable */ + wmb(); + for (j = 0; j < head->test_pnt_cnt; j++) { + writel_relaxed(j, vbif_base + head->block_bus_addr + 4); + /* make sure that test point is enabled */ + wmb(); + val = readl_relaxed(vbif_base + MMSS_VBIF_TEST_BUS_OUT); + if (dump_addr) { + *dump_addr++ = head->block_bus_addr; + *dump_addr++ = i; + *dump_addr++ = j; + *dump_addr++ = val; + } + if (in_log) + pr_err("testpoint:%x arb/xin id=%d index=%d val=0x%x\n", + head->block_bus_addr, i, j, val); + } + } +} + +/* + * sde_rot_dump_vbif_debug_bus - VBIF debug bus dump + * @bus_dump_flag - dump flag controlling in-log/memory dump option + * @dump_mem - output buffer for memory dump location + */ +static void sde_rot_dump_vbif_debug_bus(u32 bus_dump_flag, + u32 **dump_mem) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + bool in_log, in_mem; + u32 *dump_addr = NULL; + u32 value; + struct sde_rot_vbif_debug_bus *head; + phys_addr_t phys = 0; + int i, list_size = 0; + void __iomem *vbif_base; + struct sde_rot_vbif_debug_bus *dbg_bus; + u32 bus_size; + + pr_info("======== NRT VBIF Debug bus DUMP =========\n"); + vbif_base = mdata->vbif_nrt_io.base; + dbg_bus = mdata->nrt_vbif_dbg_bus; + bus_size = mdata->nrt_vbif_dbg_bus_size; + + if (!vbif_base || !dbg_bus || !bus_size) + return; + + /* allocate memory for each test point */ + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + list_size += (head->block_cnt * head->test_pnt_cnt); + } + + /* 4 bytes * 4 entries for each test point*/ + list_size *= 16; + + in_log = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG); + in_mem = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM); + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(&mdata->pdev->dev, + list_size, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n", + __func__, dump_addr, dump_addr + list_size); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + sde_smmu_ctrl(1); + + value = readl_relaxed(vbif_base + MMSS_VBIF_CLKON); + writel_relaxed(value | BIT(1), vbif_base + MMSS_VBIF_CLKON); + + /* make sure that vbif core is on */ + wmb(); + + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + + writel_relaxed(0, vbif_base + head->disable_bus_addr); + writel_relaxed(BIT(0), vbif_base + MMSS_VBIF_TEST_BUS_OUT_CTRL); + /* make sure that other bus is off */ + wmb(); + + __vbif_debug_bus(head, vbif_base, dump_addr, in_log); + if (dump_addr) + dump_addr += (head->block_cnt * head->test_pnt_cnt * 4); + } + + sde_smmu_ctrl(0); + + pr_info("========End VBIF Debug bus=========\n"); +} + +/* + * sde_rot_dump_reg - helper function for dumping rotator register set content + * @dump_name - register set name + * @reg_dump_flag - dumping flag controlling in-log/memory dump location + * @addr - starting address offset for dumping + * @len - range of the register set + * @dump_mem - output buffer for memory dump location option + */ +void sde_rot_dump_reg(const char *dump_name, u32 reg_dump_flag, u32 addr, + int len, u32 **dump_mem) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + bool in_log, in_mem; + u32 *dump_addr = NULL; + phys_addr_t phys = 0; + int i; + + in_log = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG); + in_mem = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM); + + pr_debug("reg_dump_flag=%d in_log=%d in_mem=%d\n", + reg_dump_flag, in_log, in_mem); + + if (len % 16) + len += 16; + len /= 16; + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(&mdata->pdev->dev, + len * 16, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + pr_info("%s: start_addr:0x%p end_addr:0x%p reg_addr=0x%X\n", + dump_name, dump_addr, dump_addr + (u32)len * 16, + addr); + } else { + in_mem = false; + pr_err("dump_mem: kzalloc fails!\n"); + } + } + + + for (i = 0; i < len; i++) { + u32 x0, x4, x8, xc; + + x0 = readl_relaxed(mdata->sde_io.base + addr+0x0); + x4 = readl_relaxed(mdata->sde_io.base + addr+0x4); + x8 = readl_relaxed(mdata->sde_io.base + addr+0x8); + xc = readl_relaxed(mdata->sde_io.base + addr+0xc); + + if (in_log) + pr_info("0x%08X : %08x %08x %08x %08x\n", + addr, x0, x4, x8, xc); + + if (dump_addr && in_mem) { + dump_addr[i*4] = x0; + dump_addr[i*4 + 1] = x4; + dump_addr[i*4 + 2] = x8; + dump_addr[i*4 + 3] = xc; + } + + addr += 16; + } +} + +/* + * sde_rot_dump_reg_all - dumping all SDE rotator registers + */ +static void sde_rot_dump_reg_all(void) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_rot_regdump *head, *regdump; + u32 regdump_size; + int i; + + regdump = mdata->regdump; + regdump_size = mdata->regdump_size; + + if (!regdump || !regdump_size) + return; + + /* Enable clock to rotator if not yet enabled */ + sde_smmu_ctrl(1); + + for (i = 0; (i < regdump_size) && (i < SDE_ROT_DEBUG_BASE_MAX); i++) { + head = ®dump[i]; + + if (head->access == SDE_ROT_REGDUMP_WRITE) { + writel_relaxed(1, mdata->sde_io.base + head->offset); + /* Make sure write go through */ + wmb(); + } else { + sde_rot_dump_reg(head->name, + sde_rot_dbg_evtlog.enable_reg_dump, + head->offset, head->len, + &sde_rot_dbg_evtlog.reg_dump_array[i]); + } + } + + /* Disable rotator clock */ + sde_smmu_ctrl(0); +} + +/* + * __sde_rot_evtlog_dump_calc_range - calculate dump range for EVTLOG + */ +static bool __sde_rot_evtlog_dump_calc_range(void) +{ + static u32 next; + bool need_dump = true; + unsigned long flags; + struct sde_rot_dbg_evtlog *evtlog = &sde_rot_dbg_evtlog; + + spin_lock_irqsave(&sde_rot_xlock, flags); + + evtlog->first = next; + + if (evtlog->last == evtlog->first) { + need_dump = false; + goto dump_exit; + } + + if (evtlog->last < evtlog->first) { + evtlog->first %= SDE_ROT_EVTLOG_ENTRY; + if (evtlog->last < evtlog->first) + evtlog->last += SDE_ROT_EVTLOG_ENTRY; + } + + if ((evtlog->last - evtlog->first) > SDE_ROT_EVTLOG_PRINT_ENTRY) { + pr_warn("evtlog buffer overflow before dump: %d\n", + evtlog->last - evtlog->first); + evtlog->first = evtlog->last - SDE_ROT_EVTLOG_PRINT_ENTRY; + } + next = evtlog->first + 1; + +dump_exit: + spin_unlock_irqrestore(&sde_rot_xlock, flags); + + return need_dump; +} + +/* + * sde_rot_evtlog_dump_entry - helper function for EVTLOG content dumping + * @evtlog_buf: EVTLOG dump output buffer + * @evtlog_buf_size: EVTLOG output buffer size + */ +static ssize_t sde_rot_evtlog_dump_entry(char *evtlog_buf, + ssize_t evtlog_buf_size) +{ + int i; + ssize_t off = 0; + struct tlog *log, *prev_log; + unsigned long flags; + + spin_lock_irqsave(&sde_rot_xlock, flags); + + log = &sde_rot_dbg_evtlog.logs[sde_rot_dbg_evtlog.first % + SDE_ROT_EVTLOG_ENTRY]; + + prev_log = &sde_rot_dbg_evtlog.logs[(sde_rot_dbg_evtlog.first - 1) % + SDE_ROT_EVTLOG_ENTRY]; + + off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d", + log->name, log->line); + + if (off < SDE_ROT_EVTLOG_BUF_ALIGN) { + memset((evtlog_buf + off), 0x20, + (SDE_ROT_EVTLOG_BUF_ALIGN - off)); + off = SDE_ROT_EVTLOG_BUF_ALIGN; + } + + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), + "=>[%-8d:%-11llu:%9llu][%-4d]:", sde_rot_dbg_evtlog.first, + log->time, (log->time - prev_log->time), log->pid); + + for (i = 0; i < log->data_cnt; i++) + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), + "%x ", log->data[i]); + + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n"); + + spin_unlock_irqrestore(&sde_rot_xlock, flags); + + return off; +} + +/* + * sde_rot_evtlog_dump_all - Dumping all content in EVTLOG buffer + */ +static void sde_rot_evtlog_dump_all(void) +{ + char evtlog_buf[SDE_ROT_EVTLOG_BUF_MAX]; + + while (__sde_rot_evtlog_dump_calc_range()) { + sde_rot_evtlog_dump_entry(evtlog_buf, SDE_ROT_EVTLOG_BUF_MAX); + pr_info("%s", evtlog_buf); + } +} + +/* + * sde_rot_evtlog_dump_open - debugfs open handler for evtlog dump + * @inode: debugfs inode + * @file: file handler + */ +static int sde_rot_evtlog_dump_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + return 0; +} + +/* + * sde_rot_evtlog_dump_read - debugfs read handler for evtlog dump + * @file: file handler + * @buff: user buffer content for debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_rot_evtlog_dump_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char evtlog_buf[SDE_ROT_EVTLOG_BUF_MAX]; + + if (__sde_rot_evtlog_dump_calc_range()) { + len = sde_rot_evtlog_dump_entry(evtlog_buf, + SDE_ROT_EVTLOG_BUF_MAX); + if (copy_to_user(buff, evtlog_buf, len)) + return -EFAULT; + *ppos += len; + } + + return len; +} + +/* + * sde_rot_evtlog_dump_write - debugfs write handler for evtlog dump + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_rot_evtlog_dump_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + sde_rot_evtlog_dump_all(); + + sde_rot_dump_reg_all(); + + if (sde_rot_dbg_evtlog.panic_on_err) + panic("evtlog_dump_write"); + + return count; +} + +/* + * sde_rot_evtlog_dump_helper - helper function for evtlog dump + * @dead: boolean indicates panic after dump + * @panic_name: Panic signature name show up in log + * @dump_rot: boolean indicates rotator register dump + * @dump_vbif_debug_bus: boolean indicates VBIF debug bus dump + */ +static void sde_rot_evtlog_dump_helper(bool dead, const char *panic_name, + bool dump_rot, bool dump_vbif_debug_bus) +{ + sde_rot_evtlog_dump_all(); + + if (dump_rot) + sde_rot_dump_reg_all(); + + if (dump_vbif_debug_bus) + sde_rot_dump_vbif_debug_bus( + sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump, + &sde_rot_dbg_evtlog.nrt_vbif_dbgbus_dump); + + if (dead) + panic(panic_name); +} + +/* + * sde_rot_evtlog_debug_work - schedule work function for evtlog dump + * @work: schedule work structure + */ +static void sde_rot_evtlog_debug_work(struct work_struct *work) +{ + sde_rot_evtlog_dump_helper( + sde_rot_dbg_evtlog.work_panic, + "evtlog_workitem", + sde_rot_dbg_evtlog.work_dump_reg, + sde_rot_dbg_evtlog.work_vbif_dbgbus); +} + +/* + * sde_rot_dump_panic - Issue evtlog dump and generic panic + */ +void sde_rot_dump_panic(void) +{ + sde_rot_evtlog_dump_all(); + sde_rot_dump_reg_all(); + + panic("sde_rotator"); +} + +/* + * sde_rot_evtlog_tout_handler - log dump timeout handler + * @queue: boolean indicate putting log dump into queue + * @name: function name having timeout + */ +void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...) +{ + int i; + bool dead = false; + bool dump_rot = false; + bool dump_vbif_dbgbus = false; + char *blk_name = NULL; + va_list args; + + if (!sde_rot_evtlog_is_enabled(SDE_ROT_EVTLOG_DEFAULT)) + return; + + if (queue && work_pending(&sde_rot_dbg_evtlog.evtlog_dump_work)) + return; + + va_start(args, name); + for (i = 0; i < SDE_ROT_EVTLOG_MAX_DATA; i++) { + blk_name = va_arg(args, char*); + if (IS_ERR_OR_NULL(blk_name)) + break; + + if (!strcmp(blk_name, "rot")) + dump_rot = true; + + if (!strcmp(blk_name, "vbif_dbg_bus")) + dump_vbif_dbgbus = true; + + if (!strcmp(blk_name, "panic")) + dead = true; + } + va_end(args); + + if (queue) { + /* schedule work to dump later */ + sde_rot_dbg_evtlog.work_panic = dead; + sde_rot_dbg_evtlog.work_dump_reg = dump_rot; + sde_rot_dbg_evtlog.work_vbif_dbgbus = dump_vbif_dbgbus; + schedule_work(&sde_rot_dbg_evtlog.evtlog_dump_work); + } else { + sde_rot_evtlog_dump_helper(dead, name, dump_rot, + dump_vbif_dbgbus); + } +} + +/* + * sde_rot_evtlog - log contents into memory for dump analysis + * @name: Name of function calling evtlog + * @line: line number of calling function + * @flag: Log control flag + */ +void sde_rot_evtlog(const char *name, int line, int flag, ...) +{ + unsigned long flags; + int i, val = 0; + va_list args; + struct tlog *log; + + if (!sde_rot_evtlog_is_enabled(flag)) + return; + + spin_lock_irqsave(&sde_rot_xlock, flags); + log = &sde_rot_dbg_evtlog.logs[sde_rot_dbg_evtlog.curr]; + log->time = ktime_to_us(ktime_get()); + log->name = name; + log->line = line; + log->data_cnt = 0; + log->pid = current->pid; + + va_start(args, flag); + for (i = 0; i < SDE_ROT_EVTLOG_MAX_DATA; i++) { + + val = va_arg(args, int); + if (val == SDE_ROT_DATA_LIMITER) + break; + + log->data[i] = val; + } + va_end(args); + log->data_cnt = i; + sde_rot_dbg_evtlog.curr = + (sde_rot_dbg_evtlog.curr + 1) % SDE_ROT_EVTLOG_ENTRY; + sde_rot_dbg_evtlog.last++; + + spin_unlock_irqrestore(&sde_rot_xlock, flags); +} + /* * sde_rotator_stat_show - Show statistics on read to this debugfs file * @s: Pointer to sequence file structure @@ -249,6 +862,58 @@ static int sde_rotator_core_create_debugfs( return 0; } +static const struct file_operations sde_rot_evtlog_fops = { + .open = sde_rot_evtlog_dump_open, + .read = sde_rot_evtlog_dump_read, + .write = sde_rot_evtlog_dump_write, +}; + +static int sde_rotator_evtlog_create_debugfs( + struct sde_rot_mgr *mgr, + struct dentry *debugfs_root) +{ + int i; + + sde_rot_dbg_evtlog.evtlog = debugfs_create_dir("evtlog", debugfs_root); + if (IS_ERR_OR_NULL(sde_rot_dbg_evtlog.evtlog)) { + pr_err("debugfs_create_dir fail, error %ld\n", + PTR_ERR(sde_rot_dbg_evtlog.evtlog)); + sde_rot_dbg_evtlog.evtlog = NULL; + return -ENODEV; + } + + INIT_WORK(&sde_rot_dbg_evtlog.evtlog_dump_work, + sde_rot_evtlog_debug_work); + sde_rot_dbg_evtlog.work_panic = false; + + for (i = 0; i < SDE_ROT_EVTLOG_ENTRY; i++) + sde_rot_dbg_evtlog.logs[i].counter = i; + + debugfs_create_file("dump", 0644, sde_rot_dbg_evtlog.evtlog, NULL, + &sde_rot_evtlog_fops); + debugfs_create_u32("enable", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.evtlog_enable); + debugfs_create_u32("panic", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.panic_on_err); + debugfs_create_u32("reg_dump", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.enable_reg_dump); + debugfs_create_u32("vbif_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump); + + sde_rot_dbg_evtlog.evtlog_enable = SDE_EVTLOG_DEFAULT_ENABLE; + sde_rot_dbg_evtlog.panic_on_err = SDE_EVTLOG_DEFAULT_PANIC; + sde_rot_dbg_evtlog.enable_reg_dump = SDE_EVTLOG_DEFAULT_REGDUMP; + sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump = + SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP; + + pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n", + sde_rot_dbg_evtlog.evtlog_enable, + sde_rot_dbg_evtlog.panic_on_err, + sde_rot_dbg_evtlog.enable_reg_dump); + + return 0; +} + /* * struct sde_rotator_stat_ops - processed statistics file operations */ @@ -335,6 +1000,12 @@ struct dentry *sde_rotator_create_debugfs( return NULL; } + if (sde_rotator_evtlog_create_debugfs(rot_dev->mgr, debugfs_root)) { + SDEROT_ERR("fail create evtlog debugfs\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + return debugfs_root; } diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h index 2ed1b759f3e9..dcda54274fad 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h @@ -16,6 +16,32 @@ #include <linux/types.h> #include <linux/dcache.h> +#define SDE_ROT_DATA_LIMITER (-1) +#define SDE_ROT_EVTLOG_TOUT_DATA_LIMITER (NULL) + +enum sde_rot_dbg_reg_dump_flag { + SDE_ROT_DBG_DUMP_IN_LOG = BIT(0), + SDE_ROT_DBG_DUMP_IN_MEM = BIT(1), +}; + +enum sde_rot_dbg_evtlog_flag { + SDE_ROT_EVTLOG_DEFAULT = BIT(0), + SDE_ROT_EVTLOG_IOMMU = BIT(1), + SDE_ROT_EVTLOG_DBG = BIT(6), + SDE_ROT_EVTLOG_ALL = BIT(7) +}; + +#define SDEROT_EVTLOG(...) sde_rot_evtlog(__func__, __LINE__, \ + SDE_ROT_EVTLOG_DEFAULT, ##__VA_ARGS__, SDE_ROT_DATA_LIMITER) + +#define SDEROT_EVTLOG_TOUT_HANDLER(...) \ + sde_rot_evtlog_tout_handler(false, __func__, ##__VA_ARGS__, \ + SDE_ROT_EVTLOG_TOUT_DATA_LIMITER) + +void sde_rot_evtlog(const char *name, int line, int flag, ...); +void sde_rot_dump_panic(void); +void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...); + struct sde_rotator_device; #if defined(CONFIG_DEBUG_FS) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index 76fd674d161d..548131393835 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -34,6 +34,7 @@ #include "sde_rotator_r3_hwio.h" #include "sde_rotator_r3_debug.h" #include "sde_rotator_trace.h" +#include "sde_rotator_debug.h" /* XIN mapping */ #define XIN_SSPP 0 @@ -198,6 +199,29 @@ static u32 sde_hw_rotator_output_pixfmts[] = { SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC, }; +static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = { + {0x214, 0x21c, 16, 1, 0x10}, /* arb clients */ + {0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */ + {0x21c, 0x214, 0, 12, 0xc}, /* xin blocks - clock side */ +}; + +static struct sde_rot_regdump sde_rot_r3_regdump[] = { + { "SDEROT_ROTTOP", SDE_ROT_ROTTOP_OFFSET, 0x100, SDE_ROT_REGDUMP_READ }, + { "SDEROT_SSPP", SDE_ROT_SSPP_OFFSET, 0x200, SDE_ROT_REGDUMP_READ }, + { "SDEROT_WB", SDE_ROT_WB_OFFSET, 0x300, SDE_ROT_REGDUMP_READ }, + { "SDEROT_REGDMA_CSR", SDE_ROT_REGDMA_OFFSET, 0x100, + SDE_ROT_REGDUMP_READ }, + /* + * Need to perform a SW reset to REGDMA in order to access the + * REGDMA RAM especially if REGDMA is waiting for Rotator IDLE. + * REGDMA RAM should be dump at last. + */ + { "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 1, + SDE_ROT_REGDUMP_WRITE }, + { "SDEROT_REGDMA_RAM", SDE_ROT_REGDMA_RAM_OFFSET, 0x2000, + SDE_ROT_REGDUMP_READ }, +}; + /* Invalid software timestamp value for initialization */ #define SDE_REGDMA_SWTS_INVALID (~0) @@ -332,6 +356,8 @@ static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot) REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_FSM_STATE)); + + SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus", "panic"); } /** @@ -1484,6 +1510,10 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw, &entry->dst_buf); } + SDEROT_EVTLOG(flags, item->input.width, item->input.height, + item->output.width, item->output.height, + entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr); + if (mdata->default_ot_rd_limit) { struct sde_mdp_set_ot_params ot_params; @@ -1677,6 +1707,13 @@ static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot) set_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map); } + mdata->nrt_vbif_dbg_bus = nrt_vbif_dbg_bus_r3; + mdata->nrt_vbif_dbg_bus_size = + ARRAY_SIZE(nrt_vbif_dbg_bus_r3); + + mdata->regdump = sde_rot_r3_regdump; + mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump); + return 0; } @@ -2202,6 +2239,7 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr) clk_set_flags(mgr->rot_clk[mgr->core_clk_idx].clk, CLKFLAG_NORETAIN_PERIPH); + mdata->sde_rot_hw = rot; return 0; error_hw_rev_init: if (rot->irq_num >= 0) 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 6cc975e22cd4..7bbd8aa53342 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c @@ -33,6 +33,7 @@ #include "sde_rotator_util.h" #include "sde_rotator_io_util.h" #include "sde_rotator_smmu.h" +#include "sde_rotator_debug.h" #define SMMU_SDE_ROT_SEC "qcom,smmu_sde_rot_sec" #define SMMU_SDE_ROT_UNSEC "qcom,smmu_sde_rot_unsec" @@ -332,6 +333,8 @@ int sde_smmu_ctrl(int enable) int rc = 0; mutex_lock(&sde_smmu_ref_cnt_lock); + SDEROT_EVTLOG(__builtin_return_address(0), enable, mdata->iommu_ref_cnt, + mdata->iommu_attached); SDEROT_DBG("%pS: enable:%d ref_cnt:%d attach:%d\n", __builtin_return_address(0), enable, mdata->iommu_ref_cnt, mdata->iommu_attached); @@ -407,9 +410,10 @@ static int sde_smmu_fault_handler(struct iommu_domain *domain, sde_smmu = (struct sde_smmu_client *)token; - /* TODO: trigger rotator panic and dump */ - SDEROT_ERR("TODO: trigger rotator panic and dump, iova=0x%08lx\n", - iova); + /* trigger rotator panic and dump */ + SDEROT_ERR("trigger rotator panic and dump, iova=0x%08lx\n", iova); + + sde_rot_dump_panic(); return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 566441e9c546..f0a3875a8f28 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -90,6 +90,7 @@ static void msm_comm_generate_session_error(struct msm_vidc_inst *inst); static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst); static void handle_session_error(enum hal_command_response cmd, void *data); static void msm_vidc_print_running_insts(struct msm_vidc_core *core); +static void msm_comm_print_debug_info(struct msm_vidc_inst *inst); bool msm_comm_turbo_session(struct msm_vidc_inst *inst) { @@ -905,7 +906,7 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst, call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "sess resp timeout can potentially crash the system\n"); - + msm_comm_print_debug_info(inst); BUG_ON(inst->core->resources.debug_timeout); rc = -EIO; } else { @@ -1601,6 +1602,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) struct msm_vidc_cb_cmd_done *response = data; struct msm_vidc_core *core = NULL; struct hfi_device *hdev = NULL; + struct msm_vidc_inst *inst = NULL; int rc = 0; subsystem_crashed("venus"); @@ -1640,6 +1642,19 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) dprintk(VIDC_ERR, "SYS_ERROR can potentially crash the system\n"); + /* + * For SYS_ERROR, there will not be any inst pointer. + * Just grab one of the inst from instances list and + * use it. + */ + + mutex_lock(&core->lock); + inst = list_first_entry(&core->instances, + struct msm_vidc_inst, list); + mutex_unlock(&core->lock); + + msm_comm_print_debug_info(inst); + BUG_ON(core->resources.debug_timeout); } @@ -2450,6 +2465,7 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst) call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "ABORT timeout can potentially crash the system\n"); + msm_comm_print_debug_info(inst); BUG_ON(inst->core->resources.debug_timeout); rc = -EBUSY; @@ -2522,6 +2538,7 @@ int msm_comm_check_core_init(struct msm_vidc_core *core) { int rc = 0; struct hfi_device *hdev; + struct msm_vidc_inst *inst = NULL; mutex_lock(&core->lock); if (core->state >= VIDC_CORE_INIT_DONE) { @@ -2540,6 +2557,17 @@ int msm_comm_check_core_init(struct msm_vidc_core *core) call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "SYS_INIT timeout can potentially crash the system\n"); + /* + * For SYS_INIT, there will not be any inst pointer. + * Just grab one of the inst from instances list and + * use it. + */ + inst = list_first_entry(&core->instances, + struct msm_vidc_inst, list); + + mutex_unlock(&core->lock); + msm_comm_print_debug_info(inst); + mutex_lock(&core->lock); BUG_ON(core->resources.debug_timeout); rc = -EIO; @@ -4017,6 +4045,8 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "SESS_PROP timeout can potentially crash the system\n"); + if (inst->core->resources.debug_timeout) + msm_comm_print_debug_info(inst); BUG_ON(inst->core->resources.debug_timeout); rc = -ETIMEDOUT; @@ -5232,3 +5262,92 @@ int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a) exit: return rc; } + +void msm_comm_print_inst_info(struct msm_vidc_inst *inst) +{ + struct buffer_info *temp; + struct internal_buf *buf; + int i = 0; + bool is_decode = false; + enum vidc_ports port; + + if (!inst) { + dprintk(VIDC_ERR, "%s - invalid param %p\n", + __func__, inst); + return; + } + + is_decode = inst->session_type == MSM_VIDC_DECODER; + port = is_decode ? OUTPUT_PORT : CAPTURE_PORT; + dprintk(VIDC_ERR, + "%s session, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n", + is_decode ? "Decode" : "Encode", inst->fmts[port]->name, + inst->prop.height[port], inst->prop.width[port], + inst->prop.fps, inst->prop.bitrate, + !inst->bit_depth ? "8" : "10"); + + dprintk(VIDC_ERR, + "---Buffer details for inst: %p of type: %d---\n", + inst, inst->session_type); + mutex_lock(&inst->registeredbufs.lock); + dprintk(VIDC_ERR, "registered buffer list:\n"); + list_for_each_entry(temp, &inst->registeredbufs.list, list) + for (i = 0; i < temp->num_planes; i++) + dprintk(VIDC_ERR, + "type: %d plane: %d addr: %pa size: %d\n", + temp->type, i, &temp->device_addr[i], + temp->size[i]); + + mutex_unlock(&inst->registeredbufs.lock); + + mutex_lock(&inst->scratchbufs.lock); + dprintk(VIDC_ERR, "scratch buffer list:\n"); + list_for_each_entry(buf, &inst->scratchbufs.list, list) + dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", + buf->buffer_type, &buf->handle->device_addr, + buf->handle->size); + mutex_unlock(&inst->scratchbufs.lock); + + mutex_lock(&inst->persistbufs.lock); + dprintk(VIDC_ERR, "persist buffer list:\n"); + list_for_each_entry(buf, &inst->persistbufs.list, list) + dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", + buf->buffer_type, &buf->handle->device_addr, + buf->handle->size); + mutex_unlock(&inst->persistbufs.lock); + + mutex_lock(&inst->outputbufs.lock); + dprintk(VIDC_ERR, "dpb buffer list:\n"); + list_for_each_entry(buf, &inst->outputbufs.list, list) + dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", + buf->buffer_type, &buf->handle->device_addr, + buf->handle->size); + mutex_unlock(&inst->outputbufs.lock); +} + +static void msm_comm_print_debug_info(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core = NULL; + struct msm_vidc_inst *temp = NULL; + + if (!inst || !inst->core) { + dprintk(VIDC_ERR, "%s - invalid param %p %p\n", + __func__, inst, core); + return; + } + core = inst->core; + + dprintk(VIDC_ERR, "Venus core frequency = %lu", + msm_comm_get_clock_rate(core)); + dprintk(VIDC_ERR, "Printing instance info that caused Error\n"); + msm_comm_print_inst_info(inst); + dprintk(VIDC_ERR, "Printing remaining instances info\n"); + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + /* inst already printed above. Hence don't repeat.*/ + if (temp == inst) + continue; + msm_comm_print_inst_info(temp); + } + mutex_unlock(&core->lock); +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 337760508eb1..eac7f658eb31 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -98,4 +98,5 @@ int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst); void msm_comm_cleanup_internal_buffers(struct msm_vidc_inst *inst); int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a); bool msm_comm_turbo_session(struct msm_vidc_inst *inst); +void msm_comm_print_inst_info(struct msm_vidc_inst *inst); #endif 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 1bdc5bf2c93d..25fccab99fb3 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1238,11 +1238,6 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, { struct msm_vidc_core *core = token; struct msm_vidc_inst *inst; - struct buffer_info *temp; - struct internal_buf *buf; - int i = 0; - bool is_decode = false; - enum vidc_ports port; if (!domain || !core) { dprintk(VIDC_ERR, "%s - invalid param %pK %pK\n", @@ -1257,52 +1252,7 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, mutex_lock(&core->lock); list_for_each_entry(inst, &core->instances, list) { - is_decode = inst->session_type == MSM_VIDC_DECODER; - port = is_decode ? OUTPUT_PORT : CAPTURE_PORT; - dprintk(VIDC_ERR, - "%s session, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n", - is_decode ? "Decode" : "Encode", inst->fmts[port]->name, - inst->prop.height[port], inst->prop.width[port], - inst->prop.fps, inst->prop.bitrate, - !inst->bit_depth ? "8" : "10"); - - dprintk(VIDC_ERR, - "---Buffer details for inst: %pK of type: %d---\n", - inst, inst->session_type); - mutex_lock(&inst->registeredbufs.lock); - dprintk(VIDC_ERR, "registered buffer list:\n"); - list_for_each_entry(temp, &inst->registeredbufs.list, list) - for (i = 0; i < temp->num_planes; i++) - dprintk(VIDC_ERR, - "type: %d plane: %d addr: %pa size: %d\n", - temp->type, i, &temp->device_addr[i], - temp->size[i]); - - mutex_unlock(&inst->registeredbufs.lock); - - mutex_lock(&inst->scratchbufs.lock); - dprintk(VIDC_ERR, "scratch buffer list:\n"); - list_for_each_entry(buf, &inst->scratchbufs.list, list) - dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", - buf->buffer_type, &buf->handle->device_addr, - buf->handle->size); - mutex_unlock(&inst->scratchbufs.lock); - - mutex_lock(&inst->persistbufs.lock); - dprintk(VIDC_ERR, "persist buffer list:\n"); - list_for_each_entry(buf, &inst->persistbufs.list, list) - dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", - buf->buffer_type, &buf->handle->device_addr, - buf->handle->size); - mutex_unlock(&inst->persistbufs.lock); - - mutex_lock(&inst->outputbufs.lock); - dprintk(VIDC_ERR, "dpb buffer list:\n"); - list_for_each_entry(buf, &inst->outputbufs.list, list) - dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", - buf->buffer_type, &buf->handle->device_addr, - buf->handle->size); - mutex_unlock(&inst->outputbufs.lock); + msm_comm_print_inst_info(inst); } core->smmu_fault_handled = true; mutex_unlock(&core->lock); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h index 23d84e9f7f7a..f6120dc7d1d5 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h @@ -16,6 +16,7 @@ #define DT_PARSE #include <linux/of.h> #include "msm_vidc_resources.h" +#include "msm_vidc_common.h" void msm_vidc_free_platform_resources( struct msm_vidc_platform_resources *res); diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 5a51fbcf9318..e0fb31de38ff 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -119,7 +119,7 @@ static inline bool __core_in_valid_state(struct venus_hfi_device *device) return device->state != VENUS_STATE_DEINIT; } -static void __dump_packet(u8 *packet) +static void __dump_packet(u8 *packet, enum vidc_msg_prio log_level) { u32 c = 0, packet_size = *(u32 *)packet; const int row_size = 32; @@ -132,7 +132,7 @@ static void __dump_packet(u8 *packet) packet_size % row_size : row_size; hex_dump_to_buffer(packet + c * row_size, bytes_to_read, row_size, 4, row, sizeof(row), false); - dprintk(VIDC_PKT, "%s\n", row); + dprintk(log_level, "%s\n", row); } } @@ -342,7 +342,7 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet, if (msm_vidc_debug & VIDC_PKT) { dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo); - __dump_packet(packet); + __dump_packet(packet, VIDC_PKT); } packet_size_in_words = (*(u32 *)packet) >> 2; @@ -548,7 +548,7 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet, if (msm_vidc_debug & VIDC_PKT) { dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo); - __dump_packet(packet); + __dump_packet(packet, VIDC_PKT); } return rc; @@ -2517,7 +2517,6 @@ static int venus_hfi_session_clean(void *session) mutex_lock(&device->lock); __session_clean(sess_close); - __flush_debug_queue(device, NULL); mutex_unlock(&device->lock); return 0; @@ -3337,6 +3336,7 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) { bool local_packet = false; enum vidc_msg_prio log_level = VIDC_FW; + unsigned int pending_packet_count = 0; if (!device) { dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); @@ -3361,6 +3361,23 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) log_level = VIDC_ERR; } + /* + * In FATAL situation, print all the pending messages in msg + * queue. This is useful for debugging. At this time, message + * queues may be corrupted. Hence don't trust them and just print + * first max_packets packets. + */ + + if (local_packet) { + dprintk(VIDC_ERR, + "Printing all pending messages in message Queue\n"); + while (!__iface_msgq_read(device, packet) && + pending_packet_count < max_packets) { + __dump_packet(packet, log_level); + pending_packet_count++; + } + } + while (!__iface_dbgq_read(device, packet)) { struct hfi_msg_sys_coverage_packet *pkt = (struct hfi_msg_sys_coverage_packet *) packet; diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c index 0c5754341991..b6a476cd882d 100644 --- a/drivers/mfd/wcd9xxx-irq.c +++ b/drivers/mfd/wcd9xxx-irq.c @@ -450,10 +450,22 @@ int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res) { int i, ret; u8 irq_level[wcd9xxx_res->num_irq_regs]; + struct irq_domain *domain; + struct device_node *pnode; mutex_init(&wcd9xxx_res->irq_lock); mutex_init(&wcd9xxx_res->nested_irq_lock); + pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node); + if (unlikely(!pnode)) + return -EINVAL; + + domain = irq_find_host(pnode); + if (unlikely(!domain)) + return -EINVAL; + + wcd9xxx_res->domain = domain; + wcd9xxx_res->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx_res); if (!wcd9xxx_res->irq) { pr_warn("%s: irq driver is not yet initialized\n", __func__); @@ -553,7 +565,6 @@ void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res) if (wcd9xxx_res->irq) { disable_irq_wake(wcd9xxx_res->irq); free_irq(wcd9xxx_res->irq, wcd9xxx_res); - /* Release parent's of node */ wcd9xxx_res->irq = 0; wcd9xxx_irq_put_upstream_irq(wcd9xxx_res); } @@ -626,19 +637,14 @@ wcd9xxx_irq_add_domain(struct device_node *node, static struct wcd9xxx_irq_drv_data * wcd9xxx_get_irq_drv_d(const struct wcd9xxx_core_resource *wcd9xxx_res) { - struct device_node *pnode; struct irq_domain *domain; - pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node); - /* Shouldn't happen */ - if (unlikely(!pnode)) - return NULL; + domain = wcd9xxx_res->domain; - domain = irq_find_host(pnode); - if (unlikely(!domain)) + if (domain) + return domain->host_data; + else return NULL; - - return (struct wcd9xxx_irq_drv_data *)domain->host_data; } static int phyirq_to_virq(struct wcd9xxx_core_resource *wcd9xxx_res, int offset) @@ -669,10 +675,6 @@ static unsigned int wcd9xxx_irq_get_upstream_irq( { struct wcd9xxx_irq_drv_data *data; - /* Hold parent's of node */ - if (!of_node_get(of_irq_find_parent(wcd9xxx_res->dev->of_node))) - return -EINVAL; - data = wcd9xxx_get_irq_drv_d(wcd9xxx_res); if (!data) { pr_err("%s: interrupt controller is not registerd\n", __func__); @@ -686,8 +688,7 @@ static unsigned int wcd9xxx_irq_get_upstream_irq( static void wcd9xxx_irq_put_upstream_irq( struct wcd9xxx_core_resource *wcd9xxx_res) { - /* Hold parent's of node */ - of_node_put(of_irq_find_parent(wcd9xxx_res->dev->of_node)); + wcd9xxx_res->domain = NULL; } static int wcd9xxx_map_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq) diff --git a/drivers/misc/qcom/Kconfig b/drivers/misc/qcom/Kconfig index a62297e913d2..9c73960f01ff 100644 --- a/drivers/misc/qcom/Kconfig +++ b/drivers/misc/qcom/Kconfig @@ -1,6 +1,7 @@ config MSM_QDSP6V2_CODECS bool "Audio QDSP6V2 APR support" depends on MSM_SMD + select SND_SOC_QDSP6V2 help Enable Audio codecs with APR IPC protocol support between application processor and QDSP6 for B-family. APR is @@ -9,6 +10,7 @@ config MSM_QDSP6V2_CODECS config MSM_ULTRASOUND bool "QDSP6V2 HW Ultrasound support" + select SND_SOC_QDSP6V2 help Enable HW Ultrasound support in QDSP6V2. QDSP6V2 can support HW encoder & decoder and diff --git a/drivers/misc/qcom/qdsp6v2/aac_in.c b/drivers/misc/qcom/qdsp6v2/aac_in.c index c9d5dbb0b313..7176c114f85b 100644 --- a/drivers/misc/qcom/qdsp6v2/aac_in.c +++ b/drivers/misc/qcom/qdsp6v2/aac_in.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -421,6 +421,8 @@ static long aac_in_compat_ioctl(struct file *file, unsigned int cmd, struct msm_audio_aac_enc_config cfg; struct msm_audio_aac_enc_config32 cfg_32; + memset(&cfg_32, 0, sizeof(cfg_32)); + cmd = AUDIO_GET_AAC_ENC_CONFIG; rc = aac_in_ioctl_shared(file, cmd, &cfg); if (rc) { diff --git a/drivers/misc/qcom/qdsp6v2/amrnb_in.c b/drivers/misc/qcom/qdsp6v2/amrnb_in.c index eb92137f0671..1bb441bd2ff4 100644 --- a/drivers/misc/qcom/qdsp6v2/amrnb_in.c +++ b/drivers/misc/qcom/qdsp6v2/amrnb_in.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2010-2012, 2014 The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, 2014, 2016 The Linux Foundation. + * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -221,6 +222,8 @@ static long amrnb_in_compat_ioctl(struct file *file, struct msm_audio_amrnb_enc_config_v2 *amrnb_config; struct msm_audio_amrnb_enc_config_v2_32 amrnb_config_32; + memset(&amrnb_config_32, 0, sizeof(amrnb_config_32)); + amrnb_config = (struct msm_audio_amrnb_enc_config_v2 *)audio->enc_cfg; amrnb_config_32.band_mode = amrnb_config->band_mode; diff --git a/drivers/misc/qcom/qdsp6v2/amrwb_in.c b/drivers/misc/qcom/qdsp6v2/amrwb_in.c index 4cea3dc63389..4f94ed2673e6 100644 --- a/drivers/misc/qcom/qdsp6v2/amrwb_in.c +++ b/drivers/misc/qcom/qdsp6v2/amrwb_in.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2012, 2014, 2016 The Linux Foundation. + * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -216,6 +217,8 @@ static long amrwb_in_compat_ioctl(struct file *file, struct msm_audio_amrwb_enc_config *amrwb_config; struct msm_audio_amrwb_enc_config_32 amrwb_config_32; + memset(&amrwb_config_32, 0, sizeof(amrwb_config_32)); + amrwb_config = (struct msm_audio_amrwb_enc_config *)audio->enc_cfg; amrwb_config_32.band_mode = amrwb_config->band_mode; diff --git a/drivers/misc/qcom/qdsp6v2/audio_alac.c b/drivers/misc/qcom/qdsp6v2/audio_alac.c index 9748db30fac3..3de204c1ebc8 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_alac.c +++ b/drivers/misc/qcom/qdsp6v2/audio_alac.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -196,6 +196,8 @@ static long audio_compat_ioctl(struct file *file, unsigned int cmd, struct msm_audio_alac_config *alac_config; struct msm_audio_alac_config_32 alac_config_32; + memset(&alac_config_32, 0, sizeof(alac_config_32)); + alac_config = (struct msm_audio_alac_config *)audio->codec_cfg; alac_config_32.frameLength = alac_config->frameLength; alac_config_32.compatVersion = diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrwbplus.c b/drivers/misc/qcom/qdsp6v2/audio_amrwbplus.c index ee5991177687..bfd730017d41 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_amrwbplus.c +++ b/drivers/misc/qcom/qdsp6v2/audio_amrwbplus.c @@ -2,7 +2,7 @@ * * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -205,6 +205,10 @@ static long audio_compat_ioctl(struct file *file, unsigned int cmd, struct msm_audio_amrwbplus_config_v2 *amrwbplus_config; struct msm_audio_amrwbplus_config_v2_32 amrwbplus_config_32; + + memset(&amrwbplus_config_32, 0, + sizeof(amrwbplus_config_32)); + amrwbplus_config = (struct msm_audio_amrwbplus_config_v2 *) audio->codec_cfg; diff --git a/drivers/misc/qcom/qdsp6v2/audio_ape.c b/drivers/misc/qcom/qdsp6v2/audio_ape.c index b4c2ddb947de..670ec555b8c6 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_ape.c +++ b/drivers/misc/qcom/qdsp6v2/audio_ape.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -180,6 +180,8 @@ static long audio_compat_ioctl(struct file *file, unsigned int cmd, struct msm_audio_ape_config *ape_config; struct msm_audio_ape_config_32 ape_config_32; + memset(&ape_config_32, 0, sizeof(ape_config_32)); + ape_config = (struct msm_audio_ape_config *)audio->codec_cfg; ape_config_32.compatibleVersion = ape_config->compatibleVersion; ape_config_32.compressionLevel = diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c index 3a8834446ea4..3632fc2b961b 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c +++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c @@ -630,6 +630,8 @@ static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd, case AUDIO_EFFECTS_GET_BUF_AVAIL32: { struct msm_hwacc_buf_avail32 buf_avail; + memset(&buf_avail, 0, sizeof(buf_avail)); + buf_avail.input_num_avail = atomic_read(&effects->in_count); buf_avail.output_num_avail = atomic_read(&effects->out_count); pr_debug("%s: write buf avail: %d, read buf avail: %d\n", diff --git a/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c b/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c index a15fd87c7be8..91bbba176dfd 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c +++ b/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c @@ -2,7 +2,7 @@ * * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -302,6 +302,8 @@ static long audio_compat_ioctl(struct file *file, unsigned int cmd, struct msm_audio_aac_config *aac_config; struct msm_audio_aac_config32 aac_config_32; + memset(&aac_config_32, 0, sizeof(aac_config_32)); + aac_config = (struct msm_audio_aac_config *)audio->codec_cfg; aac_config_32.format = aac_config->format; aac_config_32.audio_object = aac_config->audio_object; diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c index 5c23da7f8857..f7ad8f61f2e7 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c @@ -1936,6 +1936,7 @@ static long audio_aio_compat_ioctl(struct file *file, unsigned int cmd, case AUDIO_GET_CONFIG_32: { struct msm_audio_config32 cfg_32; mutex_lock(&audio->lock); + memset(&cfg_32, 0, sizeof(cfg_32)); cfg_32.buffer_size = audio->pcm_cfg.buffer_size; cfg_32.buffer_count = audio->pcm_cfg.buffer_count; cfg_32.channel_count = audio->pcm_cfg.channel_count; @@ -2032,6 +2033,7 @@ static long audio_aio_compat_ioctl(struct file *file, unsigned int cmd, audio->buf_cfg.frames_per_buf); mutex_lock(&audio->lock); + memset(&cfg_32, 0, sizeof(cfg_32)); cfg_32.meta_info_enable = audio->buf_cfg.meta_info_enable; cfg_32.frames_per_buf = audio->buf_cfg.frames_per_buf; if (copy_to_user((void *)arg, &cfg_32, diff --git a/drivers/misc/qcom/qdsp6v2/audio_wmapro.c b/drivers/misc/qcom/qdsp6v2/audio_wmapro.c index 8d96b99d8f84..21ad33b7fd5d 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_wmapro.c +++ b/drivers/misc/qcom/qdsp6v2/audio_wmapro.c @@ -2,7 +2,7 @@ * * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2009-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -217,6 +217,8 @@ static long audio_compat_ioctl(struct file *file, unsigned int cmd, struct msm_audio_wmapro_config *wmapro_config; struct msm_audio_wmapro_config32 wmapro_config_32; + memset(&wmapro_config_32, 0, sizeof(wmapro_config_32)); + wmapro_config = (struct msm_audio_wmapro_config *)audio->codec_cfg; wmapro_config_32.armdatareqthr = wmapro_config->armdatareqthr; diff --git a/drivers/misc/qcom/qdsp6v2/evrc_in.c b/drivers/misc/qcom/qdsp6v2/evrc_in.c index 2f931be226c6..aab8e27c0094 100644 --- a/drivers/misc/qcom/qdsp6v2/evrc_in.c +++ b/drivers/misc/qcom/qdsp6v2/evrc_in.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -224,6 +224,8 @@ static long evrc_in_compat_ioctl(struct file *file, struct msm_audio_evrc_enc_config32 cfg_32; struct msm_audio_evrc_enc_config *enc_cfg; + memset(&cfg_32, 0, sizeof(cfg_32)); + enc_cfg = audio->enc_cfg; cfg_32.cdma_rate = enc_cfg->cdma_rate; cfg_32.min_bit_rate = enc_cfg->min_bit_rate; diff --git a/drivers/misc/qcom/qdsp6v2/qcelp_in.c b/drivers/misc/qcom/qdsp6v2/qcelp_in.c index b5d5ad113722..aabf5d33a507 100644 --- a/drivers/misc/qcom/qdsp6v2/qcelp_in.c +++ b/drivers/misc/qcom/qdsp6v2/qcelp_in.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -225,6 +225,8 @@ static long qcelp_in_compat_ioctl(struct file *file, struct msm_audio_qcelp_enc_config32 cfg_32; struct msm_audio_qcelp_enc_config *enc_cfg; + memset(&cfg_32, 0, sizeof(cfg_32)); + enc_cfg = (struct msm_audio_qcelp_enc_config *)audio->enc_cfg; cfg_32.cdma_rate = enc_cfg->cdma_rate; cfg_32.min_bit_rate = enc_cfg->min_bit_rate; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 14ed8e775e6a..0542ba51445f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2337,9 +2337,10 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) switch (host->timing) { /* HS400 tuning is done in HS200 mode */ case MMC_TIMING_MMC_HS400: - err = -EINVAL; - goto out_unlock; - + if (!(mmc->caps2 & MMC_CAP2_HS400_POST_TUNING)) { + err = -EINVAL; + goto out_unlock; + } case MMC_TIMING_MMC_HS200: /* * Periodic re-tuning for HS400 is not expected to be needed, so diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 6c42ca14d2fd..9753fbb596cf 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,7 @@ #include <linux/gpio.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinmux.h> @@ -39,6 +40,8 @@ #define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5 #define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9 #define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd +#define PMIC_GPIO_SUBTYPE_GPIO_LV 0x10 +#define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11 #define PMIC_MPP_REG_RT_STS 0x10 #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 @@ -47,8 +50,11 @@ #define PMIC_GPIO_REG_MODE_CTL 0x40 #define PMIC_GPIO_REG_DIG_VIN_CTL 0x41 #define PMIC_GPIO_REG_DIG_PULL_CTL 0x42 +#define PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL 0x44 +#define PMIC_GPIO_REG_DIG_IN_CTL 0x43 #define PMIC_GPIO_REG_DIG_OUT_CTL 0x45 #define PMIC_GPIO_REG_EN_CTL 0x46 +#define PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL 0x4A /* PMIC_GPIO_REG_MODE_CTL */ #define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1 @@ -57,6 +63,13 @@ #define PMIC_GPIO_REG_MODE_DIR_SHIFT 4 #define PMIC_GPIO_REG_MODE_DIR_MASK 0x7 +#define PMIC_GPIO_MODE_DIGITAL_INPUT 0 +#define PMIC_GPIO_MODE_DIGITAL_OUTPUT 1 +#define PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT 2 +#define PMIC_GPIO_MODE_ANALOG_PASS_THRU 3 + +#define PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK 0x3 + /* PMIC_GPIO_REG_DIG_VIN_CTL */ #define PMIC_GPIO_REG_VIN_SHIFT 0 #define PMIC_GPIO_REG_VIN_MASK 0x7 @@ -68,6 +81,16 @@ #define PMIC_GPIO_PULL_DOWN 4 #define PMIC_GPIO_PULL_DISABLE 5 +/* PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL for LV/MV */ +#define PMIC_GPIO_LV_MV_OUTPUT_INVERT 0x80 +#define PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT 7 +#define PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK 0xF + +/* PMIC_GPIO_REG_DIG_IN_CTL */ +#define PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN 0x80 +#define PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK 0x7 +#define PMIC_GPIO_DIG_IN_DTEST_SEL_MASK 0xf + /* PMIC_GPIO_REG_DIG_OUT_CTL */ #define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0 #define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3 @@ -87,9 +110,29 @@ #define PMIC_GPIO_PHYSICAL_OFFSET 1 +/* PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL */ +#define PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK 0x3 + /* Qualcomm specific pin configurations */ #define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1) #define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2) +#define PMIC_GPIO_CONF_ATEST (PIN_CONFIG_END + 3) +#define PMIC_GPIO_CONF_DTEST_BUFFER (PIN_CONFIG_END + 4) + +/* The index of each function in pmic_gpio_functions[] array */ +enum pmic_gpio_func_index { + PMIC_GPIO_FUNC_INDEX_NORMAL = 0x00, + PMIC_GPIO_FUNC_INDEX_PAIRED = 0x01, + PMIC_GPIO_FUNC_INDEX_FUNC1 = 0x02, + PMIC_GPIO_FUNC_INDEX_FUNC2 = 0x03, + PMIC_GPIO_FUNC_INDEX_FUNC3 = 0x04, + PMIC_GPIO_FUNC_INDEX_FUNC4 = 0x05, + PMIC_GPIO_FUNC_INDEX_DTEST1 = 0x06, + PMIC_GPIO_FUNC_INDEX_DTEST2 = 0x07, + PMIC_GPIO_FUNC_INDEX_DTEST3 = 0x08, + PMIC_GPIO_FUNC_INDEX_DTEST4 = 0x09, + PMIC_GPIO_FUNC_INDEX_ANALOG = 0x10, +}; /** * struct pmic_gpio_pad - keep current GPIO settings @@ -101,12 +144,16 @@ * open-drain or open-source mode. * @output_enabled: Set to true if GPIO output logic is enabled. * @input_enabled: Set to true if GPIO input buffer logic is enabled. + * @lv_mv_type: Set to true if GPIO subtype is GPIO_LV(0x10) or GPIO_MV(0x11). * @num_sources: Number of power-sources supported by this GPIO. * @power_source: Current power-source used. * @buffer_type: Push-pull, open-drain or open-source. * @pullup: Constant current which flow trough GPIO output buffer. * @strength: No, Low, Medium, High * @function: See pmic_gpio_functions[] + * @atest: the ATEST selection for GPIO analog-pass-through mode + * @dtest_buffer: the DTEST buffer selection for digital input mode, + * the default value is INT_MAX if not used. */ struct pmic_gpio_pad { u16 base; @@ -116,12 +163,15 @@ struct pmic_gpio_pad { bool have_buffer; bool output_enabled; bool input_enabled; + bool lv_mv_type; unsigned int num_sources; unsigned int power_source; unsigned int buffer_type; unsigned int pullup; unsigned int strength; unsigned int function; + unsigned int atest; + unsigned int dtest_buffer; }; struct pmic_gpio_state { @@ -134,12 +184,15 @@ struct pmic_gpio_state { static const struct pinconf_generic_params pmic_gpio_bindings[] = { {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP, 0}, {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH, 0}, + {"qcom,atest", PMIC_GPIO_CONF_ATEST, 0}, + {"qcom,dtest-buffer", PMIC_GPIO_CONF_DTEST_BUFFER, 0}, }; #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = { PCONFDUMP(PMIC_GPIO_CONF_PULL_UP, "pull up strength", NULL, true), PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true), + PCONFDUMP(PMIC_GPIO_CONF_ATEST, "atest", NULL, true), }; #endif @@ -151,11 +204,25 @@ static const char *const pmic_gpio_groups[] = { "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", }; +/* + * Treat LV/MV GPIO analog-pass-through mode as a function, add it + * to the end of the function list. Add placeholder for the reserved + * functions defined in LV/MV OUTPUT_SOURCE_SEL register. + */ static const char *const pmic_gpio_functions[] = { - PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED, - PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2, - PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2, - PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4, + [PMIC_GPIO_FUNC_INDEX_NORMAL] = PMIC_GPIO_FUNC_NORMAL, + [PMIC_GPIO_FUNC_INDEX_PAIRED] = PMIC_GPIO_FUNC_PAIRED, + [PMIC_GPIO_FUNC_INDEX_FUNC1] = PMIC_GPIO_FUNC_FUNC1, + [PMIC_GPIO_FUNC_INDEX_FUNC2] = PMIC_GPIO_FUNC_FUNC2, + [PMIC_GPIO_FUNC_INDEX_FUNC3] = PMIC_GPIO_FUNC_FUNC3, + [PMIC_GPIO_FUNC_INDEX_FUNC4] = PMIC_GPIO_FUNC_FUNC4, + [PMIC_GPIO_FUNC_INDEX_DTEST1] = PMIC_GPIO_FUNC_DTEST1, + [PMIC_GPIO_FUNC_INDEX_DTEST2] = PMIC_GPIO_FUNC_DTEST2, + [PMIC_GPIO_FUNC_INDEX_DTEST3] = PMIC_GPIO_FUNC_DTEST3, + [PMIC_GPIO_FUNC_INDEX_DTEST4] = PMIC_GPIO_FUNC_DTEST4, + "reserved-a", "reserved-b", "reserved-c", + "reserved-d", "reserved-e", "reserved-f", + [PMIC_GPIO_FUNC_INDEX_ANALOG] = PMIC_GPIO_FUNC_ANALOG, }; static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip) @@ -252,21 +319,74 @@ static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function, pad->function = function; - val = 0; + val = PMIC_GPIO_MODE_DIGITAL_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = 2; + val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT; else - val = 1; + val = PMIC_GPIO_MODE_DIGITAL_OUTPUT; + } + + if (function > PMIC_GPIO_FUNC_INDEX_DTEST4 && + function < PMIC_GPIO_FUNC_INDEX_ANALOG) { + pr_err("reserved function: %s hasn't been enabled\n", + pmic_gpio_functions[function]); + return -EINVAL; } - val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + if (pad->lv_mv_type) { + if (pad->function == PMIC_GPIO_FUNC_INDEX_ANALOG) { + val = PMIC_GPIO_MODE_ANALOG_PASS_THRU; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; - ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); - if (ret < 0) - return ret; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, + pad->atest); + if (ret < 0) + return ret; + } else { + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + val = pad->out_value + << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT; + val |= pad->function + & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val); + if (ret < 0) + return ret; + } + } else { + /* + * GPIO not of LV/MV subtype doesn't have "func3", "func4" + * "analog" functions, and "dtest1" to "dtest4" functions + * have register value 2 bits lower than the function index + * in pmic_gpio_functions[]. + */ + if (function == PMIC_GPIO_FUNC_INDEX_FUNC3 + || function == PMIC_GPIO_FUNC_INDEX_FUNC4 + || function == PMIC_GPIO_FUNC_INDEX_ANALOG) { + return -EINVAL; + } else if (function >= PMIC_GPIO_FUNC_INDEX_DTEST1 && + function <= PMIC_GPIO_FUNC_INDEX_DTEST4) { + pad->function -= (PMIC_GPIO_FUNC_INDEX_DTEST1 - + PMIC_GPIO_FUNC_INDEX_FUNC3); + } + + val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; + val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + } val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT; @@ -326,6 +446,12 @@ static int pmic_gpio_config_get(struct pinctrl_dev *pctldev, case PMIC_GPIO_CONF_STRENGTH: arg = pad->strength; break; + case PMIC_GPIO_CONF_ATEST: + arg = pad->atest; + break; + case PMIC_GPIO_CONF_DTEST_BUFFER: + arg = pad->dtest_buffer; + break; default: return -EINVAL; } @@ -379,7 +505,7 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->is_enabled = false; break; case PIN_CONFIG_POWER_SOURCE: - if (arg > pad->num_sources) + if (arg >= pad->num_sources) return -EINVAL; pad->power_source = arg; break; @@ -400,6 +526,18 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, return -EINVAL; pad->strength = arg; break; + case PMIC_GPIO_CONF_ATEST: + if (arg > PMIC_GPIO_AOUT_ATEST4) + return -EINVAL; + pad->atest = arg; + break; + case PMIC_GPIO_CONF_DTEST_BUFFER: + if ((pad->lv_mv_type && arg > PMIC_GPIO_DIN_DTEST4) + || (!pad->lv_mv_type && arg > + PMIC_GPIO_DIG_IN_DTEST_SEL_MASK)) + return -EINVAL; + pad->dtest_buffer = arg; + break; default: return -EINVAL; } @@ -424,19 +562,64 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; - val = 0; + val = PMIC_GPIO_MODE_DIGITAL_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = 2; + val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT; else - val = 1; + val = PMIC_GPIO_MODE_DIGITAL_OUTPUT; + } + + if (pad->dtest_buffer != INT_MAX) { + val = pad->dtest_buffer; + if (pad->lv_mv_type) + val |= PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN; + + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_DIG_IN_CTL, val); + if (ret < 0) + return ret; } - val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + if (pad->lv_mv_type) { + if (pad->function == PMIC_GPIO_FUNC_INDEX_ANALOG) { + val = PMIC_GPIO_MODE_ANALOG_PASS_THRU; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, + pad->atest); + if (ret < 0) + return ret; + } else { + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + val = pad->out_value + << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT; + val |= pad->function + & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val); + if (ret < 0) + return ret; + } + } else { + val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; + val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + } - return pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); + return ret; } static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, @@ -444,7 +627,7 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, { struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); struct pmic_gpio_pad *pad; - int ret, val; + int ret, val, function; static const char *const biases[] = { "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA", @@ -475,14 +658,28 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; pad->out_value = ret; } + /* + * For GPIO not of LV/MV subtypes, the register value of + * the function mapping from "dtest1" to "dtest4" is 2 bits + * lower than the function index in pmic_gpio_functions[]. + */ + if (!pad->lv_mv_type && + pad->function >= PMIC_GPIO_FUNC_INDEX_FUNC3) { + function = pad->function + (PMIC_GPIO_FUNC_INDEX_DTEST1 + - PMIC_GPIO_FUNC_INDEX_FUNC3); + } else { + function = pad->function; + } seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); - seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]); + seq_printf(s, " %-7s", pmic_gpio_functions[function]); seq_printf(s, " vin-%d", pad->power_source); seq_printf(s, " %-27s", biases[pad->pullup]); seq_printf(s, " %-10s", buffer_types[pad->buffer_type]); seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); seq_printf(s, " %-7s", strengths[pad->strength]); + if (pad->dtest_buffer != INT_MAX) + seq_printf(s, " dtest buffer %d", pad->dtest_buffer); } } @@ -622,40 +819,72 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state, case PMIC_GPIO_SUBTYPE_GPIOC_8CH: pad->num_sources = 8; break; + case PMIC_GPIO_SUBTYPE_GPIO_LV: + pad->num_sources = 1; + pad->have_buffer = true; + pad->lv_mv_type = true; + break; + case PMIC_GPIO_SUBTYPE_GPIO_MV: + pad->num_sources = 2; + pad->have_buffer = true; + pad->lv_mv_type = true; + break; default: dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype); return -ENODEV; } - val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); - if (val < 0) - return val; + if (pad->lv_mv_type) { + val = pmic_gpio_read(state, pad, + PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL); + if (val < 0) + return val; + + pad->out_value = !!(val & PMIC_GPIO_LV_MV_OUTPUT_INVERT); + pad->function = val & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; - pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); + if (val < 0) + return val; + + dir = val & PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK; + } else { + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); + if (val < 0) + return val; + + pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT; + dir &= PMIC_GPIO_REG_MODE_DIR_MASK; + pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK; + } - dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT; - dir &= PMIC_GPIO_REG_MODE_DIR_MASK; switch (dir) { - case 0: + case PMIC_GPIO_MODE_DIGITAL_INPUT: pad->input_enabled = true; pad->output_enabled = false; break; - case 1: + case PMIC_GPIO_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; break; - case 2: + case PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT: pad->input_enabled = true; pad->output_enabled = true; break; + case PMIC_GPIO_MODE_ANALOG_PASS_THRU: + if (pad->lv_mv_type) + pad->function = PMIC_GPIO_FUNC_INDEX_ANALOG; + else + return -ENODEV; + break; default: dev_err(state->dev, "unknown GPIO direction\n"); return -ENODEV; } - pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; - pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK; - val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL); if (val < 0) return val; @@ -670,6 +899,17 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state, pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT; pad->pullup &= PMIC_GPIO_REG_PULL_MASK; + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_IN_CTL); + if (val < 0) + return val; + + if (pad->lv_mv_type && (val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN)) + pad->dtest_buffer = val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK; + else if (!pad->lv_mv_type) + pad->dtest_buffer = val & PMIC_GPIO_DIG_IN_DTEST_SEL_MASK; + else + pad->dtest_buffer = INT_MAX; + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL); if (val < 0) return val; @@ -680,6 +920,13 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state, pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT; pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK; + if (pad->function == PMIC_GPIO_FUNC_INDEX_ANALOG) { + val = pmic_gpio_read(state, pad, + PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL); + if (val < 0) + return val; + pad->atest = val & PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK; + } /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ pad->is_enabled = true; return 0; @@ -693,18 +940,19 @@ static int pmic_gpio_probe(struct platform_device *pdev) struct pmic_gpio_pad *pad, *pads; struct pmic_gpio_state *state; int ret, npins, i; - u32 res[2]; + u32 reg; - ret = of_property_read_u32_array(dev->of_node, "reg", res, 2); + ret = of_property_read_u32(dev->of_node, "reg", ®); if (ret < 0) { - dev_err(dev, "missing base address and/or range"); + dev_err(dev, "missing base address"); return ret; } - npins = res[1] / PMIC_GPIO_ADDRESS_RANGE; - + npins = platform_irq_count(pdev); if (!npins) return -EINVAL; + if (npins < 0) + return npins; BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups)); @@ -752,7 +1000,7 @@ static int pmic_gpio_probe(struct platform_device *pdev) if (pad->irq < 0) return pad->irq; - pad->base = res[0] + i * PMIC_GPIO_ADDRESS_RANGE; + pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE; ret = pmic_gpio_populate(state, pad); if (ret < 0) @@ -805,6 +1053,7 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8916-gpio" }, /* 4 GPIO's */ { .compatible = "qcom,pm8941-gpio" }, /* 36 GPIO's */ { .compatible = "qcom,pma8084-gpio" }, /* 22 GPIO's */ + { .compatible = "qcom,spmi-gpio" }, /* Generic */ { }, }; diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 9ce0e30e33e8..73547abc5cf5 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,7 @@ #include <linux/gpio.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinmux.h> @@ -87,6 +88,10 @@ #define PMIC_MPP_REG_AIN_ROUTE_SHIFT 0 #define PMIC_MPP_REG_AIN_ROUTE_MASK 0x7 +/* PMIC_MPP_REG_SINK_CTL */ +#define PMIC_MPP_REG_CURRENT_SINK_MASK 0x7 +#define MPP_CURRENT_SINK_MA_STEP_SIZE 5 + #define PMIC_MPP_MODE_DIGITAL_INPUT 0 #define PMIC_MPP_MODE_DIGITAL_OUTPUT 1 #define PMIC_MPP_MODE_DIGITAL_BIDIR 2 @@ -106,6 +111,7 @@ #define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 2) #define PMIC_MPP_CONF_DTEST_SELECTOR (PIN_CONFIG_END + 3) #define PMIC_MPP_CONF_PAIRED (PIN_CONFIG_END + 4) +#define PMIC_MPP_CONF_DTEST_BUFFER (PIN_CONFIG_END + 5) /** * struct pmic_mpp_pad - keep current MPP settings @@ -124,6 +130,7 @@ * @function: See pmic_mpp_functions[]. * @drive_strength: Amount of current in sink mode * @dtest: DTEST route selector + * @dtest_buffer: the DTEST buffer selection for digital input mode */ struct pmic_mpp_pad { u16 base; @@ -141,6 +148,7 @@ struct pmic_mpp_pad { unsigned int function; unsigned int drive_strength; unsigned int dtest; + unsigned int dtest_buffer; }; struct pmic_mpp_state { @@ -155,6 +163,7 @@ static const struct pinconf_generic_params pmic_mpp_bindings[] = { {"qcom,analog-level", PMIC_MPP_CONF_ANALOG_LEVEL, 0}, {"qcom,dtest", PMIC_MPP_CONF_DTEST_SELECTOR, 0}, {"qcom,paired", PMIC_MPP_CONF_PAIRED, 0}, + {"qcom,dtest-buffer", PMIC_MPP_CONF_DTEST_BUFFER, 0}, }; #ifdef CONFIG_DEBUG_FS @@ -163,6 +172,7 @@ static const struct pin_config_item pmic_conf_items[] = { PCONFDUMP(PMIC_MPP_CONF_ANALOG_LEVEL, "analog level", NULL, true), PCONFDUMP(PMIC_MPP_CONF_DTEST_SELECTOR, "dtest", NULL, true), PCONFDUMP(PMIC_MPP_CONF_PAIRED, "paired", NULL, false), + PCONFDUMP(PMIC_MPP_CONF_DTEST_BUFFER, "dtest buffer", NULL, true), }; #endif @@ -392,6 +402,9 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, case PMIC_MPP_CONF_ANALOG_LEVEL: arg = pad->aout_level; break; + case PMIC_MPP_CONF_DTEST_BUFFER: + arg = pad->dtest_buffer; + break; default: return -EINVAL; } @@ -457,7 +470,7 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->dtest = arg; break; case PIN_CONFIG_DRIVE_STRENGTH: - arg = pad->drive_strength; + pad->drive_strength = arg; break; case PMIC_MPP_CONF_AMUX_ROUTE: if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4) @@ -470,6 +483,15 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, case PMIC_MPP_CONF_PAIRED: pad->paired = !!arg; break; + case PMIC_MPP_CONF_DTEST_BUFFER: + /* + * 0xf is the max value which selects + * 4 dtest rails simultaneously + */ + if (arg > 0xf) + return -EINVAL; + pad->dtest_buffer = arg; + break; default: return -EINVAL; } @@ -481,6 +503,11 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; + val = pad->dtest_buffer; + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_IN_CTL, val); + if (ret < 0) + return ret; + val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT; ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL, val); @@ -497,6 +524,16 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; + val = 0; + if (pad->drive_strength >= MPP_CURRENT_SINK_MA_STEP_SIZE) + val = DIV_ROUND_UP(pad->drive_strength, + MPP_CURRENT_SINK_MA_STEP_SIZE) - 1; + + val &= PMIC_MPP_REG_CURRENT_SINK_MASK; + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_SINK_CTL, val); + if (ret < 0) + return ret; + ret = pmic_mpp_write_mode_ctl(state, pad); if (ret < 0) return ret; @@ -544,6 +581,8 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " dtest%d", pad->dtest); if (pad->paired) seq_puts(s, " paired"); + if (pad->dtest_buffer) + seq_printf(s, " dtest buffer %d", pad->dtest_buffer); } } @@ -741,7 +780,7 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, sel &= PMIC_MPP_REG_MODE_FUNCTION_MASK; if (sel >= PMIC_MPP_SELECTOR_DTEST_FIRST) - pad->dtest = sel + 1; + pad->dtest = sel - PMIC_MPP_SELECTOR_DTEST_FIRST + 1; else if (sel == PMIC_MPP_SELECTOR_PAIRED) pad->paired = true; @@ -752,6 +791,12 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT; pad->power_source &= PMIC_MPP_REG_VIN_MASK; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_IN_CTL); + if (val < 0) + return val; + + pad->dtest_buffer = val; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL); if (val < 0) return val; @@ -770,7 +815,8 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, if (val < 0) return val; - pad->drive_strength = val; + val &= PMIC_MPP_REG_CURRENT_SINK_MASK; + pad->drive_strength = (val + 1) * MPP_CURRENT_SINK_MA_STEP_SIZE; val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AOUT_CTL); if (val < 0) @@ -795,17 +841,19 @@ static int pmic_mpp_probe(struct platform_device *pdev) struct pmic_mpp_pad *pad, *pads; struct pmic_mpp_state *state; int ret, npins, i; - u32 res[2]; + u32 reg; - ret = of_property_read_u32_array(dev->of_node, "reg", res, 2); + ret = of_property_read_u32(dev->of_node, "reg", ®); if (ret < 0) { - dev_err(dev, "missing base address and/or range"); + dev_err(dev, "missing base address"); return ret; } - npins = res[1] / PMIC_MPP_ADDRESS_RANGE; + npins = platform_irq_count(pdev); if (!npins) return -EINVAL; + if (npins < 0) + return npins; BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups)); @@ -854,7 +902,7 @@ static int pmic_mpp_probe(struct platform_device *pdev) if (pad->irq < 0) return pad->irq; - pad->base = res[0] + i * PMIC_MPP_ADDRESS_RANGE; + pad->base = reg + i * PMIC_MPP_ADDRESS_RANGE; ret = pmic_mpp_populate(state, pad); if (ret < 0) @@ -908,6 +956,7 @@ static const struct of_device_id pmic_mpp_of_match[] = { { .compatible = "qcom,pm8916-mpp" }, /* 4 MPP's */ { .compatible = "qcom,pm8941-mpp" }, /* 8 MPP's */ { .compatible = "qcom,pma8084-mpp" }, /* 8 MPP's */ + { .compatible = "qcom,spmi-mpp" }, /* Generic */ { }, }; diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index 19a3c3bc2f1f..e51176ec83d2 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -23,6 +23,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <dt-bindings/pinctrl/qcom,pmic-gpio.h> @@ -650,11 +651,12 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl, } static const struct of_device_id pm8xxx_gpio_of_match[] = { - { .compatible = "qcom,pm8018-gpio", .data = (void *)6 }, - { .compatible = "qcom,pm8038-gpio", .data = (void *)12 }, - { .compatible = "qcom,pm8058-gpio", .data = (void *)40 }, - { .compatible = "qcom,pm8917-gpio", .data = (void *)38 }, - { .compatible = "qcom,pm8921-gpio", .data = (void *)44 }, + { .compatible = "qcom,pm8018-gpio" }, + { .compatible = "qcom,pm8038-gpio" }, + { .compatible = "qcom,pm8058-gpio" }, + { .compatible = "qcom,pm8917-gpio" }, + { .compatible = "qcom,pm8921-gpio" }, + { .compatible = "qcom,ssbi-gpio" }, { }, }; MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); @@ -665,14 +667,19 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) struct pinctrl_pin_desc *pins; struct pm8xxx_gpio *pctrl; int ret; - int i; + int i, npins; pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) return -ENOMEM; pctrl->dev = &pdev->dev; - pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev); + npins = platform_irq_count(pdev); + if (!npins) + return -EINVAL; + if (npins < 0) + return npins; + pctrl->npins = npins; pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!pctrl->regmap) { diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c index b868ef1766a0..e9f01de51e18 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c @@ -23,6 +23,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <dt-bindings/pinctrl/qcom,pmic-mpp.h> @@ -741,11 +742,12 @@ static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl, } static const struct of_device_id pm8xxx_mpp_of_match[] = { - { .compatible = "qcom,pm8018-mpp", .data = (void *)6 }, - { .compatible = "qcom,pm8038-mpp", .data = (void *)6 }, - { .compatible = "qcom,pm8917-mpp", .data = (void *)10 }, - { .compatible = "qcom,pm8821-mpp", .data = (void *)4 }, - { .compatible = "qcom,pm8921-mpp", .data = (void *)12 }, + { .compatible = "qcom,pm8018-mpp" }, + { .compatible = "qcom,pm8038-mpp" }, + { .compatible = "qcom,pm8917-mpp" }, + { .compatible = "qcom,pm8821-mpp" }, + { .compatible = "qcom,pm8921-mpp" }, + { .compatible = "qcom,ssbi-mpp" }, { }, }; MODULE_DEVICE_TABLE(of, pm8xxx_mpp_of_match); @@ -756,14 +758,19 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev) struct pinctrl_pin_desc *pins; struct pm8xxx_mpp *pctrl; int ret; - int i; + int i, npins; pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) return -ENOMEM; pctrl->dev = &pdev->dev; - pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev); + npins = platform_irq_count(pdev); + if (!npins) + return -EINVAL; + if (npins < 0) + return npins; + pctrl->npins = npins; pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!pctrl->regmap) { diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index 6addf14d7126..a02247d3e938 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -2435,6 +2435,7 @@ int ipa_mhi_init(struct ipa_mhi_init_params *params) int res; struct ipa_rm_create_params mhi_prod_params; struct ipa_rm_create_params mhi_cons_params; + struct ipa_rm_perf_profile profile; IPA_MHI_FUNC_ENTRY(); @@ -2506,6 +2507,14 @@ int ipa_mhi_init(struct ipa_mhi_init_params *params) goto fail_create_rm_prod; } + memset(&profile, 0, sizeof(profile)); + profile.max_supported_bandwidth_mbps = 1000; + res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_PROD, &profile); + if (res) { + IPA_MHI_ERR("fail to set profile to MHI_PROD\n"); + goto fail_perf_rm_prod; + } + /* Create CONS in IPA RM */ memset(&mhi_cons_params, 0, sizeof(mhi_cons_params)); mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS; @@ -2518,6 +2527,14 @@ int ipa_mhi_init(struct ipa_mhi_init_params *params) goto fail_create_rm_cons; } + memset(&profile, 0, sizeof(profile)); + profile.max_supported_bandwidth_mbps = 1000; + res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_CONS, &profile); + if (res) { + IPA_MHI_ERR("fail to set profile to MHI_CONS\n"); + goto fail_perf_rm_cons; + } + /* Initialize uC interface */ ipa_uc_mhi_init(ipa_mhi_uc_ready_cb, ipa_mhi_uc_wakeup_request_cb); @@ -2530,7 +2547,10 @@ int ipa_mhi_init(struct ipa_mhi_init_params *params) IPA_MHI_FUNC_EXIT(); return 0; +fail_perf_rm_cons: + ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS); fail_create_rm_cons: +fail_perf_rm_prod: ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD); fail_create_rm_prod: destroy_workqueue(ipa_mhi_client_ctx->wq); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index c0ac544fa271..695c8bc4cbc0 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -2397,7 +2397,7 @@ begin: if (skb->len < IPA_PKT_STATUS_SIZE) { WARN_ON(sys->prev_skb != NULL); IPADBG("status straddles buffer\n"); - sys->prev_skb = skb; + sys->prev_skb = skb_copy(skb, GFP_KERNEL); sys->len_partial = skb->len; return rc; } @@ -2482,7 +2482,7 @@ begin: !status->exception) { WARN_ON(sys->prev_skb != NULL); IPADBG("Ins header in next buffer\n"); - sys->prev_skb = skb; + sys->prev_skb = skb_copy(skb, GFP_KERNEL); sys->len_partial = skb->len; return rc; } diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 2420dd78b4c0..1be9a6745531 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -2394,18 +2394,20 @@ static void rmnet_ipa_get_stats_and_update(bool reset) } rc = ipa_qmi_get_data_stats(&req, resp); + if (rc) { + IPAWANERR("ipa_qmi_get_data_stats failed: %d\n", rc); + kfree(resp); + return; + } - if (!rc) { - memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); - msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_STATS; - msg_meta.msg_len = - sizeof(struct ipa_get_data_stats_resp_msg_v01); - rc = ipa2_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); - if (rc) { - IPAWANERR("ipa2_send_msg failed: %d\n", rc); - kfree(resp); - return; - } + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_STATS; + msg_meta.msg_len = sizeof(struct ipa_get_data_stats_resp_msg_v01); + rc = ipa2_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); + if (rc) { + IPAWANERR("ipa2_send_msg failed: %d\n", rc); + kfree(resp); + return; } } @@ -2454,18 +2456,20 @@ static void rmnet_ipa_get_network_stats_and_update(void) req.mux_id_list[0] = ipa_rmnet_ctx.metered_mux_id; rc = ipa_qmi_get_network_stats(&req, resp); + if (rc) { + IPAWANERR("ipa_qmi_get_network_stats failed %d\n", rc); + kfree(resp); + return; + } - if (!rc) { - memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); - msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_NETWORK_STATS; - msg_meta.msg_len = - sizeof(struct ipa_get_apn_data_stats_resp_msg_v01); - rc = ipa2_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); - if (rc) { - IPAWANERR("ipa2_send_msg failed: %d\n", rc); - kfree(resp); - return; - } + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_NETWORK_STATS; + msg_meta.msg_len = sizeof(struct ipa_get_apn_data_stats_resp_msg_v01); + rc = ipa2_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); + if (rc) { + IPAWANERR("ipa2_send_msg failed: %d\n", rc); + kfree(resp); + return; } } diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index aebdaab3ac77..2cd08d77df6e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2467,18 +2467,20 @@ static void rmnet_ipa_get_stats_and_update(void) req.ipa_stats_type = QMI_IPA_STATS_TYPE_PIPE_V01; rc = ipa3_qmi_get_data_stats(&req, resp); + if (rc) { + IPAWANERR("ipa3_qmi_get_data_stats failed: %d\n", rc); + kfree(resp); + return; + } - if (!rc) { - memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); - msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_STATS; - msg_meta.msg_len = - sizeof(struct ipa_get_data_stats_resp_msg_v01); - rc = ipa_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); - if (rc) { - IPAWANERR("ipa_send_msg failed: %d\n", rc); - kfree(resp); - return; - } + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_STATS; + msg_meta.msg_len = sizeof(struct ipa_get_data_stats_resp_msg_v01); + rc = ipa_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + kfree(resp); + return; } } @@ -2527,18 +2529,20 @@ static void rmnet_ipa_get_network_stats_and_update(void) req.mux_id_list[0] = ipa3_rmnet_ctx.metered_mux_id; rc = ipa3_qmi_get_network_stats(&req, resp); + if (rc) { + IPAWANERR("ipa3_qmi_get_network_stats failed: %d\n", rc); + kfree(resp); + return; + } - if (!rc) { - memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); - msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_NETWORK_STATS; - msg_meta.msg_len = - sizeof(struct ipa_get_apn_data_stats_resp_msg_v01); - rc = ipa_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); - if (rc) { - IPAWANERR("ipa_send_msg failed: %d\n", rc); - kfree(resp); - return; - } + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_NETWORK_STATS; + msg_meta.msg_len = sizeof(struct ipa_get_apn_data_stats_resp_msg_v01); + rc = ipa_send_msg(&msg_meta, resp, rmnet_ipa_free_msg); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + kfree(resp); + return; } } diff --git a/drivers/platform/msm/ipa/test/Makefile b/drivers/platform/msm/ipa/test/Makefile index e1686e608906..c20fd2b42487 100644 --- a/drivers/platform/msm/ipa/test/Makefile +++ b/drivers/platform/msm/ipa/test/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o -ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o +ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o diff --git a/drivers/platform/msm/ipa/test/ipa_test_dma.c b/drivers/platform/msm/ipa/test/ipa_test_dma.c new file mode 100644 index 000000000000..af1b584b0d8c --- /dev/null +++ b/drivers/platform/msm/ipa/test/ipa_test_dma.c @@ -0,0 +1,931 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/ipa.h> +#include "../ipa_v3/ipa_i.h" +#include "ipa_ut_framework.h" + +#define IPA_TEST_DMA_WQ_NAME_BUFF_SZ 64 +#define IPA_TEST_DMA_MT_TEST_NUM_WQ 500 +#define IPA_TEST_DMA_MEMCPY_BUFF_SIZE 16384 +#define IPA_TEST_DMA_MAX_PKT_SIZE 0xFF00 +#define IPA_DMA_TEST_LOOP_NUM 1000 +#define IPA_DMA_TEST_INT_LOOP_NUM 50 +#define IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM 128 +#define IPA_DMA_RUN_TEST_UNIT_IN_LOOP(test_unit, iters, rc, args...) \ + do { \ + int __i; \ + for (__i = 0; __i < iters; __i++) { \ + IPA_UT_LOG(#test_unit " START iter %d\n", __i); \ + rc = test_unit(args); \ + if (!rc) \ + continue; \ + IPA_UT_LOG(#test_unit " failed %d\n", rc); \ + break; \ + } \ + } while (0) + +/** + * struct ipa_test_dma_async_user_data - user_data structure for async memcpy + * @src_mem: source memory buffer + * @dest_mem: destination memory buffer + * @call_serial_number: Id of the caller + * @copy_done: Completion object + */ +struct ipa_test_dma_async_user_data { + struct ipa_mem_buffer src_mem; + struct ipa_mem_buffer dest_mem; + int call_serial_number; + struct completion copy_done; +}; + +/** + * ipa_test_dma_setup() - Suite setup function + */ +static int ipa_test_dma_setup(void **ppriv) +{ + int rc; + + IPA_UT_DBG("Start Setup\n"); + + if (!ipa3_ctx) { + IPA_UT_ERR("No IPA ctx\n"); + return -EINVAL; + } + + rc = ipa_dma_init(); + if (rc) + IPA_UT_ERR("Fail to init ipa_dma - return code %d\n", rc); + else + IPA_UT_DBG("ipa_dma_init() Completed successfully!\n"); + + *ppriv = NULL; + + return rc; +} + +/** + * ipa_test_dma_teardown() - Suite teardown function + */ +static int ipa_test_dma_teardown(void *priv) +{ + IPA_UT_DBG("Start Teardown\n"); + ipa_dma_destroy(); + return 0; +} + +static int ipa_test_dma_alloc_buffs(struct ipa_mem_buffer *src, + struct ipa_mem_buffer *dest, + int size) +{ + int i; + static int val = 1; + int rc; + + val++; + src->size = size; + src->base = dma_alloc_coherent(ipa3_ctx->pdev, src->size, + &src->phys_base, GFP_KERNEL); + if (!src->base) { + IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); + IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); + return -ENOMEM; + } + + dest->size = size; + dest->base = dma_alloc_coherent(ipa3_ctx->pdev, dest->size, + &dest->phys_base, GFP_KERNEL); + if (!dest->base) { + IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); + IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); + rc = -ENOMEM; + goto fail_alloc_dest; + } + + memset(dest->base, 0, dest->size); + for (i = 0; i < src->size; i++) + memset(src->base + i, (val + i) & 0xFF, 1); + rc = memcmp(dest->base, src->base, dest->size); + if (rc == 0) { + IPA_UT_LOG("dest & src buffers are equal\n"); + IPA_UT_TEST_FAIL_REPORT("dest & src buffers are equal"); + rc = -EFAULT; + goto fail_buf_cmp; + } + + return 0; + +fail_buf_cmp: + dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, + dest->phys_base); +fail_alloc_dest: + dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, + src->phys_base); + return rc; +} + +static void ipa_test_dma_destroy_buffs(struct ipa_mem_buffer *src, + struct ipa_mem_buffer *dest) +{ + dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, + src->phys_base); + dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, + dest->phys_base); +} + +/** + * ipa_test_dma_memcpy_sync() - memcpy in sync mode + * + * @size: buffer size + * @expect_fail: test expects the memcpy to fail + * + * To be run during tests + * 1. Alloc src and dst buffers + * 2. sync memcpy src to dst via dma + * 3. compare src and dts if memcpy succeeded as expected + */ +static int ipa_test_dma_memcpy_sync(int size, bool expect_fail) +{ + int rc = 0; + int i; + struct ipa_mem_buffer src_mem; + struct ipa_mem_buffer dest_mem; + u8 *src; + u8 *dest; + + rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); + if (rc) { + IPA_UT_LOG("fail to alloc buffers\n"); + IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); + return rc; + } + + rc = ipa_dma_sync_memcpy(dest_mem.phys_base, src_mem.phys_base, size); + if (!expect_fail && rc) { + IPA_UT_LOG("fail to sync memcpy - rc = %d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); + goto free_buffs; + } + if (expect_fail && !rc) { + IPA_UT_LOG("sync memcpy succeeded while expected to fail\n"); + IPA_UT_TEST_FAIL_REPORT( + "sync memcpy succeeded while expected to fail"); + rc = -EFAULT; + goto free_buffs; + } + + if (!rc) { + /* if memcpy succeeded, compare the buffers */ + rc = memcmp(dest_mem.base, src_mem.base, size); + if (rc) { + IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); + IPA_UT_TEST_FAIL_REPORT( + "BAD memcpy - buffs are not equals"); + src = src_mem.base; + dest = dest_mem.base; + for (i = 0; i < size; i++) { + if (*(src + i) != *(dest + i)) { + IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", + i, *(src + i), *(dest + i)); + } + } + } + } else { + /* if memcpy failed as expected, update the rc */ + rc = 0; + } + +free_buffs: + ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); + return rc; +} + +static void ipa_test_dma_async_memcpy_cb(void *comp_obj) +{ + struct completion *xfer_done; + + if (!comp_obj) { + IPA_UT_ERR("Invalid Input\n"); + return; + } + xfer_done = (struct completion *)comp_obj; + complete(xfer_done); +} + +static void ipa_test_dma_async_memcpy_cb_user_data(void *user_param) +{ + int rc; + int i; + u8 *src; + u8 *dest; + struct ipa_test_dma_async_user_data *udata = + (struct ipa_test_dma_async_user_data *)user_param; + + if (!udata) { + IPA_UT_ERR("Invalid user param\n"); + return; + } + + rc = memcmp(udata->dest_mem.base, udata->src_mem.base, + udata->src_mem.size); + if (rc) { + IPA_UT_LOG("BAD memcpy - buffs are not equal sn=%d\n", + udata->call_serial_number); + IPA_UT_TEST_FAIL_REPORT( + "BAD memcpy - buffs are not equal"); + src = udata->src_mem.base; + dest = udata->dest_mem.base; + for (i = 0; i < udata->src_mem.size; i++) { + if (*(src + i) != *(dest + i)) { + IPA_UT_ERR("byte: %d 0x%x != 0x%x\n", i, + *(src + i), *(dest + i)); + } + } + return; + } + + IPA_UT_LOG("Notify on async memcopy sn=%d\n", + udata->call_serial_number); + complete(&(udata->copy_done)); +} + +/** + * ipa_test_dma_memcpy_async() - memcpy in async mode + * + * @size: buffer size + * @expect_fail: test expected the memcpy to fail + * + * To be run during tests + * 1. Alloc src and dst buffers + * 2. async memcpy src to dst via dma and wait for completion + * 3. compare src and dts if memcpy succeeded as expected + */ +static int ipa_test_dma_memcpy_async(int size, bool expect_fail) +{ + int rc = 0; + int i; + struct ipa_mem_buffer src_mem; + struct ipa_mem_buffer dest_mem; + u8 *src; + u8 *dest; + struct completion xfer_done; + + rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); + if (rc) { + IPA_UT_LOG("fail to alloc buffers\n"); + IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); + return rc; + } + + init_completion(&xfer_done); + rc = ipa_dma_async_memcpy(dest_mem.phys_base, src_mem.phys_base, size, + ipa_test_dma_async_memcpy_cb, &xfer_done); + if (!expect_fail && rc) { + IPA_UT_LOG("fail to initiate async memcpy - rc=%d\n", + rc); + IPA_UT_TEST_FAIL_REPORT("async memcpy initiate failed"); + goto free_buffs; + } + if (expect_fail && !rc) { + IPA_UT_LOG("async memcpy succeeded while expected to fail\n"); + IPA_UT_TEST_FAIL_REPORT( + "async memcpy succeeded while expected to fail"); + rc = -EFAULT; + goto free_buffs; + } + + if (!rc) { + /* if memcpy succeeded, compare the buffers */ + wait_for_completion(&xfer_done); + rc = memcmp(dest_mem.base, src_mem.base, size); + if (rc) { + IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); + IPA_UT_TEST_FAIL_REPORT( + "BAD memcpy - buffs are not equals"); + src = src_mem.base; + dest = dest_mem.base; + for (i = 0; i < size; i++) { + if (*(src + i) != *(dest + i)) { + IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", + i, *(src + i), *(dest + i)); + } + } + } + } else { + /* if memcpy failed as expected, update the rc */ + rc = 0; + } + +free_buffs: + ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); + return rc; +} + +/** + * ipa_test_dma_sync_async_memcpy() - memcpy in sync and then async mode + * + * @size: buffer size + * + * To be run during tests + * 1. several sync memcopy in row + * 2. several async memcopy - + * back-to-back (next async try initiated after prev is completed) + */ +static int ipa_test_dma_sync_async_memcpy(int size) +{ + int rc; + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, + IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); + if (rc) { + IPA_UT_LOG("sync memcopy fail rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcopy fail"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, + IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); + if (rc) { + IPA_UT_LOG("async memcopy fail rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("async memcopy fail"); + return rc; + } + + return 0; +} + +/** + * TEST: test control API - enable/disable dma + * 1. enable dma + * 2. disable dma + */ +static int ipa_test_dma_control_api(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: memcpy before dma enable + * + * 1. sync memcpy - should fail + * 2. async memcpy - should fail + */ +static int ipa_test_dma_memcpy_before_enable(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); + if (rc) { + IPA_UT_LOG("sync memcpy succeeded unexpectedly rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); + return rc; + } + + rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); + if (rc) { + IPA_UT_LOG("async memcpy succeeded unexpectedly rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); + return rc; + } + + return 0; +} + +/** + * TEST: Sync memory copy + * + * 1. dma enable + * 2. sync memcpy + * 3. dma disable + */ +static int ipa_test_dma_sync_memcpy(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Async memory copy + * + * 1. dma enable + * 2. async memcpy + * 3. dma disable + */ +static int ipa_test_dma_async_memcpy(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("async memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("async memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Iteration of sync memory copy + * + * 1. dma enable + * 2. sync memcpy in loop - in row + * 3. dma disable + */ +static int ipa_test_dma_sync_memcpy_in_loop(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, + IPA_DMA_TEST_LOOP_NUM, rc, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("Iterations of sync memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("Iterations of sync memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Iteration of async memory copy + * + * 1. dma enable + * 2. async memcpy in loop - back-to-back + * next async copy is initiated once previous one completed + * 3. dma disable + */ +static int ipa_test_dma_async_memcpy_in_loop(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, + IPA_DMA_TEST_LOOP_NUM, rc, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("Iterations of async memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("Iterations of async memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Iteration of interleaved sync and async memory copy + * + * 1. dma enable + * 2. sync and async memcpy in loop - interleaved + * 3. dma disable + */ +static int ipa_test_dma_interleaved_sync_async_memcpy_in_loop(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_sync_async_memcpy, + IPA_DMA_TEST_INT_LOOP_NUM, rc, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE); + if (rc) { + IPA_UT_LOG( + "Iterations of interleaved sync async memcpy failed rc=%d\n" + , rc); + IPA_UT_TEST_FAIL_REPORT( + "Iterations of interleaved sync async memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +static atomic_t ipa_test_dma_mt_test_pass; + +static void ipa_test_dma_wrapper_test_one_sync(struct work_struct *work) +{ + int rc; + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("fail sync memcpy from thread rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail sync memcpy from thread"); + return; + } + atomic_inc(&ipa_test_dma_mt_test_pass); +} + +static void ipa_test_dma_wrapper_test_one_async(struct work_struct *work) +{ + int rc; + + rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("fail async memcpy from thread rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail async memcpy from thread"); + return; + } + atomic_inc(&ipa_test_dma_mt_test_pass); +} + +/** + * TEST: Multiple threads running sync and sync mem copy + * + * 1. dma enable + * 2. In-loop + * 2.1 create wq for sync memcpy + * 2.2 create wq for async memcpy + * 2.3 queue sync memcpy work + * 2.4 queue async memcoy work + * 3. In-loop + * 3.1 flush and destroy wq sync + * 3.2 flush and destroy wq async + * 3. dma disable + */ +static int ipa_test_dma_mt_sync_async(void *priv) +{ + int rc; + int i; + static struct workqueue_struct *wq_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + static struct workqueue_struct *wq_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + static struct work_struct work_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + static struct work_struct work_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + char buff[IPA_TEST_DMA_WQ_NAME_BUFF_SZ]; + + memset(wq_sync, 0, sizeof(wq_sync)); + memset(wq_sync, 0, sizeof(wq_async)); + memset(work_async, 0, sizeof(work_async)); + memset(work_sync, 0, sizeof(work_sync)); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + atomic_set(&ipa_test_dma_mt_test_pass, 0); + for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { + snprintf(buff, sizeof(buff), "ipa_test_dmaSwq%d", i); + wq_sync[i] = create_singlethread_workqueue(buff); + if (!wq_sync[i]) { + IPA_UT_ERR("failed to create sync wq#%d\n", i); + rc = -EFAULT; + goto fail_create_wq; + } + snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipa_test_dmaAwq%d", i); + wq_async[i] = create_singlethread_workqueue(buff); + if (!wq_async[i]) { + IPA_UT_ERR("failed to create async wq#%d\n", i); + rc = -EFAULT; + goto fail_create_wq; + } + + INIT_WORK(&work_sync[i], ipa_test_dma_wrapper_test_one_sync); + queue_work(wq_sync[i], &work_sync[i]); + INIT_WORK(&work_async[i], ipa_test_dma_wrapper_test_one_async); + queue_work(wq_async[i], &work_async[i]); + } + + for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { + flush_workqueue(wq_sync[i]); + destroy_workqueue(wq_sync[i]); + flush_workqueue(wq_async[i]); + destroy_workqueue(wq_async[i]); + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + if ((2 * IPA_TEST_DMA_MT_TEST_NUM_WQ) != + atomic_read(&ipa_test_dma_mt_test_pass)) { + IPA_UT_LOG( + "Multi-threaded sync/async memcopy failed passed=%d\n" + , atomic_read(&ipa_test_dma_mt_test_pass)); + IPA_UT_TEST_FAIL_REPORT( + "Multi-threaded sync/async memcopy failed"); + return -EFAULT; + } + + return 0; + +fail_create_wq: + (void)ipa_dma_disable(); + for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { + if (wq_sync[i]) + destroy_workqueue(wq_sync[i]); + if (wq_async[i]) + destroy_workqueue(wq_async[i]); + } + + return rc; +} + +/** + * TEST: Several parallel async memory copy iterations + * + * 1. create several user_data structures - one per iteration + * 2. allocate buffs. Give slice for each iteration + * 3. iterations of async mem copy + * 4. wait for all to complete + * 5. dma disable + */ +static int ipa_test_dma_parallel_async_memcpy_in_loop(void *priv) +{ + int rc; + struct ipa_test_dma_async_user_data *udata; + struct ipa_mem_buffer all_src_mem; + struct ipa_mem_buffer all_dest_mem; + int i; + bool is_fail = false; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + udata = kzalloc(IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM * + sizeof(struct ipa_test_dma_async_user_data), GFP_KERNEL); + if (!udata) { + IPA_UT_ERR("fail allocate user_data array\n"); + (void)ipa_dma_disable(); + return -ENOMEM; + } + + rc = ipa_test_dma_alloc_buffs(&all_src_mem, &all_dest_mem, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE); + if (rc) { + IPA_UT_LOG("fail to alloc buffers\n"); + IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); + kfree(udata); + (void)ipa_dma_disable(); + return rc; + } + + for (i = 0 ; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) { + udata[i].src_mem.size = + IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM; + udata[i].src_mem.base = all_src_mem.base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + udata[i].src_mem.phys_base = all_src_mem.phys_base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + + udata[i].dest_mem.size = + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + udata[i].dest_mem.base = all_dest_mem.base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + udata[i].dest_mem.phys_base = all_dest_mem.phys_base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + + udata[i].call_serial_number = i + 1; + init_completion(&(udata[i].copy_done)); + rc = ipa_dma_async_memcpy(udata[i].dest_mem.phys_base, + udata[i].src_mem.phys_base, + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM), + ipa_test_dma_async_memcpy_cb_user_data, &udata[i]); + if (rc) { + IPA_UT_LOG("async memcpy initiation fail i=%d rc=%d\n", + i, rc); + is_fail = true; + } + } + + for (i = 0; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) + wait_for_completion(&udata[i].copy_done); + + ipa_test_dma_destroy_buffs(&all_src_mem, &all_dest_mem); + kfree(udata); + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + if (is_fail) { + IPA_UT_LOG("async memcopy failed\n"); + IPA_UT_TEST_FAIL_REPORT("async memcopy failed"); + return -EFAULT; + } + + return 0; +} + +/** + * TEST: Sync memory copy + * + * 1. dma enable + * 2. sync memcpy with max packet size + * 3. dma disable + */ +static int ipa_test_dma_sync_memcpy_max_pkt_size(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MAX_PKT_SIZE, false); + if (rc) { + IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/* Suite definition block */ +IPA_UT_DEFINE_SUITE_START(dma, "DMA for GSI", + ipa_test_dma_setup, ipa_test_dma_teardown) +{ + IPA_UT_ADD_TEST(control_api, + "Control API", + ipa_test_dma_control_api, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(memcpy_before_enable, + "Call memcpy before dma enable and expect it to fail", + ipa_test_dma_memcpy_before_enable, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(sync_memcpy, + "Sync memory copy", + ipa_test_dma_sync_memcpy, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(async_memcpy, + "Async memory copy", + ipa_test_dma_async_memcpy, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(sync_memcpy_in_loop, + "Several sync memory copy iterations", + ipa_test_dma_sync_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(async_memcpy_in_loop, + "Several async memory copy iterations", + ipa_test_dma_async_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(interleaved_sync_async_memcpy_in_loop, + "Several interleaved sync and async memory copy iterations", + ipa_test_dma_interleaved_sync_async_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(multi_threaded_multiple_sync_async_memcpy, + "Several multi-threaded sync and async memory copy iterations", + ipa_test_dma_mt_sync_async, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(parallel_async_memcpy_in_loop, + "Several parallel async memory copy iterations", + ipa_test_dma_parallel_async_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(sync_memcpy_max_pkt_size, + "Sync memory copy with max packet size", + ipa_test_dma_sync_memcpy_max_pkt_size, + true, IPA_HW_v3_0, IPA_HW_MAX), +} IPA_UT_DEFINE_SUITE_END(dma); diff --git a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h index 944800f8e4be..bbb8b771ba0b 100644 --- a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h +++ b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h @@ -21,6 +21,7 @@ * No importance for order. */ IPA_UT_DECLARE_SUITE(mhi); +IPA_UT_DECLARE_SUITE(dma); IPA_UT_DECLARE_SUITE(example); @@ -31,6 +32,7 @@ IPA_UT_DECLARE_SUITE(example); IPA_UT_DEFINE_ALL_SUITES_START { IPA_UT_REGISTER_SUITE(mhi), + IPA_UT_REGISTER_SUITE(dma), IPA_UT_REGISTER_SUITE(example), } IPA_UT_DEFINE_ALL_SUITES_END; diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index b1c3441b285a..545a1e684b25 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -227,6 +227,8 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(usb_otg), POWER_SUPPLY_ATTR(battery_charging_enabled), POWER_SUPPLY_ATTR(charging_enabled), + POWER_SUPPLY_ATTR(step_charging_enabled), + POWER_SUPPLY_ATTR(step_charging_step), POWER_SUPPLY_ATTR(pin_enabled), POWER_SUPPLY_ATTR(input_suspend), POWER_SUPPLY_ATTR(input_voltage_regulation), diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 2f439b11089f..0be535194b49 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -324,6 +324,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, + POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -383,6 +384,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED: rc = smblib_get_prop_input_current_settled(chg, val); break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW: + rc = smblib_get_prop_usb_current_now(chg, val); + break; default: pr_err("get prop %d is not supported\n", psp); rc = -EINVAL; @@ -582,42 +586,51 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, + POWER_SUPPLY_PROP_CHARGER_TEMP, + POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, }; static int smb2_batt_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { + int rc; struct smb_charger *chg = power_supply_get_drvdata(psy); switch (psp) { case POWER_SUPPLY_PROP_STATUS: - smblib_get_prop_batt_status(chg, val); + rc = smblib_get_prop_batt_status(chg, val); break; case POWER_SUPPLY_PROP_HEALTH: - smblib_get_prop_batt_health(chg, val); + rc = smblib_get_prop_batt_health(chg, val); break; case POWER_SUPPLY_PROP_PRESENT: - smblib_get_prop_batt_present(chg, val); + rc = smblib_get_prop_batt_present(chg, val); break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: - smblib_get_prop_input_suspend(chg, val); + rc = smblib_get_prop_input_suspend(chg, val); break; case POWER_SUPPLY_PROP_CHARGE_TYPE: - smblib_get_prop_batt_charge_type(chg, val); + rc = smblib_get_prop_batt_charge_type(chg, val); break; case POWER_SUPPLY_PROP_CAPACITY: - smblib_get_prop_batt_capacity(chg, val); + rc = smblib_get_prop_batt_capacity(chg, val); break; case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: - smblib_get_prop_system_temp_level(chg, val); + rc = smblib_get_prop_system_temp_level(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP: + rc = smblib_get_prop_charger_temp(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: + rc = smblib_get_prop_charger_temp_max(chg, val); break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; } - return 0; + return rc; } static int smb2_batt_set_prop(struct power_supply *psy, @@ -1219,7 +1232,11 @@ static int smb2_probe(struct platform_device *pdev) return -EINVAL; } - smblib_init(chg); + rc = smblib_init(chg); + if (rc < 0) { + pr_err("Smblib_init failed rc=%d\n", rc); + goto cleanup; + } rc = smb2_parse_dt(chip); if (rc < 0) { diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 15f07ee7d36c..ee4f65430d8b 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -12,6 +12,7 @@ #include <linux/device.h> #include <linux/regmap.h> +#include <linux/iio/consumer.h> #include <linux/power_supply.h> #include <linux/regulator/driver.h> #include <linux/irq.h> @@ -1172,12 +1173,20 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, union power_supply_propval *val) { - if (chg->vbus_present) - val->intval = MICRO_5V; - else - val->intval = 0; + int rc = 0; - return 0; + rc = smblib_get_prop_usb_present(chg, val); + if (rc < 0 || !val->intval) + return rc; + + if (!chg->iio.usbin_v_chan || + PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER) + chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v"); + + if (IS_ERR(chg->iio.usbin_v_chan)) + return PTR_ERR(chg->iio.usbin_v_chan); + + return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval); } int smblib_get_prop_usb_current_max(struct smb_charger *chg, @@ -1187,6 +1196,59 @@ int smblib_get_prop_usb_current_max(struct smb_charger *chg, return 0; } +int smblib_get_prop_usb_current_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc = 0; + + rc = smblib_get_prop_usb_present(chg, val); + if (rc < 0 || !val->intval) + return rc; + + if (!chg->iio.usbin_i_chan || + PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER) + chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i"); + + if (IS_ERR(chg->iio.usbin_i_chan)) + return PTR_ERR(chg->iio.usbin_i_chan); + + return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval); +} + +int smblib_get_prop_charger_temp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->iio.temp_chan || + PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER) + chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp"); + + if (IS_ERR(chg->iio.temp_chan)) + return PTR_ERR(chg->iio.temp_chan); + + rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval); + val->intval /= 100; + return rc; +} + +int smblib_get_prop_charger_temp_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->iio.temp_max_chan || + PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER) + chg->iio.temp_max_chan = iio_channel_get(chg->dev, + "charger_temp_max"); + if (IS_ERR(chg->iio.temp_max_chan)) + return PTR_ERR(chg->iio.temp_max_chan); + + rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval); + val->intval /= 100; + return rc; +} + int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val) { @@ -1992,7 +2054,7 @@ done: vote(chg->awake_votable, PL_VOTER, false, 0); } -int smblib_create_votables(struct smb_charger *chg) +static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; @@ -2086,6 +2148,42 @@ int smblib_create_votables(struct smb_charger *chg) return rc; } +static void smblib_destroy_votables(struct smb_charger *chg) +{ + if (chg->usb_suspend_votable) + destroy_votable(chg->usb_suspend_votable); + if (chg->dc_suspend_votable) + destroy_votable(chg->dc_suspend_votable); + if (chg->fcc_max_votable) + destroy_votable(chg->fcc_max_votable); + if (chg->fcc_votable) + destroy_votable(chg->fcc_votable); + if (chg->fv_votable) + destroy_votable(chg->fv_votable); + if (chg->usb_icl_votable) + destroy_votable(chg->usb_icl_votable); + if (chg->dc_icl_votable) + destroy_votable(chg->dc_icl_votable); + if (chg->pd_allowed_votable) + destroy_votable(chg->pd_allowed_votable); + if (chg->awake_votable) + destroy_votable(chg->awake_votable); + if (chg->pl_disable_votable) + destroy_votable(chg->pl_disable_votable); +} + +static void smblib_iio_deinit(struct smb_charger *chg) +{ + if (!IS_ERR_OR_NULL(chg->iio.temp_chan)) + iio_channel_release(chg->iio.temp_chan); + if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan)) + iio_channel_release(chg->iio.temp_max_chan); + if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan)) + iio_channel_release(chg->iio.usbin_i_chan); + if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan)) + iio_channel_release(chg->iio.usbin_v_chan); +} + int smblib_init(struct smb_charger *chg) { int rc = 0; @@ -2130,18 +2228,19 @@ int smblib_init(struct smb_charger *chg) int smblib_deinit(struct smb_charger *chg) { - destroy_votable(chg->usb_suspend_votable); - destroy_votable(chg->dc_suspend_votable); - destroy_votable(chg->fcc_max_votable); - destroy_votable(chg->fcc_votable); - destroy_votable(chg->fv_votable); - destroy_votable(chg->usb_icl_votable); - destroy_votable(chg->dc_icl_votable); - destroy_votable(chg->pd_allowed_votable); - destroy_votable(chg->awake_votable); - destroy_votable(chg->pl_disable_votable); - - power_supply_unreg_notifier(&chg->nb); + switch (chg->mode) { + case PARALLEL_MASTER: + power_supply_unreg_notifier(&chg->nb); + smblib_destroy_votables(chg); + break; + case PARALLEL_SLAVE: + break; + default: + dev_err(chg->dev, "Unsupported mode %d\n", chg->mode); + return -EINVAL; + } + + smblib_iio_deinit(chg); return 0; } diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index 974dbc7f85dd..1b0c221b4764 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -88,10 +88,18 @@ struct parallel_params { int slave_fcc; }; +struct smb_iio { + struct iio_channel *temp_chan; + struct iio_channel *temp_max_chan; + struct iio_channel *usbin_i_chan; + struct iio_channel *usbin_v_chan; +}; + struct smb_charger { struct device *dev; struct regmap *regmap; struct smb_params param; + struct smb_iio iio; int *debug_mask; enum smb_mode mode; @@ -236,6 +244,8 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_usb_current_max(struct smb_charger *chg, union power_supply_propval *val); +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, @@ -246,6 +256,10 @@ int smblib_get_prop_pd_allowed(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_current_settled(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_charger_temp(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_charger_temp_max(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_usb_current_max(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_usb_voltage_min(struct smb_charger *chg, diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index cc72772dba88..a77b0bbc193c 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -267,6 +267,8 @@ static enum power_supply_property smb138x_batt_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGER_TEMP, + POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, }; static int smb138x_batt_get_prop(struct power_supply *psy, @@ -296,6 +298,12 @@ static int smb138x_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_get_prop_batt_capacity(chg, val); break; + case POWER_SUPPLY_PROP_CHARGER_TEMP: + rc = smblib_get_prop_charger_temp(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: + rc = smblib_get_prop_charger_temp_max(chg, val); + break; default: pr_err("batt power supply get prop %d not supported\n", prop); @@ -381,6 +389,8 @@ static enum power_supply_property smb138x_parallel_props[] = { POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_CHARGER_TEMP, + POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, }; static int smb138x_parallel_get_prop(struct power_supply *psy, @@ -415,6 +425,12 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, rc = smblib_get_charge_param(chg, &chg->param.fcc, &val->intval); break; + case POWER_SUPPLY_PROP_CHARGER_TEMP: + rc = smblib_get_prop_charger_temp(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: + rc = smblib_get_prop_charger_temp_max(chg, val); + break; default: pr_err("parallel power supply get prop %d not supported\n", prop); diff --git a/drivers/power/qcom/debug_core.c b/drivers/power/qcom/debug_core.c index d3620bbbeafa..ccef04ae9eb2 100644 --- a/drivers/power/qcom/debug_core.c +++ b/drivers/power/qcom/debug_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,6 +22,8 @@ #include "soc/qcom/msm-core.h" #define MAX_PSTATES 50 +#define NUM_OF_PENTRY 3 /* number of variables for ptable node */ +#define NUM_OF_EENTRY 2 /* number of variables for enable node */ enum arg_offset { CPU_OFFSET, @@ -82,15 +84,28 @@ static struct debugfs_blob_wrapper help_msg = { }; -static void add_to_ptable(uint64_t *arg) +static void add_to_ptable(unsigned int *arg) { struct core_debug *node; int i, cpu = arg[CPU_OFFSET]; + uint32_t freq = arg[FREQ_OFFSET]; + uint32_t power = arg[POWER_OFFSET]; if (!cpu_possible(cpu)) return; + if ((freq == 0) || (power == 0)) { + pr_warn("Incorrect power data\n"); + return; + } + node = &per_cpu(c_dgfs, cpu); + + if (node->len >= MAX_PSTATES) { + pr_warn("Dropped ptable update - no space left.\n"); + return; + } + if (!node->head) { node->head = kzalloc(sizeof(struct cpu_pstate_pwr) * (MAX_PSTATES + 1), @@ -98,24 +113,18 @@ static void add_to_ptable(uint64_t *arg) if (!node->head) return; } - for (i = 0; i < MAX_PSTATES; i++) { - if (node->head[i].freq == arg[FREQ_OFFSET]) { - node->head[i].power = arg[POWER_OFFSET]; + + for (i = 0; i < node->len; i++) { + if (node->head[i].freq == freq) { + node->head[i].power = power; return; } - if (node->head[i].freq == 0) - break; - } - - if (i == MAX_PSTATES) { - pr_warn("Dropped ptable update - no space left.\n"); - return; } /* Insert a new frequency (may need to move things around to keep in ascending order). */ for (i = MAX_PSTATES - 1; i > 0; i--) { - if (node->head[i-1].freq > arg[FREQ_OFFSET]) { + if (node->head[i-1].freq > freq) { node->head[i].freq = node->head[i-1].freq; node->head[i].power = node->head[i-1].power; } else if (node->head[i-1].freq != 0) { @@ -123,23 +132,29 @@ static void add_to_ptable(uint64_t *arg) } } - node->head[i].freq = arg[FREQ_OFFSET]; - node->head[i].power = arg[POWER_OFFSET]; - node->len++; + if (node->len < MAX_PSTATES) { + node->head[i].freq = freq; + node->head[i].power = power; + node->len++; + } if (node->ptr) node->ptr->len = node->len; } -static int split_ptable_args(char *line, uint64_t *arg) +static int split_ptable_args(char *line, unsigned int *arg, uint32_t n) { char *args; int i; int ret = 0; - for (i = 0; line; i++) { + for (i = 0; i < n; i++) { + if (!line) + break; args = strsep(&line, " "); - ret = kstrtoull(args, 10, &arg[i]); + ret = kstrtouint(args, 10, &arg[i]); + if (ret) + return ret; } return ret; } @@ -149,7 +164,7 @@ static ssize_t msm_core_ptable_write(struct file *file, { char *kbuf; int ret; - uint64_t arg[3]; + unsigned int arg[3]; if (len == 0) return 0; @@ -163,7 +178,7 @@ static ssize_t msm_core_ptable_write(struct file *file, goto done; } kbuf[len] = '\0'; - ret = split_ptable_args(kbuf, arg); + ret = split_ptable_args(kbuf, arg, NUM_OF_PENTRY); if (!ret) { add_to_ptable(arg); ret = len; @@ -201,7 +216,7 @@ static int msm_core_ptable_read(struct seq_file *m, void *data) seq_printf(m, "--- CPU%d - Live numbers at %ldC---\n", cpu, node->ptr->temp); print_table(m, msm_core_data[cpu].ptable, - msm_core_data[cpu].len); + node->driver_len); } } return 0; @@ -212,7 +227,7 @@ static ssize_t msm_core_enable_write(struct file *file, { char *kbuf; int ret; - uint64_t arg[3]; + unsigned int arg[3]; int cpu; if (len == 0) @@ -227,7 +242,7 @@ static ssize_t msm_core_enable_write(struct file *file, goto done; } kbuf[len] = '\0'; - ret = split_ptable_args(kbuf, arg); + ret = split_ptable_args(kbuf, arg, NUM_OF_EENTRY); if (ret) goto done; cpu = arg[CPU_OFFSET]; diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c index fe5dbbeac15e..b0439871c41a 100644 --- a/drivers/regulator/cpr3-mmss-regulator.c +++ b/drivers/regulator/cpr3-mmss-regulator.c @@ -242,8 +242,8 @@ static const int msmcobalt_v2_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = { #define MSMCOBALT_MMSS_CPR_SENSOR_COUNT 35 -#define MSMCOBALT_MMSS_AGING_SENSOR_ID 17 -#define MSMCOBALT_MMSS_AGING_BYPASS_MASK0 0 +#define MSMCOBALT_MMSS_AGING_SENSOR_ID 29 +#define MSMCOBALT_MMSS_AGING_BYPASS_MASK0 (GENMASK(23, 0)) #define MSMCOBALT_MMSS_MAX_TEMP_POINTS 3 #define MSMCOBALT_MMSS_TEMP_SENSOR_ID_START 12 diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c index 6e8db03fe16e..232373092746 100644 --- a/drivers/regulator/cpr3-regulator.c +++ b/drivers/regulator/cpr3-regulator.c @@ -3523,7 +3523,7 @@ cleanup: if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) { rc2 = cpr3_ctrl_clear_cpr4_config(ctrl); - if (rc) { + if (rc2) { cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n", rc2); rc = rc2; @@ -3725,6 +3725,17 @@ static int cpr3_regulator_aging_adjust(struct cpr3_controller *ctrl) return 0; } + /* + * Verify that the aging possible register (if specified) has an + * acceptable value. + */ + if (ctrl->aging_possible_reg) { + reg = readl_relaxed(ctrl->aging_possible_reg); + reg &= ctrl->aging_possible_mask; + if (reg != ctrl->aging_possible_val) + return 0; + } + restore_current_corner = kcalloc(vreg_count, sizeof(*restore_current_corner), GFP_KERNEL); restore_vreg_enabled = kcalloc(vreg_count, @@ -3798,7 +3809,7 @@ static int cpr3_regulator_aging_adjust(struct cpr3_controller *ctrl) max_aging_volt = max(max_aging_volt, aging_volt); } else { cpr3_err(ctrl, "CPR aging measurement failed after %d tries, rc=%d\n", - rc, CPR3_AGING_RETRY_COUNT); + j, rc); ctrl->aging_failed = true; ctrl->aging_required = false; goto cleanup; @@ -5992,6 +6003,21 @@ int cpr3_regulator_register(struct platform_device *pdev, } ctrl->cpr_ctrl_base = devm_ioremap(dev, res->start, resource_size(res)); + if (ctrl->aging_possible_mask) { + /* + * Aging possible register address is required if an aging + * possible mask has been specified. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "aging_allowed"); + if (!res || !res->start) { + cpr3_err(ctrl, "CPR aging allowed address is missing\n"); + return -ENXIO; + } + ctrl->aging_possible_reg = devm_ioremap(dev, res->start, + resource_size(res)); + } + if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPRH) { ctrl->irq = platform_get_irq_byname(pdev, "cpr"); if (ctrl->irq < 0) { diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index 0907518722df..8897def3ef76 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.h @@ -532,6 +532,9 @@ struct cpr3_panic_regs_info { * that this CPR3 controller manages. * @cpr_ctrl_base: Virtual address of the CPR3 controller base register * @fuse_base: Virtual address of fuse row 0 + * @aging_possible_reg: Virtual address of an optional platform-specific + * register that must be ready to determine if it is + * possible to perform an aging measurement. * @list: list head used in a global cpr3-regulator list so that * cpr3-regulator structs can be found easily in RAM dumps * @thread: Array of CPR3 threads managed by the CPR3 controller @@ -671,6 +674,11 @@ struct cpr3_panic_regs_info { * @aging_sensor: Array of CPR3 aging sensors which are used to perform * aging measurements at a runtime. * @aging_sensor_count: Number of elements in the aging_sensor array + * @aging_possible_mask: Optional bitmask used to mask off the + * aging_possible_reg register. + * @aging_possible_val: Optional value that the masked aging_possible_reg + * register must have in order for a CPR aging measurement + * to be possible. * @step_quot_fixed: Fixed step quotient value used for target quotient * adjustment if use_dynamic_step_quot is not set. * This parameter is only relevant for CPR4 controllers @@ -721,6 +729,7 @@ struct cpr3_controller { int ctrl_id; void __iomem *cpr_ctrl_base; void __iomem *fuse_base; + void __iomem *aging_possible_reg; struct list_head list; struct cpr3_thread *thread; int thread_count; @@ -784,6 +793,8 @@ struct cpr3_controller { bool aging_failed; struct cpr3_aging_sensor_info *aging_sensor; int aging_sensor_count; + u32 aging_possible_mask; + u32 aging_possible_val; u32 step_quot_fixed; u32 initial_temp_band; diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index 9d55e9af2e7c..51179f28fcf5 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -1169,6 +1169,24 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl) of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage", &ctrl->aging_ref_volt); + /* Aging possible bitmask is optional */ + ctrl->aging_possible_mask = 0; + of_property_read_u32(ctrl->dev->of_node, + "qcom,cpr-aging-allowed-reg-mask", + &ctrl->aging_possible_mask); + + if (ctrl->aging_possible_mask) { + /* + * Aging possible register value required if bitmask is + * specified + */ + rc = cpr3_parse_ctrl_u32(ctrl, + "qcom,cpr-aging-allowed-reg-value", + &ctrl->aging_possible_val, 0, UINT_MAX); + if (rc) + return rc; + } + if (of_find_property(ctrl->dev->of_node, "clock-names", NULL)) { ctrl->core_clk = devm_clk_get(ctrl->dev, "core_clk"); if (IS_ERR(ctrl->core_clk)) { diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c index 083459f96ac4..284180b0e72f 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -69,8 +69,9 @@ struct cprh_msmcobalt_kbss_fuses { /* * Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0. + * Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1. */ -#define CPRH_MSMCOBALT_KBSS_FUSE_COMBO_COUNT 8 +#define CPRH_MSMCOBALT_KBSS_FUSE_COMBO_COUNT 16 /* * Constants which define the name of each fuse corner. @@ -206,11 +207,19 @@ msmcobalt_v1_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = { * Open loop voltage fuse reference voltages in microvolts for MSMCOBALT v2 */ static const int -msmcobalt_v2_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = { - 688000, - 756000, - 828000, - 1056000, +msmcobalt_v2_kbss_fuse_ref_volt[2][MSMCOBALT_KBSS_FUSE_CORNERS] = { + [MSMCOBALT_KBSS_POWER_CLUSTER_ID] = { + 688000, + 756000, + 828000, + 1056000, + }, + [MSMCOBALT_KBSS_PERFORMANCE_CLUSTER_ID] = { + 756000, + 756000, + 828000, + 1056000, + }, }; #define MSMCOBALT_KBSS_FUSE_STEP_VOLT 10000 @@ -391,7 +400,7 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages( { struct device_node *node = vreg->of_node; struct cprh_msmcobalt_kbss_fuses *fuse = vreg->platform_fuses; - int i, j, soc_revision, rc = 0; + int i, j, soc_revision, id, rc = 0; bool allow_interpolation; u64 freq_low, volt_low, freq_high, volt_high; const int *ref_volt; @@ -407,13 +416,12 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages( goto done; } + id = vreg->thread->ctrl->ctrl_id; soc_revision = vreg->thread->ctrl->soc_revision; if (soc_revision == 1) ref_volt = msmcobalt_v1_kbss_fuse_ref_volt; - else if (soc_revision == 2) - ref_volt = msmcobalt_v2_kbss_fuse_ref_volt; else - ref_volt = msmcobalt_v2_kbss_fuse_ref_volt; + ref_volt = msmcobalt_v2_kbss_fuse_ref_volt[id]; for (i = 0; i < vreg->fuse_corner_count; i++) { fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse( diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index bfa82ca64499..a3bcfb42ca6a 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -996,7 +996,7 @@ static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) } } -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +static int __ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) { int err = 0; @@ -1027,7 +1027,7 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) vote = ufs_qcom_get_bus_vote(host, mode); if (vote >= 0) - err = ufs_qcom_set_bus_vote(host, vote); + err = __ufs_qcom_set_bus_vote(host, vote); else err = vote; @@ -1038,6 +1038,35 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return err; } +static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int vote, err; + + /* + * In case ufs_qcom_init() is not yet done, simply ignore. + * This ufs_qcom_set_bus_vote() shall be called from + * ufs_qcom_init() after init is done. + */ + if (!host) + return 0; + + if (on) { + vote = host->bus_vote.saved_vote; + if (vote == host->bus_vote.min_bw_vote) + ufs_qcom_update_bus_bw_vote(host); + } else { + vote = host->bus_vote.min_bw_vote; + } + + err = __ufs_qcom_set_bus_vote(host, vote); + if (err) + dev_err(hba->dev, "%s: set bus vote failed %d\n", + __func__, err); + + return err; +} + static ssize_t show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, char *buf) @@ -1403,7 +1432,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, { struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err; - int vote = 0; /* * In case ufs_qcom_init() is not yet done, simply ignore. @@ -1428,9 +1456,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, /* enable the device ref clock for HS mode*/ if (ufshcd_is_hs_mode(&hba->pwr_info)) ufs_qcom_dev_ref_clk_ctrl(host, true); - vote = host->bus_vote.saved_vote; - if (vote == host->bus_vote.min_bw_vote) - ufs_qcom_update_bus_bw_vote(host); err = ufs_qcom_ice_resume(host); if (err) @@ -1449,14 +1474,8 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, /* disable device ref_clk */ ufs_qcom_dev_ref_clk_ctrl(host, false); } - vote = host->bus_vote.min_bw_vote; } - err = ufs_qcom_set_bus_vote(host, vote); - if (err) - dev_err(hba->dev, "%s: set bus vote failed %d\n", - __func__, err); - out: return err; } @@ -2011,6 +2030,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); + ufs_qcom_set_bus_vote(hba, true); ufs_qcom_setup_clocks(hba, true, false); if (hba->dev->id < MAX_UFS_QCOM_HOSTS) @@ -2521,6 +2541,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .full_reset = ufs_qcom_full_reset, .update_sec_cfg = ufs_qcom_update_sec_cfg, .get_scale_down_gear = ufs_qcom_get_scale_down_gear, + .set_bus_vote = ufs_qcom_set_bus_vote, .dbg_register_dump = ufs_qcom_dump_dbg_regs, #ifdef CONFIG_DEBUG_FS .add_debugfs = ufs_qcom_dbg_add_debugfs, diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ce779d760c69..a49b3c7bc4ef 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7555,6 +7555,13 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on, if (!head || list_empty(head)) goto out; + /* call vendor specific bus vote before enabling the clocks */ + if (on) { + ret = ufshcd_vops_set_bus_vote(hba, on); + if (ret) + return ret; + } + /* * vendor specific setup_clocks ops may depend on clocks managed by * this standard driver hence call the vendor specific setup_clocks @@ -7593,11 +7600,24 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on, * this standard driver hence call the vendor specific setup_clocks * after enabling the clocks managed here. */ - if (on) + if (on) { ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context); + if (ret) + goto out; + } + + /* + * call vendor specific bus vote to remove the vote after + * disabling the clocks. + */ + if (!on) + ret = ufshcd_vops_set_bus_vote(hba, on); out: if (ret) { + if (on) + /* Can't do much if this fails */ + (void) ufshcd_vops_set_bus_vote(hba, false); list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled) clk_disable_unprepare(clki->clk); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 552d50081e3f..b79bebb58dcd 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -309,6 +309,7 @@ struct ufs_pwr_mode_info { * @update_sec_cfg: called to restore host controller secure configuration * @get_scale_down_gear: called to get the minimum supported gear to * scale down + * @set_bus_vote: called to vote for the required bus bandwidth * @add_debugfs: used to add debugfs entries * @remove_debugfs: used to remove debugfs entries */ @@ -335,6 +336,7 @@ struct ufs_hba_variant_ops { void (*dbg_register_dump)(struct ufs_hba *hba); int (*update_sec_cfg)(struct ufs_hba *hba, bool restore_sec_cfg); u32 (*get_scale_down_gear)(struct ufs_hba *); + int (*set_bus_vote)(struct ufs_hba *, bool); #ifdef CONFIG_DEBUG_FS void (*add_debugfs)(struct ufs_hba *hba, struct dentry *root); void (*remove_debugfs)(struct ufs_hba *hba); @@ -1259,6 +1261,13 @@ static inline u32 ufshcd_vops_get_scale_down_gear(struct ufs_hba *hba) return UFS_HS_G1; } +static inline int ufshcd_vops_set_bus_vote(struct ufs_hba *hba, bool on) +{ + if (hba->var && hba->var->vops && hba->var->vops->set_bus_vote) + return hba->var->vops->set_bus_vote(hba, on); + return 0; +} + #ifdef CONFIG_DEBUG_FS static inline void ufshcd_vops_add_debugfs(struct ufs_hba *hba, struct dentry *root) diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c index ea4dd2ce4e1d..fbde0d318584 100644 --- a/drivers/slimbus/slim-msm-ngd.c +++ b/drivers/slimbus/slim-msm-ngd.c @@ -167,6 +167,7 @@ static int ngd_qmi_available(struct notifier_block *n, unsigned long code, SLIM_INFO(dev, "Slimbus QMI NGD CB received event:%ld\n", code); switch (code) { case QMI_SERVER_ARRIVE: + atomic_set(&dev->ssr_in_progress, 0); schedule_work(&dev->dsp.dom_up); break; default: @@ -214,6 +215,8 @@ static int dsp_domr_notify_cb(struct notifier_block *n, unsigned long code, switch (code) { case SUBSYS_BEFORE_SHUTDOWN: case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: + SLIM_INFO(dev, "SLIM DSP SSR notify cb:%lu\n", code); + atomic_set(&dev->ssr_in_progress, 1); /* wait for current transaction */ mutex_lock(&dev->tx_lock); /* make sure autosuspend is not called until ADSP comes up*/ @@ -866,7 +869,7 @@ static int ngd_bulk_wr(struct slim_controller *ctrl, u8 la, u8 mt, u8 mc, } if (dev->bulk.size > dev->bulk.buf_sz) { void *temp = krealloc(dev->bulk.base, dev->bulk.size, - GFP_KERNEL); + GFP_KERNEL | GFP_DMA); if (!temp) { ret = -ENOMEM; goto retpath; @@ -1316,8 +1319,10 @@ hw_init_retry: if (ret) { SLIM_WARN(dev, "SLIM power req failed:%d, retry:%d\n", ret, retries); - msm_slim_qmi_power_request(dev, false); - if (retries < INIT_MX_RETRIES) { + if (!atomic_read(&dev->ssr_in_progress)) + msm_slim_qmi_power_request(dev, false); + if (retries < INIT_MX_RETRIES && + !atomic_read(&dev->ssr_in_progress)) { retries++; goto hw_init_retry; } @@ -1416,7 +1421,8 @@ capability_retry: SLIM_WARN(dev, "slim capability time-out:%d, stat:0x%x,cfg:0x%x\n", retries, laddr, cfg); - if (retries < INIT_MX_RETRIES) { + if ((retries < INIT_MX_RETRIES) && + !atomic_read(&dev->ssr_in_progress)) { retries++; goto capability_retry; } @@ -1683,7 +1689,7 @@ static int ngd_slim_probe(struct platform_device *pdev) /* typical txn numbers and size used in bulk operation */ dev->bulk.buf_sz = SLIM_MAX_TXNS * 8; - dev->bulk.base = kzalloc(dev->bulk.buf_sz, GFP_KERNEL); + dev->bulk.base = kzalloc(dev->bulk.buf_sz, GFP_KERNEL | GFP_DMA); if (!dev->bulk.base) { ret = -ENOMEM; goto err_nobulk; @@ -1780,6 +1786,7 @@ static int ngd_slim_probe(struct platform_device *pdev) dev->ee = 1; dev->irq = irq->start; dev->bam.irq = bam_irq->start; + atomic_set(&dev->ssr_in_progress, 0); if (rxreg_access) dev->use_rx_msgqs = MSM_MSGQ_DISABLED; @@ -1938,6 +1945,7 @@ static int ngd_slim_runtime_resume(struct device *device) struct platform_device *pdev = to_platform_device(device); struct msm_slim_ctrl *dev = platform_get_drvdata(pdev); int ret = 0; + mutex_lock(&dev->tx_lock); if (dev->state >= MSM_CTRL_ASLEEP) ret = ngd_slim_power_up(dev, false); diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h index 7616e714299c..65b9fae8040b 100644 --- a/drivers/slimbus/slim-msm.h +++ b/drivers/slimbus/slim-msm.h @@ -314,6 +314,7 @@ struct msm_slim_ctrl { void (*rx_slim)(struct msm_slim_ctrl *dev, u8 *buf); u32 current_rx_buf[10]; int current_count; + atomic_t ssr_in_progress; }; struct msm_sat_chan { diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 0e74093eeb2b..f884f829b51c 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -417,6 +417,15 @@ config ICNSS control messages to FW over QMI channel. It is also responsible for handling WLAN PD restart notifications. +config ICNSS_DEBUG + bool "ICNSS debug support" + depends on ICNSS + ---help--- + Say 'Y' here to enable ICNSS driver debug support. Debug support + primarily consists of logs consisting of information related to + hardware register access and enabling BUG_ON for certain cases to aid + the debugging. + config MSM_SECURE_BUFFER bool "Helper functions for securing buffers through TZ" help diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index e9e65ea443dd..fb8437d7a7c3 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -70,7 +70,7 @@ obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o obj-$(CONFIG_QCOM_COMMON_LOG) += common_log.o obj-$(CONFIG_QCOM_IRQ_HELPER) += irq-helper.o obj-$(CONFIG_TRACER_PKT) += tracer_pkt.o -obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o +obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o icnss_utils.o obj-$(CONFIG_SOC_BUS) += socinfo.o obj-$(CONFIG_QCOM_BUS_SCALING) += msm_bus/ obj-$(CONFIG_MSM_SERVICE_NOTIFIER) += service-notifier.o diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index 20a4a3c7fdf0..f00570aa5fe8 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -4113,6 +4113,37 @@ static struct glink_core_xprt_ctx *glink_create_dummy_xprt_ctx( return xprt_ptr; } +static struct channel_ctx *get_first_ch_ctx( + struct glink_core_xprt_ctx *xprt_ctx) +{ + unsigned long flags; + struct channel_ctx *ctx; + + spin_lock_irqsave(&xprt_ctx->xprt_ctx_lock_lhb1, flags); + if (!list_empty(&xprt_ctx->channels)) { + ctx = list_first_entry(&xprt_ctx->channels, + struct channel_ctx, port_list_node); + rwref_get(&ctx->ch_state_lhb2); + } else { + ctx = NULL; + } + spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1, flags); + return ctx; +} + +static void glink_core_move_ch_node(struct glink_core_xprt_ctx *xprt_ptr, + struct glink_core_xprt_ctx *dummy_xprt_ctx, struct channel_ctx *ctx) +{ + unsigned long flags, d_flags; + + spin_lock_irqsave(&dummy_xprt_ctx->xprt_ctx_lock_lhb1, d_flags); + spin_lock_irqsave(&xprt_ptr->xprt_ctx_lock_lhb1, flags); + rwref_get(&dummy_xprt_ctx->xprt_state_lhb0); + list_move_tail(&ctx->port_list_node, &dummy_xprt_ctx->channels); + spin_unlock_irqrestore(&xprt_ptr->xprt_ctx_lock_lhb1, flags); + spin_unlock_irqrestore(&dummy_xprt_ctx->xprt_ctx_lock_lhb1, d_flags); +} + /** * glink_core_channel_cleanup() - cleanup all channels for the transport * @@ -4123,7 +4154,7 @@ static struct glink_core_xprt_ctx *glink_create_dummy_xprt_ctx( static void glink_core_channel_cleanup(struct glink_core_xprt_ctx *xprt_ptr) { unsigned long flags, d_flags; - struct channel_ctx *ctx, *tmp_ctx; + struct channel_ctx *ctx; struct channel_lcid *temp_lcid, *temp_lcid1; struct glink_core_xprt_ctx *dummy_xprt_ctx; @@ -4132,29 +4163,18 @@ static void glink_core_channel_cleanup(struct glink_core_xprt_ctx *xprt_ptr) GLINK_ERR("%s: Dummy Transport creation failed\n", __func__); return; } - rwref_read_get(&dummy_xprt_ctx->xprt_state_lhb0); rwref_read_get(&xprt_ptr->xprt_state_lhb0); - spin_lock_irqsave(&dummy_xprt_ctx->xprt_ctx_lock_lhb1, d_flags); - spin_lock_irqsave(&xprt_ptr->xprt_ctx_lock_lhb1, flags); - - list_for_each_entry_safe(ctx, tmp_ctx, &xprt_ptr->channels, - port_list_node) { + ctx = get_first_ch_ctx(xprt_ptr); + while (ctx) { rwref_write_get_atomic(&ctx->ch_state_lhb2, true); if (ctx->local_open_state == GLINK_CHANNEL_OPENED || ctx->local_open_state == GLINK_CHANNEL_OPENING) { - rwref_get(&dummy_xprt_ctx->xprt_state_lhb0); - list_move_tail(&ctx->port_list_node, - &dummy_xprt_ctx->channels); ctx->transport_ptr = dummy_xprt_ctx; rwref_write_put(&ctx->ch_state_lhb2); + glink_core_move_ch_node(xprt_ptr, dummy_xprt_ctx, ctx); } else { /* local state is in either CLOSED or CLOSING */ - spin_unlock_irqrestore(&xprt_ptr->xprt_ctx_lock_lhb1, - flags); - spin_unlock_irqrestore( - &dummy_xprt_ctx->xprt_ctx_lock_lhb1, - d_flags); glink_core_remote_close_common(ctx, true); if (ctx->local_open_state == GLINK_CHANNEL_CLOSING) glink_core_ch_close_ack_common(ctx, true); @@ -4162,22 +4182,21 @@ static void glink_core_channel_cleanup(struct glink_core_xprt_ctx *xprt_ptr) if (ch_is_fully_closed(ctx)) glink_delete_ch_from_list(ctx, false); rwref_write_put(&ctx->ch_state_lhb2); - spin_lock_irqsave(&dummy_xprt_ctx->xprt_ctx_lock_lhb1, - d_flags); - spin_lock_irqsave(&xprt_ptr->xprt_ctx_lock_lhb1, flags); } + rwref_put(&ctx->ch_state_lhb2); + ctx = get_first_ch_ctx(xprt_ptr); } + spin_lock_irqsave(&xprt_ptr->xprt_ctx_lock_lhb1, flags); list_for_each_entry_safe(temp_lcid, temp_lcid1, &xprt_ptr->free_lcid_list, list_node) { list_del(&temp_lcid->list_node); kfree(&temp_lcid->list_node); } - dummy_xprt_ctx->dummy_in_use = false; spin_unlock_irqrestore(&xprt_ptr->xprt_ctx_lock_lhb1, flags); - spin_unlock_irqrestore(&dummy_xprt_ctx->xprt_ctx_lock_lhb1, d_flags); rwref_read_put(&xprt_ptr->xprt_state_lhb0); spin_lock_irqsave(&dummy_xprt_ctx->xprt_ctx_lock_lhb1, d_flags); + dummy_xprt_ctx->dummy_in_use = false; while (!list_empty(&dummy_xprt_ctx->channels)) { ctx = list_first_entry(&dummy_xprt_ctx->channels, struct channel_ctx, port_list_node); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 26b1cad9d5aa..aaca82f87159 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -44,11 +44,11 @@ #include "wlan_firmware_service_v01.h" -#define ICNSS_PANIC 1 #define WLFW_TIMEOUT_MS 3000 #define WLFW_SERVICE_INS_ID_V01 0 #define MAX_PROP_SIZE 32 -#define NUM_LOG_PAGES 4 +#define NUM_LOG_PAGES 10 +#define NUM_REG_LOG_PAGES 4 /* * Registers: MPM2_PSHOLD @@ -57,9 +57,12 @@ #define MPM_WCSSAON_CONFIG_OFFSET 0x18 #define MPM_WCSSAON_CONFIG_ARES_N BIT(0) #define MPM_WCSSAON_CONFIG_WLAN_DISABLE BIT(1) +#define MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD BIT(6) +#define MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD_VAL BIT(7) #define MPM_WCSSAON_CONFIG_FORCE_ACTIVE BIT(14) #define MPM_WCSSAON_CONFIG_FORCE_XO_ENABLE BIT(19) #define MPM_WCSSAON_CONFIG_DISCONNECT_CLR BIT(21) +#define MPM_WCSSAON_CONFIG_M2W_CLAMP_EN BIT(22) /* * Registers: WCSS_SR_SHADOW_REGISTERS @@ -148,6 +151,10 @@ #define ICNSS_HW_REG_RETRY 10 +#define WCSS_HM_A_PMM_HW_VERSION_V10 0x40000000 +#define WCSS_HM_A_PMM_HW_VERSION_V20 0x40010000 +#define WCSS_HM_A_PMM_HW_VERSION_Q10 0x40010001 + #define ICNSS_SERVICE_LOCATION_CLIENT_NAME "ICNSS-WLAN" #define ICNSS_WLAN_SERVICE_NAME "wlan/fw" @@ -156,6 +163,15 @@ ipc_log_string(icnss_ipc_log_context, _x); \ } while (0) +#ifdef CONFIG_ICNSS_DEBUG +#define icnss_ipc_log_long_string(_x...) do { \ + if (icnss_ipc_log_long_context) \ + ipc_log_string(icnss_ipc_log_long_context, _x); \ + } while (0) +#else +#define icnss_ipc_log_long_string(_x...) +#endif + #define icnss_pr_err(_fmt, ...) do { \ pr_err(_fmt, ##__VA_ARGS__); \ icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \ @@ -180,7 +196,13 @@ ##__VA_ARGS__); \ } while (0) -#ifdef ICNSS_PANIC +#define icnss_reg_dbg(_fmt, ...) do { \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_long_string("REG: " pr_fmt(_fmt), \ + ##__VA_ARGS__); \ + } while (0) + +#ifdef CONFIG_ICNSS_DEBUG #define ICNSS_ASSERT(_condition) do { \ if (!(_condition)) { \ icnss_pr_err("ASSERT at line %d\n", \ @@ -215,6 +237,10 @@ module_param(quirks, ulong, 0600); void *icnss_ipc_log_context; +#ifdef CONFIG_ICNSS_DEBUG +void *icnss_ipc_log_long_context; +#endif + #define ICNSS_EVENT_PENDING 2989 enum icnss_driver_event_type { @@ -383,7 +409,7 @@ static u32 icnss_hw_read_reg(void *base, u32 offset) { u32 rdata = readl_relaxed(base + offset); - icnss_pr_dbg(" READ: offset: 0x%06x 0x%08x\n", offset, rdata); + icnss_reg_dbg(" READ: offset: 0x%06x 0x%08x\n", offset, rdata); return rdata; } @@ -395,7 +421,7 @@ static void icnss_hw_write_reg_field(void *base, u32 offset, u32 mask, u32 val) val = (rdata & ~mask) | (val << shift); - icnss_pr_dbg("WRITE: offset: 0x%06x 0x%08x -> 0x%08x\n", + icnss_reg_dbg("WRITE: offset: 0x%06x 0x%08x -> 0x%08x\n", offset, rdata, val); icnss_hw_write_reg(base, offset, val); @@ -414,12 +440,12 @@ static int icnss_hw_poll_reg_field(void *base, u32 offset, u32 mask, u32 val, rdata = readl_relaxed(base + offset); - icnss_pr_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", + icnss_reg_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", offset, val, rdata, mask); while ((rdata & mask) != val) { if (retry != 0 && r >= retry) { - icnss_pr_err(" POLL FAILED: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", + icnss_pr_err("POLL FAILED: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", offset, val, rdata, mask); return -EIO; @@ -430,8 +456,8 @@ static int icnss_hw_poll_reg_field(void *base, u32 offset, u32 mask, u32 val, rdata = readl_relaxed(base + offset); if (retry) - icnss_pr_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", - offset, val, rdata, mask); + icnss_reg_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", + offset, val, rdata, mask); } @@ -758,6 +784,32 @@ static void icnss_hw_top_level_reset(struct icnss_priv *priv) ICNSS_HW_REG_RETRY); } +static void icnss_hw_io_reset(struct icnss_priv *priv, bool on) +{ + u32 hw_version = priv->soc_info.soc_id; + + if (on && !test_bit(ICNSS_FW_READY, &priv->state)) + return; + + icnss_pr_dbg("HW io reset: %s, SoC: 0x%x, state: 0x%lx\n", + on ? "ON" : "OFF", priv->soc_info.soc_id, priv->state); + + if (hw_version == WCSS_HM_A_PMM_HW_VERSION_V10 || + hw_version == WCSS_HM_A_PMM_HW_VERSION_V20) { + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD_VAL, 0); + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD, on); + } else if (hw_version == WCSS_HM_A_PMM_HW_VERSION_Q10) { + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_M2W_CLAMP_EN, + on); + } +} + int icnss_hw_reset_wlan_ss_power_down(struct icnss_priv *priv) { u32 rdata; @@ -1123,7 +1175,7 @@ static int icnss_hw_power_on(struct icnss_priv *priv) int ret = 0; unsigned long flags; - icnss_pr_dbg("Power on: state: 0x%lx\n", priv->state); + icnss_pr_dbg("HW Power on: state: 0x%lx\n", priv->state); spin_lock_irqsave(&priv->on_off_lock, flags); if (test_bit(ICNSS_POWER_ON, &priv->state)) { @@ -1143,6 +1195,8 @@ static int icnss_hw_power_on(struct icnss_priv *priv) icnss_hw_top_level_release_reset(priv); + icnss_hw_io_reset(penv, 1); + return ret; out: clear_bit(ICNSS_POWER_ON, &priv->state); @@ -1157,7 +1211,7 @@ static int icnss_hw_power_off(struct icnss_priv *priv) if (test_bit(HW_ALWAYS_ON, &quirks)) return 0; - icnss_pr_dbg("Power off: 0x%lx\n", priv->state); + icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state); spin_lock_irqsave(&priv->on_off_lock, flags); if (!test_bit(ICNSS_POWER_ON, &priv->state)) { @@ -1167,6 +1221,8 @@ static int icnss_hw_power_off(struct icnss_priv *priv) clear_bit(ICNSS_POWER_ON, &priv->state); spin_unlock_irqrestore(&priv->on_off_lock, flags); + icnss_hw_io_reset(penv, 0); + icnss_hw_reset(priv); icnss_clk_deinit(priv); @@ -1191,6 +1247,8 @@ int icnss_power_on(struct device *dev) return -EINVAL; } + icnss_pr_dbg("Power On: 0x%lx\n", priv->state); + return icnss_hw_power_on(priv); } EXPORT_SYMBOL(icnss_power_on); @@ -1205,6 +1263,8 @@ int icnss_power_off(struct device *dev) return -EINVAL; } + icnss_pr_dbg("Power Off: 0x%lx\n", priv->state); + return icnss_hw_power_off(priv); } EXPORT_SYMBOL(icnss_power_off); @@ -1235,11 +1295,11 @@ int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index) ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) { - icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", + icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", index, &addr, size, ret); goto out; } - icnss_pr_dbg("hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n", + icnss_pr_dbg("Hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n", index, source_vmlist[0], dest_nelems, dest_vmids[0], dest_vmids[1], dest_vmids[2]); out: @@ -1271,7 +1331,7 @@ int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index) ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) { - icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", + icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", index, &addr, size, ret); goto out; } @@ -1310,16 +1370,14 @@ static void icnss_remove_msa_permissions(struct icnss_priv *priv) static int wlfw_msa_mem_info_send_sync_msg(void) { - int ret = 0; + int ret; int i; struct wlfw_msa_info_req_msg_v01 req; struct wlfw_msa_info_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending MSA mem info, state: 0x%lx\n", penv->state); @@ -1342,15 +1400,14 @@ static int wlfw_msa_mem_info_send_sync_msg(void) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); + icnss_pr_err("Send MSA Mem info req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI MSA Mem info request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.msa_info_err++; goto out; } @@ -1361,7 +1418,6 @@ static int wlfw_msa_mem_info_send_sync_msg(void) icnss_pr_err("Invalid memory region length received: %d\n", resp.mem_region_info_len); ret = -EINVAL; - penv->stats.msa_info_err++; goto out; } @@ -1379,7 +1435,11 @@ static int wlfw_msa_mem_info_send_sync_msg(void) penv->icnss_mem_region[i].secure_flag); } + return 0; + out: + penv->stats.msa_info_err++; + ICNSS_ASSERT(false); return ret; } @@ -1390,10 +1450,8 @@ static int wlfw_msa_ready_send_sync_msg(void) struct wlfw_msa_ready_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending MSA ready request message, state: 0x%lx\n", penv->state); @@ -1413,20 +1471,23 @@ static int wlfw_msa_ready_send_sync_msg(void) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - penv->stats.msa_ready_err++; - icnss_pr_err("Send req failed %d\n", ret); + icnss_pr_err("Send MSA ready req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI MSA ready request failed %d %d\n", resp.resp.result, resp.resp.error); - penv->stats.msa_ready_err++; ret = resp.resp.result; goto out; } penv->stats.msa_ready_resp++; + + return 0; + out: + penv->stats.msa_ready_err++; + ICNSS_ASSERT(false); return ret; } @@ -1437,10 +1498,8 @@ static int wlfw_ind_register_send_sync_msg(void) struct wlfw_ind_register_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending indication register message, state: 0x%lx\n", penv->state); @@ -1468,21 +1527,24 @@ static int wlfw_ind_register_send_sync_msg(void) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); - penv->stats.ind_register_resp++; if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.ind_register_err++; + icnss_pr_err("Send indication register req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI indication register request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.ind_register_err++; goto out; } + penv->stats.ind_register_resp++; + + return 0; + out: + penv->stats.ind_register_err++; + ICNSS_ASSERT(false); return ret; } @@ -1493,10 +1555,8 @@ static int wlfw_cap_send_sync_msg(void) struct wlfw_cap_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending capability message, state: 0x%lx\n", penv->state); @@ -1515,16 +1575,14 @@ static int wlfw_cap_send_sync_msg(void) &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.cap_err++; + icnss_pr_err("Send capability req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI capability request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.cap_err++; goto out; } @@ -1546,7 +1604,12 @@ static int wlfw_cap_send_sync_msg(void) penv->board_info.board_id, penv->soc_info.soc_id, penv->fw_version_info.fw_version, penv->fw_version_info.fw_build_timestamp); + + return 0; + out: + penv->stats.cap_err++; + ICNSS_ASSERT(false); return ret; } @@ -1557,10 +1620,8 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) struct wlfw_wlan_mode_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; /* During recovery do not send mode request for WLAN OFF as * FW not able to process it. @@ -1592,20 +1653,24 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.mode_req_err++; + icnss_pr_err("Send mode req failed, mode: %d ret: %d\n", + mode, ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", - resp.resp.result, resp.resp.error); + icnss_pr_err("QMI mode request failed mode: %d, %d %d\n", + mode, resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.mode_req_err++; goto out; } penv->stats.mode_resp++; + + return 0; + out: + penv->stats.mode_req_err++; + ICNSS_ASSERT(false); return ret; } @@ -1616,10 +1681,8 @@ static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data) struct wlfw_wlan_cfg_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { + if (!penv || !penv->wlfw_clnt) return -ENODEV; - goto out; - } icnss_pr_dbg("Sending config request, state: 0x%lx\n", penv->state); @@ -1641,20 +1704,23 @@ static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data) &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.cfg_req_err++; + icnss_pr_err("Send config req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI config request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.cfg_req_err++; goto out; } penv->stats.cfg_resp++; + + return 0; + out: + penv->stats.cfg_req_err++; + ICNSS_ASSERT(false); return ret; } @@ -1665,10 +1731,8 @@ static int wlfw_ini_send_sync_msg(bool enable_fw_log) struct wlfw_ini_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log: %d\n", penv->state, enable_fw_log); @@ -1692,20 +1756,24 @@ static int wlfw_ini_send_sync_msg(bool enable_fw_log) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("send req failed %d\n", ret); - penv->stats.ini_req_err++; + icnss_pr_err("Send INI req failed fw_log: %d, ret: %d\n", + enable_fw_log, ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", - resp.resp.result, resp.resp.error); + icnss_pr_err("QMI INI request failed fw_log: %d, %d %d\n", + enable_fw_log, resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.ini_req_err++; goto out; } penv->stats.ini_resp++; + + return 0; + out: + penv->stats.ini_req_err++; + ICNSS_ASSERT(false); return ret; } @@ -1789,12 +1857,11 @@ static int icnss_driver_event_server_arrive(void *data) goto out; } - ret = qmi_connect_to_service(penv->wlfw_clnt, - WLFW_SERVICE_ID_V01, - WLFW_SERVICE_VERS_V01, - WLFW_SERVICE_INS_ID_V01); + ret = qmi_connect_to_service(penv->wlfw_clnt, WLFW_SERVICE_ID_V01, + WLFW_SERVICE_VERS_V01, + WLFW_SERVICE_INS_ID_V01); if (ret < 0) { - icnss_pr_err("Server not found : %d\n", ret); + icnss_pr_err("QMI WLAN Service not found : %d\n", ret); goto fail; } @@ -1815,10 +1882,8 @@ static int icnss_driver_event_server_arrive(void *data) goto fail; ret = wlfw_ind_register_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to send indication message: %d\n", ret); + if (ret < 0) goto err_power_on; - } if (!penv->msa_va) { icnss_pr_err("Invalid MSA address\n"); @@ -1827,27 +1892,21 @@ static int icnss_driver_event_server_arrive(void *data) } ret = wlfw_msa_mem_info_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to send MSA info: %d\n", ret); + if (ret < 0) goto err_power_on; - } + ret = icnss_setup_msa_permissions(penv); - if (ret < 0) { - icnss_pr_err("Failed to setup msa permissions: %d\n", - ret); + if (ret < 0) goto err_power_on; - } + ret = wlfw_msa_ready_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to send MSA ready : %d\n", ret); + if (ret < 0) goto err_setup_msa; - } ret = wlfw_cap_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to get capability: %d\n", ret); + if (ret < 0) goto err_setup_msa; - } + return ret; err_setup_msa: @@ -2680,14 +2739,10 @@ int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req.shadow_reg_len); ret = wlfw_wlan_cfg_send_sync_msg(&req); - if (ret) { - icnss_pr_err("Failed to send cfg, ret = %d\n", ret); + if (ret) goto out; - } skip: ret = wlfw_wlan_mode_send_sync_msg(mode); - if (ret) - icnss_pr_err("Failed to send mode, ret = %d\n", ret); out: if (test_bit(SKIP_QMI, &quirks)) ret = 0; @@ -3416,6 +3471,8 @@ static int icnss_probe(struct platform_device *pdev) return -EEXIST; } + icnss_pr_dbg("Platform driver probe\n"); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -3515,9 +3572,8 @@ static int icnss_probe(struct platform_device *pdev) } else { priv->smmu_iova_start = res->start; priv->smmu_iova_len = resource_size(res); - icnss_pr_dbg("smmu_iova_start: %pa, smmu_iova_len: %zu\n", - &priv->smmu_iova_start, - priv->smmu_iova_len); + icnss_pr_dbg("SMMU IOVA start: %pa, len: %zu\n", + &priv->smmu_iova_start, priv->smmu_iova_len); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -3527,7 +3583,7 @@ static int icnss_probe(struct platform_device *pdev) } else { priv->smmu_iova_ipa_start = res->start; priv->smmu_iova_ipa_len = resource_size(res); - icnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: %zu\n", + icnss_pr_dbg("SMMU IOVA IPA start: %pa, len: %zu\n", &priv->smmu_iova_ipa_start, priv->smmu_iova_ipa_len); } @@ -3688,6 +3744,26 @@ static struct platform_driver icnss_driver = { }, }; +#ifdef CONFIG_ICNSS_DEBUG +static void __init icnss_ipc_log_long_context_init(void) +{ + icnss_ipc_log_long_context = ipc_log_context_create(NUM_REG_LOG_PAGES, + "icnss_long", 0); + if (!icnss_ipc_log_long_context) + icnss_pr_err("Unable to create register log context\n"); +} + +static void __exit icnss_ipc_log_long_context_destroy(void) +{ + ipc_log_context_destroy(icnss_ipc_log_long_context); + icnss_ipc_log_long_context = NULL; +} +#else + +static void __init icnss_ipc_log_long_context_init(void) { } +static void __exit icnss_ipc_log_long_context_destroy(void) { } +#endif + static int __init icnss_initialize(void) { icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES, @@ -3695,6 +3771,8 @@ static int __init icnss_initialize(void) if (!icnss_ipc_log_context) icnss_pr_err("Unable to create log context\n"); + icnss_ipc_log_long_context_init(); + return platform_driver_register(&icnss_driver); } @@ -3703,6 +3781,8 @@ static void __exit icnss_exit(void) platform_driver_unregister(&icnss_driver); ipc_log_context_destroy(icnss_ipc_log_context); icnss_ipc_log_context = NULL; + + icnss_ipc_log_long_context_destroy(); } diff --git a/drivers/soc/qcom/icnss_utils.c b/drivers/soc/qcom/icnss_utils.c new file mode 100644 index 000000000000..5e187d5df8b3 --- /dev/null +++ b/drivers/soc/qcom/icnss_utils.c @@ -0,0 +1,132 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/slab.h> + +#define ICNSS_MAX_CH_NUM 45 + +static DEFINE_MUTEX(unsafe_channel_list_lock); +static DEFINE_MUTEX(dfs_nol_info_lock); + +static struct icnss_unsafe_channel_list { + u16 unsafe_ch_count; + u16 unsafe_ch_list[ICNSS_MAX_CH_NUM]; +} unsafe_channel_list; + +static struct icnss_dfs_nol_info { + void *dfs_nol_info; + u16 dfs_nol_info_len; +} dfs_nol_info; + +int icnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count) +{ + mutex_lock(&unsafe_channel_list_lock); + if ((!unsafe_ch_list) || (ch_count > ICNSS_MAX_CH_NUM)) { + mutex_unlock(&unsafe_channel_list_lock); + return -EINVAL; + } + + unsafe_channel_list.unsafe_ch_count = ch_count; + + if (ch_count != 0) { + memcpy( + (char *)unsafe_channel_list.unsafe_ch_list, + (char *)unsafe_ch_list, ch_count * sizeof(u16)); + } + mutex_unlock(&unsafe_channel_list_lock); + + return 0; +} +EXPORT_SYMBOL(icnss_set_wlan_unsafe_channel); + +int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + mutex_lock(&unsafe_channel_list_lock); + if (!unsafe_ch_list || !ch_count) { + mutex_unlock(&unsafe_channel_list_lock); + return -EINVAL; + } + + if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) { + mutex_unlock(&unsafe_channel_list_lock); + return -ENOMEM; + } + + *ch_count = unsafe_channel_list.unsafe_ch_count; + memcpy( + (char *)unsafe_ch_list, + (char *)unsafe_channel_list.unsafe_ch_list, + unsafe_channel_list.unsafe_ch_count * sizeof(u16)); + mutex_unlock(&unsafe_channel_list_lock); + + return 0; +} +EXPORT_SYMBOL(icnss_get_wlan_unsafe_channel); + +int icnss_wlan_set_dfs_nol(const void *info, u16 info_len) +{ + void *temp; + struct icnss_dfs_nol_info *dfs_info; + + mutex_lock(&dfs_nol_info_lock); + if (!info || !info_len) { + mutex_unlock(&dfs_nol_info_lock); + return -EINVAL; + } + + temp = kmalloc(info_len, GFP_KERNEL); + if (!temp) { + mutex_unlock(&dfs_nol_info_lock); + return -ENOMEM; + } + + memcpy(temp, info, info_len); + dfs_info = &dfs_nol_info; + kfree(dfs_info->dfs_nol_info); + + dfs_info->dfs_nol_info = temp; + dfs_info->dfs_nol_info_len = info_len; + mutex_unlock(&dfs_nol_info_lock); + + return 0; +} +EXPORT_SYMBOL(icnss_wlan_set_dfs_nol); + +int icnss_wlan_get_dfs_nol(void *info, u16 info_len) +{ + int len; + struct icnss_dfs_nol_info *dfs_info; + + mutex_lock(&dfs_nol_info_lock); + if (!info || !info_len) { + mutex_unlock(&dfs_nol_info_lock); + return -EINVAL; + } + + dfs_info = &dfs_nol_info; + + if (dfs_info->dfs_nol_info == NULL || + dfs_info->dfs_nol_info_len == 0) { + mutex_unlock(&dfs_nol_info_lock); + return -ENOENT; + } + + len = min(info_len, dfs_info->dfs_nol_info_len); + + memcpy(info, dfs_info->dfs_nol_info, len); + mutex_unlock(&dfs_nol_info_lock); + + return len; +} +EXPORT_SYMBOL(icnss_wlan_get_dfs_nol); diff --git a/drivers/soc/qcom/irq-helper.c b/drivers/soc/qcom/irq-helper.c index 7bb371f7991e..370801291230 100644 --- a/drivers/soc/qcom/irq-helper.c +++ b/drivers/soc/qcom/irq-helper.c @@ -78,10 +78,12 @@ IRQ_HELPER_ATTR(irq_blacklist_on, 0444, show_deploy, NULL); static struct irq_helper *irq_h; +/* Do not call this API in an atomic context */ int irq_blacklist_on(void) { bool flag = false; + might_sleep(); if (!irq_h) { pr_err("%s: init function is not called", __func__); return -EPERM; @@ -103,10 +105,12 @@ int irq_blacklist_on(void) } EXPORT_SYMBOL(irq_blacklist_on); +/* Do not call this API in an atomic context */ int irq_blacklist_off(void) { bool flag = false; + might_sleep(); if (!irq_h) { pr_err("%s: init function is not called", __func__); return -EPERM; diff --git a/drivers/soc/qcom/remoteqdss.c b/drivers/soc/qcom/remoteqdss.c index e66ca587adca..5e2a5babdcc8 100644 --- a/drivers/soc/qcom/remoteqdss.c +++ b/drivers/soc/qcom/remoteqdss.c @@ -28,8 +28,8 @@ static struct dentry *remoteqdss_dir; #define REMOTEQDSS_ERR(fmt, ...) \ pr_debug("%s: " fmt, __func__, ## __VA_ARGS__) -#define REMOTEQDSS_ERR_CALLER(fmt, ...) \ - pr_debug("%pf: " fmt, __builtin_return_address(1), ## __VA_ARGS__) +#define REMOTEQDSS_ERR_CALLER(fmt, caller, ...) \ + pr_debug("%pf: " fmt, caller, ## __VA_ARGS__) struct qdss_msg_translation { u64 val; @@ -97,7 +97,7 @@ struct remoteqdss_query_swentity_fmt { /* msgs is a null terminated array */ static void remoteqdss_err_translation(struct qdss_msg_translation *msgs, - u64 err) + u64 err, const void *caller) { static DEFINE_RATELIMIT_STATE(rl, 5 * HZ, 2); struct qdss_msg_translation *msg; @@ -110,12 +110,13 @@ static void remoteqdss_err_translation(struct qdss_msg_translation *msgs, for (msg = msgs; msg->msg; msg++) { if (err == msg->val && __ratelimit(&rl)) { - REMOTEQDSS_ERR_CALLER("0x%llx: %s\n", err, msg->msg); + REMOTEQDSS_ERR_CALLER("0x%llx: %s\n", caller, err, + msg->msg); return; } } - REMOTEQDSS_ERR_CALLER("Error 0x%llx\n", err); + REMOTEQDSS_ERR_CALLER("Error 0x%llx\n", caller, err); } /* Shared across all remoteqdss scm functions */ @@ -160,7 +161,7 @@ static void free_remoteqdss_data(struct remoteqdss_data *data) } static int remoteqdss_do_scm_call(struct scm_desc *desc, - dma_addr_t addr, size_t size) + dma_addr_t addr, size_t size, const void *caller) { int ret; @@ -175,7 +176,7 @@ static int remoteqdss_do_scm_call(struct scm_desc *desc, if (ret) return ret; - remoteqdss_err_translation(remoteqdss_scm_msgs, desc->ret[0]); + remoteqdss_err_translation(remoteqdss_scm_msgs, desc->ret[0], caller); ret = desc->ret[0] ? -EINVAL : 0; return ret; } @@ -194,7 +195,8 @@ static int remoteqdss_scm_query_swtrace(void *priv, u64 *val) fmt->subsys_id = data->id; fmt->cmd_id = CMD_ID_QUERY_SWTRACE_STATE; - ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt)); + ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt), + __builtin_return_address(0)); *val = desc.ret[1]; dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr); @@ -216,7 +218,8 @@ static int remoteqdss_scm_filter_swtrace(void *priv, u64 val) fmt->h.cmd_id = CMD_ID_FILTER_SWTRACE_STATE; fmt->state = (uint32_t)val; - ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt)); + ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt), + __builtin_return_address(0)); dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr); return ret; @@ -241,7 +244,8 @@ static int remoteqdss_scm_query_tag(void *priv, u64 *val) fmt->subsys_id = data->id; fmt->cmd_id = CMD_ID_QUERY_SWEVENT_TAG; - ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt)); + ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt), + __builtin_return_address(0)); *val = desc.ret[1]; dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr); @@ -268,7 +272,8 @@ static int remoteqdss_scm_query_swevent(void *priv, u64 *val) fmt->h.cmd_id = CMD_ID_QUERY_SWEVENT; fmt->event_group = data->sw_event_group; - ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt)); + ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt), + __builtin_return_address(0)); *val = desc.ret[1]; dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr); @@ -291,7 +296,8 @@ static int remoteqdss_scm_filter_swevent(void *priv, u64 val) fmt->event_group = data->sw_event_group; fmt->event_mask = (uint32_t)val; - ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt)); + ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt), + __builtin_return_address(0)); dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr); return ret; @@ -317,7 +323,8 @@ static int remoteqdss_scm_query_swentity(void *priv, u64 *val) fmt->h.cmd_id = CMD_ID_QUERY_SWENTITY; fmt->entity_group = data->sw_entity_group; - ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt)); + ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt), + __builtin_return_address(0)); *val = desc.ret[1]; dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr); @@ -340,7 +347,8 @@ static int remoteqdss_scm_filter_swentity(void *priv, u64 val) fmt->entity_group = data->sw_entity_group; fmt->entity_mask = (uint32_t)val; - ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt)); + ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt), + __builtin_return_address(0)); dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr); return ret; diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 5eaf2db32d21..03a1591e5b09 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -795,45 +795,23 @@ static int msm_rpm_read_sleep_ack(void) { int ret; char buf[MAX_ERR_BUFFER_SIZE] = {0}; - uint32_t msg_id; if (glink_enabled) ret = msm_rpm_glink_rx_poll(glink_data->glink_handle); else { ret = msm_rpm_read_smd_data(buf); - if (!ret) { - /* - * Mimic Glink behavior to ensure that the - * data is read and the msg is removed from - * the wait list. We should have gotten here - * only when there are no drivers waiting on - * ACKs. msm_rpm_get_entry_from_msg_id() - * return non-NULL only then. - */ - msg_id = msm_rpm_get_msg_id_from_ack(buf); - msm_rpm_process_ack(msg_id, 0); + if (!ret) ret = smd_is_pkt_avail(msm_rpm_data.ch_info); - } } return ret; } -static void msm_rpm_flush_noack_messages(void) -{ - while (!list_empty(&msm_rpm_wait_list)) { - if (!msm_rpm_read_sleep_ack()) - break; - } -} - static int msm_rpm_flush_requests(bool print) { struct rb_node *t; int ret; int count = 0; - msm_rpm_flush_noack_messages(); - for (t = rb_first(&tr_root); t; t = rb_next(t)) { struct slp_buf *s = rb_entry(t, struct slp_buf, node); @@ -1102,18 +1080,14 @@ static void msm_rpm_notify(void *data, unsigned event) bool msm_rpm_waiting_for_ack(void) { - bool ret = false; + bool ret; unsigned long flags; - struct msm_rpm_wait_data *elem = NULL; spin_lock_irqsave(&msm_rpm_list_lock, flags); - elem = list_first_entry_or_null(&msm_rpm_wait_list, - struct msm_rpm_wait_data, list); - if (elem) - ret = !elem->delete_on_ack; + ret = list_empty(&msm_rpm_wait_list); spin_unlock_irqrestore(&msm_rpm_list_lock, flags); - return ret; + return !ret; } static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 23e32214756a..ea4f557fcd70 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -538,6 +538,9 @@ static struct msm_soc_info cpu_of_id[] = { /* falcon ID */ [317] = {MSM_CPU_FALCON, "MSMFALCON"}, + /* triton ID */ + [318] = {MSM_CPU_TRITON, "MSMTRITON"}, + /* Uninitialized IDs are not known to run Linux. MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are considered as unknown CPU. */ @@ -1207,6 +1210,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 317; strlcpy(dummy_socinfo.build_id, "msmfalcon - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_msmtriton()) { + dummy_socinfo.id = 318; + strlcpy(dummy_socinfo.build_id, "msmtriton - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_apqcobalt()) { dummy_socinfo.id = 319; strlcpy(dummy_socinfo.build_id, "apqcobalt - ", diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 0ed8a6533e00..76d941ceb77e 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -746,6 +746,28 @@ static void subsys_stop(struct subsys_device *subsys) notify_each_subsys_device(&subsys, 1, SUBSYS_AFTER_SHUTDOWN, NULL); } +int subsystem_set_fwname(const char *name, const char *fw_name) +{ + struct subsys_device *subsys; + + if (!name) + return -EINVAL; + + if (!fw_name) + return -EINVAL; + + subsys = find_subsys(name); + if (!subsys) + return -EINVAL; + + pr_debug("Changing subsys [%s] fw_name to [%s]\n", name, fw_name); + strlcpy(subsys->desc->fw_name, fw_name, + sizeof(subsys->desc->fw_name)); + + return 0; +} +EXPORT_SYMBOL(subsystem_set_fwname); + void *__subsystem_get(const char *name, const char *fw_name) { struct subsys_device *subsys; diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 0bdb3d76cc8d..9fdb06e08d4b 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -198,13 +198,13 @@ struct msm_port { static void msm_write(struct uart_port *port, unsigned int val, unsigned int off) { - writel_relaxed(val, port->membase + off); + writel_relaxed_no_log(val, port->membase + off); } static unsigned int msm_read(struct uart_port *port, unsigned int off) { - return readl_relaxed(port->membase + off); + return readl_relaxed_no_log(port->membase + off); } /* diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 8189096f95c2..83a265f0211e 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -45,6 +45,7 @@ #include <linux/msm-bus.h> #include <linux/irq.h> #include <linux/extcon.h> +#include <linux/reset.h> #include "power.h" #include "core.h" @@ -159,6 +160,7 @@ struct dwc3_msm { struct clk *utmi_clk_src; struct clk *bus_aggr_clk; struct clk *cfg_ahb_clk; + struct reset_control *core_reset; struct regulator *dwc3_gdsc; struct usb_phy *hs_phy, *ss_phy; @@ -1517,19 +1519,19 @@ static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert) clk_disable_unprepare(mdwc->sleep_clk); clk_disable_unprepare(mdwc->core_clk); clk_disable_unprepare(mdwc->iface_clk); - ret = clk_reset(mdwc->core_clk, CLK_RESET_ASSERT); + ret = reset_control_assert(mdwc->core_reset); if (ret) - dev_err(mdwc->dev, "dwc3 core_clk assert failed\n"); + dev_err(mdwc->dev, "dwc3 core_reset assert failed\n"); } else { dev_dbg(mdwc->dev, "block_reset DEASSERT\n"); - ret = clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT); + ret = reset_control_deassert(mdwc->core_reset); + if (ret) + dev_err(mdwc->dev, "dwc3 core_reset deassert failed\n"); ndelay(200); clk_prepare_enable(mdwc->iface_clk); clk_prepare_enable(mdwc->core_clk); clk_prepare_enable(mdwc->sleep_clk); clk_prepare_enable(mdwc->utmi_clk); - if (ret) - dev_err(mdwc->dev, "dwc3 core_clk deassert failed\n"); enable_irq(mdwc->pwr_event_irq); } @@ -2041,11 +2043,16 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) { dev_dbg(mdwc->dev, "%s: exit power collapse\n", __func__); dwc3_msm_config_gdsc(mdwc, 1); - - clk_reset(mdwc->core_clk, CLK_RESET_ASSERT); + ret = reset_control_assert(mdwc->core_reset); + if (ret) + dev_err(mdwc->dev, "%s:core_reset assert failed\n", + __func__); /* HW requires a short delay for reset to take place properly */ usleep_range(1000, 1200); - clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT); + ret = reset_control_deassert(mdwc->core_reset); + if (ret) + dev_err(mdwc->dev, "%s:core_reset deassert failed\n", + __func__); clk_prepare_enable(mdwc->sleep_clk); } @@ -2366,6 +2373,17 @@ static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc) mdwc->core_clk_rate = clk_round_rate(mdwc->core_clk, LONG_MAX); } + mdwc->core_reset = devm_reset_control_get(mdwc->dev, "core_reset"); + if (IS_ERR(mdwc->core_reset)) { + dev_err(mdwc->dev, "failed to get core_reset\n"); + return PTR_ERR(mdwc->core_reset); + } + + /* + * Get Max supported clk frequency for USB Core CLK and request + * to set the same. + */ + mdwc->core_clk_rate = clk_round_rate(mdwc->core_clk, LONG_MAX); if (IS_ERR_VALUE(mdwc->core_clk_rate)) { dev_err(mdwc->dev, "fail to get core clk max freq.\n"); } else { @@ -3191,7 +3209,7 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) { - union power_supply_propval pval = {1000 * mA}; + union power_supply_propval pval = {0}; int ret; if (mdwc->charging_disabled) @@ -3208,9 +3226,14 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) } } + power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_TYPE, &pval); + if (pval.intval != POWER_SUPPLY_TYPE_USB) + return 0; + dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA); /* Set max current limit in uA */ + pval.intval = 1000 * mA; ret = power_supply_set_property(mdwc->usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (ret) { diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 3d17fd93c787..a99405261306 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -27,6 +27,14 @@ #define SSUSB_GADGET_VBUS_DRAW_UNITS 8 #define HSUSB_GADGET_VBUS_DRAW_UNITS 2 +/* + * Based on enumerated USB speed, draw power with set_config and resume + * HSUSB: 500mA, SSUSB: 900mA + */ +#define USB_VBUS_DRAW(speed)\ + (speed == USB_SPEED_SUPER ?\ + SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW) + static bool enable_l1_for_hs; module_param(enable_l1_for_hs, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(enable_l1_for_hs, "Enable support for L1 LPM for HS devices"); @@ -749,7 +757,6 @@ static int set_config(struct usb_composite_dev *cdev, struct usb_gadget *gadget = cdev->gadget; struct usb_configuration *c = NULL; int result = -EINVAL; - unsigned power = gadget_is_otg(gadget) ? 8 : 100; int tmp; /* @@ -863,14 +870,8 @@ static int set_config(struct usb_composite_dev *cdev, } } - /* Allow 900mA to draw with Super-Speed */ - if (gadget->speed == USB_SPEED_SUPER) - power = SSUSB_GADGET_VBUS_DRAW; - else - power = CONFIG_USB_GADGET_VBUS_DRAW; - done: - usb_gadget_vbus_draw(gadget, power); + usb_gadget_vbus_draw(gadget, USB_VBUS_DRAW(gadget->speed)); if (result >= 0 && cdev->delayed_status) result = USB_GADGET_DELAYED_STATUS; return result; @@ -2319,7 +2320,6 @@ void composite_resume(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; - u16 maxpower; int ret; unsigned long flags; @@ -2352,10 +2352,7 @@ void composite_resume(struct usb_gadget *gadget) f->resume(f); } - maxpower = cdev->config->MaxPower; - - usb_gadget_vbus_draw(gadget, maxpower ? - maxpower : CONFIG_USB_GADGET_VBUS_DRAW); + usb_gadget_vbus_draw(gadget, USB_VBUS_DRAW(gadget->speed)); } spin_unlock_irqrestore(&cdev->lock, flags); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index e32348d17b26..80c9928e948e 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -36,6 +36,7 @@ MODULE_PARM_DESC(num_out_bufs, static struct workqueue_struct *ipa_usb_wq; +static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi, enum gsi_ctrl_notify_state); @@ -553,6 +554,7 @@ static void ipa_work_handler(struct work_struct *w) struct device *dev; struct device *gad_dev; struct f_gsi *gsi; + bool block_db; event = read_event(d_port); @@ -665,7 +667,27 @@ static void ipa_work_handler(struct work_struct *w) } break; case STATE_CONNECTED: - if (event == EVT_DISCONNECTED) { + if (event == EVT_DISCONNECTED || event == EVT_HOST_NRDY) { + if (peek_event(d_port) == EVT_HOST_READY) { + read_event(d_port); + log_event_dbg("%s: NO_OP NRDY_RDY", __func__); + break; + } + + if (event == EVT_HOST_NRDY) { + log_event_dbg("%s: ST_CON_HOST_NRDY\n", + __func__); + block_db = true; + /* stop USB ringing doorbell to GSI(OUT_EP) */ + usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, + GSI_EP_OP_SET_CLR_BLOCK_DBL); + gsi_rndis_ipa_reset_trigger(gsi); + usb_gsi_ep_op(d_port->in_ep, NULL, + GSI_EP_OP_ENDXFER); + usb_gsi_ep_op(d_port->out_ep, NULL, + GSI_EP_OP_ENDXFER); + } + ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; usb_gadget_autopm_put_async(d_port->gadget); @@ -1269,7 +1291,7 @@ static void gsi_rndis_open(struct f_gsi *rndis) rndis_signal_connect(rndis->params); } -void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis) +static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis) { unsigned long flags; @@ -1301,12 +1323,11 @@ void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param) d_port = &rndis->d_port; - if (enable) { - gsi_rndis_ipa_reset_trigger(rndis); - usb_gsi_ep_op(d_port->in_ep, NULL, GSI_EP_OP_ENDXFER); - usb_gsi_ep_op(d_port->out_ep, NULL, GSI_EP_OP_ENDXFER); - post_event(d_port, EVT_DISCONNECTED); + if (enable) { + log_event_dbg("%s: posting HOST_NRDY\n", __func__); + post_event(d_port, EVT_HOST_NRDY); } else { + log_event_dbg("%s: posting HOST_READY\n", __func__); post_event(d_port, EVT_HOST_READY); } @@ -1359,6 +1380,12 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi, return -ENODEV; } + if (atomic_inc_return(&gsi->c_port.notify_count) != 1) { + log_event_dbg("delay ep_queue: notify req is busy %d", + atomic_read(&gsi->c_port.notify_count)); + return 0; + } + event = req->buf; switch (state) { @@ -1414,12 +1441,6 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi, log_event_dbg("send Notify type %02x", event->bNotificationType); - if (atomic_inc_return(&gsi->c_port.notify_count) != 1) { - log_event_dbg("delay ep_queue: notify req is busy %d", - atomic_read(&gsi->c_port.notify_count)); - return 0; - } - return queue_notification_request(gsi); } @@ -1469,7 +1490,8 @@ static void gsi_rndis_response_available(void *_rndis) { struct f_gsi *gsi = _rndis; - gsi_ctrl_send_notification(gsi, GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE); + gsi_ctrl_send_notification(gsi, + GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE); } static void gsi_rndis_command_complete(struct usb_ep *ep, @@ -2056,6 +2078,8 @@ static void gsi_suspend(struct usb_function *f) queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); } + log_event_dbg("%s: notify_count = %d\n", + __func__, atomic_read(&gsi->c_port.notify_count)); log_event_dbg("gsi suspended"); } @@ -2080,6 +2104,21 @@ static void gsi_resume(struct usb_function *f) else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; + if (gsi->c_port.notify && !gsi->c_port.notify->desc) + config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); + + log_event_dbg("%s: notify_count = %d\n", + __func__, atomic_read(&gsi->c_port.notify_count)); + + /* Send notification to host for RMNET, RNDIS and MBIM Interface */ + if ((gsi->prot_id == IPA_USB_MBIM || + gsi->prot_id == IPA_USB_RNDIS || + gsi->prot_id == IPA_USB_RMNET) && + (atomic_read(&gsi->c_port.notify_count) >= 1)) { + log_event_dbg("%s: force_queue\n", __func__); + queue_notification_request(gsi); + } + if (!remote_wakeup_allowed) { /* Configure EPs for GSI */ @@ -2110,11 +2149,6 @@ static void gsi_resume(struct usb_function *f) post_event(&gsi->d_port, EVT_RESUMED); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); - - if (gsi->c_port.notify && !gsi->c_port.notify->desc) - config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); - - atomic_set(&gsi->c_port.notify_count, 0); log_event_dbg("%s: completed", __func__); } diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 76b25445c6ad..dd73dfe5dcab 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1014,6 +1014,7 @@ struct net_device *gether_setup_name_default(const char *netname) spin_lock_init(&dev->lock); spin_lock_init(&dev->req_lock); INIT_WORK(&dev->work, eth_work); + INIT_WORK(&dev->rx_work, process_rx_w); INIT_LIST_HEAD(&dev->tx_reqs); INIT_LIST_HEAD(&dev->rx_reqs); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index b011efe189e7..1bb7082be8e6 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1257,8 +1257,11 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PD_ACTIVE, &val); if (pd->current_pr == PR_SRC) { - regulator_disable(pd->vconn); regulator_disable(pd->vbus); + if (pd->vconn_enabled) { + regulator_disable(pd->vconn); + pd->vconn_enabled = false; + } } if (pd->current_dr == DR_UFP) diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index b222c3c5f7b4..4ecdc350fbd4 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -27,6 +27,7 @@ #include <linux/regulator/machine.h> #include <linux/usb/phy.h> #include <linux/usb/msm_hsusb.h> +#include <linux/reset.h> #define QUSB2PHY_PWR_CTRL1 0x210 #define PWR_CTRL1_POWR_DOWN BIT(0) @@ -76,7 +77,7 @@ struct qusb_phy { struct clk *ref_clk_src; struct clk *ref_clk; struct clk *cfg_ahb_clk; - struct clk *phy_reset; + struct reset_control *phy_reset; struct regulator *vdd; struct regulator *vdda33; @@ -370,14 +371,19 @@ static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, static void qusb_phy_host_init(struct usb_phy *phy) { u8 reg; + int ret; struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); dev_dbg(phy->dev, "%s\n", __func__); /* Perform phy reset */ - clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + ret = reset_control_assert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset assert failed\n", __func__); usleep_range(100, 150); - clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + ret = reset_control_deassert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset deassert failed\n", __func__); qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq, qphy->host_init_seq_len, 0); @@ -411,9 +417,13 @@ static int qusb_phy_init(struct usb_phy *phy) qusb_phy_enable_clocks(qphy, true); /* Perform phy reset */ - clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + ret = reset_control_assert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset assert failed\n", __func__); usleep_range(100, 150); - clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + ret = reset_control_deassert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset deassert failed\n", __func__); if (qphy->emulation) { if (qphy->emu_init_seq) @@ -531,6 +541,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); u32 linestate = 0, intr_mask = 0; + int ret; if (qphy->suspended && suspend) { dev_dbg(phy->dev, "%s: USB PHY is already suspended\n", @@ -578,9 +589,15 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) qusb_phy_enable_clocks(qphy, false); } else { /* Cable disconnect case */ - clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + ret = reset_control_assert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset assert failed\n", + __func__); usleep_range(100, 150); - clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + ret = reset_control_deassert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset deassert failed\n", + __func__); /* enable clock bypass */ writel_relaxed(0x90, @@ -622,7 +639,10 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) */ wmb(); - clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + ret = reset_control_deassert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset deassert failed\n", + __func__); qusb_phy_enable_power(qphy, true, true); qusb_phy_enable_clocks(qphy, true); @@ -802,7 +822,7 @@ static int qusb_phy_probe(struct platform_device *pdev) } } - qphy->phy_reset = devm_clk_get(dev, "phy_reset"); + qphy->phy_reset = devm_reset_control_get(dev, "phy_reset"); if (IS_ERR(qphy->phy_reset)) return PTR_ERR(qphy->phy_reset); diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index af7ec03314f5..5456b9e8733b 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -27,6 +27,7 @@ #include <linux/regulator/machine.h> #include <linux/usb/phy.h> #include <linux/usb/msm_hsusb.h> +#include <linux/reset.h> #define QUSB2PHY_PLL_STATUS 0x38 #define QUSB2PHY_PLL_LOCK BIT(5) @@ -112,7 +113,7 @@ struct qusb_phy { struct clk *ref_clk_src; struct clk *ref_clk; struct clk *cfg_ahb_clk; - struct clk *phy_reset; + struct reset_control *phy_reset; struct regulator *vdd; struct regulator *vdda33; @@ -443,9 +444,13 @@ static int qusb_phy_init(struct usb_phy *phy) } /* Perform phy reset */ - clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + ret = reset_control_assert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset assert failed\n", __func__); usleep_range(100, 150); - clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + ret = reset_control_deassert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset deassert failed\n", __func__); if (qphy->emulation) { if (qphy->emu_init_seq) @@ -858,7 +863,7 @@ static int qusb_phy_probe(struct platform_device *pdev) if (IS_ERR(qphy->cfg_ahb_clk)) return PTR_ERR(qphy->cfg_ahb_clk); - qphy->phy_reset = devm_clk_get(dev, "phy_reset"); + qphy->phy_reset = devm_reset_control_get(dev, "phy_reset"); if (IS_ERR(qphy->phy_reset)) return PTR_ERR(qphy->phy_reset); @@ -1011,8 +1016,11 @@ static int qusb_phy_probe(struct platform_device *pdev) * not used, there is leakage current seen with QUSB PHY related voltage * rail. Hence keep QUSB PHY into reset state explicitly here. */ - if (hold_phy_reset) - clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + if (hold_phy_reset) { + ret = reset_control_assert(qphy->phy_reset); + if (ret) + dev_err(dev, "%s:phy_reset assert failed\n", __func__); + } ret = usb_add_phy_dev(&qphy->phy); if (ret) diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 87235a5a4f99..fc61e3172d0b 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -25,6 +25,7 @@ #include <linux/usb/msm_hsusb.h> #include <linux/clk.h> #include <linux/clk/msm-clk.h> +#include <linux/reset.h> enum core_ldo_levels { CORE_LEVEL_NONE = 0, @@ -87,9 +88,10 @@ struct msm_ssphy_qmp { struct clk *aux_clk; struct clk *cfg_ahb_clk; struct clk *pipe_clk; - struct clk *phy_reset; - struct clk *phy_phy_reset; bool power_enabled; + struct reset_control *phy_reset; + struct reset_control *phy_phy_reset; + bool clk_enabled; bool cable_connected; bool in_suspend; @@ -371,56 +373,39 @@ static int msm_ssphy_qmp_reset(struct usb_phy *uphy) dev_dbg(uphy->dev, "Resetting QMP phy\n"); /* Assert USB3 PHY reset */ - if (phy->phy_phy_reset) { - ret = clk_reset(phy->phy_phy_reset, CLK_RESET_ASSERT); - if (ret) { - dev_err(uphy->dev, "phy_phy reset assert failed\n"); - goto exit; - } - } else { - ret = clk_reset(phy->pipe_clk, CLK_RESET_ASSERT); - if (ret) { - dev_err(uphy->dev, "pipe_clk reset assert failed\n"); - goto exit; - } + ret = reset_control_assert(phy->phy_phy_reset); + if (ret) { + dev_err(uphy->dev, "phy_phy_reset assert failed\n"); + goto exit; } /* Assert USB3 PHY CSR reset */ - ret = clk_reset(phy->phy_reset, CLK_RESET_ASSERT); + ret = reset_control_assert(phy->phy_reset); if (ret) { - dev_err(uphy->dev, "phy_reset clk assert failed\n"); + dev_err(uphy->dev, "phy_reset assert failed\n"); goto deassert_phy_phy_reset; } /* Deassert USB3 PHY CSR reset */ - ret = clk_reset(phy->phy_reset, CLK_RESET_DEASSERT); + ret = reset_control_deassert(phy->phy_reset); if (ret) { - dev_err(uphy->dev, "phy_reset clk deassert failed\n"); + dev_err(uphy->dev, "phy_reset deassert failed\n"); goto deassert_phy_phy_reset; } /* Deassert USB3 PHY reset */ - if (phy->phy_phy_reset) { - ret = clk_reset(phy->phy_phy_reset, CLK_RESET_DEASSERT); - if (ret) { - dev_err(uphy->dev, "phy_phy reset deassert failed\n"); - goto exit; - } - } else { - ret = clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT); - if (ret) { - dev_err(uphy->dev, "pipe_clk reset deassert failed\n"); - goto exit; - } + ret = reset_control_deassert(phy->phy_phy_reset); + if (ret) { + dev_err(uphy->dev, "phy_phy_reset deassert failed\n"); + goto exit; } return 0; deassert_phy_phy_reset: - if (phy->phy_phy_reset) - clk_reset(phy->phy_phy_reset, CLK_RESET_DEASSERT); - else - clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT); + ret = reset_control_deassert(phy->phy_phy_reset); + if (ret) + dev_err(uphy->dev, "phy_phy_reset deassert failed\n"); exit: phy->in_suspend = false; @@ -594,26 +579,18 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) goto err; } - if (of_property_match_string(pdev->dev.of_node, - "clock-names", "phy_reset") >= 0) { - phy->phy_reset = clk_get(&pdev->dev, "phy_reset"); - if (IS_ERR(phy->phy_reset)) { - ret = PTR_ERR(phy->phy_reset); - phy->phy_reset = NULL; - dev_dbg(dev, "failed to get phy_reset\n"); - goto err; - } + phy->phy_reset = devm_reset_control_get(dev, "phy_reset"); + if (IS_ERR(phy->phy_reset)) { + ret = PTR_ERR(phy->phy_reset); + dev_dbg(dev, "failed to get phy_reset\n"); + goto err; } - if (of_property_match_string(pdev->dev.of_node, - "clock-names", "phy_phy_reset") >= 0) { - phy->phy_phy_reset = clk_get(dev, "phy_phy_reset"); - if (IS_ERR(phy->phy_phy_reset)) { - ret = PTR_ERR(phy->phy_phy_reset); - phy->phy_phy_reset = NULL; - dev_dbg(dev, "phy_phy_reset unavailable\n"); - goto err; - } + phy->phy_phy_reset = devm_reset_control_get(dev, "phy_phy_reset"); + if (IS_ERR(phy->phy_phy_reset)) { + ret = PTR_ERR(phy->phy_phy_reset); + dev_dbg(dev, "failed to get phy_phy_reset\n"); + goto err; } of_get_property(dev->of_node, "qcom,qmp-phy-reg-offset", &size); diff --git a/drivers/video/adf/adf_client.c b/drivers/video/adf/adf_client.c index 8061d8e6b9fb..75b2f0b18522 100644 --- a/drivers/video/adf/adf_client.c +++ b/drivers/video/adf/adf_client.c @@ -305,8 +305,10 @@ static int adf_buffer_map(struct adf_device *dev, struct adf_buffer *buf, } done: - if (ret < 0) + if (ret < 0) { adf_buffer_mapping_cleanup(mapping, buf); + memset(mapping, 0, sizeof(*mapping)); + } return ret; } diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index c8b415df4bce..f25a6e185051 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1434,10 +1434,54 @@ static ssize_t mdss_dp_rda_connected(struct device *dev, return ret; } + +static ssize_t mdss_dp_sysfs_wta_s3d_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret, s3d_mode; + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + + if (!dp) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + ret = kstrtoint(buf, 10, &s3d_mode); + if (ret) { + DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, ret); + goto end; + } + + dp->s3d_mode = s3d_mode; + ret = strnlen(buf, PAGE_SIZE); + DEV_DBG("%s: %d\n", __func__, dp->s3d_mode); +end: + return ret; +} + +static ssize_t mdss_dp_sysfs_rda_s3d_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + + if (!dp) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", dp->s3d_mode); + DEV_DBG("%s: '%d'\n", __func__, dp->s3d_mode); + + return ret; +} + static DEVICE_ATTR(connected, S_IRUGO, mdss_dp_rda_connected, NULL); +static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, mdss_dp_sysfs_rda_s3d_mode, + mdss_dp_sysfs_wta_s3d_mode); static struct attribute *mdss_dp_fs_attrs[] = { &dev_attr_connected.attr, + &dev_attr_s3d_mode.attr, NULL, }; diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index b724aa655424..9a8534677c5e 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -404,6 +404,7 @@ struct mdss_dp_drv_pdata { struct mutex pd_msg_mutex; struct mutex hdcp_mutex; bool cable_connected; + u32 s3d_mode; u32 aux_cmd_busy; u32 aux_cmd_i2c; int aux_trans_num; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index fe6ce30d0c89..e8d68059581f 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -27,7 +27,6 @@ #include "mdss_dba_utils.h" #define DT_CMD_HDR 6 -#define MIN_REFRESH_RATE 48 #define DEFAULT_MDP_TRANSFER_TIME 14000 #define VSYNC_DELAY msecs_to_jiffies(17) @@ -1907,10 +1906,10 @@ static int mdss_dsi_set_refresh_rate_range(struct device_node *pan_node, __func__, __LINE__); /* - * Since min refresh rate is not specified when dynamic - * fps is enabled, using minimum as 30 + * If min refresh rate is not specified, set it to the + * default panel refresh rate. */ - pinfo->min_fps = MIN_REFRESH_RATE; + pinfo->min_fps = pinfo->mipi.frame_rate; rc = 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index f35156a2cfcb..cd842cecc945 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1364,6 +1364,7 @@ static void mdss_mdp_memory_retention_enter(void) } } + __mdss_mdp_reg_access_clk_enable(mdata, true); if (mdss_mdp_clk) { clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_MEM); clk_set_flags(mdss_mdp_clk, CLKFLAG_PERIPH_OFF_SET); @@ -1375,6 +1376,7 @@ static void mdss_mdp_memory_retention_enter(void) clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_PERIPH_OFF_SET); clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_NORETAIN_PERIPH); } + __mdss_mdp_reg_access_clk_enable(mdata, false); } static void mdss_mdp_memory_retention_exit(void) @@ -1396,7 +1398,7 @@ static void mdss_mdp_memory_retention_exit(void) } } - + __mdss_mdp_reg_access_clk_enable(mdata, true); if (mdss_mdp_clk) { clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_MEM); clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_PERIPH); @@ -1408,6 +1410,7 @@ static void mdss_mdp_memory_retention_exit(void) clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_RETAIN_PERIPH); clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_PERIPH_OFF_CLEAR); } + __mdss_mdp_reg_access_clk_enable(mdata, false); } /** diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index 1a0835073663..1acac7fd21b2 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -469,3 +469,59 @@ uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size) return size; return 0; } + +/* + * Validate dentries for encrypted directories to make sure we aren't + * potentially caching stale data after a key has been added or + * removed. + */ +static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct inode *dir = d_inode(dentry->d_parent); + struct ext4_crypt_info *ci = EXT4_I(dir)->i_crypt_info; + int dir_has_key, cached_with_key; + + if (!ext4_encrypted_inode(dir)) + return 0; + + if (ci && ci->ci_keyring_key && + (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_DEAD)))) + ci = NULL; + + /* this should eventually be an flag in d_flags */ + cached_with_key = dentry->d_fsdata != NULL; + dir_has_key = (ci != NULL); + + /* + * If the dentry was cached without the key, and it is a + * negative dentry, it might be a valid name. We can't check + * if the key has since been made available due to locking + * reasons, so we fail the validation so ext4_lookup() can do + * this check. + * + * We also fail the validation if the dentry was created with + * the key present, but we no longer have the key, or vice versa. + */ + if ((!cached_with_key && d_is_negative(dentry)) || + (!cached_with_key && dir_has_key) || + (cached_with_key && !dir_has_key)) { +#if 0 /* Revalidation debug */ + char buf[80]; + char *cp = simple_dname(dentry, buf, sizeof(buf)); + + if (IS_ERR(cp)) + cp = (char *) "???"; + pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata, + cached_with_key, d_is_negative(dentry), + dir_has_key); +#endif + return 0; + } + return 1; +} + +const struct dentry_operations ext4_encrypted_d_ops = { + .d_revalidate = ext4_d_revalidate, +}; diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 1d1bca74f844..33f5e2a50cf8 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -111,6 +111,12 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) int dir_has_error = 0; struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; + if (ext4_encrypted_inode(inode)) { + err = ext4_get_encryption_info(inode); + if (err && err != -ENOKEY) + return err; + } + if (is_dx_dir(inode)) { err = ext4_dx_readdir(file, ctx); if (err != ERR_BAD_DX_DIR) { @@ -157,8 +163,11 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) index, 1); file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; bh = ext4_bread(NULL, inode, map.m_lblk, 0); - if (IS_ERR(bh)) - return PTR_ERR(bh); + if (IS_ERR(bh)) { + err = PTR_ERR(bh); + bh = NULL; + goto errout; + } } if (!bh) { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 614b79c4576e..c1b4f6ab2148 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2258,6 +2258,7 @@ struct page *ext4_encrypt(struct inode *inode, struct page *plaintext_page); int ext4_decrypt(struct page *page); int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex); +extern const struct dentry_operations ext4_encrypted_d_ops; #ifdef CONFIG_EXT4_FS_ENCRYPTION int ext4_init_crypto(void); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 06c3afcbfac8..c9aad3b8951f 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1558,6 +1558,24 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi struct ext4_dir_entry_2 *de; struct buffer_head *bh; + if (ext4_encrypted_inode(dir)) { + int res = ext4_get_encryption_info(dir); + + /* + * This should be a properly defined flag for + * dentry->d_flags when we uplift this to the VFS. + * d_fsdata is set to (void *) 1 if if the dentry is + * created while the directory was encrypted and we + * don't have access to the key. + */ + dentry->d_fsdata = NULL; + if (ext4_encryption_info(dir)) + dentry->d_fsdata = (void *) 1; + d_set_d_op(dentry, &ext4_encrypted_d_ops); + if (res && res != -ENOKEY) + return ERR_PTR(res); + } + if (dentry->d_name.len > EXT4_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 6b6b3e751f8c..06fd5f7f993d 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -232,6 +232,27 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) return error; } +static int +__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, + void *end, const char *function, unsigned int line) +{ + struct ext4_xattr_entry *entry = IFIRST(header); + int error = -EFSCORRUPTED; + + if (((void *) header >= end) || + (header->h_magic != le32_to_cpu(EXT4_XATTR_MAGIC))) + goto errout; + error = ext4_xattr_check_names(entry, end, entry); +errout: + if (error) + __ext4_error_inode(inode, function, line, 0, + "corrupted in-inode xattr"); + return error; +} + +#define xattr_check_inode(inode, header, end) \ + __xattr_check_inode((inode), (header), (end), __func__, __LINE__) + static inline int ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size) { @@ -343,7 +364,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, header = IHDR(inode, raw_inode); entry = IFIRST(header); end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = ext4_xattr_check_names(entry, end, entry); + error = xattr_check_inode(inode, header, end); if (error) goto cleanup; error = ext4_xattr_find_entry(&entry, name_index, name, @@ -474,7 +495,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) raw_inode = ext4_raw_inode(&iloc); header = IHDR(inode, raw_inode); end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header)); + error = xattr_check_inode(inode, header, end); if (error) goto cleanup; error = ext4_xattr_list_entries(dentry, IFIRST(header), @@ -990,8 +1011,7 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, is->s.here = is->s.first; is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { - error = ext4_xattr_check_names(IFIRST(header), is->s.end, - IFIRST(header)); + error = xattr_check_inode(inode, header, is->s.end); if (error) return error; /* Find the named attribute. */ @@ -1288,6 +1308,10 @@ retry: last = entry; total_ino = sizeof(struct ext4_xattr_ibody_header); + error = xattr_check_inode(inode, header, end); + if (error) + goto cleanup; + free = ext4_xattr_free_space(last, &min_offs, base, &total_ino); if (free >= new_extra_isize) { entry = IFIRST(header); diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h index f366d526c138..31c4537ea964 100644 --- a/include/dt-bindings/clock/msm-clocks-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-cobalt.h @@ -494,6 +494,7 @@ #define clk_sys_apcsaux_clk_gcc 0xf905e862 #define clk_xo_ao 0x428c856d #define clk_osm_clk_src 0xaabe68c3 +#define clk_cpu_debug_mux 0x3ae8bcb2 /* Audio External Clocks */ #define clk_audio_ap_clk 0x9b5727cb diff --git a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h index aafa76cb569d..64e2dc7183f3 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h @@ -89,15 +89,30 @@ #define PMA8084_GPIO_S4 2 #define PMA8084_GPIO_L6 3 +/* ATEST MUX selection for analog-pass-through mode */ +#define PMIC_GPIO_AOUT_ATEST1 0 +#define PMIC_GPIO_AOUT_ATEST2 1 +#define PMIC_GPIO_AOUT_ATEST3 2 +#define PMIC_GPIO_AOUT_ATEST4 3 + +/* DTEST buffer for digital input mode */ +#define PMIC_GPIO_DIN_DTEST1 0 +#define PMIC_GPIO_DIN_DTEST2 1 +#define PMIC_GPIO_DIN_DTEST3 2 +#define PMIC_GPIO_DIN_DTEST4 3 + /* To be used with "function" */ #define PMIC_GPIO_FUNC_NORMAL "normal" #define PMIC_GPIO_FUNC_PAIRED "paired" #define PMIC_GPIO_FUNC_FUNC1 "func1" #define PMIC_GPIO_FUNC_FUNC2 "func2" +#define PMIC_GPIO_FUNC_FUNC3 "func3" +#define PMIC_GPIO_FUNC_FUNC4 "func4" #define PMIC_GPIO_FUNC_DTEST1 "dtest1" #define PMIC_GPIO_FUNC_DTEST2 "dtest2" #define PMIC_GPIO_FUNC_DTEST3 "dtest3" #define PMIC_GPIO_FUNC_DTEST4 "dtest4" +#define PMIC_GPIO_FUNC_ANALOG "analog" #define PM8038_GPIO1_2_LPG_DRV PMIC_GPIO_FUNC_FUNC1 #define PM8038_GPIO3_5V_BOOST_EN PMIC_GPIO_FUNC_FUNC1 diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h index 3825f9d1e68c..ad95957d9189 100644 --- a/include/linux/input/ft5x06_ts.h +++ b/include/linux/input/ft5x06_ts.h @@ -69,6 +69,7 @@ struct ft5x06_ts_platform_data { bool i2c_pull_up; bool ignore_id_check; bool gesture_support; + bool resume_in_workqueue; int (*power_init)(bool); int (*power_on)(bool); }; diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h index 75908dfa8d64..f595275e9d42 100644 --- a/include/linux/mfd/wcd9xxx/core.h +++ b/include/linux/mfd/wcd9xxx/core.h @@ -204,6 +204,7 @@ struct wcd9xxx_core_resource { void *parent; struct device *dev; + struct irq_domain *domain; }; /* diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index dc777be5f2e1..6abd019c76f8 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -51,6 +51,7 @@ extern void arch_setup_pdev_archdata(struct platform_device *); extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int); extern int platform_get_irq(struct platform_device *, unsigned int); +extern int platform_irq_count(struct platform_device *); extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 56e78254286e..03853d956b41 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -176,6 +176,8 @@ enum power_supply_property { POWER_SUPPLY_PROP_USB_OTG, POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED, POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_STEP_CHARGING_STEP, POWER_SUPPLY_PROP_PIN_ENABLED, POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, diff --git a/include/linux/sched.h b/include/linux/sched.h index 74b2a11b1d1c..4701e0403167 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -336,8 +336,6 @@ enum migrate_types { GROUP_TO_GROUP, }; -extern const char *migrate_type_names[]; - #include <linux/spinlock.h> /* diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 73b0fbe034fb..801315d1d405 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -65,6 +65,8 @@ struct wiphy; #define CFG80211_SCAN_BSSID 1 #define CFG80211_CONNECT_PREV_BSSID 1 +#define CFG80211_CONNECT_BSS 1 +#define CFG80211_ABORT_SCAN 1 /* * wireless hardware capability structures @@ -2334,6 +2336,8 @@ struct cfg80211_qos_map { * the driver, and will be valid until passed to cfg80211_scan_done(). * For scan results, call cfg80211_inform_bss(); you can call this outside * the scan/scan_done bracket too. + * @abort_scan: Tell the driver to abort an ongoing scan. The driver shall + * indicate the status of the scan through cfg80211_scan_done(). * * @auth: Request to authenticate with the specified peer * (invoked with the wireless_dev mutex held) @@ -2606,6 +2610,7 @@ struct cfg80211_ops { int (*scan)(struct wiphy *wiphy, struct cfg80211_scan_request *request); + void (*abort_scan)(struct wiphy *wiphy, struct wireless_dev *wdev); int (*auth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req); @@ -4668,6 +4673,32 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) #endif /** + * cfg80211_connect_bss - notify cfg80211 of connection result + * + * @dev: network device + * @bssid: the BSSID of the AP + * @bss: entry of bss to which STA got connected to, can be obtained + * through cfg80211_get_bss (may be %NULL) + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @status: status code, 0 for successful connection, use + * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you + * the real status code for failures. + * @gfp: allocation flags + * + * It should be called by the underlying driver whenever connect() has + * succeeded. This is similar to cfg80211_connect_result(), but with the + * option of identifying the exact bss entry for the connection. Only one of + * these functions should be called. + */ +void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp); + +/** * cfg80211_connect_result - notify cfg80211 of connection result * * @dev: network device @@ -4684,10 +4715,15 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) * It should be called by the underlying driver whenever connect() has * succeeded. */ -void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, - const u8 *req_ie, size_t req_ie_len, - const u8 *resp_ie, size_t resp_ie_len, - u16 status, gfp_t gfp); +static inline void +cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp) +{ + cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie, + resp_ie_len, status, gfp); +} /** * cfg80211_roamed - notify cfg80211 of roaming diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 62f1ff65f273..8b64bf3b8de9 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -109,5 +109,10 @@ extern int icnss_power_off(struct device *dev); extern struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev); extern int icnss_smmu_map(struct device *dev, phys_addr_t paddr, uint32_t *iova_addr, size_t size); +extern int icnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count); +extern int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count, + u16 buf_len); +extern int icnss_wlan_set_dfs_nol(const void *info, u16 info_len); +extern int icnss_wlan_get_dfs_nol(void *info, u16 info_len); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 82672bba7c17..76555ce53d97 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -96,6 +96,8 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmhamster") #define early_machine_is_msmfalcon() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmfalcon") +#define early_machine_is_msmtriton() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmtriton") #else #define of_board_is_sim() 0 #define of_board_is_rumi() 0 @@ -133,6 +135,7 @@ #define early_machine_is_apqcobalt() 0 #define early_machine_is_msmhamster() 0 #define early_machine_is_msmfalcon() 0 +#define early_machine_is_msmtriton() 0 #endif #define PLATFORM_SUBTYPE_MDM 1 @@ -192,6 +195,7 @@ enum msm_cpu { MSM_CPU_COBALT, MSM_CPU_HAMSTER, MSM_CPU_FALCON, + MSM_CPU_TRITON, }; struct msm_soc_info { diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index 3a5f6e678b4f..780666c332e2 100644 --- a/include/soc/qcom/subsystem_restart.h +++ b/include/soc/qcom/subsystem_restart.h @@ -113,6 +113,7 @@ extern int subsystem_crashed(const char *name); extern void *subsystem_get(const char *name); extern void *subsystem_get_with_fwname(const char *name, const char *fw_name); +extern int subsystem_set_fwname(const char *name, const char *fw_name); extern void subsystem_put(void *subsystem); extern struct subsys_device *subsys_register(struct subsys_desc *desc); @@ -157,6 +158,11 @@ static inline void *subsystem_get_with_fwname(const char *name, return NULL; } +static inline int subsystem_set_fwname(const char *name, + const char *fw_name) { + return 0; +} + static inline void subsystem_put(void *subsystem) { } static inline diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 695e33f4d1cf..636ae899c304 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -804,6 +804,7 @@ struct adm_cmd_connect_afe_port_v5 { #define INT_FM_TX 0x3005 #define RT_PROXY_PORT_001_RX 0x2000 #define RT_PROXY_PORT_001_TX 0x2001 +#define DISPLAY_PORT_RX 0x6020 #define AFE_PORT_INVALID 0xFFFF #define SLIMBUS_INVALID AFE_PORT_INVALID @@ -953,6 +954,8 @@ struct adm_cmd_connect_afe_port_v5 { #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_RX 0x4010 /* SLIMbus Tx port on channel 8. */ #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_TX 0x4011 +/* AFE Rx port for audio over Display port */ +#define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020 /*USB AFE port */ #define AFE_PORT_ID_USB_RX 0x7000 #define AFE_PORT_ID_USB_TX 0x7001 diff --git a/include/sound/pcm.h b/include/sound/pcm.h index e1f4920053ed..2b6e8f8240d9 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -141,7 +141,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */ #define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */ #define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */ -#define SNDRV_PCM_RATE_384000 (1<<13) /* 384000Hz */ +#define SNDRV_PCM_RATE_352800 (1<<13) /* 352800Hz */ +#define SNDRV_PCM_RATE_384000 (1<<14) /* 384000Hz */ #define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */ #define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */ @@ -154,6 +155,9 @@ struct snd_pcm_ops { SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000) #define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\ SNDRV_PCM_RATE_192000) +#define SNDRV_PCM_RATE_8000_384000 (SNDRV_PCM_RATE_8000_192000|\ + SNDRV_PCM_RATE_352800|\ + SNDRV_PCM_RATE_384000) #define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt) #define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8) #define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8) diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h index 6be903a4c8d0..b252463b72a2 100644 --- a/include/sound/q6afe-v2.h +++ b/include/sound/q6afe-v2.h @@ -173,14 +173,16 @@ enum { IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_6, IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_7, IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_7, - /* IDX 118->122 */ + /* IDX 118->121 */ IDX_SLIMBUS_7_RX, IDX_SLIMBUS_7_TX, IDX_SLIMBUS_8_RX, IDX_SLIMBUS_8_TX, - /* IDX 123-> 124 */ + /* IDX 122-> 123 */ IDX_AFE_PORT_ID_USB_RX, IDX_AFE_PORT_ID_USB_TX, + /* IDX 124 */ + IDX_DISPLAY_PORT_RX, AFE_MAX_PORTS }; diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index f35630045c2f..1ef5ec3eaf70 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -9,9 +9,6 @@ #include <linux/binfmts.h> struct rq; -struct group_cpu_time; -struct migration_sum_data; -extern const char *task_event_names[]; /* * Tracepoint for calling kthread_stop, performed to end a kthread: @@ -113,6 +110,11 @@ TRACE_EVENT(sched_enq_deq_task, #ifdef CONFIG_SCHED_HMP +struct group_cpu_time; +struct migration_sum_data; +extern const char *task_event_names[]; +extern const char *migrate_type_names[]; + TRACE_EVENT(sched_task_load, TP_PROTO(struct task_struct *p, bool boost, int reason, diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index 95ca6e841212..b2e3c3b91f72 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -52,24 +52,29 @@ TRACE_EVENT(consume_skb, TRACE_EVENT(print_skb_gso, - TP_PROTO(struct sk_buff *skb), + TP_PROTO(struct sk_buff *skb, __be16 src, __be16 dest), - TP_ARGS(skb), + TP_ARGS(skb, src, dest), TP_STRUCT__entry( __field(void *, skbaddr) __field(int , len) __field(int , data_len) + __field(__be16, src) + __field(__be16, dest) ), TP_fast_assign( __entry->skbaddr = skb; __entry->len = skb->len; __entry->data_len = skb->data_len; + __entry->src = src; + __entry->dest = dest; ), - TP_printk("GSO: skbaddr=%p, len=%d, data_len=%d", - __entry->skbaddr, __entry->len, __entry->data_len) + TP_printk("GSO: skbaddr=%pK, len=%d, data_len=%d, src=%u, dest=%u", + __entry->skbaddr, __entry->len, __entry->data_len, + be16_to_cpu(__entry->src), be16_to_cpu(__entry->dest)) ); TRACE_EVENT(skb_copy_datagram_iovec, diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c4984741be61..5305e8f4fce1 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -822,6 +822,10 @@ * as an event to indicate changes for devices with wiphy-specific regdom * management. * + * @NL80211_CMD_ABORT_SCAN: Stop an ongoing scan. Returns -ENOENT if a scan is + * not running. The driver indicates the status of the scan through + * cfg80211_scan_done(). + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1008,6 +1012,8 @@ enum nl80211_commands { NL80211_CMD_WIPHY_REG_CHANGE, + NL80211_CMD_ABORT_SCAN, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index 82e0bdd9209d..cdb85170919a 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -18,6 +18,9 @@ #define ISP_META_CHANNEL_BIT (0x10000 << 3) #define ISP_SCRATCH_BUF_BIT (0x10000 << 4) #define ISP_OFFLINE_STATS_BIT (0x10000 << 5) +#define ISP_SVHDR_IN_BIT (0x10000 << 6) /* RDI hw stream for SVHDR */ +#define ISP_SVHDR_OUT_BIT (0x10000 << 7) /* SVHDR output bufq stream*/ + #define ISP_STATS_STREAM_BIT 0x80000000 struct msm_vfe_cfg_cmd_list; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index ae54c5bfac1d..7474463b9835 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -90,13 +90,6 @@ #define CREATE_TRACE_POINTS #include <trace/events/sched.h> -const char *task_event_names[] = {"PUT_PREV_TASK", "PICK_NEXT_TASK", - "TASK_WAKE", "TASK_MIGRATE", "TASK_UPDATE", - "IRQ_UPDATE"}; - -const char *migrate_type_names[] = {"GROUP_TO_RQ", "RQ_TO_GROUP", - "RQ_TO_RQ", "GROUP_TO_GROUP"}; - ATOMIC_NOTIFIER_HEAD(load_alert_notifier_head); DEFINE_MUTEX(sched_domains_mutex); diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 447f3880f645..5002619961ce 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -22,6 +22,13 @@ #include <trace/events/sched.h> +const char *task_event_names[] = {"PUT_PREV_TASK", "PICK_NEXT_TASK", + "TASK_WAKE", "TASK_MIGRATE", "TASK_UPDATE", + "IRQ_UPDATE"}; + +const char *migrate_type_names[] = {"GROUP_TO_RQ", "RQ_TO_GROUP", + "RQ_TO_RQ", "GROUP_TO_GROUP"}; + static ktime_t ktime_last; static bool sched_ktime_suspended; @@ -117,7 +124,18 @@ u32 __weak get_freq_max_load(int cpu, u32 freq) return 100; } -DEFINE_PER_CPU(struct freq_max_load *, freq_max_load); +struct freq_max_load_entry { + /* The maximum load which has accounted governor's headroom. */ + u64 hdemand; +}; + +struct freq_max_load { + struct rcu_head rcu; + int length; + struct freq_max_load_entry freqs[0]; +}; + +static DEFINE_PER_CPU(struct freq_max_load *, freq_max_load); static DEFINE_SPINLOCK(freq_max_load_lock); struct cpu_pwr_stats __weak *get_cpu_pwr_stats(void) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index e31334d5f581..ec7721112b05 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -28,19 +28,6 @@ extern atomic_long_t calc_load_tasks; extern void calc_global_load_tick(struct rq *this_rq); -struct freq_max_load_entry { - /* The maximum load which has accounted governor's headroom. */ - u64 hdemand; -}; - -struct freq_max_load { - struct rcu_head rcu; - int length; - struct freq_max_load_entry freqs[0]; -}; - -extern DEFINE_PER_CPU(struct freq_max_load *, freq_max_load); - extern long calc_load_fold_active(struct rq *this_rq); #ifdef CONFIG_SMP diff --git a/net/core/dev.c b/net/core/dev.c index ffd178b5f381..a299c3956daa 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -137,6 +137,8 @@ #include <linux/errqueue.h> #include <linux/hrtimer.h> #include <linux/netfilter_ingress.h> +#include <linux/tcp.h> +#include <net/tcp.h> #include "net-sysfs.h" @@ -2773,7 +2775,10 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device if (netif_needs_gso(skb, features)) { struct sk_buff *segs; - trace_print_skb_gso(skb); + __be16 src_port = tcp_hdr(skb)->source; + __be16 dest_port = tcp_hdr(skb)->dest; + + trace_print_skb_gso(skb, src_port, dest_port); segs = skb_gso_segment(skb, features); if (IS_ERR(segs)) { goto out_kfree_skb; diff --git a/net/wireless/core.h b/net/wireless/core.h index a918fc303d51..05125d092b18 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -213,6 +213,7 @@ struct cfg80211_event { const u8 *resp_ie; size_t req_ie_len; size_t resp_ie_len; + struct cfg80211_bss *bss; u16 status; } cr; struct { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 913843530213..8fae48e01a43 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6459,6 +6459,24 @@ out_free: return ERR_PTR(err); } +static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev = info->user_ptr[1]; + + if (!rdev->ops->abort_scan) + return -EOPNOTSUPP; + + if (rdev->scan_msg) + return 0; + + if (!rdev->scan_req) + return -ENOENT; + + rdev_abort_scan(rdev, wdev); + return 0; +} + static int nl80211_start_sched_scan(struct sk_buff *skb, struct genl_info *info) { @@ -11014,6 +11032,14 @@ static const struct genl_ops nl80211_ops[] = { NL80211_FLAG_NEED_RTNL, }, { + .cmd = NL80211_CMD_ABORT_SCAN, + .doit = nl80211_abort_scan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { .cmd = NL80211_CMD_GET_SCAN, .policy = nl80211_policy, .dumpit = nl80211_dump_scan, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 571aa9424354..966d15247030 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -426,6 +426,14 @@ static inline int rdev_scan(struct cfg80211_registered_device *rdev, return ret; } +static inline void rdev_abort_scan(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + trace_rdev_abort_scan(&rdev->wiphy, wdev); + rdev->ops->abort_scan(&rdev->wiphy, wdev); + trace_rdev_return_void(&rdev->wiphy); +} + static inline int rdev_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_auth_request *req) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 44f420dfa8e3..37d8ab3a71be 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -767,19 +767,32 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, kfree(country_ie); } -void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, - const u8 *req_ie, size_t req_ie_len, - const u8 *resp_ie, size_t resp_ie_len, - u16 status, gfp_t gfp) +/* Consumes bss object one way or another */ +void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_event *ev; unsigned long flags; + if (bss) { + /* Make sure the bss entry provided by the driver is valid. */ + struct cfg80211_internal_bss *ibss = bss_from_pub(bss); + + if (WARN_ON(list_empty(&ibss->list))) { + cfg80211_put_bss(wdev->wiphy, bss); + return; + } + } + ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); - if (!ev) + if (!ev) { + cfg80211_put_bss(wdev->wiphy, bss); return; + } ev->type = EVENT_CONNECT_RESULT; if (bssid) @@ -794,6 +807,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, ev->cr.resp_ie_len = resp_ie_len; memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); } + if (bss) + cfg80211_hold_bss(bss_from_pub(bss)); + ev->cr.bss = bss; ev->cr.status = status; spin_lock_irqsave(&wdev->event_lock, flags); @@ -801,7 +817,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, spin_unlock_irqrestore(&wdev->event_lock, flags); queue_work(cfg80211_wq, &rdev->event_work); } -EXPORT_SYMBOL(cfg80211_connect_result); +EXPORT_SYMBOL(cfg80211_connect_bss); /* Consumes bss object one way or another */ void __cfg80211_roamed(struct wireless_dev *wdev, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index c800ad6dd5dd..ca24294fe463 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2805,6 +2805,10 @@ TRACE_EVENT(cfg80211_ft_event, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) ); +DEFINE_EVENT(wiphy_wdev_evt, rdev_abort_scan, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH diff --git a/net/wireless/util.c b/net/wireless/util.c index a2532f46169d..a5b20d75017e 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -877,7 +877,7 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) ev->cr.resp_ie, ev->cr.resp_ie_len, ev->cr.status, ev->cr.status == WLAN_STATUS_SUCCESS, - NULL); + ev->cr.bss); break; case EVENT_ROAMED: __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie, diff --git a/sound/core/timer.c b/sound/core/timer.c index b982d1b089bd..f420cd8583da 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1121,7 +1121,11 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, mutex_lock(®ister_mutex); list_for_each_entry(timer, &snd_timer_list, device_list) { - if (timer->card && timer->card->shutdown) + if (timer->card == NULL) { + pr_debug("%s: timer->card is NULL\n", __func__); + continue; + } + if (timer->card->shutdown) continue; switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: @@ -1247,6 +1251,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, tu->tstamp = *tstamp; if ((tu->filter & (1 << event)) == 0 || !tu->tread) return; + memset(&r1, 0, sizeof(r1)); r1.event = event; r1.tstamp = *tstamp; r1.val = resolution; @@ -1281,6 +1286,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, } if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { + memset(&r1, 0, sizeof(r1)); r1.event = SNDRV_TIMER_EVENT_RESOLUTION; r1.tstamp = tstamp; r1.val = resolution; @@ -1746,6 +1752,7 @@ static int snd_timer_user_params(struct file *file, if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->tread) { struct snd_timer_tread tread; + memset(&tread, 0, sizeof(tread)); tread.event = SNDRV_TIMER_EVENT_EARLY; tread.tstamp.tv_sec = 0; tread.tstamp.tv_nsec = 0; diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c index 241410c60b97..dee66f231ceb 100755..100644 --- a/sound/soc/codecs/msm_hdmi_codec_rx.c +++ b/sound/soc/codecs/msm_hdmi_codec_rx.c @@ -19,115 +19,208 @@ #include <sound/soc.h> #include <linux/msm_ext_display.h> -#define MSM_HDMI_PCM_RATES SNDRV_PCM_RATE_48000 +#define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000 -static int msm_hdmi_audio_codec_return_value; +static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"}; -struct msm_hdmi_audio_codec_rx_data { - struct platform_device *hdmi_core_pdev; - struct msm_ext_disp_audio_codec_ops hdmi_ops; +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_type, ext_disp_audio_type_text); + +struct msm_ext_disp_audio_codec_rx_data { + struct platform_device *ext_disp_core_pdev; + struct msm_ext_disp_audio_codec_ops ext_disp_ops; + int cable_status; }; -static int msm_hdmi_edid_ctl_info(struct snd_kcontrol *kcontrol, +static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; struct msm_ext_disp_audio_edid_blk edid_blk; int rc; codec_data = snd_soc_codec_get_drvdata(codec); - if (!codec_data->hdmi_ops.get_audio_edid_blk) { - pr_debug("%s: get_audio_edid_blk() is NULL\n", __func__); + if (!codec_data) { + dev_err(codec->dev, "%s: codec_data is NULL\n", __func__); + return -EINVAL; + } + + if (!codec_data->ext_disp_ops.get_audio_edid_blk) { + dev_dbg(codec->dev, "%s: get_audio_edid_blk() is NULL\n", + __func__); uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = 0; return 0; } - rc = codec_data->hdmi_ops.get_audio_edid_blk( - codec_data->hdmi_core_pdev, - &edid_blk); + rc = codec_data->ext_disp_ops.get_audio_edid_blk( + codec_data->ext_disp_core_pdev, &edid_blk); + if (!IS_ERR_VALUE(rc)) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = edid_blk.audio_data_blk_size + edid_blk.spk_alloc_data_blk_size; } + dev_dbg(codec->dev, "%s: count: %d\n", __func__, uinfo->count); + return rc; } -static int msm_hdmi_edid_get(struct snd_kcontrol *kcontrol, +static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; struct msm_ext_disp_audio_edid_blk edid_blk; int rc; codec_data = snd_soc_codec_get_drvdata(codec); - - if (!codec_data->hdmi_ops.get_audio_edid_blk) + if (!codec_data || !codec_data->ext_disp_ops.get_audio_edid_blk) { + dev_err(codec->dev, "%s: codec_data or get_audio_edid_blk() is NULL\n", + __func__); return -EINVAL; + } - rc = codec_data->hdmi_ops.get_audio_edid_blk( - codec_data->hdmi_core_pdev, &edid_blk); - + rc = codec_data->ext_disp_ops.get_audio_edid_blk( + codec_data->ext_disp_core_pdev, &edid_blk); if (!IS_ERR_VALUE(rc)) { memcpy(ucontrol->value.bytes.data, - edid_blk.audio_data_blk, - edid_blk.audio_data_blk_size); + edid_blk.audio_data_blk, + edid_blk.audio_data_blk_size); memcpy((ucontrol->value.bytes.data + - edid_blk.audio_data_blk_size), - edid_blk.spk_alloc_data_blk, - edid_blk.spk_alloc_data_blk_size); + edid_blk.audio_data_blk_size), + edid_blk.spk_alloc_data_blk, + edid_blk.spk_alloc_data_blk_size); + + dev_dbg(codec->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n", + __func__, edid_blk.audio_data_blk_size, + edid_blk.spk_alloc_data_blk_size); } return rc; } -static const struct snd_kcontrol_new msm_hdmi_codec_rx_controls[] = { +static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + enum msm_ext_disp_cable_state cable_state; + enum msm_ext_disp_type disp_type; + int rc; + + codec_data = snd_soc_codec_get_drvdata(codec); + if (!codec_data || + !codec_data->ext_disp_ops.get_audio_edid_blk || + !codec_data->ext_disp_ops.get_intf_id) { + dev_err(codec->dev, "%s: codec_data, get_audio_edid_blk() or get_intf_id is NULL\n", + __func__); + return -EINVAL; + } + + cable_state = codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 1); + if (IS_ERR_VALUE(cable_state)) { + dev_err(codec->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n", + __func__, cable_state); + rc = cable_state; + goto done; + } + + codec_data->cable_status = cable_state; + if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) { + dev_err(codec->dev, "%s: Display cable disconnected\n", + __func__); + ucontrol->value.integer.value[0] = 0; + rc = 0; + goto done; + } + + disp_type = codec_data->ext_disp_ops.get_intf_id( + codec_data->ext_disp_core_pdev); + if (!IS_ERR_VALUE(disp_type)) { + switch (disp_type) { + case EXT_DISPLAY_TYPE_DP: + ucontrol->value.integer.value[0] = 2; + rc = 0; + break; + case EXT_DISPLAY_TYPE_HDMI: + ucontrol->value.integer.value[0] = 1; + rc = 0; + break; + default: + rc = -EINVAL; + dev_err(codec->dev, "%s: Invalid disp_type:%d\n", + __func__, disp_type); + goto done; + } + dev_dbg(codec->dev, "%s: Display type: %d\n", + __func__, disp_type); + } else { + dev_err(codec->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n", + __func__, disp_type); + rc = disp_type; + } + +done: + return rc; +} + +static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "HDMI EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, + }, { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "HDMI EDID", - .info = msm_hdmi_edid_ctl_info, - .get = msm_hdmi_edid_get, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Display Port EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, }, + SOC_ENUM_EXT("External Display Type", ext_disp_audio_type, + msm_ext_disp_audio_type_get, NULL), }; -static int msm_hdmi_audio_codec_rx_dai_startup( +static int msm_ext_disp_audio_codec_rx_dai_startup( struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int ret = 0; - struct msm_hdmi_audio_codec_rx_data *codec_data = + struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->codec->dev); - if (!codec_data->hdmi_ops.cable_status) { - dev_err(dai->dev, "%s() cable_status is null\n", __func__); + if (!codec_data || !codec_data->ext_disp_ops.cable_status) { + dev_err(dai->dev, "%s() codec_data or cable_status is null\n", + __func__); return -EINVAL; } - msm_hdmi_audio_codec_return_value = - codec_data->hdmi_ops.cable_status( - codec_data->hdmi_core_pdev, 1); - if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) { + codec_data->cable_status = + codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 1); + if (IS_ERR_VALUE(codec_data->cable_status)) { dev_err(dai->dev, - "%s() HDMI core is not ready (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); - ret = msm_hdmi_audio_codec_return_value; - } else if (!msm_hdmi_audio_codec_return_value) { + "%s() ext disp core is not ready (ret val = %d)\n", + __func__, codec_data->cable_status); + ret = codec_data->cable_status; + } else if (!codec_data->cable_status) { dev_err(dai->dev, - "%s() HDMI cable is not connected (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); + "%s() ext disp cable is not connected (ret val = %d)\n", + __func__, codec_data->cable_status); ret = -ENODEV; } return ret; } -static int msm_hdmi_audio_codec_rx_dai_hw_params( +static int msm_ext_disp_audio_codec_rx_dai_hw_params( struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -139,23 +232,24 @@ static int msm_hdmi_audio_codec_rx_dai_hw_params( int rc = 0; struct msm_ext_disp_audio_setup_params audio_setup_params = {0}; - struct msm_hdmi_audio_codec_rx_data *codec_data = + struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->codec->dev); - if (!codec_data->hdmi_ops.audio_info_setup) { - dev_err(dai->dev, "%s() audio_info_setup is null\n", __func__); + if (!codec_data || !codec_data->ext_disp_ops.audio_info_setup) { + dev_err(dai->dev, "%s: codec_data or audio_info_setup is null\n", + __func__); return -EINVAL; } - if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) { + if (IS_ERR_VALUE(codec_data->cable_status)) { dev_err_ratelimited(dai->dev, - "%s() HDMI core is not ready (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); - return msm_hdmi_audio_codec_return_value; - } else if (!msm_hdmi_audio_codec_return_value) { + "%s() ext disp core is not ready (ret val = %d)\n", + __func__, codec_data->cable_status); + return codec_data->cable_status; + } else if (!codec_data->cable_status) { dev_err_ratelimited(dai->dev, - "%s() HDMI cable is not connected (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); + "%s() ext disp cable is not connected (ret val = %d)\n", + __func__, codec_data->cable_status); return -ENODEV; } @@ -204,54 +298,49 @@ static int msm_hdmi_audio_codec_rx_dai_hw_params( audio_setup_params.level_shift = level_shift; audio_setup_params.down_mix = down_mix; - rc = codec_data->hdmi_ops.audio_info_setup( - codec_data->hdmi_core_pdev, &audio_setup_params); + rc = codec_data->ext_disp_ops.audio_info_setup( + codec_data->ext_disp_core_pdev, &audio_setup_params); if (IS_ERR_VALUE(rc)) { dev_err_ratelimited(dai->dev, - "%s() HDMI core is not ready, rc: %d\n", + "%s() ext disp core is not ready, rc: %d\n", __func__, rc); } return rc; } -static void msm_hdmi_audio_codec_rx_dai_shutdown( +static void msm_ext_disp_audio_codec_rx_dai_shutdown( struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int rc; - struct msm_hdmi_audio_codec_rx_data *codec_data = + struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->codec->dev); - if (!codec_data->hdmi_ops.cable_status) { - dev_err(dai->dev, "%s() cable_status is null\n", __func__); + if (!codec_data || !codec_data->ext_disp_ops.cable_status) { + dev_err(dai->dev, "%s: codec data or cable_status is null\n", + __func__); return; } - rc = codec_data->hdmi_ops.cable_status( - codec_data->hdmi_core_pdev, 0); + rc = codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 0); if (IS_ERR_VALUE(rc)) { dev_err(dai->dev, - "%s() HDMI core had problems releasing HDMI audio flag\n", + "%s: ext disp core had problems releasing audio flag\n", __func__); } return; } -static struct snd_soc_dai_ops msm_hdmi_audio_codec_rx_dai_ops = { - .startup = msm_hdmi_audio_codec_rx_dai_startup, - .hw_params = msm_hdmi_audio_codec_rx_dai_hw_params, - .shutdown = msm_hdmi_audio_codec_rx_dai_shutdown -}; - -static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) +static int msm_ext_disp_audio_codec_rx_probe(struct snd_soc_codec *codec) { - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; struct device_node *of_node_parent = NULL; - codec_data = kzalloc(sizeof(struct msm_hdmi_audio_codec_rx_data), + codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data), GFP_KERNEL); if (!codec_data) { @@ -268,16 +357,16 @@ static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) return -ENODEV; } - codec_data->hdmi_core_pdev = of_find_device_by_node(of_node_parent); - if (!codec_data->hdmi_core_pdev) { + codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent); + if (!codec_data->ext_disp_core_pdev) { dev_err(codec->dev, "%s(): can't get parent pdev\n", __func__); kfree(codec_data); return -ENODEV; } - if (msm_hdmi_register_audio_codec(codec_data->hdmi_core_pdev, - &codec_data->hdmi_ops)) { - dev_err(codec->dev, "%s(): can't register with hdmi core", + if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev, + &codec_data->ext_disp_ops)) { + dev_err(codec->dev, "%s(): can't register with ext disp core", __func__); kfree(codec_data); return -ENODEV; @@ -285,15 +374,15 @@ static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) dev_set_drvdata(codec->dev, codec_data); - dev_dbg(codec->dev, "%s(): registerd %s with HDMI core\n", + dev_dbg(codec->dev, "%s(): registered %s with ext disp core\n", __func__, codec->component.name); return 0; } -static int msm_hdmi_audio_codec_rx_remove(struct snd_soc_codec *codec) +static int msm_ext_disp_audio_codec_rx_remove(struct snd_soc_codec *codec) { - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; codec_data = dev_get_drvdata(codec->dev); kfree(codec_data); @@ -301,7 +390,13 @@ static int msm_hdmi_audio_codec_rx_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_dai_driver msm_hdmi_audio_codec_rx_dais[] = { +static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = { + .startup = msm_ext_disp_audio_codec_rx_dai_startup, + .hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params, + .shutdown = msm_ext_disp_audio_codec_rx_dai_shutdown +}; + +static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = { { .name = "msm_hdmi_audio_codec_rx_dai", .playback = { @@ -310,66 +405,89 @@ static struct snd_soc_dai_driver msm_hdmi_audio_codec_rx_dais[] = { .channels_max = 8, .rate_min = 48000, .rate_max = 48000, - .rates = MSM_HDMI_PCM_RATES, + .rates = MSM_EXT_DISP_PCM_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &msm_hdmi_audio_codec_rx_dai_ops, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, + }, + { + .name = "msm_dp_audio_codec_rx_dai", + .playback = { + .stream_name = "Display Port Playback", + .channels_min = 1, + .channels_max = 8, + .rate_min = 48000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, }, }; -static struct snd_soc_codec_driver msm_hdmi_audio_codec_rx_soc_driver = { - .probe = msm_hdmi_audio_codec_rx_probe, - .remove = msm_hdmi_audio_codec_rx_remove, - .controls = msm_hdmi_codec_rx_controls, - .num_controls = ARRAY_SIZE(msm_hdmi_codec_rx_controls), +static struct snd_soc_codec_driver msm_ext_disp_audio_codec_rx_soc_driver = { + .probe = msm_ext_disp_audio_codec_rx_probe, + .remove = msm_ext_disp_audio_codec_rx_remove, + .controls = msm_ext_disp_codec_rx_controls, + .num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls), }; -static int msm_hdmi_audio_codec_rx_plat_probe( +static int msm_ext_disp_audio_codec_rx_plat_probe( struct platform_device *pdev) { dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__, dev_name(&pdev->dev)); return snd_soc_register_codec(&pdev->dev, - &msm_hdmi_audio_codec_rx_soc_driver, - msm_hdmi_audio_codec_rx_dais, - ARRAY_SIZE(msm_hdmi_audio_codec_rx_dais)); + &msm_ext_disp_audio_codec_rx_soc_driver, + msm_ext_disp_audio_codec_rx_dais, + ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais)); } -static int msm_hdmi_audio_codec_rx_plat_remove( +static int msm_ext_disp_audio_codec_rx_plat_remove( struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; } -static const struct of_device_id msm_hdmi_audio_codec_rx_dt_match[] = { - { .compatible = "qcom,msm-hdmi-audio-codec-rx", }, +static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = { + { .compatible = "qcom,msm-ext-disp-audio-codec-rx", }, {} }; -MODULE_DEVICE_TABLE(of, msm_hdmi_codec_dt_match); +MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match); -static struct platform_driver msm_hdmi_audio_codec_rx_driver = { +static struct platform_driver msm_ext_disp_audio_codec_rx_driver = { .driver = { - .name = "msm-hdmi-audio-codec-rx", + .name = "msm-ext-disp-audio-codec-rx", .owner = THIS_MODULE, - .of_match_table = msm_hdmi_audio_codec_rx_dt_match, + .of_match_table = msm_ext_disp_audio_codec_rx_dt_match, }, - .probe = msm_hdmi_audio_codec_rx_plat_probe, - .remove = msm_hdmi_audio_codec_rx_plat_remove, + .probe = msm_ext_disp_audio_codec_rx_plat_probe, + .remove = msm_ext_disp_audio_codec_rx_plat_remove, }; -static int __init msm_hdmi_audio_codec_rx_init(void) +static int __init msm_ext_disp_audio_codec_rx_init(void) { - return platform_driver_register(&msm_hdmi_audio_codec_rx_driver); + int rc; + + rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver); + if (rc) { + pr_err("%s: failed to register ext disp codec driver err:%d\n", + __func__, rc); + } + + return rc; } -module_init(msm_hdmi_audio_codec_rx_init); +module_init(msm_ext_disp_audio_codec_rx_init); -static void __exit msm_hdmi_audio_codec_rx_exit(void) +static void __exit msm_ext_disp_audio_codec_rx_exit(void) { - platform_driver_unregister(&msm_hdmi_audio_codec_rx_driver); + platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver); } -module_exit(msm_hdmi_audio_codec_rx_exit); +module_exit(msm_ext_disp_audio_codec_rx_exit); -MODULE_DESCRIPTION("MSM HDMI CODEC driver"); +MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 60a7ad1b01c2..5b6af14e1d94 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1545,6 +1545,13 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) mbhc->btn_press_intr = false; if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, + false); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, + false); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, + 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); } else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) { wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED); diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 4f855ac62bff..84e5c09494c6 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -2905,6 +2905,56 @@ out: return ret; } +static u32 tavil_get_dmic_sample_rate(struct snd_soc_codec *codec, + unsigned int dmic, + struct wcd9xxx_pdata *pdata) +{ + u8 tx_stream_fs; + u8 adc_mux_index = 0, adc_mux_sel = 0; + bool dec_found = false; + u16 adc_mux_ctl_reg, tx_fs_reg; + u32 dmic_fs; + + while (dec_found == 0 && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) { + if (adc_mux_index < 4) { + adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + (adc_mux_index * 2); + } else if (adc_mux_index < WCD934X_INVALID_ADC_MUX) { + adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_index - 4; + } else if (adc_mux_index == WCD934X_INVALID_ADC_MUX) { + ++adc_mux_index; + continue; + } + adc_mux_sel = ((snd_soc_read(codec, adc_mux_ctl_reg) & + 0xF8) >> 3) - 1; + + if (adc_mux_sel == dmic) { + dec_found = true; + break; + } + + ++adc_mux_index; + } + + if (dec_found && adc_mux_index <= 8) { + tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL + (16 * adc_mux_index); + tx_stream_fs = snd_soc_read(codec, tx_fs_reg) & 0x0F; + if (tx_stream_fs <= 4) { + if (pdata->dmic_sample_rate <= + WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ) + dmic_fs = pdata->dmic_sample_rate; + else + dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ; + } else + dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ; + } else { + dmic_fs = pdata->dmic_sample_rate; + } + + return dmic_fs; +} + static u8 tavil_get_dmic_clk_val(struct snd_soc_codec *codec, u32 mclk_rate, u32 dmic_clk_rate) { @@ -2988,6 +3038,7 @@ static int tavil_codec_enable_dmic(struct snd_soc_dapm_widget *w, s32 *dmic_clk_cnt; u8 dmic_rate_val, dmic_rate_shift = 1; unsigned int dmic; + u32 dmic_sample_rate; int ret; char *wname; @@ -3030,10 +3081,12 @@ static int tavil_codec_enable_dmic(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + dmic_sample_rate = tavil_get_dmic_sample_rate(codec, dmic, + pdata); dmic_rate_val = tavil_get_dmic_clk_val(codec, pdata->mclk_rate, - pdata->dmic_sample_rate); + dmic_sample_rate); (*dmic_clk_cnt)++; if (*dmic_clk_cnt == 1) { @@ -6306,13 +6359,6 @@ static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = { {WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, - {WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, {WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x01, 0x01}, {WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01}, {WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80}, diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c index 615922274690..f1b147aafd84 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.c +++ b/sound/soc/codecs/wcd9xxx-common-v2.c @@ -198,6 +198,11 @@ void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, bool reset) pr_debug("%s, impedance not in range = %d\n", __func__, imped); return; } + if (index >= ARRAY_SIZE(imped_table)) { + pr_debug("%s, impedance index not in range = %d\n", __func__, + index); + return; + } for (i = 0; i < MAX_IMPED_PARAMS; i++) snd_soc_update_bits(codec, imped_table[index][i].reg, imped_table[index][i].mask, diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 0171810803a9..b97b73dc4191 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -90,6 +90,7 @@ struct wsa881x_priv { bool comp_enable; bool boost_enable; bool visense_enable; + u8 pa_gain; struct swr_port port[WSA881X_MAX_SWR_PORTS]; int pd_gpio; struct wsa881x_tz_priv tz_pdata; @@ -134,6 +135,47 @@ static unsigned int devnum; static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec, bool enable); +static const char * const wsa_pa_gain_text[] = { + "G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB", + "G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", + "G_0_DB" +}; + +static const struct soc_enum wsa_pa_gain_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text); + +static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = wsa881x->pa_gain; + + dev_dbg(codec->dev, "%s: PA gain = 0x%x\n", __func__, wsa881x->pa_gain); + + return 0; +} + +static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + wsa881x->pa_gain = ucontrol->value.integer.value[0]; + + return 0; +} + +static const struct snd_kcontrol_new wsa_analog_gain_controls[] = { + SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum, + wsa_pa_gain_get, wsa_pa_gain_put), +}; + static int codec_debug_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -775,6 +817,7 @@ static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + int min_gain, max_gain; dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event); switch (event) { @@ -786,15 +829,32 @@ static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w, swr_slvdev_datapath_control(wsa881x->swr_slave, wsa881x->swr_slave->dev_num, true); + /* Set register mode if compander is not enabled */ + if (!wsa881x->comp_enable) + snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, + 0x08, 0x08); + else + snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, + 0x08, 0x00); + break; case SND_SOC_DAPM_POST_PMU: if (!wsa881x->comp_enable) { + max_gain = wsa881x->pa_gain; + /* + * Gain has to set incrementally in 4 steps + * as per HW sequence + */ + if (max_gain > G_4P5DB) + min_gain = G_0DB; + else + min_gain = max_gain + 3; /* * 1ms delay is needed before change in gain * as per HW requirement. */ usleep_range(1000, 1010); - wsa881x_ramp_pa_gain(codec, G_13P5DB, G_18DB, 1000); + wsa881x_ramp_pa_gain(codec, min_gain, max_gain, 1000); } if (wsa881x->visense_enable) { wsa881x_visense_txfe_ctrl(codec, ENABLE, @@ -987,6 +1047,8 @@ static int wsa881x_probe(struct snd_soc_codec *codec) wsa881x->tz_pdata.codec = codec; wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read; wsa881x_init_thermal(&wsa881x->tz_pdata); + snd_soc_add_codec_controls(codec, wsa_analog_gain_controls, + ARRAY_SIZE(wsa_analog_gain_controls)); INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work); return 0; } diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig index 759716199224..e740a24704b7 100644 --- a/sound/soc/msm/Kconfig +++ b/sound/soc/msm/Kconfig @@ -15,6 +15,7 @@ config SND_SOC_MSM_QDSP6V2_INTF config SND_SOC_QDSP6V2 tristate "SoC ALSA audio driver for QDSP6V2" select SND_SOC_MSM_QDSP6V2_INTF + select SND_SOC_COMPRESS help To add support for MSM QDSP6V2 Soc Audio. This will enable sound soc platform specific diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index 85fa45ff400f..4cb62a6b3e7d 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -25,7 +25,7 @@ static struct snd_soc_dai_ops msm_fe_dai_ops = {}; /* Conventional and unconventional sample rate supported */ static unsigned int supported_sample_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, - 88200, 96000, 176400, 192000 + 88200, 96000, 176400, 192000, 352800, 384000 }; static struct snd_pcm_hw_constraint_list constraints_sample_rates = { @@ -92,7 +92,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia1 Playback", .aif_name = "MM_DL1", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -100,12 +100,12 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia1 Capture", .aif_name = "MM_UL1", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE| @@ -123,7 +123,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia2 Playback", .aif_name = "MM_DL2", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -131,12 +131,12 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia2 Capture", .aif_name = "MM_UL2", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -206,7 +206,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia3 Playback", .aif_name = "MM_DL3", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -214,12 +214,12 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 6, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia3 Capture", .aif_name = "MM_UL3", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), @@ -236,7 +236,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia4 Playback", .aif_name = "MM_DL4", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -244,7 +244,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -255,7 +255,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia5 Playback", .aif_name = "MM_DL5", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -263,7 +263,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia5 Capture", @@ -286,7 +286,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia6 Playback", .aif_name = "MM_DL6", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -294,7 +294,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia6 Capture", @@ -317,7 +317,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia7 Playback", .aif_name = "MM_DL7", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -325,7 +325,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -336,7 +336,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia8 Playback", .aif_name = "MM_DL8", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -344,7 +344,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia8 Capture", @@ -368,13 +368,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS0_HOSTLESS Playback", .aif_name = "SLIM0_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS0_HOSTLESS Capture", @@ -386,7 +386,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SLIMBUS0_HOSTLESS", @@ -396,13 +396,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS1_HOSTLESS Playback", .aif_name = "SLIM1_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS1_HOSTLESS Capture", @@ -423,13 +423,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS3_HOSTLESS Playback", .aif_name = "SLIM3_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS3_HOSTLESS Capture", @@ -450,13 +450,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS4_HOSTLESS Playback", .aif_name = "SLIM4_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS4_HOSTLESS Capture", @@ -477,13 +477,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS6_HOSTLESS Playback", .aif_name = "SLIM6_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SLIMBUS6_HOSTLESS", @@ -493,24 +493,24 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS8_HOSTLESS Playback", .aif_name = "SLIM8_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS8_HOSTLESS Capture", .aif_name = "SLIM8_UL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SLIMBUS8_HOSTLESS", @@ -747,13 +747,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Primary MI2S_RX Hostless Playback", .aif_name = "PRI_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "PRI_MI2S_RX_HOSTLESS", @@ -779,13 +779,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Secondary MI2S_RX Hostless Playback", .aif_name = "SEC_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SEC_MI2S_RX_HOSTLESS", @@ -811,13 +811,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Tertiary MI2S_RX Hostless Playback", .aif_name = "TERT_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "TERT_MI2S_RX_HOSTLESS", @@ -843,13 +843,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Quaternary MI2S_RX Hostless Playback", .aif_name = "QUAT_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "QUAT_MI2S_RX_HOSTLESS", @@ -2016,7 +2016,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia9 Playback", .aif_name = "MM_DL9", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2024,7 +2024,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia9 Capture", @@ -2216,7 +2216,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia10 Playback", .aif_name = "MM_DL10", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2224,7 +2224,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2235,7 +2235,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia11 Playback", .aif_name = "MM_DL11", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2243,7 +2243,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2254,7 +2254,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia12 Playback", .aif_name = "MM_DL12", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2262,7 +2262,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2273,7 +2273,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia13 Playback", .aif_name = "MM_DL13", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2281,7 +2281,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2292,7 +2292,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia14 Playback", .aif_name = "MM_DL14", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2300,7 +2300,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2311,7 +2311,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia15 Playback", .aif_name = "MM_DL15", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2319,7 +2319,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2330,7 +2330,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia16 Playback", .aif_name = "MM_DL16", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2338,7 +2338,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c index b0948acf8a71..523cd1ce4140 100644 --- a/sound/soc/msm/msmcobalt.c +++ b/sound/soc/msm/msmcobalt.c @@ -101,6 +101,12 @@ struct dev_config { u32 channels; }; +enum { + HDMI_RX_IDX = 0, + DP_RX_IDX, + EXT_DISP_RX_IDX_MAX, +}; + struct msm_wsa881x_dev_info { struct device_node *of_node; u32 index; @@ -147,6 +153,13 @@ static struct dev_config slim_tx_cfg[] = { [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, }; + +/* Default configuration of external display BE */ +static struct dev_config ext_disp_rx_cfg[] = { + [HDMI_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [DP_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + static struct dev_config usb_rx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, @@ -159,12 +172,6 @@ static struct dev_config usb_tx_cfg = { .channels = 1, }; -static struct dev_config hdmi_rx_cfg = { - .sample_rate = SAMPLING_RATE_48KHZ, - .bit_format = SNDRV_PCM_FORMAT_S16_LE, - .channels = 2, -}; - static struct dev_config proxy_rx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, @@ -178,6 +185,7 @@ static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four", "Eight"}; static const char *const vi_feed_ch_text[] = {"One", "Two"}; static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"}; static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_88P2", "KHZ_96", "KHZ_176P4", @@ -190,8 +198,8 @@ static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16", "KHZ_22P05", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_96", "KHZ_192"}; -static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", - "KHZ_192"}; +static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192"}; static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text); @@ -202,7 +210,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); -static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_chs, ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text); @@ -210,7 +218,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); -static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_format, ext_disp_bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); @@ -219,7 +227,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); -static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_sample_rate, hdmi_rx_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate, + ext_disp_sample_rate_text); static struct platform_device *spdev; @@ -999,15 +1008,33 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, return rc; } -static int hdmi_rx_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol) { + int idx; - switch (hdmi_rx_cfg.bit_format) { - case SNDRV_PCM_FORMAT_S24_3LE: - ucontrol->value.integer.value[0] = 2; - break; + if (strnstr(kcontrol->id.name, "HDMI_RX", sizeof("HDMI_RX"))) + idx = HDMI_RX_IDX; + else if (strnstr(kcontrol->id.name, "Display Port RX", + sizeof("Display Port RX"))) + idx = DP_RX_IDX; + else { + pr_err("%s: unsupported BE: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} +static int ext_disp_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_disp_rx_cfg[idx].bit_format) { case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 1; break; @@ -1018,66 +1045,79 @@ static int hdmi_rx_format_get(struct snd_kcontrol *kcontrol, break; } - pr_debug("%s: hdmi_rx_cfg = %d, ucontrol value = %ld\n", - __func__, hdmi_rx_cfg.bit_format, + pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_disp_rx_cfg[idx].bit_format, ucontrol->value.integer.value[0]); - return 0; } -static int hdmi_rx_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + switch (ucontrol->value.integer.value[0]) { - case 2: - hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; - break; case 1: - hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE; break; case 0: default: - hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE; break; } - pr_debug("%s: hdmi_rx_cfg.bit_format = %d, ucontrol value = %ld\n", - __func__, hdmi_rx_cfg.bit_format, + pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_disp_rx_cfg[idx].bit_format, ucontrol->value.integer.value[0]); return 0; } -static int hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, - hdmi_rx_cfg.channels); - ucontrol->value.integer.value[0] = hdmi_rx_cfg.channels - 2; + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.integer.value[0] = + ext_disp_rx_cfg[idx].channels - 2; + + pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].channels); return 0; } -static int hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - hdmi_rx_cfg.channels = ucontrol->value.integer.value[0] + 2; - if (hdmi_rx_cfg.channels > 8) { - pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n", - __func__, hdmi_rx_cfg.channels); - hdmi_rx_cfg.channels = 8; - } - pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, - hdmi_rx_cfg.channels); + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ext_disp_rx_cfg[idx].channels = + ucontrol->value.integer.value[0] + 2; + pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].channels); return 1; } -static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int sample_rate_val = 0; + int sample_rate_val; + int idx = ext_disp_get_port_idx(kcontrol); - switch (hdmi_rx_cfg.sample_rate) { + if (idx < 0) + return idx; + + switch (ext_disp_rx_cfg[idx].sample_rate) { case SAMPLING_RATE_192KHZ: sample_rate_val = 2; break; @@ -1093,33 +1133,36 @@ static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, } ucontrol->value.integer.value[0] = sample_rate_val; - pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__, - hdmi_rx_cfg.sample_rate); + pr_debug("%s: ext_disp_rx[%d].sample_rate = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].sample_rate); return 0; } -static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - pr_debug("%s: ucontrol value = %ld\n", __func__, - ucontrol->value.integer.value[0]); + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; switch (ucontrol->value.integer.value[0]) { case 2: - hdmi_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ; break; case 1: - hdmi_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ; break; case 0: default: - hdmi_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ; + break; } - pr_debug("%s: hdmi_rx_cfg.sample_rate = %d\n", __func__, - hdmi_rx_cfg.sample_rate); - + pr_debug("%s: control value = %ld, ext_disp_rx[%d].sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], idx, + ext_disp_rx_cfg[idx].sample_rate); return 0; } @@ -1162,8 +1205,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_ch_get, usb_audio_rx_ch_put), SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs, usb_audio_tx_ch_get, usb_audio_tx_ch_put), - SOC_ENUM_EXT("HDMI_RX Channels", hdmi_rx_chs, - hdmi_rx_ch_get, hdmi_rx_ch_put), + SOC_ENUM_EXT("HDMI_RX Channels", ext_disp_rx_chs, + ext_disp_rx_ch_get, ext_disp_rx_ch_put), + SOC_ENUM_EXT("Display Port RX Channels", ext_disp_rx_chs, + ext_disp_rx_ch_get, ext_disp_rx_ch_put), SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs, proxy_rx_ch_get, proxy_rx_ch_put), SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format, @@ -1178,8 +1223,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_format_get, usb_audio_rx_format_put), SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format, usb_audio_tx_format_get, usb_audio_tx_format_put), - SOC_ENUM_EXT("HDMI_RX Bit Format", hdmi_rx_format, - hdmi_rx_format_get, hdmi_rx_format_put), + SOC_ENUM_EXT("HDMI_RX Bit Format", ext_disp_rx_format, + ext_disp_rx_format_get, ext_disp_rx_format_put), + SOC_ENUM_EXT("Display Port RX Bit Format", ext_disp_rx_format, + ext_disp_rx_format_get, ext_disp_rx_format_put), SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate, @@ -1199,9 +1246,12 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate, usb_audio_tx_sample_rate_get, usb_audio_tx_sample_rate_put), - SOC_ENUM_EXT("HDMI_RX SampleRate", hdmi_rx_sample_rate, - hdmi_rx_sample_rate_get, - hdmi_rx_sample_rate_put), + SOC_ENUM_EXT("HDMI_RX SampleRate", ext_disp_rx_sample_rate, + ext_disp_rx_sample_rate_get, + ext_disp_rx_sample_rate_put), + SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate, + ext_disp_rx_sample_rate_get, + ext_disp_rx_sample_rate_put), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -1324,6 +1374,26 @@ static int msm_slim_get_ch_from_beid(int32_t be_id) return ch_id; } +static int msm_ext_disp_get_idx_from_beid(int32_t be_id) +{ + int idx; + + switch (be_id) { + case MSM_BACKEND_DAI_HDMI_RX: + idx = HDMI_RX_IDX; + break; + case MSM_BACKEND_DAI_DISPLAY_PORT_RX: + idx = DP_RX_IDX; + break; + default: + pr_err("%s: Incorrect ext_disp be_id %d\n", __func__, be_id); + idx = -EINVAL; + break; + } + + return idx; +} + static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -1333,9 +1403,9 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); int rc = 0; + int idx; void *config = NULL; struct snd_soc_codec *codec = NULL; - int ch_num; pr_debug("%s: format = %d, rate = %d\n", __func__, params_format(params), params_rate(params)); @@ -1347,20 +1417,20 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, case MSM_BACKEND_DAI_SLIMBUS_3_RX: case MSM_BACKEND_DAI_SLIMBUS_4_RX: case MSM_BACKEND_DAI_SLIMBUS_6_RX: - ch_num = msm_slim_get_ch_from_beid(dai_link->be_id); + idx = msm_slim_get_ch_from_beid(dai_link->be_id); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - slim_rx_cfg[ch_num].bit_format); - rate->min = rate->max = slim_rx_cfg[ch_num].sample_rate; - channels->min = channels->max = slim_rx_cfg[ch_num].channels; + slim_rx_cfg[idx].bit_format); + rate->min = rate->max = slim_rx_cfg[idx].sample_rate; + channels->min = channels->max = slim_rx_cfg[idx].channels; break; case MSM_BACKEND_DAI_SLIMBUS_0_TX: case MSM_BACKEND_DAI_SLIMBUS_3_TX: - ch_num = msm_slim_get_ch_from_beid(dai_link->be_id); + idx = msm_slim_get_ch_from_beid(dai_link->be_id); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - slim_tx_cfg[ch_num].bit_format); - rate->min = rate->max = slim_tx_cfg[ch_num].sample_rate; - channels->min = channels->max = slim_tx_cfg[ch_num].channels; + slim_tx_cfg[idx].bit_format); + rate->min = rate->max = slim_tx_cfg[idx].sample_rate; + channels->min = channels->max = slim_tx_cfg[idx].channels; break; case MSM_BACKEND_DAI_SLIMBUS_1_TX: @@ -1435,10 +1505,19 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, break; case MSM_BACKEND_DAI_HDMI_RX: + case MSM_BACKEND_DAI_DISPLAY_PORT_RX: + idx = msm_ext_disp_get_idx_from_beid(dai_link->be_id); + if (IS_ERR_VALUE(idx)) { + pr_err("%s: Incorrect ext disp idx %d\n", + __func__, idx); + rc = idx; + goto done; + } + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - hdmi_rx_cfg.bit_format); - rate->min = rate->max = hdmi_rx_cfg.sample_rate; - channels->min = channels->max = hdmi_rx_cfg.channels; + ext_disp_rx_cfg[idx].bit_format); + rate->min = rate->max = ext_disp_rx_cfg[idx].sample_rate; + channels->min = channels->max = ext_disp_rx_cfg[idx].channels; break; case MSM_BACKEND_DAI_AFE_PCM_RX: @@ -1450,7 +1529,9 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = SAMPLING_RATE_48KHZ; break; } - return 0; + +done: + return rc; } static bool msm_swap_gnd_mic(struct snd_soc_codec *codec) @@ -3293,14 +3374,14 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { }, }; -static struct snd_soc_dai_link hdmi_be_dai_link[] = { +static struct snd_soc_dai_link ext_disp_be_dai_link[] = { /* HDMI BACK END DAI Link */ { .name = LPASS_BE_HDMI, .stream_name = "HDMI Playback", .cpu_dai_name = "msm-dai-q6-hdmi.8", .platform_name = "msm-pcm-routing", - .codec_name = "msm-hdmi-audio-codec-rx", + .codec_name = "msm-ext-disp-audio-codec-rx", .codec_dai_name = "msm_hdmi_audio_codec_rx_dai", .no_pcm = 1, .dpcm_playback = 1, @@ -3309,6 +3390,21 @@ static struct snd_soc_dai_link hdmi_be_dai_link[] = { .ignore_pmdown_time = 1, .ignore_suspend = 1, }, + /* DISP PORT BACK END DAI Link */ + { + .name = LPASS_BE_DISPLAY_PORT, + .stream_name = "Display Port Playback", + .cpu_dai_name = "msm-dai-q6-dp.24608", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-ext-disp-audio-codec-rx", + .codec_dai_name = "msm_dp_audio_codec_rx_dai", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_DISPLAY_PORT_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, }; static struct snd_soc_dai_link msm_tasha_dai_links[ @@ -3317,7 +3413,7 @@ static struct snd_soc_dai_link msm_tasha_dai_links[ ARRAY_SIZE(msm_common_be_dai_links) + ARRAY_SIZE(msm_tasha_be_dai_links) + ARRAY_SIZE(msm_wcn_be_dai_links) + - ARRAY_SIZE(hdmi_be_dai_link)]; + ARRAY_SIZE(ext_disp_be_dai_link)]; static struct snd_soc_dai_link msm_tavil_dai_links[ ARRAY_SIZE(msm_common_dai_links) + @@ -3325,7 +3421,7 @@ static struct snd_soc_dai_link msm_tavil_dai_links[ ARRAY_SIZE(msm_common_be_dai_links) + ARRAY_SIZE(msm_tavil_be_dai_links) + ARRAY_SIZE(msm_wcn_be_dai_links) + - ARRAY_SIZE(hdmi_be_dai_link)]; + ARRAY_SIZE(ext_disp_be_dai_link)]; static int msm_snd_card_late_probe(struct snd_soc_card *card) { @@ -3725,14 +3821,15 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) total_links += ARRAY_SIZE(msm_wcn_be_dai_links); } - if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { - dev_dbg(dev, "%s(): HDMI support present\n", __func__); + if (of_property_read_bool(dev->of_node, + "qcom,ext-disp-audio-rx")) { + dev_dbg(dev, "%s(): External display audio support present\n", + __func__); memcpy(msm_tasha_dai_links + total_links, - hdmi_be_dai_link, - sizeof(hdmi_be_dai_link)); - total_links += ARRAY_SIZE(hdmi_be_dai_link); + ext_disp_be_dai_link, + sizeof(ext_disp_be_dai_link)); + total_links += ARRAY_SIZE(ext_disp_be_dai_link); } - dailink = msm_tasha_dai_links; } else if (!strcmp(match->data, "tavil_codec")) { card = &snd_soc_card_tavil_msm; @@ -3762,14 +3859,15 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) total_links += ARRAY_SIZE(msm_wcn_be_dai_links); } - if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { - dev_dbg(dev, "%s(): HDMI support present\n", __func__); + if (of_property_read_bool(dev->of_node, + "qcom,ext-disp-audio-rx")) { + dev_dbg(dev, "%s(): ext disp audio support present\n", + __func__); memcpy(msm_tavil_dai_links + total_links, - hdmi_be_dai_link, - sizeof(hdmi_be_dai_link)); - total_links += ARRAY_SIZE(hdmi_be_dai_link); + ext_disp_be_dai_link, + sizeof(ext_disp_be_dai_link)); + total_links += ARRAY_SIZE(ext_disp_be_dai_link); } - dailink = msm_tavil_dai_links; } else if (!strcmp(match->data, "stub_codec")) { card = &snd_soc_card_stub_msm; @@ -3786,7 +3884,6 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) dailink = msm_stub_dai_links; total_links = len_2; } - dev_dbg(dev, "%s(): No hdmi audio support\n", __func__); if (card) { card->dai_link = dailink; diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 7e0f790b30e9..70ed8dd3e038 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -2005,20 +2005,25 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, gapless_transition = prtd->gapless_state.gapless_transition; spin_unlock_irqrestore(&prtd->lock, flags); + if (gapless_transition) + pr_debug("%s session time in gapless transition", + __func__); + /* - Query timestamp from DSP if some data is with it. - This prevents timeouts. + - Do not query if no buffer has been given. + - Do not query on a gapless transition. + Playback for the 2nd stream can start (thus returning time + starting from 0) before the driver knows about EOS of first stream. */ - if (!first_buffer || gapless_transition) { - if (gapless_transition) - pr_debug("%s session time in gapless transition", - __func__); + + if (!first_buffer && !gapless_transition) { if (pdata->use_legacy_api) rc = q6asm_get_session_time_legacy(prtd->audio_client, - ×tamp); + &prtd->marker_timestamp); else rc = q6asm_get_session_time(prtd->audio_client, - ×tamp); + &prtd->marker_timestamp); + if (rc < 0) { pr_err("%s: Get Session Time return value =%lld\n", __func__, timestamp); @@ -2027,9 +2032,8 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, else return -EAGAIN; } - } else { - timestamp = prtd->marker_timestamp; } + timestamp = prtd->marker_timestamp; /* DSP returns timestamp in usec */ pr_debug("%s: timestamp = %lld usec\n", __func__, timestamp); diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c index 9c57adb863d4..69a9e14c47de 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,53 +32,82 @@ enum { STATUS_MAX }; -struct msm_hdmi_ca { +struct msm_ext_disp_ca { bool set_ca; u32 ca; }; -static struct msm_hdmi_ca hdmi_ca = { false, 0x0 }; - struct msm_dai_q6_hdmi_dai_data { DECLARE_BITMAP(status_mask, STATUS_MAX); u32 rate; u32 channels; + struct msm_ext_disp_ca ca; union afe_port_config port_config; }; -static int msm_dai_q6_hdmi_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_dai_q6_ext_disp_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; int value = ucontrol->value.integer.value[0]; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + dai_data->port_config.hdmi_multi_ch.datatype = value; pr_debug("%s: value = %d\n", __func__, value); + return 0; } -static int msm_dai_q6_hdmi_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_dai_q6_ext_disp_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + ucontrol->value.integer.value[0] = dai_data->port_config.hdmi_multi_ch.datatype; + pr_debug("%s: value = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; } -static int msm_dai_q6_hdmi_ca_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_dai_q6_ext_disp_ca_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - hdmi_ca.ca = ucontrol->value.integer.value[0]; - hdmi_ca.set_ca = true; + struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + + dai_data->ca.ca = ucontrol->value.integer.value[0]; + dai_data->ca.set_ca = true; + pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca); return 0; } -static int msm_dai_q6_hdmi_ca_get(struct snd_kcontrol *kcontrol, +static int msm_dai_q6_ext_disp_ca_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.integer.value[0] = hdmi_ca.ca; + struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = dai_data->ca.ca; + pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca); return 0; } @@ -97,12 +126,22 @@ static const struct soc_enum hdmi_config_enum[] = { static const struct snd_kcontrol_new hdmi_config_controls[] = { SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0], - msm_dai_q6_hdmi_format_get, - msm_dai_q6_hdmi_format_put), + msm_dai_q6_ext_disp_format_get, + msm_dai_q6_ext_disp_format_put), SOC_SINGLE_MULTI_EXT("HDMI RX CA", SND_SOC_NOPM, 0, HDMI_RX_CA_MAX, 0, 1, - msm_dai_q6_hdmi_ca_get, - msm_dai_q6_hdmi_ca_put), + msm_dai_q6_ext_disp_ca_get, + msm_dai_q6_ext_disp_ca_put), +}; + +static const struct snd_kcontrol_new display_port_config_controls[] = { + SOC_ENUM_EXT("Display Port RX Format", hdmi_config_enum[0], + msm_dai_q6_ext_disp_format_get, + msm_dai_q6_ext_disp_format_put), + SOC_SINGLE_MULTI_EXT("Display Port RX CA", SND_SOC_NOPM, 0, + HDMI_RX_CA_MAX, 0, 1, + msm_dai_q6_ext_disp_ca_get, + msm_dai_q6_ext_disp_ca_put), }; /* Current implementation assumes hw_param is called once @@ -200,9 +239,9 @@ static int msm_dai_q6_hdmi_prepare(struct snd_pcm_substream *substream, struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev); int rc = 0; - if (hdmi_ca.set_ca) + if (dai_data->ca.set_ca) dai_data->port_config.hdmi_multi_ch.channel_allocation = - hdmi_ca.ca; + dai_data->ca.ca; if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { rc = afe_port_start(dai->id, &dai_data->port_config, @@ -236,8 +275,8 @@ static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai) struct snd_soc_dapm_route intercon; struct snd_soc_dapm_context *dapm; - if (!dai) { - pr_err("%s: dai not found\n", __func__); + if (!dai || !dai->driver) { + pr_err("%s: dai or dai->driver is NULL\n", __func__); return -EINVAL; } dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data), @@ -252,19 +291,33 @@ static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai) msm_dai_q6_hdmi_set_dai_id(dai); - kcontrol = &hdmi_config_controls[0]; - - rc = snd_ctl_add(dai->component->card->snd_card, - snd_ctl_new1(kcontrol, dai_data)); - - kcontrol = &hdmi_config_controls[1]; - - rc = snd_ctl_add(dai->component->card->snd_card, - snd_ctl_new1(kcontrol, dai_data)); + if (dai->driver->id == HDMI_RX) { + kcontrol = &hdmi_config_controls[0]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + + kcontrol = &hdmi_config_controls[1]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + } else if (dai->driver->id == DISPLAY_PORT_RX) { + kcontrol = &display_port_config_controls[0]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + + kcontrol = &display_port_config_controls[1]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + } else { + dev_err(dai->dev, "%s: Invalid id:%d\n", + __func__, dai->driver->id); + kfree(dai_data); + dev_set_drvdata(dai->dev, NULL); + return -EINVAL; + } dapm = snd_soc_component_get_dapm(dai->component); memset(&intercon, 0 , sizeof(intercon)); - if (!rc && dai && dai->driver) { + if (!rc) { if (dai->driver->playback.stream_name && dai->driver->playback.aif_name) { dev_dbg(dai->dev, "%s add route for widget %s", @@ -325,8 +378,8 @@ static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 2, .channels_max = 8, - .rate_max = 192000, - .rate_min = 48000, + .rate_max = 192000, + .rate_min = 48000, }, .ops = &msm_dai_q6_hdmi_ops, .id = HDMI_RX, @@ -334,6 +387,27 @@ static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = { .remove = msm_dai_q6_hdmi_dai_remove, }; +static struct snd_soc_dai_driver msm_dai_q6_display_port_rx_dai[] = { + { + .playback = { + .stream_name = "Display Port Playback", + .aif_name = "DISPLAY_PORT", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 8, + .rate_max = 192000, + .rate_min = 48000, + }, + .ops = &msm_dai_q6_hdmi_ops, + .id = DISPLAY_PORT_RX, + .probe = msm_dai_q6_hdmi_dai_probe, + .remove = msm_dai_q6_hdmi_dai_remove, + }, +}; + static const struct snd_soc_component_driver msm_dai_hdmi_q6_component = { .name = "msm-dai-q6-hdmi", }; @@ -362,6 +436,12 @@ static int msm_dai_q6_hdmi_dev_probe(struct platform_device *pdev) &msm_dai_hdmi_q6_component, &msm_dai_q6_hdmi_hdmi_rx_dai, 1); break; + case DISPLAY_PORT_RX: + rc = snd_soc_register_component(&pdev->dev, + &msm_dai_hdmi_q6_component, + &msm_dai_q6_display_port_rx_dai[0], + ARRAY_SIZE(msm_dai_q6_display_port_rx_dai)); + break; default: dev_err(&pdev->dev, "invalid device ID %d\n", pdev->id); rc = -ENODEV; diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 51ebd039d96b..a898532643ae 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -37,6 +37,10 @@ #define CHANNEL_STATUS_MASK 0x4 #define AFE_API_VERSION_CLOCK_SET 1 +#define DAI_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + enum { ENC_FMT_NONE, ENC_FMT_SBC = ASM_MEDIA_FMT_SBC, @@ -2808,15 +2812,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus Playback", .aif_name = "SLIMBUS_0_RX", - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_0_RX, @@ -2827,15 +2828,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus1 Playback", .aif_name = "SLIMBUS_1_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_1_RX, @@ -2846,15 +2844,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus2 Playback", .aif_name = "SLIMBUS_2_RX", - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_2_RX, @@ -2865,15 +2860,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus3 Playback", .aif_name = "SLIMBUS_3_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_3_RX, @@ -2884,15 +2876,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus4 Playback", .aif_name = "SLIMBUS_4_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_4_RX, @@ -2903,15 +2892,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus6 Playback", .aif_name = "SLIMBUS_6_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_6_RX, @@ -2922,15 +2908,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus5 Playback", .aif_name = "SLIMBUS_5_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_5_RX, @@ -2941,15 +2924,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus7 Playback", .aif_name = "SLIMBUS_7_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_7_RX, @@ -2960,15 +2940,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus8 Playback", .aif_name = "SLIMBUS_8_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_8_RX, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index 6e5b4e871fe6..972cacb50f47 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -375,8 +375,12 @@ static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd) q6asm_cmd(prtd->audio_client, CMD_PAUSE); q6asm_cmd(prtd->audio_client, CMD_FLUSH); buf = q6asm_shared_io_buf(prtd->audio_client, dir); - if (buf) - memset(buf->data, 0, buf->actual_size); + if (buf == NULL) { + pr_err("%s: shared IO buffer is null\n", __func__); + ret = -EINVAL; + break; + } + memset(buf->data, 0, buf->actual_size); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 695f57b30322..aea60f1fa044 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -99,7 +99,8 @@ struct msm_pcm_route_bdai_pp_params { static struct msm_pcm_route_bdai_pp_params msm_bedais_pp_params[MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX] = { - {HDMI_RX, 0, 0, 0} + {HDMI_RX, 0, 0, 0}, + {DISPLAY_PORT_RX, 0, 0, 0}, }; static int msm_routing_send_device_pp_params(int port_id, int copp_idx); @@ -448,6 +449,7 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { { SLIMBUS_8_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX}, { AFE_PORT_ID_USB_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_RX}, { AFE_PORT_ID_USB_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_TX}, + { DISPLAY_PORT_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_DISPLAY_PORT}, }; /* Track ASM playback & capture sessions of DAI */ @@ -2932,6 +2934,58 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; + +static const struct snd_kcontrol_new display_port_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + /* incall music delivery mixer */ static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, @@ -5583,6 +5637,12 @@ static const struct snd_kcontrol_new hdmi_rx_port_mixer_controls[] = { msm_routing_put_port_mixer), }; +static const struct snd_kcontrol_new display_port_rx_port_mixer_controls[] = { + SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), +}; + static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SEC_I2S_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, @@ -7435,6 +7495,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0), + SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT", "Display Port Playback", + 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback", 0, 0, 0, 0), @@ -7709,6 +7771,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { slimbus_7_rx_mixer_controls, ARRAY_SIZE(slimbus_7_rx_mixer_controls)), SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0, hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)), + SND_SOC_DAPM_MIXER("DISPLAY_PORT Mixer", SND_SOC_NOPM, 0, 0, + display_port_mixer_controls, ARRAY_SIZE(display_port_mixer_controls)), SND_SOC_DAPM_MIXER("SPDIF_RX Audio Mixer", SND_SOC_NOPM, 0, 0, spdif_rx_mixer_controls, ARRAY_SIZE(spdif_rx_mixer_controls)), SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -7923,6 +7987,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("HDMI_RX Port Mixer", SND_SOC_NOPM, 0, 0, hdmi_rx_port_mixer_controls, ARRAY_SIZE(hdmi_rx_port_mixer_controls)), + SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Port Mixer", + SND_SOC_NOPM, 0, 0, display_port_rx_port_mixer_controls, + ARRAY_SIZE(display_port_rx_port_mixer_controls)), SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer", SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls, ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)), @@ -8114,6 +8181,24 @@ static const struct snd_soc_dapm_route intercon[] = { {"HDMI Mixer", "MultiMedia16", "MM_DL16"}, {"HDMI", NULL, "HDMI Mixer"}, + {"DISPLAY_PORT Mixer", "MultiMedia1", "MM_DL1"}, + {"DISPLAY_PORT Mixer", "MultiMedia2", "MM_DL2"}, + {"DISPLAY_PORT Mixer", "MultiMedia3", "MM_DL3"}, + {"DISPLAY_PORT Mixer", "MultiMedia4", "MM_DL4"}, + {"DISPLAY_PORT Mixer", "MultiMedia5", "MM_DL5"}, + {"DISPLAY_PORT Mixer", "MultiMedia6", "MM_DL6"}, + {"DISPLAY_PORT Mixer", "MultiMedia7", "MM_DL7"}, + {"DISPLAY_PORT Mixer", "MultiMedia8", "MM_DL8"}, + {"DISPLAY_PORT Mixer", "MultiMedia9", "MM_DL9"}, + {"DISPLAY_PORT Mixer", "MultiMedia10", "MM_DL10"}, + {"DISPLAY_PORT Mixer", "MultiMedia11", "MM_DL11"}, + {"DISPLAY_PORT Mixer", "MultiMedia12", "MM_DL12"}, + {"DISPLAY_PORT Mixer", "MultiMedia13", "MM_DL13"}, + {"DISPLAY_PORT Mixer", "MultiMedia14", "MM_DL14"}, + {"DISPLAY_PORT Mixer", "MultiMedia15", "MM_DL15"}, + {"DISPLAY_PORT Mixer", "MultiMedia16", "MM_DL16"}, + {"DISPLAY_PORT", NULL, "DISPLAY_PORT Mixer"}, + {"SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"SPDIF_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, {"SPDIF_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, @@ -9517,6 +9602,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, {"HDMI", NULL, "HDMI_RX Port Mixer"}, + {"DISPLAY_PORT_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, + {"DISPLAY_PORT", NULL, "DISPLAY_PORT_RX Port Mixer"}, + {"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, {"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"}, @@ -9571,6 +9659,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"BE_OUT", NULL, "SLIMBUS_8_RX"}, {"BE_OUT", NULL, "USB_AUDIO_RX"}, {"BE_OUT", NULL, "HDMI"}, + {"BE_OUT", NULL, "DISPLAY_PORT"}, {"BE_OUT", NULL, "SPDIF_RX"}, {"BE_OUT", NULL, "MI2S_RX"}, {"BE_OUT", NULL, "QUAT_MI2S_RX"}, @@ -9886,7 +9975,7 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx) pr_debug("%s: port_id %d, copp_idx %d\n", __func__, port_id, copp_idx); - if (port_id != HDMI_RX) { + if (port_id != HDMI_RX && port_id != DISPLAY_PORT_RX) { pr_err("%s: Device pp params on invalid port %d\n", __func__, port_id); return -EINVAL; @@ -9959,7 +10048,7 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) { port_id = msm_bedais[be_idx].port_id; - if (port_id == HDMI_RX) + if (port_id == HDMI_RX || port_id == DISPLAY_PORT_RX) break; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 009eebede28a..d8cec53c0d9e 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -18,6 +18,7 @@ #define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX" #define LPASS_BE_SLIMBUS_0_TX "SLIMBUS_0_TX" #define LPASS_BE_HDMI "HDMI" +#define LPASS_BE_DISPLAY_PORT "DISPLAY_PORT" #define LPASS_BE_INT_BT_SCO_RX "INT_BT_SCO_RX" #define LPASS_BE_INT_BT_SCO_TX "INT_BT_SCO_TX" #define LPASS_BE_INT_BT_A2DP_RX "INT_BT_A2DP_RX" @@ -311,6 +312,7 @@ enum { MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_BACKEND_DAI_USB_RX, MSM_BACKEND_DAI_USB_TX, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_BACKEND_DAI_MAX, }; @@ -339,7 +341,7 @@ enum { #define RELEASE_LOCK 0 #define ACQUIRE_LOCK 1 -#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX 1 +#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX 2 #define HDMI_RX_ID 0x8001 #define ADM_PP_PARAM_MUTE_ID 0 #define ADM_PP_PARAM_MUTE_BIT 1 diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c index 65c24973036e..6570819c2b31 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c @@ -670,7 +670,7 @@ static void voip_process_dl_pkt(uint8_t *voc_pkt, void *private_data) } else { *((uint32_t *)voc_pkt) = 0; spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags); - pr_err("DL data not available\n"); + pr_err_ratelimited("DL data not available\n"); } wake_up(&prtd->in_wait); } @@ -910,7 +910,7 @@ static int msm_pcm_capture_copy(struct snd_pcm_substream *substream, } else if (ret == 0) { - pr_err("%s: No UL data available\n", __func__); + pr_err_ratelimited("%s: No UL data available\n", __func__); ret = -ETIMEDOUT; } else { pr_err("%s: Read was interrupted\n", __func__); diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index 16c7ef4c0bf5..f6a687611f8a 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -423,6 +423,7 @@ int afe_get_port_type(u16 port_id) case SECONDARY_I2S_RX: case MI2S_RX: case HDMI_RX: + case DISPLAY_PORT_RX: case AFE_PORT_ID_SPDIF_RX: case SLIMBUS_0_RX: case SLIMBUS_1_RX: @@ -574,6 +575,7 @@ int afe_sizeof_cfg_cmd(u16 port_id) ret_size = SIZEOF_CFG_CMD(afe_param_id_i2s_cfg); break; case HDMI_RX: + case DISPLAY_PORT_RX: ret_size = SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg); break; @@ -2897,6 +2899,7 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; case HDMI_RX: + case DISPLAY_PORT_RX: cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; case VOICE_PLAYBACK_TX: @@ -3073,6 +3076,7 @@ int afe_get_port_index(u16 port_id) case MI2S_RX: return IDX_MI2S_RX; case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; + case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; @@ -3352,6 +3356,7 @@ int afe_open(u16 port_id, cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; case HDMI_RX: + case DISPLAY_PORT_RX: cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; case SLIMBUS_0_RX: @@ -4809,6 +4814,7 @@ int afe_validate_port(u16 port_id) case MI2S_RX: case MI2S_TX: case HDMI_RX: + case DISPLAY_PORT_RX: case AFE_PORT_ID_SPDIF_RX: case RSVD_2: case RSVD_3: @@ -5591,6 +5597,12 @@ int afe_get_sp_th_vi_ftm_data(struct afe_sp_th_vi_get_param *th_vi) goto done; } index = q6audio_get_port_index(port); + if (index < 0) { + pr_err("%s: invalid port 0x%x, index %d\n", + __func__, port, index); + ret = -EINVAL; + goto done; + } th_vi->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); th_vi->hdr.pkt_size = sizeof(*th_vi); diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c index 56dc6b58a646..a737a27cc327 100644 --- a/sound/soc/msm/qdsp6v2/q6audio-v2.c +++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c @@ -37,6 +37,7 @@ int q6audio_get_port_index(u16 port_id) case MI2S_RX: return IDX_MI2S_RX; case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; + case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; @@ -246,6 +247,8 @@ int q6audio_get_port_id(u16 port_id) case MI2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX; case MI2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX; case HDMI_RX: return AFE_PORT_ID_MULTICHAN_HDMI_RX; + case DISPLAY_PORT_RX: + return AFE_PORT_ID_HDMI_OVER_DP_RX; case AFE_PORT_ID_SPDIF_RX: return AFE_PORT_ID_SPDIF_RX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; @@ -573,6 +576,7 @@ int q6audio_validate_port(u16 port_id) case MI2S_RX: case MI2S_TX: case HDMI_RX: + case DISPLAY_PORT_RX: case RSVD_2: case RSVD_3: case DIGI_MIC_TX: diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c index 084f7df9d243..b242a8fe6017 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.c +++ b/sound/soc/msm/qdsp6v2/q6voice.c @@ -48,6 +48,7 @@ struct cvd_version_table cvd_version_table_mapping[CVD_INT_VERSION_MAX] = { {CVD_VERSION_0_0, CVD_INT_VERSION_0_0}, {CVD_VERSION_2_1, CVD_INT_VERSION_2_1}, {CVD_VERSION_2_2, CVD_INT_VERSION_2_2}, + {CVD_VERSION_2_3, CVD_INT_VERSION_2_3}, }; static struct common_data common; diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h index d230bf097eb9..3b3e728f88f2 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.h +++ b/sound/soc/msm/qdsp6v2/q6voice.h @@ -41,12 +41,14 @@ #define CVD_VERSION_0_0 "0.0" #define CVD_VERSION_2_1 "2.1" #define CVD_VERSION_2_2 "2.2" +#define CVD_VERSION_2_3 "2.3" #define CVD_INT_VERSION_DEFAULT 0 #define CVD_INT_VERSION_0_0 1 #define CVD_INT_VERSION_2_1 2 #define CVD_INT_VERSION_2_2 3 -#define CVD_INT_VERSION_LAST CVD_INT_VERSION_2_2 +#define CVD_INT_VERSION_2_3 4 +#define CVD_INT_VERSION_LAST CVD_INT_VERSION_2_3 #define CVD_INT_VERSION_MAX (CVD_INT_VERSION_LAST + 1) struct cvd_version_table { diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index b2dd69055927..c48d8c8d9766 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -201,7 +201,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; uinfo->value.integer.min = 0; - if (mc->min < 0 && (uinfo->type == SNDRV_CTL_ELEM_TYPE_INTEGER)) + if (uinfo->type == SNDRV_CTL_ELEM_TYPE_INTEGER) uinfo->value.integer.max = platform_max - mc->min; else uinfo->value.integer.max = platform_max; @@ -224,14 +224,12 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw); int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - snd_soc_info_volsw(kcontrol, uinfo); /* Max represents the number of levels in an SX control not the - * maximum value, so add the minimum value back on + * maximum value. + * uinfo->value.integer.max is set to number of levels + * in snd_soc_info_volsw_sx. No further adjustment is necessary. */ - uinfo->value.integer.max += mc->min; return 0; } diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 53dd085d3ee2..a6884fd1e4b3 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -139,6 +139,9 @@ static int snd_soc_dummy_probe(struct platform_device *pdev) { int ret; + memset(&dummy_codec, 0, + sizeof(struct snd_soc_codec_driver)); + ret = snd_soc_register_codec(&pdev->dev, &dummy_codec, &dummy_dai, 1); if (ret < 0) return ret; |
