diff options
184 files changed, 5422 insertions, 1490 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/diag_mhi.txt b/Documentation/devicetree/bindings/arm/msm/diag_mhi.txt new file mode 100644 index 000000000000..02f5103d5563 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/diag_mhi.txt @@ -0,0 +1,12 @@ +Qualcomm Technologies, Inc. Diag MHI Driver + +Required properties: +-compatible : should be "qcom,diag-mhi". +-qcom,mhi : phandle of MHI Device to connect to. + +Example: + qcom,diag { + compatible = "qcom,diag-mhi"; + qcom,mhi = <&mhi_wlan>; + }; + diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt index 3a6db0553fe3..a76b604445bd 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdp.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdp.txt @@ -3,6 +3,7 @@ Qualcomm Technologies,Inc. Adreno/Snapdragon display controller Required properties: Optional properties: +- contiguous-region: reserved memory for HDMI and DSI buffer. - qcom,sde-plane-id-map: plane id mapping for virtual plane. - qcom,sde-plane-id: each virtual plane mapping node. - reg: reg property. @@ -17,6 +18,8 @@ Optional properties: Example: &mdss_mdp { + contiguous-region = <&cont_splash_mem &cont_splash_mem_hdmi>; + qcom,sde-plane-id-map { qcom,sde-plane-id@0 { reg = <0x0>; diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt index 9fb84020add7..bb413af4b54d 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cci.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt @@ -123,6 +123,9 @@ Optional properties: - qcom,gpio-vdig : should contain index to gpio used by sensors digital vreg enable - qcom,gpio-vaf : should contain index to gpio used by sensors af vreg enable - qcom,gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n +- qcom,gpio-custom1 : should contain index to gpio used by sensors specific to usecase +- qcom,gpio-custom2 : should contain index to gpio used by sensors specific to usecase +- qcom,gpio-custom3 : should contain index to gpio used by sensors specific to usecase - qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor - qcom,gpio-req-tbl-flags : should contain direction of gpios present in qcom,gpio-req-tbl-num property (in the same order) diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index fc019bda50a7..bf3ad8a71c26 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -97,6 +97,9 @@ Optional Properties: and assign for each endpoint. - qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become stable after power on, before de-assert the PERST to the endpoint. + - qcom,switch-latency: The time (unit: ms) to wait for the PCIe endpoint's link + training with switch downstream port after the link between switch upstream + port and RC is up. - qcom,wr-halt-size: With base 2, this exponent determines the size of the data that PCIe core will halt on for each write transaction. - qcom,cpl-timeout: Completion timeout value. This value specifies the time range @@ -276,6 +279,7 @@ Example: qcom,smmu-exist; qcom,smmu-sid-base = <0x1480>; qcom,ep-latency = <100>; + qcom,switch-latency = <100>; qcom,wr-halt-size = <0xa>; /* 1KB */ qcom,cpl-timeout = <0x2>; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt new file mode 100644 index 000000000000..8a9514153172 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt @@ -0,0 +1,201 @@ +Qualcomm Technologies, Inc. MSM8998 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8998 platform. With new GPIOs tiling, GPIO pins are +grouped into various cores - NORTH, WEST, EAST. TLMM_GPIO_ID_STATUSn +register's value for a GPIO pin decides the core location for it. + +- compatible: + Usage: required + Value type: <string> + Definition: must be "qcom,msm8998-pinctrl" + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: <prop-encoded-array> + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: <none> + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: <u32> + Definition: must be 2. Specifying the pin number and flags, as defined + in <dt-bindings/interrupt-controller/irq.h> + +- gpio-controller: + Usage: required + Value type: <none> + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: <u32> + Definition: must be 2. Specifying the pin number and flags, as defined + in <dt-bindings/gpio/gpio.h> + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: <string-array> + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio149, + sdc1_clk, + sdc1_cmd, + sdc1_data + sdc2_clk, + sdc2_cmd, + sdc2_data + sdc1_rclk, + +- function: + Usage: required + Value type: <string> + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: <none> + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: <none> + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: <none> + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: <none> + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: <none> + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: <u32> + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@01010000 { + compatible = "qcom,msm8998-pinctrl"; + reg = <0x01010000 0x300000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart8"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt index 468db388b0a6..3527779ef93c 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt @@ -85,21 +85,6 @@ Charger specific properties: maximum charge current in mA for each thermal level. -- qcom,step-soc-thresholds - Usage: optional - Value type: Array of <u32> - Definition: Array of SOC threshold values, size of 4. This should be a - flat array that denotes the percentage ranging from 0 to 100. - If the array is not present, step charging is disabled. - -- qcom,step-current-deltas - Usage: optional - Value type: Array of <s32> - Definition: Array of delta values for charging current, size of 5, with - FCC as base. This should be a flat array that denotes the - 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> @@ -182,6 +167,18 @@ Charger specific properties: Definition: Specifies the deglitch interval for OTG detection. If the value is not present, 50 msec is used as default. +- qcom,step-charging-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables step-charging. + +- qcom,wd-bark-time-secs + Usage: optional + Value type: <u32> + Definition: WD bark-timeout in seconds. The possible values are + 16, 32, 64, 128. If not defined it defaults to 64. + + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= @@ -217,9 +214,6 @@ pmi8998_charger: qcom,qpnp-smb2 { dpdm-supply = <&qusb_phy0>; - qcom,step-soc-thresholds = <60 70 80 90>; - qcom,step-current-deltas = <500000 250000 150000 0 (-150000)>; - qcom,chgr@1000 { reg = <0x1000 0x100>; interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi index 4081a21b3134..db33594d3827 100644 --- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi +++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi @@ -713,6 +713,10 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -731,6 +735,10 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", diff --git a/arch/arm/boot/dts/qcom/msm-rdbg.dtsi b/arch/arm/boot/dts/qcom/msm-rdbg.dtsi index d0c91f9e72ae..6de1a8e2fb7e 100644 --- a/arch/arm/boot/dts/qcom/msm-rdbg.dtsi +++ b/arch/arm/boot/dts/qcom/msm-rdbg.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -72,4 +72,35 @@ compatible = "qcom,smp2pgpio_client_rdbg_1_out"; gpios = <&smp2pgpio_rdbg_1_out 0 0>; }; + + smp2pgpio_rdbg_5_in: qcom,smp2pgpio-rdbg-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_5_in { + compatible = "qcom,smp2pgpio_client_rdbg_5_in"; + gpios = <&smp2pgpio_rdbg_5_in 0 0>; + }; + + smp2pgpio_rdbg_5_out: qcom,smp2pgpio-rdbg-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_5_out { + compatible = "qcom,smp2pgpio_client_rdbg_5_out"; + gpios = <&smp2pgpio_rdbg_5_out 0 0>; + }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index 9dbec1e87fda..2dc5c919190c 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -1016,6 +1016,10 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -1034,6 +1038,10 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index ad14bfd00cd1..1d5e3035afd0 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -838,6 +838,10 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -856,6 +860,10 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi index d3ea51268590..c8898ec01992 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi @@ -538,6 +538,10 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -556,6 +560,10 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", diff --git a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi index e1921c3baeb3..936dfd4d1cb2 100644 --- a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi @@ -1918,6 +1918,13 @@ gpio = <&pm8994_gpios 9 0>; }; + wlan_en_vreg: wlan_en_vreg { + compatible = "regulator-fixed"; + regulator-name = "wlan_en_vreg"; + enable-active-high; + gpio = <&pm8994_gpios 8 0>; + }; + hl7509_en_vreg: hl7509_en_vreg { compatible = "regulator-fixed"; regulator-name = "hl7509_en_vreg"; diff --git a/arch/arm/boot/dts/qcom/msm8996-sde.dtsi b/arch/arm/boot/dts/qcom/msm8996-sde.dtsi index 6d0e5c4cb920..b0688668e667 100644 --- a/arch/arm/boot/dts/qcom/msm8996-sde.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-sde.dtsi @@ -20,6 +20,8 @@ "vbif_phys", "vbif_nrt_phys"; + contiguous-region = <&cont_splash_mem &cont_splash_mem_hdmi>; + /* clock and supply entries */ clocks = <&clock_mmss clk_mdss_ahb_clk>, <&clock_mmss clk_mdss_axi_clk>, diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index dcd884b4a745..c1a6d1fc4b4f 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -3355,6 +3355,82 @@ }; }; + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36866>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36868>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36870>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36867>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36869>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36871>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + qcom,msm-dai-tdm-sec-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37137>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts index 7f6f3d5d4a4c..d2aa5c854c83 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,7 +22,7 @@ model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP"; compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp"; qcom,msm-id = <315 0x10000>; - qcom,board-id = <0x02010019 0>; + qcom,board-id = <0x02010019 0>, <0x00010001 0>; }; &spi_9 { diff --git a/arch/arm/boot/dts/qcom/msm8996pro.dtsi b/arch/arm/boot/dts/qcom/msm8996pro.dtsi index 252940c9c3e5..b9a2ccb973f2 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996pro.dtsi @@ -22,7 +22,7 @@ qcom,msm-id = <305 0x10000>; chosen { - bootargs = "fpsimd.fpsimd_settings=1 app_setting.use_app_setting=0 app_setting.use_32bit_app_setting_pro=1"; + bootargs = "lpm_levels.sleep_disabled=1 fpsimd.fpsimd_settings=1 app_setting.use_app_setting=0 app_setting.use_32bit_app_setting_pro=1"; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi index 14567c3b5010..2af3bf277096 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -345,6 +345,60 @@ clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; + + /* ToF Camera*/ + qcom,camera@3 { + cell-index = <3>; + compatible = "qcom,camera"; + reg = <0x3>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <3>; + qcom,mount-angle = <90>; + cam_vio-supply = <&pm8998_lvs1>; + qcom,cam-vreg-name = "cam_vio"; + qcom,cam-vreg-min-voltage = <1800000>; + qcom,cam-vreg-max-voltage = <1800000>; + qcom,cam-vreg-op-mode = <80000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_depth_v1_active + &cam_sensor_depth_v2_active + &cam_sensor_depth_default>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_depth_v1_sleep + &cam_sensor_depth_v2_sleep + &cam_sensor_depth_sleep>; + gpios = <&tlmm 16 0>, + <&tlmm 24 0>, + <&tlmm 21 0>, + <&tlmm 28 0>, + <&tlmm 23 0>, + <&tlmm 7 0>; + qcom,gpio-vana = <1>; + qcom,gpio-custom2 = <2>; + qcom,gpio-reset = <3>; + qcom,gpio-custom3 = <4>; + qcom,gpio-custom1 = <5>; + qcom,gpio-req-tbl-num = <0 1 2 3 4 5>; + qcom,gpio-req-tbl-flags = <1 0 0 0 1 1>; + qcom,gpio-req-tbl-label = + "CAMIF_MCLK3", + "CAM_VANA", + "CAM_CUSTOM2", + "CAM_RESET1", + "CAM_CUSTOM3", + "CAM_CUSTOM1"; + qcom,sensor-position = <1>; /* 0 rear */ + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; /* I2C 1 */ + status = "ok"; + clocks = <&clock_mmss clk_mclk3_clk_src>, + <&clock_mmss clk_mmss_camss_mclk3_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + }; &pm8998_gpios { diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index 71593012148d..ed1259918620 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -993,6 +993,86 @@ }; }; + cam_sensor_depth_default: cam_sensor_depth_default { + mux { + pins = "gpio28","gpio23","gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio28","gpio23","gpio7"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_depth_sleep: cam_sensor_depth_sleep { + mux { + pins = "gpio28","gpio23","gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio28","gpio23","gpio7"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_depth_v1_active: cam_sensor_depth_v1_active { + /* Depth VANA */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_depth_v1_sleep: cam_sensor_depth_v1_sleep { + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_depth_v2_active: cam_sensor_depth_v2_active { + /* Depth CUSTOM2 */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_depth_v2_sleep: cam_sensor_depth_v2_sleep { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts index 604823ff416e..0f4b462fd57b 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts @@ -170,6 +170,15 @@ qcom,mdss-pref-prim-intf = "dsi"; }; +&mdss_dp_ctrl { + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 55 0>; + qcom,aux-sel-gpio = <&tlmm 56 0>; + qcom,usbplug-cc-gpio = <&tlmm 58 0>; +}; + &mdss_dsi { hw-config = "single_dsi"; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-pm.dtsi b/arch/arm/boot/dts/qcom/sdm630-pm.dtsi index f10477bab8cf..f39f8b880690 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-pm.dtsi @@ -24,7 +24,7 @@ qcom,vctl-timeout-us = <500>; qcom,vctl-port = <0x0>; qcom,phase-port = <0x1>; - qcom,saw2-avs-ctl = <0x101c031>; + qcom,saw2-avs-ctl = <0x1010031>; qcom,saw2-avs-limit = <0x4580458>; qcom,pfm-port = <0x2>; }; @@ -40,7 +40,7 @@ qcom,vctl-timeout-us = <500>; qcom,vctl-port = <0x0>; qcom,phase-port = <0x1>; - qcom,saw2-avs-ctl = <0x101c031>; + qcom,saw2-avs-ctl = <0x1010031>; qcom,saw2-avs-limit = <0x4580458>; qcom,pfm-port = <0x2>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index cff3aa809488..54f014aa7681 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -613,6 +613,7 @@ compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x0>; qcom,client-id = <1>; + qcom,allocate-boot-time; label = "modem"; }; }; @@ -1165,8 +1166,9 @@ < 1113600 762 >, < 1344000 2086 >, < 1670400 2929 >, - < 2150400 3879 >, - < 2380800 4943 >; + < 1881600 3879 >, + < 2150400 4943 >, + < 2380800 5163 >; }; devfreq_memlat_4: qcom,arm-memlat-mon-4 { @@ -1304,18 +1306,9 @@ compatible = "qcom,clk-cpu-osm-sdm630"; reg = <0x179c0000 0x4000>, <0x17916000 0x1000>, <0x17816000 0x1000>, <0x179d1000 0x1000>, - <0x00784130 0x8>, <0x17914800 0x800>, - <0x17814800 0x800>; + <0x00784130 0x8>; reg-names = "osm", "pwrcl_pll", "perfcl_pll", - "apcs_common", "perfcl_efuse", - "pwrcl_acd", "perfcl_acd"; - - qcom,acdtd-val = <0x0000a111 0x0000a111>; - qcom,acdcr-val = <0x002c5ffd 0x002c5ffd>; - qcom,acdsscr-val = <0x00000901 0x00000901>; - qcom,acdextint0-val = <0x2cf9ae8 0x2cf9ae8>; - qcom,acdextint1-val = <0x2cf9afe 0x2cf9afe>; - qcom,acdautoxfer-val = <0x00000015 0x00000015>; + "apcs_common", "perfcl_efuse"; vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; vdd-perfcl-supply = <&apc1_perfcl_vreg>; diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts index 7cf55acf900b..30b36c0ac541 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts @@ -42,6 +42,13 @@ reg = <0x1 0x0 0 0x10000000>; label = "ion_system_mem"; }; + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1400000>; + }; ion_audio: ion_audio_region { reg = <0 0xc8000000 0 0x00400000>; label = "ion_audio_mem"; @@ -78,6 +85,10 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -96,6 +107,10 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", @@ -477,6 +492,22 @@ }; }; + qcom_seecom: qseecom@86600000 { + compatible = "qcom,qseecom"; + reg = <0x86600000 0x2200000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,no-clock-support; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,ce-opp-freq = <171430000>; + qcom,qsee-reentrancy-support = <2>; + }; + hostless: qcom,msm-pcm-hostless { compatible = "qcom,msm-pcm-hostless"; }; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index a84172106e0f..781fa96726e2 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -291,6 +291,7 @@ struct fastrpc_file { int cid; int ssrcount; int pd; + int file_close; struct fastrpc_apps *apps; struct fastrpc_perf perf; struct dentry *debugfs_file; @@ -319,6 +320,7 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .channel = SMD_APPS_DSPS, .link.link_info.edge = "dsps", .link.link_info.transport = "smem", + .vmid = VMID_SSC_Q6, }, { .name = "cdsprpc-smd", @@ -699,7 +701,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr, if (vmid) { int srcVM[1] = {VMID_HLOS}; int destVM[2] = {VMID_HLOS, vmid}; - int destVMperm[2] = {PERM_READ | PERM_WRITE, + int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC, PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !hyp_assign_phys(map->phys, @@ -771,7 +773,7 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size, if (vmid) { int srcVM[1] = {VMID_HLOS}; int destVM[2] = {VMID_HLOS, vmid}; - int destVMperm[2] = {PERM_READ | PERM_WRITE, + int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC, PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !hyp_assign_phys(buf->phys, buf_page_size(size), @@ -1454,7 +1456,7 @@ static void smd_event_handler(void *priv, unsigned event) switch (event) { case SMD_EVENT_OPEN: - complete(&me->channel[cid].work); + complete(&me->channel[cid].workport); break; case SMD_EVENT_CLOSE: fastrpc_notify_drivers(me, cid); @@ -1475,7 +1477,7 @@ static void fastrpc_init(struct fastrpc_apps *me) me->channel = &gcinfo[0]; for (i = 0; i < NUM_CHANNELS; i++) { init_completion(&me->channel[i].work); - init_completion(&me->channel[i].workport); + init_completion(&me->channel[i].workport); me->channel[i].sesscount = 0; } } @@ -2195,6 +2197,9 @@ static int fastrpc_file_free(struct fastrpc_file *fl) return 0; } (void)fastrpc_release_current_dsp_process(fl); + spin_lock(&fl->hlock); + fl->file_close = 1; + spin_unlock(&fl->hlock); fastrpc_context_list_dtor(fl); fastrpc_buf_list_free(fl); hlist_for_each_entry_safe(map, n, &fl->maps, hn) { @@ -2583,6 +2588,14 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, p.inv.fds = 0; p.inv.attrs = 0; + spin_lock(&fl->hlock); + if (fl->file_close == 1) { + err = EBADF; + pr_warn("ADSPRPC: fastrpc_device_release is happening, So not sending any new requests to DSP"); + spin_unlock(&fl->hlock); + goto bail; + } + spin_unlock(&fl->hlock); switch (ioctl_num) { case FASTRPC_IOCTL_INVOKE: diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index e37609abf7bf..e206d9db4d7d 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -320,6 +320,7 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_ctrl_msg_mask header; + uint8_t msg_mask_tbl_count_local; if (peripheral >= NUM_PERIPHERALS) return; @@ -360,6 +361,8 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } buf = mask_info->update_buf; + msg_mask_tbl_count_local = driver->msg_mask_tbl_count; + mutex_unlock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); switch (mask_info->status) { case DIAG_CTRL_MASK_ALL_DISABLED: @@ -376,9 +379,11 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) goto err; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { - if (((first < mask->ssid_first) || - (last > mask->ssid_last_tools)) && first != ALL_SSID) { + for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) { + mutex_lock(&driver->msg_mask_lock); + if (((mask->ssid_first > first) || + (mask->ssid_last_tools < last)) && first != ALL_SSID) { + mutex_unlock(&driver->msg_mask_lock); continue; } @@ -419,19 +424,19 @@ proceed: if (mask_size > 0) memcpy(buf + header_len, mask->ptr, mask_size); mutex_unlock(&mask->lock); + mutex_unlock(&driver->msg_mask_lock); err = diagfwd_write(peripheral, TYPE_CNTL, buf, header_len + mask_size); if (err && err != -ENODEV) - pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d\n", - peripheral); + pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d, error = %d\n", + peripheral, err); if (first != ALL_SSID) break; } err: mutex_unlock(&mask_info->lock); - mutex_unlock(&driver->msg_mask_lock); } static void diag_send_time_sync_update(uint8_t peripheral) @@ -711,8 +716,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, } req = (struct diag_msg_build_mask_t *)src_buf; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if (i < (driver->msg_mask_tbl_count - 1)) { @@ -752,6 +757,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, pr_err_ratelimited("diag: In %s, unable to allocate memory for msg mask ptr, mask_size: %d\n", __func__, mask_size); mutex_unlock(&mask->lock); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); return -ENOMEM; } mask->ptr = temp; @@ -770,8 +777,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mask_info->status = DIAG_CTRL_MASK_VALID; break; } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -826,9 +833,11 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, } req = (struct diag_msg_config_rsp_t *)src_buf; + + mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); + mask = (struct diag_msg_mask_t *)mask_info->ptr; - mutex_lock(&mask_info->lock); mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -837,8 +846,8 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mask->range * sizeof(uint32_t)); mutex_unlock(&mask->lock); } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -1352,8 +1361,8 @@ static int diag_create_msg_mask_table(void) struct diag_msg_mask_t *mask = (struct diag_msg_mask_t *)msg_mask.ptr; struct diag_ssid_range_t range; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&msg_mask.lock); + mutex_lock(&driver->msg_mask_lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; @@ -1362,8 +1371,8 @@ static int diag_create_msg_mask_table(void) if (err) break; } - mutex_unlock(&msg_mask.lock); mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&msg_mask.lock); return err; } @@ -1376,8 +1385,8 @@ static int diag_create_build_time_mask(void) struct diag_msg_mask_t *build_mask = NULL; struct diag_ssid_range_t range; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&msg_bt_mask.lock); + mutex_lock(&driver->msg_mask_lock); driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { @@ -1490,9 +1499,8 @@ static int diag_create_build_time_mask(void) } memcpy(build_mask->ptr, tbl, tbl_size); } - mutex_unlock(&msg_bt_mask.lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&msg_bt_mask.lock); return err; } @@ -1662,8 +1670,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&dest->lock); + mutex_lock(&driver->msg_mask_lock); src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; @@ -1680,9 +1688,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) src_mask++; dest_mask++; } - mutex_unlock(&dest->lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&dest->lock); return err; } @@ -1693,15 +1700,15 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) if (!mask_info) return; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); __diag_mask_exit(mask_info); } @@ -1870,8 +1877,9 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, return -EIO; } mutex_unlock(&driver->diag_maskclear_mutex); - mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); + mask = (struct diag_msg_mask_t *)(mask_info->ptr); for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { ptr = mask_info->update_buf; @@ -1908,8 +1916,8 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, } total_len += len; } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); return err ? err : total_len; } diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index cc56d68217b3..d81a39e2c637 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -642,6 +642,7 @@ struct diagchar_dev { #endif int time_sync_enabled; uint8_t uses_time_api; + struct platform_device *pdev; }; extern struct diagchar_dev *driver; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index afaedc99a4e7..eaed3b101095 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -22,6 +22,8 @@ #include <linux/sched.h> #include <linux/ratelimit.h> #include <linux/timer.h> +#include <linux/platform_device.h> +#include <linux/msm_mhi.h> #ifdef CONFIG_DIAG_OVER_USB #include <linux/usb/usbdiag.h> #endif @@ -701,6 +703,11 @@ static void diag_cmd_invalidate_polling(int change_flag) driver->polling_reg_flag = 0; list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + return; + } polling = diag_cmd_chk_polling(&item->entry); if (polling == DIAG_CMD_POLLING) { driver->polling_reg_flag = 1; @@ -842,6 +849,12 @@ void diag_cmd_remove_reg_by_pid(int pid) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + mutex_unlock(&driver->cmd_reg_mutex); + return; + } if (item->pid == pid) { list_del(&item->link); kfree(item); @@ -860,6 +873,12 @@ void diag_cmd_remove_reg_by_proc(int proc) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + mutex_unlock(&driver->cmd_reg_mutex); + return; + } if (item->proc == proc) { list_del(&item->link); kfree(item); @@ -1836,14 +1855,18 @@ static int diag_ioctl_lsm_deinit(void) { int i; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; - if (i == driver->num_clients) + if (i == driver->num_clients) { + mutex_unlock(&driver->diagchar_mutex); return -EINVAL; + } driver->data_ready[i] |= DEINIT_TYPE; + mutex_unlock(&driver->diagchar_mutex); wake_up_interruptible(&driver->wait_q); return 1; @@ -3585,6 +3608,41 @@ static int diagchar_cleanup(void) return 0; } +static int diag_mhi_probe(struct platform_device *pdev) +{ + int ret; + + if (!mhi_is_device_ready(&pdev->dev, "qcom,mhi")) + return -EPROBE_DEFER; + driver->pdev = pdev; + ret = diag_remote_init(); + if (ret) { + diag_remote_exit(); + return ret; + } + ret = diagfwd_bridge_init(); + if (ret) { + diagfwd_bridge_exit(); + return ret; + } + pr_debug("diag: mhi device is ready\n"); + return 0; +} + +static const struct of_device_id diag_mhi_table[] = { + {.compatible = "qcom,diag-mhi"}, + {}, +}; + +static struct platform_driver diag_mhi_driver = { + .probe = diag_mhi_probe, + .driver = { + .name = "DIAG MHI Platform", + .owner = THIS_MODULE, + .of_match_table = diag_mhi_table, + }, +}; + static int __init diagchar_init(void) { dev_t dev; @@ -3674,9 +3732,6 @@ static int __init diagchar_init(void) ret = diag_masks_init(); if (ret) goto fail; - ret = diag_remote_init(); - if (ret) - goto fail; ret = diag_mux_init(); if (ret) goto fail; @@ -3713,9 +3768,7 @@ static int __init diagchar_init(void) goto fail; pr_debug("diagchar initialized now"); - ret = diagfwd_bridge_init(); - if (ret) - diagfwd_bridge_exit(); + platform_driver_register(&diag_mhi_driver); return 0; fail: @@ -3729,9 +3782,7 @@ fail: diagfwd_cntl_exit(); diag_dci_exit(); diag_masks_exit(); - diag_remote_exit(); return -1; - } static void diagchar_exit(void) diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 4ae2158b5a6b..74777212e4cf 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -67,7 +67,6 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info) driver->feature[peripheral].sent_feature_mask = 0; driver->feature[peripheral].rcvd_feature_mask = 0; - flush_workqueue(driver->cntl_wq); reg_dirty |= PERIPHERAL_MASK(peripheral); diag_cmd_remove_reg_by_proc(peripheral); driver->feature[peripheral].stm_support = DISABLE_STM; diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c index 03d496c2dd91..f1f8f0b2b34b 100644 --- a/drivers/char/diag/diagfwd_glink.c +++ b/drivers/char/diag/diagfwd_glink.c @@ -361,13 +361,44 @@ static void diag_glink_read_work_fn(struct work_struct *work) diagfwd_channel_read(glink_info->fwd_ctxt); } +struct diag_glink_read_work { + struct diag_glink_info *glink_info; + const void *ptr_read_done; + const void *ptr_rx_done; + size_t ptr_read_size; + struct work_struct work; +}; + +static void diag_glink_notify_rx_work_fn(struct work_struct *work) +{ + struct diag_glink_read_work *read_work = container_of(work, + struct diag_glink_read_work, work); + struct diag_glink_info *glink_info = read_work->glink_info; + + if (!glink_info || !glink_info->hdl) { + kfree(read_work); + return; + } + + diagfwd_channel_read_done(glink_info->fwd_ctxt, + (unsigned char *)(read_work->ptr_read_done), + read_work->ptr_read_size); + + glink_rx_done(glink_info->hdl, read_work->ptr_rx_done, false); + + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Rx done for packet %pK of len: %d periph: %d ch: %d\n", + read_work->ptr_rx_done, (int)read_work->ptr_read_size, + glink_info->peripheral, glink_info->type); + kfree(read_work); +} static void diag_glink_notify_rx(void *hdl, const void *priv, const void *pkt_priv, const void *ptr, size_t size) { struct diag_glink_info *glink_info = (struct diag_glink_info *)priv; - int err = 0; + struct diag_glink_read_work *read_work; if (!glink_info || !glink_info->hdl || !ptr || !pkt_priv || !hdl) return; @@ -379,12 +410,25 @@ static void diag_glink_notify_rx(void *hdl, const void *priv, "diag: received a packet %pK of len:%d from periph:%d ch:%d\n", ptr, (int)size, glink_info->peripheral, glink_info->type); + read_work = kmalloc(sizeof(*read_work), GFP_ATOMIC); + if (!read_work) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Could not allocate read_work\n"); + glink_rx_done(glink_info->hdl, ptr, true); + return; + } + memcpy((void *)pkt_priv, ptr, size); - err = diagfwd_channel_read_done(glink_info->fwd_ctxt, - (unsigned char *)pkt_priv, size); - glink_rx_done(glink_info->hdl, ptr, false); + + read_work->glink_info = glink_info; + read_work->ptr_read_done = pkt_priv; + read_work->ptr_rx_done = ptr; + read_work->ptr_read_size = size; + INIT_WORK(&read_work->work, diag_glink_notify_rx_work_fn); + queue_work(glink_info->wq, &read_work->work); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: Rx done for packet %pK of len:%d periph:%d ch:%d\n", + "diag: Rx queued for packet %pK of len: %d periph: %d ch: %d\n", ptr, (int)size, glink_info->peripheral, glink_info->type); } @@ -473,6 +517,8 @@ static void diag_glink_connect_work_fn(struct work_struct *work) atomic_set(&glink_info->opened, 1); diagfwd_channel_open(glink_info->fwd_ctxt); diagfwd_late_open(glink_info->fwd_ctxt); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink channel open: p: %d t: %d\n", + glink_info->peripheral, glink_info->type); } static void diag_glink_remote_disconnect_work_fn(struct work_struct *work) @@ -494,9 +540,9 @@ static void diag_glink_late_init_work_fn(struct work_struct *work) late_init_work); if (!glink_info || !glink_info->hdl) return; - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d\n", - glink_info->peripheral, glink_info->type); diagfwd_channel_open(glink_info->fwd_ctxt); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink late init p: %d t: %d\n", + glink_info->peripheral, glink_info->type); } static void diag_glink_transport_notify_state(void *handle, const void *priv, diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 03133a5a89aa..edfba6bb09c9 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -197,7 +197,7 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) struct diag_mhi_buf_tbl_t *item = NULL; struct diag_mhi_ch_t *ch = NULL; - if (!mhi_info || !mhi_info->enabled) + if (!mhi_info) return; /* Clear all the pending reads */ @@ -678,7 +678,25 @@ static int diag_mhi_register_ch(int id, struct diag_mhi_ch_t *ch) atomic_set(&(ch->opened), 0); ctxt = SET_CH_CTXT(id, ch->type); ch->client_info.mhi_client_cb = mhi_notifier; - return mhi_register_channel(&ch->hdl, NULL); + ch->client_info.chan = ch->chan; + ch->client_info.dev = &driver->pdev->dev; + ch->client_info.node_name = "qcom,mhi"; + ch->client_info.user_data = (void *)(uintptr_t)ctxt; + return mhi_register_channel(&ch->hdl, &ch->client_info); +} + +static void diag_mhi_dev_exit(int dev) +{ + struct diag_mhi_info *mhi_info = NULL; + + mhi_info = &diag_mhi[dev]; + if (!mhi_info) + return; + if (mhi_info->mhi_wq) + destroy_workqueue(mhi_info->mhi_wq); + mhi_close(mhi_info->id); + if (mhi_info->mempool_init) + diagmem_exit(driver, mhi_info->mempool); } int diag_mhi_init() @@ -726,22 +744,16 @@ int diag_mhi_init() return 0; fail: - diag_mhi_exit(); + diag_mhi_dev_exit(i); return -ENOMEM; } void diag_mhi_exit() { int i; - struct diag_mhi_info *mhi_info = NULL; for (i = 0; i < NUM_MHI_DEV; i++) { - mhi_info = &diag_mhi[i]; - if (mhi_info->mhi_wq) - destroy_workqueue(mhi_info->mhi_wq); - mhi_close(mhi_info->id); - if (mhi_info->mempool_init) - diagmem_exit(driver, mhi_info->mempool); + diag_mhi_dev_exit(i); } } diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 9ac1ad62ffe0..78b8452b19b3 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -1049,7 +1049,16 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral) dest_info->buf_ptr[i] = fwd_info->buf_ptr[i]; if (!check_channel_state(dest_info->ctxt)) diagfwd_late_open(dest_info); - diagfwd_cntl_open(dest_info); + + /* + * Open control channel to update masks after buffers are + * initialized for peripherals that have transport other than + * GLINK. GLINK supported peripheral mask update will + * happen after glink buffers are initialized. + */ + + if (dest_info->transport != TRANSPORT_GLINK) + diagfwd_cntl_open(dest_info); init_fn(peripheral); mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]); diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]); @@ -1240,7 +1249,18 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 1; diagfwd_buffers_init(fwd_info); - diagfwd_write_buffers_init(fwd_info); + + /* + * Initialize buffers for glink supported + * peripherals only. Open control channel to update + * masks after buffers are initialized. + */ + if (fwd_info->transport == TRANSPORT_GLINK) { + diagfwd_write_buffers_init(fwd_info); + if (fwd_info->type == TYPE_CNTL) + diagfwd_cntl_open(fwd_info); + } + if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open) fwd_info->c_ops->open(fwd_info); for (i = 0; i < NUM_WRITE_BUFFERS; i++) { @@ -1265,6 +1285,9 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) if (!fwd_info) return -EIO; + if (fwd_info->type == TYPE_CNTL) + flush_workqueue(driver->cntl_wq); + mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 0; if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close) diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c index 076ead6aaf34..40d8d12cda82 100644 --- a/drivers/clk/msm/clock-local2.c +++ b/drivers/clk/msm/clock-local2.c @@ -1517,8 +1517,8 @@ static int set_rate_pixel(struct clk *clk, unsigned long rate) { struct rcg_clk *rcg = to_rcg_clk(clk); struct clk_freq_tbl *pixel_freq = rcg->current_freq; - int frac_num[] = {3, 2, 4, 1}; - int frac_den[] = {8, 9, 9, 1}; + int frac_num[] = {1, 2, 4, 3, 2}; + int frac_den[] = {1, 3, 9, 8, 9}; int delta = 100000; int i, rc; diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c index eb69ed35f46d..040707e58e25 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c @@ -152,8 +152,6 @@ struct dsi_pll_regs { struct dsi_pll_config { u32 ref_freq; - bool div_override; - u32 output_div; bool ignore_frac; bool disable_prescaler; bool enable_ssc; @@ -212,7 +210,6 @@ static void dsi_pll_setup_config(struct dsi_pll_8998 *pll, struct dsi_pll_config *config = &pll->pll_configuration; config->ref_freq = 19200000; - config->output_div = 1; config->dec_bits = 8; config->frac_bits = 18; config->lock_timer = 64; @@ -222,7 +219,6 @@ static void dsi_pll_setup_config(struct dsi_pll_8998 *pll, config->thresh_cycles = 32; config->refclk_cycles = 256; - config->div_override = false; config->ignore_frac = false; config->disable_prescaler = false; config->enable_ssc = rsc->ssc_en; @@ -243,54 +239,14 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_8998 *pll, { struct dsi_pll_config *config = &pll->pll_configuration; struct dsi_pll_regs *regs = &pll->reg_setup; - u64 target_freq; u64 fref = rsc->vco_ref_clk_rate; - u32 computed_output_div, div_log = 0; u64 pll_freq; u64 divider; u64 dec, dec_multiple; u32 frac; u64 multiplier; - u32 i; - - target_freq = rsc->vco_current_rate; - pr_debug("target_freq = %llu\n", target_freq); - - if (config->div_override) { - computed_output_div = config->output_div; - - /* - * Computed_output_div = 2 ^ div_log - * To get div_log from output div just get the index of the - * 1 bit in the value. - * div_log ranges from 0-3. so check the 4 lsbs - */ - - for (i = 0; i < 4; i++) { - if (computed_output_div & (1 << i)) { - div_log = i; - break; - } - } - - } else { - if (target_freq < MHZ_250) { - computed_output_div = 8; - div_log = 3; - } else if (target_freq < MHZ_500) { - computed_output_div = 4; - div_log = 2; - } else if (target_freq < MHZ_1000) { - computed_output_div = 2; - div_log = 1; - } else { - computed_output_div = 1; - div_log = 0; - } - } - pr_debug("computed_output_div = %d\n", computed_output_div); - pll_freq = target_freq * computed_output_div; + pll_freq = rsc->vco_current_rate; if (config->disable_prescaler) divider = fref; @@ -315,7 +271,6 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_8998 *pll, else regs->pll_clock_inverters = 0; - regs->pll_outdiv_rate = div_log; regs->pll_lockdet_rate = config->lock_timer; regs->decimal_div_start = dec; regs->frac_div_start_low = (frac & 0xff); @@ -478,7 +433,6 @@ static void dsi_pll_commit(struct dsi_pll_8998 *pll, MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1, reg->frac_div_start_high); MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40); - MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate); MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06); MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10); MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters); @@ -597,11 +551,23 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) { int rc; struct mdss_pll_resources *rsc = vco->priv; + struct dsi_pll_8998 *pll = rsc->priv; + struct dsi_pll_regs *regs = &pll->reg_setup; dsi_pll_enable_pll_bias(rsc); if (rsc->slave) dsi_pll_enable_pll_bias(rsc->slave); + /* + * The PLL out dividers are fixed divider clocks and hence the + * set_div is not called during set_rate cycle of the tree. + * The outdiv rate is therefore set in the pll out mux's set_sel + * callback. But that will be called only after vco's set rate. + * Hence PLL out div value is set here before locking the PLL. + */ + MDSS_PLL_REG_W(rsc->pll_base, PLL_PLL_OUTDIV_RATE, + regs->pll_outdiv_rate); + /* Start PLL */ MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01); @@ -728,7 +694,9 @@ static int vco_8998_prepare(struct clk *c) static unsigned long dsi_pll_get_vco_rate(struct clk *c) { struct dsi_pll_vco_clk *vco = to_vco_clk(c); - struct mdss_pll_resources *pll = vco->priv; + struct mdss_pll_resources *rsc = vco->priv; + struct dsi_pll_8998 *pll = rsc->priv; + struct dsi_pll_regs *regs = &pll->reg_setup; int rc; u64 ref_clk = vco->ref_clk_rate; u64 vco_rate; @@ -738,27 +706,30 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) u32 outdiv; u64 pll_freq, tmp64; - rc = mdss_pll_resource_enable(pll, true); + rc = mdss_pll_resource_enable(rsc, true); if (rc) { pr_err("failed to enable pll(%d) resource, rc=%d\n", - pll->index, rc); + rsc->index, rc); return 0; } - dec = MDSS_PLL_REG_R(pll->pll_base, PLL_DECIMAL_DIV_START_1); + dec = MDSS_PLL_REG_R(rsc->pll_base, PLL_DECIMAL_DIV_START_1); dec &= 0xFF; - frac = MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_LOW_1); - frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_MID_1) & + frac = MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_LOW_1); + frac |= ((MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_MID_1) & 0xFF) << 8); - frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_HIGH_1) & + frac |= ((MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_HIGH_1) & 0x3) << 16); /* OUTDIV_1:0 field is (log(outdiv, 2)) */ - outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE); + outdiv = MDSS_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE); outdiv &= 0x3; + + regs->pll_outdiv_rate = outdiv; + outdiv = 1 << outdiv; /* @@ -776,7 +747,7 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) pr_debug("dec=0x%x, frac=0x%x, outdiv=%d, vco=%llu\n", dec, frac, outdiv, vco_rate); - (void)mdss_pll_resource_enable(pll, false); + (void)mdss_pll_resource_enable(rsc, false); return (unsigned long)vco_rate; } @@ -930,6 +901,26 @@ static int bit_clk_set_div(struct div_clk *clk, int div) return rc; } +static int dsi_pll_out_set_mux_sel(struct mux_clk *clk, int sel) +{ + struct mdss_pll_resources *rsc = clk->priv; + struct dsi_pll_8998 *pll = rsc->priv; + struct dsi_pll_regs *regs = &pll->reg_setup; + + regs->pll_outdiv_rate = sel; + + return 0; +} + +static int dsi_pll_out_get_mux_sel(struct mux_clk *clk) +{ + struct mdss_pll_resources *rsc = clk->priv; + struct dsi_pll_8998 *pll = rsc->priv; + struct dsi_pll_regs *regs = &pll->reg_setup; + + return regs->pll_outdiv_rate; +} + static int post_vco_clk_get_div(struct div_clk *clk) { int rc; @@ -1125,52 +1116,75 @@ static struct clk_mux_ops mdss_mux_ops = { .get_mux_sel = mdss_get_mux_sel, }; +static struct clk_mux_ops mdss_pll_out_mux_ops = { + .set_mux_sel = dsi_pll_out_set_mux_sel, + .get_mux_sel = dsi_pll_out_get_mux_sel, +}; + /* * Clock tree for generating DSI byte and pixel clocks. * - * - * +---------------+ - * | vco_clk | - * +-------+-------+ - * | - * +----------------------+------------------+ - * | | | - * +-------v-------+ +-------v-------+ +-------v-------+ - * | bitclk_src | | post_vco_div1 | | post_vco_div4 | - * | DIV(1..15) | +-------+-------+ +-------+-------+ - * +-------+-------+ | | - * | +------------+ | - * +--------------------+ | | - * Shadow Path | | | | - * + +-------v-------+ +------v------+ +---v-----v------+ - * | | byteclk_src | |post_bit_div | \ post_vco_mux / - * | | DIV(8) | |DIV(1,2) | \ / - * | +-------+-------+ +------+------+ +---+------+ - * | | | | - * | | +------+ +----+ - * | +--------+ | | - * | | +----v-----v------+ - * +-v---------v----+ \ pclk_src_mux / - * \ byteclk_mux / \ / - * \ / +-----+-----+ - * +----+-----+ | Shadow Path - * | | + - * v +-----v------+ | - * dsi_byte_clk | pclk_src | | - * | DIV(1..15) | | - * +-----+------+ | - * | | - * | | - * +--------+ | - * | | - * +---v----v----+ - * \ pclk_mux / - * \ / - * +---+---+ - * | - * | - * v - * dsi_pclk + * +---------------+ + * | vco_clk | + * | | + * +-------+-------+ + * | + * | + * +-------+--------+------------------+-----------------+ + * | | | | + * +------v-------+ +------v-------+ +-------v------+ +------v-------+ + * | pll_out_div1 | | pll_out_div2 | | pll_out_div4 | | pll_out_div8 | + * | DIV(1) | | DIV(2) | | DIV(4) | | DIV(8) | + * +------+-------+ +------+-------+ +-------+------+ +------+-------+ + * | | | | + * +------------+ | +--------------+ | + * | | | +---------------------------+ + * | | | | + * +--v---v---v----v--+ + * \ pll_out_mux / + * \ / + * +------+-----+ + * | + * +---------------+-----------------+ + * | | | + * +------v-----+ +-------v-------+ +-------v-------+ + * | bitclk_src | | post_vco_div1 | | post_vco_div4 | + * | DIV(1..15) | + DIV(1) | | DIV(4) | + * +------+-----+ +-------+-------+ +-------+-------+ + * | | | + * Shadow | | +---------------------+ + * Path | +-----------------------------+ | + * + | | | + * | +---------------------------------+ | | + * | | | | | + * | +------v------=+ +------v-------+ +-v---------v----+ + * | | byteclk_src | | post_bit_div | \ post_vco_mux / + * | | DIV(8) | | DIV(1,2) | \ / + * | +------+-------+ +------+-------+ +---+------+ + * | | | | + * | | | +----------+ + * | | | | + * | | +----v-----v------+ + * +-v--------v---------+ \ pclk_src_mux / + * \ byteclk_mux / \ / + * \ / +-----+-----+ + * +------+-------+ | Shadow + * | | Path + * v +-----v------+ + + * dsi_byte_clk | pclk_src | | + * | DIV(1..15) | | + * +-----+------+ | + * | | + * +------+ | + * | | + * +---v----v----+ + * \ pclk_mux / + * \ / + * +---+---+ + * | + * | + * v + * dsi_pclk * */ @@ -1186,6 +1200,83 @@ static struct dsi_pll_vco_clk dsi0pll_vco_clk = { }, }; +static struct div_clk dsi0pll_pll_out_div1 = { + .data = { + .div = 1, + .min_div = 1, + .max_div = 1, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_pll_out_div1", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pll_out_div1.c), + } +}; + +static struct div_clk dsi0pll_pll_out_div2 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_pll_out_div2", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pll_out_div2.c), + } +}; + +static struct div_clk dsi0pll_pll_out_div4 = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_pll_out_div4", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pll_out_div4.c), + } +}; + +static struct div_clk dsi0pll_pll_out_div8 = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_pll_out_div8", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pll_out_div8.c), + } +}; + +static struct mux_clk dsi0pll_pll_out_mux = { + .num_parents = 4, + .parents = (struct clk_src[]) { + {&dsi0pll_pll_out_div1.c, 0}, + {&dsi0pll_pll_out_div2.c, 1}, + {&dsi0pll_pll_out_div4.c, 2}, + {&dsi0pll_pll_out_div8.c, 3}, + }, + .ops = &mdss_pll_out_mux_ops, + .c = { + .parent = &dsi0pll_pll_out_div1.c, + .dbg_name = "dsi0pll_pll_out_mux", + .ops = &clk_ops_gen_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pll_out_mux.c), + } +}; static struct div_clk dsi0pll_bitclk_src = { .data = { .div = 1, @@ -1194,7 +1285,7 @@ static struct div_clk dsi0pll_bitclk_src = { }, .ops = &clk_bitclk_src_ops, .c = { - .parent = &dsi0pll_vco_clk.c, + .parent = &dsi0pll_pll_out_mux.c, .dbg_name = "dsi0pll_bitclk_src", .ops = &clk_ops_bitclk_src_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1210,7 +1301,7 @@ static struct div_clk dsi0pll_post_vco_div1 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi0pll_vco_clk.c, + .parent = &dsi0pll_pll_out_mux.c, .dbg_name = "dsi0pll_post_vco_div1", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1226,7 +1317,7 @@ static struct div_clk dsi0pll_post_vco_div4 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi0pll_vco_clk.c, + .parent = &dsi0pll_pll_out_mux.c, .dbg_name = "dsi0pll_post_vco_div4", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1355,6 +1446,84 @@ static struct dsi_pll_vco_clk dsi1pll_vco_clk = { }, }; +static struct div_clk dsi1pll_pll_out_div1 = { + .data = { + .div = 1, + .min_div = 1, + .max_div = 1, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_pll_out_div1", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pll_out_div1.c), + } +}; + +static struct div_clk dsi1pll_pll_out_div2 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_pll_out_div2", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pll_out_div2.c), + } +}; + +static struct div_clk dsi1pll_pll_out_div4 = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_pll_out_div4", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pll_out_div4.c), + } +}; + +static struct div_clk dsi1pll_pll_out_div8 = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_pll_out_div8", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pll_out_div8.c), + } +}; + +static struct mux_clk dsi1pll_pll_out_mux = { + .num_parents = 4, + .parents = (struct clk_src[]) { + {&dsi1pll_pll_out_div1.c, 0}, + {&dsi1pll_pll_out_div2.c, 1}, + {&dsi1pll_pll_out_div4.c, 2}, + {&dsi1pll_pll_out_div8.c, 3}, + }, + .ops = &mdss_pll_out_mux_ops, + .c = { + .parent = &dsi1pll_pll_out_div1.c, + .dbg_name = "dsi1pll_pll_out_mux", + .ops = &clk_ops_gen_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pll_out_mux.c), + } +}; + static struct div_clk dsi1pll_bitclk_src = { .data = { .div = 1, @@ -1363,7 +1532,7 @@ static struct div_clk dsi1pll_bitclk_src = { }, .ops = &clk_bitclk_src_ops, .c = { - .parent = &dsi1pll_vco_clk.c, + .parent = &dsi1pll_pll_out_mux.c, .dbg_name = "dsi1pll_bitclk_src", .ops = &clk_ops_bitclk_src_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1379,7 +1548,7 @@ static struct div_clk dsi1pll_post_vco_div1 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi1pll_vco_clk.c, + .parent = &dsi1pll_pll_out_mux.c, .dbg_name = "dsi1pll_post_vco_div1", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1395,7 +1564,7 @@ static struct div_clk dsi1pll_post_vco_div4 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi1pll_vco_clk.c, + .parent = &dsi1pll_pll_out_mux.c, .dbg_name = "dsi1pll_post_vco_div4", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1523,6 +1692,11 @@ static struct clk_lookup mdss_dsi_pll0cc_8998[] = { CLK_LIST(dsi0pll_post_vco_div1), CLK_LIST(dsi0pll_post_vco_div4), CLK_LIST(dsi0pll_bitclk_src), + CLK_LIST(dsi0pll_pll_out_mux), + CLK_LIST(dsi0pll_pll_out_div8), + CLK_LIST(dsi0pll_pll_out_div4), + CLK_LIST(dsi0pll_pll_out_div2), + CLK_LIST(dsi0pll_pll_out_div1), CLK_LIST(dsi0pll_vco_clk), }; static struct clk_lookup mdss_dsi_pll1cc_8998[] = { @@ -1536,6 +1710,11 @@ static struct clk_lookup mdss_dsi_pll1cc_8998[] = { CLK_LIST(dsi1pll_post_vco_div1), CLK_LIST(dsi1pll_post_vco_div4), CLK_LIST(dsi1pll_bitclk_src), + CLK_LIST(dsi1pll_pll_out_mux), + CLK_LIST(dsi1pll_pll_out_div8), + CLK_LIST(dsi1pll_pll_out_div4), + CLK_LIST(dsi1pll_pll_out_div2), + CLK_LIST(dsi1pll_pll_out_div1), CLK_LIST(dsi1pll_vco_clk), }; @@ -1596,6 +1775,11 @@ int dsi_pll_clock_register_8998(struct platform_device *pdev, dsi0pll_post_vco_div1.priv = pll_res; dsi0pll_post_vco_div4.priv = pll_res; dsi0pll_bitclk_src.priv = pll_res; + dsi0pll_pll_out_div1.priv = pll_res; + dsi0pll_pll_out_div2.priv = pll_res; + dsi0pll_pll_out_div4.priv = pll_res; + dsi0pll_pll_out_div8.priv = pll_res; + dsi0pll_pll_out_mux.priv = pll_res; dsi0pll_vco_clk.priv = pll_res; rc = of_msm_clock_register(pdev->dev.of_node, @@ -1612,6 +1796,11 @@ int dsi_pll_clock_register_8998(struct platform_device *pdev, dsi1pll_post_vco_div1.priv = pll_res; dsi1pll_post_vco_div4.priv = pll_res; dsi1pll_bitclk_src.priv = pll_res; + dsi1pll_pll_out_div1.priv = pll_res; + dsi1pll_pll_out_div2.priv = pll_res; + dsi1pll_pll_out_div4.priv = pll_res; + dsi1pll_pll_out_div8.priv = pll_res; + dsi1pll_pll_out_mux.priv = pll_res; dsi1pll_vco_clk.priv = pll_res; rc = of_msm_clock_register(pdev->dev.of_node, diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index b91e115462ae..abbee61c99c8 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -479,6 +479,7 @@ static void cpufreq_interactive_timer(unsigned long data) bool skip_hispeed_logic, skip_min_sample_time; bool jump_to_max_no_ts = false; bool jump_to_max = false; + bool start_hyst = true; if (!down_read_trylock(&ppol->enable_sem)) return; @@ -588,8 +589,12 @@ static void cpufreq_interactive_timer(unsigned long data) } if (now - ppol->max_freq_hyst_start_time < - tunables->max_freq_hysteresis) + tunables->max_freq_hysteresis) { + if (new_freq < ppol->policy->max && + ppol->policy->max <= tunables->hispeed_freq) + start_hyst = false; new_freq = max(tunables->hispeed_freq, new_freq); + } if (!skip_hispeed_logic && ppol->target_freq >= tunables->hispeed_freq && @@ -646,7 +651,7 @@ static void cpufreq_interactive_timer(unsigned long data) ppol->floor_validate_time = now; } - if (new_freq >= ppol->policy->max && !jump_to_max_no_ts) + if (start_hyst && new_freq >= ppol->policy->max && !jump_to_max_no_ts) ppol->max_freq_hyst_start_time = now; if (ppol->target_freq == new_freq && diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index f83a888e2129..490f8d9ddb9f 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1433,7 +1433,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, int ret = 0; bool is_pfe = false; - if (!pdev || !req || !setting) { + if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); return -EINVAL; } diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index 26f69fa61ba1..6eab3ea187c6 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -88,12 +88,10 @@ static void mdm_enable_irqs(struct mdm_ctrl *mdm) return; if (mdm->irq_mask & IRQ_ERRFATAL) { enable_irq(mdm->errfatal_irq); - irq_set_irq_wake(mdm->errfatal_irq, 1); mdm->irq_mask &= ~IRQ_ERRFATAL; } if (mdm->irq_mask & IRQ_STATUS) { enable_irq(mdm->status_irq); - irq_set_irq_wake(mdm->status_irq, 1); mdm->irq_mask &= ~IRQ_STATUS; } if (mdm->irq_mask & IRQ_PBLRDY) { @@ -107,12 +105,10 @@ static void mdm_disable_irqs(struct mdm_ctrl *mdm) if (!mdm) return; if (!(mdm->irq_mask & IRQ_ERRFATAL)) { - irq_set_irq_wake(mdm->errfatal_irq, 0); disable_irq_nosync(mdm->errfatal_irq); mdm->irq_mask |= IRQ_ERRFATAL; } if (!(mdm->irq_mask & IRQ_STATUS)) { - irq_set_irq_wake(mdm->status_irq, 0); disable_irq_nosync(mdm->status_irq); mdm->irq_mask |= IRQ_STATUS; } @@ -701,6 +697,7 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev) goto errfatal_err; } mdm->errfatal_irq = irq; + irq_set_irq_wake(mdm->errfatal_irq, 1); errfatal_err: /* status irq */ @@ -719,6 +716,7 @@ errfatal_err: goto status_err; } mdm->status_irq = irq; + irq_set_irq_wake(mdm->status_irq, 1); status_err: if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) { irq = platform_get_irq_byname(pdev, "plbrdy_irq"); diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 84125b3d1f95..4c082fff2fc5 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -48,6 +48,7 @@ msm_drm-y := \ sde/sde_backlight.o \ sde/sde_color_processing.o \ sde/sde_vbif.o \ + sde/sde_splash.o \ sde_dbg_evtlog.o \ sde_io_util.o \ dba_bridge.o \ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index e24827590b7c..c085e173232b 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -409,8 +409,8 @@ static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) gpu->funcs->pm_resume(gpu); seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A3XX_RBBM_STATUS)); - gpu->funcs->pm_suspend(gpu); adreno_show(gpu, m); + gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index b612c9a18faf..624c2a87d593 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -447,9 +447,9 @@ static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m) seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A4XX_RBBM_STATUS)); - gpu->funcs->pm_suspend(gpu); adreno_show(gpu, m); + gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 37323e962c2c..45a38b247727 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -375,6 +375,7 @@ static const struct { void a5xx_set_hwcg(struct msm_gpu *gpu, bool state) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); unsigned int i; for (i = 0; i < ARRAY_SIZE(a5xx_hwcg); i++) @@ -391,6 +392,11 @@ void a5xx_set_hwcg(struct msm_gpu *gpu, bool state) gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, state ? 0xAAA8AA00 : 0); gpu_write(gpu, REG_A5XX_RBBM_ISDB_CNT, state ? 0x182 : 0x180); + + if (state) + set_bit(A5XX_HWCG_ENABLED, &a5xx_gpu->flags); + else + clear_bit(A5XX_HWCG_ENABLED, &a5xx_gpu->flags); } static int a5xx_me_init(struct msm_gpu *gpu) @@ -1168,6 +1174,10 @@ static int a5xx_pm_resume(struct msm_gpu *gpu) if (ret) return ret; + /* If we are already up, don't mess with what works */ + if (gpu->active_cnt > 1) + return 0; + /* Turn the RBCCU domain first to limit the chances of voltage droop */ gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000); @@ -1198,22 +1208,27 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - /* Clear the VBIF pipe before shutting down */ + /* Only do this next bit if we are about to go down */ + if (gpu->active_cnt == 1) { + /* Clear the VBIF pipe before shutting down */ - gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); - spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) == 0xF); + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); + spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) + == 0xF); - gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); - /* - * Reset the VBIF before power collapse to avoid issue with FIFO - * entries - */ - - if (adreno_is_a530(adreno_gpu)) { - /* These only need to be done for A530 */ - gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x003C0000); - gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x00000000); + /* + * Reset the VBIF before power collapse to avoid issue with FIFO + * entries + */ + if (adreno_is_a530(adreno_gpu)) { + /* These only need to be done for A530 */ + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, + 0x003C0000); + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, + 0x00000000); + } } return msm_gpu_pm_suspend(gpu); @@ -1233,13 +1248,29 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) #ifdef CONFIG_DEBUG_FS static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + bool enabled = test_bit(A5XX_HWCG_ENABLED, &a5xx_gpu->flags); + gpu->funcs->pm_resume(gpu); seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A5XX_RBBM_STATUS)); - gpu->funcs->pm_suspend(gpu); + + /* + * Temporarily disable hardware clock gating before going into + * adreno_show to avoid issues while reading the registers + */ + + if (enabled) + a5xx_set_hwcg(gpu, false); adreno_show(gpu, m); + + if (enabled) + a5xx_set_hwcg(gpu, true); + + gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h index f8b00982fe86..e637237fa811 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -23,6 +23,7 @@ enum { A5XX_ZAP_SHADER_LOADED = 1, + A5XX_HWCG_ENABLED = 2, }; struct a5xx_gpu { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 2273b06b59a6..04e0056f2a49 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -297,8 +297,6 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) seq_printf(m, "rb wptr: %d\n", get_wptr(ring)); } - gpu->funcs->pm_resume(gpu); - /* dump these out in a form that can be parsed by demsm: */ seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name); for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { @@ -311,8 +309,6 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); } } - - gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 1b295949122b..f1c44b30575f 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -1253,6 +1253,13 @@ static int _sde_hdmi_hpd_enable(struct sde_hdmi *sde_hdmi) uint32_t hpd_ctrl; int i, ret; unsigned long flags; + struct drm_connector *connector; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + connector = hdmi->connector; + priv = connector->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); for (i = 0; i < config->hpd_reg_cnt; i++) { ret = regulator_enable(hdmi->hpd_regs[i]); @@ -1292,9 +1299,11 @@ static int _sde_hdmi_hpd_enable(struct sde_hdmi *sde_hdmi) } } - sde_hdmi_set_mode(hdmi, false); - _sde_hdmi_phy_reset(hdmi); - sde_hdmi_set_mode(hdmi, true); + if (!sde_kms->splash_info.handoff) { + sde_hdmi_set_mode(hdmi, false); + _sde_hdmi_phy_reset(hdmi); + sde_hdmi_set_mode(hdmi, true); + } hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b); @@ -1961,6 +1970,30 @@ enable_packet_control: hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); } +static void sde_hdmi_clear_hdr_infoframe(struct sde_hdmi *display) +{ + struct hdmi *hdmi; + struct drm_connector *connector; + u32 packet_control = 0; + + if (!display) { + SDE_ERROR("invalid input\n"); + return; + } + + hdmi = display->ctrl.ctrl; + connector = display->ctrl.ctrl->connector; + + if (!hdmi || !connector) { + SDE_ERROR("invalid input\n"); + return; + } + + packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK; + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); +} + int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, @@ -2305,15 +2338,28 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector, void *display, struct msm_display_kickoff_params *params) { + struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; + struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; + u8 hdr_op; if (!connector || !display || !params) { pr_err("Invalid params\n"); return -EINVAL; } - if (connector->hdr_supported) - sde_hdmi_panel_set_hdr_infoframe(display, - params->hdr_metadata); + hdr_ctrl = params->hdr_ctrl; + + hdr_op = sde_hdmi_hdr_get_ops(hdmi_display->curr_hdr_state, + hdr_ctrl->hdr_state); + + if (hdr_op == HDR_SEND_INFO) { + if (connector->hdr_supported) + sde_hdmi_panel_set_hdr_infoframe(display, + &hdr_ctrl->hdr_meta); + } else if (hdr_op == HDR_CLEAR_INFO) + sde_hdmi_clear_hdr_infoframe(display); + + hdmi_display->curr_hdr_state = hdr_ctrl->hdr_state; return 0; } @@ -2826,6 +2872,7 @@ int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) struct msm_drm_private *priv = NULL; struct hdmi *hdmi; struct platform_device *pdev; + struct sde_kms *sde_kms; DBG(""); if (!display || !display->drm_dev || !enc) { @@ -2884,6 +2931,19 @@ int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) enc->bridge = hdmi->bridge; priv->bridges[priv->num_bridges++] = hdmi->bridge; + /* + * After initialising HDMI bridge, we need to check + * whether the early display is enabled for HDMI. + * If yes, we need to increase refcount of hdmi power + * clocks. This can skip the clock disabling operation in + * clock_late_init when finding clk.count == 1. + */ + sde_kms = to_sde_kms(priv->kms); + if (sde_kms->splash_info.handoff) { + sde_hdmi_bridge_power_on(hdmi->bridge); + hdmi->power_on = true; + } + mutex_unlock(&display->display_lock); return 0; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 743d34d05e57..f2dd5351913b 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -147,6 +147,7 @@ struct sde_hdmi { u32 hdcp22_present; u8 hdcp_status; u32 enc_lvl; + u8 curr_hdr_state; bool auth_state; bool sink_hdcp22_support; bool src_hdcp22_support; @@ -198,6 +199,8 @@ enum hdmi_tx_scdc_access_type { #define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 #define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 +#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7 + /* Maximum pixel clock rates for hdmi tx */ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 #define HDMI_TX_3_MAX_PCLK_RATE 297000 @@ -354,6 +357,13 @@ int sde_hdmi_set_property(struct drm_connector *connector, int property_index, uint64_t value, void *display); +/** + * sde_hdmi_bridge_power_on -- A wrapper of _sde_hdmi_bridge_power_on. + * @bridge: Handle to the drm bridge. + * + * Return: void. + */ +void sde_hdmi_bridge_power_on(struct drm_bridge *bridge); /** * sde_hdmi_get_property() - get the connector properties diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index a4c3c2e7ce46..e4eb531c12aa 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -518,12 +518,17 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; /* need to update hdcp info here to ensure right HDCP support*/ sde_hdmi_update_hdcp_info(hdmi->connector); /* start HDCP authentication */ sde_hdmi_start_hdcp(hdmi->connector); + + /* reset HDR state */ + display->curr_hdr_state = HDR_DISABLE; } static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) @@ -836,6 +841,11 @@ static bool _sde_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, return true; } +void sde_hdmi_bridge_power_on(struct drm_bridge *bridge) +{ + _sde_hdmi_bridge_power_on(bridge); +} + static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { .pre_enable = _sde_hdmi_bridge_pre_enable, .enable = _sde_hdmi_bridge_enable, diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c index ba47b7702efd..a291a1112aeb 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c @@ -68,6 +68,15 @@ static void sde_hdmi_hdcp2p2_ddc_clear_status(struct sde_hdmi *display) hdmi_write(hdmi, HDMI_HDCP2P2_DDC_STATUS, reg_val); } +static const char *sde_hdmi_hdr_sname(enum sde_hdmi_hdr_state hdr_state) +{ + switch (hdr_state) { + case HDR_DISABLE: return "HDR_DISABLE"; + case HDR_ENABLE: return "HDR_ENABLE"; + default: return "HDR_INVALID_STATE"; + } +} + /** * sde_hdmi_dump_regs - utility to dump HDMI regs * @hdmi_display: Pointer to private display handle @@ -898,3 +907,50 @@ int sde_hdmi_sink_dc_support(struct drm_connector *connector, return dc_format; } + +u8 sde_hdmi_hdr_get_ops(u8 curr_state, + u8 new_state) +{ + + /** There could be 3 valid state transitions: + * 1. HDR_DISABLE -> HDR_ENABLE + * + * In this transition, we shall start sending + * HDR metadata with metadata from the HDR clip + * + * 2. HDR_ENABLE -> HDR_ENABLE + * + * In this transition, we will keep sending + * HDR metadata but with EOTF and metadata as 0 + * + * 3. HDR_ENABLE -> HDR_DISABLE + * + * In this transition, we will stop sending + * metadata to the sink and clear PKT_CTRL register + * bits. + */ + + if ((curr_state == HDR_DISABLE) + && (new_state == HDR_ENABLE)) { + HDMI_UTIL_DEBUG("State changed %s ---> %s\n", + sde_hdmi_hdr_sname(curr_state), + sde_hdmi_hdr_sname(new_state)); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_ENABLE) + && (new_state == HDR_ENABLE)) { + HDMI_UTIL_DEBUG("State changed %s ---> %s\n", + sde_hdmi_hdr_sname(curr_state), + sde_hdmi_hdr_sname(new_state)); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_ENABLE) + && (new_state == HDR_DISABLE)) { + HDMI_UTIL_DEBUG("State changed %s ---> %s\n", + sde_hdmi_hdr_sname(curr_state), + sde_hdmi_hdr_sname(new_state)); + return HDR_CLEAR_INFO; + } + + HDMI_UTIL_DEBUG("Unsupported OR no state change\n"); + return HDR_UNSUPPORTED_OP; +} + diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 10effed54a14..1d89ae222a7b 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -125,6 +125,17 @@ enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask { RXSTATUS_REAUTH_REQ = BIT(14), }; +enum sde_hdmi_hdr_state { + HDR_DISABLE, + HDR_ENABLE +}; + +enum sde_hdmi_hdr_op { + HDR_UNSUPPORTED_OP, + HDR_SEND_INFO, + HDR_CLEAR_INFO +}; + struct sde_hdmi_tx_hdcp2p2_ddc_data { enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask; u32 timeout_ms; @@ -170,4 +181,6 @@ bool sde_hdmi_validate_pixclk(struct drm_connector *connector, unsigned long pclk); int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode); +u8 sde_hdmi_hdr_get_ops(u8 curr_state, + u8 new_state); #endif /* _SDE_HDMI_UTIL_H_ */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 924ce64206f4..c8b11425a817 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1923,8 +1923,75 @@ static struct drm_driver msm_driver = { #ifdef CONFIG_PM_SLEEP static int msm_pm_suspend(struct device *dev) { - struct drm_device *ddev = dev_get_drvdata(dev); + struct drm_device *ddev; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector *conn; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct msm_drm_private *priv; + int ret = 0; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev->dev_private) + return -EINVAL; + + priv = ddev->dev_private; + SDE_EVT32(0); + + /* acquire modeset lock(s) */ + drm_modeset_lock_all(ddev); + ctx = ddev->mode_config.acquire_ctx; + + /* save current state for resume */ + if (priv->suspend_state) + drm_atomic_state_free(priv->suspend_state); + priv->suspend_state = drm_atomic_helper_duplicate_state(ddev, ctx); + if (IS_ERR_OR_NULL(priv->suspend_state)) { + DRM_ERROR("failed to back up suspend state\n"); + priv->suspend_state = NULL; + goto unlock; + } + + /* create atomic state to disable all CRTCs */ + state = drm_atomic_state_alloc(ddev); + if (IS_ERR_OR_NULL(state)) { + DRM_ERROR("failed to allocate crtc disable state\n"); + goto unlock; + } + + state->acquire_ctx = ctx; + drm_for_each_connector(conn, ddev) { + + if (!conn->state || !conn->state->crtc || + conn->dpms != DRM_MODE_DPMS_ON) + continue; + + /* force CRTC to be inactive */ + crtc_state = drm_atomic_get_crtc_state(state, + conn->state->crtc); + if (IS_ERR_OR_NULL(crtc_state)) { + DRM_ERROR("failed to get crtc %d state\n", + conn->state->crtc->base.id); + drm_atomic_state_free(state); + goto unlock; + } + crtc_state->active = false; + } + /* commit the "disable all" state */ + ret = drm_atomic_commit(state); + if (ret < 0) { + DRM_ERROR("failed to disable crtcs, %d\n", ret); + drm_atomic_state_free(state); + } + +unlock: + drm_modeset_unlock_all(ddev); + + /* disable hot-plug polling */ drm_kms_helper_poll_disable(ddev); return 0; @@ -1932,8 +1999,38 @@ static int msm_pm_suspend(struct device *dev) static int msm_pm_resume(struct device *dev) { - struct drm_device *ddev = dev_get_drvdata(dev); + struct drm_device *ddev; + struct msm_drm_private *priv; + int ret; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev->dev_private) + return -EINVAL; + + priv = ddev->dev_private; + + SDE_EVT32(priv->suspend_state != NULL); + + drm_mode_config_reset(ddev); + + drm_modeset_lock_all(ddev); + + if (priv->suspend_state) { + priv->suspend_state->acquire_ctx = + ddev->mode_config.acquire_ctx; + ret = drm_atomic_commit(priv->suspend_state); + if (ret < 0) { + DRM_ERROR("failed to restore state, %d\n", ret); + drm_atomic_state_free(priv->suspend_state); + } + priv->suspend_state = NULL; + } + drm_modeset_unlock_all(ddev); + /* enable hot-plug polling */ drm_kms_helper_poll_enable(ddev); return 0; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index ac15f399df7d..49b6029c3342 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -144,7 +144,7 @@ enum msm_mdp_conn_property { /* blob properties, always put these first */ CONNECTOR_PROP_SDE_INFO, CONNECTOR_PROP_HDR_INFO, - CONNECTOR_PROP_HDR_METADATA, + CONNECTOR_PROP_HDR_CONTROL, /* # of blob properties */ CONNECTOR_PROP_BLOBCOUNT, @@ -237,10 +237,10 @@ struct msm_display_info { /** * struct - msm_display_kickoff_params - info for display features at kickoff - * @hdr_metadata: HDR metadata info passed from userspace + * @hdr_ctrl: HDR control info passed from userspace */ struct msm_display_kickoff_params { - struct drm_msm_ext_panel_hdr_metadata *hdr_metadata; + struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; }; /** @@ -367,6 +367,9 @@ struct msm_drm_private { struct msm_vblank_ctrl vblank_ctrl; + /* saved atomic state during system suspend */ + struct drm_atomic_state *suspend_state; + /* list of clients waiting for events */ struct list_head client_event_list; }; @@ -414,6 +417,15 @@ void __msm_fence_worker(struct work_struct *work); (_cb)->func = _func; \ } while (0) +static inline bool msm_is_suspend_state(struct drm_device *dev) +{ + if (!dev || !dev->dev_private) + return false; + + return ((struct msm_drm_private *)dev->dev_private)->suspend_state != + NULL; +} + int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async); diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 8148d3e9e850..cd3a710f8f27 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -46,6 +46,8 @@ struct msm_mmu_funcs { void (*destroy)(struct msm_mmu *mmu); void (*enable)(struct msm_mmu *mmu); void (*disable)(struct msm_mmu *mmu); + int (*set_property)(struct msm_mmu *mmu, + enum iommu_attr attr, void *data); }; struct msm_mmu { diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index eb68eb977aa7..4247243055b6 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -170,12 +170,36 @@ static void msm_smmu_destroy(struct msm_mmu *mmu) kfree(smmu); } +/* user can call this API to set the attribute of smmu*/ +static int msm_smmu_set_property(struct msm_mmu *mmu, + enum iommu_attr attr, void *data) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + struct iommu_domain *domain; + int ret = 0; + + if (!client) + return -EINVAL; + + domain = client->mmu_mapping->domain; + if (!domain) + return -EINVAL; + + ret = iommu_domain_set_attr(domain, attr, data); + if (ret) + DRM_ERROR("set domain attribute failed\n"); + + return ret; +} + static const struct msm_mmu_funcs funcs = { .attach = msm_smmu_attach, .detach = msm_smmu_detach, .map = msm_smmu_map, .unmap = msm_smmu_unmap, .destroy = msm_smmu_destroy, + .set_property = msm_smmu_set_property, }; static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = { diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 76e6e4ef6e7d..6cc54d15beb2 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -83,7 +83,7 @@ int sde_connector_pre_kickoff(struct drm_connector *connector) if (!c_conn->ops.pre_kickoff) return 0; - params.hdr_metadata = &c_state->hdr_meta; + params.hdr_ctrl = &c_state->hdr_ctrl; rc = c_conn->ops.pre_kickoff(connector, c_conn->display, ¶ms); @@ -247,6 +247,7 @@ static int _sde_connector_set_hdr_info( void *usr_ptr) { struct drm_connector *connector; + struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; struct drm_msm_ext_panel_hdr_metadata *hdr_meta; int i; @@ -262,21 +263,26 @@ static int _sde_connector_set_hdr_info( return -ENOTSUPP; } - memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); + memset(&c_state->hdr_ctrl, 0, sizeof(c_state->hdr_ctrl)); if (!usr_ptr) { - SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n"); + SDE_DEBUG_CONN(c_conn, "hdr control cleared\n"); return 0; } - if (copy_from_user(&c_state->hdr_meta, + if (copy_from_user(&c_state->hdr_ctrl, (void __user *)usr_ptr, - sizeof(*hdr_meta))) { - SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n"); + sizeof(*hdr_ctrl))) { + SDE_ERROR_CONN(c_conn, "failed to copy hdr control\n"); return -EFAULT; } - hdr_meta = &c_state->hdr_meta; + hdr_ctrl = &c_state->hdr_ctrl; + + SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", + hdr_ctrl->hdr_state); + + hdr_meta = &hdr_ctrl->hdr_meta; SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", hdr_meta->hdr_supported); @@ -362,7 +368,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, SDE_ERROR("invalid topology_control: 0x%llX\n", val); } - if (idx == CONNECTOR_PROP_HDR_METADATA) { + if (idx == CONNECTOR_PROP_HDR_CONTROL) { rc = _sde_connector_set_hdr_info(c_conn, c_state, (void *)val); if (rc) SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); @@ -598,6 +604,7 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, struct sde_kms *sde_kms; struct sde_kms_info *info; struct sde_connector *c_conn = NULL; + struct sde_splash_info *sinfo; int rc; if (!dev || !dev->dev_private || !encoder) { @@ -718,8 +725,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, } msm_property_install_volatile_range(&c_conn->property_info, - "hdr_metadata", 0x0, 0, ~0, 0, - CONNECTOR_PROP_HDR_METADATA); + "hdr_control", 0x0, 0, ~0, 0, + CONNECTOR_PROP_HDR_CONTROL); msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE", 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE); @@ -751,6 +758,10 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, SDE_DEBUG("connector %d attach encoder %d\n", c_conn->base.base.id, encoder->base.id); + sinfo = &sde_kms->splash_info; + if (sinfo && sinfo->handoff) + sde_splash_setup_connector_count(sinfo, connector_type); + priv->connectors[priv->num_connectors++] = &c_conn->base; return &c_conn->base; diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index 19e2b8a3e41c..8257f29bd4b8 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -221,14 +221,14 @@ struct sde_connector { * @out_fb: Pointer to output frame buffer, if applicable * @aspace: Address space for accessing frame buffer objects, if applicable * @property_values: Local cache of current connector property values - * @hdr_meta: HDR metadata info passed from userspace + * @hdr_ctrl: HDR control info passed from userspace */ struct sde_connector_state { struct drm_connector_state base; struct drm_framebuffer *out_fb; struct msm_gem_address_space *aspace; uint64_t property_values[CONNECTOR_PROP_COUNT]; - struct drm_msm_ext_panel_hdr_metadata hdr_meta; + struct drm_msm_ext_panel_hdr_ctrl hdr_ctrl; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 5323c0194594..9ab216213d8e 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -57,7 +57,17 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) { - struct msm_drm_private *priv = crtc->dev->dev_private; + struct msm_drm_private *priv; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid crtc\n"); + return NULL; + } + priv = crtc->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid kms\n"); + return NULL; + } return to_sde_kms(priv->kms); } @@ -77,10 +87,10 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) sde_cp_crtc_destroy_properties(crtc); debugfs_remove_recursive(sde_crtc->debugfs_root); - mutex_destroy(&sde_crtc->crtc_lock); sde_fence_deinit(&sde_crtc->output_fence); drm_crtc_cleanup(crtc); + mutex_destroy(&sde_crtc->crtc_lock); kfree(sde_crtc); } @@ -590,14 +600,22 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc, { struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; + struct drm_connector *conn; + struct drm_device *dev; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; int i; - if (!crtc || !crtc->state) { + if (!crtc || !crtc->state || !crtc->dev) { SDE_ERROR("invalid crtc\n"); return; } + dev = crtc->dev; + priv = dev->dev_private; + sde_crtc = to_sde_crtc(crtc); + sde_kms = _sde_crtc_get_kms(crtc); cstate = to_sde_crtc_state(crtc->state); SDE_EVT32(DRMID(crtc)); @@ -606,6 +624,20 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc, for (i = 0; i < cstate->num_connectors; ++i) sde_connector_complete_commit(cstate->connectors[i]); + + if (!sde_kms->splash_info.handoff && + sde_kms->splash_info.lk_is_exited) { + mutex_lock(&dev->mode_config.mutex); + drm_for_each_connector(conn, crtc->dev) { + if (conn->state->crtc != crtc) + continue; + + sde_splash_clean_up_free_resource(priv->kms, + &priv->phandle, + conn->connector_type); + } + mutex_unlock(&dev->mode_config.mutex); + } } /** @@ -941,6 +973,112 @@ end: } /** + * _sde_crtc_vblank_enable_nolock - update power resource and vblank request + * @sde_crtc: Pointer to sde crtc structure + * @enable: Whether to enable/disable vblanks + */ +static void _sde_crtc_vblank_enable_nolock( + struct sde_crtc *sde_crtc, bool enable) +{ + struct drm_device *dev; + struct drm_crtc *crtc; + struct drm_encoder *enc; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!sde_crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + crtc = &sde_crtc->base; + dev = crtc->dev; + priv = dev->dev_private; + + if (!priv->kms) { + SDE_ERROR("invalid kms\n"); + return; + } + sde_kms = to_sde_kms(priv->kms); + + if (enable) { + sde_power_resource_enable(&priv->phandle, + sde_kms->core_client, true); + list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { + if (enc->crtc != crtc) + continue; + + SDE_EVT32(DRMID(crtc), DRMID(enc), enable); + + sde_encoder_register_vblank_callback(enc, + sde_crtc_vblank_cb, (void *)crtc); + } + } else { + list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { + if (enc->crtc != crtc) + continue; + + SDE_EVT32(DRMID(crtc), DRMID(enc), enable); + + sde_encoder_register_vblank_callback(enc, NULL, NULL); + } + sde_power_resource_enable(&priv->phandle, + sde_kms->core_client, false); + } +} + +/** + * _sde_crtc_set_suspend - notify crtc of suspend enable/disable + * @crtc: Pointer to drm crtc object + * @enable: true to enable suspend, false to indicate resume + */ +static void _sde_crtc_set_suspend(struct drm_crtc *crtc, bool enable) +{ + struct sde_crtc *sde_crtc; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid crtc\n"); + return; + } + sde_crtc = to_sde_crtc(crtc); + priv = crtc->dev->dev_private; + + if (!priv->kms) { + SDE_ERROR("invalid crtc kms\n"); + return; + } + sde_kms = to_sde_kms(priv->kms); + + SDE_DEBUG("crtc%d suspend = %d\n", crtc->base.id, enable); + + mutex_lock(&sde_crtc->crtc_lock); + + /* + * Update CP on suspend/resume transitions + */ + if (enable && !sde_crtc->suspend) + sde_cp_crtc_suspend(crtc); + else if (!enable && sde_crtc->suspend) + sde_cp_crtc_resume(crtc); + + /* + * If the vblank refcount != 0, release a power reference on suspend + * and take it back during resume (if it is still != 0). + */ + if (sde_crtc->suspend == enable) + SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n", + crtc->base.id, enable); + else if (atomic_read(&sde_crtc->vblank_refcount) != 0) + _sde_crtc_vblank_enable_nolock(sde_crtc, !enable); + + sde_crtc->suspend = enable; + + mutex_unlock(&sde_crtc->crtc_lock); +} + +/** * sde_crtc_duplicate_state - state duplicate hook * @crtc: Pointer to drm crtc structure * @Returns: Pointer to new drm_crtc_state structure @@ -990,6 +1128,10 @@ static void sde_crtc_reset(struct drm_crtc *crtc) return; } + /* revert suspend actions, if necessary */ + if (msm_is_suspend_state(crtc->dev)) + _sde_crtc_set_suspend(crtc, false); + /* remove previous state, if present */ if (crtc->state) { sde_crtc_destroy_state(crtc, crtc->state); @@ -1013,37 +1155,67 @@ static void sde_crtc_reset(struct drm_crtc *crtc) crtc->state = &cstate->base; } +static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en) +{ + if (!sde_crtc) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } else if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) { + SDE_DEBUG("crtc%d vblank enable\n", sde_crtc->base.base.id); + if (!sde_crtc->suspend) + _sde_crtc_vblank_enable_nolock(sde_crtc, true); + } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) { + SDE_ERROR("crtc%d invalid vblank disable\n", + sde_crtc->base.base.id); + return -EINVAL; + } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) { + SDE_DEBUG("crtc%d vblank disable\n", sde_crtc->base.base.id); + if (!sde_crtc->suspend) + _sde_crtc_vblank_enable_nolock(sde_crtc, false); + } else { + SDE_DEBUG("crtc%d vblank %s refcount:%d\n", + sde_crtc->base.base.id, + en ? "enable" : "disable", + atomic_read(&sde_crtc->vblank_refcount)); + } + + return 0; +} + static void sde_crtc_disable(struct drm_crtc *crtc) { - struct msm_drm_private *priv; - struct sde_crtc *sde_crtc; struct drm_encoder *encoder; + struct sde_crtc *sde_crtc; struct sde_kms *sde_kms; + struct msm_drm_private *priv; - if (!crtc) { + if (!crtc || !crtc->dev || !crtc->state) { SDE_ERROR("invalid crtc\n"); return; } sde_crtc = to_sde_crtc(crtc); sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { + SDE_ERROR("invalid kms handle\n"); + return; + } priv = sde_kms->dev->dev_private; SDE_DEBUG("crtc%d\n", crtc->base.id); + if (msm_is_suspend_state(crtc->dev)) + _sde_crtc_set_suspend(crtc, true); + mutex_lock(&sde_crtc->crtc_lock); SDE_EVT32(DRMID(crtc)); - if (atomic_read(&sde_crtc->vblank_refcount)) { + if (atomic_read(&sde_crtc->vblank_refcount) && !sde_crtc->suspend) { SDE_ERROR("crtc%d invalid vblank refcount\n", crtc->base.id); - SDE_EVT32(DRMID(crtc)); - drm_for_each_encoder(encoder, crtc->dev) { - if (encoder->crtc != crtc) - continue; - sde_encoder_register_vblank_callback(encoder, NULL, - NULL); - } - atomic_set(&sde_crtc->vblank_refcount, 0); + SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->vblank_refcount)); + while (atomic_read(&sde_crtc->vblank_refcount)) + if (_sde_crtc_vblank_no_lock(sde_crtc, false)) + break; } if (atomic_read(&sde_crtc->frame_pending)) { @@ -1262,40 +1434,20 @@ end: int sde_crtc_vblank(struct drm_crtc *crtc, bool en) { - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct drm_encoder *encoder; - struct drm_device *dev = crtc->dev; + struct sde_crtc *sde_crtc; + int rc; - if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) { - SDE_DEBUG("crtc%d vblank enable\n", crtc->base.id); - } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) { - SDE_ERROR("crtc%d invalid vblank disable\n", crtc->base.id); + if (!crtc) { + SDE_ERROR("invalid crtc\n"); return -EINVAL; - } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) { - SDE_DEBUG("crtc%d vblank disable\n", crtc->base.id); - } else { - SDE_DEBUG("crtc%d vblank %s refcount:%d\n", - crtc->base.id, - en ? "enable" : "disable", - atomic_read(&sde_crtc->vblank_refcount)); - return 0; } + sde_crtc = to_sde_crtc(crtc); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc != crtc) - continue; - - SDE_EVT32(DRMID(crtc), en); - - if (en) - sde_encoder_register_vblank_callback(encoder, - sde_crtc_vblank_cb, (void *)crtc); - else - sde_encoder_register_vblank_callback(encoder, NULL, - NULL); - } + mutex_lock(&sde_crtc->crtc_lock); + rc = _sde_crtc_vblank_no_lock(sde_crtc, en); + mutex_unlock(&sde_crtc->crtc_lock); - return 0; + return rc; } void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, @@ -1739,6 +1891,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, crtc->dev = dev; atomic_set(&sde_crtc->vblank_refcount, 0); + mutex_init(&sde_crtc->crtc_lock); spin_lock_init(&sde_crtc->spin_lock); atomic_set(&sde_crtc->frame_pending, 0); @@ -1760,7 +1913,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); /* initialize output fence support */ - mutex_init(&sde_crtc->crtc_lock); sde_fence_init(&sde_crtc->output_fence, sde_crtc->name, crtc->base.id); /* initialize debugfs support */ diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index aaa815c76c4e..6b8483d574b1 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -82,6 +82,7 @@ struct sde_crtc_frame_event { * @vblank_cb_count : count of vblank callback since last reset * @vblank_cb_time : ktime at vblank count reset * @vblank_refcount : reference count for vblank enable request + * @suspend : whether or not a suspend operation is in progress * @feature_list : list of color processing features supported on a crtc * @active_list : list of color processing features are active * @dirty_list : list of color processing features are dirty @@ -117,6 +118,7 @@ struct sde_crtc { u32 vblank_cb_count; ktime_t vblank_cb_time; atomic_t vblank_refcount; + bool suspend; struct list_head feature_list; struct list_head active_list; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 635c2e4e954b..a185eb338134 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -689,6 +689,7 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg, { sblk->maxupscale = MAX_SSPP_UPSCALE; sblk->maxdwnscale = MAX_SSPP_DOWNSCALE; + sblk->format_list = plane_formats_yuv; sspp->id = SSPP_VIG0 + *vig_count; sspp->clk_ctrl = SDE_CLK_CTRL_VIG0 + *vig_count; sspp->type = SSPP_TYPE_VIG; @@ -759,6 +760,7 @@ static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg, { sblk->maxupscale = MAX_SSPP_UPSCALE; sblk->maxdwnscale = MAX_SSPP_DOWNSCALE; + sblk->format_list = plane_formats; sspp->id = SSPP_RGB0 + *rgb_count; sspp->clk_ctrl = SDE_CLK_CTRL_RGB0 + *rgb_count; sspp->type = SSPP_TYPE_RGB; @@ -799,6 +801,7 @@ static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg, set_bit(SDE_SSPP_CURSOR, &sspp->features); sblk->maxupscale = SSPP_UNITY_SCALE; sblk->maxdwnscale = SSPP_UNITY_SCALE; + sblk->format_list = cursor_formats; sspp->id = SSPP_CURSOR0 + *cursor_count; sspp->clk_ctrl = SDE_CLK_CTRL_CURSOR0 + *cursor_count; sspp->type = SSPP_TYPE_CURSOR; @@ -812,6 +815,7 @@ static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg, { sblk->maxupscale = SSPP_UNITY_SCALE; sblk->maxdwnscale = SSPP_UNITY_SCALE; + sblk->format_list = plane_formats; sspp->id = SSPP_DMA0 + *dma_count; sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count; sspp->type = SSPP_TYPE_DMA; @@ -1291,6 +1295,7 @@ static int sde_wb_parse_dt(struct device_node *np, wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i); wb->vbif_idx = VBIF_NRT; wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0); + wb->format_list = wb2_formats; if (!prop_exists[WB_LEN]) wb->len = DEFAULT_SDE_HW_BLOCK_LEN; sblk->maxlinewidth = sde_cfg->max_wb_linewidth; diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 031493aa42b8..a84d65195363 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -328,24 +328,12 @@ static int sde_debugfs_danger_init(struct sde_kms *sde_kms, static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { - struct sde_kms *sde_kms = to_sde_kms(kms); - struct drm_device *dev = sde_kms->dev; - struct msm_drm_private *priv = dev->dev_private; - - sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); - return sde_crtc_vblank(crtc, true); } static void sde_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { - struct sde_kms *sde_kms = to_sde_kms(kms); - struct drm_device *dev = sde_kms->dev; - struct msm_drm_private *priv = dev->dev_private; - sde_crtc_vblank(crtc, false); - - sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); } static void sde_kms_prepare_commit(struct msm_kms *kms, @@ -355,6 +343,9 @@ static void sde_kms_prepare_commit(struct msm_kms *kms, struct drm_device *dev = sde_kms->dev; struct msm_drm_private *priv = dev->dev_private; + if (sde_kms->splash_info.handoff) + sde_splash_clean_up_exit_lk(kms); + sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); } @@ -997,8 +988,15 @@ static void _sde_kms_hw_destroy(struct sde_kms *sde_kms, sde_hw_catalog_deinit(sde_kms->catalog); sde_kms->catalog = NULL; + if (sde_kms->splash_info.handoff) { + if (sde_kms->core_client) + sde_splash_destroy(&sde_kms->splash_info, + &priv->phandle, sde_kms->core_client); + } + if (sde_kms->core_client) - sde_power_client_destroy(&priv->phandle, sde_kms->core_client); + sde_power_client_destroy(&priv->phandle, + sde_kms->core_client); sde_kms->core_client = NULL; if (sde_kms->vbif[VBIF_NRT]) @@ -1110,6 +1108,24 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) continue; } + /* Attaching smmu means IOMMU HW starts to work immediately. + * However, display HW in LK is still accessing memory + * while the memory map is not done yet. + * So first set DOMAIN_ATTR_EARLY_MAP attribute 1 to bypass + * stage 1 translation in IOMMU HW. + */ + if ((i == MSM_SMMU_DOMAIN_UNSECURE) && + sde_kms->splash_info.handoff) { + ret = mmu->funcs->set_property(mmu, + DOMAIN_ATTR_EARLY_MAP, + &sde_kms->splash_info.handoff); + if (ret) { + SDE_ERROR("failed to set map att: %d\n", ret); + mmu->funcs->destroy(mmu); + goto fail; + } + } + aspace = msm_gem_smmu_address_space_create(sde_kms->dev->dev, mmu, "sde"); if (IS_ERR(aspace)) { @@ -1127,6 +1143,19 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) goto fail; } + /* + * It's safe now to map the physical memory blcok LK accesses. + */ + if ((i == MSM_SMMU_DOMAIN_UNSECURE) && + sde_kms->splash_info.handoff) { + ret = sde_splash_smmu_map(sde_kms->dev, mmu, + &sde_kms->splash_info); + if (ret) { + SDE_ERROR("map rsv mem failed: %d\n", ret); + msm_gem_address_space_put(aspace); + goto fail; + } + } } return 0; @@ -1141,6 +1170,7 @@ static int sde_kms_hw_init(struct msm_kms *kms) struct sde_kms *sde_kms; struct drm_device *dev; struct msm_drm_private *priv; + struct sde_splash_info *sinfo; int i, rc = -EINVAL; if (!kms) { @@ -1230,6 +1260,35 @@ static int sde_kms_hw_init(struct msm_kms *kms) goto power_error; } + /* + * Read the DISP_INTF_SEL register to check + * whether early display is enabled in LK. + */ + rc = sde_splash_get_handoff_status(kms); + if (rc) { + SDE_ERROR("get early splash status failed: %d\n", rc); + goto power_error; + } + + /* + * when LK has enabled early display, sde_splash_parse_dt and + * sde_splash_init must be called. The first function is to parse the + * mandatory memory node for splash function, and the second function + * will first do bandwidth voting job, because display hardware is now + * accessing AHB data bus, otherwise device reboot will happen, and then + * to check if the memory is reserved. + */ + sinfo = &sde_kms->splash_info; + if (sinfo->handoff) { + rc = sde_splash_parse_dt(dev); + if (rc) { + SDE_ERROR("parse dt for splash info failed: %d\n", rc); + goto power_error; + } + + sde_splash_init(&priv->phandle, kms); + } + for (i = 0; i < sde_kms->catalog->vbif_count; i++) { u32 vbif_idx = sde_kms->catalog->vbif[i].id; @@ -1304,7 +1363,10 @@ static int sde_kms_hw_init(struct msm_kms *kms) */ dev->mode_config.allow_fb_modifiers = true; - sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); + if (!sde_kms->splash_info.handoff) + sde_power_resource_enable(&priv->phandle, + sde_kms->core_client, false); + return 0; drm_obj_init_err: diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 44f6be959ac9..d929e48a3fe8 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -34,6 +34,7 @@ #include "sde_power_handle.h" #include "sde_irq.h" #include "sde_core_perf.h" +#include "sde_splash.h" #define DRMID(x) ((x) ? (x)->base.id : -1) @@ -157,6 +158,9 @@ struct sde_kms { bool has_danger_ctrl; void **hdmi_displays; int hdmi_display_count; + + /* splash handoff structure */ + struct sde_splash_info splash_info; }; struct vsync_info { diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index 6fe1d1629d22..6e2ccfa8e428 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -34,6 +34,14 @@ #include "sde_plane.h" #include "sde_color_processing.h" +static bool suspend_blank = true; +module_param(suspend_blank, bool, 0400); +MODULE_PARM_DESC(suspend_blank, + "If set, active planes will force their outputs to black,\n" + "by temporarily enabling the color fill, when recovering\n" + "from a system resume instead of attempting to display the\n" + "last provided frame buffer."); + #define SDE_DEBUG_PLANE(pl, fmt, ...) SDE_DEBUG("plane%d " fmt,\ (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) @@ -138,6 +146,7 @@ struct sde_plane { struct sde_debugfs_regset32 debugfs_src; struct sde_debugfs_regset32 debugfs_scaler; struct sde_debugfs_regset32 debugfs_csc; + bool debugfs_default_scale; }; #define to_sde_plane(x) container_of(x, struct sde_plane, base) @@ -686,9 +695,20 @@ static int _sde_plane_setup_scaler3_lut(struct sde_phy_plane *pp, struct sde_plane_state *pstate) { struct sde_plane *psde = pp->sde_plane; - struct sde_hw_scaler3_cfg *cfg = pp->scaler3_cfg; + struct sde_hw_scaler3_cfg *cfg; int ret = 0; + if (!pp || !pp->scaler3_cfg) { + SDE_ERROR("invalid args\n"); + return -EINVAL; + } else if (!pstate) { + /* pstate is expected to be null on forced color fill */ + SDE_DEBUG("null pstate\n"); + return -EINVAL; + } + + cfg = pp->scaler3_cfg; + cfg->dir_lut = msm_property_get_blob( &psde->property_info, pstate->property_blobs, &cfg->dir_len, @@ -723,6 +743,7 @@ static void _sde_plane_setup_scaler3(struct sde_phy_plane *pp, } memset(scale_cfg, 0, sizeof(*scale_cfg)); + memset(&pp->pixel_ext, 0, sizeof(struct sde_hw_pixel_ext)); decimated = DECIMATED_DIMENSION(src_w, pp->pipe_cfg.horz_decimation); @@ -1070,7 +1091,8 @@ static void _sde_plane_setup_scaler(struct sde_phy_plane *pp, int error; error = _sde_plane_setup_scaler3_lut(pp, pstate); - if (error || !pp->pixel_ext_usr) { + if (error || !pp->pixel_ext_usr || + psde->debugfs_default_scale) { memset(pe, 0, sizeof(struct sde_hw_pixel_ext)); /* calculate default config for QSEED3 */ _sde_plane_setup_scaler3(pp, @@ -1081,7 +1103,8 @@ static void _sde_plane_setup_scaler(struct sde_phy_plane *pp, pp->scaler3_cfg, fmt, chroma_subsmpl_h, chroma_subsmpl_v); } - } else if (!pp->pixel_ext_usr) { + } else if (!pp->pixel_ext_usr || !pstate || + psde->debugfs_default_scale) { uint32_t deci_dim, i; /* calculate default configuration for QSEED2 */ @@ -1701,8 +1724,8 @@ void sde_plane_flush(struct drm_plane *plane) */ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) { if (psde->is_error) - /* force white frame with 0% alpha pipe output on error */ - _sde_plane_color_fill(pp, 0xFFFFFF, 0x0); + /* force white frame with 100% alpha pipe output on error */ + _sde_plane_color_fill(pp, 0xFFFFFF, 0xFF); else if (pp->color_fill & SDE_PLANE_COLOR_FILL_FLAG) /* force 100% alpha */ _sde_plane_color_fill(pp, pp->color_fill, 0xFF); @@ -1711,6 +1734,10 @@ void sde_plane_flush(struct drm_plane *plane) pp->pipe_hw->ops.setup_csc(pp->pipe_hw, pp->csc_ptr); } + /* force black color fill during suspend */ + if (msm_is_suspend_state(plane->dev) && suspend_blank) + _sde_plane_color_fill(pp, 0x0, 0x0); + /* flag h/w flush complete */ if (plane->state) to_sde_plane_state(plane->state)->pending = false; @@ -2582,6 +2609,10 @@ static void _sde_plane_init_debugfs(struct sde_plane *psde, sde_debugfs_create_regset32("scaler_blk", S_IRUGO, psde->debugfs_root, &psde->debugfs_scaler); + debugfs_create_bool("default_scaling", + 0644, + psde->debugfs_root, + &psde->debugfs_default_scale); sde_debugfs_setup_regset32(&psde->debugfs_csc, sblk->csc_blk.base + cfg->base, diff --git a/drivers/gpu/drm/msm/sde/sde_splash.c b/drivers/gpu/drm/msm/sde/sde_splash.c new file mode 100644 index 000000000000..79989f3ac1e9 --- /dev/null +++ b/drivers/gpu/drm/msm/sde/sde_splash.c @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/of_address.h> +#include <linux/debugfs.h> +#include <linux/memblock.h> + +#include "msm_drv.h" +#include "msm_mmu.h" +#include "sde_kms.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_intf.h" +#include "sde_hw_catalog.h" + +#define MDP_SSPP_TOP0_OFF 0x1000 +#define DISP_INTF_SEL 0x004 +#define SPLIT_DISPLAY_EN 0x2F4 + +/* scratch registers */ +#define SCRATCH_REGISTER_0 0x014 +#define SCRATCH_REGISTER_1 0x018 +#define SCRATCH_REGISTER_2 0x01C + +#define SDE_LK_RUNNING_VALUE 0xC001CAFE +#define SDE_LK_SHUT_DOWN_VALUE 0xDEADDEAD +#define SDE_LK_EXIT_VALUE 0xDEADBEEF + +#define SDE_LK_EXIT_MAX_LOOP 20 +/* + * In order to free reseved memory from bootup, and we are not + * able to call the __init free functions, so we need to free + * this memory by ourselves using the free_reserved_page() function. + */ +static void _sde_splash_free_bootup_memory_to_system(phys_addr_t phys, + size_t size) +{ + unsigned long pfn_start, pfn_end, pfn_idx; + + memblock_free(phys, size); + + pfn_start = phys >> PAGE_SHIFT; + pfn_end = (phys + size) >> PAGE_SHIFT; + + for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++) + free_reserved_page(pfn_to_page(pfn_idx)); +} + +static int _sde_splash_parse_dt_get_lk_pool_node(struct drm_device *dev, + struct sde_splash_info *sinfo) +{ + struct device_node *parent, *node; + struct resource r; + int ret = 0; + + if (!sinfo) + return -EINVAL; + + parent = of_find_node_by_path("/reserved-memory"); + if (!parent) + return -EINVAL; + + node = of_find_node_by_name(parent, "lk_pool"); + if (!node) { + SDE_ERROR("mem reservation for lk_pool is not presented\n"); + ret = -EINVAL; + goto parent_node_err; + } + + /* find the mode */ + if (of_address_to_resource(node, 0, &r)) { + ret = -EINVAL; + goto child_node_err; + } + + sinfo->lk_pool_paddr = (dma_addr_t)r.start; + sinfo->lk_pool_size = r.end - r.start; + + DRM_INFO("lk_pool: addr:%pK, size:%pK\n", + (void *)sinfo->lk_pool_paddr, + (void *)sinfo->lk_pool_size); + +child_node_err: + of_node_put(node); + +parent_node_err: + of_node_put(parent); + + return ret; +} + +static int _sde_splash_parse_dt_get_display_node(struct drm_device *dev, + struct sde_splash_info *sinfo) +{ + unsigned long size = 0; + dma_addr_t start; + struct device_node *node; + int ret = 0, i = 0, len = 0; + + /* get reserved memory for display module */ + if (of_get_property(dev->dev->of_node, "contiguous-region", &len)) + sinfo->splash_mem_num = len / sizeof(u32); + else + sinfo->splash_mem_num = 0; + + sinfo->splash_mem_paddr = + kmalloc(sizeof(phys_addr_t) * sinfo->splash_mem_num, + GFP_KERNEL); + if (!sinfo->splash_mem_paddr) { + SDE_ERROR("alloc splash_mem_paddr failed\n"); + return -ENOMEM; + } + + sinfo->splash_mem_size = + kmalloc(sizeof(size_t) * sinfo->splash_mem_num, + GFP_KERNEL); + if (!sinfo->splash_mem_size) { + SDE_ERROR("alloc splash_mem_size failed\n"); + goto error; + } + + sinfo->obj = kmalloc(sizeof(struct drm_gem_object *) * + sinfo->splash_mem_num, GFP_KERNEL); + if (!sinfo->obj) { + SDE_ERROR("construct splash gem objects failed\n"); + goto error; + } + + for (i = 0; i < sinfo->splash_mem_num; i++) { + node = of_parse_phandle(dev->dev->of_node, + "contiguous-region", i); + + if (node) { + struct resource r; + + ret = of_address_to_resource(node, 0, &r); + if (ret) + return ret; + + size = r.end - r.start; + start = (dma_addr_t)r.start; + + sinfo->splash_mem_paddr[i] = start; + sinfo->splash_mem_size[i] = size; + + DRM_INFO("blk: %d, addr:%pK, size:%pK\n", + i, (void *)sinfo->splash_mem_paddr[i], + (void *)sinfo->splash_mem_size[i]); + + of_node_put(node); + } + } + + return ret; + +error: + kfree(sinfo->splash_mem_paddr); + sinfo->splash_mem_paddr = NULL; + + kfree(sinfo->splash_mem_size); + sinfo->splash_mem_size = NULL; + + return -ENOMEM; +} + +static bool _sde_splash_lk_check(struct sde_hw_intr *intr) +{ + return (SDE_LK_RUNNING_VALUE == SDE_REG_READ(&intr->hw, + SCRATCH_REGISTER_1)) ? true : false; +} + +/** + * _sde_splash_notify_lk_to_exit. + * + * Function to monitor LK's status and tell it to exit. + */ +static void _sde_splash_notify_lk_exit(struct sde_hw_intr *intr) +{ + int i = 0; + + /* first is to write exit signal to scratch register*/ + SDE_REG_WRITE(&intr->hw, SCRATCH_REGISTER_1, SDE_LK_SHUT_DOWN_VALUE); + + while ((SDE_LK_EXIT_VALUE != + SDE_REG_READ(&intr->hw, SCRATCH_REGISTER_1)) && + (++i < SDE_LK_EXIT_MAX_LOOP)) { + DRM_INFO("wait for LK's exit"); + msleep(20); + } + + if (i == SDE_LK_EXIT_MAX_LOOP) + SDE_ERROR("Loop LK's exit failed\n"); +} + +static int _sde_splash_gem_new(struct drm_device *dev, + struct sde_splash_info *sinfo) +{ + int i, ret; + + for (i = 0; i < sinfo->splash_mem_num; i++) { + sinfo->obj[i] = msm_gem_new(dev, + sinfo->splash_mem_size[i], MSM_BO_UNCACHED); + + if (IS_ERR(sinfo->obj[i])) { + ret = PTR_ERR(sinfo->obj[i]); + SDE_ERROR("failed to allocate gem, ret=%d\n", ret); + goto error; + } + } + + return 0; + +error: + for (i = 0; i < sinfo->splash_mem_num; i++) { + if (sinfo->obj[i]) + msm_gem_free_object(sinfo->obj[i]); + sinfo->obj[i] = NULL; + } + + return ret; +} + +static int _sde_splash_get_pages(struct drm_gem_object *obj, phys_addr_t phys) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct page **p; + dma_addr_t paddr; + int npages = obj->size >> PAGE_SHIFT; + int i; + + p = drm_malloc_ab(npages, sizeof(struct page *)); + if (!p) + return -ENOMEM; + + paddr = phys; + + for (i = 0; i < npages; i++) { + p[i] = phys_to_page(paddr); + paddr += PAGE_SIZE; + } + + msm_obj->sgt = drm_prime_pages_to_sg(p, npages); + if (IS_ERR(msm_obj->sgt)) { + SDE_ERROR("failed to allocate sgt\n"); + return -ENOMEM; + } + + msm_obj->pages = p; + + return 0; +} + +static void _sde_splash_destroy_gem_object(struct msm_gem_object *msm_obj) +{ + if (msm_obj->pages) { + sg_free_table(msm_obj->sgt); + kfree(msm_obj->sgt); + drm_free_large(msm_obj->pages); + msm_obj->pages = NULL; + } +} + +static void _sde_splash_destroy_splash_node(struct sde_splash_info *sinfo) +{ + kfree(sinfo->splash_mem_paddr); + sinfo->splash_mem_paddr = NULL; + + kfree(sinfo->splash_mem_size); + sinfo->splash_mem_size = NULL; +} + +static int _sde_splash_free_resource(struct msm_mmu *mmu, + struct sde_splash_info *sinfo, enum splash_connector_type conn) +{ + struct msm_gem_object *msm_obj = to_msm_bo(sinfo->obj[conn]); + + if (!msm_obj) + return -EINVAL; + + if (mmu->funcs && mmu->funcs->unmap) + mmu->funcs->unmap(mmu, sinfo->splash_mem_paddr[conn], + msm_obj->sgt, NULL); + + _sde_splash_free_bootup_memory_to_system(sinfo->splash_mem_paddr[conn], + sinfo->splash_mem_size[conn]); + + _sde_splash_destroy_gem_object(msm_obj); + + return 0; +} + +__ref int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms) +{ + struct sde_kms *sde_kms; + struct sde_splash_info *sinfo; + int i = 0; + + if (!phandle || !kms) { + SDE_ERROR("invalid phandle/kms\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(kms); + sinfo = &sde_kms->splash_info; + + sinfo->dsi_connector_cnt = 0; + sinfo->hdmi_connector_cnt = 0; + + sde_power_data_bus_bandwidth_ctrl(phandle, + sde_kms->core_client, true); + + for (i = 0; i < sinfo->splash_mem_num; i++) { + if (!memblock_is_reserved(sinfo->splash_mem_paddr[i])) { + SDE_ERROR("failed to reserve memory\n"); + + /* withdraw the vote when failed. */ + sde_power_data_bus_bandwidth_ctrl(phandle, + sde_kms->core_client, false); + + return -EINVAL; + } + } + + return 0; +} + +void sde_splash_destroy(struct sde_splash_info *sinfo, + struct sde_power_handle *phandle, + struct sde_power_client *pclient) +{ + struct msm_gem_object *msm_obj; + int i = 0; + + if (!sinfo || !phandle || !pclient) { + SDE_ERROR("invalid sde_kms/phandle/pclient\n"); + return; + } + + for (i = 0; i < sinfo->splash_mem_num; i++) { + msm_obj = to_msm_bo(sinfo->obj[i]); + + if (msm_obj) + _sde_splash_destroy_gem_object(msm_obj); + } + + sde_power_data_bus_bandwidth_ctrl(phandle, pclient, false); + + _sde_splash_destroy_splash_node(sinfo); +} + +/* + * sde_splash_parse_dt. + * In the function, it will parse and reserve two kinds of memory node. + * First is to get the reserved memory for display buffers. + * Second is to get the memory node LK's code stack is running on. + */ +int sde_splash_parse_dt(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct sde_kms *sde_kms; + struct sde_splash_info *sinfo; + + if (!priv || !priv->kms) { + SDE_ERROR("Invalid kms\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(priv->kms); + sinfo = &sde_kms->splash_info; + + if (_sde_splash_parse_dt_get_display_node(dev, sinfo)) { + SDE_ERROR("get display node failed\n"); + return -EINVAL; + } + + if (_sde_splash_parse_dt_get_lk_pool_node(dev, sinfo)) { + SDE_ERROR("get LK pool node failed\n"); + return -EINVAL; + } + + return 0; +} + +int sde_splash_get_handoff_status(struct msm_kms *kms) +{ + uint32_t intf_sel = 0; + uint32_t split_display = 0; + uint32_t num_of_display_on = 0; + uint32_t i = 0; + struct sde_kms *sde_kms = to_sde_kms(kms); + struct sde_rm *rm; + struct sde_hw_blk_reg_map *c; + struct sde_splash_info *sinfo; + struct sde_mdss_cfg *catalog; + + sinfo = &sde_kms->splash_info; + if (!sinfo) { + SDE_ERROR("%s(%d): invalid splash info\n", + __func__, __LINE__); + return -EINVAL; + } + + rm = &sde_kms->rm; + + if (!rm || !rm->hw_mdp) { + SDE_ERROR("invalid rm.\n"); + return -EINVAL; + } + + c = &rm->hw_mdp->hw; + if (c) { + intf_sel = SDE_REG_READ(c, DISP_INTF_SEL); + split_display = SDE_REG_READ(c, SPLIT_DISPLAY_EN); + } + + catalog = sde_kms->catalog; + + if (intf_sel != 0) { + for (i = 0; i < catalog->intf_count; i++) + if ((intf_sel >> i*8) & 0x000000FF) + num_of_display_on++; + + /* + * For split display enabled - DSI0, DSI1 interfaces are + * considered as single display. So decrement + * 'num_of_display_on' by 1 + */ + if (split_display) + num_of_display_on--; + } + + if (num_of_display_on) { + sinfo->handoff = true; + sinfo->program_scratch_regs = true; + } else { + sinfo->handoff = false; + sinfo->program_scratch_regs = false; + } + + sinfo->lk_is_exited = false; + + return 0; +} + +int sde_splash_smmu_map(struct drm_device *dev, struct msm_mmu *mmu, + struct sde_splash_info *sinfo) +{ + struct msm_gem_object *msm_obj; + int i = 0, ret = 0; + + if (!mmu || !sinfo) + return -EINVAL; + + /* first is to construct drm_gem_objects for splash memory */ + if (_sde_splash_gem_new(dev, sinfo)) + return -ENOMEM; + + /* second is to contruct sgt table for calling smmu map */ + for (i = 0; i < sinfo->splash_mem_num; i++) { + if (_sde_splash_get_pages(sinfo->obj[i], + sinfo->splash_mem_paddr[i])) + return -ENOMEM; + } + + for (i = 0; i < sinfo->splash_mem_num; i++) { + msm_obj = to_msm_bo(sinfo->obj[i]); + + if (mmu->funcs && mmu->funcs->map) { + ret = mmu->funcs->map(mmu, sinfo->splash_mem_paddr[i], + msm_obj->sgt, IOMMU_READ | IOMMU_NOEXEC, NULL); + + if (!ret) { + SDE_ERROR("Map blk %d @%pK failed.\n", + i, (void *)sinfo->splash_mem_paddr[i]); + return ret; + } + } + } + + return ret ? 0 : -ENOMEM; +} + +void sde_splash_setup_connector_count(struct sde_splash_info *sinfo, + int connector_type) +{ + switch (connector_type) { + case DRM_MODE_CONNECTOR_HDMIA: + sinfo->hdmi_connector_cnt++; + break; + case DRM_MODE_CONNECTOR_DSI: + sinfo->dsi_connector_cnt++; + break; + default: + SDE_ERROR("invalid connector_type %d\n", connector_type); + } +} + +int sde_splash_clean_up_free_resource(struct msm_kms *kms, + struct sde_power_handle *phandle, int connector_type) +{ + struct sde_kms *sde_kms; + struct sde_splash_info *sinfo; + struct msm_mmu *mmu; + int ret = 0; + static bool hdmi_is_released; + static bool dsi_is_released; + + if (!phandle || !kms) { + SDE_ERROR("invalid phandle/kms.\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(kms); + sinfo = &sde_kms->splash_info; + if (!sinfo) { + SDE_ERROR("%s(%d): invalid splash info\n", __func__, __LINE__); + return -EINVAL; + } + + /* When both hdmi's and dsi's resource are freed, + * 1. Destroy splash node objects. + * 2. Release the memory which LK's stack is running on. + * 3. Withdraw AHB data bus bandwidth voting. + */ + if (sinfo->hdmi_connector_cnt == 0 && + sinfo->dsi_connector_cnt == 0) { + DRM_INFO("HDMI and DSI resource handoff is completed\n"); + + sinfo->lk_is_exited = false; + + _sde_splash_destroy_splash_node(sinfo); + + _sde_splash_free_bootup_memory_to_system(sinfo->lk_pool_paddr, + sinfo->lk_pool_size); + + sde_power_data_bus_bandwidth_ctrl(phandle, + sde_kms->core_client, false); + + return 0; + } + + mmu = sde_kms->aspace[0]->mmu; + + switch (connector_type) { + case DRM_MODE_CONNECTOR_HDMIA: + if (!hdmi_is_released) + sinfo->hdmi_connector_cnt--; + + if ((sinfo->hdmi_connector_cnt == 0) && (!hdmi_is_released)) { + hdmi_is_released = true; + + ret = _sde_splash_free_resource(mmu, + sinfo, SPLASH_HDMI); + } + break; + case DRM_MODE_CONNECTOR_DSI: + if (!dsi_is_released) + sinfo->dsi_connector_cnt--; + + if ((sinfo->dsi_connector_cnt == 0) && (!dsi_is_released)) { + dsi_is_released = true; + + ret = _sde_splash_free_resource(mmu, + sinfo, SPLASH_DSI); + } + break; + default: + ret = -EINVAL; + SDE_ERROR("%s: invalid connector_type %d\n", + __func__, connector_type); + } + + return ret; +} + +/* + * In below function, it will + * 1. Notify LK to exit and wait for exiting is done. + * 2. Set DOMAIN_ATTR_EARLY_MAP to 1 to enable stage 1 translation in iommu. + */ +int sde_splash_clean_up_exit_lk(struct msm_kms *kms) +{ + struct sde_splash_info *sinfo; + struct msm_mmu *mmu; + struct sde_kms *sde_kms = to_sde_kms(kms); + int ret; + + sinfo = &sde_kms->splash_info; + + if (!sinfo) { + SDE_ERROR("%s(%d): invalid splash info\n", __func__, __LINE__); + return -EINVAL; + } + + /* Monitor LK's status and tell it to exit. */ + if (sinfo->program_scratch_regs) { + if (_sde_splash_lk_check(sde_kms->hw_intr)) + _sde_splash_notify_lk_exit(sde_kms->hw_intr); + + sinfo->handoff = false; + sinfo->program_scratch_regs = false; + } + + if (!sde_kms->aspace[0] || !sde_kms->aspace[0]->mmu) { + /* We do not return fault value here, to ensure + * flag "lk_is_exited" is set. + */ + SDE_ERROR("invalid mmu\n"); + WARN_ON(1); + } else { + mmu = sde_kms->aspace[0]->mmu; + /* After LK has exited, set early domain map attribute + * to 1 to enable stage 1 translation in iommu driver. + */ + if (mmu->funcs && mmu->funcs->set_property) { + ret = mmu->funcs->set_property(mmu, + DOMAIN_ATTR_EARLY_MAP, &sinfo->handoff); + + if (ret) + SDE_ERROR("set_property failed\n"); + } + } + + sinfo->lk_is_exited = true; + return 0; +} diff --git a/drivers/gpu/drm/msm/sde/sde_splash.h b/drivers/gpu/drm/msm/sde/sde_splash.h new file mode 100644 index 000000000000..47965693f0b8 --- /dev/null +++ b/drivers/gpu/drm/msm/sde/sde_splash.h @@ -0,0 +1,124 @@ +/** + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef SDE_SPLASH_H_ +#define SDE_SPLASH_H_ + +#include "msm_kms.h" +#include "msm_mmu.h" + +enum splash_connector_type { + SPLASH_DSI = 0, + SPLASH_HDMI, +}; + +struct sde_splash_info { + /* handoff flag */ + bool handoff; + + /* flag of display scratch registers */ + bool program_scratch_regs; + + /* to indicate LK is totally exited */ + bool lk_is_exited; + + /* memory node used for display buffer */ + uint32_t splash_mem_num; + + /* physical address of memory node for display buffer */ + phys_addr_t *splash_mem_paddr; + + /* size of memory node */ + size_t *splash_mem_size; + + /* constructed gem objects for smmu mapping */ + struct drm_gem_object **obj; + + /* physical address of lk pool */ + phys_addr_t lk_pool_paddr; + + /* memory size of lk pool */ + size_t lk_pool_size; + + /* registered hdmi connector count */ + uint32_t hdmi_connector_cnt; + + /* registered dst connector count */ + uint32_t dsi_connector_cnt; +}; + +/* APIs for early splash handoff functions */ + +/** + * sde_splash_get_handoff_status. + * + * This function will read DISP_INTF_SEL regsiter to get + * the status of early splash. + */ +int sde_splash_get_handoff_status(struct msm_kms *kms); + +/** + * sde_splash_init + * + * This function will do bandwidth vote and reserved memory + */ +int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms); + +/** + *sde_splash_setup_connector_count + * + * To count connector numbers for DSI and HDMI respectively. + */ +void sde_splash_setup_connector_count(struct sde_splash_info *sinfo, + int connector_type); + +/** + * sde_splash_clean_up_exit_lk. + * + * Tell LK to exit, and clean up the resource. + */ +int sde_splash_clean_up_exit_lk(struct msm_kms *kms); + +/** + * sde_splash_clean_up_free_resource. + * + * According to input connector_type, free + * HDMI's and DSI's resource respectively. + */ +int sde_splash_clean_up_free_resource(struct msm_kms *kms, + struct sde_power_handle *phandle, int connector_type); + +/** + * sde_splash_parse_dt. + * + * Parse reserved memory block from DT for early splash. + */ +int sde_splash_parse_dt(struct drm_device *dev); + +/** + * sde_splash_smmu_map. + * + * Map the physical memory LK visited into iommu driver. + */ +int sde_splash_smmu_map(struct drm_device *dev, struct msm_mmu *mmu, + struct sde_splash_info *sinfo); + +/** + * sde_splash_destroy + * + * Destroy the resource in failed case. + */ +void sde_splash_destroy(struct sde_splash_info *sinfo, + struct sde_power_handle *phandle, + struct sde_power_client *pclient); + +#endif diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index 0e56731b16e2..883a9810fbf4 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -537,13 +537,42 @@ static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED, "smmu_info"); } + +static void a5xx_preemption_iommu_close(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); + + kgsl_free_global(device, &iommu->smmu_info); +} + #else static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) { return -ENODEV; } + +static void a5xx_preemption_iommu_close(struct adreno_device *adreno_dev) +{ +} #endif +static void a5xx_preemption_close(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_preemption *preempt = &adreno_dev->preempt; + struct adreno_ringbuffer *rb; + unsigned int i; + + del_timer(&preempt->timer); + kgsl_free_global(device, &preempt->counters); + a5xx_preemption_iommu_close(adreno_dev); + + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + kgsl_free_global(device, &rb->preemption_desc); + } +} + int a5xx_preemption_init(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -568,7 +597,7 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, "preemption_counters"); if (ret) - return ret; + goto err; addr = preempt->counters.gpuaddr; @@ -576,10 +605,16 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { ret = a5xx_preemption_ringbuffer_init(adreno_dev, rb, addr); if (ret) - return ret; + goto err; addr += A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE; } - return a5xx_preemption_iommu_init(adreno_dev); + ret = a5xx_preemption_iommu_init(adreno_dev); + +err: + if (ret) + a5xx_preemption_close(device); + + return ret; } diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index f8f0e7ccb0d3..8dc2ebd26cf9 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -348,7 +348,13 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, struct kgsl_cmd_syncpoint_fence *sync = priv; struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); struct kgsl_drawobj_sync_event *event; + struct sync_fence *fence = NULL; unsigned int id; + int ret = 0; + + fence = sync_fence_fdget(sync->fd); + if (fence == NULL) + return -EINVAL; kref_get(&drawobj->refcount); @@ -364,11 +370,13 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, set_bit(event->id, &syncobj->pending); + trace_syncpoint_fence(syncobj, fence->name); + event->handle = kgsl_sync_fence_async_wait(sync->fd, drawobj_sync_fence_func, event); if (IS_ERR_OR_NULL(event->handle)) { - int ret = PTR_ERR(event->handle); + ret = PTR_ERR(event->handle); clear_bit(event->id, &syncobj->pending); event->handle = NULL; @@ -376,18 +384,16 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, drawobj_put(drawobj); /* - * If ret == 0 the fence was already signaled - print a trace - * message so we can track that + * Print a syncpoint_fence_expire trace if + * the fence is already signaled or there is + * a failure in registering the fence waiter. */ - if (ret == 0) - trace_syncpoint_fence_expire(syncobj, "signaled"); - - return ret; + trace_syncpoint_fence_expire(syncobj, (ret < 0) ? + "error" : fence->name); } - trace_syncpoint_fence(syncobj, event->handle->name); - - return 0; + sync_fence_put(fence); + return ret; } /* drawobj_add_sync_timestamp() - Add a new sync point for a sync obj diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index c31a85b07447..685ce3ea968b 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -65,26 +65,19 @@ _kgsl_get_pool_from_order(unsigned int order) /* Map the page into kernel and zero it out */ static void -_kgsl_pool_zero_page(struct page *p, unsigned int pool_order) +_kgsl_pool_zero_page(struct page *p) { - int i; - - for (i = 0; i < (1 << pool_order); i++) { - struct page *page = nth_page(p, i); - void *addr = kmap_atomic(page); + void *addr = kmap_atomic(p); - memset(addr, 0, PAGE_SIZE); - dmac_flush_range(addr, addr + PAGE_SIZE); - kunmap_atomic(addr); - } + memset(addr, 0, PAGE_SIZE); + dmac_flush_range(addr, addr + PAGE_SIZE); + kunmap_atomic(addr); } /* Add a page to specified pool */ static void _kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p) { - _kgsl_pool_zero_page(p, pool->pool_order); - spin_lock(&pool->list_lock); list_add_tail(&p->lru, &pool->page_list); pool->page_count++; @@ -329,7 +322,6 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, } else return -ENOMEM; } - _kgsl_pool_zero_page(page, order); goto done; } @@ -349,7 +341,6 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, page = alloc_pages(gfp_mask, order); if (page == NULL) return -ENOMEM; - _kgsl_pool_zero_page(page, order); goto done; } } @@ -379,13 +370,12 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, } else return -ENOMEM; } - - _kgsl_pool_zero_page(page, order); } done: for (j = 0; j < (*page_size >> PAGE_SHIFT); j++) { p = nth_page(page, j); + _kgsl_pool_zero_page(p); pages[pcount] = p; pcount++; } diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 3e4cc4490792..2b7a1fcbaa78 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -591,7 +591,7 @@ int kgsl_devfreq_get_dev_status(struct device *dev, struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwrctrl; struct kgsl_pwrscale *pwrscale; - ktime_t tmp; + ktime_t tmp1, tmp2; if (device == NULL) return -ENODEV; @@ -602,6 +602,8 @@ int kgsl_devfreq_get_dev_status(struct device *dev, pwrctrl = &device->pwrctrl; mutex_lock(&device->mutex); + + tmp1 = ktime_get(); /* * If the GPU clock is on grab the latest power counter * values. Otherwise the most recent ACTIVE values will @@ -609,9 +611,9 @@ int kgsl_devfreq_get_dev_status(struct device *dev, */ kgsl_pwrscale_update_stats(device); - tmp = ktime_get(); - stat->total_time = ktime_us_delta(tmp, pwrscale->time); - pwrscale->time = tmp; + tmp2 = ktime_get(); + stat->total_time = ktime_us_delta(tmp2, pwrscale->time); + pwrscale->time = tmp1; stat->busy_time = pwrscale->accum_stats.busy_time; diff --git a/drivers/hwtracing/coresight/coresight-remote-etm.c b/drivers/hwtracing/coresight/coresight-remote-etm.c index 30b13282f6c0..cc0b25b130d7 100644 --- a/drivers/hwtracing/coresight/coresight-remote-etm.c +++ b/drivers/hwtracing/coresight/coresight-remote-etm.c @@ -186,12 +186,9 @@ static void remote_etm_rcv_msg(struct work_struct *work) struct remote_etm_drvdata *drvdata = container_of(work, struct remote_etm_drvdata, work_rcv_msg); - mutex_lock(&drvdata->mutex); if (qmi_recv_msg(drvdata->handle) < 0) dev_err(drvdata->dev, "%s: Error receiving QMI message\n", __func__); - - mutex_unlock(&drvdata->mutex); } static void remote_etm_notify(struct qmi_handle *handle, diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c index 56f2732334db..30da797a85dc 100644 --- a/drivers/input/misc/hbtp_input.c +++ b/drivers/input/misc/hbtp_input.c @@ -249,6 +249,10 @@ static int hbtp_input_release(struct inode *inode, struct file *file) return -ENOTTY; } hbtp->count--; + if (!completion_done(&hbtp->power_suspend_sig)) + complete(&hbtp->power_suspend_sig); + if (!completion_done(&hbtp->power_resume_sig)) + complete(&hbtp->power_resume_sig); if (hbtp->power_sig_enabled) hbtp->power_sig_enabled = false; mutex_unlock(&hbtp->mutex); diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index 4f6086970131..43d566fd38ae 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -645,6 +645,8 @@ static int add_as_linear_device(struct dm_target *ti, char *dev) android_verity_target.iterate_devices = dm_linear_iterate_devices, android_verity_target.io_hints = NULL; + set_disk_ro(dm_disk(dm_table_get_md(ti->table)), 0); + err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args); if (!err) { diff --git a/drivers/media/platform/msm/ais/isp/msm_isp.h b/drivers/media/platform/msm/ais/isp/msm_isp.h index 72a76d178aa8..86974eeb4a32 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp.h +++ b/drivers/media/platform/msm/ais/isp/msm_isp.h @@ -355,6 +355,7 @@ struct msm_vfe_hardware_info { uint32_t dmi_reg_offset; uint32_t min_ab; uint32_t min_ib; + uint32_t regulator_num; const char *regulator_names[]; }; diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.c b/drivers/media/platform/msm/ais/isp/msm_isp47.c index d63282f80aca..d33dc758aef9 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.c @@ -2537,8 +2537,7 @@ int msm_vfe47_get_regulators(struct vfe_device *vfe_dev) int rc = 0; int i; - vfe_dev->vfe_num_regulators = - sizeof(*vfe_dev->hw_info->regulator_names) / sizeof(char *); + vfe_dev->vfe_num_regulators = vfe_dev->hw_info->regulator_num; vfe_dev->regulator_info = kzalloc(sizeof(struct msm_cam_regulator) * vfe_dev->vfe_num_regulators, GFP_KERNEL); @@ -2811,6 +2810,7 @@ struct msm_vfe_hardware_info vfe47_hw_info = { .dmi_reg_offset = 0xC2C, .axi_hw_info = &msm_vfe47_axi_hw_info, .stats_hw_info = &msm_vfe47_stats_hw_info, + .regulator_num = 3, .regulator_names = {"vdd", "camss-vdd", "mmagic-vdd"}, }; EXPORT_SYMBOL(vfe47_hw_info); diff --git a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c index 811ac98beead..6c50070c91ab 100644 --- a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c @@ -2882,7 +2882,7 @@ end: return rc; } -static int msm_cpp_validate_input(unsigned int cmd, void *arg, +static int msm_cpp_validate_ioctl_input(unsigned int cmd, void *arg, struct msm_camera_v4l2_ioctl_t **ioctl_ptr) { switch (cmd) { @@ -2922,6 +2922,14 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, pr_err("sd %pK\n", sd); return -EINVAL; } + + + rc = msm_cpp_validate_ioctl_input(cmd, arg, &ioctl_ptr); + if (rc != 0) { + pr_err("input validation failed\n"); + return rc; + } + cpp_dev = v4l2_get_subdevdata(sd); if (cpp_dev == NULL) { pr_err("cpp_dev is null\n"); @@ -2933,11 +2941,6 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, return -EINVAL; } - rc = msm_cpp_validate_input(cmd, arg, &ioctl_ptr); - if (rc != 0) { - pr_err("input validation failed\n"); - return rc; - } mutex_lock(&cpp_dev->mutex); CPP_DBG("E cmd: 0x%x\n", cmd); @@ -3437,6 +3440,7 @@ STREAM_BUFF_END: } else { pr_err("%s:%d IOMMMU attach triggered in invalid state\n", __func__, __LINE__); + rc = -EINVAL; } break; } @@ -4061,7 +4065,8 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, default: pr_err_ratelimited("%s: unsupported compat type :%x LOAD %lu\n", __func__, cmd, VIDIOC_MSM_CPP_LOAD_FIRMWARE); - break; + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; } mutex_unlock(&cpp_dev->mutex); @@ -4092,7 +4097,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, default: pr_err_ratelimited("%s: unsupported compat type :%d\n", __func__, cmd); - break; + return -EINVAL; } if (is_copytouser_req) { diff --git a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c index 1adb380f335f..40806d5a164f 100644 --- a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c @@ -1722,6 +1722,10 @@ static long msm_actuator_subdev_do_ioctl( parg = &actuator_data; break; } + break; + case VIDIOC_MSM_ACTUATOR_CFG: + pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd); + return -EINVAL; } rc = msm_actuator_subdev_ioctl(sd, cmd, parg); diff --git a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c b/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c index a2a89b92c9f1..024677e1b755 100644 --- a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c @@ -152,6 +152,13 @@ static int32_t msm_flash_i2c_write_table( conf_array.reg_setting = settings->reg_setting_a; conf_array.size = settings->size; + /* Validate the settings size */ + if ((!conf_array.size) || (conf_array.size > MAX_I2C_REG_SET)) { + pr_err("failed: invalid size %d", conf_array.size); + return -EINVAL; + } + + return flash_ctrl->flash_i2c_client.i2c_func_tbl->i2c_write_table( &flash_ctrl->flash_i2c_client, &conf_array); } @@ -497,23 +504,46 @@ static int32_t msm_flash_init( } flash_ctrl->flash_state = MSM_CAMERA_FLASH_INIT; - CDBG("Exit"); return 0; } -#ifdef CONFIG_COMPAT static int32_t msm_flash_init_prepare( struct msm_flash_ctrl_t *flash_ctrl, struct msm_flash_cfg_data_t *flash_data) { + #ifdef CONFIG_COMPAT + struct msm_flash_cfg_data_t flash_data_k; + struct msm_flash_init_info_t flash_init_info; + int32_t i = 0; + + if (!is_compat_task()) { + /*for 64-bit usecase,it need copy the data to local memory*/ + flash_data_k.cfg_type = flash_data->cfg_type; + for (i = 0; i < MAX_LED_TRIGGERS; i++) { + flash_data_k.flash_current[i] = + flash_data->flash_current[i]; + flash_data_k.flash_duration[i] = + flash_data->flash_duration[i]; + } + + flash_data_k.cfg.flash_init_info = &flash_init_info; + if (copy_from_user(&flash_init_info, + (void __user *)(flash_data->cfg.flash_init_info), + sizeof(struct msm_flash_init_info_t))) { + pr_err("%s copy_from_user failed %d\n", + __func__, __LINE__); + return -EFAULT; + } + return msm_flash_init(flash_ctrl, &flash_data_k); + } + /* + * for 32-bit usecase,it already copy the userspace + * data to local memory in msm_flash_subdev_do_ioctl() + * so here do not need copy from user + */ return msm_flash_init(flash_ctrl, flash_data); -} #else -static int32_t msm_flash_init_prepare( - struct msm_flash_ctrl_t *flash_ctrl, - struct msm_flash_cfg_data_t *flash_data) -{ struct msm_flash_cfg_data_t flash_data_k; struct msm_flash_init_info_t flash_init_info; int32_t i = 0; @@ -528,15 +558,15 @@ static int32_t msm_flash_init_prepare( flash_data_k.cfg.flash_init_info = &flash_init_info; if (copy_from_user(&flash_init_info, - (void *)(flash_data->cfg.flash_init_info), + (void __user *)(flash_data->cfg.flash_init_info), sizeof(struct msm_flash_init_info_t))) { pr_err("%s copy_from_user failed %d\n", __func__, __LINE__); return -EFAULT; } return msm_flash_init(flash_ctrl, &flash_data_k); -} #endif +} static int32_t msm_flash_low( struct msm_flash_ctrl_t *flash_ctrl, diff --git a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c index 236660dca3fb..aa7658f359ac 100644 --- a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c @@ -781,6 +781,7 @@ static long msm_ois_subdev_do_ioctl( u32 = (struct msm_ois_cfg_data32 *)arg; parg = arg; + switch (cmd) { case VIDIOC_MSM_OIS_CFG32: cmd = VIDIOC_MSM_OIS_CFG; @@ -818,7 +819,6 @@ static long msm_ois_subdev_do_ioctl( settings.reg_setting = compat_ptr(settings32.reg_setting); - ois_data.cfgtype = u32->cfgtype; ois_data.cfg.settings = &settings; parg = &ois_data; break; diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c index c243d587e308..90edadaed1ef 100644 --- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c @@ -175,35 +175,45 @@ int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data, void msm_camera_io_dump(void __iomem *addr, int size, int enable) { - char line_str[128], *p_str; + char line_str[128]; int i; - u32 *p = (u32 *) addr; + ptrdiff_t p = 0; + size_t offset = 0, used = 0; u32 data; CDBG("%s: addr=%pK size=%d\n", __func__, addr, size); - if (!p || (size <= 0) || !enable) + if (!addr || (size <= 0) || !enable) return; line_str[0] = '\0'; - p_str = line_str; for (i = 0; i < size/4; i++) { if (i % 4 == 0) { -#ifdef CONFIG_COMPAT - snprintf(p_str, 20, "%016lx: ", (unsigned long) p); - p_str += 18; -#else - snprintf(p_str, 12, "%08lx: ", (unsigned long) p); - p_str += 10; -#endif + used = snprintf(line_str + offset, + sizeof(line_str) - offset, "0x%04tX: ", p); + if (offset + used >= sizeof(line_str)) { + pr_err("%s\n", line_str); + offset = 0; + line_str[0] = '\0'; + } else { + offset += used; + } + } + data = readl_relaxed(addr + p); + p = p + 4; + used = snprintf(line_str + offset, + sizeof(line_str) - offset, "%08x ", data); + if (offset + used >= sizeof(line_str)) { + pr_err("%s\n", line_str); + offset = 0; + line_str[0] = '\0'; + } else { + offset += used; } - data = readl_relaxed(p++); - snprintf(p_str, 12, "%08x ", data); - p_str += 9; if ((i + 1) % 4 == 0) { pr_err("%s\n", line_str); line_str[0] = '\0'; - p_str = line_str; + offset = 0; } } if (line_str[0] != '\0') diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index a04d7ca73fe1..63c3595a3f85 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -1057,14 +1057,18 @@ static int msm_fd_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) a->value = ctx->format.size->work_size; break; case V4L2_CID_FD_WORK_MEMORY_FD: + mutex_lock(&ctx->fd_device->recovery_lock); if (ctx->work_buf.fd != -1) msm_fd_hw_unmap_buffer(&ctx->work_buf); if (a->value >= 0) { ret = msm_fd_hw_map_buffer(&ctx->mem_pool, a->value, &ctx->work_buf); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; + } } + mutex_unlock(&ctx->fd_device->recovery_lock); break; default: return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index a8d4cfb43927..0f029c0d5178 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -136,7 +136,7 @@ static inline void msm_isp_cfg_stream_scratch( } static inline struct msm_vfe_axi_stream *msm_isp_get_stream_common_data( - struct vfe_device *vfe_dev, int stream_idx) + struct vfe_device *vfe_dev, uint32_t stream_idx) { struct msm_vfe_common_dev_data *common_data = vfe_dev->common_data; struct msm_vfe_axi_stream *stream_info; diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 3f900ded090a..9c3bd7b41ce9 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -1025,6 +1025,9 @@ static void msm_ispif_config_stereo(struct ispif_device *ispif, enum msm_ispif_vfe_intf vfe_intf; uint32_t stereo_3d_threshold = STEREO_DEFAULT_3D_THRESHOLD; + if (params->num > MAX_PARAM_ENTRIES) + return; + for (i = 0; i < params->num; i++) { vfe_intf = params->entries[i].vfe_intf; if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index e40869d41a5d..821833d53905 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -903,26 +903,45 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, void msm_jpeg_io_dump(void *base, int size) { - char line_str[128], *p_str; + char line_str[128]; void __iomem *addr = (void __iomem *)base; int i; u32 *p = (u32 *) addr; + size_t offset = 0; + size_t used = 0; + size_t min_range = 0; + size_t sizeof_line_str = sizeof(line_str); u32 data; JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size); line_str[0] = '\0'; - p_str = line_str; for (i = 0; i < size/4; i++) { if (i % 4 == 0) { - snprintf(p_str, 12, "%08lx: ", (unsigned long)p); - p_str += 10; + used = snprintf(line_str + offset, + sizeof_line_str - offset, "%pK ", p); + if ((used < min_range) || + (offset + used >= sizeof_line_str)) { + JPEG_PR_ERR("%s\n", line_str); + offset = 0; + line_str[0] = '\0'; + } else { + offset += used; + } } data = msm_camera_io_r(p++); - snprintf(p_str, 12, "%08x ", data); - p_str += 9; + used = snprintf(line_str + offset, + sizeof_line_str - offset, "%08x ", data); + if ((used < min_range) || + (offset + used >= sizeof_line_str)) { + JPEG_PR_ERR("%s\n", line_str); + offset = 0; + line_str[0] = '\0'; + } else { + offset += used; + } if ((i + 1) % 4 == 0) { JPEG_DBG_HIGH("%s\n", line_str); line_str[0] = '\0'; - p_str = line_str; + offset = 0; } } if (line_str[0] != '\0') diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 9cb7d5299ef8..4e5dc66d94a9 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -287,6 +287,7 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) return; while (1) { + unsigned long wl_flags; if (try_count > 5) { pr_err("%s : not able to delete stream %d\n", @@ -294,18 +295,20 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) break; } - write_lock(&session->stream_rwlock); + write_lock_irqsave(&session->stream_rwlock, wl_flags); try_count++; stream = msm_queue_find(&session->stream_q, struct msm_stream, list, __msm_queue_find_stream, &stream_id); if (!stream) { - write_unlock(&session->stream_rwlock); + write_unlock_irqrestore(&session->stream_rwlock, + wl_flags); return; } if (msm_vb2_get_stream_state(stream) != 1) { - write_unlock(&session->stream_rwlock); + write_unlock_irqrestore(&session->stream_rwlock, + wl_flags); continue; } @@ -315,7 +318,7 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) kfree(stream); stream = NULL; spin_unlock_irqrestore(&(session->stream_q.lock), flags); - write_unlock(&session->stream_rwlock); + write_unlock_irqrestore(&session->stream_rwlock, wl_flags); break; } diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c index 719b14226067..e271c7fcd1b6 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c @@ -47,22 +47,23 @@ int msm_vb2_buf_init(struct vb2_buffer *vb) struct msm_session *session; struct msm_vb2_buffer *msm_vb2_buf; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + unsigned long rl_flags; session = msm_get_session_from_vb2q(vb->vb2_queue); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s: Couldn't find stream\n", __func__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); msm_vb2_buf->in_freeq = 0; - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return 0; } @@ -71,7 +72,7 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags; + unsigned long flags, rl_flags; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); @@ -84,19 +85,19 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) if (IS_ERR_OR_NULL(session)) return; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return; } spin_lock_irqsave(&stream->stream_lock, flags); list_add_tail(&msm_vb2->list, &stream->queued_list); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); } static void msm_vb2_buf_finish(struct vb2_buffer *vb) @@ -104,26 +105,26 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags; + unsigned long flags, rl_flags; struct msm_vb2_buffer *msm_vb2_entry, *temp; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); if (!msm_vb2) { pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); - return; + return; } session = msm_get_session_from_vb2q(vb->vb2_queue); if (IS_ERR_OR_NULL(session)) return; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return; } @@ -136,7 +137,7 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) } } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return; } @@ -145,19 +146,19 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) struct msm_vb2_buffer *msm_vb2, *temp; struct msm_stream *stream; struct msm_session *session; - unsigned long flags; + unsigned long flags, rl_flags; struct vb2_v4l2_buffer *vb2_v4l2_buf; session = msm_get_session_from_vb2q(q); if (IS_ERR_OR_NULL(session)) return; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream_from_vb2q(q); if (!stream) { pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return; } @@ -177,7 +178,7 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); } int msm_vb2_get_stream_state(struct msm_stream *stream) @@ -255,17 +256,17 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, struct msm_session *session; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags; + unsigned long flags, rl_flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return NULL; } @@ -291,7 +292,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return vb2_v4l2_buf; } @@ -302,18 +303,18 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, struct msm_session *session; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags; + unsigned long flags, rl_flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return NULL; } @@ -337,7 +338,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return vb2_v4l2_buf; } @@ -349,17 +350,17 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, struct msm_vb2_buffer *msm_vb2; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; int rc = 0; - unsigned long flags; + unsigned long flags, rl_flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -374,7 +375,8 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n", vb, session_id, stream_id); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, + rl_flags); return -EINVAL; } msm_vb2 = @@ -391,7 +393,7 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return rc; } @@ -399,7 +401,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, unsigned int stream_id, uint32_t sequence, struct timeval *ts, uint32_t reserved) { - unsigned long flags; + unsigned long flags, rl_flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; @@ -410,11 +412,11 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -429,7 +431,8 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n", session_id, stream_id, vb); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, + rl_flags); return -EINVAL; } msm_vb2 = @@ -450,7 +453,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return rc; } @@ -461,18 +464,18 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, struct msm_session *session; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags; + unsigned long flags, rl_flags; long rc = -EINVAL; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return rc; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -501,14 +504,14 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return rc; } EXPORT_SYMBOL(msm_vb2_return_buf_by_idx); static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) { - unsigned long flags; + unsigned long flags, rl_flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; @@ -518,11 +521,11 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock(&session->stream_rwlock); + read_lock_irqsave(&session->stream_rwlock, rl_flags); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return -EINVAL; } @@ -534,7 +537,7 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock(&session->stream_rwlock); + read_unlock_irqrestore(&session->stream_rwlock, rl_flags); return 0; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c index 3f079fe2c173..457bd1730232 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -575,6 +575,8 @@ int msm_camera_get_dt_power_setting_data(struct device_node *of_node, ps[i].seq_val = SENSOR_GPIO_CUSTOM1; else if (!strcmp(seq_name, "sensor_gpio_custom2")) ps[i].seq_val = SENSOR_GPIO_CUSTOM2; + else if (!strcmp(seq_name, "sensor_gpio_custom3")) + ps[i].seq_val = SENSOR_GPIO_CUSTOM3; else rc = -EILSEQ; break; @@ -1078,6 +1080,27 @@ int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, rc = 0; } + rc = of_property_read_u32(of_node, "qcom,gpio-custom3", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-custom3 failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-custom3 invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM3] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_CUSTOM3] = 1; + CDBG("%s qcom,gpio-custom3 %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM3]); + } else { + rc = 0; + } + return rc; ERROR: 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 4149122b1c77..10f72a2155db 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -668,11 +668,11 @@ static void sde_hw_rotator_setup_fetchengine(struct sde_hw_rotator_context *ctx, /* * Determine if traffic shaping is required. Only enable traffic - * shaping when content is 4k@60fps. The actual traffic shaping + * shaping when content is 4k@30fps. The actual traffic shaping * bandwidth calculation is done in output setup. */ if (((cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) && - (cfg->fps <= 60)) { + (cfg->fps <= 30)) { SDEROT_DBG("Enable Traffic Shaper\n"); ctx->is_traffic_shaping = true; } else { diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 28a4006b480c..0f6389370643 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1491,6 +1491,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q, rc = -EINVAL; break; } + msm_dcvs_try_enable(inst); /* Pretend as if FW itself is asking for * additional buffers. @@ -1570,9 +1571,10 @@ exit: return rc; } -static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) +static int set_max_internal_buffers_size(struct msm_vidc_inst *inst) { int rc = 0; + struct msm_vidc_list *buf_list = &inst->scratchbufs; struct { enum hal_buffer type; struct hal_buffer_requirements *req; @@ -1580,13 +1582,17 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) } internal_buffers[] = { { HAL_BUFFER_INTERNAL_SCRATCH, NULL, 0}, { HAL_BUFFER_INTERNAL_SCRATCH_1, NULL, 0}, - { HAL_BUFFER_INTERNAL_SCRATCH_2, NULL, 0}, - { HAL_BUFFER_INTERNAL_PERSIST, NULL, 0}, - { HAL_BUFFER_INTERNAL_PERSIST_1, NULL, 0}, }; struct hal_frame_size frame_sz; int i; + mutex_lock(&buf_list->lock); + if (!list_empty(&buf_list->list)) { + dprintk(VIDC_DBG, "Scratch list already has allocated buf\n"); + mutex_unlock(&buf_list->lock); + return 0; + } + mutex_unlock(&buf_list->lock); frame_sz.buffer_type = HAL_BUFFER_INPUT; frame_sz.width = inst->capability.width.max; @@ -1612,6 +1618,15 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) get_buff_req_buffer(inst, internal_buffers[i].type); internal_buffers[i].size = internal_buffers[i].req ? internal_buffers[i].req->buffer_size : 0; + + rc = allocate_and_set_internal_bufs(inst, + internal_buffers[i].req, + &inst->scratchbufs, false); + if (rc) + goto alloc_fail; + dprintk(VIDC_DBG, + "Allocated scratch type : %d size to : %zd\n", + internal_buffers[i].type, internal_buffers[i].size); } frame_sz.buffer_type = HAL_BUFFER_INPUT; @@ -1624,25 +1639,18 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "%s Failed to get back old buf req, %d\n", __func__, rc); - return rc; + goto alloc_fail; } - dprintk(VIDC_DBG, "Old buffer reqs, buffer type = %d width = %d, height = %d\n", frame_sz.buffer_type, frame_sz.width, frame_sz.height); - for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) { - if (internal_buffers[i].req) { - internal_buffers[i].req->buffer_size = - internal_buffers[i].size; - dprintk(VIDC_DBG, - "Changing buffer type : %d size to : %zd\n", - internal_buffers[i].type, - internal_buffers[i].size); - } - } return 0; + +alloc_fail: + msm_comm_release_scratch_buffers(inst, false); + return rc; } static inline int start_streaming(struct msm_vidc_inst *inst) @@ -1653,6 +1661,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) struct hal_buffer_size_minimum b; unsigned int buffer_size; struct msm_vidc_format *fmt = NULL; + bool max_internal_buf = false; fmt = &inst->fmts[CAPTURE_PORT]; buffer_size = fmt->get_frame_size(0, @@ -1676,8 +1685,9 @@ static inline int start_streaming(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "H/w scaling is not in valid range\n"); return -EINVAL; } - if ((inst->flags & VIDC_SECURE) && !inst->in_reconfig && - !slave_side_cp) { + max_internal_buf = (inst->flags & VIDC_SECURE) && !slave_side_cp + && (inst->session_type == MSM_VIDC_DECODER); + if (max_internal_buf) { rc = set_max_internal_buffers_size(inst); if (rc) { dprintk(VIDC_ERR, @@ -1686,7 +1696,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) goto fail_start; } } - rc = msm_comm_set_scratch_buffers(inst); + rc = msm_comm_set_scratch_buffers(inst, max_internal_buf); if (rc) { dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index c5816511e056..e4698e0cdcd8 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1868,7 +1868,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) "Failed to get Buffer Requirements : %d\n", rc); goto fail_start; } - rc = msm_comm_set_scratch_buffers(inst); + rc = msm_comm_set_scratch_buffers(inst, false); if (rc) { dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc); goto fail_start; diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 2b3070974df8..de4705c3d2eb 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -826,7 +826,8 @@ int output_buffer_cache_invalidate(struct msm_vidc_inst *inst, if (inst->session_type == MSM_VIDC_ENCODER && !i) - size = b->m.planes[i].bytesused; + size = b->m.planes[i].bytesused + + b->m.planes[i].data_offset; else size = -1; @@ -1060,7 +1061,8 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) if (binfo->handle[i] && (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) { if (inst->session_type == MSM_VIDC_DECODER && !i) - size = b->m.planes[i].bytesused; + size = b->m.planes[i].bytesused + + b->m.planes[i].data_offset; else size = -1; rc = msm_comm_smem_cache_operations(inst, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index f85fe6fd3867..1d910f4b235c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -3342,9 +3342,9 @@ static bool reuse_internal_buffers(struct msm_vidc_inst *inst, return reused; } -static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, +int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, struct hal_buffer_requirements *internal_bufreq, - struct msm_vidc_list *buf_list) + struct msm_vidc_list *buf_list, bool set_on_fw) { struct msm_smem *handle; struct internal_buf *binfo; @@ -3381,11 +3381,13 @@ static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, binfo->handle = handle; binfo->buffer_type = internal_bufreq->buffer_type; - rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type, - handle, false); - if (rc) - goto fail_set_buffers; - + if (set_on_fw) { + rc = set_internal_buf_on_fw(inst, + internal_bufreq->buffer_type, + handle, false); + if (rc) + goto fail_set_buffers; + } mutex_lock(&buf_list->lock); list_add_tail(&binfo->list, &buf_list->list); mutex_unlock(&buf_list->lock); @@ -3426,7 +3428,7 @@ static int set_internal_buffers(struct msm_vidc_inst *inst, return 0; return allocate_and_set_internal_bufs(inst, internal_buf, - buf_list); + buf_list, true); } int msm_comm_try_state(struct msm_vidc_inst *inst, int state) @@ -3587,39 +3589,6 @@ int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd) "Failed to flush buffers: %d\n", rc); } break; - case V4L2_DEC_QCOM_CMD_RECONFIG_HINT: - { - u32 *ptr = NULL; - struct hal_buffer_requirements *output_buf; - - rc = msm_comm_try_get_bufreqs(inst); - if (rc) { - dprintk(VIDC_ERR, - "Getting buffer requirements failed: %d\n", - rc); - break; - } - - output_buf = get_buff_req_buffer(inst, - msm_comm_get_hal_output_buffer(inst)); - if (output_buf) { - if (dec) { - ptr = (u32 *)dec->raw.data; - ptr[0] = output_buf->buffer_size; - ptr[1] = output_buf->buffer_count_actual; - dprintk(VIDC_DBG, - "Reconfig hint, size is %u, count is %u\n", - ptr[0], ptr[1]); - } else { - dprintk(VIDC_ERR, "Null decoder\n"); - } - } else { - dprintk(VIDC_DBG, - "This output buffer not required, buffer_type: %x\n", - HAL_BUFFER_OUTPUT); - } - break; - } default: dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd); rc = -ENOTSUPP; @@ -4453,15 +4422,15 @@ error: return rc; } -int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst) -{ +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst, + bool max_int_buffer) { int rc = 0; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); return -EINVAL; } - if (msm_comm_release_scratch_buffers(inst, true)) + if (!max_int_buffer && msm_comm_release_scratch_buffers(inst, true)) dprintk(VIDC_WARN, "Failed to release scratch buffers\n"); rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 7d28859c040c..5658df95db26 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -41,9 +41,13 @@ int msm_comm_try_set_prop(struct msm_vidc_inst *inst, enum hal_property ptype, void *pdata); int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, union hal_get_property *hprop); -int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst); +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst, + bool max_int_buffer); int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst); int msm_comm_set_output_buffers(struct msm_vidc_inst *inst); +int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, + struct hal_buffer_requirements *internal_bufreq, + struct msm_vidc_list *buf_list, bool set_on_fw); int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst); int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb); void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index 3a329d989918..a1b4ad48b054 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -106,6 +106,7 @@ struct clock_info { u32 count; bool has_scaling; bool has_mem_retention; + unsigned long rate_on_enable; }; struct clock_set { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 52b56f615da9..20f02ce46029 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1574,6 +1574,7 @@ static int __scale_clocks(struct venus_hfi_device *device, return rc; } + static int venus_hfi_scale_clocks(void *dev, int load, struct vidc_clk_scale_data *data, unsigned long instant_bitrate) @@ -1600,6 +1601,41 @@ exit: return rc; } +static void __save_clock_rate(struct venus_hfi_device *device, bool reset) +{ + struct clock_info *cl; + + venus_hfi_for_each_clock(device, cl) { + if (cl->has_scaling) { + cl->rate_on_enable = + reset ? 0 : clk_get_rate(cl->clk); + dprintk(VIDC_PROF, "Saved clock %s rate %lu\n", + cl->name, cl->rate_on_enable); + } + } +} + +static void __restore_clock_rate(struct venus_hfi_device *device) +{ + struct clock_info *cl; + + venus_hfi_for_each_clock(device, cl) { + if (cl->has_scaling && cl->rate_on_enable) { + int rc; + + rc = __set_clk_rate(device, cl, cl->rate_on_enable); + if (rc) + dprintk(VIDC_ERR, + "Failed to restore clock %s rate %lu\n", + cl->name, cl->rate_on_enable); + else + dprintk(VIDC_DBG, + "Restored clock %s rate %lu\n", + cl->name, cl->rate_on_enable); + } + } +} + /* Writes into cmdq without raising an interrupt */ static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device, void *pkt, bool *requires_interrupt) @@ -4316,6 +4352,7 @@ static inline int __suspend(struct venus_hfi_device *device) goto err_tzbsp_suspend; } + __save_clock_rate(device, false); __venus_power_off(device, true); dprintk(VIDC_PROF, "Venus power collapsed\n"); return rc; @@ -4345,6 +4382,7 @@ static inline int __resume(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed to power on venus\n"); goto err_venus_power_on; } + __restore_clock_rate(device); /* Reboot the firmware */ rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME); @@ -4382,6 +4420,7 @@ exit: err_reset_core: __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); err_set_video_state: + __save_clock_rate(device, true); __venus_power_off(device, true); err_venus_power_on: dprintk(VIDC_ERR, "Failed to resume from power collapse\n"); @@ -4440,6 +4479,7 @@ fail_protect_mem: subsystem_put(device->resources.fw.cookie); device->resources.fw.cookie = NULL; fail_load_fw: + __save_clock_rate(device, true); __venus_power_off(device, true); fail_venus_power_on: fail_init_pkt: @@ -4461,6 +4501,7 @@ static void __unload_fw(struct venus_hfi_device *device) __vote_buses(device, NULL, 0); subsystem_put(device->resources.fw.cookie); __interface_queues_release(device); + __save_clock_rate(device, true); __venus_power_off(device, false); device->resources.fw.cookie = NULL; __deinit_resources(device); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 14a44c29dc1b..cf897947fff2 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -8531,7 +8531,11 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.ion_clnt = msm_ion_client_create("qseecom-kernel"); if (IS_ERR_OR_NULL(qseecom.ion_clnt)) { pr_err("Ion client cannot be created\n"); - rc = -ENOMEM; + + if (qseecom.ion_clnt != ERR_PTR(-EPROBE_DEFER)) + rc = -ENOMEM; + else + rc = -EPROBE_DEFER; goto exit_del_cdev; } diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 8dc93900b16d..907763ddf234 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -4179,8 +4179,10 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, /* keep track of the value in SDHCI_CAPABILITIES */ msm_host->caps_0 = caps; - if ((major == 1) && (minor >= 0x6b)) + if ((major == 1) && (minor >= 0x6b)) { msm_host->ice_hci_support = true; + host->cdr_support = true; + } } #ifdef CONFIG_MMC_CQ_HCI diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a5ff9f73dfbc..0033fea0a800 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3633,7 +3633,7 @@ static void sdhci_cmdq_set_transfer_params(struct mmc_host *mmc) ctrl |= SDHCI_CTRL_ADMA32; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } - if (host->ops->toggle_cdr) + if (host->ops->toggle_cdr && !host->cdr_support) host->ops->toggle_cdr(host, false); } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 93129b26dc5e..300be7fd0f24 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -564,6 +564,7 @@ struct sdhci_host { bool runtime_suspended; /* Host is runtime suspended */ bool bus_on; /* Bus power prevents runtime suspend */ bool preset_enabled; /* Preset is enabled */ + bool cdr_support; struct mmc_request *mrq; /* Current request */ struct mmc_command *cmd; /* Current command */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6906bddb229f..10b33840e5e5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1886,6 +1886,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_wmi_detach; } + /* If firmware indicates Full Rx Reorder support it must be used in a + * slightly different manner. Let HTT code know. + */ + ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, + ar->wmi.svc_map)); + status = ath10k_htt_rx_alloc(&ar->htt); if (status) { ath10k_err(ar, "failed to alloc htt rx: %d\n", status); @@ -1997,12 +2003,6 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, } } - /* If firmware indicates Full Rx Reorder support it must be used in a - * slightly different manner. Let HTT code know. - */ - ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, - ar->wmi.svc_map)); - status = ath10k_htt_rx_ring_refill(ar); if (status) { ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e430bab869a8..cce931e51d7e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -667,6 +667,36 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, *def = &conf->def; } +static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) +{ + int ret; + unsigned long time_left; + + lockdep_assert_held(&ar->conf_mutex); + + ret = ath10k_wmi_peer_delete(ar, vdev_id, addr); + if (ret) + return ret; + + ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); + if (ret) + return ret; + + if (QCA_REV_WCN3990(ar)) { + time_left = wait_for_completion_timeout(&ar->peer_delete_done, + 50 * HZ); + + if (time_left == 0) { + ath10k_warn(ar, "Timeout in receiving peer delete response\n"); + return -ETIMEDOUT; + } + } + + ar->num_peers--; + + return 0; +} + static int ath10k_peer_create(struct ath10k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -711,7 +741,7 @@ static int ath10k_peer_create(struct ath10k *ar, spin_unlock_bh(&ar->data_lock); ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n", addr, vdev_id); - ath10k_wmi_peer_delete(ar, vdev_id, addr); + ath10k_peer_delete(ar, vdev_id, addr); return -ENOENT; } @@ -779,36 +809,6 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); } -static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) -{ - int ret; - unsigned long time_left; - - lockdep_assert_held(&ar->conf_mutex); - - ret = ath10k_wmi_peer_delete(ar, vdev_id, addr); - if (ret) - return ret; - - ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); - if (ret) - return ret; - - if (QCA_REV_WCN3990(ar)) { - time_left = wait_for_completion_timeout(&ar->peer_delete_done, - 50 * HZ); - - if (time_left == 0) { - ath10k_warn(ar, "Timeout in receiving peer delete response\n"); - return -ETIMEDOUT; - } - } - - ar->num_peers--; - - return 0; -} - static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) { struct ath10k_peer *peer, *tmp; @@ -5094,7 +5094,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, err_peer_delete: if (arvif->vdev_type == WMI_VDEV_TYPE_AP || arvif->vdev_type == WMI_VDEV_TYPE_IBSS) - ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr); + ath10k_peer_delete(ar, arvif->vdev_id, vif->addr); err_vdev_delete: ath10k_wmi_vdev_delete(ar, arvif->vdev_id); @@ -5150,8 +5150,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP || arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { - ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id, - vif->addr); + ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, + vif->addr); if (ret) ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n", arvif->vdev_id, ret); @@ -7168,12 +7168,25 @@ ath10k_mac_update_vif_chan(struct ath10k *ar, if (WARN_ON(!arvif->is_up)) continue; + if (QCA_REV_WCN3990(ar)) { + /* In the case of wcn3990 WLAN module we send + * vdev restart only, no need to send vdev down. + */ - ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); - if (ret) { - ath10k_warn(ar, "failed to down vdev %d: %d\n", - arvif->vdev_id, ret); - continue; + ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); + if (ret) { + ath10k_warn(ar, + "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } + } else { + ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); + if (ret) { + ath10k_warn(ar, "failed to down vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } } } @@ -7204,11 +7217,17 @@ ath10k_mac_update_vif_chan(struct ath10k *ar, ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); - ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); - if (ret) { - ath10k_warn(ar, "failed to restart vdev %d: %d\n", - arvif->vdev_id, ret); - continue; + if (!QCA_REV_WCN3990(ar)) { + /* In case of other than wcn3990 WLAN module we + * send vdev down and vdev restart to the firmware. + */ + + ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); + if (ret) { + ath10k_warn(ar, "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } } ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 9406b6f71a6b..75e81991913a 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -107,8 +107,8 @@ static struct ce_attr host_ce_config_wlan[] = { { .flags = CE_ATTR_FLAGS, .src_nentries = 0, - .src_sz_max = 512, - .dest_nentries = 512, + .src_sz_max = 0, + .dest_nentries = 0, .recv_cb = ath10k_snoc_htt_rx_cb, }, diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 129859255295..c3100fcd80f2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -31,6 +31,8 @@ struct wmi_ops { struct wmi_mgmt_rx_ev_arg *arg); int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb, struct wmi_ch_info_ev_arg *arg); + int (*pull_peer_delete_resp)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_delete_resp_ev_arg *arg); int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb, struct wmi_vdev_start_ev_arg *arg); int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb, @@ -246,6 +248,16 @@ ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb, } static inline int +ath10k_wmi_pull_peer_delete_resp(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_delete_resp_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_peer_delete_resp) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_peer_delete_resp(ar, skb, arg); +} + +static inline int ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb, struct wmi_ch_info_ev_arg *arg) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 888ab5ad37f1..07b15f4c1db4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -412,15 +412,6 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, return 0; } -static int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar, - struct sk_buff *skb) -{ - ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TLV_PEER_DELETE_RESP_EVENTID\n"); - complete(&ar->peer_delete_done); - - return 0; -} - /***********/ /* TLV ops */ /***********/ @@ -657,6 +648,34 @@ static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_op_pull_peer_delete_ev( + struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_delete_resp_ev_arg *arg) +{ + const void **tb; + const struct wmi_peer_delete_resp_ev_arg *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->vdev_id = ev->vdev_id; + arg->peer_addr = ev->peer_addr; + + kfree(tb); + return 0; +} + static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, struct wmi_ch_info_ev_arg *arg) @@ -3620,6 +3639,7 @@ static const struct wmi_ops wmi_tlv_ops = { .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev, + .pull_peer_delete_resp = ath10k_wmi_tlv_op_pull_peer_delete_ev, .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 86b24c24d9f1..500d1d8f441f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -898,6 +898,7 @@ enum wmi_tlv_tag { WMI_TLV_TAG_STRUCT_HL_1_0_SVC_OFFSET = 176, WMI_TLV_TAG_STRUCT_MGMT_TX_CMD = 0x1A6, + WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT = 0x1C3, WMI_TLV_TAG_MAX }; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index d60e7fbb7e74..d6ec0de63582 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2269,6 +2269,24 @@ static bool ath10k_wmi_rx_is_decrypted(struct ath10k *ar, return true; } +int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar, + struct sk_buff *skb) +{ + int ret; + struct wmi_peer_delete_resp_ev_arg arg = {}; + + ret = ath10k_wmi_pull_peer_delete_resp(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse peer delete resp: %d\n", ret); + dev_kfree_skb(skb); + return ret; + } + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TLV_PEER_DELETE_RESP_EVENTID\n"); + complete(&ar->peer_delete_done); + + return 0; +} + int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_ev_arg arg = {}; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9bd374910379..7ae07a505c59 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6234,6 +6234,11 @@ struct wmi_scan_ev_arg { __le32 vdev_id; }; +struct wmi_peer_delete_resp_ev_arg { + __le32 vdev_id; + struct wmi_mac_addr peer_addr; +}; + struct wmi_mgmt_rx_ev_arg { __le32 channel; __le32 snr; @@ -6603,6 +6608,8 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg); int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar, + struct sk_buff *skb); int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 63bb7686b811..94861020af12 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -960,7 +960,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); - if (len < sizeof(struct ieee80211_mgmt)) + if (len < sizeof(struct ieee80211_hdr_3addr)) return -EINVAL; cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c index b4c4d09011b4..b91bf51be767 100644 --- a/drivers/net/wireless/ath/wil6210/sysfs.c +++ b/drivers/net/wireless/ath/wil6210/sysfs.c @@ -291,6 +291,8 @@ int wil6210_sysfs_init(struct wil6210_priv *wil) return err; } + kobject_uevent(&dev->kobj, KOBJ_CHANGE); + return 0; } @@ -299,4 +301,5 @@ void wil6210_sysfs_remove(struct wil6210_priv *wil) struct device *dev = wil_to_dev(wil); sysfs_remove_group(&dev->kobj, &wil6210_attribute_group); + kobject_uevent(&dev->kobj, KOBJ_CHANGE); } diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 22c59d8c3c45..c9412ca6e794 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -134,7 +134,6 @@ static DEFINE_SPINLOCK(pci_link_down_lock); #define FW_IMAGE_MISSION (0x02) #define FW_IMAGE_BDATA (0x03) #define FW_IMAGE_PRINT (0x04) -#define FW_SETUP_DELAY 2000 #define SEG_METADATA (0x01) #define SEG_NON_PAGED (0x02) @@ -274,10 +273,8 @@ static struct cnss_data { u32 fw_dma_size; u32 fw_seg_count; struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS]; - atomic_t fw_store_in_progress; /* Firmware setup complete lock */ struct mutex fw_setup_stat_lock; - struct completion fw_setup_complete; void *bdata_cpu; dma_addr_t bdata_dma; u32 bdata_dma_size; @@ -1374,15 +1371,6 @@ int cnss_get_fw_image(struct image_desc_info *image_desc_info) !penv->fw_seg_count || !penv->bdata_seg_count) return -EINVAL; - /* Check for firmware setup trigger by usersapce is in progress - * and wait for complition of firmware setup. - */ - - if (atomic_read(&penv->fw_store_in_progress)) { - wait_for_completion_timeout(&penv->fw_setup_complete, - msecs_to_jiffies(FW_SETUP_DELAY)); - } - mutex_lock(&penv->fw_setup_stat_lock); image_desc_info->fw_addr = penv->fw_dma; image_desc_info->fw_size = penv->fw_dma_size; @@ -1627,7 +1615,9 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, goto err_pcie_suspend; } + mutex_lock(&penv->fw_setup_stat_lock); cnss_wlan_fw_mem_alloc(pdev); + mutex_unlock(&penv->fw_setup_stat_lock); ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup); @@ -1874,17 +1864,11 @@ static ssize_t fw_image_setup_store(struct device *dev, if (!penv) return -ENODEV; - if (atomic_read(&penv->fw_store_in_progress)) { - pr_info("%s: Firmware setup in progress\n", __func__); - return 0; - } - - atomic_set(&penv->fw_store_in_progress, 1); - init_completion(&penv->fw_setup_complete); + mutex_lock(&penv->fw_setup_stat_lock); + pr_info("%s: Firmware setup in progress\n", __func__); if (kstrtoint(buf, 0, &val)) { - atomic_set(&penv->fw_store_in_progress, 0); - complete(&penv->fw_setup_complete); + mutex_unlock(&penv->fw_setup_stat_lock); return -EINVAL; } @@ -1895,8 +1879,7 @@ static ssize_t fw_image_setup_store(struct device *dev, if (ret != 0) { pr_err("%s: Invalid parsing of FW image files %d", __func__, ret); - atomic_set(&penv->fw_store_in_progress, 0); - complete(&penv->fw_setup_complete); + mutex_unlock(&penv->fw_setup_stat_lock); return -EINVAL; } penv->fw_image_setup = val; @@ -1906,9 +1889,8 @@ static ssize_t fw_image_setup_store(struct device *dev, penv->bmi_test = val; } - atomic_set(&penv->fw_store_in_progress, 0); - complete(&penv->fw_setup_complete); - + pr_info("%s: Firmware setup completed\n", __func__); + mutex_unlock(&penv->fw_setup_stat_lock); return count; } @@ -2007,16 +1989,21 @@ int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg) { struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info; + mutex_lock(&penv->fw_setup_stat_lock); if (!cnss_seg_info) { swap_seg = NULL; + mutex_unlock(&penv->fw_setup_stat_lock); return -ENOENT; } + if (!atomic_read(&penv->fw_available)) { pr_debug("%s: fw is not available\n", __func__); + mutex_unlock(&penv->fw_setup_stat_lock); return -ENOENT; } *swap_seg = *cnss_seg_info; + mutex_unlock(&penv->fw_setup_stat_lock); return 0; } @@ -2035,15 +2022,6 @@ static void cnss_wlan_memory_expansion(void) u_int32_t total_length = 0; struct pci_dev *pdev; - /* Check for firmware setup trigger by usersapce is in progress - * and wait for complition of firmware setup. - */ - - if (atomic_read(&penv->fw_store_in_progress)) { - wait_for_completion_timeout(&penv->fw_setup_complete, - msecs_to_jiffies(FW_SETUP_DELAY)); - } - mutex_lock(&penv->fw_setup_stat_lock); filename = cnss_wlan_get_evicted_data_file(); pdev = penv->pdev; @@ -2859,6 +2837,7 @@ static int cnss_probe(struct platform_device *pdev) penv->vreg_info.wlan_reg = NULL; penv->vreg_info.state = VREG_OFF; penv->pci_register_again = false; + mutex_init(&penv->fw_setup_stat_lock); ret = cnss_wlan_get_resources(pdev); if (ret) @@ -3016,8 +2995,6 @@ skip_ramdump: memset(phys_to_virt(0), 0, SZ_4K); #endif - atomic_set(&penv->fw_store_in_progress, 0); - mutex_init(&penv->fw_setup_stat_lock); ret = device_create_file(dev, &dev_attr_fw_image_setup); if (ret) { pr_err("cnss: fw_image_setup sys file creation failed\n"); diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c index 360ab31c61dd..c3bcb38f428f 100644 --- a/drivers/net/wireless/cnss2/debug.c +++ b/drivers/net/wireless/cnss2/debug.c @@ -15,6 +15,7 @@ #include <linux/debugfs.h> #include "main.h" #include "debug.h" +#include "pci.h" #define CNSS_IPC_LOG_PAGES 32 @@ -121,13 +122,90 @@ static int cnss_stats_open(struct inode *inode, struct file *file) } static const struct file_operations cnss_stats_fops = { - .read = seq_read, - .release = single_release, - .open = cnss_stats_open, - .owner = THIS_MODULE, - .llseek = seq_lseek, + .read = seq_read, + .release = single_release, + .open = cnss_stats_open, + .owner = THIS_MODULE, + .llseek = seq_lseek, }; +static ssize_t cnss_dev_boot_debug_write(struct file *fp, + const char __user *user_buf, + size_t count, loff_t *off) +{ + struct cnss_plat_data *plat_priv = + ((struct seq_file *)fp->private_data)->private; + char buf[64]; + char *cmd; + unsigned int len = 0; + int ret = 0; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + cmd = buf; + + if (sysfs_streq(cmd, "on")) { + ret = cnss_power_on_device(plat_priv); + } else if (sysfs_streq(cmd, "enumerate")) { + ret = cnss_pci_init(plat_priv); + } else if (sysfs_streq(cmd, "download")) { + ret = cnss_pci_start_mhi(plat_priv->bus_priv); + } else { + cnss_pr_err("Device boot debugfs command is invalid\n"); + ret = -EINVAL; + } + + if (ret) + return ret; + + return count; +} + +static int cnss_dev_boot_debug_show(struct seq_file *s, void *data) +{ + seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n"); + seq_puts(s, "<action> can be one of below:\n"); + seq_puts(s, "on: turn on device power, assert WLAN_EN\n"); + seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n"); + seq_puts(s, "download: download FW and do QMI handshake with FW\n"); + + return 0; +} + +static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, cnss_dev_boot_debug_show, inode->i_private); +} + +static const struct file_operations cnss_dev_boot_debug_fops = { + .read = seq_read, + .write = cnss_dev_boot_debug_write, + .release = single_release, + .open = cnss_dev_boot_debug_open, + .owner = THIS_MODULE, + .llseek = seq_lseek, +}; + +#ifdef CONFIG_CNSS2_DEBUG +static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv) +{ + struct dentry *root_dentry = plat_priv->root_dentry; + + debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv, + &cnss_dev_boot_debug_fops); + + return 0; +} +#else +static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv) +{ + return 0; +} +#endif + int cnss_debugfs_create(struct cnss_plat_data *plat_priv) { int ret = 0; @@ -139,11 +217,16 @@ int cnss_debugfs_create(struct cnss_plat_data *plat_priv) cnss_pr_err("Unable to create debugfs %d\n", ret); goto out; } + plat_priv->root_dentry = root_dentry; + debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv, &cnss_pin_connect_fops); debugfs_create_file("stats", 0644, root_dentry, plat_priv, &cnss_stats_fops); + + cnss_create_debug_only_node(plat_priv); + out: return ret; } diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 432960afe09a..8838a1319629 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -57,6 +57,7 @@ MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest"); enum cnss_debug_quirks { LINK_DOWN_SELF_RECOVERY, + SKIP_DEVICE_BOOT, }; unsigned long quirks; @@ -1100,7 +1101,8 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) return -ENODEV; } - if (plat_priv->ramdump_info_v2.dump_data_valid) { + if (plat_priv->ramdump_info_v2.dump_data_valid || + test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); cnss_pci_clear_dump_info(pci_priv); } @@ -2231,13 +2233,15 @@ static int cnss_probe(struct platform_device *plat_dev) if (ret) goto reset_ctx; - ret = cnss_power_on_device(plat_priv); - if (ret) - goto free_res; + if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) { + ret = cnss_power_on_device(plat_priv); + if (ret) + goto free_res; - ret = cnss_pci_init(plat_priv); - if (ret) - goto power_off; + ret = cnss_pci_init(plat_priv); + if (ret) + goto power_off; + } ret = cnss_register_esoc(plat_priv); if (ret) @@ -2290,9 +2294,11 @@ unreg_bus_scale: unreg_esoc: cnss_unregister_esoc(plat_priv); deinit_pci: - cnss_pci_deinit(plat_priv); + if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) + cnss_pci_deinit(plat_priv); power_off: - cnss_power_off_device(plat_priv); + if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) + cnss_power_off_device(plat_priv); free_res: cnss_put_resources(plat_priv); reset_ctx: diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index a17b72ce03ba..ce5a7b2bc88e 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -787,36 +787,6 @@ int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va, return 0; } -#ifdef CONFIG_CNSS_QCA6290 -#define PCI_MAX_BAR_SIZE 0xD00000 - -static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar, - unsigned long maxlen) -{ - resource_size_t start = pci_resource_start(dev, bar); - resource_size_t len = PCI_MAX_BAR_SIZE; - unsigned long flags = pci_resource_flags(dev, bar); - - if (!len || !start) - return NULL; - - if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM)) { - if (flags & IORESOURCE_CACHEABLE && !(flags & IORESOURCE_IO)) - return ioremap(start, len); - else - return ioremap_nocache(start, len); - } - - return NULL; -} -#else -static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar, - unsigned long maxlen) -{ - return pci_iomap(dev, bar, maxlen); -} -#endif - static struct cnss_msi_config msi_config = { .total_vectors = 32, .total_users = 4, @@ -1003,7 +973,7 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv) pci_set_master(pci_dev); - pci_priv->bar = cnss_pci_iomap(pci_dev, PCI_BAR_NUM, 0); + pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0); if (!pci_priv->bar) { cnss_pr_err("Failed to do PCI IO map!\n"); ret = -EIO; @@ -1366,12 +1336,10 @@ int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv) ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON); if (ret) - goto deinit_mhi; + goto out; return 0; -deinit_mhi: - cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); out: return ret; } @@ -1392,8 +1360,12 @@ void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv) cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_RESUME); cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF); - if (!plat_priv->ramdump_info_v2.dump_data_valid) - cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); + + if (plat_priv->ramdump_info_v2.dump_data_valid || + test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) + return; + + cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); } static int cnss_pci_probe(struct pci_dev *pci_dev, diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 99163d51a497..d1c0423b4517 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -50,6 +50,30 @@ enum cnss_bdf_type { CNSS_BDF_ELF, }; +static char *cnss_qmi_mode_to_str(enum wlfw_driver_mode_enum_v01 mode) +{ + switch (mode) { + case QMI_WLFW_MISSION_V01: + return "MISSION"; + case QMI_WLFW_FTM_V01: + return "FTM"; + case QMI_WLFW_EPPING_V01: + return "EPPING"; + case QMI_WLFW_WALTEST_V01: + return "WALTEST"; + case QMI_WLFW_OFF_V01: + return "OFF"; + case QMI_WLFW_CCPM_V01: + return "CCPM"; + case QMI_WLFW_QVIT_V01: + return "QVIT"; + case QMI_WLFW_CALIBRATION_V01: + return "CALIBRATION"; + default: + return "UNKNOWN"; + } +}; + static void cnss_wlfw_clnt_notifier_work(struct work_struct *work) { struct cnss_plat_data *plat_priv = @@ -585,8 +609,8 @@ int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv, if (!plat_priv) return -ENODEV; - cnss_pr_dbg("Sending mode message, state: 0x%lx, mode: %d\n", - plat_priv->driver_state, mode); + cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n", + cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state); if (mode == QMI_WLFW_OFF_V01 && test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { @@ -617,14 +641,15 @@ int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv, cnss_pr_dbg("WLFW service is disconnected while sending mode off request.\n"); return 0; } - cnss_pr_err("Failed to send mode request, mode: %d, err = %d\n", - mode, ret); + cnss_pr_err("Failed to send mode request, mode: %s(%d), err: %d\n", + cnss_qmi_mode_to_str(mode), mode, ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - cnss_pr_err("Mode request failed, mode: %d, result: %d err: %d\n", - mode, resp.resp.result, resp.resp.error); + cnss_pr_err("Mode request failed, mode: %s(%d), result: %d, err: %d\n", + cnss_qmi_mode_to_str(mode), mode, resp.resp.result, + resp.resp.error); ret = resp.resp.result; goto out; } diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 505a9e016777..9347882fba92 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -397,7 +397,7 @@ static struct { int user_cal_read; int user_cal_available; u32 user_cal_rcvd; - int user_cal_exp_size; + u32 user_cal_exp_size; int iris_xo_mode_set; int fw_vbatt_state; char wlan_nv_macAddr[WLAN_MAC_ADDR_SIZE]; diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 6bf41edc37ff..8e66cd5770b5 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -278,6 +278,7 @@ #define PERST_PROPAGATION_DELAY_US_MIN 1000 #define PERST_PROPAGATION_DELAY_US_MAX 1005 +#define SWITCH_DELAY_MAX 20 #define REFCLK_STABILIZATION_DELAY_US_MIN 1000 #define REFCLK_STABILIZATION_DELAY_US_MAX 1005 #define LINK_UP_TIMEOUT_US_MIN 5000 @@ -626,6 +627,7 @@ struct msm_pcie_dev_t { bool ext_ref_clk; bool common_phy; uint32_t ep_latency; + uint32_t switch_latency; uint32_t wr_halt_size; uint32_t cpl_timeout; uint32_t current_bdf; @@ -1985,6 +1987,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->common_phy); PCIE_DBG_FS(dev, "ep_latency: %dms\n", dev->ep_latency); + PCIE_DBG_FS(dev, "switch_latency: %dms\n", + dev->switch_latency); PCIE_DBG_FS(dev, "wr_halt_size: 0x%x\n", dev->wr_halt_size); PCIE_DBG_FS(dev, "cpl_timeout: 0x%x\n", @@ -4676,7 +4680,15 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) goto link_fail; } - msleep(500); + if (dev->switch_latency) { + PCIE_DBG(dev, "switch_latency: %dms\n", + dev->switch_latency); + if (dev->switch_latency <= SWITCH_DELAY_MAX) + usleep_range(dev->switch_latency * 1000, + dev->switch_latency * 1000); + else + msleep(dev->switch_latency); + } msm_pcie_config_controller(dev); @@ -6280,6 +6292,20 @@ static int msm_pcie_probe(struct platform_device *pdev) PCIE_DBG(&msm_pcie_dev[rc_idx], "RC%d: ep-latency: 0x%x.\n", rc_idx, msm_pcie_dev[rc_idx].ep_latency); + msm_pcie_dev[rc_idx].switch_latency = 0; + ret = of_property_read_u32((&pdev->dev)->of_node, + "qcom,switch-latency", + &msm_pcie_dev[rc_idx].switch_latency); + + if (ret) + PCIE_DBG(&msm_pcie_dev[rc_idx], + "RC%d: switch-latency does not exist.\n", + rc_idx); + else + PCIE_DBG(&msm_pcie_dev[rc_idx], + "RC%d: switch-latency: 0x%x.\n", + rc_idx, msm_pcie_dev[rc_idx].switch_latency); + msm_pcie_dev[rc_idx].wr_halt_size = 0; ret = of_property_read_u32(pdev->dev.of_node, "qcom,wr-halt-size", diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 7ed83fb74fcc..62e263a139cc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -1654,6 +1654,21 @@ int ipa3_setup_dflt_rt_tables(void) return 0; } +static int ipa3_clkon_cfg_wa(void) +{ + struct ipahal_reg_clkon_cfg clkon_cfg = { 0 }; + int ret = 0; + + clkon_cfg.cgc_open_misc = 1; + + if (ipa3_cfg_clkon_cfg(&clkon_cfg)) { + IPAERR("fail to set cgc_open_misc = 1\n"); + ret = -EPERM; + } + + return ret; +} + static int ipa3_setup_exception_path(void) { struct ipa_ioc_add_hdr *hdr; @@ -3962,6 +3977,8 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, /* Prevent consequent calls from trying to load the FW again. */ if (ipa3_ctx->ipa_initialization_complete) return 0; + /* move proxy vote for modem on ipa3_post_init */ + IPA_ACTIVE_CLIENTS_INC_SPECIAL("PROXY_CLK_VOTE"); if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) { memset(&gsi_props, 0, sizeof(gsi_props)); @@ -4063,8 +4080,14 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, ipa3_trigger_ipa_ready_cbs(); complete_all(&ipa3_ctx->init_completion_obj); - pr_info("IPA driver initialization was successful.\n"); + /* WA to disable MISC clock gating for IPA_HW_v3_1 */ + if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_1) { + pr_info(" WA to set cgc_open_misc = 1\n"); + ipa3_clkon_cfg_wa(); + } + + pr_info("IPA driver initialization was successful\n"); return 0; fail_teth_bridge_driver_init: @@ -4275,7 +4298,6 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, int i; struct ipa3_flt_tbl *flt_tbl; struct ipa3_rt_tbl_set *rset; - struct ipa_active_client_logging_info log_info; IPADBG("IPA Driver initialization started\n"); @@ -4465,8 +4487,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, mutex_init(&ipa3_ctx->ipa3_active_clients.mutex); spin_lock_init(&ipa3_ctx->ipa3_active_clients.spinlock); - IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE"); - ipa3_active_clients_log_inc(&log_info, false); + /* move proxy vote for modem to ipa3_post_init() */ ipa3_ctx->ipa3_active_clients.cnt = 1; /* Assign resource limitation to each group */ @@ -4702,7 +4723,6 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, init_completion(&ipa3_ctx->init_completion_obj); init_completion(&ipa3_ctx->uc_loaded_completion_obj); - /* * For GSI, we can't register the GSI driver yet, as it expects * the GSI FW to be up and running before the registration. @@ -4745,6 +4765,8 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, IPADBG("ipa cdev added successful. major:%d minor:%d\n", MAJOR(ipa3_ctx->dev_num), MINOR(ipa3_ctx->dev_num)); + /* proxy vote for motem is added in ipa3_post_init() phase */ + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return 0; fail_cdev_add: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 5fe425ea7655..034b7fc45d8d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -2093,6 +2093,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void) struct ipa3_rx_pkt_wrapper *rx_pkt; struct ipa3_rx_pkt_wrapper *tmp; + spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); + list_for_each_entry_safe(rx_pkt, tmp, &ipa3_ctx->wc_memb.wlan_comm_desc_list, link) { list_del(&rx_pkt->link); @@ -2113,6 +2115,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void) IPAERR("wlan comm buff total cnt: %d\n", ipa3_ctx->wc_memb.wlan_comm_total_cnt); + spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); + } static void ipa3_alloc_wlan_rx_common_cache(u32 size) @@ -2150,11 +2154,13 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size) goto fail_dma_mapping; } + spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); list_add_tail(&rx_pkt->link, &ipa3_ctx->wc_memb.wlan_comm_desc_list); rx_len_cached = ++ipa3_ctx->wc_memb.wlan_comm_total_cnt; ipa3_ctx->wc_memb.wlan_comm_free_cnt++; + spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index f8529faf159d..7c3b5838242e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -359,7 +359,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, entry->hdr = hdr_entry; if (add_ref_hdr) hdr_entry->ref_cnt++; - entry->cookie = IPA_HDR_COOKIE; + entry->cookie = IPA_PROC_HDR_COOKIE; needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type); @@ -610,7 +610,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl; entry = ipa3_id_find(proc_ctx_hdl); - if (!entry || (entry->cookie != IPA_HDR_COOKIE)) { + if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) { IPAERR_RL("bad parm\n"); return -EINVAL; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index a890e88a8f61..4278dc45aad2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1877,6 +1877,7 @@ void ipa3_dump_buff_internal(void *base, dma_addr_t phy_base, u32 size); #else #define IPA_DUMP_BUFF(base, phy_base, size) #endif +int ipa3_cfg_clkon_cfg(struct ipahal_reg_clkon_cfg *clkon_cfg); int ipa3_init_mem_partition(struct device_node *dev_node); int ipa3_controller_static_bind(struct ipa3_controller *controller, enum ipa_hw_type ipa_hw_type); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 1fa1196dda63..e8bd0cd2ffb5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -795,6 +795,28 @@ void _ipa_sram_settings_read_v3_0(void) } /** + * ipa3_cfg_clkon_cfg() - configure IPA clkon_cfg + * @clkon_cfg: IPA clkon_cfg + * + * Return codes: + * 0: success + */ +int ipa3_cfg_clkon_cfg(struct ipahal_reg_clkon_cfg *clkon_cfg) +{ + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + IPADBG("cgc_open_misc = %d\n", + clkon_cfg->cgc_open_misc); + + ipahal_write_reg_fields(IPA_CLKON_CFG, clkon_cfg); + + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + return 0; +} + +/** * ipa3_cfg_route() - configure IPA route * @route: IPA route * diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 585f9e6bd492..0db9f30181a7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -19,6 +19,7 @@ #include "ipahal_reg_i.h" static const char *ipareg_name_to_str[IPA_REG_MAX] = { + __stringify(IPA_CLKON_CFG), __stringify(IPA_ROUTE), __stringify(IPA_IRQ_STTS_EE_n), __stringify(IPA_IRQ_EN_EE_n), @@ -858,6 +859,18 @@ static void ipareg_construct_endp_init_hdr_n(enum ipahal_reg_name reg, IPA_ENDP_INIT_HDR_n_HDR_LEN_BMSK); } +static void ipareg_construct_clkon_cfg(enum ipahal_reg_name reg, + const void *fields, u32 *val) +{ + struct ipahal_reg_clkon_cfg *clkon_cfg; + + clkon_cfg = (struct ipahal_reg_clkon_cfg *)fields; + + IPA_SETFIELD_IN_REG(*val, clkon_cfg->cgc_open_misc, + IPA_CLKON_CFG_CGC_OPEN_MISC_SHFT, + IPA_CLKON_CFG_CGC_OPEN_MISC_BMSK); +} + static void ipareg_construct_route(enum ipahal_reg_name reg, const void *fields, u32 *val) { @@ -1159,6 +1172,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { /* IPAv3.1 */ + [IPA_HW_v3_1][IPA_CLKON_CFG] = { + ipareg_construct_clkon_cfg, ipareg_parse_dummy, + 0x00000044, 0}, [IPA_HW_v3_1][IPA_IRQ_SUSPEND_INFO_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, 0x00003030, 0x1000}, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h index c37415f13380..4db09475d5e2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h @@ -22,6 +22,7 @@ * array as well. */ enum ipahal_reg_name { + IPA_CLKON_CFG, IPA_ROUTE, IPA_IRQ_STTS_EE_n, IPA_IRQ_EN_EE_n, @@ -90,6 +91,14 @@ enum ipahal_reg_name { }; /* + * struct ipahal_reg_clkon_cfg - IPA clock on configuration register + * @cgc_open_misc: clock gating needs for MISC + */ +struct ipahal_reg_clkon_cfg { + u32 cgc_open_misc; +}; + +/* * struct ipahal_reg_route - IPA route register * @route_dis: route disable * @route_def_pipe: route default pipe diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h index ac97e5ac0494..37458c4d0697 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h @@ -21,6 +21,9 @@ int ipahal_reg_init(enum ipa_hw_type ipa_hw_type); #define IPA_GETFIELD_FROM_REG(reg, shift, mask) \ (((reg) & (mask)) >> (shift)) +/* IPA_CLKON_CFG register */ +#define IPA_CLKON_CFG_CGC_OPEN_MISC_SHFT 0x3 +#define IPA_CLKON_CFG_CGC_OPEN_MISC_BMSK 0x8 /* IPA_ROUTE register */ #define IPA_ROUTE_ROUTE_DIS_SHFT 0x0 diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c index 4563810d7e5b..5b50666d30a2 100644 --- a/drivers/platform/msm/mhi_uci/mhi_uci.c +++ b/drivers/platform/msm/mhi_uci/mhi_uci.c @@ -326,73 +326,6 @@ static int mhi_init_inbound(struct uci_client *client_handle) return ret_val; } -static int mhi_uci_send_packet(struct mhi_client_handle **client_handle, - void *buf, - u32 size) -{ - u32 nr_avail_trbs = 0; - u32 i = 0; - void *data_loc = NULL; - unsigned long memcpy_result = 0; - int data_left_to_insert = 0; - size_t data_to_insert_now = 0; - u32 data_inserted_so_far = 0; - int ret_val = 0; - struct uci_client *uci_handle; - struct uci_buf *uci_buf; - - uci_handle = container_of(client_handle, struct uci_client, - out_attr.mhi_handle); - - nr_avail_trbs = atomic_read(&uci_handle->out_attr.avail_pkts); - data_left_to_insert = size; - - for (i = 0; i < nr_avail_trbs; ++i) { - data_to_insert_now = min_t(size_t, data_left_to_insert, - uci_handle->out_attr.max_packet_size); - data_loc = kmalloc(data_to_insert_now + sizeof(*uci_buf), - GFP_KERNEL); - if (!data_loc) { - uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, - "Failed to allocate memory 0x%zx\n", - data_to_insert_now); - return -ENOMEM; - } - uci_buf = data_loc + data_to_insert_now; - uci_buf->data = data_loc; - uci_buf->pkt_id = uci_handle->out_attr.pkt_count++; - memcpy_result = copy_from_user(uci_buf->data, - buf + data_inserted_so_far, - data_to_insert_now); - if (memcpy_result) - goto error_xfer; - - uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, - "At trb i = %d/%d, size = %lu, id %llu chan %d\n", - i, nr_avail_trbs, data_to_insert_now, uci_buf->pkt_id, - uci_handle->out_attr.chan_id); - ret_val = mhi_queue_xfer(*client_handle, uci_buf->data, - data_to_insert_now, MHI_EOT); - if (ret_val) { - goto error_xfer; - } else { - data_left_to_insert -= data_to_insert_now; - data_inserted_so_far += data_to_insert_now; - atomic_inc(&uci_handle->out_pkt_pend_ack); - atomic_dec(&uci_handle->out_attr.avail_pkts); - list_add_tail(&uci_buf->node, - &uci_handle->out_attr.buf_head); - } - if (!data_left_to_insert) - break; - } - return data_inserted_so_far; - -error_xfer: - kfree(uci_buf->data); - return data_inserted_so_far; -} - static int mhi_uci_send_status_cmd(struct uci_client *client) { void *buf = NULL; @@ -963,18 +896,11 @@ static ssize_t mhi_uci_client_write(struct file *file, goto sys_interrupt; } - while (bytes_transferrd != count) { - ret_val = mhi_uci_send_packet(&chan_attr->mhi_handle, - (void *)buf, count); - if (ret_val < 0) - goto sys_interrupt; + while (count) { + size_t xfer_size; + void *data_loc = NULL; + struct uci_buf *uci_buf; - bytes_transferrd += ret_val; - if (bytes_transferrd == count) - break; - uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, - "No descriptors available, did we poll, chan %d?\n", - chan); mutex_unlock(&chan_attr->chan_lock); ret_val = wait_event_interruptible(chan_attr->wq, (atomic_read(&chan_attr->avail_pkts) || @@ -991,6 +917,37 @@ static ssize_t mhi_uci_client_write(struct file *file, ret_val = -ERESTARTSYS; goto sys_interrupt; } + + xfer_size = min_t(size_t, count, chan_attr->max_packet_size); + data_loc = kmalloc(xfer_size + sizeof(*uci_buf), GFP_KERNEL); + if (!data_loc) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Failed to allocate memory %lu\n", xfer_size); + ret_val = -ENOMEM; + goto sys_interrupt; + } + + uci_buf = data_loc + xfer_size; + uci_buf->data = data_loc; + uci_buf->pkt_id = uci_handle->out_attr.pkt_count++; + ret_val = copy_from_user(uci_buf->data, buf, xfer_size); + if (unlikely(ret_val)) { + kfree(uci_buf->data); + goto sys_interrupt; + } + ret_val = mhi_queue_xfer(chan_attr->mhi_handle, uci_buf->data, + xfer_size, MHI_EOT); + if (unlikely(ret_val)) { + kfree(uci_buf->data); + goto sys_interrupt; + } + + bytes_transferrd += xfer_size; + count -= xfer_size; + buf += xfer_size; + atomic_inc(&uci_handle->out_pkt_pend_ack); + atomic_dec(&uci_handle->out_attr.avail_pkts); + list_add_tail(&uci_buf->node, &uci_handle->out_attr.buf_head); } mutex_unlock(&chan_attr->chan_lock); diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index de6c86984e3f..87ab2b24175f 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -4,6 +4,6 @@ obj-$(CONFIG_SMB1351_USB_CHARGER) += battery.o smb1351-charger.o pmic-voter.o obj-$(CONFIG_MSM_BCL_CTL) += msm_bcl.o obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o -obj-$(CONFIG_QPNP_SMB2) += battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o +obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o obj-$(CONFIG_SMB138X_CHARGER) += battery.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o obj-$(CONFIG_QPNP_QNOVO) += battery.o qpnp-qnovo.o diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index e03681ec13cc..265f98288745 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -1611,7 +1611,7 @@ static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv) static int fg_charge_full_update(struct fg_chip *chip) { union power_supply_propval prop = {0, }; - int rc, msoc, bsoc, recharge_soc; + int rc, msoc, bsoc, recharge_soc, msoc_raw; u8 full_soc[2] = {0xFF, 0xFF}; if (!chip->dt.hold_soc_while_full) @@ -1647,6 +1647,7 @@ static int fg_charge_full_update(struct fg_chip *chip) pr_err("Error in getting msoc, rc=%d\n", rc); goto out; } + msoc_raw = DIV_ROUND_CLOSEST(msoc * FULL_SOC_RAW, FULL_CAPACITY); fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n", msoc, bsoc, chip->health, chip->charge_status, @@ -1670,7 +1671,7 @@ static int fg_charge_full_update(struct fg_chip *chip) fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n", msoc); } - } else if ((bsoc >> 8) <= recharge_soc && chip->charge_full) { + } else if (msoc_raw < recharge_soc && chip->charge_full) { chip->delta_soc = FULL_CAPACITY - msoc; /* @@ -1700,8 +1701,8 @@ static int fg_charge_full_update(struct fg_chip *chip) rc); goto out; } - fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d delta_soc: %d\n", - bsoc >> 8, recharge_soc, chip->delta_soc); + fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n", + msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc); } else { goto out; } diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 7b7f991ecba9..630d02eb7a67 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -19,6 +19,7 @@ #include <linux/power_supply.h> #include <linux/of.h> #include <linux/of_irq.h> +#include <linux/log2.h> #include <linux/qpnp/qpnp-revid.h> #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> @@ -122,87 +123,6 @@ static struct smb_params v1_params = { .max_u = 1575000, .step_u = 25000, }, - .step_soc_threshold[0] = { - .name = "step charge soc threshold 1", - .reg = STEP_CHG_SOC_OR_BATT_V_TH1_REG, - .min_u = 0, - .max_u = 100, - .step_u = 1, - }, - .step_soc_threshold[1] = { - .name = "step charge soc threshold 2", - .reg = STEP_CHG_SOC_OR_BATT_V_TH2_REG, - .min_u = 0, - .max_u = 100, - .step_u = 1, - }, - .step_soc_threshold[2] = { - .name = "step charge soc threshold 3", - .reg = STEP_CHG_SOC_OR_BATT_V_TH3_REG, - .min_u = 0, - .max_u = 100, - .step_u = 1, - }, - .step_soc_threshold[3] = { - .name = "step charge soc threshold 4", - .reg = STEP_CHG_SOC_OR_BATT_V_TH4_REG, - .min_u = 0, - .max_u = 100, - .step_u = 1, - }, - .step_soc = { - .name = "step charge soc", - .reg = STEP_CHG_SOC_VBATT_V_REG, - .min_u = 0, - .max_u = 100, - .step_u = 1, - .set_proc = smblib_mapping_soc_from_field_value, - }, - .step_cc_delta[0] = { - .name = "step charge current delta 1", - .reg = STEP_CHG_CURRENT_DELTA1_REG, - .min_u = 100000, - .max_u = 3200000, - .step_u = 100000, - .get_proc = smblib_mapping_cc_delta_to_field_value, - .set_proc = smblib_mapping_cc_delta_from_field_value, - }, - .step_cc_delta[1] = { - .name = "step charge current delta 2", - .reg = STEP_CHG_CURRENT_DELTA2_REG, - .min_u = 100000, - .max_u = 3200000, - .step_u = 100000, - .get_proc = smblib_mapping_cc_delta_to_field_value, - .set_proc = smblib_mapping_cc_delta_from_field_value, - }, - .step_cc_delta[2] = { - .name = "step charge current delta 3", - .reg = STEP_CHG_CURRENT_DELTA3_REG, - .min_u = 100000, - .max_u = 3200000, - .step_u = 100000, - .get_proc = smblib_mapping_cc_delta_to_field_value, - .set_proc = smblib_mapping_cc_delta_from_field_value, - }, - .step_cc_delta[3] = { - .name = "step charge current delta 4", - .reg = STEP_CHG_CURRENT_DELTA4_REG, - .min_u = 100000, - .max_u = 3200000, - .step_u = 100000, - .get_proc = smblib_mapping_cc_delta_to_field_value, - .set_proc = smblib_mapping_cc_delta_from_field_value, - }, - .step_cc_delta[4] = { - .name = "step charge current delta 5", - .reg = STEP_CHG_CURRENT_DELTA5_REG, - .min_u = 100000, - .max_u = 3200000, - .step_u = 100000, - .get_proc = smblib_mapping_cc_delta_to_field_value, - .set_proc = smblib_mapping_cc_delta_from_field_value, - }, .freq_buck = { .name = "buck switching frequency", .reg = CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG, @@ -236,7 +156,6 @@ static struct smb_params pm660_params = { }, }; -#define STEP_CHARGING_MAX_STEPS 5 struct smb_dt_props { int usb_icl_ua; int dc_icl_ua; @@ -244,14 +163,13 @@ struct smb_dt_props { int wipower_max_uw; int min_freq_khz; int max_freq_khz; - u32 step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1]; - s32 step_cc_delta[STEP_CHARGING_MAX_STEPS]; struct device_node *revid_dev_node; int float_option; int chg_inhibit_thr_mv; bool no_battery; bool hvdcp_disable; bool auto_recharge_soc; + int wd_bark_time; }; struct smb2 { @@ -273,6 +191,11 @@ module_param_named( #define MICRO_1P5A 1500000 #define MICRO_P1A 100000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 +#define MIN_WD_BARK_TIME 16 +#define DEFAULT_WD_BARK_TIME 64 +#define BITE_WDOG_TIMEOUT_8S 0x3 +#define BARK_WDOG_TIMEOUT_MASK GENMASK(3, 2) +#define BARK_WDOG_TIMEOUT_SHIFT 2 static int smb2_parse_dt(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; @@ -284,27 +207,13 @@ static int smb2_parse_dt(struct smb2 *chip) return -EINVAL; } - chg->step_chg_enabled = true; - - if (of_property_count_u32_elems(node, "qcom,step-soc-thresholds") - != STEP_CHARGING_MAX_STEPS - 1) - chg->step_chg_enabled = false; + chg->step_chg_enabled = of_property_read_bool(node, + "qcom,step-charging-enable"); - rc = of_property_read_u32_array(node, "qcom,step-soc-thresholds", - chip->dt.step_soc_threshold, - STEP_CHARGING_MAX_STEPS - 1); - if (rc < 0) - chg->step_chg_enabled = false; - - if (of_property_count_u32_elems(node, "qcom,step-current-deltas") - != STEP_CHARGING_MAX_STEPS) - chg->step_chg_enabled = false; - - rc = of_property_read_u32_array(node, "qcom,step-current-deltas", - chip->dt.step_cc_delta, - STEP_CHARGING_MAX_STEPS); - if (rc < 0) - chg->step_chg_enabled = false; + rc = of_property_read_u32(node, "qcom,wd-bark-time-secs", + &chip->dt.wd_bark_time); + if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME) + chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME; chip->dt.no_battery = of_property_read_bool(node, "qcom,batteryless-platform"); @@ -989,7 +898,6 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, - POWER_SUPPLY_PROP_STEP_CHARGING_STEP, POWER_SUPPLY_PROP_CHARGE_DONE, POWER_SUPPLY_PROP_PARALLEL_DISABLE, POWER_SUPPLY_PROP_SET_SHIP_MODE, @@ -1047,9 +955,6 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: val->intval = chg->step_chg_enabled; break; - case POWER_SUPPLY_PROP_STEP_CHARGING_STEP: - rc = smblib_get_prop_step_chg_step(chg, val); - break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: rc = smblib_get_prop_batt_voltage_now(chg, val); break; @@ -1163,6 +1068,9 @@ static int smb2_batt_set_prop(struct power_supply *psy, vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0); } break; + case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: + chg->step_chg_enabled = !!val->intval; + break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: chg->batt_profile_fcc_ua = val->intval; vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval); @@ -1203,6 +1111,7 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_DP_DM: case POWER_SUPPLY_PROP_RERUN_AICL: case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: + case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: return 1; default: break; @@ -1330,73 +1239,6 @@ static int smb2_init_vconn_regulator(struct smb2 *chip) /*************************** * HARDWARE INITIALIZATION * ***************************/ -static int smb2_config_step_charging(struct smb2 *chip) -{ - struct smb_charger *chg = &chip->chg; - int rc = 0; - int i; - - if (!chg->step_chg_enabled) - return rc; - - for (i = 0; i < STEP_CHARGING_MAX_STEPS - 1; i++) { - rc = smblib_set_charge_param(chg, - &chg->param.step_soc_threshold[i], - chip->dt.step_soc_threshold[i]); - if (rc < 0) { - pr_err("Couldn't configure soc thresholds rc = %d\n", - rc); - goto err_out; - } - } - - for (i = 0; i < STEP_CHARGING_MAX_STEPS; i++) { - rc = smblib_set_charge_param(chg, &chg->param.step_cc_delta[i], - chip->dt.step_cc_delta[i]); - if (rc < 0) { - pr_err("Couldn't configure cc delta rc = %d\n", - rc); - goto err_out; - } - } - - rc = smblib_write(chg, STEP_CHG_UPDATE_REQUEST_TIMEOUT_CFG_REG, - STEP_CHG_UPDATE_REQUEST_TIMEOUT_40S); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure soc request timeout reg rc=%d\n", - rc); - goto err_out; - } - - rc = smblib_write(chg, STEP_CHG_UPDATE_FAIL_TIMEOUT_CFG_REG, - STEP_CHG_UPDATE_FAIL_TIMEOUT_120S); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure soc fail timeout reg rc=%d\n", - rc); - goto err_out; - } - - /* - * enable step charging, source soc, standard mode, go to final - * state in case of failure. - */ - rc = smblib_write(chg, CHGR_STEP_CHG_MODE_CFG_REG, - STEP_CHARGING_ENABLE_BIT | - STEP_CHARGING_SOURCE_SELECT_BIT | - STEP_CHARGING_SOC_FAIL_OPTION_BIT); - if (rc < 0) { - dev_err(chg->dev, "Couldn't configure charger rc=%d\n", rc); - goto err_out; - } - - return 0; -err_out: - chg->step_chg_enabled = false; - return rc; -} - static int smb2_config_wipower_input_power(struct smb2 *chip, int uw) { int rc; @@ -1572,7 +1414,7 @@ static int smb2_init_hw(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; int rc; - u8 stat; + u8 stat, val; if (chip->dt.no_battery) chg->fake_capacity = 50; @@ -1720,11 +1562,27 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } - /* configure step charging */ - rc = smb2_config_step_charging(chip); - if (rc < 0) { - dev_err(chg->dev, "Couldn't configure step charging rc=%d\n", - rc); + val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT) & + BARK_WDOG_TIMEOUT_MASK; + val |= BITE_WDOG_TIMEOUT_8S; + rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG, + BITE_WDOG_DISABLE_CHARGING_CFG_BIT | + BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK, + val); + if (rc) { + pr_err("Couldn't configue WD config rc=%d\n", rc); + return rc; + } + + /* enable WD BARK and enable it on plugin */ + rc = smblib_masked_write(chg, WD_CFG_REG, + WATCHDOG_TRIGGER_AFP_EN_BIT | + WDOG_TIMER_EN_ON_PLUGIN_BIT | + BARK_WDOG_INT_EN_BIT, + WDOG_TIMER_EN_ON_PLUGIN_BIT | + BARK_WDOG_INT_EN_BIT); + if (rc) { + pr_err("Couldn't configue WD config rc=%d\n", rc); return rc; } @@ -1783,6 +1641,13 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg); + if (rc < 0) { + dev_err(chg->dev, "Couldn't read float charger options rc=%d\n", + rc); + return rc; + } + switch (chip->dt.chg_inhibit_thr_mv) { case 50: rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG, @@ -1944,8 +1809,8 @@ static int smb2_determine_initial_status(struct smb2 *chip) smblib_handle_usb_source_change(0, &irq_data); smblib_handle_chg_state_change(0, &irq_data); smblib_handle_icl_change(0, &irq_data); - smblib_handle_step_chg_state_change(0, &irq_data); - smblib_handle_step_chg_soc_update_request(0, &irq_data); + smblib_handle_batt_temp_changed(0, &irq_data); + smblib_handle_wdog_bark(0, &irq_data); return 0; } @@ -1967,18 +1832,15 @@ static struct smb_irq_info smb2_irqs[] = { }, [STEP_CHG_STATE_CHANGE_IRQ] = { .name = "step-chg-state-change", - .handler = smblib_handle_step_chg_state_change, - .wake = true, + .handler = NULL, }, [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = { .name = "step-chg-soc-update-fail", - .handler = smblib_handle_step_chg_soc_update_fail, - .wake = true, + .handler = NULL, }, [STEP_CHG_SOC_UPDATE_REQ_IRQ] = { .name = "step-chg-soc-update-request", - .handler = smblib_handle_step_chg_soc_update_request, - .wake = true, + .handler = NULL, }, /* OTG IRQs */ [OTG_FAIL_IRQ] = { @@ -2001,6 +1863,7 @@ static struct smb_irq_info smb2_irqs[] = { [BATT_TEMP_IRQ] = { .name = "bat-temp", .handler = smblib_handle_batt_temp_changed, + .wake = true, }, [BATT_OCP_IRQ] = { .name = "bat-ocp", @@ -2096,7 +1959,8 @@ static struct smb_irq_info smb2_irqs[] = { }, [WDOG_BARK_IRQ] = { .name = "wdog-bark", - .handler = NULL, + .handler = smblib_handle_wdog_bark, + .wake = true, }, [AICL_FAIL_IRQ] = { .name = "aicl-fail", @@ -2336,15 +2200,15 @@ static int smb2_probe(struct platform_device *pdev) return rc; } - rc = smblib_init(chg); + rc = smb2_parse_dt(chip); if (rc < 0) { - pr_err("Smblib_init failed rc=%d\n", rc); + pr_err("Couldn't parse device tree rc=%d\n", rc); goto cleanup; } - rc = smb2_parse_dt(chip); + rc = smblib_init(chg); if (rc < 0) { - pr_err("Couldn't parse device tree rc=%d\n", rc); + pr_err("Smblib_init failed rc=%d\n", rc); goto cleanup; } diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 64d71727f7e6..0ed07aa13855 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -23,6 +23,7 @@ #include "smb-lib.h" #include "smb-reg.h" #include "battery.h" +#include "step-chg-jeita.h" #include "storm-watch.h" #define smblib_err(chg, fmt, ...) \ @@ -102,35 +103,6 @@ unlock: return rc; } -static int smblib_get_step_cc_delta(struct smb_charger *chg, int *cc_delta_ua) -{ - int rc, step_state; - u8 stat; - - if (!chg->step_chg_enabled) { - *cc_delta_ua = 0; - return 0; - } - - rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", - rc); - return rc; - } - - step_state = (stat & STEP_CHARGING_STATUS_MASK) >> - STEP_CHARGING_STATUS_SHIFT; - rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state], - cc_delta_ua); - if (rc < 0) { - smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc); - return rc; - } - - return 0; -} - static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua) { int rc, cc_minus_ua; @@ -149,7 +121,7 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua) } rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp, - &cc_minus_ua); + &cc_minus_ua); if (rc < 0) { smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc); return rc; @@ -402,28 +374,6 @@ int smblib_set_charge_param(struct smb_charger *chg, return rc; } -static int step_charge_soc_update(struct smb_charger *chg, int capacity) -{ - int rc = 0; - - rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity); - if (rc < 0) { - smblib_err(chg, "Error in updating soc, rc=%d\n", rc); - return rc; - } - - rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG, - STEP_CHG_SOC_VBATT_V_UPDATE_BIT); - if (rc < 0) { - smblib_err(chg, - "Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n", - rc); - return rc; - } - - return rc; -} - int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) { int rc = 0; @@ -538,6 +488,45 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, /******************** * HELPER FUNCTIONS * ********************/ +static int smblib_request_dpdm(struct smb_charger *chg, bool enable) +{ + int rc = 0; + + /* fetch the DPDM regulator */ + if (!chg->dpdm_reg && of_get_property(chg->dev->of_node, + "dpdm-supply", NULL)) { + chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm"); + if (IS_ERR(chg->dpdm_reg)) { + rc = PTR_ERR(chg->dpdm_reg); + smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n", + rc); + chg->dpdm_reg = NULL; + return rc; + } + } + + if (enable) { + if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) { + smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n"); + rc = regulator_enable(chg->dpdm_reg); + if (rc < 0) + smblib_err(chg, + "Couldn't enable dpdm regulator rc=%d\n", + rc); + } + } else { + if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { + smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); + rc = regulator_disable(chg->dpdm_reg); + if (rc < 0) + smblib_err(chg, + "Couldn't disable dpdm regulator rc=%d\n", + rc); + } + } + + return rc; +} static void smblib_rerun_apsd(struct smb_charger *chg) { @@ -564,10 +553,17 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* if PD is active, APSD is disabled so won't have a valid result */ - if (chg->pd_active) + if (chg->pd_active) { chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; - else + } else { + /* + * Update real charger type only if its not FLOAT + * detected as as SDP + */ + if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT && + chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) chg->real_charger_type = apsd_result->pst; + } smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n", apsd_result->name, chg->pd_active); @@ -650,13 +646,9 @@ static void smblib_uusb_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); - if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { - smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); - rc = regulator_disable(chg->dpdm_reg); - if (rc < 0) - smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n", - rc); - } + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc); if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data; @@ -748,24 +740,9 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg) if (!val.intval) return 0; - /* fetch the DPDM regulator */ - if (!chg->dpdm_reg && of_get_property(chg->dev->of_node, - "dpdm-supply", NULL)) { - chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm"); - if (IS_ERR(chg->dpdm_reg)) { - smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n", - PTR_ERR(chg->dpdm_reg)); - chg->dpdm_reg = NULL; - } - } - - if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) { - smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n"); - rc = regulator_enable(chg->dpdm_reg); - if (rc < 0) - smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n", - rc); - } + rc = smblib_request_dpdm(chg, true); + if (rc < 0) + smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); chg->uusb_apsd_rerun_done = true; smblib_rerun_apsd(chg); @@ -835,6 +812,7 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) { int rc; u8 icl_options; + const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* power source is SDP */ switch (icl_ua) { @@ -859,6 +837,21 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return -EINVAL; } + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB && + apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) { + /* + * change the float charger configuration to SDP, if this + * is the case of SDP being detected as FLOAT + */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, + FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't set float ICL options rc=%d\n", + rc); + return rc; + } + } + rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options); if (rc < 0) { @@ -1804,30 +1797,6 @@ int smblib_get_prop_batt_temp(struct smb_charger *chg, return rc; } -int smblib_get_prop_step_chg_step(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - u8 stat; - - if (!chg->step_chg_enabled) { - val->intval = -1; - return 0; - } - - rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", - rc); - return rc; - } - - val->intval = (stat & STEP_CHARGING_STATUS_MASK) >> - STEP_CHARGING_STATUS_SHIFT; - - return rc; -} - int smblib_get_prop_batt_charge_done(struct smb_charger *chg, union power_supply_propval *val) { @@ -2476,6 +2445,31 @@ int smblib_get_prop_die_health(struct smb_charger *chg, return 0; } +#define SDP_CURRENT_UA 500000 +#define CDP_CURRENT_UA 1500000 +#define DCP_CURRENT_UA 1500000 +#define HVDCP_CURRENT_UA 3000000 +#define TYPEC_DEFAULT_CURRENT_UA 900000 +#define TYPEC_MEDIUM_CURRENT_UA 1500000 +#define TYPEC_HIGH_CURRENT_UA 3000000 +static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode) +{ + int rp_ua; + + switch (typec_mode) { + case POWER_SUPPLY_TYPEC_SOURCE_HIGH: + rp_ua = TYPEC_HIGH_CURRENT_UA; + break; + case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: + case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: + /* fall through */ + default: + rp_ua = DCP_CURRENT_UA; + } + + return rp_ua; +} + /******************* * USB PSY SETTERS * * *****************/ @@ -2493,14 +2487,54 @@ int smblib_set_prop_pd_current_max(struct smb_charger *chg, return rc; } +static int smblib_handle_usb_current(struct smb_charger *chg, + int usb_current) +{ + int rc = 0, rp_ua, typec_mode; + + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) { + if (usb_current == -ETIMEDOUT) { + /* + * Valid FLOAT charger, report the current based + * of Rp + */ + typec_mode = smblib_get_prop_typec_mode(chg); + rp_ua = get_rp_based_dcp_current(chg, typec_mode); + rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, + true, rp_ua); + if (rc < 0) + return rc; + } else { + /* + * FLOAT charger detected as SDP by USB driver, + * charge with the requested current and update the + * real_charger_type + */ + chg->real_charger_type = POWER_SUPPLY_TYPE_USB; + rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, + true, usb_current); + if (rc < 0) + return rc; + rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, + false, 0); + if (rc < 0) + return rc; + } + } else { + rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, + true, usb_current); + } + + return rc; +} + int smblib_set_prop_usb_current_max(struct smb_charger *chg, const union power_supply_propval *val) { int rc = 0; if (!chg->pd_active) { - rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, - true, val->intval); + rc = smblib_handle_usb_current(chg, val->intval); } else if (chg->system_suspend_supported) { if (val->intval <= USBIN_25MA) rc = vote(chg->usb_icl_votable, @@ -2883,46 +2917,72 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, return rc; } +static int smblib_recover_from_soft_jeita(struct smb_charger *chg) +{ + u8 stat_1, stat_2; + int rc; + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", + rc); + return rc; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", + rc); + return rc; + } + + if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) && + ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) { + /* + * We are moving from JEITA soft -> Normal and charging + * is terminated + */ + rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable charging rc=%d\n", + rc); + return rc; + } + rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, + CHARGING_ENABLE_CMD_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable charging rc=%d\n", + rc); + return rc; + } + } + + chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK; + + return 0; +} + /*********************** * USB MAIN PSY GETTERS * *************************/ int smblib_get_prop_fcc_delta(struct smb_charger *chg, - union power_supply_propval *val) + union power_supply_propval *val) { - int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0; - - rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua); - if (rc < 0) { - smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc); - step_cc_delta_ua = 0; - } else { - hw_cc_delta_ua = step_cc_delta_ua; - } + int rc, jeita_cc_delta_ua = 0; rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua); if (rc < 0) { smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc); jeita_cc_delta_ua = 0; - } else if (jeita_cc_delta_ua < 0) { - /* HW will take the min between JEITA and step charge */ - hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua); } - val->intval = hw_cc_delta_ua; + val->intval = jeita_cc_delta_ua; return 0; } /*********************** * USB MAIN PSY SETTERS * *************************/ - -#define SDP_CURRENT_UA 500000 -#define CDP_CURRENT_UA 1500000 -#define DCP_CURRENT_UA 1500000 -#define HVDCP_CURRENT_UA 3000000 -#define TYPEC_DEFAULT_CURRENT_UA 900000 -#define TYPEC_MEDIUM_CURRENT_UA 1500000 -#define TYPEC_HIGH_CURRENT_UA 3000000 int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua) { @@ -3089,62 +3149,19 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) return IRQ_HANDLED; } -irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data) -{ - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; - - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); - - if (chg->step_chg_enabled) - rerun_election(chg->fcc_votable); - - return IRQ_HANDLED; -} - -irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data) -{ - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; - - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); - - if (chg->step_chg_enabled) - rerun_election(chg->fcc_votable); - - return IRQ_HANDLED; -} - -#define STEP_SOC_REQ_MS 3000 -irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data) +irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; int rc; - union power_supply_propval pval = {0, }; - - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); - if (!chg->bms_psy) { - schedule_delayed_work(&chg->step_soc_req_work, - msecs_to_jiffies(STEP_SOC_REQ_MS)); + rc = smblib_recover_from_soft_jeita(chg); + if (rc < 0) { + smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n", + rc); return IRQ_HANDLED; } - rc = smblib_get_prop_batt_capacity(chg, &pval); - if (rc < 0) - smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc); - else - step_charge_soc_update(chg, pval.intval); - - return IRQ_HANDLED; -} - -irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data) -{ - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; - rerun_election(chg->fcc_votable); power_supply_changed(chg->batt_psy); return IRQ_HANDLED; @@ -3256,25 +3273,10 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V : chg->chg_freq.freq_removal); - /* fetch the DPDM regulator */ - if (!chg->dpdm_reg && of_get_property(chg->dev->of_node, - "dpdm-supply", NULL)) { - chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm"); - if (IS_ERR(chg->dpdm_reg)) { - smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n", - PTR_ERR(chg->dpdm_reg)); - chg->dpdm_reg = NULL; - } - } - if (vbus_rising) { - if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) { - smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n"); - rc = regulator_enable(chg->dpdm_reg); - if (rc < 0) - smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n", - rc); - } + rc = smblib_request_dpdm(chg, true); + if (rc < 0) + smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); /* Schedule work to enable parallel charger */ vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); @@ -3294,13 +3296,9 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) } } - if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { - smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); - rc = regulator_disable(chg->dpdm_reg); - if (rc < 0) - smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n", - rc); - } + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); } if (chg->micro_usb_mode) @@ -3521,24 +3519,6 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, rising ? "rising" : "falling"); } -static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode) -{ - int rp_ua; - - switch (typec_mode) { - case POWER_SUPPLY_TYPEC_SOURCE_HIGH: - rp_ua = TYPEC_HIGH_CURRENT_UA; - break; - case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: - case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: - /* fall through */ - default: - rp_ua = DCP_CURRENT_UA; - } - - return rp_ua; -} - static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) { int typec_mode; @@ -3564,11 +3544,17 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); break; case POWER_SUPPLY_TYPE_USB_DCP: - case POWER_SUPPLY_TYPE_USB_FLOAT: typec_mode = smblib_get_prop_typec_mode(chg); rp_ua = get_rp_based_dcp_current(chg, typec_mode); vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua); break; + case POWER_SUPPLY_TYPE_USB_FLOAT: + /* + * limit ICL to 100mA, the USB driver will enumerate to check + * if this is a SDP and appropriately set the current + */ + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); + break; case POWER_SUPPLY_TYPE_USB_HVDCP: case POWER_SUPPLY_TYPE_USB_HVDCP_3: vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000); @@ -3700,13 +3686,9 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) chg->cc2_detach_wa_active = false; - if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { - smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); - rc = regulator_disable(chg->dpdm_reg); - if (rc < 0) - smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n", - rc); - } + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data; @@ -3763,6 +3745,13 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) chg->pd_hard_reset = 0; chg->typec_legacy_valid = false; + /* write back the default FLOAT charger configuration */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, + (u8)FLOAT_OPTIONS_MASK, chg->float_cfg); + if (rc < 0) + smblib_err(chg, "Couldn't write float charger options rc=%d\n", + rc); + /* reset back to 120mS tCC debounce */ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0); if (rc < 0) @@ -3842,10 +3831,14 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg) smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", rc); - if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) + if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) { typec_sink_insertion(chg); - else + } else { + rc = smblib_request_dpdm(chg, true); + if (rc < 0) + smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); typec_sink_removal(chg); + } } static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) @@ -3858,6 +3851,24 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) return; /* + * if APSD indicates FLOAT and the USB stack had detected SDP, + * do not respond to Rp changes as we do not confirm that its + * a legacy cable + */ + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) + return; + /* + * We want the ICL vote @ 100mA for a FLOAT charger + * until the detection by the USB stack is complete. + * Ignore the Rp changes unless there is a + * pre-existing valid vote. + */ + if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT && + get_client_vote(chg->usb_icl_votable, + LEGACY_UNKNOWN_VOTER) <= 100000) + return; + + /* * handle Rp change for DCP/FLOAT/OCP. * Update the current only if the Rp is different from * the last Rp value. @@ -4042,10 +4053,15 @@ irqreturn_t smblib_handle_wdog_bark(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; int rc; + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT); if (rc < 0) smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc); + if (chg->step_chg_enabled) + power_supply_changed(chg->batt_psy); + return IRQ_HANDLED; } @@ -4128,22 +4144,6 @@ static void bms_update_work(struct work_struct *work) power_supply_changed(chg->batt_psy); } -static void step_soc_req_work(struct work_struct *work) -{ - struct smb_charger *chg = container_of(work, struct smb_charger, - step_soc_req_work.work); - union power_supply_propval pval = {0, }; - int rc; - - rc = smblib_get_prop_batt_capacity(chg, &pval); - if (rc < 0) { - smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc); - return; - } - - step_charge_soc_update(chg, pval.intval); -} - static void clear_hdc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, @@ -4676,7 +4676,6 @@ int smblib_init(struct smb_charger *chg) INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); - INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work); INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work); INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); @@ -4698,6 +4697,13 @@ int smblib_init(struct smb_charger *chg) return rc; } + rc = qcom_step_chg_init(chg->step_chg_enabled); + if (rc < 0) { + smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n", + rc); + return rc; + } + rc = smblib_create_votables(chg); if (rc < 0) { smblib_err(chg, "Couldn't create votables rc=%d\n", @@ -4732,7 +4738,6 @@ int smblib_deinit(struct smb_charger *chg) cancel_work_sync(&chg->bms_update_work); cancel_work_sync(&chg->rdstd_cc2_detach_work); cancel_delayed_work_sync(&chg->hvdcp_detect_work); - cancel_delayed_work_sync(&chg->step_soc_req_work); cancel_delayed_work_sync(&chg->clear_hdc_work); cancel_work_sync(&chg->otg_oc_work); cancel_work_sync(&chg->vconn_oc_work); @@ -4744,6 +4749,7 @@ int smblib_deinit(struct smb_charger *chg) cancel_delayed_work_sync(&chg->bb_removal_work); power_supply_unreg_notifier(&chg->nb); smblib_destroy_votables(chg); + qcom_step_chg_deinit(); qcom_batt_deinit(); break; case PARALLEL_SLAVE: diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 18714827b8d2..8c810352f78f 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -190,9 +190,6 @@ struct smb_params { struct smb_chg_param dc_icl_div2_mid_hv; struct smb_chg_param dc_icl_div2_hv; struct smb_chg_param jeita_cc_comp; - struct smb_chg_param step_soc_threshold[4]; - struct smb_chg_param step_soc; - struct smb_chg_param step_cc_delta[5]; struct smb_chg_param freq_buck; struct smb_chg_param freq_boost; }; @@ -287,7 +284,6 @@ struct smb_charger { struct work_struct rdstd_cc2_detach_work; struct delayed_work hvdcp_detect_work; struct delayed_work ps_change_timeout_work; - struct delayed_work step_soc_req_work; struct delayed_work clear_hdc_work; struct work_struct otg_oc_work; struct work_struct vconn_oc_work; @@ -329,6 +325,8 @@ struct smb_charger { bool pr_swap_in_progress; int typec_mode; int usb_icl_change_irq_enabled; + u32 jeita_status; + u8 float_cfg; /* workaround flag */ u32 wa_flags; @@ -383,9 +381,6 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev); irqreturn_t smblib_handle_debug(int irq, void *data); irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data); irqreturn_t smblib_handle_chg_state_change(int irq, void *data); -irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data); -irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data); -irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data); irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data); irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data); irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data); @@ -423,9 +418,6 @@ int smblib_get_prop_batt_current_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_temp(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_step_chg_step(struct smb_charger *chg, - union power_supply_propval *val); - int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, @@ -505,7 +497,7 @@ int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg, void smblib_suspend_on_debug_battery(struct smb_charger *chg); int smblib_rerun_apsd_if_required(struct smb_charger *chg); int smblib_get_prop_fcc_delta(struct smb_charger *chg, - union power_supply_propval *val); + union power_supply_propval *val); int smblib_icl_override(struct smb_charger *chg, bool override); int smblib_dp_dm(struct smb_charger *chg, int val); int smblib_rerun_aicl(struct smb_charger *chg); diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 335b160e24a5..ec74e3825dd5 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -845,6 +845,13 @@ static int smb138x_init_slave_hw(struct smb138x *chip) } } + /* configure to a fixed 700khz freq to avoid tdie errors */ + rc = smblib_set_charge_param(chg, &chg->param.freq_buck, 700); + if (rc < 0) { + pr_err("Couldn't configure 700Khz switch freq rc=%d\n", rc); + return rc; + } + /* enable watchdog bark and bite interrupts, and disable the watchdog */ rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT | WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c new file mode 100644 index 000000000000..a2c08be960be --- /dev/null +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -0,0 +1,272 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define pr_fmt(fmt) "QCOM-STEPCHG: %s: " fmt, __func__ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/power_supply.h> +#include <linux/slab.h> +#include <linux/pmic-voter.h> +#include "step-chg-jeita.h" + +#define MAX_STEP_CHG_ENTRIES 8 +#define STEP_CHG_VOTER "STEP_CHG_VOTER" +#define STATUS_CHANGE_VOTER "STATUS_CHANGE_VOTER" + +#define is_between(left, right, value) \ + (((left) >= (right) && (left) >= (value) \ + && (value) >= (right)) \ + || ((left) <= (right) && (left) <= (value) \ + && (value) <= (right))) + +struct step_chg_data { + u32 vbatt_soc_low; + u32 vbatt_soc_high; + u32 fcc_ua; +}; + +struct step_chg_cfg { + u32 psy_prop; + char *prop_name; + struct step_chg_data cfg[MAX_STEP_CHG_ENTRIES]; +}; + +struct step_chg_info { + ktime_t last_update_time; + bool step_chg_enable; + + struct votable *fcc_votable; + struct wakeup_source *step_chg_ws; + struct power_supply *batt_psy; + struct delayed_work status_change_work; + struct notifier_block nb; +}; + +static struct step_chg_info *the_chip; + +/* + * Step Charging Configuration + * Update the table based on the battery profile + * Supports VBATT and SOC based source + */ +static struct step_chg_cfg step_chg_config = { + .psy_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW, + .prop_name = "VBATT", + .cfg = { + /* VBAT_LOW VBAT_HIGH FCC */ + {3600000, 4000000, 3000000}, + {4000000, 4200000, 2800000}, + {4200000, 4400000, 2000000}, + }, +/* + * SOC STEP-CHG configuration example. + * + * .psy_prop = POWER_SUPPLY_PROP_CAPACITY, + * .prop_name = "SOC", + * .cfg = { + * //SOC_LOW SOC_HIGH FCC + * {20, 70, 3000000}, + * {70, 90, 2750000}, + * {90, 100, 2500000}, + * }, + */ +}; + +static bool is_batt_available(struct step_chg_info *chip) +{ + if (!chip->batt_psy) + chip->batt_psy = power_supply_get_by_name("battery"); + + if (!chip->batt_psy) + return false; + + return true; +} + +static int get_fcc(int threshold) +{ + int i; + + for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++) + if (is_between(step_chg_config.cfg[i].vbatt_soc_low, + step_chg_config.cfg[i].vbatt_soc_high, threshold)) + return step_chg_config.cfg[i].fcc_ua; + + return -ENODATA; +} + +static int handle_step_chg_config(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0, fcc_ua = 0; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, &pval); + if (rc < 0) + chip->step_chg_enable = 0; + else + chip->step_chg_enable = pval.intval; + + if (!chip->step_chg_enable) { + if (chip->fcc_votable) + vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0); + return 0; + } + + rc = power_supply_get_property(chip->batt_psy, + step_chg_config.psy_prop, &pval); + if (rc < 0) { + pr_err("Couldn't read %s property rc=%d\n", + step_chg_config.prop_name, rc); + return rc; + } + + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) + return -EINVAL; + + fcc_ua = get_fcc(pval.intval); + if (fcc_ua < 0) { + /* remove the vote if no step-based fcc is found */ + vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0); + return 0; + } + + vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua); + + pr_debug("%s = %d Step-FCC = %duA\n", + step_chg_config.prop_name, pval.intval, fcc_ua); + + return 0; +} + +#define STEP_CHG_HYSTERISIS_DELAY_US 5000000 /* 5 secs */ +static void status_change_work(struct work_struct *work) +{ + struct step_chg_info *chip = container_of(work, + struct step_chg_info, status_change_work.work); + int rc = 0; + u64 elapsed_us; + + elapsed_us = ktime_us_delta(ktime_get(), chip->last_update_time); + if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US) + goto release_ws; + + if (!is_batt_available(chip)) + goto release_ws; + + rc = handle_step_chg_config(chip); + if (rc < 0) + goto release_ws; + + chip->last_update_time = ktime_get(); + +release_ws: + __pm_relax(chip->step_chg_ws); +} + +static int step_chg_notifier_call(struct notifier_block *nb, + unsigned long ev, void *v) +{ + struct power_supply *psy = v; + struct step_chg_info *chip = container_of(nb, struct step_chg_info, nb); + + if (ev != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + if ((strcmp(psy->desc->name, "battery") == 0)) { + __pm_stay_awake(chip->step_chg_ws); + schedule_delayed_work(&chip->status_change_work, 0); + } + + return NOTIFY_OK; +} + +static int step_chg_register_notifier(struct step_chg_info *chip) +{ + int rc; + + chip->nb.notifier_call = step_chg_notifier_call; + rc = power_supply_reg_notifier(&chip->nb); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + return rc; + } + + return 0; +} + +int qcom_step_chg_init(bool step_chg_enable) +{ + int rc; + struct step_chg_info *chip; + + if (the_chip) { + pr_err("Already initialized\n"); + return -EINVAL; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->step_chg_ws = wakeup_source_register("qcom-step-chg"); + if (!chip->step_chg_ws) { + rc = -EINVAL; + goto cleanup; + } + + chip->step_chg_enable = step_chg_enable; + + if (step_chg_enable && (!step_chg_config.psy_prop || + !step_chg_config.prop_name)) { + /* fail if step-chg configuration is invalid */ + pr_err("Step-chg configuration not defined - fail\n"); + return -ENODATA; + } + + INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); + + rc = step_chg_register_notifier(chip); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + goto release_wakeup_source; + } + + the_chip = chip; + + if (step_chg_enable) + pr_info("Step charging enabled. Using %s source\n", + step_chg_config.prop_name); + + return 0; + +release_wakeup_source: + wakeup_source_unregister(chip->step_chg_ws); +cleanup: + kfree(chip); + return rc; +} + +void qcom_step_chg_deinit(void) +{ + struct step_chg_info *chip = the_chip; + + if (!chip) + return; + + cancel_delayed_work_sync(&chip->status_change_work); + power_supply_unreg_notifier(&chip->nb); + wakeup_source_unregister(chip->step_chg_ws); + the_chip = NULL; + kfree(chip); +} diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h new file mode 100644 index 000000000000..928eeb7a670b --- /dev/null +++ b/drivers/power/supply/qcom/step-chg-jeita.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __STEP_CHG_H__ +#define __STEP_CHG_H__ +int qcom_step_chg_init(bool); +void qcom_step_chg_deinit(void); +#endif /* __STEP_CHG_H__ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index a2f2cc0c2c51..c23023f43d30 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1483,7 +1483,7 @@ start: hba->clk_gating.state = REQ_CLKS_ON; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); - queue_work(hba->clk_gating.ungating_workq, + queue_work(hba->clk_gating.clk_gating_workq, &hba->clk_gating.ungate_work); /* * fall through to check if we should wait for this @@ -1751,7 +1751,8 @@ static enum hrtimer_restart ufshcd_clkgate_hrtimer_handler( struct ufs_hba *hba = container_of(timer, struct ufs_hba, clk_gating.gate_hrtimer); - schedule_work(&hba->clk_gating.gate_work); + queue_work(hba->clk_gating.clk_gating_workq, + &hba->clk_gating.gate_work); return HRTIMER_NORESTART; } @@ -1759,7 +1760,7 @@ static enum hrtimer_restart ufshcd_clkgate_hrtimer_handler( static void ufshcd_init_clk_gating(struct ufs_hba *hba) { struct ufs_clk_gating *gating = &hba->clk_gating; - char wq_name[sizeof("ufs_clk_ungating_00")]; + char wq_name[sizeof("ufs_clk_gating_00")]; hba->clk_gating.state = CLKS_ON; @@ -1788,9 +1789,10 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba) hrtimer_init(&gating->gate_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); gating->gate_hrtimer.function = ufshcd_clkgate_hrtimer_handler; - snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_ungating_%d", + snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d", hba->host->host_no); - hba->clk_gating.ungating_workq = create_singlethread_workqueue(wq_name); + hba->clk_gating.clk_gating_workq = + create_singlethread_workqueue(wq_name); gating->is_enabled = true; @@ -1854,7 +1856,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) device_remove_file(hba->dev, &hba->clk_gating.enable_attr); ufshcd_cancel_gate_work(hba); cancel_work_sync(&hba->clk_gating.ungate_work); - destroy_workqueue(hba->clk_gating.ungating_workq); + destroy_workqueue(hba->clk_gating.clk_gating_workq); } static void ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, u32 delay) diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index d66205ff9f5d..da3ad78d3405 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -431,7 +431,7 @@ struct ufs_clk_gating { struct device_attribute enable_attr; bool is_enabled; int active_reqs; - struct workqueue_struct *ungating_workq; + struct workqueue_struct *clk_gating_workq; }; /* Hibern8 state */ diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index c74cd3b814cd..bf815cb68f90 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -84,35 +84,59 @@ module_param(qmi_timeout, ulong, 0600); } while (0) #define icnss_pr_err(_fmt, ...) do { \ - pr_err(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + printk("%s" pr_fmt(_fmt), KERN_ERR, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ } while (0) #define icnss_pr_warn(_fmt, ...) do { \ - pr_warn(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("WRN: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + printk("%s" pr_fmt(_fmt), KERN_WARNING, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ } while (0) #define icnss_pr_info(_fmt, ...) do { \ - pr_info(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("INF: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + printk("%s" pr_fmt(_fmt), KERN_INFO, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ } while (0) +#if defined(CONFIG_DYNAMIC_DEBUG) #define icnss_pr_dbg(_fmt, ...) do { \ - pr_debug(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("DBG: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_string(pr_fmt(_fmt), ##__VA_ARGS__); \ } while (0) #define icnss_pr_vdbg(_fmt, ...) do { \ - pr_debug(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_long_string(pr_fmt(_fmt), ##__VA_ARGS__); \ + } while (0) +#elif defined(DEBUG) +#define icnss_pr_dbg(_fmt, ...) do { \ + printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ + } while (0) + +#define icnss_pr_vdbg(_fmt, ...) do { \ + printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ + } while (0) +#else +#define icnss_pr_dbg(_fmt, ...) do { \ + no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ } while (0) +#define icnss_pr_vdbg(_fmt, ...) do { \ + no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ + } while (0) +#endif + #ifdef CONFIG_ICNSS_DEBUG #define ICNSS_ASSERT(_condition) do { \ if (!(_condition)) { \ @@ -2579,21 +2603,22 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, if (event_data == NULL) return notifier_from_errno(-ENOMEM); + event_data->crashed = true; + if (state == NULL) { - event_data->crashed = true; priv->stats.recovery.root_pd_crash++; goto event_post; } switch (*state) { case ROOT_PD_WDOG_BITE: - event_data->crashed = true; event_data->wdog_bite = true; priv->stats.recovery.root_pd_crash++; break; case ROOT_PD_SHUTDOWN: cause = ICNSS_ROOT_PD_SHUTDOWN; priv->stats.recovery.root_pd_shutdown++; + event_data->crashed = false; break; case USER_PD_STATE_CHANGE: if (test_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state)) { @@ -2605,7 +2630,6 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, } break; default: - event_data->crashed = true; priv->stats.recovery.root_pd_crash++; break; } diff --git a/drivers/soc/qcom/scm_qcpe.c b/drivers/soc/qcom/scm_qcpe.c index 54a978157bda..0263350ae931 100644 --- a/drivers/soc/qcom/scm_qcpe.c +++ b/drivers/soc/qcom/scm_qcpe.c @@ -219,7 +219,7 @@ static int scm_call_qcpe(u32 fn_id, struct scm_desc *desc) if (!opened) { ret = habmm_socket_open(&handle, MM_QCPE_VM1, 0, 0); if (ret != HAB_OK) { - pr_err("scm_call2: habmm_socket_open failed with ret = %d", + pr_err("scm_call_qcpe: habmm_socket_open failed with ret = %d", ret); return ret; } @@ -239,19 +239,26 @@ static int scm_call_qcpe(u32 fn_id, struct scm_desc *desc) return ret; size_bytes = sizeof(smc_params); + memset(&smc_params, 0x0, sizeof(smc_params)); ret = habmm_socket_recv(handle, &smc_params, &size_bytes, 0, 0); if (ret != HAB_OK) return ret; + if (size_bytes != sizeof(smc_params)) { + pr_err("scm_call_qcpe: expected size: %lu, actual=%u\n", + sizeof(smc_params), size_bytes); + return SCM_ERROR; + } + desc->ret[0] = smc_params.x1; desc->ret[1] = smc_params.x2; desc->ret[2] = smc_params.x3; - pr_info("scm_call_qcpe: OUT: 0x%llx, 0x%llx, 0x%llx", - desc->ret[0], desc->ret[1], desc->ret[2]); + pr_info("scm_call_qcpe: OUT: 0x%llx, 0x%llx, 0x%llx, 0x%llx", + smc_params.x0, desc->ret[0], desc->ret[1], desc->ret[2]); - return 0; + return smc_params.x0; } static u32 smc(u32 cmd_addr) diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index e4afce02afc7..24de162e5401 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -196,6 +196,7 @@ struct spcom_channel { * glink state: CONNECTED / LOCAL_DISCONNECTED, REMOTE_DISCONNECTED */ unsigned glink_state; + bool is_closing; /* Events notification */ struct completion connect; @@ -483,7 +484,17 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) switch (event) { case GLINK_CONNECTED: pr_debug("GLINK_CONNECTED, ch name [%s].\n", ch->name); + mutex_lock(&ch->lock); + + if (ch->is_closing) { + pr_err("Unexpected CONNECTED while closing [%s].\n", + ch->name); + mutex_unlock(&ch->lock); + return; + } + ch->glink_state = event; + /* * if spcom_notify_state() is called within glink_open() * then ch->glink_handle is not updated yet. @@ -493,7 +504,16 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) ch->glink_handle = handle; } - /* prepare default rx buffer after connected */ + /* signal before unlock mutex & before calling glink */ + complete_all(&ch->connect); + + /* + * Prepare default rx buffer. + * glink_queue_rx_intent() can be called only AFTER connected. + * We do it here, ASAP, to allow rx data. + */ + + pr_debug("call glink_queue_rx_intent() ch [%s].\n", ch->name); ret = glink_queue_rx_intent(ch->glink_handle, ch, ch->rx_buf_size); if (ret) { @@ -503,7 +523,9 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) ch->rx_buf_size); ch->rx_buf_ready = true; } - complete_all(&ch->connect); + + pr_debug("GLINK_CONNECTED, ch name [%s] done.\n", ch->name); + mutex_unlock(&ch->lock); break; case GLINK_LOCAL_DISCONNECTED: /* @@ -668,6 +690,13 @@ static int spcom_init_channel(struct spcom_channel *ch, const char *name) ch->glink_state = GLINK_LOCAL_DISCONNECTED; ch->actual_rx_size = 0; ch->rx_buf_size = SPCOM_RX_BUF_SIZE; + ch->is_closing = false; + ch->glink_handle = NULL; + ch->ref_count = 0; + ch->rx_abort = false; + ch->tx_abort = false; + ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */ + ch->pid = 0; return 0; } @@ -738,6 +767,8 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec) /* init completion before calling glink_open() */ reinit_completion(&ch->connect); + ch->is_closing = false; + handle = glink_open(&cfg); if (IS_ERR_OR_NULL(handle)) { pr_err("glink_open failed.\n"); @@ -752,6 +783,8 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec) ch->pid = current_pid(); ch->txn_id = INITIAL_TXN_ID; + mutex_unlock(&ch->lock); + pr_debug("Wait for connection on channel [%s] timeout_msec [%d].\n", name, timeout_msec); @@ -768,8 +801,6 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec) pr_debug("Channel [%s] opened, no timeout.\n", name); } - mutex_unlock(&ch->lock); - return 0; exit_err: mutex_unlock(&ch->lock); @@ -796,6 +827,8 @@ static int spcom_close(struct spcom_channel *ch) return 0; } + ch->is_closing = true; + ret = glink_close(ch->glink_handle); if (ret) pr_err("glink_close() fail, ret [%d].\n", ret); @@ -811,6 +844,7 @@ static int spcom_close(struct spcom_channel *ch) ch->pid = 0; pr_debug("Channel closed [%s].\n", ch->name); + mutex_unlock(&ch->lock); return 0; @@ -2752,7 +2786,7 @@ static int __init spcom_init(void) { int ret; - pr_info("spcom driver Ver 1.0 23-Nov-2015.\n"); + pr_info("spcom driver version 1.1 17-July-2017.\n"); ret = platform_driver_register(&spcom_driver); if (ret) diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index 745a069df88a..625030f1f256 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -134,6 +134,8 @@ static int msm_watchdog_suspend(struct device *dev) return 0; __raw_writel(1, wdog_dd->base + WDT0_RST); if (wdog_dd->wakeup_irq_enable) { + /* Make sure register write is complete before proceeding */ + mb(); wdog_dd->last_pet = sched_clock(); return 0; } @@ -148,8 +150,15 @@ static int msm_watchdog_resume(struct device *dev) { struct msm_watchdog_data *wdog_dd = (struct msm_watchdog_data *)dev_get_drvdata(dev); - if (!enable || wdog_dd->wakeup_irq_enable) + if (!enable) + return 0; + if (wdog_dd->wakeup_irq_enable) { + __raw_writel(1, wdog_dd->base + WDT0_RST); + /* Make sure register write is complete before proceeding */ + mb(); + wdog_dd->last_pet = sched_clock(); return 0; + } __raw_writel(1, wdog_dd->base + WDT0_EN); __raw_writel(1, wdog_dd->base + WDT0_RST); mb(); diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index b1f4c3f27111..4b586f62cdc7 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -2858,7 +2858,7 @@ static void msm_thermal_bite(int zone_id, int temp) tsens_id, temp); } /* If it is a secure device ignore triggering the thermal bite. */ - if (scm_is_secure_device()) + if (!scm_is_secure_device()) return; if (!is_scm_armv8()) { scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0); diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index fc9faaee3170..b80e75fc3521 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -2255,7 +2255,7 @@ void disable_wakeup_interrupt(struct msm_hs_port *msm_uport) return; if (msm_uport->wakeup.enabled) { - disable_irq_nosync(msm_uport->wakeup.irq); + disable_irq(msm_uport->wakeup.irq); enable_irq(uport->irq); spin_lock_irqsave(&uport->lock, flags); msm_uport->wakeup.enabled = false; @@ -2614,8 +2614,7 @@ static int msm_hs_startup(struct uart_port *uport) msm_hs_resource_vote(msm_uport); if (is_use_low_power_wakeup(msm_uport)) { - ret = request_threaded_irq(msm_uport->wakeup.irq, NULL, - msm_hs_wakeup_isr, + ret = request_irq(msm_uport->wakeup.irq, msm_hs_wakeup_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "msm_hs_wakeup", msm_uport); if (unlikely(ret)) { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 1b4fb562ce4b..927c84ea4921 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -39,6 +39,7 @@ #define DWC3_MSG_MAX 500 /* Global constants */ +#define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 @@ -748,6 +749,7 @@ struct dwc3_scratchpad_array { * @ctrl_req: usb control request which is used for ep0 * @ep0_trb: trb which is used for the ctrl_req * @ep0_bounce: bounce buffer for ep0 + * @zlp_buf: used when request->zero is set * @setup_buf: used while precessing STD USB requests * @ctrl_req_addr: dma address of ctrl_req * @ep0_trb: dma address of ep0_trb @@ -853,6 +855,7 @@ struct dwc3 { struct usb_ctrlrequest *ctrl_req; struct dwc3_trb *ep0_trb; void *ep0_bounce; + void *zlp_buf; void *scratchbuf; u8 *setup_buf; dma_addr_t ctrl_req_addr; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 8e8c1a349e6a..70db070b05d8 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -72,6 +72,8 @@ MODULE_PARM_DESC(cpu_to_affin, "affin usb irq to this cpu"); /* XHCI registers */ #define USB3_HCSPARAMS1 (0x4) +#define USB3_HCCPARAMS2 (0x1c) +#define HCC_CTC(p) ((p) & (1 << 3)) #define USB3_PORTSC (0x420) /** @@ -213,6 +215,7 @@ struct dwc3_msm { struct notifier_block dwc3_cpu_notifier; struct notifier_block usbdev_nb; bool hc_died; + bool xhci_ss_compliance_enable; struct extcon_dev *extcon_vbus; struct extcon_dev *extcon_id; @@ -2631,8 +2634,6 @@ done: static void check_for_sdp_connection(struct work_struct *w) { - int ret; - union power_supply_propval pval = {0}; struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, sdp_check.work); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); @@ -2643,21 +2644,6 @@ static void check_for_sdp_connection(struct work_struct *w) /* floating D+/D- lines detected */ if (dwc->gadget.state < USB_STATE_DEFAULT && dwc3_gadget_get_link_state(dwc) != DWC3_LINK_STATE_CMPLY) { - if (!mdwc->usb_psy) { - mdwc->usb_psy = power_supply_get_by_name("usb"); - if (!mdwc->usb_psy) { - dev_dbg(mdwc->dev, - "Could not get usb power_supply\n"); - return; - } - } - pval.intval = -ETIMEDOUT; - ret = power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &pval); - if (ret) - dev_dbg(mdwc->dev, - "power supply error when setting property\n"); - mdwc->vbus_active = 0; dbg_event(0xFF, "Q RW SPD CHK", mdwc->vbus_active); queue_work(mdwc->dwc3_wq, &mdwc->resume_work); @@ -2835,6 +2821,34 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(speed); static void msm_dwc3_perf_vote_work(struct work_struct *w); +static ssize_t xhci_link_compliance_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + if (mdwc->xhci_ss_compliance_enable) + return snprintf(buf, PAGE_SIZE, "y\n"); + else + return snprintf(buf, PAGE_SIZE, "n\n"); +} + +static ssize_t xhci_link_compliance_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + bool value; + int ret; + + ret = strtobool(buf, &value); + if (!ret) { + mdwc->xhci_ss_compliance_enable = value; + return count; + } + + return ret; +} + +static DEVICE_ATTR_RW(xhci_link_compliance); static int dwc3_msm_probe(struct platform_device *pdev) { @@ -3179,6 +3193,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); + device_create_file(&pdev->dev, &dev_attr_xhci_link_compliance); host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (host_mode || @@ -3210,6 +3225,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) int ret_pm; device_remove_file(&pdev->dev, &dev_attr_mode); + device_remove_file(&pdev->dev, &dev_attr_xhci_link_compliance); if (cpu_to_affin) unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier); @@ -3474,6 +3490,25 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) } /* + * If the Compliance Transition Capability(CTC) flag of + * HCCPARAMS2 register is set and xhci_link_compliance sysfs + * param has been enabled by the user for the SuperSpeed host + * controller, then write 10 (Link in Compliance Mode State) + * onto the Port Link State(PLS) field of the PORTSC register + * for 3.0 host controller which is at an offset of USB3_PORTSC + * + 0x10 from the DWC3 base address. Also, disable the runtime + * PM of 3.0 root hub (root hub of shared_hcd of xhci device) + */ + if (HCC_CTC(dwc3_msm_read_reg(mdwc->base, USB3_HCCPARAMS2)) + && mdwc->xhci_ss_compliance_enable + && dwc->maximum_speed == USB_SPEED_SUPER) { + dwc3_msm_write_reg(mdwc->base, USB3_PORTSC + 0x10, + 0x10340); + pm_runtime_disable(&hcd_to_xhci(platform_get_drvdata( + dwc->xhci))->shared_hcd->self.root_hub->dev); + } + + /* * In some cases it is observed that USB PHY is not going into * suspend with host mode suspend functionality. Hence disable * XHCI's runtime PM here if disable_host_mode_pm is set. @@ -3656,14 +3691,16 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) return 0; psy_type = get_psy_type(mdwc); - if (psy_type != POWER_SUPPLY_TYPE_USB && - psy_type != POWER_SUPPLY_TYPE_USB_FLOAT) + if (psy_type == POWER_SUPPLY_TYPE_USB) { + dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA); + /* Set max current limit in uA */ + pval.intval = 1000 * mA; + } else if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT) { + pval.intval = -ETIMEDOUT; + } else { 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/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 658fcca485d8..94709587f238 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1340,6 +1340,32 @@ static bool dwc3_gadget_is_suspended(struct dwc3 *dwc) return false; } +static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep, + struct usb_request *request) +{ + dwc3_gadget_ep_free_request(ep, request); +} + +static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep) +{ + struct dwc3_request *req; + struct usb_request *request; + struct usb_ep *ep = &dep->endpoint; + + dwc3_trace(trace_dwc3_gadget, "queueing ZLP\n"); + request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC); + if (!request) + return -ENOMEM; + + request->length = 0; + request->buf = dwc->zlp_buf; + request->complete = __dwc3_gadget_ep_zlp_complete; + + req = to_dwc3_request(request); + + return __dwc3_gadget_ep_queue(dep, req); +} + static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags) { @@ -1387,6 +1413,16 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, ret = __dwc3_gadget_ep_queue(dep, req); + /* + * Okay, here's the thing, if gadget driver has requested for a ZLP by + * setting request->zero, instead of doing magic, we will just queue an + * extra usb_request ourselves so that it gets handled the same way as + * any other request. + */ + if (ret == 0 && request->zero && request->length && + (request->length % ep->maxpacket == 0)) + ret = __dwc3_gadget_ep_queue_zlp(dwc, dep); + out: spin_unlock_irqrestore(&dwc->lock, flags); @@ -3554,6 +3590,12 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err3; } + dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL); + if (!dwc->zlp_buf) { + ret = -ENOMEM; + goto err4; + } + dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; @@ -3595,12 +3637,12 @@ int dwc3_gadget_init(struct dwc3 *dwc) ret = dwc3_gadget_init_endpoints(dwc); if (ret) - goto err4; + goto err5; ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); - goto err4; + goto err5; } if (!dwc->is_drd) { @@ -3612,6 +3654,9 @@ int dwc3_gadget_init(struct dwc3 *dwc) return 0; +err5: + kfree(dwc->zlp_buf); + err4: dwc3_gadget_free_endpoints(dwc); dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, @@ -3649,6 +3694,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc->ep0_bounce, dwc->ep0_bounce_addr); kfree(dwc->setup_buf); + kfree(dwc->zlp_buf); dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index eeccae8bfc1b..442d44278f33 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -35,7 +35,8 @@ (speed == USB_SPEED_SUPER ?\ SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW) -static bool disable_l1_for_hs; +/* disable LPM by default */ +static bool disable_l1_for_hs = true; module_param(disable_l1_for_hs, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(disable_l1_for_hs, "Disable support for L1 LPM for HS devices"); diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 1ef3442cf618..7950f25136a5 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -346,6 +346,7 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) struct acc_dev *dev = ep->driver_data; char *string_dest = NULL; int length = req->actual; + unsigned long flags; if (req->status != 0) { pr_err("acc_complete_set_string, err %d\n", req->status); @@ -371,22 +372,26 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) case ACCESSORY_STRING_SERIAL: string_dest = dev->serial; break; + default: + pr_err("unknown accessory string index %d\n", + dev->string_index); + return; } - if (string_dest) { - unsigned long flags; - if (length >= ACC_STRING_SIZE) - length = ACC_STRING_SIZE - 1; - - spin_lock_irqsave(&dev->lock, flags); - memcpy(string_dest, req->buf, length); - /* ensure zero termination */ - string_dest[length] = 0; - spin_unlock_irqrestore(&dev->lock, flags); - } else { - pr_err("unknown accessory string index %d\n", - dev->string_index); + if (!length) { + pr_debug("zero length for accessory string index %d\n", + dev->string_index); + return; } + + if (length >= ACC_STRING_SIZE) + length = ACC_STRING_SIZE - 1; + + spin_lock_irqsave(&dev->lock, flags); + memcpy(string_dest, req->buf, length); + /* ensure zero termination */ + string_dest[length] = 0; + spin_unlock_irqrestore(&dev->lock, flags); } static void acc_complete_set_hid_report_desc(struct usb_ep *ep, diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 3f903d4776b4..19fe6c8cb25a 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1579,6 +1579,12 @@ static void gsi_rndis_command_complete(struct usb_ep *ep, struct f_gsi *rndis = req->context; int status; + if (req->status != 0) { + log_event_err("RNDIS command completion error %d\n", + req->status); + return; + } + status = rndis_msg_parser(rndis->params, (u8 *) req->buf); if (status < 0) log_event_err("RNDIS command error %d, %d/%d", diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 777acb489875..8536f10a2e35 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -183,15 +183,28 @@ static struct usb_qdss_opts *to_fi_usb_qdss_opts(struct usb_function_instance *f } /*----------------------------------------------------------------------*/ -static void qdss_ctrl_write_complete(struct usb_ep *ep, +static void qdss_write_complete(struct usb_ep *ep, struct usb_request *req) { struct f_qdss *qdss = ep->driver_data; struct qdss_request *d_req = req->context; + struct usb_ep *in; + struct list_head *list_pool; + enum qdss_state state; unsigned long flags; pr_debug("qdss_ctrl_write_complete\n"); + if (qdss->debug_inface_enabled) { + in = qdss->port.ctrl_in; + list_pool = &qdss->ctrl_write_pool; + state = USB_QDSS_CTRL_WRITE_DONE; + } else { + in = qdss->port.data; + list_pool = &qdss->data_write_pool; + state = USB_QDSS_DATA_WRITE_DONE; + } + if (!req->status) { /* send zlp */ if ((req->length >= ep->maxpacket) && @@ -199,13 +212,13 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep, req->length = 0; d_req->actual = req->actual; d_req->status = req->status; - if (!usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC)) + if (!usb_ep_queue(in, req, GFP_ATOMIC)) return; } } spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->ctrl_write_pool); + list_add_tail(&req->list, list_pool); if (req->length != 0) { d_req->actual = req->actual; d_req->status = req->status; @@ -213,8 +226,7 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep, spin_unlock_irqrestore(&qdss->lock, flags); if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req, - NULL); + qdss->ch.notify(qdss->ch.priv, state, d_req, NULL); } static void qdss_ctrl_read_complete(struct usb_ep *ep, @@ -252,6 +264,12 @@ void usb_qdss_free_req(struct usb_qdss_ch *ch) return; } + list_for_each_safe(act, tmp, &qdss->data_write_pool) { + req = list_entry(act, struct usb_request, list); + list_del(&req->list); + usb_ep_free_request(qdss->port.data, req); + } + list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) { req = list_entry(act, struct usb_request, list); list_del(&req->list); @@ -271,23 +289,41 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf, { struct f_qdss *qdss = ch->priv_usb; struct usb_request *req; + struct usb_ep *in; + struct list_head *list_pool; int i; pr_debug("usb_qdss_alloc_req\n"); - if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) { + if (!qdss) { + pr_err("usb_qdss_alloc_req: channel %s closed\n", ch->name); + return -ENODEV; + } + + if ((qdss->debug_inface_enabled && + (no_write_buf <= 0 || no_read_buf <= 0)) || + (!qdss->debug_inface_enabled && + (no_write_buf <= 0 || no_read_buf))) { pr_err("usb_qdss_alloc_req: missing params\n"); return -ENODEV; } + if (qdss->debug_inface_enabled) { + in = qdss->port.ctrl_in; + list_pool = &qdss->ctrl_write_pool; + } else { + in = qdss->port.data; + list_pool = &qdss->data_write_pool; + } + for (i = 0; i < no_write_buf; i++) { - req = usb_ep_alloc_request(qdss->port.ctrl_in, GFP_ATOMIC); + req = usb_ep_alloc_request(in, GFP_ATOMIC); if (!req) { pr_err("usb_qdss_alloc_req: ctrl_in allocation err\n"); goto fail; } - req->complete = qdss_ctrl_write_complete; - list_add_tail(&req->list, &qdss->ctrl_write_pool); + req->complete = qdss_write_complete; + list_add_tail(&req->list, list_pool); } for (i = 0; i < no_read_buf; i++) { @@ -479,21 +515,20 @@ static void usb_qdss_disconnect_work(struct work_struct *work) qdss = container_of(work, struct f_qdss, disconnect_w); pr_debug("usb_qdss_disconnect_work\n"); - /* - * Uninitialized init data i.e. ep specific operation. - * Notify qdss to cancel all active transfers. - */ - if (qdss->ch.app_conn) { + + /* Notify qdss to cancel all active transfers */ + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, + USB_QDSS_DISCONNECT, + NULL, + NULL); + + /* Uninitialized init data i.e. ep specific operation */ + if (qdss->ch.app_conn && !strcmp(qdss->ch.name, USB_QDSS_CH_MSM)) { status = uninit_data(qdss->port.data); if (status) pr_err("%s: uninit_data error\n", __func__); - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, - USB_QDSS_DISCONNECT, - NULL, - NULL); - status = set_qdss_data_connection(qdss, 0); if (status) pr_err("qdss_disconnect error"); @@ -550,15 +585,16 @@ static void usb_qdss_connect_work(struct work_struct *work) } pr_debug("usb_qdss_connect_work\n"); + + if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) + goto notify; + status = set_qdss_data_connection(qdss, 1); if (status) { pr_err("set_qdss_data_connection error(%d)", status); return; } - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, - NULL, &qdss->ch); spin_lock_irqsave(&qdss->lock, flags); req = qdss->endless_req; spin_unlock_irqrestore(&qdss->lock, flags); @@ -566,8 +602,15 @@ static void usb_qdss_connect_work(struct work_struct *work) return; status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC); - if (status) + if (status) { pr_err("%s: usb_ep_queue error (%d)\n", __func__, status); + return; + } + +notify: + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, + NULL, &qdss->ch); } static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt) @@ -706,6 +749,7 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name) spin_lock_init(&qdss->lock); INIT_LIST_HEAD(&qdss->ctrl_read_pool); INIT_LIST_HEAD(&qdss->ctrl_write_pool); + INIT_LIST_HEAD(&qdss->data_write_pool); INIT_WORK(&qdss->connect_w, usb_qdss_connect_work); INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work); @@ -801,6 +845,50 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) } EXPORT_SYMBOL(usb_qdss_ctrl_write); +int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) +{ + struct f_qdss *qdss = ch->priv_usb; + unsigned long flags; + struct usb_request *req = NULL; + + pr_debug("usb_qdss_ctrl_write\n"); + + if (!qdss) + return -ENODEV; + + spin_lock_irqsave(&qdss->lock, flags); + + if (qdss->usb_connected == 0) { + spin_unlock_irqrestore(&qdss->lock, flags); + return -EIO; + } + + if (list_empty(&qdss->data_write_pool)) { + pr_err("error: usb_qdss_data_write list is empty\n"); + spin_unlock_irqrestore(&qdss->lock, flags); + return -EAGAIN; + } + + req = list_first_entry(&qdss->data_write_pool, struct usb_request, + list); + list_del(&req->list); + spin_unlock_irqrestore(&qdss->lock, flags); + + req->buf = d_req->buf; + req->length = d_req->length; + req->context = d_req; + if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) { + spin_lock_irqsave(&qdss->lock, flags); + list_add_tail(&req->list, &qdss->data_write_pool); + spin_unlock_irqrestore(&qdss->lock, flags); + pr_err("qdss usb_ep_queue failed\n"); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL(usb_qdss_write); + struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, void (*notify)(void *, unsigned, struct qdss_request *, struct usb_qdss_ch *)) @@ -859,7 +947,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch) pr_debug("usb_qdss_close\n"); spin_lock_irqsave(&qdss_lock, flags); - if (!qdss || !qdss->usb_connected) { + ch->priv_usb = NULL; + if (!qdss || !qdss->usb_connected || + !strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) { ch->app_conn = 0; spin_unlock_irqrestore(&qdss_lock, flags); return; diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index cad0f4cc06f9..fb7c01c0f939 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -53,6 +53,10 @@ struct f_qdss { struct usb_qdss_ch ch; struct list_head ctrl_read_pool; struct list_head ctrl_write_pool; + + /* for mdm channel SW path */ + struct list_head data_write_pool; + struct work_struct connect_w; struct work_struct disconnect_w; spinlock_t lock; diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 3f1c2b32abb8..0cbe95304417 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1702,7 +1702,6 @@ static void usbpd_sm(struct work_struct *w) if (pd->current_pr == PR_SINK) { usbpd_set_state(pd, PE_SNK_STARTUP); } else if (pd->current_pr == PR_SRC) { - enable_vbus(pd); if (!pd->vconn_enabled && pd->typec_mode == POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE) { @@ -1712,6 +1711,7 @@ static void usbpd_sm(struct work_struct *w) else pd->vconn_enabled = true; } + enable_vbus(pd); usbpd_set_state(pd, PE_SRC_STARTUP); } diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c index c6ff92ed1686..3330f8f62b78 100644 --- a/drivers/video/fbdev/msm/mdss_dba_utils.c +++ b/drivers/video/fbdev/msm/mdss_dba_utils.c @@ -576,6 +576,7 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo) video_cfg.h_pulse_width = pinfo->lcdc.h_pulse_width; video_cfg.v_pulse_width = pinfo->lcdc.v_pulse_width; video_cfg.pclk_khz = (unsigned long)pinfo->clk_rate / 1000; + video_cfg.hdmi_mode = !hdmi_edid_is_dvi_mode(ud->edid_data); /* Calculate number of DSI lanes configured */ video_cfg.num_of_input_lanes = 0; @@ -591,8 +592,6 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo) /* Get scan information from EDID */ video_cfg.vic = mdss_dba_get_vic_panel_info(ud, pinfo); ud->current_vic = video_cfg.vic; - video_cfg.hdmi_mode = hdmi_edid_get_sink_mode(ud->edid_data, - video_cfg.vic); video_cfg.scaninfo = hdmi_edid_get_sink_scaninfo(ud->edid_data, video_cfg.vic); if (ud->ops.video_on) diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 2f169074261a..a98e5a9007bd 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1094,8 +1094,14 @@ static int dp_audio_info_setup(struct platform_device *pdev, struct mdss_dp_drv_pdata *dp_ctrl = platform_get_drvdata(pdev); if (!dp_ctrl || !params) { - DEV_ERR("%s: invalid input\n", __func__); - return -ENODEV; + pr_err("invalid input\n"); + rc = -ENODEV; + goto end; + } + + if (!dp_ctrl->power_on) { + pr_debug("DP is already power off\n"); + goto end; } mdss_dp_audio_setup_sdps(&dp_ctrl->ctrl_io, params->num_of_channels); @@ -1103,6 +1109,7 @@ static int dp_audio_info_setup(struct platform_device *pdev, mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt); mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true); +end: return rc; } /* dp_audio_info_setup */ @@ -1134,6 +1141,11 @@ static void dp_audio_teardown_done(struct platform_device *pdev) return; } + if (!dp->power_on) { + pr_err("DP is already power off\n"); + return; + } + mdss_dp_audio_enable(&dp->ctrl_io, false); /* Make sure the DP audio engine is disabled */ wmb(); @@ -3982,12 +3994,6 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) { int ret = 0; - /* In case of HPD_IRQ events without DP link being turned on such as - * adb shell stop, skip handling hpd_irq event. - */ - if (!dp->dp_initialized) - goto exit; - pr_debug("start\n"); dp->hpd_irq_on = true; @@ -4103,6 +4109,15 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) if (dp_drv->alt_mode.dp_status.hpd_irq) { pr_debug("Attention: hpd_irq high\n"); + /* In case of HPD_IRQ events without DP link being + * turned on such as adb shell stop, skip handling + * hpd_irq event. + */ + if (!dp_drv->dp_initialized) { + pr_err("DP not initialized yet\n"); + return; + } + if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->cp_irq) { if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data)) return; diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index 23a63121b78c..786fe10055da 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -395,6 +395,7 @@ static int dp_aux_rw_cmds_retry(struct mdss_dp_drv_pdata *dp, int i; u32 aux_cfg1_config_count; int ret; + bool connected = false; aux_cfg1_config_count = mdss_dp_phy_aux_get_config_cnt(dp, PHY_AUX_CFG1); @@ -404,6 +405,15 @@ retry: do { struct edp_cmd cmd1 = *cmd; + mutex_lock(&dp->attention_lock); + connected = dp->cable_connected; + mutex_unlock(&dp->attention_lock); + + if (!connected) { + pr_err("dp cable disconnected\n"); + break; + } + dp->aux_error_num = EDP_AUX_ERR_NONE; pr_debug("Trying %s, iteration count: %d\n", mdss_dp_aux_transaction_to_string(transaction), diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c index 5a677dfe7484..36a062dc5207 100644 --- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c @@ -894,22 +894,24 @@ static bool dp_hdcp2p2_supported(struct dp_hdcp2p2_ctrl *ctrl) { struct edp_cmd cmd = {0}; const u32 offset = 0x6921d; - u8 buf; + u8 buf[3]; cmd.read = 1; cmd.addr = offset; - cmd.len = sizeof(buf); - cmd.out_buf = &buf; + cmd.len = ARRAY_SIZE(buf); + cmd.out_buf = buf; if (dp_aux_read(ctrl->init_data.cb_data, &cmd)) { pr_err("RxCaps read failed\n"); goto error; } - pr_debug("rxcaps 0x%x\n", buf); + pr_debug("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1); + pr_debug("VERSION=%d\n", buf[0]); - if (buf & BIT(1)) + if ((buf[2] & BIT(1)) && (buf[0] == 0x2)) return true; + error: return false; } diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 4ac10ab494e5..f9a71375c207 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -2720,8 +2720,6 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, ctrl_pdata->update_phy_timing); rc = mdss_dsi_on(pdata); - mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, - pdata); break; case MDSS_EVENT_UNBLANK: if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index a953dd1a2ac2..2143c2bdb84b 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -62,6 +62,11 @@ #define EDID_VENDOR_ID_SIZE 4 #define EDID_IEEE_REG_ID 0x0c03 +enum edid_sink_mode { + SINK_MODE_DVI, + SINK_MODE_HDMI +}; + enum luminance_value { NO_LUMINANCE_DATA = 3, MAXIMUM_LUMINANCE = 4, @@ -151,10 +156,13 @@ struct hdmi_edid_ctrl { }; static bool hdmi_edid_is_mode_supported(struct hdmi_edid_ctrl *edid_ctrl, - struct msm_hdmi_mode_timing_info *timing) + struct msm_hdmi_mode_timing_info *timing, u32 out_format) { + u32 pclk = hdmi_tx_setup_tmds_clk_rate(timing->pixel_freq, + out_format, false); + if (!timing->supported || - timing->pixel_freq > edid_ctrl->init_data.max_pclk_khz) + pclk > edid_ctrl->init_data.max_pclk_khz) return false; return true; @@ -931,7 +939,8 @@ static void hdmi_edid_add_sink_y420_format(struct hdmi_edid_ctrl *edid_ctrl, u32 ret = hdmi_get_supported_mode(&timing, &edid_ctrl->init_data.ds_data, video_format); - u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, &timing); + u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, + &timing, MDP_Y_CBCR_H2V2); struct hdmi_edid_sink_data *sink = &edid_ctrl->sink_data; if (video_format >= HDMI_VFRMT_MAX) { @@ -1699,7 +1708,8 @@ static void hdmi_edid_add_sink_video_format(struct hdmi_edid_ctrl *edid_ctrl, u32 ret = hdmi_get_supported_mode(&timing, &edid_ctrl->init_data.ds_data, video_format); - u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, &timing); + u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, + &timing, MDP_RGBA_8888); struct hdmi_edid_sink_data *sink_data = &edid_ctrl->sink_data; struct disp_mode_info *disp_mode_list = sink_data->disp_mode_list; u32 i = 0; @@ -2418,7 +2428,7 @@ end: return scaninfo; } /* hdmi_edid_get_sink_scaninfo */ -u32 hdmi_edid_get_sink_mode(void *input, u32 mode) +static u32 hdmi_edid_get_sink_mode(void *input) { struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; bool sink_mode; @@ -2431,13 +2441,8 @@ u32 hdmi_edid_get_sink_mode(void *input, u32 mode) if (edid_ctrl->edid_override && (edid_ctrl->override_data.sink_mode != -1)) sink_mode = edid_ctrl->override_data.sink_mode; - else { - if (edid_ctrl->sink_mode && - (mode > 0 && mode <= HDMI_EVFRMT_END)) - sink_mode = SINK_MODE_HDMI; - else - sink_mode = SINK_MODE_DVI; - } + else + sink_mode = edid_ctrl->sink_mode; return sink_mode; } /* hdmi_edid_get_sink_mode */ @@ -2452,21 +2457,10 @@ u32 hdmi_edid_get_sink_mode(void *input, u32 mode) */ bool hdmi_edid_is_dvi_mode(void *input) { - struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; - int sink_mode; - - if (!edid_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); - return true; - } - - if (edid_ctrl->edid_override && - (edid_ctrl->override_data.sink_mode != -1)) - sink_mode = edid_ctrl->override_data.sink_mode; + if (hdmi_edid_get_sink_mode(input)) + return false; else - sink_mode = edid_ctrl->sink_mode; - - return (sink_mode == SINK_MODE_DVI); + return true; } /** diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index c604d0fbf7b2..af802bb45f89 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -58,16 +58,10 @@ struct hdmi_edid_override_data { int vic; }; -enum edid_sink_mode { - SINK_MODE_DVI, - SINK_MODE_HDMI -}; - int hdmi_edid_parser(void *edid_ctrl); u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size); u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution); bool hdmi_edid_is_dvi_mode(void *input); -u32 hdmi_edid_get_sink_mode(void *edid_ctrl, u32 mode); bool hdmi_edid_sink_scramble_override(void *input); bool hdmi_edid_get_sink_scrambler_support(void *input); bool hdmi_edid_get_scdc_support(void *input); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 2e267f2695d7..9ee0c27b225e 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -375,12 +375,11 @@ static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl) } } -static inline bool hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) +static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) { void *data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); - return (hdmi_edid_get_sink_mode(data, - hdmi_ctrl->vic) == SINK_MODE_DVI); + return hdmi_edid_is_dvi_mode(data); } /* hdmi_tx_is_dvi_mode */ static inline u32 hdmi_tx_is_in_splash(struct hdmi_tx_ctrl *hdmi_ctrl) @@ -2482,8 +2481,7 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) hdmi_ctrl_reg |= BIT(2); /* Set transmission mode to DVI based in EDID info */ - if (hdmi_edid_get_sink_mode(data, - hdmi_ctrl->vic) == SINK_MODE_DVI) + if (hdmi_edid_is_dvi_mode(data)) hdmi_ctrl_reg &= ~BIT(1); /* DVI mode */ /* @@ -2942,6 +2940,7 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev, { int rc = 0; struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev); + u32 is_mode_dvi; if (!hdmi_ctrl || !params) { DEV_ERR("%s: invalid input\n", __func__); @@ -2950,8 +2949,9 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev, mutex_lock(&hdmi_ctrl->tx_lock); - if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) && - hdmi_tx_is_panel_on(hdmi_ctrl)) { + is_mode_dvi = hdmi_tx_is_dvi_mode(hdmi_ctrl); + + if (!is_mode_dvi && hdmi_tx_is_panel_on(hdmi_ctrl)) { memcpy(&hdmi_ctrl->audio_params, params, sizeof(struct msm_ext_disp_audio_setup_params)); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 0165c48a0467..54fb21a5f35d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -696,7 +696,6 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe, if (flags & PERF_CALC_PIPE_APPLY_CLK_FUDGE) rate = mdss_mdp_clk_fudge_factor(mixer, rate); - rate = min(mdata->max_mdp_clk_rate, rate); return rate; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index 1035d23fe9ce..09d1dab0d180 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -1863,12 +1863,14 @@ static void __print_buf(struct seq_file *s, struct mdss_mdp_data *buf, seq_puts(s, "\n"); } -static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe) +static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe, + struct msm_fb_data_type *mfd) { struct mdss_mdp_data *buf; int format; int smps[4]; int i; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); seq_printf(s, "\nSSPP #%d type=%s ndx=%x flags=0x%16llx play_cnt=%u xin_id=%d\n", pipe->num, mdss_mdp_pipetype2str(pipe->type), @@ -1923,11 +1925,14 @@ static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe) seq_puts(s, "Data:\n"); + mutex_lock(&mdp5_data->list_lock); list_for_each_entry(buf, &pipe->buf_queue, pipe_list) __print_buf(s, buf, false); + mutex_unlock(&mdp5_data->list_lock); } -static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer) +static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer, + struct msm_fb_data_type *mfd) { struct mdss_mdp_pipe *pipe; int i, cnt = 0; @@ -1944,7 +1949,7 @@ static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer) for (i = 0; i < ARRAY_SIZE(mixer->stage_pipe); i++) { pipe = mixer->stage_pipe[i]; if (pipe) { - __dump_pipe(s, pipe); + __dump_pipe(s, pipe, mfd); cnt++; } } @@ -2019,8 +2024,8 @@ static void __dump_ctl(struct seq_file *s, struct mdss_mdp_ctl *ctl) seq_printf(s, "Play Count=%u Underrun Count=%u\n", ctl->play_cnt, ctl->underrun_cnt); - __dump_mixer(s, ctl->mixer_left); - __dump_mixer(s, ctl->mixer_right); + __dump_mixer(s, ctl->mixer_left, ctl->mfd); + __dump_mixer(s, ctl->mixer_right, ctl->mfd); } static int __dump_mdp(struct seq_file *s, struct mdss_data_type *mdata) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index c31c0149866a..bdf6705ef597 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -643,8 +643,13 @@ static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl, display_hctl = (hsync_end_x << 16) | hsync_start_x; den_polarity = 0; - hsync_polarity = p->h_polarity; - vsync_polarity = p->v_polarity; + if (ctx->intf_type == MDSS_INTF_HDMI) { + hsync_polarity = p->h_polarity; + vsync_polarity = p->v_polarity; + } else { + hsync_polarity = 0; + vsync_polarity = 0; + } polarity_ctl = (den_polarity << 2) | /* DEN Polarity */ (vsync_polarity << 1) | /* VSYNC Polarity */ (hsync_polarity << 0); /* HSYNC Polarity */ diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c index 71cab148e1c3..aabf7c507376 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -358,7 +358,8 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, int ret = 0, i = 0; char __iomem *hist_addr; u32 sz = 0, temp = 0, *data = NULL; - struct mdp_hist_lut_data_v1_7 *lut_data = NULL; + struct mdp_hist_lut_data_v1_7 lut_data_v1_7; + struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7; struct mdp_hist_lut_data *lut_cfg_data = NULL; if (!base_addr || !cfg_data) { @@ -378,7 +379,11 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, lut_cfg_data->version, lut_cfg_data->cfg_payload); return -EINVAL; } - lut_data = lut_cfg_data->cfg_payload; + if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, + sizeof(*lut_data))) { + pr_err("copy from user failed for lut_data\n"); + return -EFAULT; + } if (lut_data->len != ENHIST_LUT_ENTRIES) { pr_err("invalid hist_lut len %d", lut_data->len); return -EINVAL; @@ -1786,7 +1791,8 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data, { int ret = 0, i = 0; struct mdp_igc_lut_data *lut_cfg_data = NULL; - struct mdp_igc_lut_data_v1_7 *lut_data = NULL; + struct mdp_igc_lut_data_v1_7 lut_data_v1_7; + struct mdp_igc_lut_data_v1_7 *lut_data = &lut_data_v1_7; char __iomem *c1 = NULL, *c2 = NULL; u32 *c0c1_data = NULL, *c2_data = NULL; u32 data = 0, sz = 0; @@ -1810,7 +1816,11 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data, ret = -EINVAL; goto exit; } - lut_data = lut_cfg_data->cfg_payload; + if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, + sizeof(*lut_data))) { + pr_err("copy from user failed for lut_data\n"); + return -EFAULT; + } if (lut_data->len != IGC_LUT_ENTRIES) { pr_err("invalid lut len %d\n", lut_data->len); ret = -EINVAL; @@ -1954,20 +1964,24 @@ static int pp_pgc_get_config(char __iomem *base_addr, void *cfg_data, u32 *c0_data = NULL, *c1_data = NULL, *c2_data = NULL; u32 val = 0, i = 0, sz = 0; struct mdp_pgc_lut_data *pgc_data = NULL; - struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = NULL; + struct mdp_pgc_lut_data_v1_7 pgc_lut_data_v17; + struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = &pgc_lut_data_v17; if (!base_addr || !cfg_data) { pr_err("invalid params base_addr %pK cfg_data %pK block_type %d\n", base_addr, cfg_data, block_type); return -EINVAL; } pgc_data = (struct mdp_pgc_lut_data *) cfg_data; - pgc_data_v17 = (struct mdp_pgc_lut_data_v1_7 *) - pgc_data->cfg_payload; - if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data_v17) { + if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data->cfg_payload) { pr_err("invalid pgc version %d payload %pK\n", - pgc_data->version, pgc_data_v17); + pgc_data->version, pgc_data->cfg_payload); return -EINVAL; } + if (copy_from_user(pgc_data_v17, (void __user *) pgc_data->cfg_payload, + sizeof(*pgc_data_v17))) { + pr_err("copy from user failed for pgc lut data\n"); + return -EFAULT; + } if (!(pgc_data->flags & MDP_PP_OPS_READ)) { pr_info("read ops is not set %d", pgc_data->flags); return -EINVAL; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c index 25cb94f89dd5..b377f0921508 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -298,7 +298,8 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, int ret = 0, i = 0; char __iomem *hist_lut_addr; u32 sz = 0, temp = 0, *data = NULL; - struct mdp_hist_lut_data_v1_7 *lut_data = NULL; + struct mdp_hist_lut_data_v1_7 lut_data_v1_7; + struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7; struct mdp_hist_lut_data *lut_cfg_data = NULL; if (!base_addr || !cfg_data) { @@ -323,7 +324,11 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, lut_cfg_data->version, lut_cfg_data->cfg_payload); return -EINVAL; } - lut_data = lut_cfg_data->cfg_payload; + if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, + sizeof(*lut_data))) { + pr_err("copy from user failed for lut_data\n"); + return -EFAULT; + } if (lut_data->len != ENHIST_LUT_ENTRIES) { pr_err("invalid hist_lut len %d", lut_data->len); return -EINVAL; diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c index 61b0518d3ee6..2028222748c3 100644 --- a/drivers/video/fbdev/msm/mdss_rotator.c +++ b/drivers/video/fbdev/msm/mdss_rotator.c @@ -373,6 +373,15 @@ static bool mdss_rotator_is_work_pending(struct mdss_rot_mgr *mgr, return false; } +static void mdss_rotator_install_fence_fd(struct mdss_rot_entry_container *req) +{ + int i = 0; + + for (i = 0; i < req->count; i++) + sync_fence_install(req->entries[i].output_fence, + req->entries[i].output_fence_fd); +} + static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) { int ret = 0, fd; @@ -411,7 +420,6 @@ static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) goto get_fd_err; } - sync_fence_install(fence, fd); rot_timeline->next_value++; mutex_unlock(&rot_timeline->lock); @@ -2240,6 +2248,7 @@ static int mdss_rotator_handle_request(struct mdss_rot_mgr *mgr, goto handle_request_err1; } + mdss_rotator_install_fence_fd(req); mdss_rotator_queue_request(mgr, private, req); mutex_unlock(&mgr->lock); @@ -2400,6 +2409,7 @@ static int mdss_rotator_handle_request32(struct mdss_rot_mgr *mgr, goto handle_request32_err1; } + mdss_rotator_install_fence_fd(req); mdss_rotator_queue_request(mgr, private, req); mutex_unlock(&mgr->lock); diff --git a/fs/Kconfig b/fs/Kconfig index a5d2dc39ba07..4adb93ec85ea 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -282,4 +282,9 @@ endif # NETWORK_FILESYSTEMS source "fs/nls/Kconfig" source "fs/dlm/Kconfig" +config FILE_TABLE_DEBUG + bool "Enable FILE_TABLE_DEBUG" + help + This option enables debug of the open files using a global filetable + endmenu diff --git a/fs/file_table.c b/fs/file_table.c index ad17e05ebf95..b4baa0de4988 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -41,6 +41,141 @@ static struct kmem_cache *filp_cachep __read_mostly; static struct percpu_counter nr_files __cacheline_aligned_in_smp; +#ifdef CONFIG_FILE_TABLE_DEBUG +#include <linux/hashtable.h> +#include <mount.h> +static DEFINE_MUTEX(global_files_lock); +static DEFINE_HASHTABLE(global_files_hashtable, 10); + +struct global_filetable_lookup_key { + struct work_struct work; + uintptr_t value; +}; + +void global_filetable_print_warning_once(void) +{ + pr_err_once("\n**********************************************************\n"); + pr_err_once("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_err_once("** **\n"); + pr_err_once("** VFS FILE TABLE DEBUG is enabled . **\n"); + pr_err_once("** Allocating extra memory and slowing access to files **\n"); + pr_err_once("** **\n"); + pr_err_once("** This means that this is a DEBUG kernel and it is **\n"); + pr_err_once("** unsafe for production use. **\n"); + pr_err_once("** **\n"); + pr_err_once("** If you see this message and you are not debugging **\n"); + pr_err_once("** the kernel, report this immediately to your vendor! **\n"); + pr_err_once("** **\n"); + pr_err_once("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_err_once("**********************************************************\n"); +} + +void global_filetable_add(struct file *filp) +{ + struct mount *mnt; + + if (filp->f_path.dentry->d_iname == NULL || + strlen(filp->f_path.dentry->d_iname) == 0) + return; + + mnt = real_mount(filp->f_path.mnt); + + mutex_lock(&global_files_lock); + hash_add(global_files_hashtable, &filp->f_hash, (uintptr_t)mnt); + mutex_unlock(&global_files_lock); +} + +void global_filetable_del(struct file *filp) +{ + mutex_lock(&global_files_lock); + hash_del(&filp->f_hash); + mutex_unlock(&global_files_lock); +} + +static void global_print_file(struct file *filp, char *path_buffer, int *count) +{ + char *pathname; + + pathname = d_path(&filp->f_path, path_buffer, PAGE_SIZE); + if (IS_ERR(pathname)) + pr_err("VFS: File %d Address : %pa partial filename: %s ref_count=%ld\n", + ++(*count), &filp, filp->f_path.dentry->d_iname, + atomic_long_read(&filp->f_count)); + else + pr_err("VFS: File %d Address : %pa full filepath: %s ref_count=%ld\n", + ++(*count), &filp, pathname, + atomic_long_read(&filp->f_count)); +} + +static void global_filetable_print(uintptr_t lookup_mnt) +{ + struct hlist_node *tmp; + struct file *filp; + struct mount *mnt; + int index; + int count = 0; + char *path_buffer = (char *)__get_free_page(GFP_TEMPORARY); + + mutex_lock(&global_files_lock); + pr_err("\n**********************************************************\n"); + pr_err("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + + pr_err("\n"); + pr_err("VFS: The following files hold a reference to the mount\n"); + pr_err("\n"); + hash_for_each_possible_safe(global_files_hashtable, filp, tmp, f_hash, + lookup_mnt) { + mnt = real_mount(filp->f_path.mnt); + if ((uintptr_t)mnt == lookup_mnt) + global_print_file(filp, path_buffer, &count); + } + pr_err("\n"); + pr_err("VFS: Found total of %d open files\n", count); + pr_err("\n"); + + count = 0; + pr_err("\n"); + pr_err("VFS: The following files need to cleaned up\n"); + pr_err("\n"); + hash_for_each_safe(global_files_hashtable, index, tmp, filp, f_hash) { + if (atomic_long_read(&filp->f_count) == 0) + global_print_file(filp, path_buffer, &count); + } + + pr_err("\n"); + pr_err("VFS: Found total of %d files awaiting clean-up\n", count); + pr_err("\n"); + pr_err("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_err("\n**********************************************************\n"); + + mutex_unlock(&global_files_lock); + free_page((unsigned long)path_buffer); +} + +static void global_filetable_print_work_fn(struct work_struct *work) +{ + struct global_filetable_lookup_key *key; + uintptr_t lookup_mnt; + + key = container_of(work, struct global_filetable_lookup_key, work); + lookup_mnt = key->value; + kfree(key); + global_filetable_print(lookup_mnt); +} + +void global_filetable_delayed_print(struct mount *mnt) +{ + struct global_filetable_lookup_key *key; + + key = kzalloc(sizeof(*key), GFP_KERNEL); + if (key == NULL) + return; + key->value = (uintptr_t)mnt; + INIT_WORK(&key->work, global_filetable_print_work_fn); + schedule_work(&key->work); +} +#endif /* CONFIG_FILE_TABLE_DEBUG */ + static void file_free_rcu(struct rcu_head *head) { struct file *f = container_of(head, struct file, f_u.fu_rcuhead); @@ -219,6 +354,7 @@ static void __fput(struct file *file) put_write_access(inode); __mnt_drop_write(mnt); } + global_filetable_del(file); file->f_path.dentry = NULL; file->f_path.mnt = NULL; file->f_inode = NULL; @@ -314,6 +450,7 @@ void __init files_init(void) filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); percpu_counter_init(&nr_files, 0, GFP_KERNEL); + global_filetable_print_warning_once(); } /* diff --git a/fs/internal.h b/fs/internal.h index 6387b35a1c0d..1b93a3929b16 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -153,3 +153,29 @@ extern void mnt_pin_kill(struct mount *m); * fs/nsfs.c */ extern struct dentry_operations ns_dentry_operations; + +#ifdef CONFIG_FILE_TABLE_DEBUG +void global_filetable_print_warning_once(void); +void global_filetable_add(struct file *filp); +void global_filetable_del(struct file *filp); +void global_filetable_delayed_print(struct mount *mnt); + +#else /* i.e NOT CONFIG_FILE_TABLE_DEBUG */ + +static inline void global_filetable_print_warning_once(void) +{ +} + +static inline void global_filetable_add(struct file *filp) +{ +} + +static inline void global_filetable_del(struct file *filp) +{ +} + +static inline void global_filetable_delayed_print(struct mount *mnt) +{ +} + +#endif /* CONFIG_FILE_TABLE_DEBUG */ diff --git a/fs/namei.c b/fs/namei.c index 816b6e8e934e..b5dfe2c5b51e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3379,6 +3379,8 @@ out2: error = -ESTALE; } file = ERR_PTR(error); + } else { + global_filetable_add(file); } return file; } diff --git a/fs/namespace.c b/fs/namespace.c index a22959c97384..0f52d90c356f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1595,6 +1595,8 @@ static int do_umount(struct mount *mnt, int flags) } unlock_mount_hash(); namespace_unlock(); + if (retval == -EBUSY) + global_filetable_delayed_print(mnt); return retval; } diff --git a/include/dt-bindings/clock/msm-clocks-8998.h b/include/dt-bindings/clock/msm-clocks-8998.h index cd36374a04a7..67e47c46e09a 100644 --- a/include/dt-bindings/clock/msm-clocks-8998.h +++ b/include/dt-bindings/clock/msm-clocks-8998.h @@ -443,6 +443,11 @@ #define clk_dsi0pll_pclk_src 0x5efd85d4 #define clk_dsi0pll_pclk_src_mux 0x84b14663 #define clk_dsi0pll_post_bit_div 0xf46dcf27 +#define clk_dsi0pll_pll_out_div1 0xeda5b7fe +#define clk_dsi0pll_pll_out_div2 0x97fa476d +#define clk_dsi0pll_pll_out_div4 0x90a98ce0 +#define clk_dsi0pll_pll_out_div8 0x9d9d85cf +#define clk_dsi0pll_pll_out_mux 0x179c27ca #define clk_dsi0pll_post_vco_mux 0xfaf9bd1f #define clk_dsi0pll_post_vco_div1 0xabb50b2a #define clk_dsi0pll_post_vco_div4 0xbe51c091 @@ -455,6 +460,11 @@ #define clk_dsi1pll_pclk_src 0xeddcd80e #define clk_dsi1pll_pclk_src_mux 0x3651feb3 #define clk_dsi1pll_post_bit_div 0x712f0260 +#define clk_dsi1pll_pll_out_div8 0x87628ddb +#define clk_dsi1pll_pll_out_div4 0x0d9a384b +#define clk_dsi1pll_pll_out_div2 0x0c9b5748 +#define clk_dsi1pll_pll_out_div1 0x3193164e +#define clk_dsi1pll_pll_out_mux 0x171bf8fd #define clk_dsi1pll_post_vco_mux 0xc6a90d20 #define clk_dsi1pll_post_vco_div1 0x6f47ca7d #define clk_dsi1pll_post_vco_div4 0x90628974 diff --git a/include/linux/fs.h b/include/linux/fs.h index 4b27be2038e3..df1171bada01 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -912,6 +912,10 @@ struct file { struct list_head f_tfile_llink; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; + +#ifdef CONFIG_FILE_TABLE_DEBUG + struct hlist_node f_hash; +#endif /* #ifdef CONFIG_FILE_TABLE_DEBUG */ } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ struct file_handle { diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h index e01e6781eb21..f2b8782528a8 100644 --- a/include/linux/usb/usb_qdss.h +++ b/include/linux/usb/usb_qdss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2013, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,6 +15,9 @@ #include <linux/kernel.h> +#define USB_QDSS_CH_MDM "qdss_mdm" +#define USB_QDSS_CH_MSM "qdss" + struct qdss_request { char *buf; int length; diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index 927c3626edb7..8b51873e7b08 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -84,6 +84,21 @@ struct drm_msm_ext_panel_hdr_metadata { }; /** + * HDR Control + * This encapsulates the HDR metadata as well as a state control + * for the HDR metadata as required by the HDMI spec to send the + * relevant metadata depending on the state of the HDR playback. + * hdr_state: Controls HDR state, takes values ENABLE(1)/DISABLE(0) + * hdr_meta: Metadata sent by the userspace for the HDR clip + */ + +#define DRM_MSM_EXT_PANEL_HDR_CTRL +struct drm_msm_ext_panel_hdr_ctrl { + __u8 hdr_state; /* HDR state */ + struct drm_msm_ext_panel_hdr_metadata hdr_meta; /* HDR metadata */ +}; + +/** * HDR sink properties * These are defined as per EDID spec and shall be used by the userspace * to determine the HDR properties to be set to the sink. diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h index 83927c614e91..a92c144f712e 100644 --- a/include/uapi/media/msm_camsensor_sdk.h +++ b/include/uapi/media/msm_camsensor_sdk.h @@ -113,8 +113,10 @@ enum msm_sensor_power_seq_gpio_t { SENSOR_GPIO_FL_RESET, SENSOR_GPIO_CUSTOM1, SENSOR_GPIO_CUSTOM2, + SENSOR_GPIO_CUSTOM3, SENSOR_GPIO_MAX, }; +#define SENSOR_GPIO_CUSTOM3 SENSOR_GPIO_CUSTOM3 enum msm_ir_cut_filter_gpio_t { IR_CUT_FILTER_GPIO_P = 0, diff --git a/kernel/cpu.c b/kernel/cpu.c index 87b88e8c0233..1d6b0a209bc0 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -523,8 +523,8 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen) ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls); if (ret) { nr_calls--; - pr_warn("%s: attempt to bring up CPU %u failed\n", - __func__, cpu); + pr_warn_ratelimited("%s: attempt to bring up CPU %u failed\n", + __func__, cpu); goto out_notify; } diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index a4d4de05b2d1..75c950ede9c7 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -511,6 +511,41 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) unsigned long flags; /* + * If a spinner is present, there is a chance that the load of + * rwsem_has_spinner() in rwsem_wake() can be reordered with + * respect to decrement of rwsem count in __up_write() leading + * to wakeup being missed. + * + * spinning writer up_write caller + * --------------- ----------------------- + * [S] osq_unlock() [L] osq + * spin_lock(wait_lock) + * sem->count=0xFFFFFFFF00000001 + * +0xFFFFFFFF00000000 + * count=sem->count + * MB + * sem->count=0xFFFFFFFE00000001 + * -0xFFFFFFFF00000001 + * RMB + * spin_trylock(wait_lock) + * return + * rwsem_try_write_lock(count) + * spin_unlock(wait_lock) + * schedule() + * + * Reordering of atomic_long_sub_return_release() in __up_write() + * and rwsem_has_spinner() in rwsem_wake() can cause missing of + * wakeup in up_write() context. In spinning writer, sem->count + * and local variable count is 0XFFFFFFFE00000001. It would result + * in rwsem_try_write_lock() failing to acquire rwsem and spinning + * writer going to sleep in rwsem_down_write_failed(). + * + * The smp_rmb() here is to make sure that the spinner state is + * consulted after sem->count is updated in up_write context. + */ + smp_rmb(); + + /* * If a spinner is present, it is not necessary to do the wakeup. * Try to do wakeup only if the trylock succeeds to minimize * spinlock contention which may introduce too much delay in the diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c index ae60f35b363d..b17556c346ce 100644 --- a/net/rmnet_data/rmnet_data_handlers.c +++ b/net/rmnet_data/rmnet_data_handlers.c @@ -476,10 +476,12 @@ static rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb, if (likely((ckresult == RMNET_MAP_CHECKSUM_OK) || (ckresult == RMNET_MAP_CHECKSUM_SKIPPED))) skb->ip_summed |= CHECKSUM_UNNECESSARY; - else if (ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION - && ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT - && ckresult != RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET - && ckresult != RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET) { + else if (ckresult != + RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION && + ckresult != RMNET_MAP_CHECKSUM_VALIDATION_FAILED && + ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT && + ckresult != RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET && + ckresult != RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET) { rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM); return RX_HANDLER_CONSUMED; diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 9ff010cee67e..1afd88a87e0f 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -731,7 +731,7 @@ country JO: (5170 - 5250 @ 80), (23) (5735 - 5835 @ 80), (23) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - ((57000 - 66000 @ 2160), (40) + (57000 - 66000 @ 2160), (40) country JP: DFS-JP (2402 - 2482 @ 40), (20) diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 3a12dd172d04..b428e1b8b11c 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -527,10 +527,12 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, kc_update_timestamp(entry); entry->state = ACTIVE_ICE_LOADED; - if (async && (!strcmp(s_type, - (char *)PFK_UFS))) + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { entry->loaded_ref_cnt++; - + } break; } case (FREE): @@ -544,14 +546,16 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, entry->state = ACTIVE_ICE_LOADED; /* - * only increase ref cnt for async calls, + * In case of UFS only increase ref cnt for async calls, * sync calls from within work thread do not pass * requests further to HW */ - if (async && (!strcmp(s_type, - (char *)PFK_UFS))) + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { entry->loaded_ref_cnt++; - + } } break; case (ACTIVE_ICE_PRELOAD): @@ -561,9 +565,12 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, case (ACTIVE_ICE_LOADED): kc_update_timestamp(entry); - if (async && (!strcmp(s_type, - (char *)PFK_UFS))) + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { entry->loaded_ref_cnt++; + } break; case(SCM_ERROR): ret = entry->scm_error; @@ -621,36 +628,24 @@ void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, return; } - if (!strcmp(s_type, (char *)PFK_UFS)) { - ref_cnt = --entry->loaded_ref_cnt; + ref_cnt = --entry->loaded_ref_cnt; - if (ref_cnt < 0) - pr_err("internal error, ref count should never be negative\n"); + if (ref_cnt < 0) + pr_err("internal error, ref count should never be negative\n"); - if (!ref_cnt) { - entry->state = INACTIVE; - /* - * wake-up invalidation if it's waiting - * for the entry to be released - */ - if (entry->thread_pending) { - tmp_pending = entry->thread_pending; - entry->thread_pending = NULL; - - kc_spin_unlock(); - wake_up_process(tmp_pending); - return; - } - } - } else { + if (!ref_cnt) { entry->state = INACTIVE; /* - * wake-up invalidation if it's waiting - * for the entry to be released - */ + * wake-up invalidation if it's waiting + * for the entry to be released + */ if (entry->thread_pending) { - wake_up_process(entry->thread_pending); + tmp_pending = entry->thread_pending; entry->thread_pending = NULL; + + kc_spin_unlock(); + wake_up_process(tmp_pending); + return; } } diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c index b6121d75c148..b1dff8764618 100644 --- a/sound/soc/msm/apq8096-auto.c +++ b/sound/soc/msm/apq8096-auto.c @@ -3044,21 +3044,22 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = { .codec_name = "snd-soc-dummy", }, { - .name = "SLIMBUS_4 Hostless", - .stream_name = "SLIMBUS_4 Hostless", - .cpu_dai_name = "SLIMBUS4_HOSTLESS", - .platform_name = "msm-pcm-hostless", + .name = "MSM8996 HFP RX", + .stream_name = "MultiMedia21", + .cpu_dai_name = "MultiMedia21", + .platform_name = "msm-pcm-loopback", .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, .ignore_suspend = 1, - /* this dailink has playback support */ + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + /* this dainlink has playback support */ .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA21, }, { .name = "VoLTE", @@ -3480,12 +3481,13 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, { - .name = "MSM8996 Compress9", - .stream_name = "Compress9", + .name = "MSM8996 ULL NOIRQ 2", + .stream_name = "MM_NOIRQ_2", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-compress-dsp", + .platform_name = "msm-pcm-dsp-noirq", .dynamic = 1, .dpcm_playback = 1, + .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .codec_dai_name = "snd-soc-dummy-dai", diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index cc89408fcb39..5facafdc7729 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -2496,8 +2496,21 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .rate_min = 8000, .rate_max = 384000, }, + .capture = { + .stream_name = "MultiMedia16 Capture", + .aif_name = "MM_UL16", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, .ops = &msm_fe_Multimedia_dai_ops, - .compress_new = snd_soc_new_compress, .name = "MultiMedia16", .probe = fe_dai_probe, }, @@ -2656,6 +2669,20 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .rate_min = 8000, .rate_max = 384000, }, + .capture = { + .stream_name = "MultiMedia21 Capture", + .aif_name = "MM_UL21", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, .ops = &msm_fe_Multimedia_dai_ops, .name = "MultiMedia21", .probe = fe_dai_probe, @@ -2736,6 +2763,45 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .name = "MultiMedia25", .probe = fe_dai_probe, }, + { + .playback = { + .stream_name = "MultiMedia26 Playback", + .aif_name = "MM_DL26", + .rates = (SNDRV_PCM_RATE_8000_384000 | + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 384000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia26", + .probe = fe_dai_probe, + }, + { + .capture = { + .stream_name = "MultiMedia27 Capture", + .aif_name = "MM_UL27", + .rates = (SNDRV_PCM_RATE_8000_192000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 192000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia27", + .probe = fe_dai_probe, + }, }; static int msm_fe_dai_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c index 4eafd322d50d..010dfa3322a0 100644 --- a/sound/soc/msm/msm8996.c +++ b/sound/soc/msm/msm8996.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2910,12 +2910,13 @@ static struct snd_soc_dai_link msm8996_common_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, { - .name = "MSM8996 Compress9", - .stream_name = "Compress9", + .name = "MSM8996 ULL NOIRQ_2", + .stream_name = "MM_NOIRQ_2", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-compress-dsp", + .platform_name = "msm-pcm-dsp-noirq", .dynamic = 1, .dpcm_playback = 1, + .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .codec_dai_name = "snd-soc-dummy-dai", diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index e715770d909a..b8bd32e046a3 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -557,6 +557,13 @@ static struct snd_soc_dapm_route wcd_audio_paths[] = { {"MIC BIAS4", NULL, "MCLK"}, }; +static u32 mi2s_ebit_clk[MI2S_MAX] = { + Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT, +}; + static struct afe_clk_set mi2s_clk[MI2S_MAX] = { { AFE_API_VERSION_I2S_CONFIG, @@ -4508,6 +4515,11 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) */ mutex_lock(&mi2s_intf_conf[index].lock); if (++mi2s_intf_conf[index].ref_cnt == 1) { + /* Check if msm needs to provide the clock to the interface */ + if (!mi2s_intf_conf[index].msm_is_mi2s_master) { + fmt = SND_SOC_DAIFMT_CBM_CFM; + mi2s_clk[index].clk_id = mi2s_ebit_clk[index]; + } ret = msm_mi2s_set_sclk(substream, true); if (IS_ERR_VALUE(ret)) { dev_err(rtd->card->dev, @@ -4527,9 +4539,6 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) ret = -EINVAL; goto clk_off; } - /* Check if msm needs to provide the clock to the interface */ - if (!mi2s_intf_conf[index].msm_is_mi2s_master) - fmt = SND_SOC_DAIFMT_CBM_CFM; ret = snd_soc_dai_set_fmt(cpu_dai, fmt); if (IS_ERR_VALUE(ret)) { pr_err("%s: set fmt cpu dai failed for MI2S (%d), err:%d\n", @@ -5306,12 +5315,13 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, { - .name = MSM_DAILINK_NAME(Compress9), - .stream_name = "Compress9", + .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), + .stream_name = "MM_NOIRQ_2", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-compress-dsp", + .platform_name = "msm-pcm-dsp-noirq", .dynamic = 1, .dpcm_playback = 1, + .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .codec_dai_name = "snd-soc-dummy-dai", @@ -5500,7 +5510,7 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { { .name = MSM_DAILINK_NAME(Transcode Loopback Playback), .stream_name = "Transcode Loopback Playback", - .cpu_dai_name = "MultiMedia14", + .cpu_dai_name = "MultiMedia26", .platform_name = "msm-transcode-loopback", .dynamic = 1, .dpcm_playback = 1, @@ -5511,12 +5521,12 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .ignore_suspend = 1, .ignore_pmdown_time = 1, /* this dainlink has playback support */ - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA26, }, { .name = MSM_DAILINK_NAME(Transcode Loopback Capture), .stream_name = "Transcode Loopback Capture", - .cpu_dai_name = "MultiMedia18", + .cpu_dai_name = "MultiMedia27", .platform_name = "msm-transcode-loopback", .dynamic = 1, .dpcm_capture = 1, @@ -5526,7 +5536,7 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .codec_name = "snd-soc-dummy", .ignore_suspend = 1, .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA18, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA27, }, { .name = "MultiMedia21", diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 2bf61521ad52..38937612dcce 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -605,6 +605,27 @@ static struct msm_pcm_routing_fdai_data /* MULTIMEDIA20 */ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA21 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA22 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA23 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA24 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA25 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA26 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA27 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, /* CS_VOICE */ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, @@ -3654,6 +3675,11 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 = msm_route_ec_ref_rx_enum[0], msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); +static const struct snd_kcontrol_new ext_ec_ref_mux_ul16 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL16 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 = SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux", msm_route_ec_ref_rx_enum[0], @@ -3812,6 +3838,9 @@ static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { @@ -3872,6 +3901,9 @@ static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { @@ -3932,7 +3964,9 @@ static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = { @@ -3984,6 +4018,9 @@ static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_2_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = { @@ -4044,6 +4081,9 @@ static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_5_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { @@ -4119,6 +4159,9 @@ static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { @@ -4179,6 +4222,9 @@ static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { @@ -4239,6 +4285,9 @@ static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { @@ -4299,6 +4348,9 @@ static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { @@ -4353,6 +4405,9 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = { @@ -4419,6 +4474,9 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { @@ -4479,6 +4537,9 @@ static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = { @@ -4530,6 +4591,9 @@ static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT0_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int4_mi2s_rx_mixer_controls[] = { @@ -4581,6 +4645,9 @@ static const struct snd_kcontrol_new int4_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT4_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new hdmi_mixer_controls[] = { @@ -4656,6 +4723,9 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new display_port_mixer_controls[] = { @@ -4707,6 +4777,9 @@ static const struct snd_kcontrol_new display_port_mixer_controls[] = { 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), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; /* incall music delivery mixer */ @@ -4819,6 +4892,9 @@ static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_6_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_7_rx_mixer_controls[] = { @@ -4885,6 +4961,9 @@ static const struct snd_kcontrol_new slimbus_7_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_7_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new usb_audio_rx_mixer_controls[] = { @@ -4936,6 +5015,9 @@ static const struct snd_kcontrol_new usb_audio_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_USB_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = { @@ -4996,6 +5078,9 @@ static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = { @@ -5047,6 +5132,9 @@ static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = { @@ -5107,6 +5195,9 @@ static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_FM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { @@ -5167,6 +5258,9 @@ static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_AFE_PCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { @@ -5227,6 +5321,12 @@ static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { @@ -5287,6 +5387,12 @@ static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = { @@ -5338,6 +5444,9 @@ static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_auxpcm_rx_mixer_controls[] = { @@ -5389,6 +5498,9 @@ static const struct snd_kcontrol_new quat_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = { @@ -5440,6 +5552,12 @@ static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = { @@ -5491,6 +5609,12 @@ static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = { @@ -5542,6 +5666,12 @@ static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = { @@ -5593,6 +5723,12 @@ static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = { @@ -5695,6 +5831,12 @@ static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = { @@ -5746,6 +5888,12 @@ static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = { @@ -5797,6 +5945,12 @@ static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = { @@ -5848,6 +6002,12 @@ static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = { @@ -5950,6 +6110,12 @@ static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = { @@ -6052,6 +6218,12 @@ static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = { @@ -6103,6 +6275,12 @@ static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = { @@ -6154,6 +6332,12 @@ static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = { @@ -6205,6 +6389,12 @@ static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_4, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_4, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = { @@ -6259,6 +6449,12 @@ static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = { @@ -6364,6 +6560,12 @@ static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = { @@ -6418,6 +6620,12 @@ static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = { @@ -6472,6 +6680,12 @@ static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul1_mixer_controls[] = { @@ -7161,6 +7375,114 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new mmul16_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + static const struct snd_kcontrol_new mmul9_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, @@ -7350,6 +7672,75 @@ static const struct snd_kcontrol_new mmul20_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new mmul21_mixer_controls[] = { + SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul27_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = { SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, @@ -11457,6 +11848,7 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_IN("MM_DL23", "MultiMedia23 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("MM_DL24", "MultiMedia24 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("MM_DL25", "MultiMedia25 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL26", "MultiMedia26 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0), @@ -11466,10 +11858,13 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL16", "MultiMedia16 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL20", "MultiMedia20 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL21", "MultiMedia21 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL27", "MultiMedia27 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0), @@ -12202,6 +12597,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0, mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia16 Mixer", SND_SOC_NOPM, 0, 0, + mmul16_mixer_controls, ARRAY_SIZE(mmul16_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0, mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0, @@ -12210,6 +12607,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia20 Mixer", SND_SOC_NOPM, 0, 0, mmul20_mixer_controls, ARRAY_SIZE(mmul20_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia21 Mixer", SND_SOC_NOPM, 0, 0, + mmul21_mixer_controls, ARRAY_SIZE(mmul21_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia27 Mixer", SND_SOC_NOPM, 0, 0, + mmul27_mixer_controls, ARRAY_SIZE(mmul27_mixer_controls)), SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)), SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -12532,6 +12933,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &ext_ec_ref_mux_ul8), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul9), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL16 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul16), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul17), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0, @@ -12557,6 +12960,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"}, {"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12575,6 +12979,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"}, {"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12598,6 +13003,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_0_RX Audio Mixer", "MultiMedia23", "MM_DL23"}, {"SLIMBUS_0_RX Audio Mixer", "MultiMedia24", "MM_DL24"}, {"SLIMBUS_0_RX Audio Mixer", "MultiMedia25", "MM_DL25"}, + {"SLIMBUS_0_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"}, {"SLIMBUS_2_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12616,6 +13022,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_2_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SLIMBUS_2_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SLIMBUS_2_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SLIMBUS_2_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_2_RX", NULL, "SLIMBUS_2_RX Audio Mixer"}, {"SLIMBUS_5_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12634,6 +13041,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_5_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SLIMBUS_5_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SLIMBUS_5_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SLIMBUS_5_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_5_RX", NULL, "SLIMBUS_5_RX Audio Mixer"}, {"HDMI Mixer", "MultiMedia1", "MM_DL1"}, @@ -12657,6 +13065,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"HDMI Mixer", "MultiMedia23", "MM_DL23"}, {"HDMI Mixer", "MultiMedia24", "MM_DL24"}, {"HDMI Mixer", "MultiMedia25", "MM_DL25"}, + {"HDMI Mixer", "MultiMedia26", "MM_DL26"}, {"HDMI", NULL, "HDMI Mixer"}, {"DISPLAY_PORT Mixer", "MultiMedia1", "MM_DL1"}, @@ -12675,6 +13084,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"DISPLAY_PORT Mixer", "MultiMedia14", "MM_DL14"}, {"DISPLAY_PORT Mixer", "MultiMedia15", "MM_DL15"}, {"DISPLAY_PORT Mixer", "MultiMedia16", "MM_DL16"}, + {"DISPLAY_PORT Mixer", "MultiMedia26", "MM_DL26"}, {"DISPLAY_PORT", NULL, "DISPLAY_PORT Mixer"}, {"SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12693,6 +13103,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SPDIF_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SPDIF_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SPDIF_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SPDIF_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SPDIF_RX", NULL, "SPDIF_RX Audio Mixer"}, /* incall */ @@ -12733,6 +13144,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_6_RX Audio Mixer", "MultiMedia23", "MM_DL23"}, {"SLIMBUS_6_RX Audio Mixer", "MultiMedia24", "MM_DL24"}, {"SLIMBUS_6_RX Audio Mixer", "MultiMedia25", "MM_DL25"}, + {"SLIMBUS_6_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"}, {"SLIMBUS_7_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12756,6 +13168,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_7_RX Audio Mixer", "MultiMedia23", "MM_DL23"}, {"SLIMBUS_7_RX Audio Mixer", "MultiMedia24", "MM_DL24"}, {"SLIMBUS_7_RX Audio Mixer", "MultiMedia25", "MM_DL25"}, + {"SLIMBUS_7_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_7_RX", NULL, "SLIMBUS_7_RX Audio Mixer"}, {"USB_AUDIO_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12774,6 +13187,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"USB_AUDIO_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"USB_AUDIO_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"USB_AUDIO_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"USB_AUDIO_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"USB_AUDIO_RX", NULL, "USB_AUDIO_RX Audio Mixer"}, {"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"}, @@ -12803,6 +13217,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia16 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, {"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12821,6 +13236,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"MI2S_RX", NULL, "MI2S_RX Audio Mixer"}, {"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12838,6 +13254,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"QUAT_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"}, {"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12854,6 +13271,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"TERT_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"}, {"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12870,6 +13288,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"}, {"SEC_MI2S_RX_SD1 Audio Mixer", "MultiMedia6", "MM_DL6"}, @@ -12893,6 +13312,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"}, {"INT0_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12910,6 +13330,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"INT0_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"INT0_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"INT0_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"INT0_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX Audio Mixer"}, {"INT4_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12927,6 +13348,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"INT4_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"INT4_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"INT4_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"INT4_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX Audio Mixer"}, {"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12946,6 +13368,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUIN_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"QUIN_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUIN_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"QUIN_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX Audio Mixer"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12964,6 +13387,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"}, {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12982,6 +13407,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Audio Mixer"}, {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13000,6 +13427,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Audio Mixer"}, {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13018,6 +13447,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Audio Mixer"}, {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13054,6 +13485,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"}, {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13072,6 +13505,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Audio Mixer"}, {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13090,6 +13525,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Audio Mixer"}, {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13108,6 +13545,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Audio Mixer"}, {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13144,6 +13583,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Audio Mixer"}, {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13180,6 +13621,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1 Audio Mixer"}, {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13198,6 +13641,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2 Audio Mixer"}, {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13216,6 +13661,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"}, {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13234,6 +13681,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13253,6 +13702,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia20", "MM_DL20"}, + {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13271,6 +13722,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13289,6 +13741,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"}, {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13326,6 +13779,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia20", "MM_DL20"}, + {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Audio Mixer"}, {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13345,6 +13800,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia20", "MM_DL20"}, + {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Audio Mixer"}, {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13364,6 +13821,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia20", "MM_DL20"}, + {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Audio Mixer"}, {"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"}, @@ -13371,9 +13830,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"}, {"MultiMedia3 Mixer", "MI2S_TX", "MI2S_TX"}, {"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"}, + {"MultiMedia16 Mixer", "MI2S_TX", "MI2S_TX"}, {"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"MultiMedia6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia27 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"MultiMedia1 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"}, {"MultiMedia2 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"}, {"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, @@ -13383,24 +13844,29 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia2 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia27 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"MultiMedia3 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"}, {"MultiMedia5 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, + {"MultiMedia16 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"}, + {"MultiMedia16 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia1 Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia1 Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, + {"MultiMedia16 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia2 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"}, {"MultiMedia2 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"}, {"MultiMedia2 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia27 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia2 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, @@ -13409,9 +13875,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia6 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, {"MultiMedia3 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, {"MultiMedia5 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, + {"MultiMedia16 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, {"MultiMedia6 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, + {"MultiMedia16 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, @@ -13566,6 +14034,25 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia20 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, {"MultiMedia20 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, + {"MultiMedia21 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, + {"MultiMedia21 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, + {"MultiMedia21 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"MultiMedia21 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, + {"MultiMedia21 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"}, + {"MultiMedia21 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"}, + {"MultiMedia21 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"}, + {"MultiMedia21 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"}, + {"MultiMedia21 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, + {"MultiMedia21 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, + {"MultiMedia21 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, + {"MultiMedia21 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"}, + {"MultiMedia21 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"}, + {"MultiMedia21 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, + {"MultiMedia21 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, + {"MultiMedia21 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, + {"MultiMedia21 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, + {"MultiMedia21 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, + {"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia4 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, @@ -13573,6 +14060,24 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia6 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia8 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, + {"MultiMedia16 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, + {"MultiMedia16 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, + {"MultiMedia16 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"MultiMedia16 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, + {"MultiMedia16 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"}, + {"MultiMedia16 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"}, + {"MultiMedia16 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"}, + {"MultiMedia16 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"}, + {"MultiMedia16 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, + {"MultiMedia16 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, + {"MultiMedia16 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, + {"MultiMedia16 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"}, + {"MultiMedia16 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"}, + {"MultiMedia16 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, + {"MultiMedia16 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, + {"MultiMedia16 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, + {"MultiMedia16 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, + {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, @@ -13655,8 +14160,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"MultiMedia16 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"MultiMedia16 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, @@ -13672,6 +14179,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"}, + {"MultiMedia16 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MM_UL1", NULL, "MultiMedia1 Mixer"}, {"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MM_UL2", NULL, "MultiMedia2 Mixer"}, @@ -13681,10 +14189,13 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL6", NULL, "MultiMedia6 Mixer"}, {"MM_UL8", NULL, "MultiMedia8 Mixer"}, {"MM_UL9", NULL, "MultiMedia9 Mixer"}, + {"MM_UL16", NULL, "MultiMedia16 Mixer"}, {"MM_UL17", NULL, "MultiMedia17 Mixer"}, {"MM_UL18", NULL, "MultiMedia18 Mixer"}, {"MM_UL19", NULL, "MultiMedia19 Mixer"}, {"MM_UL20", NULL, "MultiMedia20 Mixer"}, + {"MM_UL21", NULL, "MultiMedia21 Mixer"}, + {"MM_UL27", NULL, "MultiMedia27 Mixer"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, @@ -13702,6 +14213,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_UL6"}, + {"AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_UL21"}, {"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"}, {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13720,6 +14234,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_DL21"}, + {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_UL6"}, + {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_UL21"}, {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"}, {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -14091,6 +14608,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"}, {"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"}, {"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"}, + {"MM_UL16", NULL, "AUDIO_REF_EC_UL16 MUX"}, {"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"}, {"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"}, {"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"}, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index a8daff09db58..c640be343e10 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -198,6 +198,8 @@ enum { MSM_FRONTEND_DAI_MULTIMEDIA23, MSM_FRONTEND_DAI_MULTIMEDIA24, MSM_FRONTEND_DAI_MULTIMEDIA25, + MSM_FRONTEND_DAI_MULTIMEDIA26, + MSM_FRONTEND_DAI_MULTIMEDIA27, MSM_FRONTEND_DAI_CS_VOICE, MSM_FRONTEND_DAI_VOIP, MSM_FRONTEND_DAI_AFE_RX, @@ -223,8 +225,8 @@ enum { MSM_FRONTEND_DAI_MAX, }; -#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA25 + 1) -#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA25 +#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA27 + 1) +#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA27 enum { MSM_BACKEND_DAI_PRI_I2S_RX = 0, diff --git a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c index 6bb85ca8e84e..5c5f7bc482c8 100644 --- a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c @@ -100,7 +100,7 @@ static void loopback_event_handler(uint32_t opcode, return; } - cstream = trans->source.cstream; + cstream = trans->sink.cstream; ac = trans->audio_client; /* @@ -223,6 +223,7 @@ static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) ret = -EINVAL; goto exit; } + msm_adsp_init_mixer_ctl_pp_event_queue(rtd); } pr_debug("%s: num stream%d, stream name %s\n", __func__, @@ -237,8 +238,7 @@ static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) } runtime->private_data = trans; - if (trans->num_streams == 1) - msm_adsp_init_mixer_ctl_pp_event_queue(rtd); + exit: mutex_unlock(&trans->lock); return ret; @@ -283,14 +283,14 @@ static int msm_transcode_loopback_free(struct snd_compr_stream *cstream) trans->num_streams--; stop_transcoding(trans); - if (cstream->direction == SND_COMPRESS_PLAYBACK) + if (cstream->direction == SND_COMPRESS_PLAYBACK) { memset(&trans->sink, 0, sizeof(struct loopback_stream)); - else if (cstream->direction == SND_COMPRESS_CAPTURE) + msm_adsp_clean_mixer_ctl_pp_event_queue(rtd); + } else if (cstream->direction == SND_COMPRESS_CAPTURE) { memset(&trans->source, 0, sizeof(struct loopback_stream)); + } trans->session_state = LOOPBACK_SESSION_CLOSE; - if (trans->num_streams == 1) - msm_adsp_clean_mixer_ctl_pp_event_queue(rtd); mutex_unlock(&trans->lock); return ret; } diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index e1bfc950d0e3..018681309f2e 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -2364,7 +2364,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, struct adm_cmd_device_open_v5 open; struct adm_cmd_device_open_v6 open_v6; int ret = 0; - int port_idx, copp_idx, flags; + int port_idx, flags; + int copp_idx = -1; int tmp_port = q6audio_get_port_id(port_id); pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n", @@ -2418,8 +2419,17 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)) rate = 16000; - copp_idx = adm_get_idx_if_copp_exists(port_idx, topology, perf_mode, - rate, bit_width, app_type); + /* + * Routing driver reuses the same adm for streams with the same + * app_type, sample_rate etc. + * This isn't allowed for ULL streams as per the DSP interface + */ + if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) + copp_idx = adm_get_idx_if_copp_exists(port_idx, topology, + perf_mode, + rate, bit_width, + app_type); + if (copp_idx < 0) { copp_idx = adm_get_next_available_copp(port_idx); if (copp_idx >= MAX_COPPS_PER_PORT) { diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index d3cff9fccf59..a44569530846 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -423,14 +423,22 @@ static void config_debug_fs_run(void) } } -static void config_debug_fs_write(struct audio_buffer *ab) +static void config_debug_fs_write(struct audio_buffer *ab, int offset) { if (out_enable_flag) { char zero_pattern[2] = {0x00, 0x00}; + char *data; + + if ((offset < 0) || (offset > ab->size)) { + pr_err("Invalid offset %d", offset); + return; + } + + data = (char *)ab->data + offset; /* If First two byte is non zero and last two byte is zero then it is warm output pattern */ - if ((strncmp(((char *)ab->data), zero_pattern, 2)) && - (!strncmp(((char *)ab->data + 2), zero_pattern, 2))) { + if ((strncmp(data, zero_pattern, 2)) && + (!strncmp((data + 2), zero_pattern, 2))) { do_gettimeofday(&out_warm_tv); pr_debug("%s: WARM:apr_send_pkt at %ld sec %ld microsec\n", __func__, @@ -440,8 +448,8 @@ static void config_debug_fs_write(struct audio_buffer *ab) } /* If First two byte is zero and last two byte is non zero then it is cont ouput pattern */ - else if ((!strncmp(((char *)ab->data), zero_pattern, 2)) - && (strncmp(((char *)ab->data + 2), zero_pattern, 2))) { + else if ((!strncmp(data, zero_pattern, 2)) + && (strncmp((data + 2), zero_pattern, 2))) { do_gettimeofday(&out_cont_tv); pr_debug("%s: CONT:apr_send_pkt at %ld sec %ld microsec\n", __func__, @@ -488,7 +496,7 @@ outbuf_fail: return; } #else -static void config_debug_fs_write(struct audio_buffer *ab) +static void config_debug_fs_write(struct audio_buffer *ab, int offset) { return; } @@ -7979,6 +7987,7 @@ int q6asm_async_write(struct audio_client *ac, u32 liomode; u32 io_compressed; u32 io_compressed_stream; + int offset = 0; if (ac == NULL) { pr_err("%s: APR handle NULL\n", __func__); @@ -8040,7 +8049,10 @@ int q6asm_async_write(struct audio_client *ac, } } - config_debug_fs_write(ab); + if (ab != NULL) { + offset = lbuf_phys_addr - ab->phys; + config_debug_fs_write(ab, offset); + } rc = apr_send_pkt(ac->apr, (uint32_t *) &write); if (rc < 0) { @@ -8187,7 +8199,7 @@ int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts, write.mem_map_handle); mutex_unlock(&port->lock); - config_debug_fs_write(ab); + config_debug_fs_write(ab, 0); rc = apr_send_pkt(ac->apr, (uint32_t *) &write); if (rc < 0) { diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c index 1c03d8c9e797..30c3ffe2347d 100644 --- a/sound/soc/msm/sdm660-ext-dai-links.c +++ b/sound/soc/msm/sdm660-ext-dai-links.c @@ -1270,10 +1270,10 @@ static struct snd_soc_dai_link msm_ext_common_fe_dai[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, {/* hw:x,33 */ - .name = MSM_DAILINK_NAME(Compress9), - .stream_name = "Compress9", + .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), + .stream_name = "MM_NOIRQ_2", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-compress-dsp", + .platform_name = "msm-pcm-dsp-noirq", .dynamic = 1, .dpcm_capture = 1, .dpcm_playback = 1, diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c index f4219148e81c..0f28e100f535 100644 --- a/sound/soc/msm/sdm660-internal.c +++ b/sound/soc/msm/sdm660-internal.c @@ -2188,10 +2188,10 @@ static struct snd_soc_dai_link msm_int_dai[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, {/* hw:x,33 */ - .name = MSM_DAILINK_NAME(Compress9), - .stream_name = "Compress9", + .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), + .stream_name = "MM_NOIRQ_2", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-compress-dsp", + .platform_name = "msm-pcm-dsp-noirq", .dynamic = 1, .dpcm_capture = 1, .dpcm_playback = 1, |
