diff options
81 files changed, 3582 insertions, 564 deletions
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt new file mode 100644 index 000000000000..626ca2124366 --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt @@ -0,0 +1,16 @@ +* Qualcomm Technologies, Inc. WCN3990 chipset WLAN platform Driver + +This driver adds support for the Integrated WCN3990 WLAN module, WCN3990 +is integrated 802.11ac chipset with SNOC bus interface. It also add support +for SNOC bus registration, copy engine configuration for the WCN3990 chipset, +shadow register configuration, create host to target communication interface +to interact with WLAN firmware, WLAN module interface control and data +receive(RX)/transmit(TX) control. + +Required properties: + - compatible: "qcom,wcn3990-wifi"; + +Example: + qcom,msm_ath10k@18000000 { + compatible = "qcom,wcn3990-wifi"; + }; diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt index 3e22f178aa82..d08ca957c954 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt @@ -203,10 +203,11 @@ IBB subnode required properties: - qcom,qpnp-ibb-init-lcd-voltage: The default output voltage when IBB regulator is configured in lcd mode. +IBB subnode optional properties: + - qcom,qpnp-ibb-discharge-resistor: The discharge resistor in Kilo Ohms which controls the soft start time. Supported values are 300, 64, 32 and 16. -IBB subnode optional properties: - qcom,qpnp-ibb-slew-rate: The time (in us) taken by the regulator to change voltage value in one step. This property is not diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 86e1bdb417ab..fc2c89bfbbd5 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1649,6 +1649,7 @@ Optional properties: capacitor mode. - qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external capacitor mode. +- qcom,wsa-disable : Boolean. Disables WSA speaker dailinks from sound node. - qcom,msm-spk-ext-pa : GPIO which enables external speaker pa. - qcom,msm-mclk-freq : This property is used to inform machine driver about mclk frequency needs to be configured for internal and external PA. @@ -1685,6 +1686,7 @@ Example: qcom,msm-mclk-freq = <9600000>; qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; + qcom,wsa-disable; qcom,msm-mbhc-moist-cfg = <1>, <3>, <0>; qcom,msm-hs-micbias-type = "internal"; qcom,msm-micbias1-ext-cap; diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index fa6ee8969946..47fad8aa4a1a 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -19,6 +19,7 @@ Required properties : and reset lines used by this controller. - reset-names: reset signal name strings sorted in the same order as the resets property. +- qcom,core-clk-rate: clock frequency to be set for USB master clock. Optional properties : - reg: Additional registers @@ -54,7 +55,8 @@ Optional properties : - qcom,disable-dev-mode-pm: If present, it disables PM runtime functionality for device mode. - qcom,disable-host-mode-pm: If present, it disables XHCI PM runtime functionality when USB host mode is used. -- qcom,core-clk-rate: If present, indicates clock frequency to be set for USB master clock. +- qcom,core-clk-rate-hs: If present, indicates min core clock frequency required to support + hs speed. - extcon: phandles to external connector devices. First phandle should point to external connector, which provide "USB" cable events, the second should point to external connector device, which provide "USB-HOST" diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 2c5137a6fef6..6475fa234065 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -850,14 +850,13 @@ via the /proc/sys interface: Each write syscall must fully contain the sysctl value to be written, and multiple writes on the same sysctl file descriptor will rewrite the sysctl value, regardless of file position. - 0 - (default) Same behavior as above, but warn about processes that - perform writes to a sysctl file descriptor when the file position - is not 0. - 1 - Respect file position when writing sysctl strings. Multiple writes - will append to the sysctl value buffer. Anything past the max length - of the sysctl value buffer will be ignored. Writes to numeric sysctl - entries must always be at file position 0 and the value must be - fully contained in the buffer sent in the write syscall. + 0 - Same behavior as above, but warn about processes that perform writes + to a sysctl file descriptor when the file position is not 0. + 1 - (default) Respect file position when writing sysctl strings. Multiple + writes will append to the sysctl value buffer. Anything past the max + length of the sysctl value buffer will be ignored. Writes to numeric + sysctl entries must always be at file position 0 and the value must + be fully contained in the buffer sent in the write syscall. ============================================================== diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi new file mode 100644 index 000000000000..3c0134b665fc --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi @@ -0,0 +1,189 @@ +/* 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. + */ + +&mdss_mdp { + dsi_nt35695b_truly_fhd_cmd: qcom,mdss_dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd command mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <96>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6e 2a + 3c 44 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-on-command = [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 35 02 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi new file mode 100644 index 000000000000..d6b24f4e54d2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi @@ -0,0 +1,185 @@ +/* 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. + */ + +&mdss_mdp { + dsi_nt35695b_truly_fhd_video: qcom,mdss_dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <96>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6e 2a + 3c 44 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-on-command = [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 35 02 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi index bc960093fcea..e34cf0426887 100644 --- a/arch/arm/boot/dts/qcom/msm-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi @@ -810,6 +810,7 @@ status = "disabled"; compatible = "qcom,sdm660-asoc-snd"; qcom,model = "sdm660-snd-card"; + qcom,wsa-disable; qcom,wcn-btfm; qcom,mi2s-audio-intf; qcom,auxpcm-audio-intf; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index b1880c076e1c..be47b6483288 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -534,7 +534,6 @@ qcom,qpnp-ibb-soft-start = <1000>; - qcom,qpnp-ibb-discharge-resistor = <32>; qcom,qpnp-ibb-lab-pwrup-delay = <8000>; qcom,qpnp-ibb-lab-pwrdn-delay = <8000>; qcom,qpnp-ibb-en-discharge; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 9490046133a3..30679791006b 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -1286,8 +1286,7 @@ compatible = "qcom,glink_ssr"; label = "modem"; qcom,edge = "mpss"; - qcom,notify-edges = <&glink_lpass>, <&glink_dsps>, <&glink_rpm>, - <&glink_spss>; + qcom,notify-edges = <&glink_lpass>, <&glink_dsps>, <&glink_rpm>; qcom,xprt = "smem"; }; @@ -1295,8 +1294,7 @@ compatible = "qcom,glink_ssr"; label = "adsp"; qcom,edge = "lpass"; - qcom,notify-edges = <&glink_mpss>, <&glink_dsps>, <&glink_rpm>, - <&glink_spss>; + qcom,notify-edges = <&glink_mpss>, <&glink_dsps>, <&glink_rpm>; qcom,xprt = "smem"; }; @@ -1304,8 +1302,7 @@ compatible = "qcom,glink_ssr"; label = "slpi"; qcom,edge = "dsps"; - qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, <&glink_rpm>, - <&glink_spss>; + qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, <&glink_rpm>; qcom,xprt = "smem"; }; @@ -1739,6 +1736,7 @@ "utmi_clk", "sleep_clk", "xo"; qcom,core-clk-rate = <120000000>; + qcom,core-clk-rate-hs = <60000000>; resets = <&clock_gcc USB_30_BCR>; reset-names = "core_reset"; diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi index 534d4c0c7822..e2344063ce16 100644 --- a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi @@ -27,3 +27,52 @@ &pm660_charger { qcom,batteryless-platform; }; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <110 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi index c3f5d331a734..7a4e36ddda9e 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi @@ -36,3 +36,52 @@ &pm660_fg { qcom,battery-data = <&mtp_batterydata>; }; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <110 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-rumi.dts b/arch/arm/boot/dts/qcom/sdm630-rumi.dts index ddf954f9f6ff..2ea1af4da90c 100644 --- a/arch/arm/boot/dts/qcom/sdm630-rumi.dts +++ b/arch/arm/boot/dts/qcom/sdm630-rumi.dts @@ -86,3 +86,52 @@ compatible = "qcom,dummycc"; clock-output-names = "debug_clocks"; }; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <110 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 973d86f52896..9aa83c07ebac 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -26,6 +26,8 @@ aliases { serial0 = &uartblsp1dm1; + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 for SD card */ }; chosen { @@ -644,6 +646,21 @@ interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>; }; + qcom,bcl { + compatible = "qcom,bcl"; + qcom,bcl-enable; + qcom,bcl-framework-interface; + qcom,bcl-hotplug-list = <&CPU2 &CPU3>; + qcom,bcl-soc-hotplug-list = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,ibat-monitor { + qcom,low-threshold-uamp = <3400000>; + qcom,high-threshold-uamp = <4200000>; + qcom,vph-high-threshold-uv = <3500000>; + qcom,vph-low-threshold-uv = <3300000>; + qcom,soc-low-threshold = <10>; + }; + }; + wdog: qcom,wdt@17817000 { status = "disabled"; compatible = "qcom,msm-watchdog"; @@ -1108,7 +1125,6 @@ compatible = "qcom,rpm-glink"; qcom,glink-edge = "rpm"; rpm-channel-name = "rpm_requests"; - rpm-standalone; }; qcom,ipc_router { @@ -1382,6 +1398,116 @@ qcom,not-wakeup; /* Needed until Full-boot-chain enabled */ status = "ok"; }; + + qcom_seecom: qseecom@86d00000 { + compatible = "qcom,qseecom"; + reg = <0x86d00000 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,support-fde; + qcom,no-clock-support; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 200000 400000>, + <55 512 300000 800000>, + <55 512 400000 1000000>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_rpmcc QSEECOM_CE1_CLK>, + <&clock_rpmcc QSEECOM_CE1_CLK>, + <&clock_rpmcc QSEECOM_CE1_CLK>, + <&clock_rpmcc QSEECOM_CE1_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_cedev: qcedev@1de0000{ + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 206 0>; + qcom,bam-pipe-pair = <1>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_rpmcc QCEDEV_CE1_CLK>, + <&clock_rpmcc QCEDEV_CE1_CLK>, + <&clock_rpmcc QCEDEV_CE1_CLK>, + <&clock_rpmcc QCEDEV_CE1_CLK>; + qcom,ce-opp-freq = <171430000>; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 206 0>; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_rpmcc QCRYPTO_CE1_CLK>, + <&clock_rpmcc QCRYPTO_CE1_CLK>, + <&clock_rpmcc QCRYPTO_CE1_CLK>, + <&clock_rpmcc QCRYPTO_CE1_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + }; + + qcom_tzlog: tz-log@146bf720 { + compatible = "qcom,tz-log"; + reg = <0x146bf720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_rng: qrng@793000 { + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 618 0 0>, /* No vote */ + <1 618 0 800>; /* 100 KHz */ + clocks = <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; }; #include "sdm630-ion.dtsi" diff --git a/arch/arm/boot/dts/qcom/sdm660-blsp.dtsi b/arch/arm/boot/dts/qcom/sdm660-blsp.dtsi index 023c34d65680..555d9a285102 100644 --- a/arch/arm/boot/dts/qcom/sdm660-blsp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-blsp.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 @@ -518,9 +518,10 @@ clocks = <&clock_gcc GCC_BLSP2_UART1_APPS_CLK>, <&clock_gcc GCC_BLSP2_AHB_CLK>; pinctrl-names = "sleep", "default"; - pinctrl-0 = <&blsp2_uart1_sleep>; - pinctrl-1 = <&blsp2_uart1_active>; - + pinctrl-0 = <&blsp2_uart1_tx_sleep>, + <&blsp2_uart1_rxcts_sleep>, <&blsp2_uart1_rfr_sleep>; + pinctrl-1 = <&blsp2_uart1_tx_active>, + <&blsp2_uart1_rxcts_active>, <&blsp2_uart1_rfr_active>; qcom,msm-bus,name = "buart3"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; diff --git a/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi index 676e970a7e73..0b82fbf7ffbc 100644 --- a/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi @@ -125,6 +125,20 @@ qcom,panel-roi-alignment = <720 128 720 128 1440 128>; }; +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm660l_l4>; diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi index f9915fbf3f58..a5e66f38df3c 100644 --- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi @@ -321,4 +321,98 @@ reg = <0xa8f8000 0x300>; qcom,reset-ep-after-lpm-resume; }; + + sdhc_1: sdhci@c0c4000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>; + reg-names = "hc_mem", "cmdq_mem"; + + interrupts = <0 110 0>, <0 112 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <26 81>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cmdq-latency-us = <26 81>, <26 81>; + qcom,pm-qos-legacy-latency-us = <26 81>, <26 81>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */ + <78 512 1046 3200>, /* 400 KB/s*/ + <78 512 52286 160000>, /* 20 MB/s */ + <78 512 65360 200000>, /* 25 MB/s */ + <78 512 130718 400000>, /* 50 MB/s */ + <78 512 130718 400000>, /* 100 MB/s */ + <78 512 261438 800000>, /* 200 MB/s */ + <78 512 261438 800000>, /* 400 MB/s */ + <78 512 1338562 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 400000000 4294967295>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,ice-clk-rates = <300000000 150000000>; + + status = "disabled"; + }; + + sdhc_2: sdhci@c084000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0xc084000 0x1000>; + reg-names = "hc_mem"; + + interrupts = <0 125 0>, <0 221 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */ + <81 512 1046 3200>, /* 400 KB/s */ + <81 512 52286 160000>, /* 20 MB/s */ + <81 512 65360 200000>, /* 25 MB/s */ + <81 512 130718 400000>, /* 50 MB/s */ + <81 512 261438 800000>, /* 100 MB/s */ + <81 512 261438 800000>, /* 200 MB/s */ + <81 512 1338562 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <26 81>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-legacy-latency-us = <26 81>, <26 81>; + + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index a25343981ace..da41c9127d90 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -20,6 +20,8 @@ #include "dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi" #include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi" #include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -139,3 +141,19 @@ 23 1e 07 08 05 03 04 a0 23 18 07 08 04 03 04 a0]; }; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-mtp.dts index 97058d470446..72bfa20b2bf9 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-mtp.dts @@ -24,3 +24,7 @@ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index 0c933807cdd8..2c207873aa0b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -1190,29 +1190,83 @@ }; }; - blsp2_uart1_active: blsp2_uart1_active { - mux { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - function = "blsp_uart5"; + blsp2_uart1: blsp2_uart1 { + blsp2_uart1_tx_active: blsp2_uart1_tx_active { + mux { + pins = "gpio16"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - drive-strength = <2>; - bias-disable; + blsp2_uart1_tx_sleep: blsp2_uart1_tx_sleep { + mux { + pins = "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-pull-up; + }; }; - }; - blsp2_uart1_sleep: blsp2_uart1_sleep { - mux { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - function = "gpio"; + blsp2_uart1_rxcts_active: blsp2_uart1_rxcts_active { + mux { + pins = "gpio17", "gpio18"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - drive-strength = <2>; - bias-disable; + blsp2_uart1_rxcts_sleep: blsp2_uart1_rxcts_sleep { + mux { + pins = "gpio17", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp2_uart1_rfr_active: blsp2_uart1_rfr_active { + mux { + pins = "gpio19"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_rfr_sleep: blsp2_uart1_rfr_sleep { + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-no-pull; + }; }; }; diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 9bcc0ad84917..cab1821db191 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -104,6 +104,7 @@ str x20, [sp, #S_ORIG_ADDR_LIMIT] mov x20, #TASK_SIZE_64 str x20, [tsk, #TI_ADDR_LIMIT] + ALTERNATIVE(nop, SET_PSTATE_UAO(0), ARM64_HAS_UAO, CONFIG_ARM64_UAO) .endif /* \el == 0 */ mrs x22, elr_el1 mrs x23, spsr_el1 @@ -139,6 +140,8 @@ /* Restore the task's original addr_limit. */ ldr x20, [sp, #S_ORIG_ADDR_LIMIT] str x20, [tsk, #TI_ADDR_LIMIT] + + /* No need to restore UAO, it will be restored from SPSR_EL1 */ .endif ldp x21, x22, [sp, #S_PC] // load ELR, SPSR diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 68cd3bb8eb89..eacaee18645b 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -291,7 +291,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, } if (permission_fault(esr) && (addr < USER_DS)) { - if (get_fs() == KERNEL_DS) + /* regs->orig_addr_limit may be 0 if we entered from EL0 */ + if (regs->orig_addr_limit == KERNEL_DS) die("Accessing user space memory with fs=KERNEL_DS", regs, esr); if (!search_exception_tables(regs->pc)) diff --git a/drivers/clk/msm/clock-gcc-8998.c b/drivers/clk/msm/clock-gcc-8998.c index 87cf6cc5631e..8b7efbd093b5 100644 --- a/drivers/clk/msm/clock-gcc-8998.c +++ b/drivers/clk/msm/clock-gcc-8998.c @@ -263,6 +263,7 @@ static struct rcg_clk hmss_ahb_clk_src = { static struct clk_freq_tbl ftbl_usb30_master_clk_src[] = { F( 19200000, cxo_clk_src, 1, 0, 0), + F( 60000000, gpll0_out_main, 10, 0, 0), F( 120000000, gpll0_out_main, 5, 0, 0), F( 150000000, gpll0_out_main, 4, 0, 0), F_END diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index 0276952debbb..de21a231b73f 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -234,7 +234,7 @@ static int tz_init_ca(struct devfreq_msm_adreno_tz_data *priv) { unsigned int tz_ca_data[2]; struct scm_desc desc = {0}; - unsigned int *tz_buf; + u8 *tz_buf; int ret; /* Set data for TZ */ @@ -279,7 +279,7 @@ static int tz_init(struct devfreq_msm_adreno_tz_data *priv, scm_is_call_available(SCM_SVC_DCVS, TZ_UPDATE_ID_64) && scm_is_call_available(SCM_SVC_DCVS, TZ_RESET_ID_64)) { struct scm_desc desc = {0}; - unsigned int *tz_buf; + u8 *tz_buf; if (!is_scm_armv8()) { ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID_64, diff --git a/drivers/gpu/msm/adreno_cp_parser.c b/drivers/gpu/msm/adreno_cp_parser.c index 2ccb8139e6b8..d9645375c8a8 100644 --- a/drivers/gpu/msm/adreno_cp_parser.c +++ b/drivers/gpu/msm/adreno_cp_parser.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 @@ -53,7 +53,7 @@ static int load_state_unit_sizes[7][2] = { static int adreno_ib_find_objs(struct kgsl_device *device, struct kgsl_process_private *process, uint64_t gpuaddr, uint64_t dwords, - int obj_type, + uint64_t ib2base, int obj_type, struct adreno_ib_object_list *ib_obj_list, int ib_level); @@ -483,7 +483,7 @@ static int ib_parse_draw_indx(struct kgsl_device *device, unsigned int *pkt, ret = adreno_ib_find_objs(device, process, ib_parse_vars->set_draw_groups[i].cmd_stream_addr, ib_parse_vars->set_draw_groups[i].cmd_stream_dwords, - SNAPSHOT_GPU_OBJECT_DRAW, + 0, SNAPSHOT_GPU_OBJECT_DRAW, ib_obj_list, 2); if (ret) break; @@ -686,8 +686,8 @@ static int ib_parse_type7_set_draw_state(struct kgsl_device *device, if (cmd_stream_dwords) ret = adreno_ib_find_objs(device, process, cmd_stream_addr, cmd_stream_dwords, - SNAPSHOT_GPU_OBJECT_DRAW, ib_obj_list, - 2); + 0, SNAPSHOT_GPU_OBJECT_DRAW, + ib_obj_list, 2); if (ret) break; continue; @@ -698,7 +698,7 @@ static int ib_parse_type7_set_draw_state(struct kgsl_device *device, gpuaddr = gpuaddr << 32 | ptr[i + 1]; ret = adreno_ib_find_objs(device, process, gpuaddr, (ptr[i] & 0x0000FFFF), - SNAPSHOT_GPU_OBJECT_IB, + 0, SNAPSHOT_GPU_OBJECT_IB, ib_obj_list, 2); if (ret) break; @@ -760,7 +760,7 @@ static int ib_parse_set_draw_state(struct kgsl_device *device, if (flags & 0x8) { ret = adreno_ib_find_objs(device, process, ptr[i + 1], (ptr[i] & 0x0000FFFF), - SNAPSHOT_GPU_OBJECT_IB, + 0, SNAPSHOT_GPU_OBJECT_IB, ib_obj_list, 2); if (ret) break; @@ -775,6 +775,7 @@ static int ib_parse_set_draw_state(struct kgsl_device *device, * @process: Process in which the IB is allocated * @gpuaddr: IB2 gpuaddr * @dwords: IB2 size in dwords + * @ib2base: Base address of active IB2 * @ib_obj_list: List of objects found in IB * @ib_level: The level from which function is called, either from IB1 or IB2 * @@ -783,7 +784,7 @@ static int ib_parse_set_draw_state(struct kgsl_device *device, */ static int adreno_cp_parse_ib2(struct kgsl_device *device, struct kgsl_process_private *process, - uint64_t gpuaddr, uint64_t dwords, + uint64_t gpuaddr, uint64_t dwords, uint64_t ib2base, struct adreno_ib_object_list *ib_obj_list, int ib_level) { @@ -794,6 +795,10 @@ static int adreno_cp_parse_ib2(struct kgsl_device *device, */ if (2 == ib_level) return -EINVAL; + + /* Save current IB2 statically */ + if (ib2base == gpuaddr) + kgsl_snapshot_push_object(process, gpuaddr, dwords); /* * only try to find sub objects iff this IB has * not been processed already @@ -807,7 +812,7 @@ static int adreno_cp_parse_ib2(struct kgsl_device *device, return 0; } - return adreno_ib_find_objs(device, process, gpuaddr, dwords, + return adreno_ib_find_objs(device, process, gpuaddr, dwords, ib2base, SNAPSHOT_GPU_OBJECT_IB, ib_obj_list, 2); } @@ -816,6 +821,7 @@ static int adreno_cp_parse_ib2(struct kgsl_device *device, * @device: The device pointer on which the IB executes * @process: The process in which the IB and all contained objects are mapped. * @gpuaddr: The gpu address of the IB + * @ib2base: IB2 base address * @dwords: Size of ib in dwords * @obj_type: The object type can be either an IB or a draw state sequence * @ib_obj_list: The list in which the IB and the objects in it are added. @@ -828,7 +834,7 @@ static int adreno_cp_parse_ib2(struct kgsl_device *device, static int adreno_ib_find_objs(struct kgsl_device *device, struct kgsl_process_private *process, uint64_t gpuaddr, uint64_t dwords, - int obj_type, + uint64_t ib2base, int obj_type, struct adreno_ib_object_list *ib_obj_list, int ib_level) { @@ -904,7 +910,7 @@ static int adreno_ib_find_objs(struct kgsl_device *device, uint64_t size = src[i + 2]; ret = adreno_cp_parse_ib2(device, process, - gpuaddrib2, size, + gpuaddrib2, size, ib2base, ib_obj_list, ib_level); if (ret) goto done; @@ -930,7 +936,7 @@ static int adreno_ib_find_objs(struct kgsl_device *device, gpuaddrib2 = gpuaddrib2 << 32 | src[i + 1]; ret = adreno_cp_parse_ib2(device, process, - gpuaddrib2, size, + gpuaddrib2, size, ib2base, ib_obj_list, ib_level); if (ret) goto done; @@ -982,6 +988,7 @@ done: * @process: The process in which the IB and all contained objects are mapped * @gpuaddr: The gpu address of the IB * @dwords: Size of ib in dwords + * @ib2base: Base address of active IB2 * @ib_obj_list: The list in which the IB and the objects in it are added. * * Find all the memory objects that an IB needs for execution and place @@ -993,7 +1000,7 @@ done: */ int adreno_ib_create_object_list(struct kgsl_device *device, struct kgsl_process_private *process, - uint64_t gpuaddr, uint64_t dwords, + uint64_t gpuaddr, uint64_t dwords, uint64_t ib2base, struct adreno_ib_object_list **out_ib_obj_list) { int ret = 0; @@ -1016,7 +1023,7 @@ int adreno_ib_create_object_list(struct kgsl_device *device, return -ENOMEM; } - ret = adreno_ib_find_objs(device, process, gpuaddr, dwords, + ret = adreno_ib_find_objs(device, process, gpuaddr, dwords, ib2base, SNAPSHOT_GPU_OBJECT_IB, ib_obj_list, 1); /* Even if there was an error return the remaining objects found */ diff --git a/drivers/gpu/msm/adreno_cp_parser.h b/drivers/gpu/msm/adreno_cp_parser.h index 0248de2d600a..f4d6cd99226e 100644 --- a/drivers/gpu/msm/adreno_cp_parser.h +++ b/drivers/gpu/msm/adreno_cp_parser.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -178,7 +178,7 @@ static inline int adreno_cp_parser_regindex(struct adreno_device *adreno_dev, int adreno_ib_create_object_list( struct kgsl_device *device, struct kgsl_process_private *process, - uint64_t gpuaddr, uint64_t dwords, + uint64_t gpuaddr, uint64_t dwords, uint64_t ib2base, struct adreno_ib_object_list **out_ib_obj_list); void adreno_ib_destroy_obj_list(struct adreno_ib_object_list *ib_obj_list); diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c index f5f99c3ebb4a..5fecdcfb6364 100644 --- a/drivers/gpu/msm/adreno_perfcounter.c +++ b/drivers/gpu/msm/adreno_perfcounter.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-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 @@ -638,6 +638,9 @@ static void _perfcounter_enable_vbif_pwr(struct adreno_device *adreno_dev, static void _power_counter_enable_alwayson(struct adreno_device *adreno_dev, struct adreno_perfcounters *counters) { + if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU)) + return; + kgsl_regwrite(KGSL_DEVICE(adreno_dev), A5XX_GPMU_ALWAYS_ON_COUNTER_RESET, 1); counters->groups[KGSL_PERFCOUNTER_GROUP_ALWAYSON_PWR].regs[0].value = 0; @@ -674,6 +677,9 @@ static void _power_counter_enable_default(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_perfcount_register *reg; + if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU)) + return; + reg = &counters->groups[group].regs[counter]; kgsl_regwrite(device, reg->select, countable); kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1); @@ -927,6 +933,9 @@ static uint64_t _perfcounter_read_pwrcntr(struct adreno_device *adreno_dev, struct adreno_perfcount_register *reg; unsigned int lo = 0, hi = 0; + if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU)) + return 0; + reg = &group->regs[counter]; kgsl_regread(device, reg->offset, &lo); diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index 08d7d3c1b935..711d7ba83e61 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,8 +27,6 @@ #define SNAPSHOT_OBJ_BUFSIZE 64 -#define SNAPSHOT_OBJ_TYPE_IB 0 - /* Used to print error message if an IB has too many objects in it */ static int ib_max_objs; @@ -53,8 +51,7 @@ static inline int adreno_rb_ctxtswitch(struct adreno_device *adreno_dev, } /* Push a new buffer object onto the list */ -static void push_object(int type, - struct kgsl_process_private *process, +void kgsl_snapshot_push_object(struct kgsl_process_private *process, uint64_t gpuaddr, uint64_t dwords) { int index; @@ -101,7 +98,6 @@ static void push_object(int type, } /* Put it on the list of things to parse */ - objbuf[objbufptr].type = type; objbuf[objbufptr].gpuaddr = gpuaddr; objbuf[objbufptr].size = dwords << 2; objbuf[objbufptr++].entry = entry; @@ -112,8 +108,7 @@ static void push_object(int type, * to be dumped */ -static int find_object(int type, uint64_t gpuaddr, - struct kgsl_process_private *process) +static int find_object(uint64_t gpuaddr, struct kgsl_process_private *process) { int index; @@ -131,14 +126,12 @@ static int find_object(int type, uint64_t gpuaddr, * @snapshot: The snapshot data. * @process: The process to which the IB belongs * @ib_obj_list: List of the IB objects - * @ib2base: IB2 base address at time of the fault * * Returns 0 on success else error code */ static int snapshot_freeze_obj_list(struct kgsl_snapshot *snapshot, struct kgsl_process_private *process, - struct adreno_ib_object_list *ib_obj_list, - uint64_t ib2base) + struct adreno_ib_object_list *ib_obj_list) { int ret = 0; struct adreno_ib_object *ib_objs; @@ -163,21 +156,15 @@ static int snapshot_freeze_obj_list(struct kgsl_snapshot *snapshot, } if (freeze) { - /* Save current IB2 statically */ - if (ib2base == ib_objs->gpuaddr) { - push_object(SNAPSHOT_OBJ_TYPE_IB, - process, ib_objs->gpuaddr, ib_objs->size >> 2); + temp_ret = kgsl_snapshot_get_object(snapshot, + process, ib_objs->gpuaddr, + ib_objs->size, + ib_objs->snapshot_obj_type); + if (temp_ret < 0) { + if (ret >= 0) + ret = temp_ret; } else { - temp_ret = kgsl_snapshot_get_object(snapshot, - process, ib_objs->gpuaddr, - ib_objs->size, - ib_objs->snapshot_obj_type); - if (temp_ret < 0) { - if (ret >= 0) - ret = temp_ret; - } else { - snapshot_frozen_objsize += temp_ret; - } + snapshot_frozen_objsize += temp_ret; } } } @@ -203,8 +190,7 @@ static inline void parse_ib(struct kgsl_device *device, * list */ if (gpuaddr == snapshot->ib1base) { - push_object(SNAPSHOT_OBJ_TYPE_IB, process, - gpuaddr, dwords); + kgsl_snapshot_push_object(process, gpuaddr, dwords); return; } @@ -213,7 +199,8 @@ static inline void parse_ib(struct kgsl_device *device, return; if (-E2BIG == adreno_ib_create_object_list(device, process, - gpuaddr, dwords, &ib_obj_list)) + gpuaddr, dwords, snapshot->ib2base, + &ib_obj_list)) ib_max_objs = 1; if (ib_obj_list) @@ -559,8 +546,7 @@ void kgsl_snapshot_add_active_ib_obj_list(struct kgsl_device *device, int index = -ENOENT; if (!snapshot->ib1dumped) - index = find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib1base, - snapshot->process); + index = find_object(snapshot->ib1base, snapshot->process); /* only do this for IB1 because the IB2's are part of IB1 objects */ if ((index != -ENOENT) && @@ -569,19 +555,19 @@ void kgsl_snapshot_add_active_ib_obj_list(struct kgsl_device *device, objbuf[index].entry->priv, objbuf[index].gpuaddr, objbuf[index].size >> 2, + snapshot->ib2base, &ib_obj_list)) ib_max_objs = 1; if (ib_obj_list) { /* freeze the IB objects in the IB */ snapshot_freeze_obj_list(snapshot, objbuf[index].entry->priv, - ib_obj_list, snapshot->ib2base); + ib_obj_list); adreno_ib_destroy_obj_list(ib_obj_list); } } else { /* Get the IB2 index from parsed object */ - index = find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib2base, - snapshot->process); + index = find_object(snapshot->ib2base, snapshot->process); if (index != -ENOENT) parse_ib(device, snapshot, snapshot->process, @@ -624,6 +610,7 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf, struct adreno_ib_object_list *ib_obj_list; struct kgsl_snapshot *snapshot; struct kgsl_snapshot_object *obj; + struct kgsl_memdesc *memdesc; if (meta == NULL || meta->snapshot == NULL || meta->obj == NULL) { KGSL_CORE_ERR("snapshot: bad metadata"); @@ -631,13 +618,18 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf, } snapshot = meta->snapshot; obj = meta->obj; + memdesc = &obj->entry->memdesc; + + /* If size is zero get it from the medesc size */ + if (!obj->size) + obj->size = (memdesc->size - (obj->gpuaddr - memdesc->gpuaddr)); if (remain < (obj->size + sizeof(*header))) { KGSL_CORE_ERR("snapshot: Not enough memory for the ib\n"); return 0; } - src = kgsl_gpuaddr_to_vaddr(&obj->entry->memdesc, obj->gpuaddr); + src = kgsl_gpuaddr_to_vaddr(memdesc, obj->gpuaddr); if (src == NULL) { KGSL_DRV_ERR(device, "snapshot: Unable to map GPU memory object 0x%016llX into the kernel\n", @@ -653,13 +645,14 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf, if (-E2BIG == adreno_ib_create_object_list(device, obj->entry->priv, obj->gpuaddr, obj->size >> 2, + snapshot->ib2base, &ib_obj_list)) ib_max_objs = 1; if (ib_obj_list) { /* freeze the IB objects in the IB */ snapshot_freeze_obj_list(snapshot, obj->entry->priv, - ib_obj_list, meta->ib2base); + ib_obj_list); adreno_ib_destroy_obj_list(ib_obj_list); } } @@ -688,26 +681,18 @@ static void dump_object(struct kgsl_device *device, int obj, { struct snapshot_ib_meta meta; - switch (objbuf[obj].type) { - case SNAPSHOT_OBJ_TYPE_IB: - meta.snapshot = snapshot; - meta.obj = &objbuf[obj]; - meta.ib1base = snapshot->ib1base; - meta.ib1size = snapshot->ib1size; - meta.ib2base = snapshot->ib2base; - meta.ib2size = snapshot->ib2size; + meta.snapshot = snapshot; + meta.obj = &objbuf[obj]; + meta.ib1base = snapshot->ib1base; + meta.ib1size = snapshot->ib1size; + meta.ib2base = snapshot->ib2base; + meta.ib2size = snapshot->ib2size; - kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB_V2, + kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB_V2, snapshot, snapshot_ib, &meta); - if (objbuf[obj].entry) { - kgsl_memdesc_unmap(&(objbuf[obj].entry->memdesc)); - kgsl_mem_entry_put(objbuf[obj].entry); - } - break; - default: - KGSL_CORE_ERR("snapshot: Invalid snapshot object type: %d\n", - objbuf[obj].type); - break; + if (objbuf[obj].entry) { + kgsl_memdesc_unmap(&(objbuf[obj].entry->memdesc)); + kgsl_mem_entry_put(objbuf[obj].entry); } } @@ -909,10 +894,10 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot, * figure how often this really happens. */ - if (-ENOENT == find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib1base, - snapshot->process) && snapshot->ib1size) { - push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process, - snapshot->ib1base, snapshot->ib1size); + if (-ENOENT == find_object(snapshot->ib1base, snapshot->process) && + snapshot->ib1size) { + kgsl_snapshot_push_object(snapshot->process, snapshot->ib1base, + snapshot->ib1size); KGSL_CORE_ERR( "CP_IB1_BASE not found in the ringbuffer.Dumping %x dwords of the buffer.\n", snapshot->ib1size); @@ -926,10 +911,9 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot, * correct size. */ - if (-ENOENT == find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib2base, - snapshot->process)) { - push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process, - snapshot->ib2base, snapshot->ib2size); + if (-ENOENT == find_object(snapshot->ib2base, snapshot->process)) { + kgsl_snapshot_push_object(snapshot->process, snapshot->ib2base, + snapshot->ib2size); } /* diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h index e2ded87b7431..2cb8b8fdf890 100644 --- a/drivers/gpu/msm/kgsl_snapshot.h +++ b/drivers/gpu/msm/kgsl_snapshot.h @@ -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 @@ -255,4 +255,6 @@ struct kgsl_snapshot_gpu_object_v2 { __u64 size; /* Size of the object (in dwords) */ } __packed; +void kgsl_snapshot_push_object(struct kgsl_process_private *process, + uint64_t gpuaddr, uint64_t dwords); #endif diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c index 782b0eaa3648..78d3dd9d752a 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c @@ -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 @@ -298,7 +298,7 @@ static unsigned long __calculate_vmem_plus_ab(struct vidc_bus_vote_data *d) vmem_plus = 1; dprintk(VIDC_WARN, "could not calculate vmem ab value due to core freq mismatch\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); } exit: diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index babea6824c51..b36e3739e43b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.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 @@ -1313,7 +1313,11 @@ static void cleanup_instance(struct msm_vidc_inst *inst) debugfs_remove_recursive(inst->debugfs_root); mutex_lock(&inst->pending_getpropq.lock); - WARN_ON(!list_empty(&inst->pending_getpropq.list)); + if (!list_empty(&inst->pending_getpropq.list)) { + dprintk(VIDC_ERR, + "pending_getpropq not empty\n"); + WARN_ON(VIDC_DBG_WARN_ENABLE); + } mutex_unlock(&inst->pending_getpropq.lock); } } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h index 11d8621564a6..39ac6273f34e 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,6 +23,7 @@ #endif #define VIDC_DBG_TAG VIDC_DBG_LABEL ": %4s: " +#define VIDC_DBG_WARN_ENABLE (msm_vidc_debug & VIDC_INFO) /* To enable messages OR these values and * echo the result to debugfs file. diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 30d1bae48e7d..777fb52b2201 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.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 @@ -105,7 +105,11 @@ static int __tzbsp_set_video_state(enum tzbsp_video_state state); */ static inline void __strict_check(struct venus_hfi_device *device) { - WARN_ON(!mutex_is_locked(&device->lock)); + if (!mutex_is_locked(&device->lock)) { + dprintk(VIDC_WARN, + "device->lock mutex is not locked\n"); + WARN_ON(VIDC_DBG_WARN_ENABLE); + } } static inline void __set_state(struct venus_hfi_device *device, @@ -267,7 +271,7 @@ static int __acquire_regulator(struct regulator_info *rinfo) if (!regulator_is_enabled(rinfo->regulator)) { dprintk(VIDC_WARN, "Regulator is not enabled %s\n", rinfo->name); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); } return rc; @@ -617,7 +621,7 @@ static void __write_register(struct venus_hfi_device *device, if (!device->power_enabled) { dprintk(VIDC_WARN, "HFI Write register failed : Power is OFF\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return; } @@ -643,7 +647,7 @@ static int __read_register(struct venus_hfi_device *device, u32 reg) if (!device->power_enabled) { dprintk(VIDC_WARN, "HFI Read register failed : Power is OFF\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return -EINVAL; } @@ -1360,7 +1364,7 @@ static int __halt_axi(struct venus_hfi_device *device) if (!device->power_enabled) { dprintk(VIDC_WARN, "Clocks are OFF, skipping AXI HALT\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return -EINVAL; } @@ -3530,7 +3534,11 @@ static int __response_handler(struct venus_hfi_device *device) if (session_id) { struct hal_session *session = NULL; - WARN_ON(upper_32_bits((uintptr_t)*session_id) != 0); + if (upper_32_bits((uintptr_t)*session_id) != 0) { + dprintk(VIDC_WARN, + "Upper 32 bits of session_id != 0\n"); + WARN_ON(VIDC_DBG_WARN_ENABLE); + } session = __get_session(device, (u32)(uintptr_t)*session_id); if (!session) { @@ -4088,7 +4096,7 @@ static int __disable_regulator(struct regulator_info *rinfo) disable_regulator_failed: /* Bring attention to this issue */ - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return rc; } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 46daa96a68a3..3c6dba648574 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -46,11 +46,20 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask #define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb +#ifndef CONFIG_ATH10K_SNOC struct ce_desc { __le32 addr; __le16 nbytes; __le16 flags; /* %CE_DESC_FLAGS_ */ }; +#else +struct ce_desc { + __le64 addr; + u16 nbytes; /* length in register map */ + u16 flags; /* fw_metadata_high */ + u32 toeplitz_hash_result; +}; +#endif struct ath10k_ce_ring { /* Number of entries in this ring; must be power of 2 */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 21ae8d663e67..bf77ac66c79e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1560,10 +1560,22 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); } +/* WAR: WCN3990 fw loading is done by PIL, assign WMI/HTT version */ +static inline void init_fw_param(struct ath10k *ar, + struct ath10k_fw_file *fw_file) +{ + if (QCA_REV_WCN3990(ar)) { + fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_HL_1_0; + fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV; + } +} + static int ath10k_core_init_firmware_features(struct ath10k *ar) { struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file; + init_fw_param(ar, &ar->normal_mode_fw.fw_file); + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) && !test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) { ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); @@ -1666,6 +1678,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_TLV: + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: ar->max_num_peers = TARGET_TLV_NUM_PEERS; ar->max_num_stations = TARGET_TLV_NUM_STATIONS; ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; @@ -1712,6 +1725,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1; break; case ATH10K_FW_WMI_OP_VERSION_TLV: + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV; break; case ATH10K_FW_WMI_OP_VERSION_10_4: diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 175aae38c375..c01f59955797 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -451,8 +451,16 @@ static const char *htc_service_name(enum ath10k_htc_svc_id id) return "NMI Data"; case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: return "HTT Data"; + case ATH10K_HTC_SVC_ID_HTT_DATA2_MSG: + return "HTT Data"; + case ATH10K_HTC_SVC_ID_HTT_DATA3_MSG: + return "HTT Data"; + case ATH10K_HTC_SVC_ID_HTT_IPA_MSG: + return "IPA"; case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS: return "RAW"; + case ATH10K_HTC_SVC_ID_HTT_LOG_MSG: + return "PKTLOG"; } return "Unknown"; diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 0c55cd92a951..5f28099b2c88 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -222,7 +222,8 @@ enum ath10k_htc_svc_gid { ATH10K_HTC_SVC_GRP_WMI = 1, ATH10K_HTC_SVC_GRP_NMI = 2, ATH10K_HTC_SVC_GRP_HTT = 3, - + ATH10K_IPA_SERVICE_GROUP = 5, + ATH10K_LOG_SERVICE_GROUP = 6, ATH10K_HTC_SVC_GRP_TEST = 254, ATH10K_HTC_SVC_GRP_LAST = 255, }; @@ -246,7 +247,10 @@ enum ath10k_htc_svc_id { ATH10K_HTC_SVC_ID_NMI_DATA = SVC(ATH10K_HTC_SVC_GRP_NMI, 1), ATH10K_HTC_SVC_ID_HTT_DATA_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 0), - + ATH10K_HTC_SVC_ID_HTT_DATA2_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 1), + ATH10K_HTC_SVC_ID_HTT_DATA3_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 2), + ATH10K_HTC_SVC_ID_HTT_IPA_MSG = SVC(ATH10K_IPA_SERVICE_GROUP, 0), + ATH10K_HTC_SVC_ID_HTT_LOG_MSG = SVC(ATH10K_LOG_SERVICE_GROUP, 0), /* raw stream service (i.e. flash, tcmd, calibration apps) */ ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS = SVC(ATH10K_HTC_SVC_GRP_TEST, 0), }; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 09bdd4bbc3be..78df1d1ad67c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -27,6 +27,7 @@ #define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX #define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1) +#define HTT_RX_RING_FILL_LEVEL_DUAL_MAC (HTT_RX_RING_SIZE - 1) /* when under memory pressure rx ring refill may fail and needs a retry */ #define HTT_RX_RING_REFILL_RETRY_MS 50 @@ -474,7 +475,15 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) */ htt->rx_ring.size = HTT_RX_RING_SIZE; htt->rx_ring.size_mask = htt->rx_ring.size - 1; - htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL; + + switch (ar->hw_rev) { + case ATH10K_HW_WCN3990: + htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC; + break; + default: + htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL; + break; + } if (!is_power_of_2(htt->rx_ring.size)) { ath10k_warn(ar, "htt rx ring size is not power of 2\n"); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index d1c68992ead6..b7d9c23e17fa 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -184,6 +184,7 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_TLV = 4, ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, ATH10K_FW_WMI_OP_VERSION_10_4 = 6, + ATH10K_FW_WMI_OP_VERSION_HL_1_0 = 7, /* keep last */ ATH10K_FW_WMI_OP_VERSION_MAX, @@ -525,6 +526,11 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +/* Target specific defines for WMI-HL-1.0 firmware */ +#define TARGET_HL_10_TLV_NUM_PEERS 14 +#define TARGET_HL_10_TLV_AST_SKID_LIMIT 6 +#define TARGET_HL_10_TLV_NUM_WDS_ENTRIES 2 + /* Diagnostic Window */ #define CE_DIAG_PIPE 7 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a6bad3e3de56..7a5bfeea8f3d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3899,16 +3899,12 @@ void __ath10k_scan_finish(struct ath10k *ar) break; case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: - if (!ar->scan.is_roc) { - struct cfg80211_scan_info info = { - .aborted = (ar->scan.state == - ATH10K_SCAN_ABORTING), - }; - - ieee80211_scan_completed(ar->hw, &info); - } else if (ar->scan.roc_notify) { + if (!ar->scan.is_roc) + ieee80211_scan_completed(ar->hw, + (ar->scan.state == + ATH10K_SCAN_ABORTING)); + else if (ar->scan.roc_notify) ieee80211_remain_on_channel_expired(ar->hw); - } /* fall through */ case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; @@ -7959,6 +7955,7 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); break; case ATH10K_FW_WMI_OP_VERSION_TLV: + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) { ar->hw->wiphy->iface_combinations = ath10k_tlv_qcs_if_comb; diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 034e7a54c5b2..6260f11d4e32 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -205,12 +205,25 @@ struct rx_attention { * descriptor. */ +#ifndef CONFIG_ATH10K_SNOC struct rx_frag_info { u8 ring0_more_count; u8 ring1_more_count; u8 ring2_more_count; u8 ring3_more_count; } __packed; +#else +struct rx_frag_info { + u8 ring0_more_count; + u8 ring1_more_count; + u8 ring2_more_count; + u8 ring3_more_count; + u8 ring4_more_count; + u8 ring5_more_count; + u8 ring6_more_count; + u8 ring7_more_count; +} __packed; +#endif /* * ring0_more_count @@ -465,11 +478,23 @@ struct rx_msdu_start_qca99x0 { __le32 info2; /* %RX_MSDU_START_INFO2_ */ } __packed; +#ifdef CONFIG_ATH10K_SNOC +struct rx_msdu_start_wcn3990 { + __le32 info3; +} __packed; +#else +struct rx_msdu_start_wcn3990 { +} __packed; +#endif + struct rx_msdu_start { struct rx_msdu_start_common common; union { struct rx_msdu_start_qca99x0 qca99x0; } __packed; + union { + struct rx_msdu_start_wcn3990 wcn3990; + } __packed; } __packed; /* @@ -589,10 +614,18 @@ struct rx_msdu_end_qca99x0 { __le32 info2; } __packed; +struct rx_msdu_end_wcn3990 { + __le32 rule_indication_0; + __le32 rule_indication_1; + __le32 rule_indication_2; + __le32 rule_indication_3; +} __packed; + struct rx_msdu_end { struct rx_msdu_end_common common; union { struct rx_msdu_end_qca99x0 qca99x0; + struct rx_msdu_end_wcn3990 wcn3990; } __packed; } __packed; @@ -953,8 +986,13 @@ struct rx_ppdu_end_qca6174 { struct rx_pkt_end { __le32 info0; /* %RX_PKT_END_INFO0_ */ +#ifndef CONFIG_ATH10K_SNOC __le32 phy_timestamp_1; __le32 phy_timestamp_2; +#else + __le64 phy_timestamp_1; + __le64 phy_timestamp_2; +#endif } __packed; #define RX_LOCATION_INFO0_RTT_FAC_LEGACY_MASK 0x00003fff @@ -990,6 +1028,9 @@ struct rx_pkt_end { struct rx_location_info { __le32 rx_location_info0; /* %RX_LOCATION_INFO0_ */ __le32 rx_location_info1; /* %RX_LOCATION_INFO1_ */ +#ifdef CONFIG_ATH10K_SNOC + __le32 rx_location_info2; /* %RX_LOCATION_INFO2_ */ +#endif } __packed; enum rx_phy_ppdu_end_info0 { @@ -1080,6 +1121,25 @@ struct rx_ppdu_end_qca9984 { __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; +struct rx_timing_offset { + __le32 timing_offset; + __le32 reserved; +}; + +struct rx_ppdu_end_wcn3990 { + __le32 reserved_info_0; + __le32 reserved_info_1; + __le32 rx_antenna_info; + __le32 rx_coex_info; + __le32 rx_mpdu_cnt_info; + __le32 rx_bb_length; + __le64 phy_timestamp_tx; + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + struct rx_timing_offset rx_timing_offset; + struct rx_location_info rx_location_info; +} __packed; + struct rx_ppdu_end { struct rx_ppdu_end_common common; union { @@ -1087,6 +1147,7 @@ struct rx_ppdu_end { struct rx_ppdu_end_qca6174 qca6174; struct rx_ppdu_end_qca99x0 qca99x0; struct rx_ppdu_end_qca9984 qca9984; + struct rx_ppdu_end_wcn3990 wcn3990; } __packed; } __packed; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c new file mode 100644 index 000000000000..44d9e6c053a6 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -0,0 +1,704 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include "debug.h" +#include "hif.h" +#include "htc.h" +#include "ce.h" +#include "snoc.h" +#include <soc/qcom/icnss.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); + +static struct ce_attr host_ce_config_wlan[] = { + /* CE0: host->target HTC control streams */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 16, + .src_sz_max = 2048, + .dest_nentries = 0, + .send_cb = ath10k_snoc_htc_tx_cb, + }, + + /* CE1: target->host HTT + HTC control */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, + }, + + /* CE2: target->host WMI */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 64, + .recv_cb = ath10k_snoc_htc_rx_cb, + }, + + /* CE3: host->target WMI */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, + .send_cb = ath10k_snoc_htc_tx_cb, + }, + + /* CE4: host->target HTT */ + { + .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .src_nentries = 256, + .src_sz_max = 256, + .dest_nentries = 0, + .send_cb = ath10k_snoc_htt_tx_cb, + }, + + /* CE5: target->host HTT (ipa_uc->target ) */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 512, + .dest_nentries = 512, + .recv_cb = ath10k_snoc_htt_rx_cb, + }, + + /* CE6: target autonomous hif_memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE7: ce_diag, the Diagnostic Window */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 2, + .src_sz_max = 2048, + .dest_nentries = 2, + }, + + /* CE8: Target to uMC */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 128, + }, + + /* CE9 target->host HTT */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, + }, + + /* CE10: target->host HTT */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, + }, + + /* CE11: target -> host PKTLOG */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, + }, +}; + +static struct ce_pipe_config target_ce_config_wlan[] = { + /* CE0: host->target HTC control and raw streams */ + { + .pipenum = __cpu_to_le32(0), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE1: target->host HTT + HTC control */ + { + .pipenum = __cpu_to_le32(1), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE2: target->host WMI */ + { + .pipenum = __cpu_to_le32(2), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(64), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE3: host->target WMI */ + { + .pipenum = __cpu_to_le32(3), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE4: host->target HTT */ + { + .pipenum = __cpu_to_le32(4), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(256), + .nbytes_max = __cpu_to_le32(256), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE5: target->host HTT (HIF->HTT) */ + { + .pipenum = __cpu_to_le32(5), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(1024), + .nbytes_max = __cpu_to_le32(64), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE6: Reserved for target autonomous hif_memcpy */ + { + .pipenum = __cpu_to_le32(6), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(16384), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE7 used only by Host */ + { + .pipenum = __cpu_to_le32(7), + .pipedir = __cpu_to_le32(4), + .nentries = __cpu_to_le32(0), + .nbytes_max = __cpu_to_le32(0), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE8 Target to uMC */ + { + .pipenum = __cpu_to_le32(8), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(0), + .reserved = __cpu_to_le32(0), + }, + + /* CE9 target->host HTT */ + { + .pipenum = __cpu_to_le32(9), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE10 target->host HTT */ + { + .pipenum = __cpu_to_le32(10), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE11 target autonomous qcache memcpy */ + { + .pipenum = __cpu_to_le32(11), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, +}; + +static struct service_to_pipe target_service_to_ce_map_wlan[] = { + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(4), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(1), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_IPA_MSG), + __cpu_to_le32(PIPEDIR_OUT),/* IPA service */ + __cpu_to_le32(5), + }, + { /* in = DL = target -> host */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA2_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(9), + }, + { /* in = DL = target -> host */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA3_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(10), + }, + { /* in = DL = target -> host pktlog */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_LOG_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(11), + }, + /* (Additions here) */ + + { /* must be last */ + __cpu_to_le32(0), + __cpu_to_le32(0), + __cpu_to_le32(0), + }, +}; + +void ath10k_snoc_write32(void *ar, u32 offset, u32 value) +{ +} + +u32 ath10k_snoc_read32(void *ar, u32 offset) +{ + u32 val = 0; + return val; +} + +static int __ath10k_snoc_rx_post_buf(struct ath10k_snoc_pipe *pipe) +{ + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + struct sk_buff *skb; + dma_addr_t paddr; + int ret; + + skb = dev_alloc_skb(pipe->buf_sz); + if (!skb) + return -ENOMEM; + + WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); + + paddr = dma_map_single(ar->dev, skb->data, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ar->dev, paddr))) { + ath10k_warn(ar, "failed to dma map snoc rx buf\n"); + dev_kfree_skb_any(skb); + return -EIO; + } + + ATH10K_SKB_RXCB(skb)->paddr = paddr; + + spin_lock_bh(&ar_snoc->ce_lock); + ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); + spin_unlock_bh(&ar_snoc->ce_lock); + if (ret) { + dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + +static void ath10k_snoc_rx_post_pipe(struct ath10k_snoc_pipe *pipe) +{ + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + int ret, num; + + if (pipe->buf_sz == 0) + return; + + if (!ce_pipe->dest_ring) + return; + + spin_lock_bh(&ar_snoc->ce_lock); + num = __ath10k_ce_rx_num_free_bufs(ce_pipe); + spin_unlock_bh(&ar_snoc->ce_lock); + while (num--) { + ret = __ath10k_snoc_rx_post_buf(pipe); + if (ret) { + if (ret == -ENOSPC) + break; + ath10k_warn(ar, "failed to post rx buf: %d\n", ret); + mod_timer(&ar_snoc->rx_post_retry, jiffies + + ATH10K_SNOC_RX_POST_RETRY_MS); + break; + } + } +} + +static void ath10k_snoc_rx_post(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int i; + + for (i = 0; i < CE_COUNT; i++) + ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); +} + +static void ath10k_snoc_rx_replenish_retry(unsigned long ptr) +{ + struct ath10k *ar = (void *)ptr; + + ath10k_snoc_rx_post(ar); +} + +static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state) +{ + struct ath10k *ar = ce_state->ar; + struct sk_buff_head list; + struct sk_buff *skb; + + __skb_queue_head_init(&list); + while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { + if (!skb) + continue; + + __skb_queue_tail(&list, skb); + } + + while ((skb = __skb_dequeue(&list))) + ath10k_htc_tx_completion_handler(ar, skb); +} + +static void ath10k_snoc_process_rx_cb(struct ath10k_ce_pipe *ce_state, + void (*callback)(struct ath10k *ar, + struct sk_buff *skb)) +{ + struct ath10k *ar = ce_state->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_pipe *pipe_info = &ar_snoc->pipe_info[ce_state->id]; + struct sk_buff *skb; + struct sk_buff_head list; + void *transfer_context; + unsigned int nbytes, max_nbytes; + + __skb_queue_head_init(&list); + while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, + &nbytes) == 0) { + skb = transfer_context; + max_nbytes = skb->len + skb_tailroom(skb); + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, + max_nbytes, DMA_FROM_DEVICE); + + if (unlikely(max_nbytes < nbytes)) { + ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; + } + + skb_put(skb, nbytes); + __skb_queue_tail(&list, skb); + } + + while ((skb = __skb_dequeue(&list))) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc rx ce pipe %d len %d\n", + ce_state->id, skb->len); + + callback(ar, skb); + } + + ath10k_snoc_rx_post_pipe(pipe_info); +} + +static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + +static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + /* CE4 polling needs to be done whenever CE pipe which transports + * HTT Rx (target->host) is processed. + */ + ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE); + + ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + +static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state) +{ + struct ath10k *ar = ce_state->ar; + struct sk_buff *skb; + + while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { + /* no need to call tx completion for NULL pointers */ + if (!skb) + continue; + + dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + skb->len, DMA_TO_DEVICE); + ath10k_htt_hif_tx_complete(ar, skb); + } +} + +static void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb) +{ + skb_pull(skb, sizeof(struct ath10k_htc_hdr)); + ath10k_htt_t2h_msg_handler(ar, skb); +} + +static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + /* CE4 polling needs to be done whenever CE pipe which transports + * HTT Rx (target->host) is processed. + */ + ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE); + + ath10k_snoc_process_rx_cb(ce_state, ath10k_snoc_htt_rx_deliver); +} + +static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) +{ + return 0; +} + +static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) +{ + return 0; +} + +static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe, + int force) +{ +} + +static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, + u16 service_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + return 0; +} + +static void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ +} + +static void ath10k_snoc_hif_stop(struct ath10k *ar) +{ +} + +static void ath10k_snoc_hif_power_down(struct ath10k *ar) +{ +} + +static int ath10k_snoc_hif_start(struct ath10k *ar) +{ + return 0; +} + +static int ath10k_snoc_hif_power_up(struct ath10k *ar) +{ + return 0; +} + +static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { + .tx_sg = ath10k_snoc_hif_tx_sg, + .start = ath10k_snoc_hif_start, + .stop = ath10k_snoc_hif_stop, + .map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe, + .get_default_pipe = ath10k_snoc_hif_get_default_pipe, + .send_complete_check = ath10k_snoc_hif_send_complete_check, + .get_free_queue_number = ath10k_snoc_hif_get_free_queue_number, + .power_up = ath10k_snoc_hif_power_up, + .power_down = ath10k_snoc_hif_power_down, + .read32 = ath10k_snoc_read32, + .write32 = ath10k_snoc_write32, +}; + +static int ath10k_snoc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct ath10k *ar; + struct ath10k_snoc *ar_snoc; + enum ath10k_hw_rev hw_rev; + struct device *dev; + + dev = &pdev->dev; + hw_rev = ATH10K_HW_WCN3990; + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(37)); + ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC, + hw_rev, &ath10k_snoc_hif_ops); + if (!ar) { + dev_err(dev, "failed to allocate core\n"); + return -ENOMEM; + } + ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 probed\n", __func__); + + return ret; +} + +static int ath10k_snoc_remove(struct platform_device *pdev) +{ + struct ath10k *ar = platform_get_drvdata(pdev); + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + if (!ar) + return -EINVAL; + + if (!ar_snoc) + return -EINVAL; + + ath10k_core_destroy(ar); + ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__); + + return 0; +} + +static const struct of_device_id ath10k_snoc_dt_match[] = { + {.compatible = "qcom,wcn3990-wifi"}, + {} +}; +MODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match); + +static struct platform_driver ath10k_snoc_driver = { + .probe = ath10k_snoc_probe, + .remove = ath10k_snoc_remove, + .driver = { + .name = "ath10k_snoc", + .owner = THIS_MODULE, + .of_match_table = ath10k_snoc_dt_match, + }, +}; + +static int __init ath10k_snoc_init(void) +{ + int ret; + + ret = platform_driver_register(&ath10k_snoc_driver); + if (ret) + pr_err("failed to register ath10k snoc driver: %d\n", + ret); + + return ret; +} +module_init(ath10k_snoc_init); + +static void __exit ath10k_snoc_exit(void) +{ + platform_driver_unregister(&ath10k_snoc_driver); +} +module_exit(ath10k_snoc_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices"); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h new file mode 100644 index 000000000000..1db8b532f4fa --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -0,0 +1,204 @@ +/* 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 _SNOC_H_ +#define _SNOC_H_ + +#include "hw.h" +#include "ce.h" +#include "pci.h" +#define ATH10K_SNOC_RX_POST_RETRY_MS 50 +#define CE_POLL_PIPE 4 + +/* struct snoc_state: SNOC target state + * @pipe_cfg_addr: pipe configuration address + * @svc_to_pipe_map: pipe services + */ +struct snoc_state { + u32 pipe_cfg_addr; + u32 svc_to_pipe_map; +}; + +/* struct ath10k_snoc_pipe: SNOC pipe configuration + * @ath10k_ce_pipe: pipe handle + * @pipe_num: pipe number + * @hif_ce_state: pointer to ce state + * @buf_sz: buffer size + * @pipe_lock: pipe lock + * @ar_snoc: snoc private structure + * @intr: tasklet structure + */ + +struct ath10k_snoc_pipe { + struct ath10k_ce_pipe *ce_hdl; + u8 pipe_num; + struct ath10k *hif_ce_state; + size_t buf_sz; + /* protect ce info */ + spinlock_t pipe_lock; + struct ath10k_snoc *ar_snoc; + struct tasklet_struct intr; +}; + +/* struct ath10k_snoc_supp_chip: supported chip set + * @dev_id: device id + * @rev_id: revison id + */ +struct ath10k_snoc_supp_chip { + u32 dev_id; + u32 rev_id; +}; + +/* struct ath10k_snoc_info: SNOC info struct + * @v_addr: base virtual address + * @p_addr: base physical address + * @chip_id: chip id + * @chip_family: chip family + * @board_id: board id + * @soc_id: soc id + * @fw_version: fw version + */ +struct ath10k_snoc_info { + void __iomem *v_addr; + phys_addr_t p_addr; + u32 chip_id; + u32 chip_family; + u32 board_id; + u32 soc_id; + u32 fw_version; +}; + +/* struct ath10k_target_info: SNOC target info + * @target_version: target version + * @target_type: target type + * @target_revision: target revision + * @soc_version: target soc version + */ +struct ath10k_target_info { + u32 target_version; + u32 target_type; + u32 target_revision; + u32 soc_version; +}; + +/* struct ath10k_snoc: SNOC info struct + * @dev: device structure + * @ar:ath10k base structure + * @mem: mem base virtual address + * @mem_pa: mem base physical address + * @target_info: snoc target info + * @mem_len: mempry map length + * @intr_tq: rx tasklet handle + * @pipe_info: pipe info struct + * @ce_lock: protect ce structures + * @ce_states: maps ce id to ce state + * @rx_post_retry: rx buffer post processing timer + * @vaddr_rri_on_ddr: virtual address for RRI + * @is_driver_probed: flag to indicate driver state + */ +struct ath10k_snoc { + struct device *dev; + struct ath10k *ar; + void __iomem *mem; + dma_addr_t mem_pa; + struct ath10k_target_info target_info; + size_t mem_len; + struct tasklet_struct intr_tq; + struct ath10k_snoc_pipe pipe_info[CE_COUNT_MAX]; + /* protects CE info */ + spinlock_t ce_lock; + struct ath10k_ce_pipe ce_states[CE_COUNT_MAX]; + struct timer_list rx_post_retry; + u32 *vaddr_rri_on_ddr; + bool is_driver_probed; +}; + +/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration + * @pipe_num: pipe number + * @pipe_dir: pipe direction + * @nentries: entries in pipe + * @nbytes_max: pipe max size + * @flags: pipe flags + * @reserved: reserved + */ +struct ath10k_ce_tgt_pipe_cfg { + u32 pipe_num; + u32 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; + u32 reserved; +}; + +/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration + * @service_id: target version + * @pipe_dir: pipe direction + * @pipe_num: pipe number + */ +struct ath10k_ce_svc_pipe_cfg { + u32 service_id; + u32 pipe_dir; + u32 pipe_num; +}; + +/* struct ath10k_shadow_reg_cfg: shadow register configuration + * @ce_id: copy engine id + * @reg_offset: offset to copy engine + */ +struct ath10k_shadow_reg_cfg { + u16 ce_id; + u16 reg_offset; +}; + +/* struct ath10k_wlan_enable_cfg: wlan enable configuration + * @num_ce_tgt_cfg: no of ce target configuration + * @ce_tgt_cfg: target ce configuration + * @num_ce_svc_pipe_cfg: no of ce service configuration + * @ce_svc_cfg: ce service configuration + * @num_shadow_reg_cfg: no of shadow registers + * @shadow_reg_cfg: shadow register configuration + */ +struct ath10k_wlan_enable_cfg { + u32 num_ce_tgt_cfg; + struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg; + u32 num_ce_svc_pipe_cfg; + struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct ath10k_shadow_reg_cfg *shadow_reg_cfg; +}; + +/* enum ath10k_driver_mode: ath10k driver mode + * @ATH10K_MISSION: mission mode + * @ATH10K_FTM: ftm mode + * @ATH10K_EPPING: epping mode + * @ATH10K_OFF: off mode + */ +enum ath10k_driver_mode { + ATH10K_MISSION, + ATH10K_FTM, + ATH10K_EPPING, + ATH10K_OFF +}; + +static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) +{ + return (struct ath10k_snoc *)ar->drv_priv; +} + +void ath10k_snoc_write32(void *ar, u32 offset, u32 value); +void ath10k_snoc_soc_write32(struct ath10k *ar, u32 addr, u32 val); +void ath10k_snoc_reg_write32(struct ath10k *ar, u32 addr, u32 val); +u32 ath10k_snoc_read32(void *ar, u32 offset); +u32 ath10k_snoc_soc_read32(struct ath10k *ar, u32 addr); +u32 ath10k_snoc_reg_read32(struct ath10k *ar, u32 addr); + +#endif /* _SNOC_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index e64f59300a7c..7a8f9cfd8253 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -937,7 +937,12 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]; reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]; - svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; + if (QCA_REV_WCN3990(ar)) { + svc_bmap = (__le32 *)(skb->data + + WMI_TLV_TAG_STRUCT_HL_1_0_SVC_OFFSET); + } else { + svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; + } mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT]; if (!ev || !reg || !svc_bmap || !mem_reqs) { @@ -1400,7 +1405,18 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); - cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); + if (QCA_REV_WCN3990(ar)) { + cfg->num_peers = __cpu_to_le32(TARGET_HL_10_TLV_NUM_PEERS); + cfg->ast_skid_limit = + __cpu_to_le32(TARGET_HL_10_TLV_AST_SKID_LIMIT); + cfg->num_wds_entries = + __cpu_to_le32(TARGET_HL_10_TLV_NUM_WDS_ENTRIES); + } else { + cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); + cfg->ast_skid_limit = __cpu_to_le32(0x10); + cfg->num_wds_entries = __cpu_to_le32(0x20); + } + if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) { cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); @@ -1412,7 +1428,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->num_peer_keys = __cpu_to_le32(2); cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); - cfg->ast_skid_limit = __cpu_to_le32(0x10); cfg->tx_chain_mask = __cpu_to_le32(0x7); cfg->rx_chain_mask = __cpu_to_le32(0x7); cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64); @@ -1428,7 +1443,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->num_mcast_table_elems = __cpu_to_le32(0); cfg->mcast2ucast_mode = __cpu_to_le32(0); cfg->tx_dbg_log_size = __cpu_to_le32(0x400); - cfg->num_wds_entries = __cpu_to_le32(0x20); cfg->dma_burst_size = __cpu_to_le32(0); cfg->mac_aggr_delim = __cpu_to_le32(0); cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0); @@ -3562,7 +3576,78 @@ static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { .pmf = WMI_TLV_PEER_PMF, }; -/************/ +static const struct wmi_ops wmi_hl_1_0_ops = { + .rx = ath10k_wmi_tlv_op_rx, + .map_svc = wmi_hl_1_0_svc_map, + .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_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, + .pull_phyerr_hdr = ath10k_wmi_tlv_op_pull_phyerr_ev_hdr, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, + .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, + .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev, + .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev, + .get_txbf_conf_scheme = ath10k_wmi_tlv_txbf_conf_scheme, + .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param, + .gen_init = ath10k_wmi_tlv_op_gen_init, + .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key, + .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf, + .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param, + .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc, + .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, + .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, + .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, + .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, + .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, + .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, + .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, + .gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable, + .gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event, + .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind, + .gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern, + .gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern, + .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state, + .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, + .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, + .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, +}; + +void ath10k_wmi_hl_1_0_attach(struct ath10k *ar) +{ + ar->wmi.cmd = &wmi_tlv_cmd_map; + ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; + ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; + ar->wmi.ops = &wmi_hl_1_0_ops; +} + /* TLV init */ /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index b8aa6000573c..496fee5d489b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -889,6 +889,7 @@ enum wmi_tlv_tag { WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT, WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM, WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR, + WMI_TLV_TAG_STRUCT_HL_1_0_SVC_OFFSET = 176, WMI_TLV_TAG_MAX }; @@ -966,6 +967,125 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, }; +enum wmi_hl_10_service { + WMI_HL_10_SERVICE_BEACON_OFFLOAD = 0, + WMI_HL_10_SERVICE_SCAN_OFFLOAD, + WMI_HL_10_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_HL_10_SERVICE_BCN_MISS_OFFLOAD, + WMI_HL_10_SERVICE_STA_PWRSAVE, + WMI_HL_10_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_HL_10_SERVICE_AP_UAPSD, + WMI_HL_10_SERVICE_AP_DFS, + WMI_HL_10_SERVICE_11AC, + WMI_HL_10_SERVICE_BLOCKACK, + WMI_HL_10_SERVICE_PHYERR, + WMI_HL_10_SERVICE_BCN_FILTER, + WMI_HL_10_SERVICE_RTT, + WMI_HL_10_SERVICE_WOW, + WMI_HL_10_SERVICE_RATECTRL_CACHE, + WMI_HL_10_SERVICE_IRAM_TIDS, + WMI_HL_10_SERVICE_ARPNS_OFFLOAD, + WMI_HL_10_SERVICE_NLO, + WMI_HL_10_SERVICE_GTK_OFFLOAD, + WMI_HL_10_SERVICE_SCAN_SCH, + WMI_HL_10_SERVICE_CSA_OFFLOAD, + WMI_HL_10_SERVICE_CHATTER, + WMI_HL_10_SERVICE_COEX_FREQAVOID, + WMI_HL_10_SERVICE_PACKET_POWER_SAVE, + WMI_HL_10_SERVICE_FORCE_FW_HANG, + WMI_HL_10_SERVICE_GPIO, + WMI_HL_10_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_HL_10_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_HL_10_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_HL_10_SERVICE_STA_KEEP_ALIVE, + WMI_HL_10_SERVICE_TX_ENCAP, + WMI_HL_10_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_HL_10_SERVICE_EARLY_RX, + WMI_HL_10_SERVICE_STA_SMPS, + WMI_HL_10_SERVICE_FWTEST, + WMI_HL_10_SERVICE_STA_WMMAC, + WMI_HL_10_SERVICE_TDLS, + WMI_HL_10_SERVICE_BURST, + WMI_HL_10_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_HL_10_SERVICE_ADAPTIVE_OCS, + WMI_HL_10_SERVICE_BA_SSN_SUPPORT, + WMI_HL_10_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_HL_10_SERVICE_WLAN_HB, + WMI_HL_10_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_HL_10_SERVICE_BATCH_SCAN, + WMI_HL_10_SERVICE_QPOWER, + WMI_HL_10_SERVICE_PLMREQ, + WMI_HL_10_SERVICE_THERMAL_MGMT, + WMI_HL_10_SERVICE_RMC, + WMI_HL_10_SERVICE_MHF_OFFLOAD, + WMI_HL_10_SERVICE_COEX_SAR, + WMI_HL_10_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_HL_10_SERVICE_NAN, + WMI_HL_10_SERVICE_L1SS_STAT, + WMI_HL_10_SERVICE_ESTIMATE_LINKSPEED, + WMI_HL_10_SERVICE_OBSS_SCAN, + WMI_HL_10_SERVICE_TDLS_OFFCHAN, + WMI_HL_10_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_HL_10_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_HL_10_SERVICE_IBSS_PWRSAVE, + WMI_HL_10_SERVICE_LPASS, + WMI_HL_10_SERVICE_EXTSCAN, + WMI_HL_10_SERVICE_D0WOW, + WMI_HL_10_SERVICE_HSOFFLOAD, + WMI_HL_10_SERVICE_ROAM_HO_OFFLOAD, + WMI_HL_10_SERVICE_RX_FULL_REORDER, + WMI_HL_10_SERVICE_DHCP_OFFLOAD, + WMI_HL_10_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_HL_10_SERVICE_MDNS_OFFLOAD, + WMI_HL_10_SERVICE_SAP_AUTH_OFFLOAD, + WMI_HL_10_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT, + WMI_HL_10_SERVICE_OCB, + WMI_HL_10_SERVICE_AP_ARPNS_OFFLOAD, + WMI_HL_10_SERVICE_PER_BAND_CHAINMASK_SUPPORT, + WMI_HL_10_SERVICE_PACKET_FILTER_OFFLOAD, + WMI_HL_10_SERVICE_MGMT_TX_HTT, + WMI_HL_10_SERVICE_MGMT_TX_WMI, + WMI_HL_10_SERVICE_EXT_MSG, + WMI_HL_10_SERVICE_MAWC, + WMI_HL_10_SERVICE_PEER_ASSOC_CONF, + WMI_HL_10_SERVICE_EGAP, + WMI_HL_10_SERVICE_STA_PMF_OFFLOAD, + WMI_HL_10_SERVICE_UNIFIED_WOW_CAPABILITY, + WMI_HL_10_SERVICE_ENHANCED_PROXY_STA, + WMI_HL_10_SERVICE_ATF, + WMI_HL_10_SERVICE_COEX_GPIO, + WMI_HL_10_SERVICE_AUX_SPECTRAL_INTF, + WMI_HL_10_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_HL_10_SERVICE_BSS_CHANNEL_INFO_64, + WMI_HL_10_SERVICE_ENTERPRISE_MESH, + WMI_HL_10_SERVICE_RESTRT_CHNL_SUPPORT, + WMI_HL_10_SERVICE_BPF_OFFLOAD, + WMI_HL_10_SERVICE_SYNC_DELETE_CMDS, + WMI_HL_10_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_HL_10_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_HL_10_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES, + WMI_HL_10_SERVICE_NAN_DATA, + WMI_HL_10_SERVICE_NAN_RTT, + WMI_HL_10_SERVICE_11AX, + WMI_HL_10_SERVICE_DEPRECATED_REPLACE, + WMI_HL_10_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, + WMI_HL_10_SERVICE_ENHANCED_MCAST_FILTER, + WMI_HL_10_SERVICE_PERIODIC_CHAN_STAT_SUPPORT, + WMI_HL_10_SERVICE_MESH_11S, + WMI_HL_10_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT, + WMI_HL_10_SERVICE_VDEV_RX_FILTER, + WMI_HL_10_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT, + WMI_HL_10_SERVICE_MARK_FIRST_WAKEUP_PACKET, + WMI_HL_10_SERVICE_MULTIPLE_MCAST_FILTER_SET, + WMI_HL_10_SERVICE_HOST_MANAGED_RX_REORDER, + WMI_HL_10_SERVICE_FLASH_RDWR_SUPPORT, + WMI_HL_10_SERVICE_WLAN_STATS_REPORT, + WMI_HL_10_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT, + WMI_HL_10_SERVICE_DFS_PHYERR_OFFLOAD, + WMI_HL_10_MAX_SERVICE = 128, + WMI_HL_10_MAX_EXT_SERVICE +}; + #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ ((svc_id) < (len) && \ __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \ @@ -978,6 +1098,63 @@ enum wmi_tlv_service { } while (0) static inline void +wmi_hl_1_0_svc_map(const __le32 *in, unsigned long *out, size_t len) +{ + SVCMAP(WMI_HL_10_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_SERVICE_ROAM_SCAN_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE, len); + SVCMAP(WMI_HL_10_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); + SVCMAP(WMI_HL_10_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD, len); + SVCMAP(WMI_HL_10_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS, len); + SVCMAP(WMI_HL_10_SERVICE_11AC, + WMI_SERVICE_11AC, len); + SVCMAP(WMI_HL_10_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK, len); + SVCMAP(WMI_HL_10_SERVICE_PHYERR, + WMI_SERVICE_PHYERR, len); + SVCMAP(WMI_HL_10_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER, len); + SVCMAP(WMI_HL_10_SERVICE_RTT, + WMI_SERVICE_RTT, len); + SVCMAP(WMI_HL_10_SERVICE_WOW, + WMI_SERVICE_WOW, len); + SVCMAP(WMI_HL_10_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE, len); + SVCMAP(WMI_HL_10_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS, len); + SVCMAP(WMI_HL_10_SERVICE_ARPNS_OFFLOAD, + WMI_SERVICE_ARPNS_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_NLO, + WMI_SERVICE_NLO, len); + SVCMAP(WMI_HL_10_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH, len); + SVCMAP(WMI_HL_10_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_CHATTER, + WMI_SERVICE_CHATTER, len); + SVCMAP(WMI_HL_10_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID, len); + SVCMAP(WMI_HL_10_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE, len); + SVCMAP(WMI_HL_10_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG, len); + SVCMAP(WMI_HL_10_SERVICE_RX_FULL_REORDER, + WMI_SERVICE_RX_FULL_REORDER, len); +} + +static inline void wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) { SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD, @@ -1182,6 +1359,14 @@ struct wmi_tlv_svc_rdy_ev { __le32 max_num_scan_chans; __le32 hw_bd_id; /* 0 means hw_bd_info is invalid */ struct wmi_tlv_hw_bd_info hw_bd_info[5]; +#ifdef CONFIG_ATH10K_SNOC + __le32 max_supported_macs; + __le32 wmi_fw_sub_feat_caps; + __le32 num_dbs_hw_modes; + __le32 txrx_chainmask; + __le32 default_dbs_hw_mode_index; + __le32 num_msdu_desc; +#endif } __packed; struct wmi_tlv_rdy_ev { @@ -1641,5 +1826,5 @@ struct wmi_tlv_tx_pause_ev { } __packed; void ath10k_wmi_tlv_attach(struct ath10k *ar); - +void ath10k_wmi_hl_1_0_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b1d212fd8fd7..f7ada7147136 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -8196,6 +8196,9 @@ int ath10k_wmi_attach(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_TLV: ath10k_wmi_tlv_attach(ar); break; + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: + ath10k_wmi_hl_1_0_attach(ar); + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: ath10k_err(ar, "unsupported WMI op version: %d\n", diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h index ea186d641d59..8efa292d5ff4 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.h +++ b/drivers/net/wireless/ath/wil6210/ftm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -96,7 +96,7 @@ enum qca_wlan_vendor_attr_loc { QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23, QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24, QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25, - QCA_WLAN_VENDOR_ATTR_FREQ = 26, + QCA_WLAN_VENDOR_ATTR_FREQ = 28, /* keep last */ QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_LOC_MAX = QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST - 1, diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 4a12af466c36..8dc93f42b059 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -1214,6 +1214,8 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + smblib_rerun_apsd_if_required(chg); + /* clear the ICL override if it is set */ if (stat & ICL_OVERRIDE_LATCH_BIT) { rc = smblib_write(chg, CMD_APSD_REG, ICL_OVERRIDE_BIT); @@ -1820,6 +1822,8 @@ static int smb2_probe(struct platform_device *pdev) struct smb_charger *chg; int rc = 0; u8 stat; + union power_supply_propval val; + int usb_present, batt_present, batt_health, batt_charge_type; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -1943,7 +1947,37 @@ static int smb2_probe(struct platform_device *pdev) smb2_create_debugfs(chip); - pr_info("QPNP SMB2 probed successfully\n"); + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + pr_err("Couldn't get usb present rc=%d\n", rc); + goto cleanup; + } + usb_present = val.intval; + + rc = smblib_get_prop_batt_present(chg, &val); + if (rc < 0) { + pr_err("Couldn't get batt present rc=%d\n", rc); + goto cleanup; + } + batt_present = val.intval; + + rc = smblib_get_prop_batt_health(chg, &val); + if (rc < 0) { + pr_err("Couldn't get batt health rc=%d\n", rc); + goto cleanup; + } + batt_health = val.intval; + + rc = smblib_get_prop_batt_charge_type(chg, &val); + if (rc < 0) { + pr_err("Couldn't get batt charge type rc=%d\n", rc); + goto cleanup; + } + batt_charge_type = val.intval; + + pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n", + usb_present, chg->usb_psy_desc.type, + batt_present, batt_health, batt_charge_type); return rc; cleanup: @@ -1987,6 +2021,10 @@ static void smb2_shutdown(struct platform_device *pdev) smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0); smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT); + + /* force enable APSD */ + smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + AUTO_SRC_DETECT_BIT, AUTO_SRC_DETECT_BIT); } static const struct of_device_id match_table[] = { diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 5f840f233f20..dbda0b6a9c9a 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -660,6 +660,39 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg) pr_info("Input suspended: Fake battery\n"); } +int smblib_rerun_apsd_if_required(struct smb_charger *chg) +{ + const struct apsd_result *apsd_result; + union power_supply_propval val; + int rc; + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return rc; + } + + if (!val.intval) + return 0; + + apsd_result = smblib_get_apsd_result(chg); + if ((apsd_result->pst == POWER_SUPPLY_TYPE_UNKNOWN) + || (apsd_result->pst == POWER_SUPPLY_TYPE_USB)) { + /* rerun APSD */ + pr_info("Reruning APSD type = %s at bootup\n", + apsd_result->name); + rc = smblib_masked_write(chg, CMD_APSD_REG, + APSD_RERUN_BIT, + APSD_RERUN_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't rerun APSD rc = %d\n", rc); + return rc; + } + } + + return 0; +} + /********************* * VOTABLE CALLBACKS * *********************/ @@ -2346,6 +2379,12 @@ int smblib_reg_block_restore(struct smb_charger *chg, static struct reg_info cc2_detach_settings[] = { { + .reg = TYPE_C_CFG_REG, + .mask = APSD_START_ON_CC_BIT, + .val = 0, + .desc = "TYPE_C_CFG_REG", + }, + { .reg = TYPE_C_CFG_2_REG, .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT, .val = TYPE_C_UFP_MODE_BIT, diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index c5d014193fd6..a4121224b121 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -385,6 +385,7 @@ int smblib_get_prop_slave_current_now(struct smb_charger *chg, int smblib_set_prop_ship_mode(struct smb_charger *chg, const union power_supply_propval *val); void smblib_suspend_on_debug_battery(struct smb_charger *chg); +int smblib_rerun_apsd_if_required(struct smb_charger *chg); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index ed76a585ed03..c836e780fc86 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -39,6 +39,9 @@ #define DEAD_TIME_MASK GENMASK(7, 4) #define HIGH_DEAD_TIME_MASK GENMASK(7, 4) +#define SMB2CHG_DC_TM_SREFGEN (DCIN_BASE + 0xE2) +#define STACKED_DIODE_EN_BIT BIT(2) + enum { OOB_COMP_WA_BIT = BIT(0), }; @@ -1216,6 +1219,13 @@ static int smb138x_slave_probe(struct smb138x *chip) goto cleanup; } + /* enable stacked diode */ + rc = smblib_write(chg, SMB2CHG_DC_TM_SREFGEN, STACKED_DIODE_EN_BIT); + if (rc < 0) { + pr_err("Couldn't enable stacked diode rc=%d\n", rc); + return rc; + } + rc = smb138x_init_parallel_psy(chip); if (rc < 0) { pr_err("Couldn't initialize parallel psy rc=%d\n", rc); diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c index 1ac9791b467b..1070a34073e4 100644 --- a/drivers/regulator/cpr3-mmss-regulator.c +++ b/drivers/regulator/cpr3-mmss-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -453,45 +453,24 @@ done: } /** - * cpr3_msm8996_mmss_apply_closed_loop_offset_voltages() - modify the - * closed-loop voltage adjustments by the amounts that are needed - * for this fuse combo + * cpr3_msm8996_mmss_adjust_target_quotients() - adjust the target quotients + * for each corner according to device tree values and fuse values * @vreg: Pointer to the CPR3 regulator - * @volt_adjust: Array of closed-loop voltage adjustment values of length - * vreg->corner_count which is further adjusted based upon - * offset voltage fuse values. * * Return: 0 on success, errno on failure */ -static int cpr3_msm8996_mmss_apply_closed_loop_offset_voltages( - struct cpr3_regulator *vreg, int *volt_adjust) +static int cpr3_msm8996_mmss_adjust_target_quotients( + struct cpr3_regulator *vreg) { struct cpr3_msm8996_mmss_fuses *fuse = vreg->platform_fuses; const struct cpr3_fuse_param (*offset_param)[2]; - u32 *corner_map; int *volt_offset; - int rc = 0, i, fuse_len; - - if (!of_find_property(vreg->of_node, - "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) { - /* No closed-loop offset required. */ - return 0; - } + int i, fuse_len, rc = 0; - corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map), - GFP_KERNEL); volt_offset = kcalloc(vreg->fuse_corner_count, sizeof(*volt_offset), GFP_KERNEL); - if (!corner_map || !volt_offset) { - rc = -ENOMEM; - goto done; - } - - rc = cpr3_parse_corner_array_property(vreg, - "qcom,cpr-fused-closed-loop-voltage-adjustment-map", - 1, corner_map); - if (rc) - goto done; + if (!volt_offset) + return -ENOMEM; offset_param = cpr3_ctrl_is_msm8998(vreg->thread->ctrl) ? msm8998_mmss_offset_voltage_param @@ -507,223 +486,11 @@ static int cpr3_msm8996_mmss_apply_closed_loop_offset_voltages( i, volt_offset[i]); } - for (i = 0; i < vreg->corner_count; i++) { - if (corner_map[i] == 0) { - continue; - } else if (corner_map[i] > vreg->fuse_corner_count) { - cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n", - i, corner_map[i]); - rc = -EINVAL; - goto done; - } - - volt_adjust[i] += volt_offset[corner_map[i] - 1]; - } + rc = cpr3_adjust_target_quotients(vreg, volt_offset); + if (rc) + cpr3_err(vreg, "adjust target quotients failed, rc=%d\n", rc); -done: - kfree(corner_map); kfree(volt_offset); - - return rc; -} - -/** - * cpr3_mmss_enforce_inc_quotient_monotonicity() - Ensure that target quotients - * increase monotonically from lower to higher corners - * @vreg: Pointer to the CPR3 regulator - * - * Return: 0 on success, errno on failure - */ -static void cpr3_mmss_enforce_inc_quotient_monotonicity( - struct cpr3_regulator *vreg) -{ - int i, j; - - for (i = 1; i < vreg->corner_count; i++) { - for (j = 0; j < CPR3_RO_COUNT; j++) { - if (vreg->corner[i].target_quot[j] - && vreg->corner[i].target_quot[j] - < vreg->corner[i - 1].target_quot[j]) { - cpr3_debug(vreg, "corner %d RO%u target quot=%u < corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", - i, j, - vreg->corner[i].target_quot[j], - i - 1, j, - vreg->corner[i - 1].target_quot[j], - i, j, - vreg->corner[i - 1].target_quot[j]); - vreg->corner[i].target_quot[j] - = vreg->corner[i - 1].target_quot[j]; - } - } - } -} - -/** - * cpr3_mmss_enforce_dec_quotient_monotonicity() - Ensure that target quotients - * decrease monotonically from higher to lower corners - * @vreg: Pointer to the CPR3 regulator - * - * Return: 0 on success, errno on failure - */ -static void cpr3_mmss_enforce_dec_quotient_monotonicity( - struct cpr3_regulator *vreg) -{ - int i, j; - - for (i = vreg->corner_count - 2; i >= 0; i--) { - for (j = 0; j < CPR3_RO_COUNT; j++) { - if (vreg->corner[i + 1].target_quot[j] - && vreg->corner[i].target_quot[j] - > vreg->corner[i + 1].target_quot[j]) { - cpr3_debug(vreg, "corner %d RO%u target quot=%u > corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", - i, j, - vreg->corner[i].target_quot[j], - i + 1, j, - vreg->corner[i + 1].target_quot[j], - i, j, - vreg->corner[i + 1].target_quot[j]); - vreg->corner[i].target_quot[j] - = vreg->corner[i + 1].target_quot[j]; - } - } - } -} - -/** - * _cpr3_mmss_adjust_target_quotients() - adjust the target quotients for each - * corner of the regulator according to input adjustment and - * scaling arrays - * @vreg: Pointer to the CPR3 regulator - * @volt_adjust: Pointer to an array of closed-loop voltage adjustments - * with units of microvolts. The array must have - * vreg->corner_count number of elements. - * @ro_scale: Pointer to a flattened 2D array of RO scaling factors. - * The array must have an inner dimension of CPR3_RO_COUNT - * and an outer dimension of vreg->corner_count - * @label: Null terminated string providing a label for the type - * of adjustment. - * - * Return: true if any corners received a positive voltage adjustment (> 0), - * else false - */ -static bool _cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, - const int *volt_adjust, const int *ro_scale, const char *label) -{ - int i, j, quot_adjust; - bool is_increasing = false; - u32 prev_quot; - - for (i = 0; i < vreg->corner_count; i++) { - for (j = 0; j < CPR3_RO_COUNT; j++) { - if (vreg->corner[i].target_quot[j]) { - quot_adjust = cpr3_quot_adjustment( - ro_scale[i * CPR3_RO_COUNT + j], - volt_adjust[i]); - if (quot_adjust) { - prev_quot = vreg->corner[i]. - target_quot[j]; - vreg->corner[i].target_quot[j] - += quot_adjust; - cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n", - i, j, label, prev_quot, - vreg->corner[i].target_quot[j], - volt_adjust[i]); - } - } - } - if (volt_adjust[i] > 0) - is_increasing = true; - } - - return is_increasing; -} - -/** - * cpr3_mmss_adjust_target_quotients() - adjust the target quotients for each - * corner according to device tree values and fuse values - * @vreg: Pointer to the CPR3 regulator - * - * Return: 0 on success, errno on failure - */ -static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg) -{ - int i, rc; - int *volt_adjust, *ro_scale; - bool explicit_adjustment, fused_adjustment, is_increasing; - - explicit_adjustment = of_find_property(vreg->of_node, - "qcom,cpr-closed-loop-voltage-adjustment", NULL); - fused_adjustment = of_find_property(vreg->of_node, - "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL); - - if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) { - /* No adjustment required. */ - return 0; - } else if (!of_find_property(vreg->of_node, - "qcom,cpr-ro-scaling-factor", NULL)) { - cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n"); - return -EINVAL; - } - - volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust), - GFP_KERNEL); - ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT, - sizeof(*ro_scale), GFP_KERNEL); - if (!volt_adjust || !ro_scale) { - rc = -ENOMEM; - goto done; - } - - rc = cpr3_parse_corner_array_property(vreg, - "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale); - if (rc) { - cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n", - rc); - goto done; - } - - for (i = 0; i < vreg->corner_count; i++) - memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT], - sizeof(*ro_scale) * CPR3_RO_COUNT); - - if (explicit_adjustment) { - rc = cpr3_parse_corner_array_property(vreg, - "qcom,cpr-closed-loop-voltage-adjustment", - 1, volt_adjust); - if (rc) { - cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", - rc); - goto done; - } - - _cpr3_mmss_adjust_target_quotients(vreg, volt_adjust, ro_scale, - "from DT"); - cpr3_mmss_enforce_inc_quotient_monotonicity(vreg); - } - - if (fused_adjustment) { - memset(volt_adjust, 0, - sizeof(*volt_adjust) * vreg->corner_count); - - rc = cpr3_msm8996_mmss_apply_closed_loop_offset_voltages(vreg, - volt_adjust); - if (rc) { - cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n", - rc); - goto done; - } - - is_increasing = _cpr3_mmss_adjust_target_quotients(vreg, - volt_adjust, ro_scale, "from fuse"); - if (is_increasing) - cpr3_mmss_enforce_inc_quotient_monotonicity(vreg); - else - cpr3_mmss_enforce_dec_quotient_monotonicity(vreg); - } - -done: - kfree(volt_adjust); - kfree(ro_scale); return rc; } @@ -1112,7 +879,7 @@ static int cpr3_mmss_init_thread(struct cpr3_thread *thread) return rc; } - rc = cpr3_mmss_adjust_target_quotients(vreg); + rc = cpr3_msm8996_mmss_adjust_target_quotients(vreg); if (rc) { cpr3_err(vreg, "unable to adjust target quotients, rc=%d\n", rc); diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index 2e997b526b90..f0230b8ae2e5 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -904,6 +904,8 @@ int cpr3_apm_init(struct cpr3_controller *ctrl); int cpr3_mem_acc_init(struct cpr3_regulator *vreg); void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg); void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg); +int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + int *fuse_volt_adjust); #else @@ -1084,6 +1086,12 @@ static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg) { } +static inline int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + int *fuse_volt_adjust) +{ + return 0; +} + #endif /* CONFIG_REGULATOR_CPR3 */ #endif /* __REGULATOR_CPR_REGULATOR_H__ */ diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index 7f712d4f6ee4..0a1a1c56bd16 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -2147,3 +2147,259 @@ void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg) corner->ceiling_volt, corner->open_loop_volt); } } + +/** + * cpr3_apply_closed_loop_offset_voltages() - modify the closed-loop voltage + * adjustments by the amounts that are needed for this + * fuse combo + * @vreg: Pointer to the CPR3 regulator + * @volt_adjust: Array of closed-loop voltage adjustment values of length + * vreg->corner_count which is further adjusted based upon + * offset voltage fuse values. + * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length + * vreg->fuse_corner_count. + * + * Return: 0 on success, errno on failure + */ +static int cpr3_apply_closed_loop_offset_voltages(struct cpr3_regulator *vreg, + int *volt_adjust, int *fuse_volt_adjust) +{ + u32 *corner_map; + int rc = 0, i; + + if (!of_find_property(vreg->of_node, + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) { + /* No closed-loop offset required. */ + return 0; + } + + corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map), + GFP_KERNEL); + if (!corner_map) + return -ENOMEM; + + rc = cpr3_parse_corner_array_property(vreg, + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", + 1, corner_map); + if (rc) + goto done; + + for (i = 0; i < vreg->corner_count; i++) { + if (corner_map[i] == 0) { + continue; + } else if (corner_map[i] > vreg->fuse_corner_count) { + cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n", + i, corner_map[i]); + rc = -EINVAL; + goto done; + } + + volt_adjust[i] += fuse_volt_adjust[corner_map[i] - 1]; + } + +done: + kfree(corner_map); + return rc; +} + +/** + * cpr3_enforce_inc_quotient_monotonicity() - Ensure that target quotients + * increase monotonically from lower to higher corners + * @vreg: Pointer to the CPR3 regulator + * + * Return: 0 on success, errno on failure + */ +static void cpr3_enforce_inc_quotient_monotonicity(struct cpr3_regulator *vreg) +{ + int i, j; + + for (i = 1; i < vreg->corner_count; i++) { + for (j = 0; j < CPR3_RO_COUNT; j++) { + if (vreg->corner[i].target_quot[j] + && vreg->corner[i].target_quot[j] + < vreg->corner[i - 1].target_quot[j]) { + cpr3_debug(vreg, "corner %d RO%u target quot=%u < corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", + i, j, + vreg->corner[i].target_quot[j], + i - 1, j, + vreg->corner[i - 1].target_quot[j], + i, j, + vreg->corner[i - 1].target_quot[j]); + vreg->corner[i].target_quot[j] + = vreg->corner[i - 1].target_quot[j]; + } + } + } +} + +/** + * cpr3_enforce_dec_quotient_monotonicity() - Ensure that target quotients + * decrease monotonically from higher to lower corners + * @vreg: Pointer to the CPR3 regulator + * + * Return: 0 on success, errno on failure + */ +static void cpr3_enforce_dec_quotient_monotonicity(struct cpr3_regulator *vreg) +{ + int i, j; + + for (i = vreg->corner_count - 2; i >= 0; i--) { + for (j = 0; j < CPR3_RO_COUNT; j++) { + if (vreg->corner[i + 1].target_quot[j] + && vreg->corner[i].target_quot[j] + > vreg->corner[i + 1].target_quot[j]) { + cpr3_debug(vreg, "corner %d RO%u target quot=%u > corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", + i, j, + vreg->corner[i].target_quot[j], + i + 1, j, + vreg->corner[i + 1].target_quot[j], + i, j, + vreg->corner[i + 1].target_quot[j]); + vreg->corner[i].target_quot[j] + = vreg->corner[i + 1].target_quot[j]; + } + } + } +} + +/** + * _cpr3_adjust_target_quotients() - adjust the target quotients for each + * corner of the regulator according to input adjustment and + * scaling arrays + * @vreg: Pointer to the CPR3 regulator + * @volt_adjust: Pointer to an array of closed-loop voltage adjustments + * with units of microvolts. The array must have + * vreg->corner_count number of elements. + * @ro_scale: Pointer to a flattened 2D array of RO scaling factors. + * The array must have an inner dimension of CPR3_RO_COUNT + * and an outer dimension of vreg->corner_count + * @label: Null terminated string providing a label for the type + * of adjustment. + * + * Return: true if any corners received a positive voltage adjustment (> 0), + * else false + */ +static bool _cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + const int *volt_adjust, const int *ro_scale, const char *label) +{ + int i, j, quot_adjust; + bool is_increasing = false; + u32 prev_quot; + + for (i = 0; i < vreg->corner_count; i++) { + for (j = 0; j < CPR3_RO_COUNT; j++) { + if (vreg->corner[i].target_quot[j]) { + quot_adjust = cpr3_quot_adjustment( + ro_scale[i * CPR3_RO_COUNT + j], + volt_adjust[i]); + if (quot_adjust) { + prev_quot = vreg->corner[i]. + target_quot[j]; + vreg->corner[i].target_quot[j] + += quot_adjust; + cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n", + i, j, label, prev_quot, + vreg->corner[i].target_quot[j], + volt_adjust[i]); + } + } + } + if (volt_adjust[i] > 0) + is_increasing = true; + } + + return is_increasing; +} + +/** + * cpr3_adjust_target_quotients() - adjust the target quotients for each + * corner according to device tree values and fuse values + * @vreg: Pointer to the CPR3 regulator + * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length + * vreg->fuse_corner_count. This parameter could be null + * pointer when no fused adjustments are needed. + * + * Return: 0 on success, errno on failure + */ +int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + int *fuse_volt_adjust) +{ + int i, rc; + int *volt_adjust, *ro_scale; + bool explicit_adjustment, fused_adjustment, is_increasing; + + explicit_adjustment = of_find_property(vreg->of_node, + "qcom,cpr-closed-loop-voltage-adjustment", NULL); + fused_adjustment = of_find_property(vreg->of_node, + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL); + + if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) { + /* No adjustment required. */ + return 0; + } else if (!of_find_property(vreg->of_node, + "qcom,cpr-ro-scaling-factor", NULL)) { + cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n"); + return -EINVAL; + } + + volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust), + GFP_KERNEL); + ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT, + sizeof(*ro_scale), GFP_KERNEL); + if (!volt_adjust || !ro_scale) { + rc = -ENOMEM; + goto done; + } + + rc = cpr3_parse_corner_array_property(vreg, + "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale); + if (rc) { + cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n", + rc); + goto done; + } + + for (i = 0; i < vreg->corner_count; i++) + memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT], + sizeof(*ro_scale) * CPR3_RO_COUNT); + + if (explicit_adjustment) { + rc = cpr3_parse_corner_array_property(vreg, + "qcom,cpr-closed-loop-voltage-adjustment", + 1, volt_adjust); + if (rc) { + cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", + rc); + goto done; + } + + _cpr3_adjust_target_quotients(vreg, volt_adjust, ro_scale, + "from DT"); + cpr3_enforce_inc_quotient_monotonicity(vreg); + } + + if (fused_adjustment && fuse_volt_adjust) { + memset(volt_adjust, 0, + sizeof(*volt_adjust) * vreg->corner_count); + + rc = cpr3_apply_closed_loop_offset_voltages(vreg, volt_adjust, + fuse_volt_adjust); + if (rc) { + cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n", + rc); + goto done; + } + + is_increasing = _cpr3_adjust_target_quotients(vreg, volt_adjust, + ro_scale, "from fuse"); + if (is_increasing) + cpr3_enforce_inc_quotient_monotonicity(vreg); + else + cpr3_enforce_dec_quotient_monotonicity(vreg); + } + +done: + kfree(volt_adjust); + kfree(ro_scale); + return rc; +} diff --git a/drivers/regulator/cpr4-mmss-ldo-regulator.c b/drivers/regulator/cpr4-mmss-ldo-regulator.c index 2843f71745fc..f8e3ea40ddac 100644 --- a/drivers/regulator/cpr4-mmss-ldo-regulator.c +++ b/drivers/regulator/cpr4-mmss-ldo-regulator.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 @@ -417,6 +417,45 @@ done: } /** + * cpr4_sdm660_mmss_adjust_target_quotients() - adjust the target quotients for + * each corner according to device tree values and fuse values + * @vreg: Pointer to the CPR3 regulator + * + * Return: 0 on success, errno on failure + */ +static int cpr4_sdm660_mmss_adjust_target_quotients(struct cpr3_regulator *vreg) +{ + struct cpr4_sdm660_mmss_fuses *fuse = vreg->platform_fuses; + const struct cpr3_fuse_param (*offset_param)[2]; + int *volt_offset; + int i, fuse_len, rc = 0; + + volt_offset = kcalloc(vreg->fuse_corner_count, sizeof(*volt_offset), + GFP_KERNEL); + if (!volt_offset) + return -ENOMEM; + + offset_param = sdm660_mmss_offset_voltage_param; + for (i = 0; i < vreg->fuse_corner_count; i++) { + fuse_len = offset_param[i][0].bit_end + 1 + - offset_param[i][0].bit_start; + volt_offset[i] = cpr3_convert_open_loop_voltage_fuse( + 0, SDM660_MMSS_OFFSET_FUSE_STEP_VOLT, + fuse->offset_voltage[i], fuse_len); + if (volt_offset[i]) + cpr3_info(vreg, "fuse_corner[%d] offset=%7d uV\n", + i, volt_offset[i]); + } + + rc = cpr3_adjust_target_quotients(vreg, volt_offset); + if (rc) + cpr3_err(vreg, "adjust target quotients failed, rc=%d\n", rc); + + kfree(volt_offset); + return rc; +} + +/** * cpr4_mmss_print_settings() - print out MMSS CPR configuration settings into * the kernel log for debugging purposes * @vreg: Pointer to the CPR3 regulator @@ -489,6 +528,13 @@ static int cpr4_mmss_init_thread(struct cpr3_thread *thread) return rc; } + rc = cpr4_sdm660_mmss_adjust_target_quotients(vreg); + if (rc) { + cpr3_err(vreg, "unable to adjust target quotients, rc=%d\n", + rc); + return rc; + } + rc = cpr4_sdm660_mmss_calculate_open_loop_voltages(vreg); if (rc) { cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n", diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index 9a8a3b18d03a..40c62c355188 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.c @@ -333,7 +333,7 @@ enum ibb_mode { IBB_HW_SW_CONTROL, }; -static const int ibb_discharge_resistor_table[] = { +static const int ibb_dischg_res_table[] = { 300, 64, 32, @@ -946,38 +946,27 @@ static int qpnp_ibb_soft_start_ctl_v1(struct qpnp_labibb *labibb, rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-discharge-resistor", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(ibb_dischg_res_table); val++) { + if (ibb_dischg_res_table[val] == tmp) + break; + } - if (rc < 0) { - pr_err("qcom,qpnp-ibb-discharge-resistor is missing, rc = %d\n", - rc); - return rc; - } - - if (labibb->mode == QPNP_LABIBB_AMOLED_MODE) { - /* - * AMOLED mode needs ibb discharge resistor to be - * configured for 300KOhm - */ - if (tmp < ibb_discharge_resistor_table[0]) - tmp = ibb_discharge_resistor_table[0]; - } - - for (val = 0; val < ARRAY_SIZE(ibb_discharge_resistor_table); val++) - if (ibb_discharge_resistor_table[val] == tmp) - break; + if (val == ARRAY_SIZE(ibb_dischg_res_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-discharge-resistor\n"); + return -EINVAL; + } - if (val == ARRAY_SIZE(ibb_discharge_resistor_table)) { - pr_err("Invalid value in qcom,qpnp-ibb-discharge-resistor\n"); - return -EINVAL; + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_SOFT_START_CTL, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_IBB_SOFT_START_CTL, rc); + return rc; + } } - rc = qpnp_labibb_write(labibb, labibb->ibb_base + - REG_IBB_SOFT_START_CTL, &val, 1); - if (rc < 0) - pr_err("write to register %x failed rc = %d\n", - REG_IBB_SOFT_START_CTL, rc); - - return rc; + return 0; } static int qpnp_ibb_soft_start_ctl_v2(struct qpnp_labibb *labibb, @@ -3408,7 +3397,8 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, * before by the bootloader. */ if (labibb->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) - labibb->swire_control = val & IBB_ENABLE_CTL_SWIRE_RDY; + labibb->swire_control = ibb_enable_ctl & + IBB_ENABLE_CTL_SWIRE_RDY; if (ibb_enable_ctl & (IBB_ENABLE_CTL_SWIRE_RDY | IBB_ENABLE_CTL_MODULE_EN)) { diff --git a/drivers/scsi/ufs/ufs-qcom-debugfs.c b/drivers/scsi/ufs/ufs-qcom-debugfs.c index 8532439c392d..4547a6dbdb23 100644 --- a/drivers/scsi/ufs/ufs-qcom-debugfs.c +++ b/drivers/scsi/ufs/ufs-qcom-debugfs.c @@ -67,6 +67,7 @@ static int ufs_qcom_dbg_testbus_en_read(void *data, u64 *attr_val) static int ufs_qcom_dbg_testbus_en_set(void *data, u64 attr_id) { struct ufs_qcom_host *host = data; + int ret = 0; if (!host) return -EINVAL; @@ -76,7 +77,13 @@ static int ufs_qcom_dbg_testbus_en_set(void *data, u64 attr_id) else host->dbg_print_en &= ~UFS_QCOM_DBG_PRINT_TEST_BUS_EN; - return ufs_qcom_testbus_config(host); + pm_runtime_get_sync(host->hba->dev); + ufshcd_hold(host->hba, false); + ret = ufs_qcom_testbus_config(host); + ufshcd_release(host->hba, false); + pm_runtime_put_sync(host->hba->dev); + + return ret; } DEFINE_SIMPLE_ATTRIBUTE(ufs_qcom_dbg_testbus_en_ops, @@ -142,7 +149,11 @@ static ssize_t ufs_qcom_dbg_testbus_cfg_write(struct file *file, * Sanity check of the {major, minor} tuple is done in the * config function */ + pm_runtime_get_sync(host->hba->dev); + ufshcd_hold(host->hba, false); ret = ufs_qcom_testbus_config(host); + ufshcd_release(host->hba, false); + pm_runtime_put_sync(host->hba->dev); if (!ret) dev_dbg(host->hba->dev, "%s: New configuration: major=%d, minor=%d\n", diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 85f82b2251c1..814d1dcfe90e 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -173,10 +173,19 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work) struct ice_data_setting ice_set; struct ufs_qcom_host *qcom_host = container_of(work, struct ufs_qcom_host, ice_cfg_work); + struct request *req_pending = NULL; - if (!qcom_host->ice.vops->config_start || !qcom_host->req_pending) + if (!qcom_host->ice.vops->config_start) return; + spin_lock_irqsave(&qcom_host->ice_work_lock, flags); + req_pending = qcom_host->req_pending; + if (!req_pending) { + spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); + return; + } + spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); + /* * config_start is called again as previous attempt returned -EAGAIN, * this call shall now take care of the necessary key setup. @@ -263,6 +272,10 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, if (qcom_host->ice.vops->config_start) { memset(&ice_set, 0, sizeof(ice_set)); + + spin_lock_irqsave( + &qcom_host->ice_work_lock, flags); + err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev, cmd->request, &ice_set, true); if (err) { @@ -281,13 +294,11 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, "%s: scheduling task for ice setup\n", __func__); - spin_lock_irqsave( - &qcom_host->ice_work_lock, flags); - if (!qcom_host->req_pending) { ufshcd_scsi_block_requests( qcom_host->hba); qcom_host->req_pending = cmd->request; + if (!schedule_work( &qcom_host->ice_cfg_work)) { qcom_host->req_pending = NULL; @@ -302,9 +313,6 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, } } - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, flags); - } else { if (err != -EBUSY) dev_err(qcom_host->hba->dev, @@ -312,9 +320,14 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, __func__, err); } + spin_unlock_irqrestore(&qcom_host->ice_work_lock, + flags); + return err; } + spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); + if (ufs_qcom_is_data_cmd(cmd_op, true)) *enable = !ice_set.encr_bypass; else if (ufs_qcom_is_data_cmd(cmd_op, false)) @@ -380,8 +393,13 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, return -EINVAL; } - memset(&ice_set, 0, sizeof(ice_set)); + if (qcom_host->ice.vops->config_start) { + memset(&ice_set, 0, sizeof(ice_set)); + + spin_lock_irqsave( + &qcom_host->ice_work_lock, flags); + err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev, req, &ice_set, true); if (err) { @@ -401,9 +419,6 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, "%s: scheduling task for ice setup\n", __func__); - spin_lock_irqsave( - &qcom_host->ice_work_lock, flags); - if (!qcom_host->req_pending) { ufshcd_scsi_block_requests( qcom_host->hba); @@ -422,9 +437,6 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, } } - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, flags); - } else { if (err != -EBUSY) dev_err(qcom_host->hba->dev, @@ -432,8 +444,14 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, __func__, err); } + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, flags); + return err; } + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, flags); } cmd_op = cmd->cmnd[0]; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 03b222d8be93..7369478a8c5d 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -2452,6 +2452,11 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host) return true; } +/* + * The caller of this function must make sure that the controller + * is out of runtime suspend and appropriate clocks are enabled + * before accessing. + */ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) { int reg; @@ -2522,8 +2527,6 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) } mask <<= offset; - pm_runtime_get_sync(host->hba->dev); - ufshcd_hold(host->hba, false); ufshcd_rmwl(host->hba, TEST_BUS_SEL, (u32)host->testbus.select_major << 19, REG_UFS_CFG1); @@ -2536,8 +2539,6 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) * committed before returning. */ mb(); - ufshcd_release(host->hba, false); - pm_runtime_put_sync(host->hba->dev); return 0; } diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d4acc3c911f5..bf357b50e798 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2769,6 +2769,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) hba = shost_priv(host); + if (!cmd || !cmd->request || !hba) + return -EINVAL; + tag = cmd->request->tag; if (!ufshcd_valid_tag(hba, tag)) { dev_err(hba->dev, @@ -2854,13 +2857,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) ufshcd_vops_pm_qos_req_start(hba, cmd->request); /* IO svc time latency histogram */ - if (hba != NULL && cmd->request != NULL) { - if (hba->latency_hist_enabled && - (cmd->request->cmd_type == REQ_TYPE_FS)) { - cmd->request->lat_hist_io_start = ktime_get(); - cmd->request->lat_hist_enabled = 1; - } else - cmd->request->lat_hist_enabled = 0; + if (hba->latency_hist_enabled && + (cmd->request->cmd_type == REQ_TYPE_FS)) { + cmd->request->lat_hist_io_start = ktime_get(); + cmd->request->lat_hist_enabled = 1; + } else { + cmd->request->lat_hist_enabled = 0; } WARN_ON(hba->clk_gating.state != CLKS_ON); @@ -4141,17 +4143,17 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) ufshcd_hold_all(hba); spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) { - ret = -EBUSY; - goto out; - } - /* * Wait for all the outstanding tasks/transfer requests. * Verify by checking the doorbell registers are clear. */ start = ktime_get(); do { + if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) { + ret = -EBUSY; + goto out; + } + tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL); tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); if (!tm_doorbell && !tr_doorbell) { diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 4192424df275..873416944b19 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -2066,7 +2066,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, icnss_pr_info("Modem went down, state: %lx\n", priv->state); - event_data = kzalloc(sizeof(*data), GFP_KERNEL); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); @@ -2141,7 +2141,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data, priv->state); - event_data = kzalloc(sizeof(*data), GFP_KERNEL); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index 5726c3277456..76f9ed046120 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.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 @@ -38,6 +38,7 @@ static void mem_share_svc_recv_msg(struct work_struct *work); static DECLARE_DELAYED_WORK(work_recv_msg, mem_share_svc_recv_msg); static struct workqueue_struct *mem_share_svc_workqueue; static uint64_t bootup_request; +static bool ramdump_event; static void *memshare_ramdump_dev[MAX_CLIENTS]; static struct device *memshare_dev[MAX_CLIENTS]; @@ -337,18 +338,25 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, bootup_request++; break; + case SUBSYS_RAMDUMP_NOTIFICATION: + ramdump_event = 1; + break; + case SUBSYS_BEFORE_POWERUP: - if (_cmd) + if (_cmd) { notifdata = (struct notif_data *) _cmd; - else + } else { + ramdump_event = 0; break; + } - if (notifdata->enable_ramdump) { + if (notifdata->enable_ramdump && ramdump_event) { pr_info("memshare: %s, Ramdump collection is enabled\n", __func__); ret = mem_share_do_ramdump(); if (ret) pr_err("Ramdump collection failed\n"); + ramdump_event = 0; } break; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index bc0e0184a917..1e252febc783 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -156,6 +156,7 @@ struct dwc3_msm { struct clk *xo_clk; struct clk *core_clk; long core_clk_rate; + long core_clk_rate_hs; struct clk *iface_clk; struct clk *sleep_clk; struct clk *utmi_clk; @@ -195,6 +196,7 @@ struct dwc3_msm { struct power_supply *usb_psy; struct work_struct vbus_draw_work; bool in_host_mode; + enum usb_device_speed max_rh_port_speed; unsigned int tx_fifo_size; bool vbus_active; bool suspend; @@ -342,6 +344,23 @@ static inline void dwc3_msm_write_readback(void *base, u32 offset, __func__, val, offset); } +static bool dwc3_msm_is_ss_rhport_connected(struct dwc3_msm *mdwc) +{ + int i, num_ports; + u32 reg; + + reg = dwc3_msm_read_reg(mdwc->base, USB3_HCSPARAMS1); + num_ports = HCS_MAX_PORTS(reg); + + for (i = 0; i < num_ports; i++) { + reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); + if ((reg & PORT_CONNECT) && DEV_SUPERSPEED(reg)) + return true; + } + + return false; +} + static bool dwc3_msm_is_host_superspeed(struct dwc3_msm *mdwc) { int i, num_ports; @@ -2128,6 +2147,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) static int dwc3_msm_resume(struct dwc3_msm *mdwc) { int ret; + long core_clk_rate; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__); @@ -2175,7 +2195,15 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) clk_prepare_enable(mdwc->iface_clk); if (mdwc->noc_aggr_clk) clk_prepare_enable(mdwc->noc_aggr_clk); - clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); + + core_clk_rate = mdwc->core_clk_rate; + if (mdwc->in_host_mode && mdwc->max_rh_port_speed == USB_SPEED_HIGH) { + core_clk_rate = mdwc->core_clk_rate_hs; + dev_dbg(mdwc->dev, "%s: set hs core clk rate %ld\n", __func__, + core_clk_rate); + } + + clk_set_rate(mdwc->core_clk, core_clk_rate); clk_prepare_enable(mdwc->core_clk); /* set Memory core: ON, Memory periphery: ON */ @@ -2496,6 +2524,11 @@ static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc) if (ret) dev_err(mdwc->dev, "fail to set core_clk freq:%d\n", ret); + if (of_property_read_u32(mdwc->dev->of_node, "qcom,core-clk-rate-hs", + (u32 *)&mdwc->core_clk_rate_hs)) { + dev_dbg(mdwc->dev, "USB core-clk-rate-hs is not present\n"); + mdwc->core_clk_rate_hs = mdwc->core_clk_rate; + } mdwc->core_reset = devm_reset_control_get(mdwc->dev, "core_reset"); if (IS_ERR(mdwc->core_reset)) { @@ -2723,6 +2756,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; struct device *dev = &pdev->dev; + union power_supply_propval pval = {0}; struct dwc3_msm *mdwc; struct dwc3 *dwc; struct resource *res; @@ -3016,10 +3050,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) */ mdwc->lpm_flags = MDWC3_POWER_COLLAPSE | MDWC3_SS_PHY_SUSPEND; atomic_set(&dwc->in_lpm, 1); - pm_runtime_set_suspended(mdwc->dev); pm_runtime_set_autosuspend_delay(mdwc->dev, 1000); pm_runtime_use_autosuspend(mdwc->dev); - pm_runtime_enable(mdwc->dev); device_init_wakeup(mdwc->dev, 1); if (of_property_read_bool(node, "qcom,disable-dev-mode-pm")) @@ -3036,18 +3068,32 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->pm_qos_latency = 0; } + mdwc->usb_psy = power_supply_get_by_name("usb"); + if (!mdwc->usb_psy) { + dev_warn(mdwc->dev, "Could not get usb power_supply\n"); + pval.intval = -EINVAL; + } else { + power_supply_get_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + } + /* Update initial VBUS/ID state from extcon */ if (mdwc->extcon_vbus && extcon_get_cable_state_(mdwc->extcon_vbus, EXTCON_USB)) dwc3_msm_vbus_notifier(&mdwc->vbus_nb, true, mdwc->extcon_vbus); - if (mdwc->extcon_id && extcon_get_cable_state_(mdwc->extcon_id, + else if (mdwc->extcon_id && extcon_get_cable_state_(mdwc->extcon_id, EXTCON_USB_HOST)) dwc3_msm_id_notifier(&mdwc->id_nb, true, mdwc->extcon_id); + else if (!pval.intval) { + /* USB cable is not connected */ + schedule_delayed_work(&mdwc->sm_work, 0); + } else { + if (pval.intval > 0) + dev_info(mdwc->dev, "charger detection in progress\n"); + } device_create_file(&pdev->dev, &dev_attr_mode); - schedule_delayed_work(&mdwc->sm_work, 0); - host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (!dwc->is_drd && host_mode) { dev_dbg(&pdev->dev, "DWC3 in host only mode\n"); @@ -3166,10 +3212,26 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, if (udev->parent && !udev->parent->parent && udev->dev.parent->parent == &dwc->xhci->dev) { if (event == USB_DEVICE_ADD && udev->actconfig) { + if (!dwc3_msm_is_ss_rhport_connected(mdwc)) { + /* + * Core clock rate can be reduced only if root + * hub SS port is not enabled/connected. + */ + clk_set_rate(mdwc->core_clk, + mdwc->core_clk_rate_hs); + dev_dbg(mdwc->dev, + "set hs core clk rate %ld\n", + mdwc->core_clk_rate_hs); + mdwc->max_rh_port_speed = USB_SPEED_HIGH; + } else { + mdwc->max_rh_port_speed = USB_SPEED_SUPER; + } + if (udev->speed >= USB_SPEED_SUPER) max_power = udev->actconfig->desc.bMaxPower * 8; else max_power = udev->actconfig->desc.bMaxPower * 2; + dev_dbg(mdwc->dev, "%s configured bMaxPower:%d (mA)\n", dev_name(&udev->dev), max_power); @@ -3181,6 +3243,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, pval.intval = 0; power_supply_set_property(mdwc->usb_psy, POWER_SUPPLY_PROP_BOOST_CURRENT, &pval); + mdwc->max_rh_port_speed = USB_SPEED_UNKNOWN; } } @@ -3538,13 +3601,25 @@ static void dwc3_otg_sm_work(struct work_struct *w) /* Check OTG state */ switch (mdwc->otg_state) { case OTG_STATE_UNDEFINED: - /* Do nothing if no cable connected */ + /* put controller and phy in suspend if no cable connected */ if (test_bit(ID, &mdwc->inputs) && - !test_bit(B_SESS_VLD, &mdwc->inputs)) + !test_bit(B_SESS_VLD, &mdwc->inputs)) { + dbg_event(0xFF, "undef_id_!bsv", 0); + pm_runtime_set_active(mdwc->dev); + pm_runtime_enable(mdwc->dev); + pm_runtime_get_noresume(mdwc->dev); + dwc3_msm_resume(mdwc); + pm_runtime_put_sync(mdwc->dev); + dbg_event(0xFF, "Undef NoUSB", + atomic_read(&mdwc->dev->power.usage_count)); + mdwc->otg_state = OTG_STATE_B_IDLE; break; + } dbg_event(0xFF, "Exit UNDEF", 0); mdwc->otg_state = OTG_STATE_B_IDLE; + pm_runtime_set_suspended(mdwc->dev); + pm_runtime_enable(mdwc->dev); /* fall-through */ case OTG_STATE_B_IDLE: if (!test_bit(ID, &mdwc->inputs)) { diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 7cafd0dd59f5..97d86b6ac69b 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2490,8 +2490,14 @@ static void handle_exception(struct fsg_common *common) case FSG_STATE_CONFIG_CHANGE: do_set_interface(common, common->new_fsg); - if (common->new_fsg) + if (common->new_fsg) { + /* + * make sure delayed_status flag updated when set_alt + * returned. + */ + msleep(200); usb_composite_setup_continue(common->cdev); + } break; case FSG_STATE_EXIT: diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 656b58eb62d7..111d7cfc7c9a 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -428,6 +428,12 @@ static inline bool mdss_fb_is_power_on_lp(struct msm_fb_data_type *mfd) return mdss_panel_is_power_on_lp(mfd->panel_power_state); } +static inline bool mdss_fb_is_power_on_ulp(struct msm_fb_data_type *mfd) +{ + return mdss_panel_is_power_on_ulp(mfd->panel_power_state); +} + + static inline bool mdss_fb_is_hdmi_primary(struct msm_fb_data_type *mfd) { return (mfd && (mfd->index == 0) && diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index d3d332d780d5..cb9cc08140f0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1,5 +1,5 @@ /* - * 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 @@ -124,6 +124,7 @@ #define DS_ENHANCER_UPDATE BIT(5) #define DS_VALIDATE BIT(6) #define DS_DIRTY_UPDATE BIT(7) +#define DS_PU_ENABLE BIT(8) /** * Destination Scaler DUAL mode overfetch pixel count @@ -386,6 +387,7 @@ struct mdss_mdp_destination_scaler { u16 last_mixer_height; u32 flags; struct mdp_scale_data_v2 scaler; + struct mdss_rect panel_roi; }; @@ -1169,6 +1171,14 @@ static inline int is_dest_scaling_enable(struct mdss_mdp_mixer *mixer) mixer && mixer->ds && (mixer->ds->flags & DS_ENABLE)); } +static inline int is_dest_scaling_pu_enable(struct mdss_mdp_mixer *mixer) +{ + if (is_dest_scaling_enable(mixer)) + return (mixer->ds->flags & DS_PU_ENABLE); + + return 0; +} + static inline u32 get_ds_input_width(struct mdss_mdp_mixer *mixer) { struct mdss_mdp_destination_scaler *ds; diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index f7840ee8245e..ffbf156e9eed 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4434,6 +4434,13 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int power_state) goto end; } + /* + * reset the play_cnt, after the cmd_stop + * this will ensure pipes are reconfiged + * after every panel power state change + */ + ctl->play_cnt = 0; + if (mdss_panel_is_power_on(power_state)) { pr_debug("panel is not off, leaving ctl power on\n"); goto end; @@ -4450,8 +4457,6 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int power_state) mdss_mdp_reset_mixercfg(ctl); - ctl->play_cnt = 0; - end: if (!ret) { ctl->power_state = power_state; @@ -4653,7 +4658,15 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, previous_frame_pu_type = mdss_mdp_get_pu_type(ctl); if (ctl->mixer_left) { mdss_mdp_set_mixer_roi(ctl->mixer_left, l_roi); - ctl->roi = ctl->mixer_left->roi; + if (is_dest_scaling_enable(ctl->mixer_left)) + ctl->roi = ctl->mixer_left->ds->panel_roi; + else + ctl->roi = ctl->mixer_left->roi; + + pr_debug("ctl->mixer_left: [%d %d %d %d] ds:%d\n", + ctl->roi.x, ctl->roi.y, + ctl->roi.w, ctl->roi.h, + is_dest_scaling_enable(ctl->mixer_left)); } if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) { @@ -4661,20 +4674,43 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, if (sctl && sctl->mixer_left) { mdss_mdp_set_mixer_roi(sctl->mixer_left, r_roi); - sctl->roi = sctl->mixer_left->roi; + if (is_dest_scaling_enable(sctl->mixer_left)) + sctl->roi = sctl->mixer_left->ds->panel_roi; + else + sctl->roi = sctl->mixer_left->roi; + + pr_debug("sctl->mixer_left: [%d %d %d %d] ds:%d\n", + sctl->roi.x, sctl->roi.y, + sctl->roi.w, sctl->roi.h, + is_dest_scaling_enable(sctl->mixer_left)); + } } else if (is_dual_lm_single_display(ctl->mfd) && ctl->mixer_right) { mdss_mdp_set_mixer_roi(ctl->mixer_right, r_roi); /* in this case, CTL_ROI is a union of left+right ROIs. */ - ctl->roi.w += ctl->mixer_right->roi.w; + if (is_dest_scaling_enable(ctl->mixer_right)) + ctl->roi.w += ctl->mixer_right->ds->panel_roi.w; + else + ctl->roi.w += ctl->mixer_right->roi.w; /* right_only, update roi.x as per CTL ROI guidelines */ if (ctl->mixer_left && !ctl->mixer_left->valid_roi) { - ctl->roi = ctl->mixer_right->roi; - ctl->roi.x = left_lm_w_from_mfd(ctl->mfd) + - ctl->mixer_right->roi.x; + if (is_dest_scaling_enable(ctl->mixer_right)) { + ctl->roi = ctl->mixer_right->ds->panel_roi; + ctl->roi.x = + get_ds_output_width(ctl->mixer_left) + + ctl->mixer_right->ds->panel_roi.x; + } else { + ctl->roi = ctl->mixer_right->roi; + ctl->roi.x = left_lm_w_from_mfd(ctl->mfd) + + ctl->mixer_right->roi.x; + } + pr_debug("ctl->mixer_right_only : [%d %d %d %d] ds:%d\n", + ctl->roi.x, ctl->roi.y, + ctl->roi.w, ctl->roi.h, + is_dest_scaling_enable(ctl->mixer_right)); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index af763cf6b306..0eb82dd8371d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -67,6 +67,36 @@ static inline void *u64_to_ptr(uint64_t address) return (void *)(uintptr_t)address; } +static inline struct mdp_destination_scaler_data *__dest_scaler_next( + struct mdp_destination_scaler_data *ds_data, int ds_count) +{ + struct mdp_destination_scaler_data *ds_data_r = ds_data; + size_t offset; + + /* + * Advanced to next ds_data structure from commit if + * there is more than 1 for source split usecase. + */ + if (ds_count > 1) { + ds_data_r = ds_data + 1; + + /* + * To check for binary compatibility with old user mode + * driver which does not have ROI support in destination + * scalar. + */ + if ((ds_data_r->dest_scaler_ndx != 1) && + (ds_data_r->lm_height != ds_data->lm_height)) { + offset = offsetof(struct mdp_destination_scaler_data, + panel_roi); + ds_data_r = (struct mdp_destination_scaler_data *)( + (void *)ds_data + offset); + } + } + + return ds_data_r; +} + static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) { struct mdss_data_type *mdata = ctl->mdata; @@ -94,6 +124,9 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) ctl->mixer_right->roi = (struct mdss_rect) { 0, 0, ctl->mixer_right->width, ctl->mixer_right->height }; + if (split_ctl) + split_ctl->mixer_left->roi = + ctl->mixer_right->roi; /* * Disable destination scaler by resetting the control @@ -143,6 +176,46 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) } } +static int __dest_scaler_panel_roi_update( + struct mdp_destination_scaler_data *ds_data, + struct mdss_mdp_destination_scaler *ds) +{ + if (ds_data->flags & MDP_DESTSCALER_ROI_ENABLE) { + /* + * Updating PANEL ROI info, used in partial update + */ + if ((ds_data->panel_roi.w > ds->scaler.dst_width) || + (ds_data->panel_roi.h > + ds->scaler.dst_height) || + (ds_data->panel_roi.w == 0) || + (ds_data->panel_roi.h == 0)) { + pr_err("Invalid panel ROI parameter for dest-scaler-%d: [%d %d %d %d]\n", + ds_data->dest_scaler_ndx, + ds_data->panel_roi.x, + ds_data->panel_roi.y, + ds_data->panel_roi.w, + ds_data->panel_roi.h); + ds->flags &= ~DS_PU_ENABLE; + return -EINVAL; + } + ds->panel_roi.x = ds_data->panel_roi.x; + ds->panel_roi.y = ds_data->panel_roi.y; + ds->panel_roi.w = ds_data->panel_roi.w; + ds->panel_roi.h = ds_data->panel_roi.h; + ds->flags |= DS_PU_ENABLE; + pr_debug("dest-scaler[%d] panel_roi update: [%d,%d,%d,%d]\n", + ds->num, + ds_data->panel_roi.x, ds_data->panel_roi.y, + ds_data->panel_roi.w, ds_data->panel_roi.h); + MDSS_XLOG(ds->num, ds_data->panel_roi.x, ds_data->panel_roi.y, + ds_data->panel_roi.w, ds_data->panel_roi.h); + } else { + ds->flags &= ~DS_PU_ENABLE; + } + + return 0; +} + static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data, struct mdss_mdp_destination_scaler *ds, u32 max_input_width, u32 max_output_width) @@ -188,6 +261,9 @@ static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data, ds->src_height = ds_data->lm_height; } + if (__dest_scaler_panel_roi_update(ds_data, ds)) + return -EINVAL; + if (ds_data->flags == 0) { pr_debug("Disabling destination scaler-%d\n", ds_data->dest_scaler_ndx); @@ -235,13 +311,7 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl, } if (ctl->mixer_right && ctl->mixer_right->ds) { - /* - * Advanced to next ds_data structure from commit if - * there is more than 1 for split display usecase. - */ - if (ds_count > 1) - ds_data++; - + ds_data = __dest_scaler_next(ds_data, ds_count); pinfo = &ctl->panel_data->panel_info; if ((ds_data->lm_width > get_panel_xres(pinfo)) || (ds_data->lm_height > get_panel_yres(pinfo)) || @@ -317,14 +387,17 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, int ret = 0; struct mdss_data_type *mdata; struct mdss_mdp_ctl *ctl; + struct mdss_mdp_ctl *sctl; struct mdss_mdp_destination_scaler *ds_left = NULL; struct mdss_mdp_destination_scaler *ds_right = NULL; struct mdss_panel_info *pinfo; u32 scaler_width, scaler_height; + struct mdp_destination_scaler_data *ds_data_r = NULL; if (ds_data) { mdata = mfd_to_mdata(mfd); ctl = mfd_to_ctl(mfd); + sctl = mdss_mdp_get_split_ctl(ctl); if (ctl->mixer_left) ds_left = ctl->mixer_left->ds; @@ -332,6 +405,9 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ctl->mixer_right) ds_right = ctl->mixer_right->ds; + if (sctl && sctl->mixer_left && ds_right) + sctl->mixer_left->ds = ds_right; + switch (ds_mode) { case DS_DUAL_MODE: if (!ds_left || !ds_right) { @@ -346,13 +422,28 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; - ret = __dest_scaler_data_setup(&ds_data[1], ds_right, + ds_data_r = __dest_scaler_next(ds_data, 2); + ret = __dest_scaler_data_setup(ds_data_r, ds_right, mdata->max_dest_scaler_input_width - MDSS_MDP_DS_OVERFETCH_SIZE, mdata->max_dest_scaler_output_width); if (ret) goto reset_mixer; + if ((ds_right->flags & DS_PU_ENABLE) && sctl) { + pinfo = &ctl->panel_data->panel_info; + if (ds_right->panel_roi.x >= + get_panel_xres(pinfo)) { + ds_right->panel_roi.x -= + get_panel_xres(pinfo); + } else { + pr_err("SCTL DS right roi.x:%d < left panel width:%d\n", + ds_right->panel_roi.x, + get_panel_xres(pinfo)); + goto reset_mixer; + } + } + ds_left->flags &= ~(DS_LEFT|DS_RIGHT); ds_left->flags |= DS_DUAL_MODE; ds_right->flags &= ~(DS_LEFT|DS_RIGHT); @@ -377,6 +468,17 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; + /* + * For Partial update usecase, it is possible switching + * from Left+Right mode to Left only mode. So make sure + * cleanup the DS_RIGHT flags. + */ + if (ds_right) { + ds_right->flags &= + ~(DS_DUAL_MODE|DS_ENABLE|DS_PU_ENABLE); + ds_right->flags |= DS_VALIDATE; + } + MDSS_XLOG(ds_left->num, ds_left->src_width, ds_left->src_height, ds_left->flags); break; @@ -396,6 +498,26 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; + if (ds_left) { + ds_left->flags &= + ~(DS_DUAL_MODE|DS_ENABLE|DS_PU_ENABLE); + ds_left->flags |= DS_VALIDATE; + } + + if ((ds_right->flags & DS_PU_ENABLE) && sctl) { + pinfo = &ctl->panel_data->panel_info; + if (ds_right->panel_roi.x >= + get_panel_xres(pinfo)) { + ds_right->panel_roi.x -= + get_panel_xres(pinfo); + } else { + pr_err("SCTL DS-right-only roi.x:%d < Left panel width:%d\n", + ds_right->panel_roi.x, + get_panel_xres(pinfo)); + goto reset_mixer; + } + } + MDSS_XLOG(ds_right->num, ds_right->src_width, ds_right->src_height, ds_right->flags); break; @@ -418,11 +540,11 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, pinfo = &ctl->panel_data->panel_info; scaler_width = 0; scaler_height = 0; - if (ds_left && ds_left->flags) { + if (ds_left && (ds_left->flags & DS_ENABLE)) { scaler_width += ds_left->scaler.dst_width; scaler_height = ds_left->scaler.dst_height; } - if (ds_right && ds_right->flags) { + if (ds_right && (ds_right->flags & DS_ENABLE)) { scaler_width += ds_right->scaler.dst_width; scaler_height = ds_right->scaler.dst_height; } @@ -2731,7 +2853,8 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd, return -ENODEV; } - if (mdss_fb_is_power_off(mfd)) { + if (mdss_fb_is_power_off(mfd) || + mdss_fb_is_power_on_ulp(mfd)) { pr_err("display interface is in off state fb:%d\n", mfd->index); return -EPERM; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index c6fc10833d7f..9864d611e8e4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.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 @@ -1930,6 +1930,39 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe) pipe->restore_roi = false; } +static void __restore_dest_scaler_roi(struct mdss_mdp_ctl *ctl) +{ + struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; + struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + + if (is_dest_scaling_pu_enable(ctl->mixer_left)) { + ctl->mixer_left->ds->panel_roi.x = 0; + ctl->mixer_left->ds->panel_roi.y = 0; + ctl->mixer_left->ds->panel_roi.w = get_panel_xres(pinfo); + ctl->mixer_left->ds->panel_roi.h = get_panel_yres(pinfo); + + if ((ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) && + sctl) { + if (ctl->panel_data->next) + pinfo = &ctl->panel_data->next->panel_info; + sctl->mixer_left->ds->panel_roi.x = 0; + sctl->mixer_left->ds->panel_roi.y = 0; + sctl->mixer_left->ds->panel_roi.w = + get_panel_xres(pinfo); + sctl->mixer_left->ds->panel_roi.h = + get_panel_yres(pinfo); + } else if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) { + ctl->mixer_right->ds->panel_roi.x = + get_panel_xres(pinfo); + ctl->mixer_right->ds->panel_roi.y = 0; + ctl->mixer_right->ds->panel_roi.w = + get_panel_xres(pinfo); + ctl->mixer_right->ds->panel_roi.h = + get_panel_yres(pinfo); + } + } +} + /** * __adjust_pipe_rect() - Adjust pipe roi for dual partial update feature. * @pipe: pipe to check against. @@ -2145,6 +2178,9 @@ set_roi: } dual_roi->enabled = false; } + + if (pinfo->partial_update_enabled) + __restore_dest_scaler_roi(ctl); } pr_debug("after processing: %s l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d, dual_pu_roi:%d\n", diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 6870193166f2..563cb8be1a04 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -2406,8 +2406,16 @@ bool mdss_mdp_is_amortizable_pipe(struct mdss_mdp_pipe *pipe, struct mdss_mdp_mixer *mixer, struct mdss_data_type *mdata) { /* do not apply for rotator or WB */ - return ((pipe->dst.y > mdata->prefill_data.ts_threshold) && - (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)); + if (!((pipe->dst.y > mdata->prefill_data.ts_threshold) && + (mixer->type == MDSS_MDP_MIXER_TYPE_INTF))) + return false; + + /* do not apply for sdm660 in command mode */ + if ((IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, + MDSS_MDP_HW_REV_320)) && !mixer->ctl->is_video_mode) + return false; + + return true; } static inline void __get_ordered_rects(struct mdss_mdp_pipe *pipe, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 294344b3f0f0..e5930177c96a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -70,6 +70,7 @@ struct wiphy; #define CFG80211_UPDATE_CONNECT_PARAMS 1 #define CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT 1 #define CFG80211_RAND_TA_FOR_PUBLIC_ACTION_FRAME 1 +#define CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN 1 /* * wireless hardware capability structures @@ -1569,6 +1570,17 @@ struct cfg80211_sched_scan_plan { }; /** + * struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment. + * + * @band: band of BSS which should match for RSSI level adjustment. + * @delta: value of RSSI level adjustment. + */ +struct cfg80211_bss_select_adjust { + enum nl80211_band band; + s8 delta; +}; + +/** * struct cfg80211_sched_scan_request - scheduled scan request description * * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans) @@ -1603,6 +1615,16 @@ struct cfg80211_sched_scan_plan { * cycle. The driver may ignore this parameter and start * immediately (or at any other time), if this feature is not * supported. + * @relative_rssi_set: Indicates whether @relative_rssi is set or not. + * @relative_rssi: Relative RSSI threshold in dB to restrict scan result + * reporting in connected state to cases where a matching BSS is determined + * to have better or slightly worse RSSI than the current connected BSS. + * The relative RSSI threshold values are ignored in disconnected state. + * @rssi_adjust: delta dB of RSSI preference to be given to the BSSs that belong + * to the specified band while deciding whether a better BSS is reported + * using @relative_rssi. If delta is a negative number, the BSSs that + * belong to the specified band will be penalized by delta dB in relative + * comparisions. */ struct cfg80211_sched_scan_request { struct cfg80211_ssid *ssids; @@ -1622,6 +1644,10 @@ struct cfg80211_sched_scan_request { u8 mac_addr[ETH_ALEN] __aligned(2); u8 mac_addr_mask[ETH_ALEN] __aligned(2); + bool relative_rssi_set; + s8 relative_rssi; + struct cfg80211_bss_select_adjust rssi_adjust; + /* internal */ struct wiphy *wiphy; struct net_device *dev; @@ -1907,6 +1933,22 @@ struct cfg80211_ibss_params { }; /** + * struct cfg80211_bss_selection - connection parameters for BSS selection. + * + * @behaviour: requested BSS selection behaviour. + * @param: parameters for requestion behaviour. + * @band_pref: preferred band for %NL80211_BSS_SELECT_ATTR_BAND_PREF. + * @adjust: parameters for %NL80211_BSS_SELECT_ATTR_RSSI_ADJUST. + */ +struct cfg80211_bss_selection { + enum nl80211_bss_select_attr behaviour; + union { + enum ieee80211_band band_pref; + struct cfg80211_bss_select_adjust adjust; + } param; +}; + +/** * struct cfg80211_connect_params - Connection parameters * * This structure provides information needed to complete IEEE 802.11 @@ -1943,6 +1985,7 @@ struct cfg80211_ibss_params { * @vht_capa_mask: The bits of vht_capa which are to be used. * @pbss: if set, connect to a PCP instead of AP. Valid for DMG * networks. + * @bss_select: criteria to be used for BSS selection. * @prev_bssid: previous BSSID, if not %NULL use reassociate frame */ struct cfg80211_connect_params { @@ -1967,6 +2010,7 @@ struct cfg80211_connect_params { struct ieee80211_vht_cap vht_capa; struct ieee80211_vht_cap vht_capa_mask; bool pbss; + struct cfg80211_bss_selection bss_select; const u8 *prev_bssid; }; @@ -3284,6 +3328,9 @@ struct wiphy_iftype_ext_capab { * low rssi when a frame is heard on different channel, then it should set * this variable to the maximal offset for which it can compensate. * This value should be set in MHz. + * @bss_select_support: bitmask indicating the BSS selection criteria supported + * by the driver in the .connect() callback. The bit position maps to the + * attribute indices defined in &enum nl80211_bss_select_attr. */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -3411,6 +3458,8 @@ struct wiphy { u8 max_num_csa_counters; u8 max_adj_channel_rssi_comp; + u32 bss_select_support; + char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index 24f1e7c7b742..3bd8bea8ae0d 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -125,6 +125,12 @@ DESTINATION SCALER FLAG CONFIGURATION */ #define MDP_DESTSCALER_ENHANCER_UPDATE 0x4 +/* + * Indicating a partial update to panel ROI. ROI can be + * applied anytime when Destination scaler is enabled. + */ +#define MDP_DESTSCALER_ROI_ENABLE 0x8 + /********************************************************************** VALIDATE/COMMIT FLAG CONFIGURATION **********************************************************************/ @@ -405,6 +411,12 @@ struct mdp_destination_scaler_data { * A userspace pointer points to struct mdp_scale_data_v2. */ uint64_t __user scale; + + /* + * Panel ROI is used when partial update is required in + * current commit call. + */ + struct mdp_rect panel_roi; }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 335b331cbf4f..0505b1f9872b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1934,6 +1934,20 @@ enum nl80211_commands { * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also * used in various commands/events for specifying the BSSID. * + * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which + * other BSSs has to be better or slightly worse than the current + * connected BSS so that they get reported to user space. + * This will give an opportunity to userspace to consider connecting to + * other matching BSSs which have better or slightly worse RSSI than + * the current connected BSS by using an offloaded operation to avoid + * unnecessary wakeups. + * + * @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in + * the specified band is to be adjusted before doing + * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out + * better BSSs. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2340,6 +2354,9 @@ enum nl80211_attrs { NL80211_ATTR_BSSID, + NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, + NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3008,6 +3025,13 @@ enum nl80211_reg_rule_attr { * how this API was implemented in the past. Also, due to the same problem, * the only way to create a matchset with only an RSSI filter (with this * attribute) is if there's only a single matchset with the RSSI attribute. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether + * %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or + * relative to current bss's RSSI. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for + * BSS-es in the specified band is to be adjusted before doing + * RSSI-based BSS selection. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter * attribute number currently defined * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use @@ -3017,6 +3041,8 @@ enum nl80211_sched_scan_match_attr { NL80211_SCHED_SCAN_MATCH_ATTR_SSID, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, + NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI, + NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST, /* keep last */ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, @@ -4609,6 +4635,9 @@ enum nl80211_feature_flags { * in @NL80211_CMD_FRAME while not associated. * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports * randomized TA in @NL80211_CMD_FRAME while associated. + * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan + * for reporting BSSs with better RSSI than the current connected BSS + * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI). * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -4626,6 +4655,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_FILS_STA, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED, + NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -4875,4 +4905,48 @@ enum nl80211_sched_scan_plan { __NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1 }; +/** + * struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters. + * + * @band: band of BSS that must match for RSSI value adjustment. + * @delta: value used to adjust the RSSI value of matching BSS. + */ +struct nl80211_bss_select_rssi_adjust { + __u8 band; + __s8 delta; +} __attribute__((packed)); + +/** + * enum nl80211_bss_select_attr - attributes for bss selection. + * + * @__NL80211_BSS_SELECT_ATTR_INVALID: reserved. + * @NL80211_BSS_SELECT_ATTR_RSSI: Flag indicating only RSSI-based BSS selection + * is requested. + * @NL80211_BSS_SELECT_ATTR_BAND_PREF: attribute indicating BSS + * selection should be done such that the specified band is preferred. + * When there are multiple BSS-es in the preferred band, the driver + * shall use RSSI-based BSS selection as a second step. The value of + * this attribute is according to &enum nl80211_band (u32). + * @NL80211_BSS_SELECT_ATTR_RSSI_ADJUST: When present the RSSI level for + * BSS-es in the specified band is to be adjusted before doing + * RSSI-based BSS selection. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. + * @NL80211_BSS_SELECT_ATTR_MAX: highest bss select attribute number. + * @__NL80211_BSS_SELECT_ATTR_AFTER_LAST: internal use. + * + * One and only one of these attributes are found within %NL80211_ATTR_BSS_SELECT + * for %NL80211_CMD_CONNECT. It specifies the required BSS selection behaviour + * which the driver shall use. + */ +enum nl80211_bss_select_attr { + __NL80211_BSS_SELECT_ATTR_INVALID, + NL80211_BSS_SELECT_ATTR_RSSI, + NL80211_BSS_SELECT_ATTR_BAND_PREF, + NL80211_BSS_SELECT_ATTR_RSSI_ADJUST, + + /* keep last */ + __NL80211_BSS_SELECT_ATTR_AFTER_LAST, + NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c52655581c4c..ac4c3f1d144a 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7940,10 +7940,11 @@ static int detach_tasks(struct lb_env *env) if (env->imbalance <= 0) return 0; + if (!same_cluster(env->dst_cpu, env->src_cpu)) + env->flags |= LBF_IGNORE_PREFERRED_CLUSTER_TASKS; + if (cpu_capacity(env->dst_cpu) < cpu_capacity(env->src_cpu)) env->flags |= LBF_IGNORE_BIG_TASKS; - else if (!same_cluster(env->dst_cpu, env->src_cpu)) - env->flags |= LBF_IGNORE_PREFERRED_CLUSTER_TASKS; redo: while (!list_empty(tasks)) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index d3873333c766..a2a87c3ad44e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -178,7 +178,7 @@ extern int no_unaligned_warning; #define SYSCTL_WRITES_WARN 0 #define SYSCTL_WRITES_STRICT 1 -static int sysctl_writes_strict = SYSCTL_WRITES_WARN; +static int sysctl_writes_strict = SYSCTL_WRITES_STRICT; static int proc_do_cad_pid(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d41925306d75..c42587d02190 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1754,13 +1754,25 @@ static void unreserve_highatomic_pageblock(const struct alloc_context *ac) struct page, lru); /* - * It should never happen but changes to locking could - * inadvertently allow a per-cpu drain to add pages - * to MIGRATE_HIGHATOMIC while unreserving so be safe - * and watch for underflows. + * In page freeing path, migratetype change is racy so + * we can counter several free pages in a pageblock + * in this loop althoug we changed the pageblock type + * from highatomic to ac->migratetype. So we should + * adjust the count once. */ - zone->nr_reserved_highatomic -= min(pageblock_nr_pages, - zone->nr_reserved_highatomic); + if (get_pageblock_migratetype(page) == + MIGRATE_HIGHATOMIC) { + /* + * It should never happen but changes to + * locking could inadvertently allow a per-cpu + * drain to add pages to MIGRATE_HIGHATOMIC + * while unreserving so be safe and watch for + * underflows. + */ + zone->nr_reserved_highatomic -= min( + pageblock_nr_pages, + zone->nr_reserved_highatomic); + } /* * Convert to ac->migratetype and avoid the normal @@ -1802,7 +1814,8 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype) page = list_entry(area->free_list[fallback_mt].next, struct page, lru); - if (can_steal) + if (can_steal && + get_pageblock_migratetype(page) != MIGRATE_HIGHATOMIC) steal_suitable_fallback(zone, page, start_migratetype); /* Remove the page from the freelists */ @@ -2240,7 +2253,8 @@ int __isolate_free_page(struct page *page, unsigned int order) struct page *endpage = page + (1 << order) - 1; for (; page < endpage; page += pageblock_nr_pages) { int mt = get_pageblock_migratetype(page); - if (!is_migrate_isolate(mt) && !is_migrate_cma(mt)) + if (!is_migrate_isolate(mt) && !is_migrate_cma(mt) + && mt != MIGRATE_HIGHATOMIC) set_pageblock_migratetype(page, MIGRATE_MOVABLE); } diff --git a/net/wireless/core.c b/net/wireless/core.c index 16043faba52c..14868e42f3ca 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -619,6 +619,13 @@ int wiphy_register(struct wiphy *wiphy) !rdev->ops->set_mac_acl))) return -EINVAL; + /* assure only valid behaviours are flagged by driver + * hence subtract 2 as bit 0 is invalid. + */ + if (WARN_ON(wiphy->bss_select_support && + (wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2)))) + return -EINVAL; + if (wiphy->addresses) memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2d71cafde513..5ec8e5cf8a8e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -402,7 +402,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, [NL80211_ATTR_PBSS] = { .type = NLA_FLAG }, + [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED }, [NL80211_ATTR_BSSID] = { .len = ETH_ALEN }, + [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 }, + [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = { + .len = sizeof(struct nl80211_bss_select_rssi_adjust) + }, }; /* policy for the key attributes */ @@ -487,6 +492,15 @@ nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = { [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 }, }; +static const struct nla_policy +nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = { + [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG }, + [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 }, + [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = { + .len = sizeof(struct nl80211_bss_select_rssi_adjust) + }, +}; + static int nl80211_prepare_wdev_dump(struct sk_buff *skb, struct netlink_callback *cb, struct cfg80211_registered_device **rdev, @@ -1778,6 +1792,25 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, } } + if (rdev->wiphy.bss_select_support) { + struct nlattr *nested; + u32 bss_select_support = rdev->wiphy.bss_select_support; + + nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT); + if (!nested) + goto nla_put_failure; + + i = 0; + while (bss_select_support) { + if ((bss_select_support & 1) && + nla_put_flag(msg, i)) + goto nla_put_failure; + i++; + bss_select_support >>= 1; + } + nla_nest_end(msg, nested); + } + /* done */ state->split_start = 0; break; @@ -6087,6 +6120,73 @@ static int validate_scan_freqs(struct nlattr *freqs) return n_channels; } +static bool is_band_valid(struct wiphy *wiphy, enum ieee80211_band b) +{ + return b < IEEE80211_NUM_BANDS && wiphy->bands[b]; +} + +static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy, + struct cfg80211_bss_selection *bss_select) +{ + struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1]; + struct nlattr *nest; + int err; + bool found = false; + int i; + + /* only process one nested attribute */ + nest = nla_data(nla); + if (!nla_ok(nest, nla_len(nest))) + return -EINVAL; + + err = nla_parse(attr, NL80211_BSS_SELECT_ATTR_MAX, nla_data(nest), + nla_len(nest), nl80211_bss_select_policy); + if (err) + return err; + + /* only one attribute may be given */ + for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) { + if (attr[i]) { + if (found) + return -EINVAL; + found = true; + } + } + + bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID; + + if (attr[NL80211_BSS_SELECT_ATTR_RSSI]) + bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI; + + if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) { + bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF; + bss_select->param.band_pref = + nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]); + if (!is_band_valid(wiphy, bss_select->param.band_pref)) + return -EINVAL; + } + + if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) { + struct nl80211_bss_select_rssi_adjust *adj_param; + + adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]); + bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST; + bss_select->param.adjust.band = adj_param->band; + bss_select->param.adjust.delta = adj_param->delta; + if (!is_band_valid(wiphy, bss_select->param.adjust.band)) + return -EINVAL; + } + + /* user-space did not provide behaviour attribute */ + if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID) + return -EINVAL; + + if (!(wiphy->bss_select_support & BIT(bss_select->behaviour))) + return -EINVAL; + + return 0; +} + static int nl80211_parse_random_mac(struct nlattr **attrs, u8 *mac_addr, u8 *mac_addr_mask) { @@ -6557,6 +6657,12 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, if (!n_plans || n_plans > wiphy->max_sched_scan_plans) return ERR_PTR(-EINVAL); + if (!wiphy_ext_feature_isset( + wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) && + (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] || + attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST])) + return ERR_PTR(-EINVAL); + request = kzalloc(sizeof(*request) + sizeof(*request->ssids) * n_ssids + sizeof(*request->match_sets) * n_match_sets @@ -6762,6 +6868,26 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, request->delay = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]); + if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) { + request->relative_rssi = nla_get_s8( + attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]); + request->relative_rssi_set = true; + } + + if (request->relative_rssi_set && + attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) { + struct nl80211_bss_select_rssi_adjust *rssi_adjust; + + rssi_adjust = nla_data( + attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]); + request->rssi_adjust.band = rssi_adjust->band; + request->rssi_adjust.delta = rssi_adjust->delta; + if (!is_band_valid(wiphy, request->rssi_adjust.band)) { + err = -EINVAL; + goto out_free; + } + } + err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs); if (err) goto out_free; @@ -8349,6 +8475,21 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) return -EOPNOTSUPP; } + if (info->attrs[NL80211_ATTR_BSS_SELECT]) { + /* bss selection makes no sense if bssid is set */ + if (connect.bssid) { + kzfree(connkeys); + return -EINVAL; + } + + err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT], + wiphy, &connect.bss_select); + if (err) { + kzfree(connkeys); + return err; + } + } + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); wdev_unlock(dev->ieee80211_ptr); @@ -9245,6 +9386,20 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg, if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay)) return -ENOBUFS; + if (req->relative_rssi_set) { + struct nl80211_bss_select_rssi_adjust rssi_adjust; + + if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, + req->relative_rssi)) + return -ENOBUFS; + + rssi_adjust.band = req->rssi_adjust.band; + rssi_adjust.delta = req->rssi_adjust.delta; + if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, + sizeof(rssi_adjust), &rssi_adjust)) + return -ENOBUFS; + } + freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); if (!freqs) return -ENOBUFS; diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c index 58eb30c39764..5dc5bf9d1b3c 100644 --- a/sound/soc/msm/sdm660-common.c +++ b/sound/soc/msm/sdm660-common.c @@ -2864,10 +2864,12 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) ret = -EPROBE_DEFER; goto err; } - ret = msm_init_wsa_dev(pdev, card); - if (ret) - goto err; + if (!of_property_read_bool(pdev->dev.of_node, "qcom,wsa-disable")) { + ret = msm_init_wsa_dev(pdev, card); + if (ret) + goto err; + } ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret == -EPROBE_DEFER) { diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c index 0460d7f9fc68..3fe327ad0442 100644 --- a/sound/soc/msm/sdm660-external.c +++ b/sound/soc/msm/sdm660-external.c @@ -48,8 +48,8 @@ #define TLMM_LPI_GPIO22_CFG 0x15078040 #define LPI_GPIO22_CFG_VAL 0x0000009 -#define TLMM_LPI_GPIO22_INOUT 0x15078044 -#define LPI_GPIO22_INOUT_VAL 0x00000000 +#define TLMM_LPI_GPIO22_INOUT 0x179D1318 +#define LPI_GPIO22_INOUT_VAL 0x0020000 #define WSA8810_NAME_1 "wsa881x.20170211" #define WSA8810_NAME_2 "wsa881x.20170212" @@ -1227,8 +1227,9 @@ static void msm_snd_interrupt_config(struct msm_asoc_mach_data *pdata) pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg); iowrite32(LPI_GPIO22_CFG_VAL, pdata->msm_snd_intr_lpi.lpi_gpio_cfg); - iowrite32(LPI_GPIO22_INOUT_VAL, - pdata->msm_snd_intr_lpi.lpi_gpio_inout); + val = ioread32(pdata->msm_snd_intr_lpi.lpi_gpio_inout); + val |= LPI_GPIO22_INOUT_VAL; + iowrite32(val, pdata->msm_snd_intr_lpi.lpi_gpio_inout); } static int msm_adsp_power_up_config(struct snd_soc_codec *codec) @@ -1511,6 +1512,17 @@ int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) 134, 135, 136, 137, 138, 139, 140, 141, 142, 143}; + /* Tavil Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148, + 149, 150, 151}; + unsigned int tx_ch_tavil[WCD934X_TX_MAX] = {128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143}; + pr_debug("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev)); rtd->pmdown_time = 0; @@ -1571,14 +1583,11 @@ int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_ignore_suspend(dapm, "EAR"); snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1"); snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2"); - snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3"); - snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4"); snd_soc_dapm_ignore_suspend(dapm, "AMIC1"); snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); snd_soc_dapm_ignore_suspend(dapm, "AMIC3"); snd_soc_dapm_ignore_suspend(dapm, "AMIC4"); snd_soc_dapm_ignore_suspend(dapm, "AMIC5"); - snd_soc_dapm_ignore_suspend(dapm, "AMIC6"); snd_soc_dapm_ignore_suspend(dapm, "DMIC0"); snd_soc_dapm_ignore_suspend(dapm, "DMIC1"); snd_soc_dapm_ignore_suspend(dapm, "DMIC2"); @@ -1586,21 +1595,33 @@ int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_ignore_suspend(dapm, "DMIC4"); snd_soc_dapm_ignore_suspend(dapm, "DMIC5"); snd_soc_dapm_ignore_suspend(dapm, "ANC EAR"); - snd_soc_dapm_ignore_suspend(dapm, "ANC HEADPHONE"); snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT"); snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT"); snd_soc_dapm_ignore_suspend(dapm, "HPHL"); snd_soc_dapm_ignore_suspend(dapm, "HPHR"); - snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL"); - snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR"); - snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1"); - snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2"); snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI"); snd_soc_dapm_ignore_suspend(dapm, "VIINPUT"); + if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) { + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1"); + snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2"); + } + snd_soc_dapm_sync(dapm); - snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), - tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + + if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) { + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch_tavil), + tx_ch_tavil, ARRAY_SIZE(rx_ch_tavil), + rx_ch_tavil); + } else { + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), + rx_ch); + } if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) { msm_codec_fn.get_afe_config_fn = tavil_get_afe_config; diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c index c002399beb6b..805ff2335b42 100644 --- a/sound/soc/msm/sdm660-internal.c +++ b/sound/soc/msm/sdm660-internal.c @@ -2227,21 +2227,6 @@ static struct snd_soc_dai_link msm_int_dai[] = { .codec_name = "snd-soc-dummy", }, {/* hw:x,35 */ - .name = LPASS_BE_INT5_MI2S_TX, - .stream_name = "INT5 MI2S Capture", - .cpu_dai_name = "msm-dai-q6-mi2s.12", - .platform_name = "msm-pcm-hostless", - .codec_name = "msm_sdw_codec", - .codec_dai_name = "msm_sdw_vifeedback", - .be_id = MSM_BACKEND_DAI_INT5_MI2S_TX, - .be_hw_params_fixup = int_mi2s_be_hw_params_fixup, - .ops = &msm_sdw_mi2s_be_ops, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .dpcm_capture = 1, - .ignore_pmdown_time = 1, - }, - {/* hw:x,36 */ .name = "Primary MI2S_RX Hostless", .stream_name = "Primary MI2S_RX Hostless", .cpu_dai_name = "PRI_MI2S_RX_HOSTLESS", @@ -2258,7 +2243,7 @@ static struct snd_soc_dai_link msm_int_dai[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, - {/* hw:x,37 */ + {/* hw:x,36 */ .name = "Secondary MI2S_RX Hostless", .stream_name = "Secondary MI2S_RX Hostless", .cpu_dai_name = "SEC_MI2S_RX_HOSTLESS", @@ -2275,7 +2260,7 @@ static struct snd_soc_dai_link msm_int_dai[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, - {/* hw:x,38 */ + {/* hw:x,37 */ .name = "Tertiary MI2S_RX Hostless", .stream_name = "Tertiary MI2S_RX Hostless", .cpu_dai_name = "TERT_MI2S_RX_HOSTLESS", @@ -2292,7 +2277,7 @@ static struct snd_soc_dai_link msm_int_dai[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, - {/* hw:x,39 */ + {/* hw:x,38 */ .name = "INT0 MI2S_RX Hostless", .stream_name = "INT0 MI2S_RX Hostless", .cpu_dai_name = "INT0_MI2S_RX_HOSTLESS", @@ -2309,6 +2294,28 @@ static struct snd_soc_dai_link msm_int_dai[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, +}; + + +static struct snd_soc_dai_link msm_int_wsa_dai[] = { + {/* hw:x,39 */ + .name = LPASS_BE_INT5_MI2S_TX, + .stream_name = "INT5_mi2s Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.12", + .platform_name = "msm-pcm-hostless", + .codec_name = "msm_sdw_codec", + .codec_dai_name = "msm_sdw_vifeedback", + .be_id = MSM_BACKEND_DAI_INT5_MI2S_TX, + .be_hw_params_fixup = int_mi2s_be_hw_params_fixup, + .ops = &msm_sdw_mi2s_be_ops, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + }, +}; + +static struct snd_soc_dai_link msm_int_be_dai[] = { /* Backend I2S DAI Links */ { .name = LPASS_BE_INT0_MI2S_RX, @@ -2344,21 +2351,6 @@ static struct snd_soc_dai_link msm_int_dai[] = { .ignore_suspend = 1, }, { - .name = LPASS_BE_INT4_MI2S_RX, - .stream_name = "INT4 MI2S Playback", - .cpu_dai_name = "msm-dai-q6-mi2s.11", - .platform_name = "msm-pcm-routing", - .codec_name = "msm_sdw_codec", - .codec_dai_name = "msm_sdw_i2s_rx1", - .no_pcm = 1, - .dpcm_playback = 1, - .be_id = MSM_BACKEND_DAI_INT4_MI2S_RX, - .init = &msm_sdw_audrx_init, - .be_hw_params_fixup = int_mi2s_be_hw_params_fixup, - .ops = &msm_sdw_mi2s_be_ops, - .ignore_suspend = 1, - }, - { .name = LPASS_BE_INT2_MI2S_TX, .stream_name = "INT2 MI2S Capture", .cpu_dai_name = "msm-dai-q6-mi2s.9", @@ -2898,11 +2890,32 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { }, }; +static struct snd_soc_dai_link msm_wsa_be_dai_links[] = { + { + .name = LPASS_BE_INT4_MI2S_RX, + .stream_name = "INT4 MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.11", + .platform_name = "msm-pcm-routing", + .codec_name = "msm_sdw_codec", + .codec_dai_name = "msm_sdw_i2s_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_INT4_MI2S_RX, + .init = &msm_sdw_audrx_init, + .be_hw_params_fixup = int_mi2s_be_hw_params_fixup, + .ops = &msm_sdw_mi2s_be_ops, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_int_dai_links[ ARRAY_SIZE(msm_int_dai) + +ARRAY_SIZE(msm_int_wsa_dai) + +ARRAY_SIZE(msm_int_be_dai) + ARRAY_SIZE(msm_mi2s_be_dai_links) + ARRAY_SIZE(msm_auxpcm_be_dai_links)+ -ARRAY_SIZE(msm_wcn_be_dai_links)]; +ARRAY_SIZE(msm_wcn_be_dai_links) + +ARRAY_SIZE(msm_wsa_be_dai_links)]; static struct snd_soc_card sdm660_card = { /* snd_soc_card_sdm660 */ @@ -2965,6 +2978,16 @@ static struct snd_soc_card *msm_int_populate_sndcard_dailinks( len1 = ARRAY_SIZE(msm_int_dai); memcpy(msm_int_dai_links, msm_int_dai, sizeof(msm_int_dai)); dailink = msm_int_dai_links; + if (!of_property_read_bool(dev->of_node, + "qcom,wsa-disable")) { + memcpy(dailink + len1, + msm_int_wsa_dai, + sizeof(msm_int_wsa_dai)); + len1 += ARRAY_SIZE(msm_int_wsa_dai); + } + memcpy(dailink + len1, msm_int_be_dai, sizeof(msm_int_be_dai)); + len1 += ARRAY_SIZE(msm_int_be_dai); + if (of_property_read_bool(dev->of_node, "qcom,mi2s-audio-intf")) { memcpy(dailink + len1, @@ -2987,6 +3010,12 @@ static struct snd_soc_card *msm_int_populate_sndcard_dailinks( sizeof(msm_wcn_be_dai_links)); len1 += ARRAY_SIZE(msm_wcn_be_dai_links); } + if (!of_property_read_bool(dev->of_node, "qcom,wsa-disable")) { + memcpy(dailink + len1, + msm_wsa_be_dai_links, + sizeof(msm_wsa_be_dai_links)); + len1 += ARRAY_SIZE(msm_wsa_be_dai_links); + } card->dai_link = dailink; card->num_links = len1; return card; |
