Merge "xhci-plat: Use correct dev to get usb-phy handle"
diff --git a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
index 105dcac..30961be 100644
--- a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
@@ -7,7 +7,7 @@
Required Properties:
- compatible: The bus devices need to be compatible with
"qcom,mdm2-modem", "qcom,ext-mdm9x25", "qcom,ext-mdm9x35", "qcom, ext-mdm9x45",
- "qcom,ext-mdm9x55".
+ "qcom,ext-mdm9x55", "qcom,ext-sdxpoorwills".
Required named gpio properties:
- qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt b/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt
new file mode 100644
index 0000000..28f6e7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt
@@ -0,0 +1,63 @@
+Msm Machine Name
+
+Machine name is used to:
+ 1. show up in the beginning of kernel message.
+ Example:
+ [ 0.000000] Machine: Qualcomm Technologies, Inc. MSM8953 PMI8950 MTP
+ 2. show up as arch description when do dump stack.
+ Example:
+ [ 1.222319] WARNING: CPU: 2 PID: 1 at kernel/lib/debugobjects.c:263 debug_print_object+0xa8/0xb0
+ [ 1.222334] Modules linked in:
+ [ 1.222362] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.9.65+ #71
+ [ 1.222376] Hardware name: Qualcomm Technologies, Inc. MSM8953 PMI8950 MTP (DT)
+ [ 1.222392] task: ffffffc0ed1b0080 task.stack: ffffffc0ed1b8000
+ [ 1.222408] PC is at debug_print_object+0xa8/0xb0
+ [ 1.222424] LR is at debug_print_object+0xa8/0xb0
+
+Msm machine name is a string concatenated from:
+ 1. constant string contain msm information: "Qualcomm Technologies, Inc.".
+ 2. string of device tree property "qcom,msm-name".
+ 3. string of device tree property "qcom,pmic-name".
+ 4. string of device tree property "model".
+
+The reason for using msm machine Name is single board overlay device tree
+may applied to multiple soc device trees. The "model" property in soc device
+tree is overwritten with board overlay device tree. So the final string in
+"model" property can only contain Board information. And "qcom,msm-name"
+and "qcom,pmic-name" property is introduced.
+
+Optional properties:
+- qcom,msm-name: The name string of MSM SoC chip
+- qcom,pmic-name: The name string of MSM Pmic chip
+
+Required properties:
+- model: in soc device tree
+ Contain the soc and pmic information.
+ Will be overwritten by model string in board overlay device tree.
+ It will be used in bootloader for debug purpose.
+- model: in board overlay device tree
+ Contain the board information. It is the final model string that
+ kernel can see.
+
+Note:
+When device tree property qcom,msm-name and qcom,pmic-name exist, it will
+use concatenated msm machine name string for final machine name.
+When device tree property qcom,msm-name and qcom,pmic-name doesn't exist,
+it will use model property string for final machine name.
+
+Example:
+* In soc device tree:
+ / {
+ model = "Qualcomm Technologies, Inc. APQ 8953 + PMI8950 SOC";
+ compatible = "qcom,apq8053";
+ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+ qcom,pmic-name = "PMI8950";
+ qcom,msm-id = <293 0x0>;
+ qcom,msm-name = "APQ8053";
+ };
+* In board overlay device tree:
+ / {
+ model = "MTP";
+ compatible = "qcom,mtp";
+ };
+
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index b3d4d44..9bc8168 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -110,6 +110,12 @@
- SDM450
compatible = "qcom,sdm450"
+- SDM632
+ compatible = "qcom,sdm632"
+
+- SDA632
+ compatible = "qcom,sda632"
+
- MSM8937
compatible = "qcom,msm8937"
@@ -321,6 +327,7 @@
compatible = "qcom,sdm450-mtp"
compatible = "qcom,sdm450-cdp"
compatible = "qcom,sdm450-qrd"
+compatible = "qcom,sdm632-rumi"
compatible = "qcom,mdm9640-cdp"
compatible = "qcom,mdm9640-mtp"
compatible = "qcom,mdm9640-rumi"
diff --git a/Documentation/devicetree/bindings/cnss/cnss-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt
new file mode 100644
index 0000000..9dff08d
--- /dev/null
+++ b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt
@@ -0,0 +1,75 @@
+* Qualcomm Technologies, Inc. ConNectivity SubSystem Platform Driver
+
+This platform driver adds support for the CNSS subsystem used for PCIe
+based Wi-Fi devices. It also adds support to integrate PCIe WLAN module
+to subsystem restart framework. Apart from that, it also manages the
+3.3V voltage regulator, WLAN Enable GPIO signal and PCIe link dynamically
+with support for suspend and resume by retaining the PCI config space
+states when PCIe link is shutdown. The main purpose of this device tree
+entry below is to invoke the CNSS platform driver and provide handle to
+the WLAN enable GPIO, 3.3V fixed voltage regulator resources. It also
+provides the reserved RAM dump memory location and size.
+
+Required properties:
+ - compatible: "qcom,cnss" for QCA6174 device
+ "qcom,cnss-qca6290" for QCA6290 device
+ - wlan-en-gpio: WLAN_EN GPIO signal specified by the chip specifications
+ - vdd-wlan-supply: phandle to the regulator device tree node
+ - pinctrl-names: Names corresponding to the numbered pinctrl states
+ - pinctrl-<n>: Pinctrl states as described in
+ bindings/pinctrl/pinctrl-bindings.txt
+ - qcom,wlan-rc-num: PCIe root complex number which WLAN chip is attached to
+
+Optional properties:
+ - qcom,notify-modem-status: Boolean property to decide whether modem
+ notification should be enabled or not in this
+ platform
+ - wlan-soc-swreg-supply: phandle to the external 1.15V regulator for QCA6174
+ - wlan-ant-switch-supply: phandle to the 2.7V regulator for the antenna
+ switch of QCA6174
+ - qcom,wlan-uart-access: Boolean property to decide whether QCA6174
+ has exclusive access to UART.
+ - vdd-wlan-io-supply: phandle to the 1.8V IO regulator for QCA6174
+ - vdd-wlan-xtal-supply: phandle to the 1.8V XTAL regulator for QCA6174
+ - vdd-wlan-xtal-aon-supply: phandle to the LDO-4 regulator. This is needed
+ on platforms where XTAL regulator depends on
+ always on regulator in VDDmin.
+ - vdd-wlan-core-supply: phandle to the 1.3V CORE regulator for QCA6174
+ - vdd-wlan-sp2t-supply: phandle to the 2.7V SP2T regulator for QCA6174
+ - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
+ format to be used for allocations associated
+ between WLAN/PCIe and SMMU
+ - qcom,wlan-ramdump-dynamic: To enable CNSS RAMDUMP collection
+ by providing the size of CNSS DUMP
+ - reg: Memory regions defined as starting address and size
+ - reg-names: Names of the memory regions defined in reg entry
+ - wlan-bootstrap-gpio: WLAN_BOOTSTRAP GPIO signal specified by QCA6174
+ which should be drived depending on platforms
+ - qcom,is-dual-wifi-enabled: Boolean property to control wlan enable(wlan-en)
+ gpio on dual-wifi platforms.
+ - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174
+ specifications.
+ - qcom,wlan-en-vreg-support: Boolean property to decide the whether the
+ WLAN_EN pin is a gpio or fixed regulator.
+ - qcom,mhi: phandle to indicate the device which needs MHI support.
+ - qcom,cap-tsf-gpio: WLAN_TSF_CAPTURED GPIO signal specified by the chip
+ specifications, should be drived depending on products
+
+Example:
+
+ qcom,cnss@0d400000 {
+ compatible = "qcom,cnss";
+ reg = <0x0d400000 0x200000>;
+ reg-names = "ramdump";
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+ wlan-en-gpio = <&msmgpio 82 0>;
+ vdd-wlan-supply = <&wlan_vreg>;
+ qcom,notify-modem-status;
+ wlan-soc-swreg-supply = <&pma8084_l27>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cnss_default>;
+ qcom,wlan-rc-num = <0>;
+ qcom,wlan-smmu-iova-address = <0 0x10000000>;
+ qcom,mhi = <&mhi_wlan>;
+ qcom,cap-tsf-gpio = <&tlmm 126 1>;
+ };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index 42e97f7..c7268ef 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -80,6 +80,13 @@
or disabled.
- qcom,auto-calibration-enable : A boolean property which enables auto-calibration
of the WLED sink configuration.
+- qcom,wled-brightness-map : Array of brightness map codes of size 256.
+ These codes will be mapped to the brightness
+ level requested in the scale of 0-4095. Code
+ entry is of 16 bit size.
+- qcom,wled-stepper-en : A boolean property to specify if stepper algorithm
+ needs to be enabled. This needs the brightness map
+ table to be specified.
Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
- qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320.
@@ -123,4 +130,5 @@
qcom,en-phase-stag;
qcom,led-strings-list = [00 01 02 03];
qcom,en-ext-pfet-sc-pro;
+ qcom,wled-brightness-map = /bits/ 16 <0 . . 4095>;
};
diff --git a/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt
new file mode 100644
index 0000000..5bb85a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt
@@ -0,0 +1,25 @@
+GPIO USB VBUS Detection
+
+Discrete USB VBUS detection circuitry can be connected to the AP or PMICs.
+Such circuits can be used to detect the when a USB cable is connected to
+an upstream port such as a standard host or a wall charger by detecting
+the presence of VBUS voltage. The GPIO can be configured to trigger an
+interrupt, and allow the software driver to in turn notify the USB
+subsytem using the power_supply framework.
+
+Required Properties:
+ - compatible: must be "qcom,gpio-usbdetect"
+ - qcom,vbus-det-gpio: GPIO from which VBUS detection can be read from.
+ - interrupts: an interrupt triggered by the output of the detection circuit
+ - interrupt-names: must be "vbus_det_irq"
+
+Optional Properties:
+ - vin-supply: phandle to a regulator that powers this circuit, if needed
+
+Example:
+
+ usb_detect {
+ compatible = "qcom,gpio-usbdetect";
+ qcom,vbus-det-gpio = <&pm8084 2 0>;
+ vin-supply = <&vbus_det_reg>;
+ };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi
new file mode 100644
index 0000000..0b94534
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
+
+&soc {
+ pcie0: qcom,pcie@1c00000 {
+ compatible = "qcom,pci-msm";
+ cell-index = <0>;
+
+ reg = <0x01c00000 0x2000>,
+ <0x01c02000 0x1000>,
+ <0x40000000 0xf1d>,
+ <0x40000f20 0xa8>,
+ <0x40001000 0x1000>,
+ <0x40100000 0x100000>,
+ <0x40200000 0x100000>,
+ <0x40300000 0x1d00000>,
+ <0x01fce008 0x4>;
+
+ reg-names = "parf", "phy", "dm_core", "elbi", "iatu",
+ "conf", "io", "bars", "tcsr";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>,
+ <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1d00000>;
+ interrupt-parent = <&pcie0>;
+ interrupts = <0 1 2 3 4 5>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0xffffffff>;
+ interrupt-map = <0 0 0 0 &intc 0 119 0
+ 0 0 0 1 &intc 0 141 0
+ 0 0 0 2 &intc 0 142 0
+ 0 0 0 3 &intc 0 143 0
+ 0 0 0 4 &intc 0 144 0
+ 0 0 0 5 &intc 0 140 0>;
+
+ interrupt-names = "int_msi", "int_a", "int_b", "int_c",
+ "int_d", "int_global_int";
+
+ qcom,phy-sequence = <0x840 0x03 0x0
+ 0x094 0x08 0x0
+ 0x154 0x33 0x0
+ 0x058 0x0f 0x0
+ 0x0a4 0x42 0x0
+ 0x1bc 0x11 0x0
+ 0x0bc 0x82 0x0
+ 0x0d4 0x03 0x0
+ 0x0d0 0x55 0x0
+ 0x0cc 0x55 0x0
+ 0x0b0 0x1a 0x0
+ 0x0ac 0x0a 0x0
+ 0x158 0x01 0x0
+ 0x074 0x06 0x0
+ 0x07c 0x16 0x0
+ 0x084 0x36 0x0
+ 0x1b0 0x1e 0x0
+ 0x1ac 0xb9 0x0
+ 0x050 0x07 0x0
+ 0x29c 0x12 0x0
+ 0x284 0x05 0x0
+ 0x234 0xd9 0x0
+ 0x238 0xcc 0x0
+ 0x51c 0x03 0x0
+ 0x518 0x1c 0x0
+ 0x524 0x14 0x0
+ 0x4ec 0x0e 0x0
+ 0x4f0 0x4a 0x0
+ 0x4f4 0x0f 0x0
+ 0x5b4 0x04 0x0
+ 0x434 0x7f 0x0
+ 0x444 0x70 0x0
+ 0x510 0x17 0x0
+ 0x4d8 0x01 0x0
+ 0x598 0xe0 0x0
+ 0x59c 0xc8 0x0
+ 0x5a0 0xc8 0x0
+ 0x5a4 0x09 0x0
+ 0x5a8 0xb1 0x0
+ 0x584 0x24 0x0
+ 0x588 0xe4 0x0
+ 0x58c 0xec 0x0
+ 0x590 0x39 0x0
+ 0x594 0x36 0x0
+ 0x570 0xef 0x0
+ 0x574 0xef 0x0
+ 0x578 0x2f 0x0
+ 0x57c 0xd3 0x0
+ 0x580 0x40 0x0
+ 0x4fc 0x00 0x0
+ 0x4f8 0xc0 0x0
+ 0x9a4 0x01 0x0
+ 0xc90 0x00 0x0
+ 0xc40 0x01 0x0
+ 0xc48 0x01 0x0
+ 0xca0 0x11 0x0
+ 0x048 0x90 0x0
+ 0xc1c 0xc1 0x0
+ 0x988 0x88 0x0
+ 0x998 0x08 0x0
+ 0x8dc 0x0d 0x0
+ 0x800 0x00 0x0
+ 0x844 0x03 0x0>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie0_clkreq_default
+ &pcie0_perst_default
+ &pcie0_wake_default>;
+
+ perst-gpio = <&tlmm 57 0>;
+ wake-gpio = <&tlmm 53 0>;
+
+ gdsc-vdd-supply = <&gdsc_pcie>;
+ vreg-1.8-supply = <&pmxpoorwills_l1>;
+ vreg-0.9-supply = <&pmxpoorwills_l4>;
+ vreg-cx-supply = <&pmxpoorwills_s5_level>;
+
+ qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>;
+ qcom,vreg-0.9-voltage-level = <872000 872000 24000>;
+ qcom,vreg-cx-voltage-level = <RPMH_REGULATOR_LEVEL_MAX
+ RPMH_REGULATOR_LEVEL_SVS 0>;
+
+ qcom,l0s-supported;
+ qcom,l1-supported;
+ qcom,l1ss-supported;
+ qcom,aux-clk-sync;
+
+ qcom,ep-latency = <10>;
+
+ qcom,slv-addr-space-size = <0x40000000>;
+
+ qcom,cpl-timeout = <0x2>;
+
+ qcom,boot-option = <0x1>;
+
+ linux,pci-domain = <0>;
+
+ qcom,use-19p2mhz-aux-clk;
+
+ qcom,msm-bus,name = "pcie0";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <45 512 0 0>,
+ <45 512 500 800>;
+
+ clocks = <&clock_gcc GCC_PCIE_PIPE_CLK>,
+ <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_PCIE_AUX_CLK>,
+ <&clock_gcc GCC_PCIE_CFG_AHB_CLK>,
+ <&clock_gcc GCC_PCIE_MSTR_AXI_CLK>,
+ <&clock_gcc GCC_PCIE_SLV_AXI_CLK>,
+ <&clock_gcc GCC_PCIE_0_CLKREF_CLK>,
+ <&clock_gcc GCC_PCIE_SLV_Q2A_AXI_CLK>,
+ <&clock_gcc GCC_PCIE_SLEEP_CLK>,
+ <&clock_gcc GCC_PCIE_PHY_REFGEN_CLK>;
+
+ clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src",
+ "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk",
+ "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+ "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk",
+ "pcie_0_sleep_clk", "pcie_phy_refgen_clk";
+
+ max-clock-frequency-hz = <0>, <0>, <0>, <0>, <0>, <0>,
+ <0>, <0>, <0>, <0>, <100000000>;
+
+ resets = <&clock_gcc GCC_PCIE_BCR>,
+ <&clock_gcc GCC_PCIE_PHY_BCR>;
+
+ reset-names = "pcie_0_core_reset",
+ "pcie_0_phy_reset";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index fa9c4f8..1e212b7 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -382,6 +382,44 @@
};
};
+ pcie0 {
+ pcie0_clkreq_default: pcie0_clkreq_default {
+ mux {
+ pins = "gpio56";
+ function = "pcie_clkreq";
+ };
+ config {
+ pins = "gpio56";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie0_perst_default: pcie0_perst_default {
+ mux {
+ pins = "gpio57";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio57";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ pcie0_wake_default: pcie0_wake_default {
+ mux {
+ pins = "gpio53";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio53";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
/* HS UART CONFIGURATION */
blsp1_uart1a: blsp1_uart1a {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 322e2cc..0fc20dd 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -67,7 +67,7 @@
#address-cells = <1>;
CPU0: cpu@0 {
- device-type = "cpu";
+ device_type = "cpu";
compatible = "arm,cortex-a7";
reg = <0x0>;
#cooling-cells = <2>;
@@ -76,6 +76,7 @@
aliases {
qpic_nand1 = &qnand_1;
+ pci-domain0 = &pcie0;
sdhc1 = &sdhc_1; /* SDC1 eMMC/SD/SDIO slot */
};
@@ -771,6 +772,14 @@
mbox-desc-offset = <0x0>;
#mbox-cells = <1>;
};
+
+ usb_detect: qcom,gpio-usbdetect {
+ compatible = "qcom,gpio-usbdetect";
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0x0d 0x0 IRQ_TYPE_NONE>;
+ interrupt-names = "vbus_det_irq";
+ status = "disabled";
+ };
};
#include "pmxpoorwills.dtsi"
@@ -778,6 +787,7 @@
#include "sdxpoorwills-regulator.dtsi"
#include "sdxpoorwills-smp2p.dtsi"
#include "sdxpoorwills-usb.dtsi"
+#include "sdxpoorwills-pcie.dtsi"
#include "sdxpoorwills-bus.dtsi"
#include "sdxpoorwills-thermal.dtsi"
#include "sdxpoorwills-audio.dtsi"
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 9d60c9e..d375cc3 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -304,6 +304,9 @@
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
@@ -325,6 +328,7 @@
CONFIG_REGULATOR_MEM_ACC=y
CONFIG_REGULATOR_MSM_GFX_LDO=y
CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 36c8651..3b6f240 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -314,6 +314,9 @@
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
@@ -335,6 +338,7 @@
CONFIG_REGULATOR_MEM_ACC=y
CONFIG_REGULATOR_MSM_GFX_LDO=y
CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 834dfb8..7a85ac6 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -309,6 +309,7 @@
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_REVID=y
+CONFIG_GPIO_USB_DETECT=y
CONFIG_USB_BAM=y
CONFIG_MSM_CLK_RPMH=y
CONFIG_MDM_GCC_SDXPOORWILLS=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 760d4d4..b4b4ba9 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -308,6 +308,7 @@
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_REVID=y
+CONFIG_GPIO_USB_DETECT=y
CONFIG_MSM_CLK_RPMH=y
CONFIG_MDM_GCC_SDXPOORWILLS=y
CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 062c484..906623e 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -22,6 +22,7 @@
extern unsigned int user_debug;
extern char* (*arch_read_hardware_id)(void);
+const char * __init arch_read_machine_name(void);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 877f461..09dd8ff 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -1174,7 +1174,7 @@
return 0;
}
-subsys_initcall(topology_init);
+postcore_initcall(topology_init);
#ifdef CONFIG_HAVE_PROC_CPU
static int __init proc_cpu_init(void)
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index b2adfb4..d4b94da 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -41,7 +41,10 @@
sda845-v2.1-qrd-overlay.dtbo \
sda845-v2.1-4k-panel-cdp-overlay.dtbo \
sda845-v2.1-4k-panel-mtp-overlay.dtbo \
- sda845-v2.1-4k-panel-qrd-overlay.dtbo
+ sda845-v2.1-4k-panel-qrd-overlay.dtbo \
+ sda845-v2.1-cdp-sdxpoorwills-overlay.dtbo \
+ sda845-v2.1-mtp-sdxpoorwills-overlay.dtbo \
+ sda845-v2-mtp-sdxpoorwills-overlay.dtbo
sdm845-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-mtp-overlay.dtbo-base := sdm845.dtb
@@ -81,6 +84,9 @@
sda845-v2.1-4k-panel-cdp-overlay.dtbo-base := sda845-v2.1.dtb
sda845-v2.1-4k-panel-mtp-overlay.dtbo-base := sda845-v2.1.dtb
sda845-v2.1-4k-panel-qrd-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-cdp-sdxpoorwills-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-mtp-sdxpoorwills-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2-mtp-sdxpoorwills-overlay.dtbo-base := sda845-v2.dtb
else
dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
sdm845-rumi.dtb \
@@ -124,6 +130,8 @@
sda670-mtp-overlay.dtbo \
sda670-pm660a-cdp-overlay.dtbo \
sda670-pm660a-mtp-overlay.dtbo \
+ sdm670-tasha-codec-cdp-overlay.dtbo \
+ sdm670-pm660a-tasha-codec-cdp-overlay.dtbo \
qcs605-cdp-overlay.dtbo \
qcs605-mtp-overlay.dtbo \
qcs605-360camera-overlay.dtbo \
@@ -149,6 +157,8 @@
sdm670-usbc-external-codec-mtp-overlay.dtbo-base := sdm670.dtb
sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-tasha-codec-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-pm660a-tasha-codec-cdp-overlay.dtbo-base := sdm670.dtb
sda670-cdp-overlay.dtbo-base := sda670.dtb
sda670-mtp-overlay.dtbo-base := sda670.dtb
sda670-pm660a-cdp-overlay.dtbo-base := sda670.dtb
@@ -181,6 +191,8 @@
sdm670-usbc-pm660a-mtp.dtb \
sda670-mtp.dtb \
sda670-cdp.dtb \
+ sdm670-tasha-codec-cdp.dtb \
+ sdm670-pm660a-tasha-codec-cdp.dtb \
sda670-pm660a-mtp.dtb \
sda670-pm660a-cdp.dtb \
qcs605-360camera.dtb \
@@ -191,6 +203,52 @@
endif
ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+dtbo-$(CONFIG_ARCH_MSM8953) += msm8953-mtp-overlay.dtbo \
+ msm8953-cdp-overlay.dtbo \
+ msm8953-rcm-overlay.dtbo \
+ msm8953-ipc-overlay.dtbo \
+ msm8953-qrd-overlay.dtbo \
+ msm8953-iot-mtp-overlay.dtbo \
+ msm8953-ext-codec-mtp-overlay.dtbo \
+ msm8953-ext-codec-rcm-overlay.dtbo \
+ msm8953-cdp-1200p-overlay.dtbo
+
+dtbo-$(CONFIG_ARCH_SDM450) += msm8953-mtp-overlay.dtbo \
+ msm8953-cdp-overlay.dtbo \
+ msm8953-rcm-overlay.dtbo \
+ msm8953-qrd-overlay.dtbo \
+ msm8953-iot-mtp-overlay.dtbo
+
+msm8953-mtp-overlay.dtbo-base := sdm450.dtb \
+ msm8953.dtb \
+ apq8053.dtb \
+ msm8953-pmi8940.dtb \
+ msm8953-pmi8937.dtb \
+ sdm450-pmi8940.dtb \
+ sdm450-pmi8937.dtb
+msm8953-cdp-overlay.dtbo-base := sdm450.dtb \
+ msm8953.dtb \
+ apq8053.dtb \
+ msm8953-pmi8940.dtb \
+ msm8953-pmi8937.dtb
+msm8953-rcm-overlay.dtbo-base := sdm450.dtb \
+ msm8953.dtb \
+ apq8053.dtb
+msm8953-ipc-overlay.dtbo-base := msm8953.dtb \
+ apq8053.dtb
+msm8953-qrd-overlay.dtbo-base := sdm450.dtb \
+ msm8953.dtb
+msm8953-iot-mtp-overlay.dtbo-base := sdm450.dtb \
+ msm8953.dtb \
+ apq8053.dtb
+msm8953-ext-codec-mtp-overlay.dtbo-base := msm8953.dtb \
+ apq8053.dtb \
+ msm8953-pmi8940.dtb \
+ msm8953-pmi8937.dtb
+msm8953-ext-codec-rcm-overlay.dtbo-base := msm8953.dtb \
+ apq8053.dtb
+msm8953-cdp-1200p-overlay.dtbo-base := msm8953.dtb
+
else
dtb-$(CONFIG_ARCH_MSM8953) += msm8953-cdp.dtb \
msm8953-mtp.dtb \
@@ -225,6 +283,9 @@
sdm450-qrd-sku4.dtb \
sdm450-pmi632-cdp-s2.dtb \
sdm450-pmi632-mtp-s3.dtb
+
+dtb-$(CONFIG_ARCH_SDM632) += sdm632-rumi.dtb
+
endif
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dts b/arch/arm64/boot/dts/qcom/apq8053.dts
new file mode 100644
index 0000000..bf9e2f2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8053.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC";
+ compatible = "qcom,apq8053";
+ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+ qcom,pmic-name = "PMI8950";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dtsi b/arch/arm64/boot/dts/qcom/apq8053.dtsi
index 15a1595..4600dc1 100644
--- a/arch/arm64/boot/dts/qcom/apq8053.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -12,9 +12,10 @@
*/
#include "msm8953.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8953";
+ model = "Qualcomm Technologies, Inc. APQ8053";
compatible = "qcom,apq8053";
qcom,msm-id = <304 0x0>;
+ qcom,msm-name = "APQ8053";
};
&secure_mem {
diff --git a/arch/arm64/boot/dts/qcom/external-soc.dtsi b/arch/arm64/boot/dts/qcom/external-soc.dtsi
new file mode 100644
index 0000000..e6609c0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/external-soc.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2017-2018, 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.
+ */
+
+&soc {
+ mdm3: qcom,mdm3 {
+ compatible = "qcom,ext-sdxpoorwills";
+ cell-index = <0>;
+ #address-cells = <0>;
+ interrupt-parent = <&mdm3>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-names =
+ "err_fatal_irq",
+ "status_irq",
+ "mdm2ap_vddmin_irq";
+ /* modem attributes */
+ qcom,ramdump-delays-ms = <2000>;
+ qcom,ramdump-timeout-ms = <120000>;
+ qcom,vddmin-modes = "normal";
+ qcom,vddmin-drive-strength = <8>;
+ qcom,sfr-query;
+ qcom,sysmon-id = <20>;
+ qcom,ssctl-instance-id = <0x10>;
+ qcom,support-shutdown;
+ qcom,pil-force-shutdown;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts
new file mode 100644
index 0000000..03ec7b5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+ model = "CDP 1200P";
+ qcom,board-id = <1 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts
new file mode 100644
index 0000000..145a40c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+ model = "CDP";
+ qcom,board-id = <1 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
index d202d99..42d21f4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
@@ -290,7 +290,7 @@
};
&soc {
- cpuss_dump {
+ cpuss_dump: cpuss_dump {
compatible = "qcom,cpuss-dump";
qcom,l2_dump0 {
/* L2 cache dump for A53 cluster */
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts
new file mode 100644
index 0000000..08a343e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-mtp.dtsi"
+
+/ {
+ model = "Ext Codec MTP";
+ qcom,board-id= <8 1>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts
new file mode 100644
index 0000000..45fdf06
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+ model = "Ext Codec RCM";
+ qcom,board-id = <21 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
index 96e8591..fb7cfdd 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
@@ -140,6 +140,9 @@
/* Context aware jump target power level */
qcom,ca-target-pwrlevel = <3>;
+ /* Enable gpu cooling device */
+ #cooling-cells = <2>;
+
/* GPU Mempools */
qcom,gpu-mempools {
#address-cells= <1>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts
new file mode 100644
index 0000000..fec135d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-mtp.dtsi"
+
+/ {
+ model = "IOT MTP";
+ qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts
new file mode 100644
index 0000000..3f957da
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-ipc.dtsi"
+
+/ {
+ model = "IPC";
+ qcom,board-id = <12 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
new file mode 100644
index 0000000..49956df
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-mtp.dtsi"
+
+/ {
+ model = "MTP";
+ qcom,board-id = <8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index a45bb66..eec350d 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -48,6 +48,31 @@
};
};
+ uart1_console_active: uart1_console_active {
+ mux {
+ pins = "gpio20", "gpio21";
+ function = "blsp_uart6";
+ };
+
+ config {
+ pins = "gpio20", "gpio21";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart1_console_sleep: uart1_console_sleep {
+ mux {
+ pins = "gpio20", "gpio21";
+ function = "blsp_uart6";
+ };
+
+ config {
+ pins = "gpio20", "gpio21";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
};
cci {
cci0_active: cci0_active {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
new file mode 100644
index 0000000..a9f64a4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC";
+ compatible = "qcom,msm8953";
+ qcom,pmic-id = <0x010016 0x020037 0x0 0x0>;
+ qcom,pmic-name = "PMI8937";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
new file mode 100644
index 0000000..e9c80a0d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC";
+ compatible = "qcom,msm8953";
+ qcom,pmic-id = <0x010016 0x020040 0x0 0x0>;
+ qcom,pmic-name = "PMI8940";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts
new file mode 100644
index 0000000..7f5fc4e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-qrd-sku3.dtsi"
+
+/ {
+ model = "QRD SKU3";
+ qcom,board-id = <0xb 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts
new file mode 100644
index 0000000..dbb7f57
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+ model = "RCM";
+ qcom,board-id = <21 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
index 208ef41..d5a6f52 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
@@ -265,6 +265,14 @@
type = "passive";
};
};
+ cooling-maps {
+ gpu_cdev0 {
+ trip = <&gpu_trip0>;
+ cooling-device =
+ <&msm_gpu THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
deca-cpu-max-step {
@@ -589,6 +597,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&mdm_core_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&mdm_core_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -619,6 +631,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&qdsp_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&qdsp_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -649,6 +665,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&camera_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -679,6 +699,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu4_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -709,6 +733,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu5_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -739,6 +767,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu6_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu6_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -769,6 +801,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu7_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu7_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -799,6 +835,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&apc1_l2_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&apc1_l2_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -829,6 +869,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu0_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -859,6 +903,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu1_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -889,6 +937,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu2_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -919,6 +971,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&cpu3_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -949,6 +1005,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&apc0_l2_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&apc0_l2_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -979,6 +1039,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&gpu0_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&gpu0_trip>;
cooling-device = <&cx_cdev 0 0>;
@@ -1009,6 +1073,10 @@
cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
(THERMAL_MAX_LIMIT - 4)>;
};
+ gpu_vdd_cdev {
+ trip = <&gpu1_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
cx_vdd_cdev {
trip = <&gpu1_trip>;
cooling-device = <&cx_cdev 0 0>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts
new file mode 100644
index 0000000..ddf2218
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC";
+ compatible = "qcom,msm8953";
+ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+ qcom,pmic-name = "PMI8950";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 0d7932b..a142840 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -19,9 +19,10 @@
#include <dt-bindings/clock/msm-clocks-8953.h>
/ {
- model = "Qualcomm Technologies, Inc. MSM 8953";
+ model = "Qualcomm Technologies, Inc. MSM8953";
compatible = "qcom,msm8953";
qcom,msm-id = <293 0x0>;
+ qcom,msm-name = "MSM8953";
interrupt-parent = <&intc>;
chosen {
@@ -507,6 +508,16 @@
status = "disabled";
};
+ blsp1_serial1: serial@78b0000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b0000 0x200>;
+ interrupts = <0 108 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
#dma-cells = <4>;
compatible = "qcom,sps-dma";
@@ -1070,7 +1081,7 @@
rpm-channel-type = <15>; /* SMD_APPS_RPM */
};
- qcom,wdt@b017000 {
+ wdog: qcom,wdt@b017000 {
compatible = "qcom,msm-watchdog";
reg = <0xb017000 0x1000>;
reg-names = "wdt-base";
diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi
index 1f8d20e..aff92a8 100644
--- a/arch/arm64/boot/dts/qcom/pm8005.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -25,11 +25,12 @@
reg = <0x100 0x100>;
};
- qcom,temp-alarm@2400 {
+ pm8005_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
label = "pm8005_tz";
+ #thermal-sensor-cells = <0>;
};
pm8005_gpios: pinctrl@c000 {
@@ -79,3 +80,28 @@
};
};
};
+
+&thermal_zones {
+ pm8005_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8005_tz>;
+ trips {
+ pm8005-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8005-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8005-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8937.dtsi b/arch/arm64/boot/dts/qcom/pm8937.dtsi
index 086a929..6a61445 100644
--- a/arch/arm64/boot/dts/qcom/pm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8937.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,8 +14,8 @@
&spmi_bus {
qcom,pm8937@0 {
- spmi-slave-container;
- reg = <0x0>;
+ compatible ="qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <1>;
@@ -27,10 +27,10 @@
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
- interrupts = <0x0 0x8 0x0>,
- <0x0 0x8 0x1>,
- <0x0 0x8 0x4>,
- <0x0 0x8 0x5>;
+ interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>,
+ <0x0 0x8 0x1 IRQ_TYPE_NONE>,
+ <0x0 0x8 0x4 IRQ_TYPE_NONE>,
+ <0x0 0x8 0x5 IRQ_TYPE_NONE>;
interrupt-names = "kpdpwr", "resin",
"resin-bark", "kpdpwr-resin-bark";
qcom,pon-dbc-delay = <15625>;
@@ -52,7 +52,7 @@
pm8937_temp_alarm: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
- interrupts = <0x0 0x24 0x0>;
+ interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
label = "pm8937_tz";
qcom,channel-num = <8>;
qcom,threshold-set = <0>;
@@ -65,7 +65,6 @@
};
pm8937_rtc: qcom,pm8937_rtc {
- spmi-dev-container;
compatible = "qcom,qpnp-rtc";
#address-cells = <1>;
#size-cells = <1>;
@@ -78,110 +77,37 @@
qcom,pm8937_rtc_alarm@6100 {
reg = <0x6100 0x100>;
- interrupts = <0x0 0x61 0x1>;
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
};
};
pm8937_mpps: mpps {
- compatible = "qcom,qpnp-pin";
- spmi-dev-container;
+ compatible = "qcom,spmi-mpp";
+ reg = <0xa000 0x400>;
+ interrupts = <0x0 0xa0 0 IRQ_TYPE_NONE>,
+ <0x0 0xa1 0 IRQ_TYPE_NONE>,
+ <0x0 0xa2 0 IRQ_TYPE_NONE>,
+ <0x0 0xa3 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pm8937_mpp1", "pm8937_mpp2",
+ "pm8937_mpp3", "pm8937_mpp4";
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8937-mpp";
-
- mpp@a000 {
- reg = <0xa000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- mpp@a100 {
- /* MPP2 - PA_THERM config */
- reg = <0xa100 0x100>;
- qcom,pin-num = <2>;
- qcom,mode = <4>; /* AIN input */
- qcom,invert = <1>; /* Enable MPP */
- qcom,ain-route = <1>; /* AMUX 6 */
- qcom,master-en = <1>;
- qcom,src-sel = <0>; /* Function constant */
- };
-
- mpp@a200 {
- reg = <0xa200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- mpp@a300 {
- /* MPP4 - CASE_THERM config */
- reg = <0xa300 0x100>;
- qcom,pin-num = <4>;
- qcom,mode = <4>; /* AIN input */
- qcom,invert = <1>; /* Enable MPP */
- qcom,ain-route = <3>; /* AMUX 8 */
- qcom,master-en = <1>;
- qcom,src-sel = <0>; /* Function constant */
- };
};
pm8937_gpios: gpios {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
+ compatible = "qcom,spmi-gpio";
+ reg = <0xc000 0x800>;
+ interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>,
+ <0x0 0xc1 0 IRQ_TYPE_NONE>,
+ <0x0 0xc4 0 IRQ_TYPE_NONE>,
+ <0x0 0xc6 0 IRQ_TYPE_NONE>,
+ <0x0 0xc7 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pm8937_gpio1", "pm8937_gpio2",
+ "pm8937_gpio5", "pmi8937_gpio7",
+ "pm8937_gpio8";
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8937-gpio";
-
- gpio@c000 {
- reg = <0xc000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- gpio@c100 {
- reg = <0xc100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- gpio@c200 {
- reg = <0xc200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- gpio@c300 {
- reg = <0xc300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
-
- gpio@c400 {
- reg = <0xc400 0x100>;
- qcom,pin-num = <5>;
- status = "disabled";
- };
-
- gpio@c500 {
- reg = <0xc500 0x100>;
- qcom,pin-num = <6>;
- status = "disabled";
- };
-
- gpio@c600 {
- reg = <0xc600 0x100>;
- qcom,pin-num = <7>;
- status = "disabled";
- };
-
- gpio@c700 {
- reg = <0xc700 0x100>;
- qcom,pin-num = <8>;
- status = "disabled";
- };
+ qcom,gpios-disallowed = <3 4 6>;
};
pm8937_vadc: vadc@3100 {
@@ -189,7 +115,7 @@
reg = <0x3100 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <0x0 0x31 0x0>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
@@ -326,9 +252,9 @@
reg = <0x3400 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <0x0 0x34 0x0>,
- <0x0 0x34 0x3>,
- <0x0 0x34 0x4>;
+ interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eoc-int-en-set",
"high-thr-en-set",
"low-thr-en-set";
@@ -365,8 +291,8 @@
};
pm8937_1: qcom,pm8937@1 {
- spmi-slave-container;
- reg = <0x1>;
+ compatible = "qcom,spmi-pmic";
+ reg = <0x1 SPMI_USID>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index 6b557e9..074b7da 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -32,6 +32,162 @@
qcom,secondary-pon-reset;
};
+ pmi632_vadc: vadc@3100 {
+ compatible = "qcom,qpnp-vadc-hc";
+ reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-vdd-reference = <1875>;
+ qcom,adc-full-scale-code = <0x70e4>;
+
+ chan@0 {
+ label = "ref_gnd";
+ reg = <0>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@1 {
+ label = "ref_1250v";
+ reg = <1>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@84 {
+ label = "vbat_sns";
+ reg = <0x84>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@6 {
+ label = "die_temp";
+ reg = <6>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <19>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@7 {
+ label = "usb_in_i";
+ reg = <7>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <21>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@8 {
+ label = "usb_in_v";
+ reg = <8>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <8>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@9 {
+ label = "chg_temp";
+ reg = <9>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <18>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@4a {
+ label = "bat_therm";
+ reg = <0x4a>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <17>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@4b {
+ label = "bat_id";
+ reg = <0x4b>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <8>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+
+ chan@1e {
+ label = "mid_chg";
+ reg = <0x1e>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <3>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ };
+
pmi632_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
@@ -123,5 +279,30 @@
#pwm-cells = <2>;
status = "disabled";
};
+
+ pmi632_lcdb: qpnp-lcdb@ec00 {
+ compatible = "qcom,qpnp-lcdb-regulator";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xec00 0x100>;
+ interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "sc-irq";
+
+ qcom,pmic-revid = <&pmi632_revid>;
+
+ lcdb_ldo_vreg: ldo {
+ label = "ldo";
+ regulator-name = "lcdb_ldo";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+
+ lcdb_ncp_vreg: ncp {
+ label = "ncp";
+ regulator-name = "lcdb_ncp";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index d5b9945..a7aa08a 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -16,8 +16,8 @@
&spmi_bus {
qcom,pmi8937@2 {
- spmi-slave-container;
- reg = <0x2>;
+ compatible ="qcom,spmi-pmic";
+ reg = <0x2 SPMI_USID>;
#address-cells = <1>;
#size-cells = <1>;
@@ -45,7 +45,7 @@
reg = <0x3100 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <0x2 0x31 0x0>;
+ interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
@@ -141,35 +141,19 @@
};
pmi8937_mpps: mpps {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
+ compatible = "qcom,spmi-mpp";
+ reg = <0xa000 0x400>;
+ interrupts = <0x2 0xa0 0 IRQ_TYPE_NONE>,
+ <0x2 0xa1 0 IRQ_TYPE_NONE>,
+ <0x2 0xa2 0 IRQ_TYPE_NONE>,
+ <0x2 0xa3 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pmi8937_mpp1", "pmi8937_mpp2",
+ "pmi8937_mpp3", "pmi8937_mpp4";
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pmi8937-mpp";
-
- mpp@a000 {
- reg = <0xa000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- mpp@a100 {
- reg = <0xa100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- mpp@a300 {
- reg = <0xa300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
};
pmi8937_charger: qcom,qpnp-smbcharger {
- spmi-dev-container;
compatible = "qcom,qpnp-smbcharger";
#address-cells = <1>;
#size-cells = <1>;
@@ -191,14 +175,14 @@
qcom,chgr@1000 {
reg = <0x1000 0x100>;
- interrupts = <0x2 0x10 0x0>,
- <0x2 0x10 0x1>,
- <0x2 0x10 0x2>,
- <0x2 0x10 0x3>,
- <0x2 0x10 0x4>,
- <0x2 0x10 0x5>,
- <0x2 0x10 0x6>,
- <0x2 0x10 0x7>;
+ interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x7 IRQ_TYPE_NONE>;
interrupt-names = "chg-error",
"chg-inhibit",
@@ -212,9 +196,9 @@
qcom,otg@1100 {
reg = <0x1100 0x100>;
- interrupts = <0x2 0x11 0x0>,
- <0x2 0x11 0x1>,
- <0x2 0x11 0x3>;
+ interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x3 IRQ_TYPE_NONE>;
interrupt-names = "otg-fail",
"otg-oc",
"usbid-change";
@@ -222,14 +206,14 @@
qcom,bat-if@1200 {
reg = <0x1200 0x100>;
- interrupts = <0x2 0x12 0x0>,
- <0x2 0x12 0x1>,
- <0x2 0x12 0x2>,
- <0x2 0x12 0x3>,
- <0x2 0x12 0x4>,
- <0x2 0x12 0x5>,
- <0x2 0x12 0x6>,
- <0x2 0x12 0x7>;
+ interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x7 IRQ_TYPE_NONE>;
interrupt-names = "batt-hot",
"batt-warm",
@@ -243,10 +227,10 @@
qcom,usb-chgpth@1300 {
reg = <0x1300 0x100>;
- interrupts = <0x2 0x13 0x0>,
- <0x2 0x13 0x1>,
- <0x2 0x13 0x2>,
- <0x2 0x13 0x5>;
+ interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x5 IRQ_TYPE_NONE>;
interrupt-names = "usbin-uv",
"usbin-ov",
@@ -256,20 +240,20 @@
qcom,dc-chgpth@1400 {
reg = <0x1400 0x100>;
- interrupts = <0x2 0x14 0x0>,
- <0x2 0x14 0x1>;
+ interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x1 IRQ_TYPE_NONE>;
interrupt-names = "dcin-uv",
"dcin-ov";
};
qcom,chgr-misc@1600 {
reg = <0x1600 0x100>;
- interrupts = <0x2 0x16 0x0>,
- <0x2 0x16 0x1>,
- <0x2 0x16 0x2>,
- <0x2 0x16 0x3>,
- <0x2 0x16 0x4>,
- <0x2 0x16 0x5>;
+ interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x5 IRQ_TYPE_NONE>;
interrupt-names = "power-ok",
"temp-shutdown",
@@ -285,7 +269,6 @@
};
pmi8937_fg: qcom,fg {
- spmi-dev-container;
compatible = "qcom,qpnp-fg";
#address-cells = <1>;
#size-cells = <1>;
@@ -303,13 +286,13 @@
qcom,fg-soc@4000 {
status = "okay";
reg = <0x4000 0x100>;
- interrupts = <0x2 0x40 0x0>,
- <0x2 0x40 0x1>,
- <0x2 0x40 0x2>,
- <0x2 0x40 0x3>,
- <0x2 0x40 0x4>,
- <0x2 0x40 0x5>,
- <0x2 0x40 0x6>;
+ interrupts = <0x2 0x40 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x6 IRQ_TYPE_NONE>;
interrupt-names = "high-soc",
"low-soc",
@@ -322,14 +305,14 @@
qcom,fg-batt@4100 {
reg = <0x4100 0x100>;
- interrupts = <0x2 0x41 0x0>,
- <0x2 0x41 0x1>,
- <0x2 0x41 0x2>,
- <0x2 0x41 0x3>,
- <0x2 0x41 0x4>,
- <0x2 0x41 0x5>,
- <0x2 0x41 0x6>,
- <0x2 0x41 0x7>;
+ interrupts = <0x2 0x41 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x7 IRQ_TYPE_NONE>;
interrupt-names = "soft-cold",
"soft-hot",
@@ -348,8 +331,8 @@
qcom,fg-memif@4400 {
status = "okay";
reg = <0x4400 0x100>;
- interrupts = <0x2 0x44 0x0>,
- <0x2 0x44 0x2>;
+ interrupts = <0x2 0x44 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x44 0x2 IRQ_TYPE_NONE>;
interrupt-names = "mem-avail",
"data-rcvry-sug";
@@ -360,8 +343,8 @@
compatible = "qcom,msm-bcl";
reg = <0x4200 0xff>;
reg-names = "fg_user_adc";
- interrupts = <0x2 0x42 0x0>,
- <0x2 0x42 0x1>;
+ interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x1 IRQ_TYPE_NONE>;
interrupt-names = "bcl-high-ibat-int",
"bcl-low-vbat-int";
qcom,vbat-scaling-factor = <39000>;
@@ -384,8 +367,8 @@
};
qcom,pmi8937@3 {
- spmi-slave-container;
- reg = <0x3>;
+ compatible ="qcom,spmi-pmic";
+ reg = <0x3 SPMI_USID>;
#address-cells = <1>;
#size-cells = <1>;
@@ -405,7 +388,7 @@
<0xd900 0x100>;
reg-names = "qpnp-wled-ctrl-base",
"qpnp-wled-sink-base";
- interrupts = <0x3 0xd8 0x2>;
+ interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "sc-irq";
status = "okay";
linux,name = "wled";
@@ -424,6 +407,7 @@
qcom,fs-curr-ua = <20000>;
qcom,led-strings-list = [00 01];
qcom,en-ext-pfet-sc-pro;
+ qcom,pmic-revid = <&pmi8937_revid>;
qcom,cons-sync-write-delay-us = <1000>;
};
@@ -510,8 +494,8 @@
pmi_haptic: qcom,haptic@c000 {
compatible = "qcom,qpnp-haptic";
reg = <0xc000 0x100>;
- interrupts = <0x3 0xc0 0x0>,
- <0x3 0xc0 0x1>;
+ interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "sc-irq", "play-irq";
qcom,pmic-revid = <&pmi8937_revid>;
vcc_pon-supply = <&pon_perph_reg>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
index 59001ba..c6d5c87 100644
--- a/arch/arm64/boot/dts/qcom/pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,10 +14,9 @@
#include <dt-bindings/msm/power-on.h>
&spmi_bus {
-
qcom,pmi8940@2 {
- spmi-slave-container;
- reg = <0x2>;
+ compatible ="qcom,spmi-pmic";
+ reg = <0x2 SPMI_USID>;
#address-cells = <1>;
#size-cells = <1>;
@@ -45,7 +44,7 @@
reg = <0x3100 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <0x2 0x31 0x0>;
+ interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
@@ -141,35 +140,19 @@
};
pmi8940_mpps: mpps {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
+ compatible = "qcom,spmi-mpp";
+ reg = <0xa000 0x400>;
+ interrupts = <0x2 0xa0 0 IRQ_TYPE_NONE>,
+ <0x2 0xa1 0 IRQ_TYPE_NONE>,
+ <0x2 0xa2 0 IRQ_TYPE_NONE>,
+ <0x2 0xa3 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pmi8940_mpp1", "pmi8940_mpp2",
+ "pmi8940_mpp3", "pmi8940_mpp4";
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pmi8940-mpp";
-
- mpp@a000 {
- reg = <0xa000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- mpp@a100 {
- reg = <0xa100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- mpp@a300 {
- reg = <0xa300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
};
pmi8940_charger: qcom,qpnp-smbcharger {
- spmi-dev-container;
compatible = "qcom,qpnp-smbcharger";
#address-cells = <1>;
#size-cells = <1>;
@@ -188,14 +171,14 @@
qcom,chgr@1000 {
reg = <0x1000 0x100>;
- interrupts = <0x2 0x10 0x0>,
- <0x2 0x10 0x1>,
- <0x2 0x10 0x2>,
- <0x2 0x10 0x3>,
- <0x2 0x10 0x4>,
- <0x2 0x10 0x5>,
- <0x2 0x10 0x6>,
- <0x2 0x10 0x7>;
+ interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x7 IRQ_TYPE_NONE>;
interrupt-names = "chg-error",
"chg-inhibit",
@@ -209,9 +192,9 @@
qcom,otg@1100 {
reg = <0x1100 0x100>;
- interrupts = <0x2 0x11 0x0>,
- <0x2 0x11 0x1>,
- <0x2 0x11 0x3>;
+ interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x3 IRQ_TYPE_NONE>;
interrupt-names = "otg-fail",
"otg-oc",
"usbid-change";
@@ -219,14 +202,14 @@
qcom,bat-if@1200 {
reg = <0x1200 0x100>;
- interrupts = <0x2 0x12 0x0>,
- <0x2 0x12 0x1>,
- <0x2 0x12 0x2>,
- <0x2 0x12 0x3>,
- <0x2 0x12 0x4>,
- <0x2 0x12 0x5>,
- <0x2 0x12 0x6>,
- <0x2 0x12 0x7>;
+ interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x7 IRQ_TYPE_NONE>;
interrupt-names = "batt-hot",
"batt-warm",
@@ -240,10 +223,10 @@
qcom,usb-chgpth@1300 {
reg = <0x1300 0x100>;
- interrupts = <0x2 0x13 0x0>,
- <0x2 0x13 0x1>,
- <0x2 0x13 0x2>,
- <0x2 0x13 0x5>;
+ interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x5 IRQ_TYPE_NONE>;
interrupt-names = "usbin-uv",
"usbin-ov",
@@ -253,20 +236,20 @@
qcom,dc-chgpth@1400 {
reg = <0x1400 0x100>;
- interrupts = <0x2 0x14 0x0>,
- <0x2 0x14 0x1>;
+ interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x1 IRQ_TYPE_NONE>;
interrupt-names = "dcin-uv",
"dcin-ov";
};
qcom,chgr-misc@1600 {
reg = <0x1600 0x100>;
- interrupts = <0x2 0x16 0x0>,
- <0x2 0x16 0x1>,
- <0x2 0x16 0x2>,
- <0x2 0x16 0x3>,
- <0x2 0x16 0x4>,
- <0x2 0x16 0x5>;
+ interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x5 IRQ_TYPE_NONE>;
interrupt-names = "power-ok",
"temp-shutdown",
@@ -282,7 +265,6 @@
};
pmi8940_fg: qcom,fg {
- spmi-dev-container;
compatible = "qcom,qpnp-fg";
#address-cells = <1>;
#size-cells = <1>;
@@ -300,13 +282,13 @@
qcom,fg-soc@4000 {
status = "okay";
reg = <0x4000 0x100>;
- interrupts = <0x2 0x40 0x0>,
- <0x2 0x40 0x1>,
- <0x2 0x40 0x2>,
- <0x2 0x40 0x3>,
- <0x2 0x40 0x4>,
- <0x2 0x40 0x5>,
- <0x2 0x40 0x6>;
+ interrupts = <0x2 0x40 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x6 IRQ_TYPE_NONE>;
interrupt-names = "high-soc",
"low-soc",
@@ -319,14 +301,14 @@
qcom,fg-batt@4100 {
reg = <0x4100 0x100>;
- interrupts = <0x2 0x41 0x0>,
- <0x2 0x41 0x1>,
- <0x2 0x41 0x2>,
- <0x2 0x41 0x3>,
- <0x2 0x41 0x4>,
- <0x2 0x41 0x5>,
- <0x2 0x41 0x6>,
- <0x2 0x41 0x7>;
+ interrupts = <0x2 0x41 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x7 IRQ_TYPE_NONE>;
interrupt-names = "soft-cold",
"soft-hot",
@@ -345,8 +327,8 @@
qcom,fg-memif@4400 {
status = "okay";
reg = <0x4400 0x100>;
- interrupts = <0x2 0x44 0x0>,
- <0x2 0x44 0x2>;
+ interrupts = <0x2 0x44 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x44 0x2 IRQ_TYPE_NONE>;
interrupt-names = "mem-avail",
"data-rcvry-sug";
@@ -357,8 +339,8 @@
compatible = "qcom,msm-bcl";
reg = <0x4200 0xff>;
reg-names = "fg_user_adc";
- interrupts = <0x2 0x42 0x0>,
- <0x2 0x42 0x1>;
+ interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x1 IRQ_TYPE_NONE>;
interrupt-names = "bcl-high-ibat-int",
"bcl-low-vbat-int";
qcom,vbat-scaling-factor = <39000>;
@@ -381,8 +363,8 @@
};
qcom,pmi8940@3 {
- spmi-slave-container;
- reg = <0x3>;
+ compatible ="qcom,spmi-pmic";
+ reg = <0x3 SPMI_USID>;
#address-cells = <1>;
#size-cells = <1>;
@@ -398,10 +380,10 @@
labibb: qpnp-labibb-regulator {
status = "disabled";
- spmi-dev-container;
compatible = "qcom,qpnp-labibb-regulator";
#address-cells = <1>;
#size-cells = <1>;
+ qcom,qpnp-labibb-mode = "lcd";
qcom,pmic-revid = <&pmi8940_revid>;
ibb_regulator: qcom,ibb@dc00 {
@@ -475,7 +457,7 @@
<0xd900 0x100>;
reg-names = "qpnp-wled-ctrl-base",
"qpnp-wled-sink-base";
- interrupts = <0x3 0xd8 0x2>;
+ interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "sc-irq";
status = "okay";
linux,name = "wled";
@@ -495,6 +477,7 @@
qcom,en-phase-stag;
qcom,led-strings-list = [00 01];
qcom,en-ext-pfet-sc-pro;
+ qcom,pmic-revid = <&pmi8940_revid>;
qcom,cons-sync-write-delay-us = <1000>;
};
@@ -581,8 +564,8 @@
pmi_haptic: qcom,haptic@c000 {
compatible = "qcom,qpnp-haptic";
reg = <0xc000 0x100>;
- interrupts = <0x3 0xc0 0x0>,
- <0x3 0xc0 0x1>;
+ interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "sc-irq", "play-irq";
qcom,pmic-revid = <&pmi8940_revid>;
vcc_pon-supply = <&pon_perph_reg>;
diff --git a/arch/arm64/boot/dts/qcom/sda632.dtsi b/arch/arm64/boot/dts/qcom/sda632.dtsi
new file mode 100644
index 0000000..8a71b19
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda632.dtsi
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "sdm632.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA632";
+ compatible = "qcom,sda632";
+ qcom,msm-id = <350 0x0>;
+};
+
+&secure_mem {
+ status = "disabled";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
new file mode 100644
index 0000000..944ca3b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
@@ -0,0 +1,271 @@
+/* Copyright (c) 2017-2018, 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.
+ */
+
+&mdm3 {
+ pinctrl-names = "default", "mdm_active", "mdm_suspend";
+ pinctrl-0 = <&ap2mdm_pon_reset_default>;
+ pinctrl-1 = <&ap2mdm_active &mdm2ap_active>;
+ pinctrl-2 = <&ap2mdm_sleep &mdm2ap_sleep>;
+ interrupt-map = <0 &tlmm 24 0x3
+ 1 &tlmm 21 0x3>;
+ qcom,mdm2ap-errfatal-gpio = <&tlmm 24 0x00>;
+ qcom,ap2mdm-errfatal-gpio = <&tlmm 23 0x00>;
+ qcom,mdm2ap-status-gpio = <&tlmm 22 0x00>;
+ qcom,ap2mdm-status-gpio = <&tlmm 21 0x00>;
+ qcom,ap2mdm-soft-reset-gpio = <&pm8998_gpios 10 0>;
+ qcom,mdm-link-info = "0304_00.01.00";
+ status = "ok";
+};
+
+&pm8998_gpios {
+ ap2mdm_pon_reset {
+ ap2mdm_pon_reset_default: ap2mdm_pon_reset_default {
+ /* MDM PON conrol*/
+ pins = "gpio10";
+ function = "normal";
+ output-low;
+ power-source = <0>;
+ };
+ };
+};
+
+&pil_modem {
+ status = "disabled";
+};
+
+&pcie0_wake_default {
+ config {
+ /delete-property/ bias-pull-down;
+ };
+};
+
+&led_flash_rear {
+ status = "disabled";
+};
+
+&led_flash_front {
+ status = "disabled";
+};
+
+&ois_rear {
+ status = "disabled";
+};
+
+&eeprom_rear {
+ status = "disabled";
+};
+
+&eeprom_rear_aux {
+ status = "disabled";
+};
+
+&eeprom_front {
+ status = "disabled";
+};
+
+&soc {
+ qcom,cam-req-mgr {
+ status = "disabled";
+ };
+
+ cam_csiphy0: qcom,csiphy@ac65000 {
+ status = "disabled";
+ };
+
+ cam_csiphy1: qcom,csiphy@ac66000 {
+ status = "disabled";
+ };
+
+ cam_csiphy2: qcom,csiphy@ac67000 {
+ status = "disabled";
+ };
+
+ cam_cci: qcom,cci@ac4a000 {
+ status = "disabled";
+
+ i2c_freq_100Khz: qcom,i2c_standard_mode {
+ status = "disabled";
+ };
+
+ i2c_freq_400Khz: qcom,i2c_fast_mode {
+ status = "disabled";
+ };
+
+ i2c_freq_custom: qcom,i2c_custom_mode {
+ status = "disabled";
+ };
+
+ i2c_freq_1Mhz: qcom,i2c_fast_plus_mode {
+ status = "disabled";
+ };
+ };
+
+ qcom,cam_smmu {
+ status = "disabled";
+
+ msm_cam_smmu_ife {
+ ife_iova_mem_map: iova-mem-map {
+ iova-mem-region-io {
+ status = "disabled";
+ };
+ };
+ };
+
+ msm_cam_smmu_jpeg {
+ jpeg_iova_mem_map: iova-mem-map {
+ iova-mem-region-io {
+ status = "disabled";
+ };
+ };
+ };
+
+ msm_cam_smmu_icp {
+ icp_iova_mem_map: iova-mem-map {
+ iova-mem-region-firmware {
+ status = "disabled";
+ };
+
+ iova-mem-region-shared {
+ status = "disabled";
+ };
+
+ iova-mem-region-io {
+ status = "disabled";
+ };
+ };
+ };
+
+ msm_cam_smmu_cpas_cdm {
+ cpas_cdm_iova_mem_map: iova-mem-map {
+ iova-mem-region-io {
+ status = "disabled";
+ };
+ };
+ };
+
+ msm_cam_smmu_fd {
+ fd_iova_mem_map: iova-mem-map {
+ iova-mem-region-io {
+ status = "disabled";
+ };
+ };
+ };
+ };
+
+ qcom,cam-cpas@ac40000 {
+ status = "disabled";
+ };
+
+ qcom,cam-cdm-intf {
+ status = "disabled";
+ };
+
+ qcom,cpas-cdm0@ac48000 {
+ status = "disabled";
+ };
+
+ qcom,cam-isp {
+ status = "disabled";
+ };
+
+ cam_csid0: qcom,csid0@acb3000 {
+ status = "disabled";
+ };
+
+ cam_vfe0: qcom,vfe0@acaf000 {
+ status = "disabled";
+ };
+
+ cam_csid1: qcom,csid1@acba000 {
+ status = "disabled";
+ };
+
+ cam_vfe1: qcom,vfe1@acb6000 {
+ status = "disabled";
+ };
+
+ cam_csid_lite: qcom,csid-lite@acc8000 {
+ status = "disabled";
+ };
+
+ cam_vfe_lite: qcom,vfe-lite@acc4000 {
+ status = "disabled";
+ };
+
+ qcom,cam-icp {
+ status = "disabled";
+ };
+
+ cam_a5: qcom,a5@ac00000 {
+ status = "disabled";
+ };
+
+ cam_ipe0: qcom,ipe0 {
+ status = "disabled";
+ };
+
+ cam_ipe1: qcom,ipe1 {
+ status = "disabled";
+ };
+
+ cam_bps: qcom,bps {
+ status = "disabled";
+ };
+
+ clock_camcc: qcom,camcc@ad00000 {
+ status = "disabled";
+ };
+
+ qcom,cam-jpeg {
+ status = "disabled";
+ };
+
+ cam_jpeg_enc: qcom,jpegenc@ac4e000 {
+ status = "disabled";
+ };
+
+ cam_jpeg_dma: qcom,jpegdma@0xac52000 {
+ status = "disabled";
+ };
+
+ qcom,cam-fd {
+ status = "disabled";
+ };
+
+ cam_fd: qcom,fd@ac5a000 {
+ status = "disabled";
+ };
+
+ qcom,cam-sensor@0 {
+ status = "disabled";
+ };
+
+ qcom,cam-sensor@1 {
+ status = "disabled";
+ };
+
+ qcom,cam-sensor@2 {
+ status = "disabled";
+ };
+
+ qcom,cam-sensor@3 {
+ status = "disabled";
+ };
+
+ cam_csiphy3: qcom,csiphy@ac68000 {
+ status = "disabled";
+ };
+};
+
+&wil6210 {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts
new file mode 100644
index 0000000..5377813
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "external-soc.dtsi"
+#include "sda845-sdxpoorwills.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA845 v2 + SDXPOORWILLS MTP";
+ compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <8 5>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts
new file mode 100644
index 0000000..10e4a32
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "external-soc.dtsi"
+#include "sda845-sdxpoorwills.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA845 v2.1 + SDXPOORWILLS CDP";
+ compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp";
+ qcom,msm-id = <341 0x20001>;
+ qcom,board-id = <1 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts
new file mode 100644
index 0000000..09fa20f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "external-soc.dtsi"
+#include "sda845-sdxpoorwills.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA845 v2.1 + SDXPOORWILLS MTP";
+ compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp";
+ qcom,msm-id = <341 0x20001>;
+ qcom,board-id = <8 5>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
new file mode 100644
index 0000000..700e950
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm450.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC";
+ compatible = "qcom,sdm450";
+ qcom,pmic-id = <0x010016 0x020037 0x0 0x0>;
+ qcom,pmic-name = "PMI8937";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
new file mode 100644
index 0000000..f50d177
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm450.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC";
+ compatible = "qcom,sdm450";
+ qcom,pmic-id = <0x010016 0x020040 0x0 0x0>;
+ qcom,pmic-name = "PMI8940";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts
new file mode 100644
index 0000000..b829b81
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm450.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC";
+ compatible = "qcom,sdm450";
+ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+ qcom,pmic-name = "PMI8950";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dtsi b/arch/arm64/boot/dts/qcom/sdm450.dtsi
index 2f3e8c4..3e24714 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450.dtsi
@@ -17,6 +17,7 @@
model = "Qualcomm Technologies, Inc. SDM450";
compatible = "qcom,sdm450";
qcom,msm-id = <338 0x0>;
+ qcom,msm-name = "SDM450";
};
&CPU4 {
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
new file mode 100644
index 0000000..031fd7e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/ {
+ /delete-node/ cpus;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ core2 {
+ cpu = <&CPU2>;
+ };
+ core3 {
+ cpu = <&CPU3>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&CPU4>;
+ };
+ core1 {
+ cpu = <&CPU5>;
+ };
+ core2 {
+ cpu = <&CPU6>;
+ };
+ core3 {
+ cpu = <&CPU7>;
+ };
+ };
+ };
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ next-level-cache = <&L2_0>;
+ L2_0: l2-cache {
+ compatible = "arm,arch-cache";
+ cache-level = <2>;
+ /* A53 L2 dump not supported */
+ qcom,dump-size = <0x0>;
+ };
+ L1_I_0: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_D_0: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_0: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ enable-method = "psci";
+ reg = <0x0 0x1>;
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ next-level-cache = <&L2_0>;
+ L1_I_1: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_D_1: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_1: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
+ };
+
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ enable-method = "psci";
+ reg = <0x0 0x2>;
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ next-level-cache = <&L2_0>;
+ L1_I_2: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_D_2: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_2: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
+ };
+
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ enable-method = "psci";
+ reg = <0x0 0x3>;
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ next-level-cache = <&L2_0>;
+ L1_I_3: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_D_3: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_3: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
+ };
+
+ CPU4: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ enable-method = "psci";
+ reg = <0x0 0x100>;
+ efficiency = <1638>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ next-level-cache = <&L2_1>;
+ L2_1: l2-cache {
+ compatible = "arm,arch-cache";
+ cache-level = <2>;
+ };
+ L1_I_100: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x12000>;
+ };
+ L1_D_100: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_100: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
+ };
+
+ CPU5: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53","arm,armv8";
+ enable-method = "psci";
+ reg = <0x0 0x101>;
+ efficiency = <1638>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ next-level-cache = <&L2_1>;
+ L1_I_101: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x12000>;
+ };
+ L1_D_101: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_101: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
+ };
+
+ CPU6: cpu@102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53","arm,armv8";
+ enable-method = "psci";
+ reg = <0x0 0x102>;
+ efficiency = <1638>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ next-level-cache = <&L2_1>;
+ L1_I_102: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x12000>;
+ };
+ L1_D_102: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_102: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
+ };
+
+ CPU7: cpu@103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53","arm,armv8";
+ enable-method = "psci";
+ reg = <0x0 0x103>;
+ efficiency = <1638>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ next-level-cache = <&L2_1>;
+ L1_I_103: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x12000>;
+ };
+ L1_D_103: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9040>;
+ };
+ L1_TLB_103: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
+ };
+ };
+};
+
+&cpuss_dump {
+ qcom,l1_tlb_dump0 {
+ qcom,dump-node = <&L1_TLB_0>;
+ qcom,dump-id = <0x20>;
+ };
+ qcom,l1_tlb_dump1 {
+ qcom,dump-node = <&L1_TLB_1>;
+ qcom,dump-id = <0x21>;
+ };
+ qcom,l1_tlb_dump2 {
+ qcom,dump-node = <&L1_TLB_2>;
+ qcom,dump-id = <0x22>;
+ };
+ qcom,l1_tlb_dump3 {
+ qcom,dump-node = <&L1_TLB_3>;
+ qcom,dump-id = <0x23>;
+ };
+ qcom,l1_tlb_dump100 {
+ qcom,dump-node = <&L1_TLB_100>;
+ qcom,dump-id = <0x24>;
+ };
+ qcom,l1_tlb_dump101 {
+ qcom,dump-node = <&L1_TLB_101>;
+ qcom,dump-id = <0x25>;
+ };
+ qcom,l1_tlb_dump102 {
+ qcom,dump-node = <&L1_TLB_102>;
+ qcom,dump-id = <0x26>;
+ };
+ qcom,l1_tlb_dump103 {
+ qcom,dump-node = <&L1_TLB_103>;
+ qcom,dump-id = <0x27>;
+ };
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rumi.dts b/arch/arm64/boot/dts/qcom/sdm632-rumi.dts
new file mode 100644
index 0000000..5a6f88a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-rumi.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm632-rumi.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM632 RUMI";
+ compatible = "qcom,sdm632-rumi", "qcom,sdm632", "qcom,rumi";
+ qcom,board-id = <15 0>;
+ qcom,pmic-id = <0 0 0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi
new file mode 100644
index 0000000..3ba8a4d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&blsp1_serial1 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_console_active>;
+};
+
+&wdog {
+ status = "disabled";
+};
+
+&modem_mem {
+ status = "disabled";
+};
+
+&adsp_fw_mem {
+ status = "disabled";
+};
+
+&wcnss_fw_mem {
+ status = "disabled";
+};
+
+&venus_mem {
+ status = "disabled";
+};
+
+&secure_mem {
+ status = "disabled";
+};
+
+&qseecom_mem {
+ status = "disabled";
+};
+
+&adsp_mem {
+ status = "disabled";
+};
+
+&dfps_data_mem {
+ status = "disabled";
+};
+
+&cont_splash_mem {
+ status = "disabled";
+};
+
+&gpu_mem {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
new file mode 100644
index 0000000..3ebd50e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, 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 "msm8953.dtsi"
+#include "sdm632-cpu.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM632";
+ compatible = "qcom,sdm632";
+ qcom,msm-id = <349 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 1f40e20..715affd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -229,6 +229,7 @@
qcom,cam_smmu {
compatible = "qcom,msm-cam-smmu";
status = "ok";
+ non-fatal-fault-disabled;
msm_cam_smmu_lrme {
compatible = "qcom,msm-cam-smmu-cb";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts
new file mode 100644
index 0000000..15fadc6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts
@@ -0,0 +1,74 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A + Tasha Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 5>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_panel_pwr_supply_labibb_amoled {
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6100000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4000000>;
+ qcom,supply-max-voltage = <6300000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@4 {
+ reg = <4>;
+ qcom,supply-name = "oledb";
+ qcom,supply-min-voltage = <5000000>;
+ qcom,supply-max-voltage = <8100000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+};
+
+&dsi_rm67195_amoled_fhd_cmd_display {
+ qcom,dsi-display-active;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+ oledb-supply = <&pm660a_oledb>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts
new file mode 100644
index 0000000..ec906ee
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts
@@ -0,0 +1,68 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Tasha Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 5>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_panel_pwr_supply_labibb_amoled {
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6100000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4000000>;
+ qcom,supply-max-voltage = <6300000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@4 {
+ reg = <4>;
+ qcom,supply-name = "oledb";
+ qcom,supply-min-voltage = <5000000>;
+ qcom,supply-max-voltage = <8100000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+};
+
+&dsi_rm67195_amoled_fhd_cmd_display {
+ qcom,dsi-display-active;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+ oledb-supply = <&pm660a_oledb>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts
new file mode 100644
index 0000000..cc772cd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Tasha Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 5>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts
new file mode 100644
index 0000000..e862911
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Tasha Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 5>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
index 8cbc84f..a0fa9cf 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -471,7 +471,7 @@
};
gpu_vdd_cdev {
trip = <&aoss0_trip>;
- cooling-device = <&msm_gpu 4 4>;
+ cooling-device = <&msm_gpu 0 0>;
};
cx_vdd_cdev {
trip = <&aoss0_trip>;
@@ -496,606 +496,6 @@
};
};
- cpu0-silver-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 1>;
- tracks-low;
- trips {
- cpu0_trip: cpu0-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpu0_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpu1-silver-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 2>;
- tracks-low;
- trips {
- cpu1_trip: cpu1-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpu1_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpu2-silver-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 3>;
- tracks-low;
- trips {
- cpu2_trip: cpu2-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpu2_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpu3-silver-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 4>;
- tracks-low;
- trips {
- cpu3_trip: cpu3-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpu3_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpuss-0-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 5>;
- tracks-low;
- trips {
- l3_0_trip: l3-0-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&l3_0_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpuss-1-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 6>;
- tracks-low;
- trips {
- l3_1_trip: l3-1-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&l3_1_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpu4-silver-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 7>;
- tracks-low;
- trips {
- cpu4_trip: cpu4-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpu4_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpu5-silver-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 8>;
- tracks-low;
- trips {
- cpu5_trip: cpu5-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpu5_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpu0-gold-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 9>;
- tracks-low;
- trips {
- cpug0_trip: cpug0-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpug0_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- cpu1-gold-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 10>;
- tracks-low;
- trips {
- cpug1_trip: cpug1-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&cpug1_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- gpu0-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 11>;
- tracks-low;
- trips {
- gpu0_trip_l: gpu0-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&gpu0_trip_l>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- gpu1-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens0 12>;
- tracks-low;
- trips {
- gpu1_trip_l: gpu1-trip_l {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&gpu1_trip_l>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
aoss1-lowf {
polling-delay-passive = <0>;
polling-delay = <0>;
@@ -1121,7 +521,7 @@
};
gpu_vdd_cdev {
trip = <&aoss1_trip>;
- cooling-device = <&msm_gpu 4 4>;
+ cooling-device = <&msm_gpu 0 0>;
};
cx_vdd_cdev {
trip = <&aoss1_trip>;
@@ -1146,356 +546,6 @@
};
};
- mdm-dsp-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens1 1>;
- tracks-low;
- trips {
- dsp_trip: dsp-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&dsp_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- ddr-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens1 2>;
- tracks-low;
- trips {
- ddr_trip: ddr-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&ddr_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- wlan-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens1 3>;
- tracks-low;
- trips {
- wlan_trip: wlan-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&wlan_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- compute-hvx-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens1 4>;
- tracks-low;
- trips {
- hvx_trip: hvx-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&hvx_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- camera-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens1 5>;
- tracks-low;
- trips {
- camera_trip: camera-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&camera_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- mmss-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens1 6>;
- tracks-low;
- trips {
- mmss_trip: mmss-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&mmss_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
- mdm-core-lowf {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "low_limits_floor";
- thermal-sensors = <&tsens1 7>;
- tracks-low;
- trips {
- mdm_trip: mdm-trip {
- temperature = <5000>;
- hysteresis = <5000>;
- type = "passive";
- };
- };
- cooling-maps {
- cpu0_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&CPU0 2 2>;
- };
- cpu6_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
- (THERMAL_MAX_LIMIT-8)>;
- };
- gpu_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&msm_gpu 4 4>;
- };
- cx_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&cx_cdev 0 0>;
- };
- mx_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&mx_cdev 0 0>;
- };
- modem_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&modem_vdd 0 0>;
- };
- adsp_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&adsp_vdd 0 0>;
- };
- cdsp_vdd_cdev {
- trip = <&mdm_trip>;
- cooling-device = <&cdsp_vdd 0 0>;
- };
- };
- };
-
lmh-dcvs-01 {
polling-delay-passive = <0>;
polling-delay = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
index a3a48af..d708a12 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -91,16 +91,26 @@
pinctrl-0 = <&camera_dvdd_en_default>;
vin-supply = <&pm8998_s3>;
};
+
+ camera_vana_ldo: gpio-regulator@4 {
+ compatible = "regulator-fixed";
+ reg = <0x04 0x00>;
+ regulator-name = "camera_vana_ldo";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-enable-ramp-delay = <233>;
+ enable-active-high;
+ gpio = <&tlmm 8 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cam_sensor_rear_vana>;
+ vin-supply = <&pmi8998_bob>;
+ };
};
&cam_cci {
qcom,cam-res-mgr {
compatible = "qcom,cam-res-mgr";
status = "ok";
- shared-gpios = <8>;
- pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend";
- pinctrl-0 = <&cam_res_mgr_active>;
- pinctrl-1 = <&cam_res_mgr_suspend>;
};
actuator_rear: qcom,actuator@0 {
@@ -339,13 +349,13 @@
eeprom-src = <&eeprom_rear_aux>;
cam_vdig-supply = <&camera_ldo>;
cam_vio-supply = <&pm8998_lvs1>;
- cam_vana-supply = <&pmi8998_bob>;
+ cam_vana-supply = <&camera_vana_ldo>;
cam_clk-supply = <&titan_top_gdsc>;
regulator-names = "cam_vdig", "cam_vio", "cam_vana",
"cam_clk";
rgltr-cntrl-support;
- rgltr-min-voltage = <1050000 0 3312000 0>;
- rgltr-max-voltage = <1050000 0 3600000 0>;
+ rgltr-min-voltage = <1050000 0 2850000 0>;
+ rgltr-max-voltage = <1050000 0 2850000 0>;
rgltr-load-current = <105000 0 80000 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -354,15 +364,12 @@
pinctrl-1 = <&cam_sensor_mclk2_suspend
&cam_sensor_rear2_suspend>;
gpios = <&tlmm 15 0>,
- <&tlmm 9 0>,
- <&tlmm 8 0>;
+ <&tlmm 9 0>;
gpio-reset = <1>;
- gpio-vana = <2>;
- gpio-req-tbl-num = <0 1 2>;
- gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-num = <0 1>;
+ gpio-req-tbl-flags = <1 0>;
gpio-req-tbl-label = "CAMIF_MCLK1",
- "CAM_RESET1",
- "CAM_VANA1";
+ "CAM_RESET1";
sensor-mode = <0>;
cci-master = <1>;
status = "ok";
@@ -384,14 +391,14 @@
actuator-src = <&actuator_front>;
led-flash-src = <&led_flash_front>;
cam_vio-supply = <&pm8998_lvs1>;
- cam_vana-supply = <&pmi8998_bob>;
+ cam_vana-supply = <&camera_vana_ldo>;
cam_vdig-supply = <&camera_ldo>;
cam_clk-supply = <&titan_top_gdsc>;
regulator-names = "cam_vio", "cam_vana", "cam_vdig",
"cam_clk";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 3312000 1050000 0>;
- rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-min-voltage = <0 2850000 1050000 0>;
+ rgltr-max-voltage = <0 2850000 1050000 0>;
rgltr-load-current = <0 80000 105000 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -400,15 +407,12 @@
pinctrl-1 = <&cam_sensor_mclk1_suspend
&cam_sensor_front_suspend>;
gpios = <&tlmm 14 0>,
- <&tlmm 28 0>,
- <&tlmm 8 0>;
+ <&tlmm 28 0>;
gpio-reset = <1>;
- gpio-vana = <2>;
- gpio-req-tbl-num = <0 1 2>;
- gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-num = <0 1>;
+ gpio-req-tbl-flags = <1 0>;
gpio-req-tbl-label = "CAMIF_MCLK2",
- "CAM_RESET2",
- "CAM_VANA1";
+ "CAM_RESET2";
sensor-mode = <0>;
cci-master = <1>;
status = "ok";
@@ -428,14 +432,14 @@
sensor-position-yaw = <0>;
led-flash-src = <&led_flash_iris>;
cam_vio-supply = <&pm8998_lvs1>;
- cam_vana-supply = <&pmi8998_bob>;
+ cam_vana-supply = <&camera_vana_ldo>;
cam_vdig-supply = <&camera_ldo>;
cam_clk-supply = <&titan_top_gdsc>;
regulator-names = "cam_vio", "cam_vana", "cam_vdig",
"cam_clk";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 3312000 1050000 0>;
- rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-min-voltage = <0 2850000 1050000 0>;
+ rgltr-max-voltage = <0 2850000 1050000 0>;
rgltr-load-current = <0 80000 105000 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
@@ -444,15 +448,12 @@
pinctrl-1 = <&cam_sensor_mclk3_suspend
&cam_sensor_iris_suspend>;
gpios = <&tlmm 16 0>,
- <&tlmm 9 0>,
- <&tlmm 8 0>;
+ <&tlmm 9 0>;
gpio-reset = <1>;
- gpio-vana = <2>;
- gpio-req-tbl-num = <0 1 2>;
- gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-num = <0 1>;
+ gpio-req-tbl-flags = <1 0>;
gpio-req-tbl-label = "CAMIF_MCLK3",
- "CAM_RESET3",
- "CAM_VANA1";
+ "CAM_RESET3";
sensor-mode = <0>;
cci-master = <1>;
status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index a7cf880..90e1f24 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -166,6 +166,15 @@
};
port@1 {
+ reg = <6>;
+ funnel_swao_in_sensor_etm0: endpoint {
+ slave-mode;
+ remote-endpoint=
+ <&sensor_etm0_out_funnel_swao>;
+ };
+ };
+
+ port@2 {
reg = <7>;
funnel_swao_in_tpda_swao: endpoint {
slave-mode;
@@ -2049,6 +2058,20 @@
};
};
+ sensor_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+
+ coresight-name = "coresight-sensor-etm0";
+ qcom,inst-id = <8>;
+
+ port {
+ sensor_etm0_out_funnel_swao: endpoint {
+ remote-endpoint =
+ <&funnel_swao_in_sensor_etm0>;
+ };
+ };
+ };
+
modem_etm0 {
compatible = "qcom,coresight-remote-etm";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index c16e1d8..1c7269a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -328,6 +328,13 @@
/delete-property/ pinctrl-0;
};
+ gpio-regulator@4 {
+ /delete-property/ gpio;
+ /delete-property/ vin-supply;
+ /delete-property/ pinctrl-names;
+ /delete-property/ pinctrl-0;
+ };
+
/delete-node/ qcom,spmi-debug@6b22000;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 191e76d..11c48bd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -3099,6 +3099,20 @@
};
};
+ cam_sensor_rear_vana: cam_sensor_rear_vana {
+ /* AVDD LDO */
+ mux {
+ pins = "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
cam_res_mgr_active: cam_res_mgr_active {
/* AVDD_LDO*/
mux {
@@ -3200,6 +3214,77 @@
bias-pull-down; /* pull down */
};
};
+
+ ap2mdm {
+ ap2mdm_active: ap2mdm_active {
+ mux {
+ /* ap2mdm-status
+ * ap2mdm-errfatal
+ * ap2mdm-vddmin
+ */
+ pins = "gpio21", "gpio23";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21", "gpio23";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ ap2mdm_sleep: ap2mdm_sleep {
+ mux {
+ /* ap2mdm-status
+ * ap2mdm-errfatal
+ * ap2mdm-vddmin
+ */
+ pins = "gpio21", "gpio23";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21", "gpio23";
+ drive-strength = <8>;
+ bias-disable;
+ };
+
+ };
+ };
+
+ mdm2ap {
+ mdm2ap_active: mdm2ap_active {
+ mux {
+ /* mdm2ap-status
+ * mdm2ap-errfatal
+ * mdm2ap-vddmin
+ */
+ pins = "gpio22", "gpio20";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22", "gpio20";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ };
+ mdm2ap_sleep: mdm2ap_sleep {
+ mux {
+ /* mdm2ap-status
+ * mdm2ap-errfatal
+ * mdm2ap-vddmin
+ */
+ pins = "gpio22", "gpio20";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22", "gpio20";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index d2ee9eb..05d77d3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -156,6 +156,7 @@
qcom,cam_smmu {
compatible = "qcom,msm-cam-smmu";
status = "ok";
+ non-fatal-fault-disabled;
msm_cam_smmu_lrme {
compatible = "qcom,msm-cam-smmu-cb";
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 4a732e3..9b242a0 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -339,6 +339,7 @@
CONFIG_REGULATOR_MEM_ACC=y
CONFIG_REGULATOR_MSM_GFX_LDO=y
CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_REGULATOR_RPM_SMD=y
CONFIG_REGULATOR_SPM=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index ec7aad8..f6e49cd 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -349,6 +349,7 @@
CONFIG_REGULATOR_MEM_ACC=y
CONFIG_REGULATOR_MSM_GFX_LDO=y
CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_REGULATOR_RPM_SMD=y
CONFIG_REGULATOR_SPM=y
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index b64410c..96c11e7 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -46,6 +46,8 @@
extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
extern char* (*arch_read_hardware_id)(void);
+const char * __init arch_read_machine_name(void);
+
#define show_unhandled_signals_ratelimited() \
({ \
static DEFINE_RATELIMIT_STATE(_rs, \
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index a58fb92..f58539f 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -65,6 +65,7 @@
#include <asm/efi.h>
#include <asm/xen/hypervisor.h>
#include <asm/mmu_context.h>
+#include <asm/system_misc.h>
phys_addr_t __fdt_pointer __initdata;
@@ -186,6 +187,11 @@
pr_warn("Large number of MPIDR hash buckets detected\n");
}
+const char * __init __weak arch_read_machine_name(void)
+{
+ return of_flat_dt_get_machine_name();
+}
+
static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
void *dt_virt = fixmap_remap_fdt(dt_phys);
@@ -201,7 +207,7 @@
cpu_relax();
}
- machine_name = of_flat_dt_get_machine_name();
+ machine_name = arch_read_machine_name();
if (machine_name) {
dump_stack_set_arch_desc("%s (DT)", machine_name);
pr_info("Machine: %s\n", machine_name);
diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c
index af8bf00..f3c587d 100644
--- a/drivers/char/diag/diagfwd_socket.c
+++ b/drivers/char/diag/diagfwd_socket.c
@@ -513,8 +513,10 @@
info->hdl->sk->sk_user_data = NULL;
info->hdl->sk->sk_data_ready = NULL;
write_unlock_bh(&info->hdl->sk->sk_callback_lock);
+ mutex_lock(&info->socket_info_mutex);
sock_release(info->hdl);
info->hdl = NULL;
+ mutex_unlock(&info->socket_info_mutex);
wake_up_interruptible(&info->read_wait_q);
}
DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", info->name);
@@ -820,6 +822,8 @@
break;
}
+ if (info->port_type == PORT_TYPE_CLIENT)
+ mutex_init(&info->socket_info_mutex);
info->svc_id = DIAG_SVC_ID;
info->ins_id = ins_base + ins_offset;
info->inited = 1;
@@ -1031,6 +1035,8 @@
diagfwd_deregister(info->peripheral, info->type, (void *)info);
info->fwd_ctxt = NULL;
info->hdl = NULL;
+ if (info->port_type == PORT_TYPE_CLIENT)
+ mutex_destroy(&info->socket_info_mutex);
if (info->wq)
destroy_workqueue(info->wq);
@@ -1119,13 +1125,28 @@
read_msg.msg_name = &src_addr;
read_msg.msg_namelen = sizeof(src_addr);
+ if (info->port_type != PORT_TYPE_SERVER) {
+ mutex_lock(&info->socket_info_mutex);
+ if (!info->hdl) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s closing read thread\n",
+ info->name);
+ mutex_unlock(&info->socket_info_mutex);
+ goto fail;
+ }
+ }
pkt_len = kernel_recvmsg(info->hdl, &read_msg, &iov, 1, 0,
MSG_PEEK);
- if (pkt_len <= 0)
+ if (pkt_len <= 0) {
+ if (info->port_type != PORT_TYPE_SERVER)
+ mutex_unlock(&info->socket_info_mutex);
break;
+ }
if (pkt_len > bytes_remaining) {
buf_full = 1;
+ if (info->port_type != PORT_TYPE_SERVER)
+ mutex_unlock(&info->socket_info_mutex);
break;
}
@@ -1135,6 +1156,8 @@
read_len = kernel_recvmsg(info->hdl, &read_msg, &iov, 1,
pkt_len, 0);
+ if (info->port_type != PORT_TYPE_SERVER)
+ mutex_unlock(&info->socket_info_mutex);
if (read_len <= 0)
goto fail;
@@ -1211,7 +1234,16 @@
write_msg.msg_name = &info->remote_addr;
write_msg.msg_namelen = sizeof(info->remote_addr);
write_msg.msg_flags |= MSG_DONTWAIT;
+ if (info->port_type != PORT_TYPE_SERVER) {
+ mutex_lock(&info->socket_info_mutex);
+ if (!info->hdl) {
+ mutex_unlock(&info->socket_info_mutex);
+ return -ENODEV;
+ }
+ }
write_len = kernel_sendmsg(info->hdl, &write_msg, &iov, 1, len);
+ if (info->port_type != PORT_TYPE_SERVER)
+ mutex_unlock(&info->socket_info_mutex);
if (write_len < 0) {
err = write_len;
/*
diff --git a/drivers/char/diag/diagfwd_socket.h b/drivers/char/diag/diagfwd_socket.h
index a9487b1..c42be06 100644
--- a/drivers/char/diag/diagfwd_socket.h
+++ b/drivers/char/diag/diagfwd_socket.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -65,6 +65,7 @@
struct work_struct read_work;
struct diagfwd_info *fwd_ctxt;
wait_queue_head_t read_wait_q;
+ struct mutex socket_info_mutex;
};
union cntl_port_msg {
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 0ea769c..19fe223 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2006-2007 Adam Belay <abelay@novell.com>
* Copyright (C) 2009 Intel Corporation
*
@@ -619,7 +619,7 @@
next_event_us = (uint32_t)(ktime_to_us(get_next_event_time(dev->cpu)));
- if (is_cpu_biased(dev->cpu))
+ if (is_cpu_biased(dev->cpu) && (!cpu_isolated(dev->cpu)))
goto done_select;
for (i = 0; i < cpu->nlevels; i++) {
diff --git a/drivers/esoc/Kconfig b/drivers/esoc/Kconfig
index 3c65f69..4613150 100644
--- a/drivers/esoc/Kconfig
+++ b/drivers/esoc/Kconfig
@@ -38,7 +38,7 @@
allow logging of different esoc driver traces.
config ESOC_MDM_4x
- bool "Add support for external mdm9x25/mdm9x35/mdm9x55"
+ bool "Add support for external modem"
help
In some Qualcomm Technologies, Inc. boards, an external modem such as
mdm9x25 or mdm9x35 is connected to a primary msm. The primary soc can
@@ -49,7 +49,7 @@
tristate "Command engine for 4x series external modems"
help
Provides a command engine to control the behavior of an external modem
- such as mdm9x25/mdm9x35/mdm9x55/QSC. Allows the primary soc to put the
+ such as mdm9x25/mdm9x35/mdm9x55/sdxpoorwills/QSC. Allows the primary soc to put the
external modem in a specific mode. Also listens for events on the
external modem.
diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c
index 677e21d..bbec9d3 100644
--- a/drivers/esoc/esoc-mdm-4x.c
+++ b/drivers/esoc/esoc-mdm-4x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017-2018, 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
@@ -794,6 +794,28 @@
mdm->gpio_state_running = NULL;
return retval;
}
+
+static void mdm_release_ipc_gpio(struct mdm_ctrl *mdm)
+{
+ int i;
+
+ if (!mdm)
+ return;
+
+ for (i = 0; i < NUM_GPIOS; ++i)
+ if (gpio_is_valid(MDM_GPIO(mdm, i)))
+ gpio_free(MDM_GPIO(mdm, i));
+}
+
+static void mdm_free_irq(struct mdm_ctrl *mdm)
+{
+ if (!mdm)
+ return;
+
+ free_irq(mdm->errfatal_irq, mdm);
+ free_irq(mdm->status_irq, mdm);
+}
+
static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
const struct mdm_ops *ops,
struct platform_device *pdev)
@@ -1028,6 +1050,108 @@
return 0;
}
+static int sdxpoorwills_setup_hw(struct mdm_ctrl *mdm,
+ const struct mdm_ops *ops,
+ struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *node;
+ struct esoc_clink *esoc;
+ const struct esoc_clink_ops *clink_ops = ops->clink_ops;
+ const struct mdm_pon_ops *pon_ops = ops->pon_ops;
+
+ mdm->dev = &pdev->dev;
+ mdm->pon_ops = pon_ops;
+ node = pdev->dev.of_node;
+
+ esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(esoc)) {
+ dev_err(mdm->dev, "cannot allocate esoc device\n");
+ return PTR_ERR(esoc);
+ }
+
+ esoc->pdev = pdev;
+
+ mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+ if (!mdm->mdm_queue) {
+ dev_err(mdm->dev, "could not create mdm_queue\n");
+ return -ENOMEM;
+ }
+
+ mdm->irq_mask = 0;
+ mdm->ready = false;
+
+ ret = mdm_dt_parse_gpios(mdm);
+ if (ret) {
+ dev_err(mdm->dev, "Failed to parse DT gpios\n");
+ goto err_destroy_wrkq;
+ }
+
+ ret = mdm_pon_dt_init(mdm);
+ if (ret) {
+ dev_err(mdm->dev, "Failed to parse PON DT gpio\n");
+ goto err_destroy_wrkq;
+ }
+
+ ret = mdm_pinctrl_init(mdm);
+ if (ret) {
+ dev_err(mdm->dev, "Failed to init pinctrl\n");
+ goto err_destroy_wrkq;
+ }
+
+ ret = mdm_pon_setup(mdm);
+ if (ret) {
+ dev_err(mdm->dev, "Failed to setup PON\n");
+ goto err_destroy_wrkq;
+ }
+
+ ret = mdm_configure_ipc(mdm, pdev);
+ if (ret) {
+ dev_err(mdm->dev, "Failed to configure the ipc\n");
+ goto err_release_ipc;
+ }
+
+ esoc->name = SDXPOORWILLS_LABEL;
+ esoc->link_name = SDXPOORWILLS_PCIE;
+
+ ret = of_property_read_string(node, "qcom,mdm-link-info",
+ &esoc->link_info);
+ if (ret)
+ dev_info(mdm->dev, "esoc link info missing\n");
+
+ esoc->clink_ops = clink_ops;
+ esoc->parent = mdm->dev;
+ esoc->owner = THIS_MODULE;
+ esoc->np = pdev->dev.of_node;
+ set_esoc_clink_data(esoc, mdm);
+
+ ret = esoc_clink_register(esoc);
+ if (ret) {
+ dev_err(mdm->dev, "esoc registration failed\n");
+ goto err_free_irq;
+ }
+ dev_dbg(mdm->dev, "esoc registration done\n");
+
+ init_completion(&mdm->debug_done);
+ INIT_WORK(&mdm->mdm_status_work, mdm_status_fn);
+ INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason);
+ INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check);
+ mdm->get_restart_reason = false;
+ mdm->debug_fail = false;
+ mdm->esoc = esoc;
+ mdm->init = 0;
+
+ return 0;
+
+err_free_irq:
+ mdm_free_irq(mdm);
+err_release_ipc:
+ mdm_release_ipc_gpio(mdm);
+err_destroy_wrkq:
+ destroy_workqueue(mdm->mdm_queue);
+ return ret;
+}
+
static struct esoc_clink_ops mdm_cops = {
.cmd_exe = mdm_cmd_exe,
.get_status = mdm_get_status,
@@ -1053,6 +1177,12 @@
.pon_ops = &mdm9x55_pon_ops,
};
+static struct mdm_ops sdxpoorwills_ops = {
+ .clink_ops = &mdm_cops,
+ .config_hw = sdxpoorwills_setup_hw,
+ .pon_ops = &sdxpoorwills_pon_ops,
+};
+
static const struct of_device_id mdm_dt_match[] = {
{ .compatible = "qcom,ext-mdm9x25",
.data = &mdm9x25_ops, },
@@ -1060,6 +1190,8 @@
.data = &mdm9x35_ops, },
{ .compatible = "qcom,ext-mdm9x55",
.data = &mdm9x55_ops, },
+ { .compatible = "qcom,ext-sdxpoorwills",
+ .data = &sdxpoorwills_ops, },
{},
};
MODULE_DEVICE_TABLE(of, mdm_dt_match);
diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c
index 77ae84b..4291bbc 100644
--- a/drivers/esoc/esoc-mdm-drv.c
+++ b/drivers/esoc/esoc-mdm-drv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -309,6 +309,10 @@
.name = "MDM9x55",
.data = NULL,
},
+ {
+ .name = "SDXPOORWILLS",
+ .data = NULL,
+ },
};
static struct esoc_drv esoc_ssr_drv = {
diff --git a/drivers/esoc/esoc-mdm-pon.c b/drivers/esoc/esoc-mdm-pon.c
index 0e85776..9624275 100644
--- a/drivers/esoc/esoc-mdm-pon.c
+++ b/drivers/esoc/esoc-mdm-pon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017-2018, 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
@@ -60,6 +60,24 @@
return 0;
}
+/* This function can be called from atomic context. */
+static int sdxpoorwills_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
+{
+ int soft_reset_direction_assert = mdm->soft_reset_inverted;
+
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ soft_reset_direction_assert);
+ /*
+ * Allow PS hold assert to be detected
+ */
+ if (!atomic)
+ usleep_range(80000, 180000);
+ else
+ mdelay(100);
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ !soft_reset_direction_assert);
+ return 0;
+}
static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
{
@@ -99,6 +117,7 @@
{
struct device *dev = mdm->dev;
int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
+
/* Assert the soft reset line whether mdm2ap_status went low or not */
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
soft_reset_direction);
@@ -135,6 +154,27 @@
return 0;
}
+static int sdxpoorwills_power_down(struct mdm_ctrl *mdm)
+{
+ struct device *dev = mdm->dev;
+ int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
+
+ /* Assert the soft reset line whether mdm2ap_status went low or not */
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ soft_reset_direction);
+ dev_info(dev, "Doing a hard reset\n");
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ soft_reset_direction);
+ /*
+ * Currently, there is a debounce timer on the charm PMIC. It is
+ * necessary to hold the PMIC RESET low for 325ms
+ * for the reset to fully take place. Sleep here to ensure the
+ * reset has occurred before the function exits.
+ */
+ mdelay(325);
+ return 0;
+}
+
static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
{
if (!gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET)))
@@ -158,6 +198,16 @@
!mdm->soft_reset_inverted);
}
+static void sdxpoorwills_cold_reset(struct mdm_ctrl *mdm)
+{
+ dev_info(mdm->dev, "Triggering mdm cold reset");
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ !!mdm->soft_reset_inverted);
+ mdelay(600);
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ !mdm->soft_reset_inverted);
+}
+
static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
{
int val;
@@ -215,3 +265,12 @@
.dt_init = mdm4x_pon_dt_init,
.setup = mdm4x_pon_setup,
};
+
+struct mdm_pon_ops sdxpoorwills_pon_ops = {
+ .pon = mdm4x_do_first_power_on,
+ .soft_reset = sdxpoorwills_toggle_soft_reset,
+ .poff_force = sdxpoorwills_power_down,
+ .cold_reset = sdxpoorwills_cold_reset,
+ .dt_init = mdm4x_pon_dt_init,
+ .setup = mdm4x_pon_setup,
+};
diff --git a/drivers/esoc/esoc-mdm.h b/drivers/esoc/esoc-mdm.h
index 621d913..baf4e0b 100644
--- a/drivers/esoc/esoc-mdm.h
+++ b/drivers/esoc/esoc-mdm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017-2018, 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
@@ -35,6 +35,8 @@
#define MDM9x35_HSIC "HSIC"
#define MDM9x55_LABEL "MDM9x55"
#define MDM9x55_PCIE "PCIe"
+#define SDXPOORWILLS_LABEL "SDXPOORWILLS"
+#define SDXPOORWILLS_PCIE "PCIe"
#define MDM2AP_STATUS_TIMEOUT_MS 120000L
#define MDM_MODEM_TIMEOUT 3000
#define DEF_RAMDUMP_TIMEOUT 120000
@@ -150,4 +152,5 @@
extern struct mdm_pon_ops mdm9x25_pon_ops;
extern struct mdm_pon_ops mdm9x35_pon_ops;
extern struct mdm_pon_ops mdm9x55_pon_ops;
+extern struct mdm_pon_ops sdxpoorwills_pon_ops;
#endif
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index 26c1c39..da37baf 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, 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
@@ -335,8 +335,8 @@
.num_protected_regs = 0x20,
.busy_mask = 0xFFFFFFFE,
.gpmufw_name = "a630_gmu.bin",
- .gpmu_major = 0x0,
- .gpmu_minor = 0x005,
+ .gpmu_major = 0x1,
+ .gpmu_minor = 0x003,
.gpmu_tsens = 0x000C000D,
.max_power = 5448,
},
@@ -357,7 +357,7 @@
.busy_mask = 0xFFFFFFFE,
.gpmufw_name = "a630_gmu.bin",
.gpmu_major = 0x1,
- .gpmu_minor = 0x001,
+ .gpmu_minor = 0x003,
.gpmu_tsens = 0x000C000D,
.max_power = 5448,
},
@@ -368,7 +368,7 @@
.minor = 5,
.patchid = ANY_ID,
.features = ADRENO_64BIT | ADRENO_RPMH |
- ADRENO_GPMU | ADRENO_CONTENT_PROTECTION,
+ ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC,
.sqefw_name = "a630_sqe.fw",
.zap_name = "a615_zap",
.gpudev = &adreno_a6xx_gpudev,
@@ -377,6 +377,6 @@
.busy_mask = 0xFFFFFFFE,
.gpmufw_name = "a630_gmu.bin",
.gpmu_major = 0x1,
- .gpmu_minor = 0x001,
+ .gpmu_minor = 0x003,
},
};
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 7d11007..e0b725f 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1517,7 +1517,7 @@
adreno_writereg64(adreno_dev,
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
- KGSL_IOMMU_SECURE_BASE);
+ KGSL_IOMMU_SECURE_BASE(&device->mmu));
adreno_writereg(adreno_dev,
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE,
KGSL_IOMMU_SECURE_SIZE);
@@ -1848,11 +1848,6 @@
error_mmu_off:
kgsl_mmu_stop(&device->mmu);
- if (gpudev->oob_clear &&
- ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
- gpudev->oob_clear(adreno_dev,
- OOB_BOOT_SLUMBER_CLEAR_MASK);
- }
error_pwr_off:
/* set the state back to original state */
@@ -2106,7 +2101,7 @@
* anything to mmap().
*/
shadowprop.gpuaddr =
- (unsigned int) device->memstore.gpuaddr;
+ (unsigned long)device->memstore.gpuaddr;
shadowprop.size = device->memstore.size;
/* GSL needs this to be set, even if it
* appears to be meaningless
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index baf366e..a615dca 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -2424,8 +2424,8 @@
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
A5XX_CP_RB_CNTL_DEFAULT);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
- rb->buffer_desc.gpuaddr);
+ adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_BASE,
+ ADRENO_REG_CP_RB_BASE_HI, rb->buffer_desc.gpuaddr);
ret = a5xx_microcode_load(adreno_dev);
if (ret)
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 6275c19..c01640c 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -63,6 +63,9 @@
{ adreno_is_a615, a615_gbif },
};
+
+static unsigned long a6xx_oob_state_bitmask;
+
struct kgsl_hwcg_reg {
unsigned int off;
unsigned int val;
@@ -324,7 +327,6 @@
static struct reg_list_pair a6xx_ifpc_pwrup_reglist[] = {
{ A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x0 },
{ A6XX_CP_CHICKEN_DBG, 0x0 },
- { A6XX_CP_ADDR_MODE_CNTL, 0x0 },
{ A6XX_CP_DBG_ECO_CNTL, 0x0 },
{ A6XX_CP_PROTECT_CNTL, 0x0 },
{ A6XX_CP_PROTECT_REG, 0x0 },
@@ -1083,8 +1085,8 @@
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
A6XX_CP_RB_CNTL_DEFAULT);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
- rb->buffer_desc.gpuaddr);
+ adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_BASE,
+ ADRENO_REG_CP_RB_BASE_HI, rb->buffer_desc.gpuaddr);
ret = a6xx_microcode_load(adreno_dev);
if (ret)
@@ -1451,7 +1453,7 @@
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
int ret = 0;
- if (!kgsl_gmu_isenabled(device))
+ if (!kgsl_gmu_isenabled(device) || !clear_mask)
return 0;
kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set_mask);
@@ -1467,6 +1469,8 @@
kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, clear_mask);
+ set_bit((fls(clear_mask) - 1), &a6xx_oob_state_bitmask);
+
trace_kgsl_gmu_oob_set(set_mask);
return ret;
}
@@ -1481,10 +1485,15 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- if (!kgsl_gmu_isenabled(device))
+ if (!kgsl_gmu_isenabled(device) || !clear_mask)
return;
- kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, clear_mask);
+ if (test_and_clear_bit(fls(clear_mask) - 1,
+ &a6xx_oob_state_bitmask))
+ kgsl_gmu_regwrite(device,
+ A6XX_GMU_HOST2GMU_INTR_SET,
+ clear_mask);
+
trace_kgsl_gmu_oob_clear(clear_mask);
}
@@ -2308,6 +2317,9 @@
ret = a6xx_gmu_suspend(device);
break;
case GMU_FW_STOP:
+ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
+ a6xx_oob_clear(adreno_dev,
+ OOB_BOOT_SLUMBER_CLEAR_MASK);
ret = a6xx_rpmh_power_off_gpu(device);
break;
case GMU_DCVS_NOHFI:
diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c
index 2d2c9e5..022aa9f 100644
--- a/drivers/gpu/msm/adreno_sysfs.c
+++ b/drivers/gpu/msm/adreno_sysfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -31,7 +31,7 @@
#define _ADRENO_SYSFS_ATTR_RO(_name, __show) \
struct adreno_sysfs_attribute adreno_attr_##_name = { \
- .attr = __ATTR(_name, 0644, __show, NULL), \
+ .attr = __ATTR(_name, 0444, __show, NULL), \
.show = _ ## _name ## _show, \
.store = NULL, \
}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 0338c5fd..4b11bbe 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -35,12 +35,14 @@
#include "kgsl_pwrctrl.h"
#define CP_APERTURE_REG 0
+#define CP_SMMU_APERTURE_ID 0x1B
#define _IOMMU_PRIV(_mmu) (&((_mmu)->priv.iommu))
-#define ADDR_IN_GLOBAL(_a) \
- (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE) && \
- ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE + KGSL_IOMMU_GLOBAL_MEM_SIZE)))
+#define ADDR_IN_GLOBAL(_mmu, _a) \
+ (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu)) && \
+ ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) + \
+ KGSL_IOMMU_GLOBAL_MEM_SIZE)))
/*
* Flag to set SMMU memory attributes required to
@@ -184,7 +186,8 @@
if (entry != NULL) {
struct kgsl_pagetable *pagetable = device->mmu.securepagetable;
entry->pagetable = pagetable;
- entry->gpuaddr = KGSL_IOMMU_SECURE_BASE + secure_global_size;
+ entry->gpuaddr = KGSL_IOMMU_SECURE_BASE(&device->mmu) +
+ secure_global_size;
ret = kgsl_mmu_map(pagetable, entry);
if (ret == 0)
@@ -223,7 +226,8 @@
KGSL_IOMMU_GLOBAL_MEM_SIZE))
return;
- memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE + global_pt_alloc;
+ memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu) + global_pt_alloc;
+
memdesc->priv |= KGSL_MEMDESC_GLOBAL;
global_pt_alloc += memdesc->size;
@@ -641,7 +645,7 @@
/* Set the maximum possible size as an initial value */
nextentry->gpuaddr = (uint64_t) -1;
- if (ADDR_IN_GLOBAL(faultaddr)) {
+ if (ADDR_IN_GLOBAL(mmu, faultaddr)) {
_get_global_entries(faultaddr, preventry, nextentry);
} else if (context) {
private = context->proc_priv;
@@ -1030,13 +1034,13 @@
struct kgsl_iommu_pt *pt)
{
if (mmu->secured && pagetable->name == KGSL_MMU_SECURE_PT) {
- pt->compat_va_start = KGSL_IOMMU_SECURE_BASE;
- pt->compat_va_end = KGSL_IOMMU_SECURE_END;
- pt->va_start = KGSL_IOMMU_SECURE_BASE;
- pt->va_end = KGSL_IOMMU_SECURE_END;
+ pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+ pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu);
+ pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+ pt->va_end = KGSL_IOMMU_SECURE_END(mmu);
} else {
pt->compat_va_start = KGSL_IOMMU_SVM_BASE32;
- pt->compat_va_end = KGSL_IOMMU_SVM_END32;
+ pt->compat_va_end = KGSL_IOMMU_SECURE_BASE(mmu);
pt->va_start = KGSL_IOMMU_VA_BASE64;
pt->va_end = KGSL_IOMMU_VA_END64;
}
@@ -1045,7 +1049,7 @@
pagetable->name != KGSL_MMU_SECURE_PT) {
if ((BITS_PER_LONG == 32) || is_compat_task()) {
pt->svm_start = KGSL_IOMMU_SVM_BASE32;
- pt->svm_end = KGSL_IOMMU_SVM_END32;
+ pt->svm_end = KGSL_IOMMU_SECURE_BASE(mmu);
} else {
pt->svm_start = KGSL_IOMMU_SVM_BASE64;
pt->svm_end = KGSL_IOMMU_SVM_END64;
@@ -1059,19 +1063,19 @@
{
if (mmu->secured) {
if (pagetable->name == KGSL_MMU_SECURE_PT) {
- pt->compat_va_start = KGSL_IOMMU_SECURE_BASE;
- pt->compat_va_end = KGSL_IOMMU_SECURE_END;
- pt->va_start = KGSL_IOMMU_SECURE_BASE;
- pt->va_end = KGSL_IOMMU_SECURE_END;
+ pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+ pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu);
+ pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+ pt->va_end = KGSL_IOMMU_SECURE_END(mmu);
} else {
pt->va_start = KGSL_IOMMU_SVM_BASE32;
- pt->va_end = KGSL_IOMMU_SECURE_BASE;
+ pt->va_end = KGSL_IOMMU_SECURE_BASE(mmu);
pt->compat_va_start = pt->va_start;
pt->compat_va_end = pt->va_end;
}
} else {
pt->va_start = KGSL_IOMMU_SVM_BASE32;
- pt->va_end = KGSL_IOMMU_GLOBAL_MEM_BASE;
+ pt->va_end = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu);
pt->compat_va_start = pt->va_start;
pt->compat_va_end = pt->va_end;
}
@@ -1166,7 +1170,7 @@
desc.args[3] = 0xFFFFFFFF;
desc.arginfo = SCM_ARGS(4);
- return scm_call2(SCM_SIP_FNID(SCM_SVC_MP, 0x1B), &desc);
+ return scm_call2(SCM_SIP_FNID(SCM_SVC_MP, CP_SMMU_APERTURE_ID), &desc);
}
static int _init_global_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt)
@@ -1209,7 +1213,8 @@
goto done;
}
- if (!MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE)) {
+ if (!MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE) &&
+ scm_is_call_available(SCM_SVC_MP, CP_SMMU_APERTURE_ID)) {
ret = program_smmu_aperture(cb_num, CP_APERTURE_REG);
if (ret) {
pr_err("SMMU aperture programming call failed with error %d\n",
@@ -2381,7 +2386,8 @@
struct rb_node *node;
/* Make sure the requested address doesn't fall in the global range */
- if (ADDR_IN_GLOBAL(gpuaddr) || ADDR_IN_GLOBAL(gpuaddr + size))
+ if (ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr) ||
+ ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr + size))
return -ENOMEM;
spin_lock(&pagetable->lock);
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index acf8ae4..462ff3b 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -24,12 +24,17 @@
* are mapped into all pagetables.
*/
#define KGSL_IOMMU_GLOBAL_MEM_SIZE (20 * SZ_1M)
-#define KGSL_IOMMU_GLOBAL_MEM_BASE 0xf8000000
+#define KGSL_IOMMU_GLOBAL_MEM_BASE32 0xf8000000
+#define KGSL_IOMMU_GLOBAL_MEM_BASE64 TASK_SIZE_32
+
+#define KGSL_IOMMU_GLOBAL_MEM_BASE(__mmu) \
+ (MMU_FEATURE(__mmu, KGSL_MMU_64BIT) ? \
+ KGSL_IOMMU_GLOBAL_MEM_BASE64 : KGSL_IOMMU_GLOBAL_MEM_BASE32)
#define KGSL_IOMMU_SECURE_SIZE SZ_256M
-#define KGSL_IOMMU_SECURE_END KGSL_IOMMU_GLOBAL_MEM_BASE
-#define KGSL_IOMMU_SECURE_BASE \
- (KGSL_IOMMU_GLOBAL_MEM_BASE - KGSL_IOMMU_SECURE_SIZE)
+#define KGSL_IOMMU_SECURE_END(_mmu) KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu)
+#define KGSL_IOMMU_SECURE_BASE(_mmu) \
+ (KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) - KGSL_IOMMU_SECURE_SIZE)
#define KGSL_IOMMU_SVM_BASE32 0x300000
#define KGSL_IOMMU_SVM_END32 (0xC0000000 - SZ_16M)
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 16a3e7d..f3e16b3 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -39,9 +39,22 @@
#define PMI_CHG_SCALE_2 391750000000
#define QPNP_VADC_HC_VREF_CODE 0x4000
#define QPNP_VADC_HC_VDD_REFERENCE_MV 1875
+#define CHRG_SCALE_1 -250
+#define CHRG_SCALE_2 377500000
+#define DIE_SCALE_1 500
+#define DIE_SCALE_2 -273150000
+
/* Clamp negative ADC code to 0 */
#define QPNP_VADC_HC_MAX_CODE 0x7FFF
+/*Invalid current reading*/
+#define QPNP_IADC_INV 0x8000
+
+#define IADC_SCALE_1 0xffff
+#define IADC_SCALE_2 152593
+
+#define USBIN_I_SCALE 25
+
/*
* Units for temperature below (on x axis) is in 0.1DegC as
* required by the battery driver. Note the resolution used
@@ -590,6 +603,80 @@
{30, 125}
};
+/* Voltage to temperature */
+static const struct qpnp_vadc_map_pt adcmap_batt_therm[] = {
+ {1770, -400},
+ {1757, -380},
+ {1743, -360},
+ {1727, -340},
+ {1710, -320},
+ {1691, -300},
+ {1671, -280},
+ {1650, -260},
+ {1627, -240},
+ {1602, -220},
+ {1576, -200},
+ {1548, -180},
+ {1519, -160},
+ {1488, -140},
+ {1456, -120},
+ {1423, -100},
+ {1388, -80},
+ {1353, -60},
+ {1316, -40},
+ {1278, -20},
+ {1240, 0},
+ {1201, 20},
+ {1162, 40},
+ {1122, 60},
+ {1082, 80},
+ {1042, 100},
+ {1003, 120},
+ {964, 140},
+ {925, 160},
+ {887, 180},
+ {849, 200},
+ {812, 220},
+ {777, 240},
+ {742, 260},
+ {708, 280},
+ {675, 300},
+ {643, 320},
+ {613, 340},
+ {583, 360},
+ {555, 380},
+ {528, 400},
+ {502, 420},
+ {477, 440},
+ {453, 460},
+ {430, 480},
+ {409, 500},
+ {388, 520},
+ {369, 540},
+ {350, 560},
+ {333, 580},
+ {316, 600},
+ {300, 620},
+ {285, 640},
+ {271, 660},
+ {257, 680},
+ {245, 700},
+ {233, 720},
+ {221, 740},
+ {210, 760},
+ {200, 780},
+ {190, 800},
+ {181, 820},
+ {173, 840},
+ {164, 860},
+ {157, 880},
+ {149, 900},
+ {142, 920},
+ {136, 940},
+ {129, 960},
+ {124, 980}
+};
+
/*
* Voltage to temperature table for 100k pull up for NTCG104EF104 with
* 1.875V reference.
@@ -899,6 +986,36 @@
}
EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
+int32_t qpnp_adc_batt_therm(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t batt_thm_voltage = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ if (adc_properties->adc_hc) {
+ /* (code * vref_vadc (1.875V) * 1000) / (scale_code * 1000) */
+ if (adc_code > QPNP_VADC_HC_MAX_CODE)
+ adc_code = 0;
+ batt_thm_voltage = (int64_t) adc_code;
+ batt_thm_voltage *= (adc_properties->adc_vdd_reference
+ * 1000);
+ batt_thm_voltage = div64_s64(batt_thm_voltage,
+ adc_properties->full_scale_code * 1000);
+ qpnp_adc_map_voltage_temp(adcmap_batt_therm,
+ ARRAY_SIZE(adcmap_batt_therm),
+ batt_thm_voltage, &adc_chan_result->physical);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_batt_therm);
+
int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *chip,
int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -920,6 +1037,70 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
+int32_t qpnp_adc_scale_chrg_temp(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int rc = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ rc = qpnp_adc_scale_default(vadc, adc_code, adc_properties,
+ chan_properties, adc_chan_result);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+ adc_chan_result->physical);
+ adc_chan_result->physical = (int64_t) ((CHRG_SCALE_1) *
+ (adc_chan_result->physical));
+ adc_chan_result->physical = (int64_t) (adc_chan_result->physical +
+ CHRG_SCALE_2);
+ adc_chan_result->physical = (int64_t) adc_chan_result->physical;
+ adc_chan_result->physical = div64_s64(adc_chan_result->physical,
+ 1000000);
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_chrg_temp);
+
+int32_t qpnp_adc_scale_die_temp(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int rc = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ rc = qpnp_adc_scale_default(vadc, adc_code, adc_properties,
+ chan_properties, adc_chan_result);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+ adc_chan_result->physical);
+ adc_chan_result->physical = (int64_t) ((DIE_SCALE_1) *
+ (adc_chan_result->physical));
+ adc_chan_result->physical = (int64_t) (adc_chan_result->physical +
+ DIE_SCALE_2);
+ adc_chan_result->physical = (int64_t) adc_chan_result->physical;
+ adc_chan_result->physical = div64_s64(adc_chan_result->physical,
+ 1000000);
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_die_temp);
+
int32_t qpnp_adc_scale_qrd_batt_therm(struct qpnp_vadc_chip *chip,
int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -1279,6 +1460,73 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_default);
+int32_t qpnp_iadc_scale_default(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t scale_current = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ if (adc_properties->adc_hc) {
+
+ if (adc_code == QPNP_IADC_INV)
+ return -EINVAL;
+
+ scale_current = (int64_t) adc_code;
+
+ if (adc_code > QPNP_IADC_INV) {
+ scale_current = ((~scale_current) & IADC_SCALE_1);
+ scale_current++;
+ scale_current = -scale_current;
+ }
+ }
+
+ scale_current *= IADC_SCALE_2;
+ scale_current = div64_s64(scale_current,
+ 1000);
+ scale_current *= chan_properties->offset_gain_denominator;
+ scale_current = div64_s64(scale_current,
+ chan_properties->offset_gain_numerator);
+ adc_chan_result->measurement = scale_current;
+ /*
+ * Note: adc_chan_result->measurement is in uA.
+ */
+ adc_chan_result->physical = adc_chan_result->measurement;
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_iadc_scale_default);
+
+int qpnp_adc_scale_usbin_curr(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int rc = 0;
+
+ rc = qpnp_adc_scale_default(vadc, adc_code, adc_properties,
+ chan_properties, adc_chan_result);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+ adc_chan_result->physical);
+ adc_chan_result->physical = (int64_t) ((USBIN_I_SCALE) *
+ adc_chan_result->physical);
+ adc_chan_result->physical = div64_s64(adc_chan_result->physical,
+ 10);
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_usbin_curr);
+
int32_t qpnp_adc_usb_scaler(struct qpnp_vadc_chip *chip,
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 6fde46e..8b44c0f 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -219,6 +219,11 @@
[SCALE_NCP_03WF683_THERM] = {qpnp_adc_scale_therm_ncp03},
[SCALE_QRD_SKUT1_BATT_THERM] = {qpnp_adc_scale_qrd_skut1_batt_therm},
[SCALE_PMI_CHG_TEMP] = {qpnp_adc_scale_pmi_chg_temp},
+ [SCALE_BATT_THERM_TEMP] = {qpnp_adc_batt_therm},
+ [SCALE_CHRG_TEMP] = {qpnp_adc_scale_chrg_temp},
+ [SCALE_DIE_TEMP] = {qpnp_adc_scale_die_temp},
+ [SCALE_I_DEFAULT] = {qpnp_iadc_scale_default},
+ [SCALE_USBIN_I] = {qpnp_adc_scale_usbin_curr},
};
static struct qpnp_vadc_rscale_fn adc_vadc_rscale_fn[] = {
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 145af90..0bc9439 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -3600,6 +3600,11 @@
return -EPERM;
mutex_lock(&drvdata->lock);
+ if (!drvdata->enable) {
+ mutex_unlock(&drvdata->lock);
+ return -EPERM;
+ }
+
TPDM_UNLOCK(drvdata);
val = tpdm_readl(drvdata, TPDM_CMB_READVAL);
TPDM_LOCK(drvdata);
@@ -3622,6 +3627,11 @@
return -EPERM;
mutex_lock(&drvdata->lock);
+ if (!drvdata->enable) {
+ mutex_unlock(&drvdata->lock);
+ return -EPERM;
+ }
+
TPDM_UNLOCK(drvdata);
val = tpdm_readl(drvdata, TPDM_CMB_READCTL);
TPDM_LOCK(drvdata);
@@ -3650,6 +3660,11 @@
return -EPERM;
mutex_lock(&drvdata->lock);
+ if (!drvdata->enable) {
+ mutex_unlock(&drvdata->lock);
+ return -EPERM;
+ }
+
TPDM_UNLOCK(drvdata);
tpdm_writel(drvdata, val, TPDM_CMB_READCTL);
TPDM_LOCK(drvdata);
@@ -3748,6 +3763,11 @@
return -EPERM;
mutex_lock(&drvdata->lock);
+ if (!drvdata->enable) {
+ mutex_unlock(&drvdata->lock);
+ return -EPERM;
+ }
+
TPDM_UNLOCK(drvdata);
tpdm_writel(drvdata, val, TPDM_CMB_MARKR);
TPDM_LOCK(drvdata);
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
index 9ce3026..3d808fb 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
@@ -4720,6 +4720,8 @@
struct synaptics_rmi4_exp_fhandler *exp_fhandler;
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
unsigned char device_ctrl;
+ const struct synaptics_dsx_board_data *bdata =
+ rmi4_data->hw_if->board_data;
if (rmi4_data->stay_awake)
return 0;
@@ -4762,9 +4764,10 @@
synaptics_rmi4_free_fingers(rmi4_data);
}
- if (rmi4_data->ts_pinctrl)
- pinctrl_select_state(rmi4_data->ts_pinctrl,
- rmi4_data->pinctrl_state_suspend);
+ if (bdata->reset_gpio >= 0) {
+ gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
+ msleep(bdata->reset_active_ms);
+ }
synaptics_rmi4_enable_reg(rmi4_data, false);
@@ -4790,6 +4793,8 @@
struct synaptics_rmi4_exp_fhandler *exp_fhandler;
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_dsx_board_data *bdata =
+ rmi4_data->hw_if->board_data;
if (rmi4_data->stay_awake)
return 0;
@@ -4801,9 +4806,13 @@
synaptics_rmi4_enable_reg(rmi4_data, true);
- if (rmi4_data->ts_pinctrl)
- pinctrl_select_state(rmi4_data->ts_pinctrl,
- rmi4_data->pinctrl_state_active);
+ if (bdata->reset_gpio >= 0) {
+ gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
+ msleep(bdata->reset_active_ms);
+ gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state);
+ msleep(bdata->reset_delay_ms);
+ }
+
rmi4_data->current_page = MASK_8BIT;
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index 29e09c9..d2e576d 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -210,6 +210,7 @@
#define QPNP_WLED_SEC_ACCESS_REG(b) (b + 0xD0)
#define QPNP_WLED_SEC_UNLOCK 0xA5
+#define NUM_DDIC_CODES 256
#define QPNP_WLED_MAX_STRINGS 4
#define QPNP_PM660_WLED_MAX_STRINGS 3
#define WLED_MAX_LEVEL_4095 4095
@@ -315,6 +316,7 @@
* @ cdev - led class device
* @ pdev - platform device
* @ work - worker for led operation
+ * @ wq - workqueue for setting brightness level
* @ lock - mutex lock for exclusive access
* @ fdbk_op - output feedback mode
* @ dim_mode - dimming mode
@@ -340,6 +342,10 @@
* @ ramp_ms - delay between ramp steps in ms
* @ ramp_step - ramp step size
* @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC
+ * @ auto_calibration_ovp_count - OVP fault irq count to run auto calibration
+ * @ max_strings - Number of strings supported in WLED peripheral
+ * @ prev_level - Previous brightness level
+ * @ brt_map_table - Brightness map table
* @ strings - supported list of strings
* @ num_strings - number of strings
* @ loop_auto_gm_thresh - the clamping level for auto gm
@@ -353,6 +359,13 @@
* @ en_cabc - enable or disable cabc
* @ disp_type_amoled - type of display: LCD/AMOLED
* @ en_ext_pfet_sc_pro - enable sc protection on external pfet
+ * @ prev_state - previous state of WLED
+ * @ stepper_en - Flag to enable stepper algorithm
+ * @ ovp_irq_disabled - OVP interrupt disable status
+ * @ auto_calib_enabled - Flag to enable auto calibration feature
+ * @ auto_calib_done - Flag to indicate auto calibration is done
+ * @ module_dis_perm - Flat to keep module permanently disabled
+ * @ start_ovp_fault_time - Time when the OVP fault first occurred
*/
struct qpnp_wled {
struct led_classdev cdev;
@@ -360,6 +373,7 @@
struct regmap *regmap;
struct pmic_revid_data *pmic_rev_id;
struct work_struct work;
+ struct workqueue_struct *wq;
struct mutex lock;
struct mutex bus_lock;
enum qpnp_wled_fdbk_op fdbk_op;
@@ -388,6 +402,8 @@
u16 cons_sync_write_delay_us;
u16 auto_calibration_ovp_count;
u16 max_strings;
+ u16 prev_level;
+ u16 *brt_map_table;
u8 strings[QPNP_WLED_MAX_STRINGS];
u8 num_strings;
u8 loop_auto_gm_thresh;
@@ -402,6 +418,7 @@
bool disp_type_amoled;
bool en_ext_pfet_sc_pro;
bool prev_state;
+ bool stepper_en;
bool ovp_irq_disabled;
bool auto_calib_enabled;
bool auto_calib_done;
@@ -409,6 +426,21 @@
ktime_t start_ovp_fault_time;
};
+static int qpnp_wled_step_delay_us = 52000;
+module_param_named(
+ total_step_delay_us, qpnp_wled_step_delay_us, int, 0600
+);
+
+static int qpnp_wled_step_size_threshold = 3;
+module_param_named(
+ step_size_threshold, qpnp_wled_step_size_threshold, int, 0600
+);
+
+static int qpnp_wled_step_delay_gain = 2;
+module_param_named(
+ step_delay_gain, qpnp_wled_step_delay_gain, int, 0600
+);
+
/* helper to read a pmic register */
static int qpnp_wled_read_reg(struct qpnp_wled *wled, u16 addr, u8 *data)
{
@@ -570,6 +602,93 @@
return rc;
}
+ pr_debug("level:%d\n", level);
+ return 0;
+}
+
+static int qpnp_wled_set_map_level(struct qpnp_wled *wled, int level)
+{
+ int rc, i;
+
+ if (level < wled->prev_level) {
+ for (i = wled->prev_level; i >= level; i--) {
+ rc = qpnp_wled_set_level(wled, wled->brt_map_table[i]);
+ if (rc < 0) {
+ pr_err("set brightness level failed, rc:%d\n",
+ rc);
+ return rc;
+ }
+ }
+ } else if (level > wled->prev_level) {
+ for (i = wled->prev_level; i <= level; i++) {
+ rc = qpnp_wled_set_level(wled, wled->brt_map_table[i]);
+ if (rc < 0) {
+ pr_err("set brightness level failed, rc:%d\n",
+ rc);
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int qpnp_wled_set_step_level(struct qpnp_wled *wled, int new_level)
+{
+ int rc, i, num_steps, delay_us;
+ u16 level, start_level, end_level, step_size;
+ bool level_inc = false;
+
+ level = wled->prev_level;
+ start_level = wled->brt_map_table[level];
+ end_level = wled->brt_map_table[new_level];
+ level_inc = (new_level > level);
+
+ num_steps = abs(start_level - end_level);
+ if (!num_steps)
+ return 0;
+
+ delay_us = qpnp_wled_step_delay_us / num_steps;
+ pr_debug("level goes from [%d %d] num_steps: %d, delay: %d\n",
+ start_level, end_level, num_steps, delay_us);
+
+ if (delay_us < 500) {
+ step_size = 1000 / delay_us;
+ num_steps = num_steps / step_size;
+ delay_us = 1000;
+ } else {
+ if (num_steps < qpnp_wled_step_size_threshold)
+ delay_us *= qpnp_wled_step_delay_gain;
+
+ step_size = 1;
+ }
+
+ i = start_level;
+ while (num_steps--) {
+ if (level_inc)
+ i += step_size;
+ else
+ i -= step_size;
+
+ rc = qpnp_wled_set_level(wled, i);
+ if (rc < 0)
+ return rc;
+
+ if (delay_us > 0) {
+ if (delay_us < 20000)
+ usleep_range(delay_us, delay_us + 1);
+ else
+ msleep(delay_us / USEC_PER_MSEC);
+ }
+ }
+
+ if (i != end_level) {
+ i = end_level;
+ rc = qpnp_wled_set_level(wled, i);
+ if (rc < 0)
+ return rc;
+ }
+
return 0;
}
@@ -942,15 +1061,33 @@
static void qpnp_wled_work(struct work_struct *work)
{
struct qpnp_wled *wled;
- int level, rc;
+ int level, level_255, rc;
wled = container_of(work, struct qpnp_wled, work);
+ mutex_lock(&wled->lock);
level = wled->cdev.brightness;
- mutex_lock(&wled->lock);
+ if (wled->brt_map_table) {
+ /*
+ * Change the 12 bit level to 8 bit level and use the mapped
+ * values for 12 bit level from brightness map table.
+ */
+ level_255 = DIV_ROUND_CLOSEST(level, 16);
+ if (level_255 > 255)
+ level_255 = 255;
- if (level) {
+ pr_debug("level: %d level_255: %d\n", level, level_255);
+ if (wled->stepper_en)
+ rc = qpnp_wled_set_step_level(wled, level_255);
+ else
+ rc = qpnp_wled_set_map_level(wled, level_255);
+ if (rc) {
+ dev_err(&wled->pdev->dev, "wled set level failed\n");
+ goto unlock_mutex;
+ }
+ wled->prev_level = level_255;
+ } else if (level) {
rc = qpnp_wled_set_level(wled, level);
if (rc) {
dev_err(&wled->pdev->dev, "wled set level failed\n");
@@ -1009,7 +1146,7 @@
level = wled->cdev.max_brightness;
wled->cdev.brightness = level;
- schedule_work(&wled->work);
+ queue_work(wled->wq, &wled->work);
}
static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
@@ -2115,7 +2252,7 @@
struct property *prop;
const char *temp_str;
u32 temp_val;
- int rc, i;
+ int rc, i, size;
u8 *strings;
wled->cdev.name = "wled";
@@ -2134,6 +2271,45 @@
return rc;
}
+ if (of_find_property(pdev->dev.of_node, "qcom,wled-brightness-map",
+ NULL)) {
+ size = of_property_count_elems_of_size(pdev->dev.of_node,
+ "qcom,wled-brightness-map", sizeof(u16));
+ if (size != NUM_DDIC_CODES) {
+ pr_err("Invalid WLED brightness map size:%d\n", size);
+ return rc;
+ }
+
+ wled->brt_map_table = devm_kcalloc(&pdev->dev, NUM_DDIC_CODES,
+ sizeof(u16), GFP_KERNEL);
+ if (!wled->brt_map_table)
+ return -ENOMEM;
+
+ rc = of_property_read_u16_array(pdev->dev.of_node,
+ "qcom,wled-brightness-map", wled->brt_map_table,
+ NUM_DDIC_CODES);
+ if (rc < 0) {
+ pr_err("Error in reading WLED brightness map, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ for (i = 0; i < NUM_DDIC_CODES; i++) {
+ if (wled->brt_map_table[i] > WLED_MAX_LEVEL_4095) {
+ pr_err("WLED brightness map not in range\n");
+ return -EDOM;
+ }
+
+ if ((i > 1) && wled->brt_map_table[i]
+ < wled->brt_map_table[i - 1]) {
+ pr_err("WLED brightness map not in ascending order?\n");
+ return -EDOM;
+ }
+ }
+ }
+
+ wled->stepper_en = of_property_read_bool(pdev->dev.of_node,
+ "qcom,wled-stepper-en");
wled->disp_type_amoled = of_property_read_bool(pdev->dev.of_node,
"qcom,disp-type-amoled");
if (wled->disp_type_amoled) {
@@ -2470,6 +2646,7 @@
}
wled->pmic_rev_id = get_revid_data(revid_node);
+ of_node_put(revid_node);
if (IS_ERR_OR_NULL(wled->pmic_rev_id)) {
pr_err("Unable to get pmic_revid rc=%ld\n",
PTR_ERR(wled->pmic_rev_id));
@@ -2484,6 +2661,12 @@
pr_debug("PMIC subtype %d Digital major %d\n",
wled->pmic_rev_id->pmic_subtype, wled->pmic_rev_id->rev4);
+ wled->wq = alloc_ordered_workqueue("qpnp_wled_wq", WQ_HIGHPRI);
+ if (!wled->wq) {
+ pr_err("Unable to alloc workqueue for WLED\n");
+ return -ENOMEM;
+ }
+
prop = of_get_address_by_name(pdev->dev.of_node, QPNP_WLED_SINK_BASE,
NULL, NULL);
if (!prop) {
@@ -2549,6 +2732,7 @@
led_classdev_unregister(&wled->cdev);
wled_register_fail:
cancel_work_sync(&wled->work);
+ destroy_workqueue(wled->wq);
mutex_destroy(&wled->lock);
return rc;
}
@@ -2564,6 +2748,7 @@
led_classdev_unregister(&wled->cdev);
cancel_work_sync(&wled->work);
+ destroy_workqueue(wled->wq);
mutex_destroy(&wled->lock);
return 0;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index 00ead5d..3ebe7a1 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -662,9 +662,10 @@
opp = dev_pm_opp_find_freq_ceil(dev, &corner_freq);
if (IS_ERR(opp)) {
- CAM_ERR(CAM_CPAS, "Error on OPP freq :%ld, %pK",
+ CAM_DBG(CAM_CPAS, "OPP Ceil not available for freq :%ld, %pK",
corner_freq, opp);
- return -EINVAL;
+ *req_level = CAM_TURBO_VOTE;
+ return 0;
}
corner = dev_pm_opp_get_voltage(opp);
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
index 6909972..73663b3 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 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
@@ -74,6 +74,7 @@
#define ICP_SHARED_MEM_IN_BYTES (1024 * 1024)
#define ICP_UNCACHED_HEAP_SIZE_IN_BYTES (2 * 1024 * 1024)
#define ICP_HFI_MAX_PKT_SIZE_IN_WORDS 25600
+#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS 256
#define ICP_HFI_QTBL_HOSTID1 0x01000000
#define ICP_HFI_QTBL_STATUS_ENABLED 0x00000001
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
index 837efec..0412b8a 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 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
@@ -197,6 +197,7 @@
} __packed;
#define MAX_NUM_OF_IMAGE_PLANES 2
+#define MAX_HFR_GROUP 16
enum hfi_ipe_io_images {
IPE_INPUT_IMAGE_FULL,
@@ -220,6 +221,40 @@
IPE_IO_IMAGES_MAX
};
+enum bps_io_images {
+ BPS_INPUT_IMAGE,
+ BPS_OUTPUT_IMAGE_FULL,
+ BPS_OUTPUT_IMAGE_DS4,
+ BPS_OUTPUT_IMAGE_DS16,
+ BPS_OUTPUT_IMAGE_DS64,
+ BPS_OUTPUT_IMAGE_STATS_BG,
+ BPS_OUTPUT_IMAGE_STATS_BHIST,
+ BPS_OUTPUT_IMAGE_REG1,
+ BPS_OUTPUT_IMAGE_REG2,
+ BPS_OUTPUT_IMAGE_FIRST = BPS_OUTPUT_IMAGE_FULL,
+ BPS_OUTPUT_IMAGE_LAST = BPS_OUTPUT_IMAGE_REG2,
+ BPS_IO_IMAGES_MAX
+};
+
+struct frame_buffer {
+ uint32_t buffer_ptr[MAX_NUM_OF_IMAGE_PLANES];
+ uint32_t meta_buffer_ptr[MAX_NUM_OF_IMAGE_PLANES];
+} __packed;
+
+struct bps_frame_process_data {
+ struct frame_buffer buffers[BPS_IO_IMAGES_MAX];
+ uint32_t max_num_cores;
+ uint32_t target_time;
+ uint32_t ubwc_stats_buffer_addr;
+ uint32_t ubwc_stats_buffer_size;
+ uint32_t cdm_buffer_addr;
+ uint32_t cdm_buffer_size;
+ uint32_t iq_settings_addr;
+ uint32_t strip_lib_out_addr;
+ uint32_t cdm_prog_addr;
+ uint32_t request_id;
+};
+
enum hfi_ipe_image_format {
IMAGE_FORMAT_INVALID,
IMAGE_FORMAT_MIPI_8,
@@ -361,6 +396,49 @@
struct buffer_layout meta_buf_layout[MAX_NUM_OF_IMAGE_PLANES];
} __packed;
+struct ica_stab_coeff {
+ uint32_t coeffs[8];
+} __packed;
+
+struct ica_stab_params {
+ uint32_t mode;
+ struct ica_stab_coeff transforms[3];
+} __packed;
+
+struct frame_set {
+ struct frame_buffer buffers[IPE_IO_IMAGES_MAX];
+ struct ica_stab_params ica_params;
+ uint32_t cdm_ica1_addr;
+ uint32_t cdm_ica2_addr;
+} __packed;
+
+struct ipe_frame_process_data {
+ uint32_t strip_lib_out_addr;
+ uint32_t iq_settings_addr;
+ uint32_t scratch_buffer_addr;
+ uint32_t scratch_buffer_size;
+ uint32_t ubwc_stats_buffer_addr;
+ uint32_t ubwc_stats_buffer_size;
+ uint32_t cdm_buffer_addr;
+ uint32_t cdm_buffer_size;
+ uint32_t max_num_cores;
+ uint32_t target_time;
+ uint32_t cdm_prog_base;
+ uint32_t cdm_pre_ltm;
+ uint32_t cdm_post_ltm;
+ uint32_t cdm_anr_full_pass;
+ uint32_t cdm_anr_ds4;
+ uint32_t cdm_anr_ds16;
+ uint32_t cdm_anr_ds64;
+ uint32_t cdm_tf_full_pass;
+ uint32_t cdm_tf_ds4;
+ uint32_t cdm_tf_ds16;
+ uint32_t cdm_tf_ds64;
+ uint32_t request_id;
+ uint32_t frames_in_batch;
+ struct frame_set framesets[MAX_HFR_GROUP];
+} __packed;
+
/**
* struct hfi_cmd_ipe_config
* @images: images descreptions
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index eca16d6..77f33d0 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -138,6 +138,7 @@
struct hfi_q_hdr *q;
uint32_t new_read_idx, size_in_words, word_diff, temp;
uint32_t *read_q, *read_ptr, *write_ptr;
+ uint32_t size_upper_bound = 0;
int rc = 0;
if (!pmsg) {
@@ -175,10 +176,13 @@
goto err;
}
- if (q_id == Q_MSG)
+ if (q_id == Q_MSG) {
read_q = (uint32_t *)g_hfi->map.msg_q.kva;
- else
+ size_upper_bound = ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS;
+ } else {
read_q = (uint32_t *)g_hfi->map.dbg_q.kva;
+ size_upper_bound = ICP_HFI_MAX_PKT_SIZE_IN_WORDS;
+ }
read_ptr = (uint32_t *)(read_q + q->qhdr_read_idx);
write_ptr = (uint32_t *)(read_q + q->qhdr_write_idx);
@@ -196,7 +200,7 @@
}
if ((size_in_words == 0) ||
- (size_in_words > ICP_HFI_MAX_PKT_SIZE_IN_WORDS)) {
+ (size_in_words > size_upper_bound)) {
CAM_ERR(CAM_HFI, "invalid HFI message packet size - 0x%08x",
size_in_words << BYTE_WORD_SHIFT);
q->qhdr_read_idx = q->qhdr_write_idx;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
index 25e1ce7..5bd7f1c 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
@@ -276,22 +276,29 @@
rc = cam_bps_handle_resume(bps_dev);
break;
case CAM_ICP_BPS_CMD_UPDATE_CLK: {
- uint32_t clk_rate = *(uint32_t *)cmd_args;
+ struct cam_a5_clk_update_cmd *clk_upd_cmd =
+ (struct cam_a5_clk_update_cmd *)cmd_args;
+ uint32_t clk_rate = clk_upd_cmd->curr_clk_rate;
CAM_DBG(CAM_ICP, "bps_src_clk rate = %d", (int)clk_rate);
+
if (!core_info->clk_enable) {
- cam_bps_handle_pc(bps_dev);
- cam_cpas_reg_write(core_info->cpas_handle,
- CAM_CPAS_REG_CPASTOP,
- hw_info->pwr_ctrl, true, 0x0);
+ if (clk_upd_cmd->ipe_bps_pc_enable) {
+ cam_bps_handle_pc(bps_dev);
+ cam_cpas_reg_write(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP,
+ hw_info->pwr_ctrl, true, 0x0);
+ }
rc = cam_bps_toggle_clk(soc_info, true);
if (rc)
CAM_ERR(CAM_ICP, "Enable failed");
else
core_info->clk_enable = true;
- rc = cam_bps_handle_resume(bps_dev);
- if (rc)
- CAM_ERR(CAM_ICP, "handle resume failed");
+ if (clk_upd_cmd->ipe_bps_pc_enable) {
+ rc = cam_bps_handle_resume(bps_dev);
+ if (rc)
+ CAM_ERR(CAM_ICP, "BPS resume failed");
+ }
}
CAM_DBG(CAM_ICP, "clock rate %d", clk_rate);
rc = cam_bps_update_clk_rate(soc_info, clk_rate);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index f44fcc0..0012b34 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -247,12 +247,12 @@
(struct cam_icp_clk_info *)task_data->data;
uint32_t id;
uint32_t i;
- uint32_t curr_clk_rate;
struct cam_icp_hw_ctx_data *ctx_data;
struct cam_hw_intf *ipe0_dev_intf = NULL;
struct cam_hw_intf *ipe1_dev_intf = NULL;
struct cam_hw_intf *bps_dev_intf = NULL;
struct cam_hw_intf *dev_intf = NULL;
+ struct cam_a5_clk_update_cmd clk_upd_cmd;
ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
@@ -290,14 +290,17 @@
CAM_DBG(CAM_ICP, "Disable %d", clk_info->hw_type);
+ clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag;
+
dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
- &curr_clk_rate, sizeof(curr_clk_rate));
+ &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd));
if (clk_info->hw_type != ICP_CLK_HW_BPS)
if (ipe1_dev_intf)
ipe1_dev_intf->hw_ops.process_cmd(
ipe1_dev_intf->hw_priv, id,
- &curr_clk_rate, sizeof(curr_clk_rate));
+ &clk_upd_cmd,
+ sizeof(struct cam_a5_clk_update_cmd));
return 0;
}
@@ -747,6 +750,7 @@
struct cam_hw_intf *ipe1_dev_intf = NULL;
struct cam_hw_intf *bps_dev_intf = NULL;
struct cam_hw_intf *dev_intf = NULL;
+ struct cam_a5_clk_update_cmd clk_upd_cmd;
ipe0_dev_intf = hw_mgr->ipe0_dev_intf;
ipe1_dev_intf = hw_mgr->ipe1_dev_intf;
@@ -768,14 +772,18 @@
id = CAM_ICP_IPE_CMD_UPDATE_CLK;
}
+ clk_upd_cmd.curr_clk_rate = curr_clk_rate;
+ clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag;
+
dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
- &curr_clk_rate, sizeof(curr_clk_rate));
+ &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd));
if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS)
if (ipe1_dev_intf)
ipe1_dev_intf->hw_ops.process_cmd(
ipe1_dev_intf->hw_priv, id,
- &curr_clk_rate, sizeof(curr_clk_rate));
+ &clk_upd_cmd,
+ sizeof(struct cam_a5_clk_update_cmd));
return 0;
}
@@ -863,7 +871,7 @@
if (hw_mgr->bps_ctxt_cnt++)
goto end;
bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0);
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
bps_dev_intf->hw_ops.process_cmd(
bps_dev_intf->hw_priv,
CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0);
@@ -874,7 +882,7 @@
goto end;
ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0);
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
ipe0_dev_intf->hw_ops.process_cmd(
ipe0_dev_intf->hw_priv,
CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
@@ -884,21 +892,21 @@
ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv,
NULL, 0);
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
ipe1_dev_intf->hw_ops.process_cmd(
ipe1_dev_intf->hw_priv,
CAM_ICP_IPE_CMD_POWER_RESUME,
NULL, 0);
}
}
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
hw_mgr->core_info = hw_mgr->core_info |
(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1);
}
}
CAM_DBG(CAM_ICP, "core_info %X", hw_mgr->core_info);
- if (icp_hw_mgr.icp_pc_flag)
+ if (icp_hw_mgr.ipe_bps_pc_flag)
rc = hfi_enable_ipe_bps_pc(true, hw_mgr->core_info);
else
rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info);
@@ -936,7 +944,7 @@
if (hw_mgr->bps_ctxt_cnt)
goto end;
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
rc = bps_dev_intf->hw_ops.process_cmd(
bps_dev_intf->hw_priv,
CAM_ICP_BPS_CMD_POWER_COLLAPSE,
@@ -954,7 +962,7 @@
if (hw_mgr->ipe_ctxt_cnt)
goto end;
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
rc = ipe0_dev_intf->hw_ops.process_cmd(
ipe0_dev_intf->hw_priv,
CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
@@ -963,7 +971,7 @@
ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
if (ipe1_dev_intf) {
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
rc = ipe1_dev_intf->hw_ops.process_cmd(
ipe1_dev_intf->hw_priv,
CAM_ICP_IPE_CMD_POWER_COLLAPSE,
@@ -973,7 +981,7 @@
ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
NULL, 0);
}
- if (icp_hw_mgr.icp_pc_flag) {
+ if (icp_hw_mgr.ipe_bps_pc_flag) {
hw_mgr->core_info = hw_mgr->core_info &
(~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1));
}
@@ -1031,7 +1039,18 @@
rc = -ENOMEM;
goto err;
}
- icp_hw_mgr.icp_pc_flag = 1;
+ icp_hw_mgr.icp_pc_flag = false;
+
+ if (!debugfs_create_bool("ipe_bps_pc",
+ 0644,
+ icp_hw_mgr.dentry,
+ &icp_hw_mgr.ipe_bps_pc_flag)) {
+ CAM_ERR(CAM_ICP, "failed to create ipe_bps_pc entry");
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ icp_hw_mgr.ipe_bps_pc_flag = false;
if (!debugfs_create_file("icp_debug_clk",
0644,
@@ -1159,11 +1178,9 @@
mutex_lock(&ctx_data->ctx_mutex);
if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) {
+ CAM_DBG(CAM_ICP, "ctx %u is in %d state",
+ ctx_data->ctx_id, ctx_data->state);
mutex_unlock(&ctx_data->ctx_mutex);
- CAM_WARN(CAM_ICP,
- "ctx with id: %u not in the right state : %x",
- ctx_data->ctx_id,
- ctx_data->state);
return 0;
}
@@ -1814,7 +1831,10 @@
}
a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
- rc = cam_icp_mgr_send_pc_prep(hw_mgr);
+ if (!hw_mgr->icp_pc_flag)
+ rc = cam_icp_mgr_hw_close(hw_mgr, NULL);
+ else
+ rc = cam_icp_mgr_send_pc_prep(hw_mgr);
cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
@@ -1871,33 +1891,6 @@
hw_mgr->a5_jtag_debug);
}
-static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr)
-{
- int rc = 0;
- struct cam_hw_intf *a5_dev_intf = NULL;
-
- CAM_DBG(CAM_ICP, "Enter");
- a5_dev_intf = hw_mgr->a5_dev_intf;
-
- if (!a5_dev_intf) {
- CAM_ERR(CAM_ICP, "a5 dev intf is wrong");
- return -EINVAL;
- }
-
- rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
- if (rc)
- return -EINVAL;
-
- rc = cam_icp_mgr_hfi_resume(hw_mgr);
- if (rc)
- goto hfi_resume_failed;
-
- CAM_DBG(CAM_ICP, "Exit");
- return rc;
-hfi_resume_failed:
- cam_icp_mgr_icp_power_collapse(hw_mgr);
- return rc;
-}
static int cam_icp_mgr_abort_handle(
struct cam_icp_hw_ctx_data *ctx_data)
{
@@ -2021,7 +2014,10 @@
msecs_to_jiffies((timeout)));
if (!rem_jiffies) {
rc = -ETIMEDOUT;
- CAM_ERR(CAM_ICP, "FW response timeout: %d", rc);
+ CAM_ERR(CAM_ICP, "FW response timeout: %d for %u",
+ rc, ctx_data->ctx_id);
+ if (icp_hw_mgr.a5_debug_q)
+ cam_icp_mgr_process_dbg_buf();
}
kfree(destroy_cmd);
@@ -2050,6 +2046,7 @@
cam_icp_mgr_ipe_bps_power_collapse(hw_mgr,
&hw_mgr->ctx_data[ctx_id], 0);
hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE;
+ CAM_DBG(CAM_ICP, "E: ctx_id = %d", ctx_id);
cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]);
cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]);
@@ -2068,6 +2065,7 @@
hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_FREE;
mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+ CAM_DBG(CAM_ICP, "X: ctx_id = %d", ctx_id);
return 0;
}
@@ -2145,6 +2143,7 @@
hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ CAM_DBG(CAM_ICP, "Exit");
return rc;
}
@@ -2321,11 +2320,50 @@
return rc;
}
+static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr)
+{
+ int rc = 0;
+ struct cam_hw_intf *a5_dev_intf = NULL;
+ bool downloadFromResume = true;
+
+ CAM_DBG(CAM_ICP, "Enter");
+ a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5 dev intf is wrong");
+ return -EINVAL;
+ }
+
+ if (hw_mgr->fw_download == false) {
+ CAM_DBG(CAM_ICP, "Downloading FW");
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ cam_icp_mgr_hw_open(hw_mgr, &downloadFromResume);
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
+ CAM_DBG(CAM_ICP, "FW Download Done Exit");
+ return 0;
+ }
+
+ rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
+ if (rc)
+ return -EINVAL;
+
+ rc = cam_icp_mgr_hfi_resume(hw_mgr);
+ if (rc)
+ goto hfi_resume_failed;
+
+ CAM_DBG(CAM_ICP, "Exit");
+ return rc;
+hfi_resume_failed:
+ cam_icp_mgr_icp_power_collapse(hw_mgr);
+ return rc;
+}
+
static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args)
{
struct cam_hw_intf *a5_dev_intf = NULL;
struct cam_hw_info *a5_dev = NULL;
struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+ bool icp_pc = false;
int rc = 0;
if (!hw_mgr) {
@@ -2378,17 +2416,23 @@
}
hw_mgr->ctxt_cnt = 0;
+ hw_mgr->fw_download = true;
if (icp_hw_mgr.a5_debug_q)
hfi_set_debug_level(icp_hw_mgr.a5_dbg_lvl);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ CAM_INFO(CAM_ICP, "FW download done successfully");
rc = cam_ipe_bps_deint(hw_mgr);
+ if (download_fw_args)
+ icp_pc = *((bool *)download_fw_args);
+
+ if (download_fw_args && icp_pc == true)
+ return rc;
+
rc = cam_icp_mgr_icp_power_collapse(hw_mgr);
- hw_mgr->fw_download = true;
- CAM_DBG(CAM_ICP, "FW download done successfully");
return rc;
fw_init_failed:
@@ -2489,6 +2533,8 @@
rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
if (rc)
goto config_err;
+ CAM_DBG(CAM_ICP, "req_id = %lld %u",
+ req_id, ctx_data->ctx_id);
mutex_unlock(&ctx_data->ctx_mutex);
return 0;
@@ -2539,14 +2585,17 @@
}
static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr,
- struct cam_packet *packet,
+ struct cam_packet *packet, struct cam_icp_hw_ctx_data *ctx_data,
uint32_t *fw_cmd_buf_iova_addr)
{
int rc = 0;
- int i;
+ int i, j, k;
uint64_t addr;
size_t len;
struct cam_cmd_buf_desc *cmd_desc = NULL;
+ uint64_t cpu_addr = 0;
+ struct ipe_frame_process_data *frame_process_data = NULL;
+ struct bps_frame_process_data *bps_frame_process_data = NULL;
cmd_desc = (struct cam_cmd_buf_desc *)
((uint32_t *) &packet->payload + packet->cmd_buf_offset/4);
@@ -2564,6 +2613,67 @@
*fw_cmd_buf_iova_addr = addr;
*fw_cmd_buf_iova_addr =
(*fw_cmd_buf_iova_addr + cmd_desc[i].offset);
+ rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
+ &cpu_addr, &len);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "get cmd buf failed %x",
+ hw_mgr->iommu_hdl);
+ *fw_cmd_buf_iova_addr = 0;
+ return rc;
+ }
+ cpu_addr = cpu_addr + cmd_desc[i].offset;
+ }
+ }
+
+ if (!cpu_addr) {
+ CAM_ERR(CAM_ICP, "Invalid cpu addr");
+ return -EINVAL;
+ }
+
+ if (ctx_data->icp_dev_acquire_info->dev_type !=
+ CAM_ICP_RES_TYPE_BPS) {
+ CAM_DBG(CAM_ICP, "cpu addr = %llx", cpu_addr);
+ frame_process_data = (struct ipe_frame_process_data *)cpu_addr;
+ CAM_DBG(CAM_ICP, "%u %u %u", frame_process_data->max_num_cores,
+ frame_process_data->target_time,
+ frame_process_data->frames_in_batch);
+ frame_process_data->strip_lib_out_addr = 0;
+ frame_process_data->iq_settings_addr = 0;
+ frame_process_data->scratch_buffer_addr = 0;
+ frame_process_data->ubwc_stats_buffer_addr = 0;
+ frame_process_data->cdm_buffer_addr = 0;
+ frame_process_data->cdm_prog_base = 0;
+ for (i = 0; i < frame_process_data->frames_in_batch; i++) {
+ for (j = 0; j < IPE_IO_IMAGES_MAX; j++) {
+ for (k = 0; k < MAX_NUM_OF_IMAGE_PLANES; k++) {
+ frame_process_data->
+ framesets[i].buffers[j].
+ buffer_ptr[k] = 0;
+ frame_process_data->
+ framesets[i].buffers[j].
+ meta_buffer_ptr[k] = 0;
+ }
+ }
+ }
+ } else {
+ CAM_DBG(CAM_ICP, "cpu addr = %llx", cpu_addr);
+ bps_frame_process_data =
+ (struct bps_frame_process_data *)cpu_addr;
+ CAM_DBG(CAM_ICP, "%u %u",
+ bps_frame_process_data->max_num_cores,
+ bps_frame_process_data->target_time);
+ bps_frame_process_data->ubwc_stats_buffer_addr = 0;
+ bps_frame_process_data->cdm_buffer_addr = 0;
+ bps_frame_process_data->iq_settings_addr = 0;
+ bps_frame_process_data->strip_lib_out_addr = 0;
+ bps_frame_process_data->cdm_prog_addr = 0;
+ for (i = 0; i < BPS_IO_IMAGES_MAX; i++) {
+ for (j = 0; j < MAX_NUM_OF_IMAGE_PLANES; j++) {
+ bps_frame_process_data->
+ buffers[i].buffer_ptr[j] = 0;
+ bps_frame_process_data->
+ buffers[i].meta_buffer_ptr[j] = 0;
+ }
}
}
@@ -2766,12 +2876,13 @@
}
rc = cam_icp_mgr_process_cmd_desc(hw_mgr, packet,
- &fw_cmd_buf_iova_addr);
+ ctx_data, &fw_cmd_buf_iova_addr);
if (rc) {
mutex_unlock(&ctx_data->ctx_mutex);
return rc;
}
+ CAM_DBG(CAM_ICP, "E: req id = %lld", packet->header.request_id);
/* Update Buffer Address from handles and patch information */
rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl,
hw_mgr->iommu_sec_hdl);
@@ -2809,6 +2920,8 @@
prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
+ CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u",
+ packet->header.request_id, ctx_data->ctx_id);
mutex_unlock(&ctx_data->ctx_mutex);
return rc;
}
@@ -3025,6 +3138,7 @@
return -EINVAL;
}
+ CAM_DBG(CAM_ICP, "Enter");
ctx_data = release_hw->ctxt_to_hw_map;
if (!ctx_data) {
CAM_ERR(CAM_ICP, "NULL ctx data");
@@ -3054,7 +3168,9 @@
rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
if (!hw_mgr->ctxt_cnt) {
CAM_DBG(CAM_ICP, "Last Release");
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
cam_icp_mgr_icp_power_collapse(hw_mgr);
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
cam_icp_hw_mgr_reset_clk_info(hw_mgr);
hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
}
@@ -3063,6 +3179,7 @@
if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)
cam_icp_timer_stop(hw_mgr);
+ CAM_DBG(CAM_ICP, "Exit");
return rc;
}
@@ -3302,6 +3419,7 @@
return -EINVAL;
}
+ CAM_DBG(CAM_ICP, "ENTER");
mutex_lock(&hw_mgr->hw_mgr_mutex);
ctx_id = cam_icp_mgr_get_free_ctx(hw_mgr);
if (ctx_id >= CAM_ICP_CTX_MAX) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 43d7a4a..85f5b550 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -258,6 +258,8 @@
* @dentry: Debugfs entry
* @a5_debug: A5 debug flag
* @icp_pc_flag: Flag to enable/disable power collapse
+ * @ipe_bps_pc_flag: Flag to enable/disable
+ * power collapse for ipe & bps
* @icp_debug_clk: Set clock based on debug value
* @icp_default_clk: Set this clok if user doesn't supply
* @clk_info: Clock info of hardware
@@ -295,6 +297,7 @@
struct dentry *dentry;
bool a5_debug;
bool icp_pc_flag;
+ bool ipe_bps_pc_flag;
uint64_t icp_debug_clk;
uint64_t icp_default_clk;
struct cam_icp_clk_info clk_info[ICP_CLK_HW_MAX];
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
index 6915ad5..9e05f2b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
@@ -22,4 +22,15 @@
CAM_ICP_DEV_BPS,
CAM_ICP_DEV_MAX,
};
+
+/**
+ * struct cam_a5_clk_update_cmd - Payload for hw manager command
+ *
+ * @curr_clk_rate: clk rate to HW
+ * @ipe_bps_pc_enable power collpase enable flag
+ */
+struct cam_a5_clk_update_cmd {
+ uint32_t curr_clk_rate;
+ bool ipe_bps_pc_enable;
+};
#endif
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
index 5b4156a..87478af 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
@@ -267,22 +267,28 @@
rc = cam_ipe_handle_resume(ipe_dev);
break;
case CAM_ICP_IPE_CMD_UPDATE_CLK: {
- uint32_t clk_rate = *(uint32_t *)cmd_args;
+ struct cam_a5_clk_update_cmd *clk_upd_cmd =
+ (struct cam_a5_clk_update_cmd *)cmd_args;
+ uint32_t clk_rate = clk_upd_cmd->curr_clk_rate;
CAM_DBG(CAM_ICP, "ipe_src_clk rate = %d", (int)clk_rate);
if (!core_info->clk_enable) {
- cam_ipe_handle_pc(ipe_dev);
- cam_cpas_reg_write(core_info->cpas_handle,
- CAM_CPAS_REG_CPASTOP,
- hw_info->pwr_ctrl, true, 0x0);
+ if (clk_upd_cmd->ipe_bps_pc_enable) {
+ cam_ipe_handle_pc(ipe_dev);
+ cam_cpas_reg_write(core_info->cpas_handle,
+ CAM_CPAS_REG_CPASTOP,
+ hw_info->pwr_ctrl, true, 0x0);
+ }
rc = cam_ipe_toggle_clk(soc_info, true);
if (rc)
CAM_ERR(CAM_ICP, "Enable failed");
else
core_info->clk_enable = true;
- rc = cam_ipe_handle_resume(ipe_dev);
- if (rc)
- CAM_ERR(CAM_ICP, "handle resume failed");
+ if (clk_upd_cmd->ipe_bps_pc_enable) {
+ rc = cam_ipe_handle_resume(ipe_dev);
+ if (rc)
+ CAM_ERR(CAM_ICP, "bps resume failed");
+ }
}
CAM_DBG(CAM_ICP, "clock rate %d", clk_rate);
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 01c0a02..d1153ba 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -456,6 +456,9 @@
}
}
+ if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_BUBBLE)
+ request_id = 0;
+
__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
CAM_REQ_MGR_SOF_EVENT_SUCCESS);
} else {
@@ -612,7 +615,10 @@
req_isp->bubble_report = 0;
}
- request_id = req->request_id;
+ if (req->request_id > ctx_isp->reported_req_id) {
+ request_id = req->request_id;
+ ctx_isp->reported_req_id = request_id;
+ }
__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
CAM_REQ_MGR_SOF_EVENT_ERROR);
@@ -738,9 +744,18 @@
req_isp->bubble_report = 0;
}
- request_id = req->request_id;
- __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
- CAM_REQ_MGR_SOF_EVENT_ERROR);
+ if (!req_isp->bubble_report) {
+ if (req->request_id > ctx_isp->reported_req_id) {
+ request_id = req->request_id;
+ ctx_isp->reported_req_id = request_id;
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_ERROR);
+ } else
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+ } else
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
@@ -1310,6 +1325,17 @@
struct cam_isp_hw_sof_event_data *sof_event_data = evt_data;
uint64_t request_id = 0;
+ /*
+ * Sof in bubble applied state means, reg update not received.
+ * before increment frame id and override time stamp value, send
+ * the previous sof time stamp that got captured in the
+ * sof in applied state.
+ */
+ CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
+ ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+
ctx_isp->frame_id++;
ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
@@ -1359,9 +1385,18 @@
req_isp->bubble_report = 0;
}
- request_id = req->request_id;
- __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
- CAM_REQ_MGR_SOF_EVENT_ERROR);
+ if (!req_isp->bubble_report) {
+ if (req->request_id > ctx_isp->reported_req_id) {
+ request_id = req->request_id;
+ ctx_isp->reported_req_id = request_id;
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_ERROR);
+ } else
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+ } else
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
/* change the state to bubble, as reg update has not come */
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index ccab3a0..8d41ae7 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -3733,10 +3733,13 @@
struct cam_vfe_top_irq_evt_payload *evt_payload;
int rc = -EINVAL;
- if (!handler_priv)
+ if (!evt_payload_priv)
return rc;
evt_payload = evt_payload_priv;
+ if (!handler_priv)
+ goto put_payload;
+
ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)handler_priv;
CAM_DBG(CAM_ISP, "addr of evt_payload = %pK core_index:%d",
@@ -3764,7 +3767,7 @@
if (rc) {
CAM_ERR(CAM_ISP, "Encountered Error (%d), ignoring other irqs",
rc);
- return IRQ_HANDLED;
+ goto put_payload;
}
CAM_DBG(CAM_ISP, "Calling EOF");
@@ -3786,6 +3789,8 @@
cam_ife_hw_mgr_handle_epoch_for_camif_hw_res(ife_hwr_mgr_ctx,
evt_payload_priv);
+put_payload:
+ cam_vfe_put_evt_payload(evt_payload->core_info, &evt_payload);
return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
index 031b7b2..b632e77 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -607,6 +607,33 @@
CAM_DBG(CAM_ISP, "Exit");
}
+irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv)
+{
+ struct cam_irq_controller *controller = priv;
+ uint32_t i = 0;
+
+ if (!controller)
+ return IRQ_NONE;
+
+ for (i = 0; i < controller->num_registers; i++) {
+
+ cam_io_w_mb(0x0, controller->mem_base +
+ controller->irq_register_arr[i].clear_reg_offset);
+ }
+
+ if (controller->global_clear_offset)
+ cam_io_w_mb(controller->global_clear_bitmask,
+ controller->mem_base +
+ controller->global_clear_offset);
+
+ for (i = 0; i < controller->num_registers; i++) {
+ cam_io_w_mb(0x0, controller->mem_base +
+ controller->irq_register_arr[i].mask_reg_offset);
+ }
+
+ return IRQ_HANDLED;
+}
+
irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv)
{
struct cam_irq_controller *controller = priv;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
index 7e307b5..e3071ac 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
@@ -250,4 +250,18 @@
*/
int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle);
+/*
+ * cam_irq_controller_clear_and_mask()
+ *
+ * @brief: This function clears and masks all the irq bits
+ *
+ * @irq_num: Number of IRQ line that was set that lead to this
+ * function being called
+ * @priv: Private data registered with request_irq is passed back
+ * here. This private data should be the irq_controller
+ * structure.
+ *
+ * @return: IRQ_HANDLED/IRQ_NONE
+ */
+irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv);
#endif /* _CAM_IRQ_CONTROLLER_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 70c9c3b..bce0374 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 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
@@ -1884,21 +1884,23 @@
if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX ||
!csid_reg->rdi_reg[res->res_id]) {
- CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d",
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d",
csid_hw->hw_intf->hw_idx, res->res_id);
return -EINVAL;
}
if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
- CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d",
- csid_hw->hw_intf->hw_idx,
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d Res:%d already in stopped state:%d",
+ csid_hw->hw_intf->hw_idx,
res->res_id, res->res_state);
return rc;
}
if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
- CAM_DBG(CAM_ISP, "CSID:%d Res:%d Invalid res_state%d",
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d Res:%d Invalid res_state%d",
csid_hw->hw_intf->hw_idx, res->res_id,
res->res_state);
return -EINVAL;
@@ -2006,21 +2008,23 @@
soc_info = &csid_hw->hw_info->soc_info;
if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) {
- CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d",
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d",
csid_hw->hw_intf->hw_idx, res->res_id);
return -EINVAL;
}
if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
- CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d",
- csid_hw->hw_intf->hw_idx,
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d Res:%d already in stopped state:%d",
+ csid_hw->hw_intf->hw_idx,
res->res_id, res->res_state);
return rc;
}
if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
- CAM_DBG(CAM_ISP, "CSID:%d Res:%d Invalid state%d",
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d Res:%d Invalid state%d",
csid_hw->hw_intf->hw_idx, res->res_id,
res->res_state);
return -EINVAL;
@@ -2258,6 +2262,33 @@
return rc;
}
+static int cam_ife_csid_reset_retain_sw_reg(
+ struct cam_ife_csid_hw *csid_hw)
+{
+ int rc = 0;
+ struct cam_ife_csid_reg_offset *csid_reg =
+ csid_hw->csid_info->csid_reg;
+
+ cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb,
+ csid_hw->hw_info->soc_info.reg_map[0].mem_base +
+ csid_reg->cmn_reg->csid_rst_strobes_addr);
+
+ CAM_DBG(CAM_ISP, " Waiting for SW reset complete from irq handler");
+ rc = wait_for_completion_timeout(&csid_hw->csid_top_complete,
+ msecs_to_jiffies(IFE_CSID_TIMEOUT));
+ if (rc <= 0) {
+ CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d",
+ csid_hw->hw_intf->hw_idx, rc);
+ if (rc == 0)
+ rc = -ETIMEDOUT;
+ } else {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+
static int cam_ife_csid_init_hw(void *hw_priv,
void *init_args, uint32_t arg_size)
{
@@ -2290,7 +2321,6 @@
goto end;
}
-
if ((res->res_type == CAM_ISP_RESOURCE_PIX_PATH) &&
(res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED)) {
CAM_ERR(CAM_ISP,
@@ -2304,7 +2334,6 @@
CAM_DBG(CAM_ISP, "CSID:%d res type :%d res_id:%d",
csid_hw->hw_intf->hw_idx, res->res_type, res->res_id);
-
/* Initialize the csid hardware */
rc = cam_ife_csid_enable_hw(csid_hw);
if (rc)
@@ -2328,6 +2357,12 @@
break;
}
+ rc = cam_ife_csid_reset_retain_sw_reg(csid_hw);
+ if (rc < 0) {
+ CAM_ERR(CAM_ISP, "CSID: Failed in SW reset");
+ return rc;
+ }
+
if (rc)
cam_ife_csid_disable_hw(csid_hw);
end:
@@ -2489,8 +2524,7 @@
/*wait for the path to halt */
for (i = 0; i < csid_stop->num_res; i++) {
res = csid_stop->node_res[i];
- if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH &&
- csid_stop->stop_cmd == CAM_CSID_HALT_AT_FRAME_BOUNDARY)
+ if (csid_stop->stop_cmd == CAM_CSID_HALT_AT_FRAME_BOUNDARY)
rc = cam_ife_csid_res_wait_for_halt(csid_hw, res);
else
res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
@@ -2548,8 +2582,35 @@
}
+static int cam_ife_csid_halt_device(
+ struct cam_ife_csid_hw *csid_hw)
+{
+ uint32_t i;
+ int rc = 0;
+ struct cam_isp_resource_node *res_node;
+
+ res_node = &csid_hw->ipp_res;
+ if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
+ rc = cam_ife_csid_disable_ipp_path(csid_hw,
+ res_node, CAM_CSID_HALT_IMMEDIATELY);
+ res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
+ }
+
+ for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) {
+ res_node = &csid_hw->rdi_res[i];
+ if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
+ rc = cam_ife_csid_disable_rdi_path(csid_hw,
+ res_node, CAM_CSID_HALT_IMMEDIATELY);
+ res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
+ }
+ }
+ return rc;
+}
+
+
irqreturn_t cam_ife_csid_irq(int irq_num, void *data)
{
+ int rc = 0;
struct cam_ife_csid_hw *csid_hw;
struct cam_hw_soc_info *soc_info;
struct cam_ife_csid_reg_offset *csid_reg;
@@ -2623,22 +2684,52 @@
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow",
csid_hw->hw_intf->hw_idx);
+ rc = cam_ife_csid_halt_device(csid_hw);
+ if (rc) {
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d csid halt device fail rc = %d",
+ csid_hw->hw_intf->hw_idx, rc);
+ }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow",
csid_hw->hw_intf->hw_idx);
+ rc = cam_ife_csid_halt_device(csid_hw);
+ if (rc) {
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d csid halt device fail rc = %d",
+ csid_hw->hw_intf->hw_idx, rc);
+ }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow",
csid_hw->hw_intf->hw_idx);
+ rc = cam_ife_csid_halt_device(csid_hw);
+ if (rc) {
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d csid halt device fail rc = %d",
+ csid_hw->hw_intf->hw_idx, rc);
+ }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow",
csid_hw->hw_intf->hw_idx);
+ rc = cam_ife_csid_halt_device(csid_hw);
+ if (rc) {
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d csid halt device fail rc = %d",
+ csid_hw->hw_intf->hw_idx, rc);
+ }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW",
csid_hw->hw_intf->hw_idx);
+ rc = cam_ife_csid_halt_device(csid_hw);
+ if (rc) {
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "CSID:%d csid halt device fail rc = %d",
+ csid_hw->hw_intf->hw_idx, rc);
+ }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION",
@@ -2664,7 +2755,7 @@
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT",
csid_hw->hw_intf->hw_idx);
}
- if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) {
+ if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_STREAM_UNDERFLOW",
csid_hw->hw_intf->hw_idx);
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index 4a7a4f2..02fec28 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -172,6 +172,8 @@
th_payload->evt_status_arr[1]);
cam_irq_controller_disable_irq(core_info->vfe_irq_controller,
core_info->irq_err_handle);
+ cam_irq_controller_clear_and_mask(evt_id,
+ core_info->vfe_irq_controller);
}
rc = cam_vfe_get_evt_payload(handler_priv->core_info, &evt_payload);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index c166113..36ce652 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 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
@@ -60,7 +60,7 @@
static uint32_t bus_error_irq_mask[3] = {
0x7800,
0x0000,
- 0x00C0,
+ 0x0040,
};
enum cam_vfe_bus_packer_format {
@@ -106,6 +106,7 @@
struct cam_vfe_bus_irq_evt_payload evt_payload[
CAM_VFE_BUS_VER2_PAYLOAD_MAX];
struct list_head free_payload_list;
+ spinlock_t spin_lock;
struct mutex bus_mutex;
uint32_t secure_mode;
uint32_t num_sec_out;
@@ -214,16 +215,23 @@
struct cam_vfe_bus_ver2_common_data *common_data,
struct cam_vfe_bus_irq_evt_payload **evt_payload)
{
+ int rc;
+
+ spin_lock(&common_data->spin_lock);
if (list_empty(&common_data->free_payload_list)) {
*evt_payload = NULL;
CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload");
- return -ENODEV;
+ rc = -ENODEV;
+ goto done;
}
*evt_payload = list_first_entry(&common_data->free_payload_list,
struct cam_vfe_bus_irq_evt_payload, list);
list_del_init(&(*evt_payload)->list);
- return 0;
+ rc = 0;
+done:
+ spin_unlock(&common_data->spin_lock);
+ return rc;
}
static enum cam_vfe_bus_comp_grp_id
@@ -254,6 +262,7 @@
struct cam_vfe_bus_ver2_common_data *common_data = NULL;
uint32_t *ife_irq_regs = NULL;
uint32_t status_reg0, status_reg1, status_reg2;
+ unsigned long flags;
if (!core_info) {
CAM_ERR(CAM_ISP, "Invalid param core_info NULL");
@@ -276,8 +285,12 @@
}
common_data = core_info;
+
+ spin_lock_irqsave(&common_data->spin_lock, flags);
list_add_tail(&(*evt_payload)->list,
&common_data->free_payload_list);
+ spin_unlock_irqrestore(&common_data->spin_lock, flags);
+
*evt_payload = NULL;
return 0;
@@ -2556,8 +2569,21 @@
CAM_DBG(CAM_ISP, "WM %d image address 0x%x",
wm_data->index, reg_val_pair[j-1]);
- frame_inc = io_cfg->planes[i].plane_stride *
- io_cfg->planes[i].slice_height;
+ if (wm_data->en_ubwc) {
+ frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride *
+ io_cfg->planes[i].slice_height, 4096);
+ frame_inc += io_cfg->planes[i].meta_size;
+ CAM_DBG(CAM_ISP,
+ "WM %d frm %d: ht: %d stride %d meta: %d",
+ wm_data->index, frame_inc,
+ io_cfg->planes[i].slice_height,
+ io_cfg->planes[i].plane_stride,
+ io_cfg->planes[i].meta_size);
+ } else {
+ frame_inc = io_cfg->planes[i].plane_stride *
+ io_cfg->planes[i].slice_height;
+ }
+
CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j,
wm_data->hw_regs->frame_inc, frame_inc);
CAM_DBG(CAM_ISP, "WM %d frame_inc %d",
@@ -2975,6 +3001,7 @@
}
}
+ spin_lock_init(&bus_priv->common_data.spin_lock);
INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) {
INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index 9848454..f427ab9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -355,7 +355,6 @@
CAM_DBG(CAM_ISP, "Received EPOCH");
ret = CAM_VFE_IRQ_STATUS_SUCCESS;
}
- cam_vfe_put_evt_payload(payload->core_info, &payload);
break;
case CAM_ISP_HW_EVENT_REG_UPDATE:
if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) {
@@ -373,7 +372,6 @@
if (irq_status1 & camif_priv->reg_data->error_irq_mask1) {
CAM_DBG(CAM_ISP, "Received ERROR\n");
ret = CAM_ISP_HW_ERROR_OVERFLOW;
- cam_vfe_put_evt_payload(payload->core_info, &payload);
} else {
ret = CAM_ISP_HW_ERROR_NONE;
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
index 28e99f2..50dca827 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
@@ -209,7 +209,6 @@
CAM_DBG(CAM_ISP, "Received REG UPDATE");
ret = CAM_VFE_IRQ_STATUS_SUCCESS;
}
- cam_vfe_put_evt_payload(payload->core_info, &payload);
break;
default:
break;
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 65922dd..6e2e7e9 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -742,7 +742,7 @@
struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv;
uint32_t dev_type;
struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL;
- struct cam_jpeg_hw_cfg_req *cfg_req, *req_temp;
+ struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL;
if (!hw_mgr || !ctx_data) {
CAM_ERR(CAM_JPEG, "Invalid args");
@@ -776,8 +776,8 @@
list_for_each_entry_safe(cfg_req, req_temp,
&hw_mgr->hw_config_req_list, list) {
- if ((struct cam_jpeg_hw_ctx_data *)cfg_req->
- hw_cfg_args.ctxt_to_hw_map != ctx_data)
+ if ((cfg_req) && ((struct cam_jpeg_hw_ctx_data *)cfg_req->
+ hw_cfg_args.ctxt_to_hw_map != ctx_data))
continue;
list_del_init(&cfg_req->list);
@@ -800,11 +800,14 @@
return -EINVAL;
}
- request_id = *(int64_t *)flush_args->flush_req_pending[0];
+ if (flush_args->num_req_pending)
+ return 0;
+
+ request_id = *(int64_t *)flush_args->flush_req_active[0];
list_for_each_entry_safe(cfg_req, req_temp,
&hw_mgr->hw_config_req_list, list) {
- if (cfg_req->hw_cfg_args.ctxt_to_hw_map
- != ctx_data)
+ if ((cfg_req) && (cfg_req->hw_cfg_args.ctxt_to_hw_map
+ != ctx_data))
continue;
if (cfg_req->req_id != request_id)
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
index 3fc9032..bb952e6 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -60,8 +60,17 @@
hw_info->bus_rd_reg.bus_client_reg[index].core_cfg, 0x1);
/* 5. unpack_cfg */
- cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
- hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, 0x0);
+ if (io_buf->io_cfg->format == CAM_FORMAT_PD10)
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
+ 0x0);
+ else if (io_buf->io_cfg->format == CAM_FORMAT_Y_ONLY)
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
+ 0x1);
+ else
+ CAM_ERR(CAM_LRME, "Unsupported format %d",
+ io_buf->io_cfg->format);
}
static void cam_lrme_hw_util_fill_we_reg(struct cam_lrme_hw_io_buffer *io_buf,
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 784e90b..d7662f1 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -1138,9 +1138,8 @@
* @brief : Cleans up the mem allocated while linking
* @link : pointer to link, mem associated with this link is freed
*
- * @return : returns if unlink for any device was success or failure
*/
-static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
+static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
{
int32_t i = 0;
struct cam_req_mgr_connected_device *dev;
@@ -1157,12 +1156,13 @@
dev = &link->l_dev[i];
if (dev != NULL) {
link_data.dev_hdl = dev->dev_hdl;
- if (dev->ops && dev->ops->link_setup)
+ if (dev->ops && dev->ops->link_setup) {
rc = dev->ops->link_setup(&link_data);
if (rc)
CAM_ERR(CAM_CRM,
- "Unlink failed dev_hdl %d",
- dev->dev_hdl);
+ "Unlink failed dev_hdl 0x%x rc=%d",
+ dev->dev_hdl, rc);
+ }
dev->dev_hdl = 0;
dev->parent = NULL;
dev->ops = NULL;
@@ -1176,8 +1176,6 @@
link->pd_mask = 0;
link->num_devs = 0;
link->max_delay = 0;
-
- return rc;
}
/**
@@ -1263,45 +1261,71 @@
return NULL;
}
+/*
+ * __cam_req_mgr_free_link()
+ *
+ * @brief: Frees the link and its request queue
+ *
+ * @link: link identifier
+ *
+ */
+static void __cam_req_mgr_free_link(struct cam_req_mgr_core_link *link)
+{
+ kfree(link->req.in_q);
+ link->req.in_q = NULL;
+ kfree(link);
+}
+
/**
* __cam_req_mgr_unreserve_link()
*
- * @brief : Reserves one link data struct within session
+ * @brief : Removes the link data struct from the session and frees it
* @session: session identifier
* @link : link identifier
*
*/
static void __cam_req_mgr_unreserve_link(
struct cam_req_mgr_core_session *session,
- struct cam_req_mgr_core_link **link)
+ struct cam_req_mgr_core_link *link)
{
- int32_t i = 0;
+ int i;
- if (!session || !*link) {
+ if (!session || !link) {
CAM_ERR(CAM_CRM, "NULL session/link ptr %pK %pK",
- session, *link);
+ session, link);
return;
}
mutex_lock(&session->lock);
- if (!session->num_links)
- CAM_WARN(CAM_CRM, "No active link or invalid state %d",
- session->num_links);
- else {
- for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
- if (session->links[i] == *link)
- session->links[i] = NULL;
- }
- session->num_links--;
- CAM_DBG(CAM_CRM, "Active session links (%d)",
- session->num_links);
+ if (!session->num_links) {
+ CAM_WARN(CAM_CRM, "No active link or invalid state: hdl %x",
+ link->link_hdl);
+ mutex_unlock(&session->lock);
+ return;
}
- kfree((*link)->req.in_q);
- (*link)->req.in_q = NULL;
- kfree(*link);
- *link = NULL;
- mutex_unlock(&session->lock);
+ for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+ if (session->links[i] == link)
+ session->links[i] = NULL;
+ }
+
+ if ((session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) &&
+ (link->sync_link)) {
+ /*
+ * make sure to unlink sync setup under the assumption
+ * of only having 2 links in a given session
+ */
+ session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC;
+ for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+ if (session->links[i])
+ session->links[i]->sync_link = NULL;
+ }
+ }
+
+ session->num_links--;
+ CAM_DBG(CAM_CRM, "Active session links (%d)", session->num_links);
+ mutex_unlock(&session->lock);
+ __cam_req_mgr_free_link(link);
}
/* Workqueue context processing section */
@@ -2145,11 +2169,58 @@
return rc;
}
+/**
+ * __cam_req_mgr_unlink()
+ *
+ * @brief : Unlink devices on a link structure from the session
+ * @link : Pointer to the link structure
+ *
+ * @return: 0 for success, negative for failure
+ *
+ */
+static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link)
+{
+ int rc;
+
+ mutex_lock(&link->lock);
+ spin_lock_bh(&link->link_state_spin_lock);
+ link->state = CAM_CRM_LINK_STATE_IDLE;
+ spin_unlock_bh(&link->link_state_spin_lock);
+ __cam_req_mgr_print_req_tbl(&link->req);
+
+ /* Destroy workq payload data */
+ kfree(link->workq->task.pool[0].payload);
+ link->workq->task.pool[0].payload = NULL;
+
+ /* Destroy workq and timer of link */
+ crm_timer_exit(&link->watchdog);
+
+ cam_req_mgr_workq_destroy(&link->workq);
+
+ /* Cleanup request tables and unlink devices */
+ __cam_req_mgr_destroy_link_info(link);
+
+ /* Free memory holding data of linked devs */
+ __cam_req_mgr_destroy_subdev(link->l_dev);
+
+ /* Destroy the link handle */
+ rc = cam_destroy_device_hdl(link->link_hdl);
+ if (rc < 0) {
+ CAM_ERR(CAM_CRM, "error while destroying dev handle %d %x",
+ rc, link->link_hdl);
+ }
+
+ mutex_unlock(&link->lock);
+ return rc;
+}
+
int cam_req_mgr_destroy_session(
struct cam_req_mgr_session_info *ses_info)
{
int rc;
+ int i;
struct cam_req_mgr_core_session *cam_session = NULL;
+ struct cam_req_mgr_core_link *link;
if (!ses_info) {
CAM_DBG(CAM_CRM, "NULL session info pointer");
@@ -2167,10 +2238,20 @@
}
mutex_lock(&cam_session->lock);
if (cam_session->num_links) {
- CAM_ERR(CAM_CRM, "destroy session %x num_active_links %d",
+ CAM_DBG(CAM_CRM, "destroy session %x num_active_links %d",
ses_info->session_hdl,
cam_session->num_links);
- /* @TODO : Go through active links and destroy ? */
+
+ for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+ link = cam_session->links[i];
+
+ if (!link)
+ continue;
+
+ /* Ignore return value since session is going away */
+ __cam_req_mgr_unlink(link);
+ __cam_req_mgr_free_link(link);
+ }
}
list_del(&cam_session->entry);
mutex_unlock(&cam_session->lock);
@@ -2286,7 +2367,7 @@
link_info->link_hdl = 0;
link_hdl_fail:
mutex_unlock(&link->lock);
- __cam_req_mgr_unreserve_link(cam_session, &link);
+ __cam_req_mgr_unreserve_link(cam_session, link);
mutex_unlock(&g_crm_core_dev->crm_lock);
return rc;
}
@@ -2296,7 +2377,6 @@
int rc = 0;
struct cam_req_mgr_core_session *cam_session;
struct cam_req_mgr_core_link *link;
- int i;
if (!unlink_info) {
CAM_ERR(CAM_CRM, "NULL pointer");
@@ -2319,60 +2399,18 @@
link = cam_get_device_priv(unlink_info->link_hdl);
if (!link) {
CAM_ERR(CAM_CRM, "NULL pointer");
- mutex_unlock(&g_crm_core_dev->crm_lock);
- return -EINVAL;
+ rc = -EINVAL;
+ goto done;
}
- mutex_lock(&link->lock);
- spin_lock_bh(&link->link_state_spin_lock);
- link->state = CAM_CRM_LINK_STATE_IDLE;
- spin_unlock_bh(&link->link_state_spin_lock);
- __cam_req_mgr_print_req_tbl(&link->req);
-
- if ((cam_session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) &&
- (link->sync_link)) {
- /*
- * make sure to unlink sync setup under the assumption
- * of only having 2 links in a given session
- */
- cam_session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC;
- for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
- if (cam_session->links[i])
- cam_session->links[i]->sync_link = NULL;
- }
- }
-
- /* Destroy workq payload data */
- kfree(link->workq->task.pool[0].payload);
- link->workq->task.pool[0].payload = NULL;
-
- /* Destroy workq and timer of link */
- crm_timer_exit(&link->watchdog);
-
- cam_req_mgr_workq_destroy(&link->workq);
-
- /* Cleanup request tables and unlink devices */
- rc = __cam_req_mgr_destroy_link_info(link);
- if (rc) {
- CAM_ERR(CAM_CORE, "Unlink failed. Cannot proceed");
- return rc;
- }
-
- /* Free memory holding data of linked devs */
- __cam_req_mgr_destroy_subdev(link->l_dev);
-
- /* Destroy the link handle */
- rc = cam_destroy_device_hdl(unlink_info->link_hdl);
- if (rc < 0) {
- CAM_ERR(CAM_CRM, "error while destroying dev handle %d %x",
- rc, link->link_hdl);
- }
+ rc = __cam_req_mgr_unlink(link);
/* Free curent link and put back into session's free pool of links */
- mutex_unlock(&link->lock);
- __cam_req_mgr_unreserve_link(cam_session, &link);
- mutex_unlock(&g_crm_core_dev->crm_lock);
+ if (!rc)
+ __cam_req_mgr_unreserve_link(cam_session, link);
+done:
+ mutex_unlock(&g_crm_core_dev->crm_lock);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index e0d4502..23d25a4 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -612,37 +612,36 @@
case CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE: {
CAM_DBG(CAM_FLASH,
"CAMERA_FLASH_CMD_TYPE_OPS case called");
- if ((fctrl->flash_state == CAM_FLASH_STATE_START) ||
+ if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
(fctrl->flash_state ==
- CAM_FLASH_STATE_CONFIG)) {
- flash_operation_info =
- (struct cam_flash_set_on_off *) cmd_buf;
- if (!flash_operation_info) {
- CAM_ERR(CAM_FLASH,
- "flash_operation_info Null");
- return -EINVAL;
- }
-
- fctrl->per_frame[frame_offset].opcode =
- flash_operation_info->opcode;
- fctrl->per_frame[frame_offset].cmn_attr.count =
- flash_operation_info->count;
- for (i = 0;
- i < flash_operation_info->count; i++)
- fctrl->per_frame[frame_offset].
- led_current_ma[i]
- = flash_operation_info->
- led_current_ma[i];
-
- } else {
- CAM_ERR(CAM_FLASH,
- "Rxed Update packets without linking");
+ CAM_FLASH_STATE_ACQUIRE)) {
+ CAM_WARN(CAM_FLASH,
+ "Rxed Flash fire ops without linking");
fctrl->per_frame[frame_offset].
cmn_attr.is_settings_valid = false;
+ return 0;
+ }
+
+ flash_operation_info =
+ (struct cam_flash_set_on_off *) cmd_buf;
+ if (!flash_operation_info) {
+ CAM_ERR(CAM_FLASH,
+ "flash_operation_info Null");
return -EINVAL;
}
+
+ fctrl->per_frame[frame_offset].opcode =
+ flash_operation_info->opcode;
+ fctrl->per_frame[frame_offset].cmn_attr.count =
+ flash_operation_info->count;
+ for (i = 0;
+ i < flash_operation_info->count; i++)
+ fctrl->per_frame[frame_offset].
+ led_current_ma[i]
+ = flash_operation_info->
+ led_current_ma[i];
+ }
break;
- }
default:
CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d",
cmn_hdr->cmd_type);
@@ -741,18 +740,18 @@
break;
}
case CAM_PKT_NOP_OPCODE: {
- if ((fctrl->flash_state == CAM_FLASH_STATE_START) ||
- (fctrl->flash_state == CAM_FLASH_STATE_CONFIG)) {
- CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
- csl_packet->header.request_id);
- goto update_req_mgr;
- } else {
- CAM_ERR(CAM_FLASH,
- "Rxed Update packets without linking");
+ if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
+ (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) {
+ CAM_WARN(CAM_FLASH,
+ "Rxed NOP packets without linking");
fctrl->per_frame[frame_offset].
cmn_attr.is_settings_valid = false;
- return -EINVAL;
+ return 0;
}
+
+ CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
+ csl_packet->header.request_id);
+ goto update_req_mgr;
}
default:
CAM_ERR(CAM_FLASH, "Wrong Opcode : %d",
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
index eddbf97..085bcf6 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -82,7 +82,8 @@
}
case CAM_RELEASE_DEV: {
CAM_DBG(CAM_FLASH, "CAM_RELEASE_DEV");
- if (fctrl->flash_state != CAM_FLASH_STATE_ACQUIRE) {
+ if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
+ (fctrl->flash_state == CAM_FLASH_STATE_START)) {
CAM_WARN(CAM_FLASH,
"Cannot apply Release dev: Prev state:%d",
fctrl->flash_state);
@@ -131,7 +132,8 @@
}
case CAM_START_DEV: {
CAM_DBG(CAM_FLASH, "CAM_START_DEV");
- if (fctrl->flash_state != CAM_FLASH_STATE_CONFIG) {
+ if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
+ (fctrl->flash_state == CAM_FLASH_STATE_START)) {
CAM_WARN(CAM_FLASH,
"Cannot apply Start Dev: Prev state: %d",
fctrl->flash_state);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
index 76f5b46..db80584 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -469,7 +469,7 @@
CAM_ERR(CAM_OIS, "invalid cmd buf");
return -EINVAL;
}
- cmd_buf += cmd_desc->offset / sizeof(uint32_t);
+ cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
cmm_hdr = (struct common_header *)cmd_buf;
switch (cmm_hdr->cmd_type) {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 9ce7a21..9894ca3 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -38,6 +38,31 @@
add_req.req_id);
}
+static void cam_sensor_release_stream_rsc(
+ struct cam_sensor_ctrl_t *s_ctrl)
+{
+ struct i2c_settings_array *i2c_set = NULL;
+ int rc;
+
+ i2c_set = &(s_ctrl->i2c_data.streamoff_settings);
+ if (i2c_set->is_settings_valid == 1) {
+ i2c_set->is_settings_valid = -1;
+ rc = delete_request(i2c_set);
+ if (rc < 0)
+ CAM_ERR(CAM_SENSOR,
+ "failed while deleting Streamoff settings");
+ }
+
+ i2c_set = &(s_ctrl->i2c_data.streamon_settings);
+ if (i2c_set->is_settings_valid == 1) {
+ i2c_set->is_settings_valid = -1;
+ rc = delete_request(i2c_set);
+ if (rc < 0)
+ CAM_ERR(CAM_SENSOR,
+ "failed while deleting Streamon settings");
+ }
+}
+
static void cam_sensor_release_resource(
struct cam_sensor_ctrl_t *s_ctrl)
{
@@ -61,26 +86,10 @@
CAM_ERR(CAM_SENSOR,
"failed while deleting Res settings");
}
- i2c_set = &(s_ctrl->i2c_data.streamoff_settings);
- if (i2c_set->is_settings_valid == 1) {
- i2c_set->is_settings_valid = -1;
- rc = delete_request(i2c_set);
- if (rc < 0)
- CAM_ERR(CAM_SENSOR,
- "failed while deleting Streamoff settings");
- }
- i2c_set = &(s_ctrl->i2c_data.streamon_settings);
- if (i2c_set->is_settings_valid == 1) {
- i2c_set->is_settings_valid = -1;
- rc = delete_request(i2c_set);
- if (rc < 0)
- CAM_ERR(CAM_SENSOR,
- "failed while deleting Streamoff settings");
- }
+
if (s_ctrl->i2c_data.per_frame != NULL) {
for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
i2c_set = &(s_ctrl->i2c_data.per_frame[i]);
-
if (i2c_set->is_settings_valid == 1) {
i2c_set->is_settings_valid = -1;
rc = delete_request(i2c_set);
@@ -165,42 +174,42 @@
}
case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: {
- if ((s_ctrl->sensor_state == CAM_SENSOR_CONFIG) ||
- (s_ctrl->sensor_state == CAM_SENSOR_START)) {
- i2c_reg_settings =
- &i2c_data->
- per_frame[csl_packet->header.request_id %
- MAX_PER_FRAME_ARRAY];
- CAM_DBG(CAM_SENSOR, "Received Packet: %lld",
- csl_packet->header.request_id % MAX_PER_FRAME_ARRAY);
- if (i2c_reg_settings->is_settings_valid == 1) {
- CAM_ERR(CAM_SENSOR,
- "Already some pkt in offset req : %lld",
- csl_packet->header.request_id);
- rc = delete_request(i2c_reg_settings);
- if (rc < 0) {
- CAM_ERR(CAM_SENSOR,
- "Failed in Deleting the err: %d", rc);
- return rc;
- }
- }
- } else {
- CAM_ERR(CAM_SENSOR,
+ if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+ (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) {
+ CAM_WARN(CAM_SENSOR,
"Rxed Update packets without linking");
- return -EINVAL;
+ return 0;
+ }
+
+ i2c_reg_settings =
+ &i2c_data->
+ per_frame[csl_packet->header.request_id %
+ MAX_PER_FRAME_ARRAY];
+ CAM_DBG(CAM_SENSOR, "Received Packet: %lld",
+ csl_packet->header.request_id % MAX_PER_FRAME_ARRAY);
+ if (i2c_reg_settings->is_settings_valid == 1) {
+ CAM_ERR(CAM_SENSOR,
+ "Already some pkt in offset req : %lld",
+ csl_packet->header.request_id);
+ rc = delete_request(i2c_reg_settings);
+ if (rc < 0) {
+ CAM_ERR(CAM_SENSOR,
+ "Failed in Deleting the err: %d", rc);
+ return rc;
+ }
}
break;
}
case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: {
- if ((s_ctrl->sensor_state == CAM_SENSOR_CONFIG) ||
- (s_ctrl->sensor_state == CAM_SENSOR_START)) {
- cam_sensor_update_req_mgr(s_ctrl, csl_packet);
- } else {
- CAM_ERR(CAM_SENSOR,
- "Rxed Update packets without linking");
- rc = -EINVAL;
+ if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+ (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) {
+ CAM_WARN(CAM_SENSOR,
+ "Rxed NOP packets without linking");
+ return 0;
}
- return rc;
+
+ cam_sensor_update_req_mgr(s_ctrl, csl_packet);
+ return 0;
}
default:
CAM_ERR(CAM_SENSOR, "Invalid Packet Header");
@@ -489,7 +498,7 @@
return;
cam_sensor_release_resource(s_ctrl);
-
+ cam_sensor_release_stream_rsc(s_ctrl);
if (s_ctrl->sensor_state >= CAM_SENSOR_ACQUIRE)
cam_sensor_power_down(s_ctrl);
@@ -706,8 +715,8 @@
}
break;
case CAM_RELEASE_DEV: {
- if ((s_ctrl->sensor_state < CAM_SENSOR_ACQUIRE) ||
- (s_ctrl->sensor_state > CAM_SENSOR_CONFIG)) {
+ if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+ (s_ctrl->sensor_state == CAM_SENSOR_START)) {
rc = -EINVAL;
CAM_WARN(CAM_SENSOR,
"Not in right state to release : %d",
@@ -722,6 +731,7 @@
}
cam_sensor_release_resource(s_ctrl);
+ cam_sensor_release_stream_rsc(s_ctrl);
if (s_ctrl->bridge_intf.device_hdl == -1) {
CAM_ERR(CAM_SENSOR,
"Invalid Handles: link hdl: %d device hdl: %d",
@@ -754,7 +764,8 @@
break;
}
case CAM_START_DEV: {
- if (s_ctrl->sensor_state != CAM_SENSOR_CONFIG) {
+ if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+ (s_ctrl->sensor_state == CAM_SENSOR_START)) {
rc = -EINVAL;
CAM_WARN(CAM_SENSOR,
"Not in right state to start : %d",
@@ -793,6 +804,8 @@
"cannot apply streamoff settings");
}
}
+
+ cam_sensor_release_resource(s_ctrl);
s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
}
break;
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
index 7824102..c757315 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -434,7 +434,7 @@
CAM_ERR(CAM_SMMU, "Error: domain = %pK, device = %pK",
domain, dev);
CAM_ERR(CAM_SMMU, "iova = %lX, flags = %d", iova, flags);
- return 0;
+ return -EINVAL;
}
cb_name = (char *)token;
@@ -448,12 +448,12 @@
CAM_ERR(CAM_SMMU,
"Error: index is not valid, index = %d, token = %s",
idx, cb_name);
- return 0;
+ return -EINVAL;
}
payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC);
if (!payload)
- return 0;
+ return -EINVAL;
payload->domain = domain;
payload->dev = dev;
@@ -468,7 +468,7 @@
schedule_work(&iommu_cb_set.smmu_work);
- return 0;
+ return -EINVAL;
}
static int cam_smmu_translate_dir_to_iommu_dir(
@@ -3140,12 +3140,10 @@
CAM_ERR(CAM_SMMU, "Error: failed to setup cb : %s", cb->name);
goto cb_init_fail;
}
-
if (cb->io_support && cb->mapping)
iommu_set_fault_handler(cb->mapping->domain,
cam_smmu_iommu_fault_handler,
(void *)cb->name);
-
/* increment count to next bank */
iommu_cb_set.cb_init_count++;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index bdc4e2a..ff4f84f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -3004,12 +3004,6 @@
struct mmc_card *card = host->card;
int ret;
- /*
- * In the case of recovery, we can't expect flushing the cache to work
- * always, but we have a go and ignore errors.
- */
- mmc_flush_cache(host->card);
-
if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
mmc_can_reset(card)) {
mmc_host_clk_hold(host);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index e2e9603..75faeb1 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -121,6 +121,7 @@
Select Y to compile the driver in order to have WLAN functionality
support.
+source "drivers/net/wireless/cnss2/Kconfig"
source "drivers/net/wireless/cnss_utils/Kconfig"
source "drivers/net/wireless/cnss_genl/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 7a75193..4ffbd10 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -26,6 +26,8 @@
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
+obj-$(CONFIG_CNSS2) += cnss2/
+
obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
diff --git a/drivers/net/wireless/cnss2/Kconfig b/drivers/net/wireless/cnss2/Kconfig
new file mode 100644
index 0000000..daa343e
--- /dev/null
+++ b/drivers/net/wireless/cnss2/Kconfig
@@ -0,0 +1,40 @@
+config CNSS2
+ tristate "CNSS2 Platform Driver for Wi-Fi Module"
+ depends on !CNSS && PCI_MSM
+ ---help---
+ This module adds the support for Connectivity Subsystem (CNSS) used
+ for PCIe based Wi-Fi devices with QCA6174/QCA6290 chipsets.
+ This driver also adds support to integrate WLAN module to subsystem
+ restart framework.
+
+config CNSS2_DEBUG
+ bool "CNSS2 Platform Driver Debug Support"
+ depends on CNSS2
+ ---help---
+ This option is to enable CNSS2 platform driver debug support which
+ primarily includes providing additional verbose logs for certain
+ features, enabling kernel panic for certain cases to aid the
+ debugging, and enabling any other debug mechanisms.
+
+config CNSS_ASYNC
+ bool "Enable/disable CNSS platform driver asynchronous probe"
+ depends on CNSS2
+ ---help---
+ If enabled, CNSS platform driver would do asynchronous probe.
+ Using asynchronous probe will allow CNSS platform driver to
+ probe in parallel with other device drivers and will help to
+ reduce kernel boot time.
+
+config BUS_AUTO_SUSPEND
+ bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers"
+ depends on CNSS2
+ depends on PCI
+ ---help---
+ Runtime Power Management is supported for PCIe based WLAN Drivers.
+ The features enable cld wlan driver to suspend pcie bus when APPS
+ is awake based on the driver inactivity with the Firmware.
+ The Feature uses runtime power management framework from kernel to
+ track bus access clients and to synchronize the driver activity
+ during system pm.
+ This config flag controls the feature per target based. The feature
+ requires CNSS driver support.
diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile
new file mode 100644
index 0000000..b49d089
--- /dev/null
+++ b/drivers/net/wireless/cnss2/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_CNSS2) += cnss2.o
+
+cnss2-y := main.o
+cnss2-y += debug.o
+cnss2-y += pci.o
+cnss2-y += power.o
+cnss2-y += qmi.o
+cnss2-y += wlan_firmware_service_v01.o
diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c
new file mode 100644
index 0000000..5e2d44c
--- /dev/null
+++ b/drivers/net/wireless/cnss2/debug.c
@@ -0,0 +1,495 @@
+/* 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
+ * 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/err.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include "main.h"
+#include "debug.h"
+#include "pci.h"
+
+#define CNSS_IPC_LOG_PAGES 32
+
+void *cnss_ipc_log_context;
+
+static int cnss_pin_connect_show(struct seq_file *s, void *data)
+{
+ struct cnss_plat_data *cnss_priv = s->private;
+
+ seq_puts(s, "Pin connect results\n");
+ seq_printf(s, "FW power pin result: %04x\n",
+ cnss_priv->pin_result.fw_pwr_pin_result);
+ seq_printf(s, "FW PHY IO pin result: %04x\n",
+ cnss_priv->pin_result.fw_phy_io_pin_result);
+ seq_printf(s, "FW RF pin result: %04x\n",
+ cnss_priv->pin_result.fw_rf_pin_result);
+ seq_printf(s, "Host pin result: %04x\n",
+ cnss_priv->pin_result.host_pin_result);
+ seq_puts(s, "\n");
+
+ return 0;
+}
+
+static int cnss_pin_connect_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cnss_pin_connect_show, inode->i_private);
+}
+
+static const struct file_operations cnss_pin_connect_fops = {
+ .read = seq_read,
+ .release = single_release,
+ .open = cnss_pin_connect_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
+};
+
+static int cnss_stats_show_state(struct seq_file *s,
+ struct cnss_plat_data *plat_priv)
+{
+ enum cnss_driver_state i;
+ int skip = 0;
+ unsigned long state;
+
+ seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
+ for (i = 0, state = plat_priv->driver_state; state != 0;
+ state >>= 1, i++) {
+ if (!(state & 0x1))
+ continue;
+
+ if (skip++)
+ seq_puts(s, " | ");
+
+ switch (i) {
+ case CNSS_QMI_WLFW_CONNECTED:
+ seq_puts(s, "QMI_WLFW_CONNECTED");
+ continue;
+ case CNSS_FW_MEM_READY:
+ seq_puts(s, "FW_MEM_READY");
+ continue;
+ case CNSS_FW_READY:
+ seq_puts(s, "FW_READY");
+ continue;
+ case CNSS_COLD_BOOT_CAL:
+ seq_puts(s, "COLD_BOOT_CAL");
+ continue;
+ case CNSS_DRIVER_LOADING:
+ seq_puts(s, "DRIVER_LOADING");
+ continue;
+ case CNSS_DRIVER_UNLOADING:
+ seq_puts(s, "DRIVER_UNLOADING");
+ continue;
+ case CNSS_DRIVER_PROBED:
+ seq_puts(s, "DRIVER_PROBED");
+ continue;
+ case CNSS_DRIVER_RECOVERY:
+ seq_puts(s, "DRIVER_RECOVERY");
+ continue;
+ case CNSS_FW_BOOT_RECOVERY:
+ seq_puts(s, "FW_BOOT_RECOVERY");
+ continue;
+ case CNSS_DEV_ERR_NOTIFY:
+ seq_puts(s, "DEV_ERR");
+ continue;
+ case CNSS_DRIVER_DEBUG:
+ seq_puts(s, "DRIVER_DEBUG");
+ continue;
+ }
+
+ seq_printf(s, "UNKNOWN-%d", i);
+ }
+ seq_puts(s, ")\n");
+
+ return 0;
+}
+
+static int cnss_stats_show(struct seq_file *s, void *data)
+{
+ struct cnss_plat_data *plat_priv = s->private;
+
+ cnss_stats_show_state(s, plat_priv);
+
+ return 0;
+}
+
+static int cnss_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cnss_stats_show, inode->i_private);
+}
+
+static const struct file_operations cnss_stats_fops = {
+ .read = seq_read,
+ .release = single_release,
+ .open = cnss_stats_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
+};
+
+static ssize_t cnss_dev_boot_debug_write(struct file *fp,
+ const char __user *user_buf,
+ size_t count, loff_t *off)
+{
+ struct cnss_plat_data *plat_priv =
+ ((struct seq_file *)fp->private_data)->private;
+ char buf[64];
+ char *cmd;
+ unsigned int len = 0;
+ int ret = 0;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ cmd = buf;
+
+ if (sysfs_streq(cmd, "on")) {
+ ret = cnss_power_on_device(plat_priv);
+ } else if (sysfs_streq(cmd, "off")) {
+ cnss_power_off_device(plat_priv);
+ } else if (sysfs_streq(cmd, "enumerate")) {
+ ret = cnss_pci_init(plat_priv);
+ } else if (sysfs_streq(cmd, "download")) {
+ set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+ ret = cnss_pci_start_mhi(plat_priv->bus_priv);
+ } else if (sysfs_streq(cmd, "linkup")) {
+ ret = cnss_resume_pci_link(plat_priv->bus_priv);
+ } else if (sysfs_streq(cmd, "linkdown")) {
+ ret = cnss_suspend_pci_link(plat_priv->bus_priv);
+ } else if (sysfs_streq(cmd, "powerup")) {
+ set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_POWER_UP,
+ CNSS_EVENT_SYNC, NULL);
+ } else if (sysfs_streq(cmd, "shutdown")) {
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_POWER_DOWN,
+ CNSS_EVENT_SYNC, NULL);
+ clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+ } else {
+ cnss_pr_err("Device boot debugfs command is invalid\n");
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
+{
+ seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
+ seq_puts(s, "<action> can be one of below:\n");
+ seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
+ seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
+ seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
+ seq_puts(s, "download: download FW and do QMI handshake with FW\n");
+ seq_puts(s, "linkup: bring up PCIe link\n");
+ seq_puts(s, "linkdown: bring down PCIe link\n");
+ seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
+ seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
+
+ return 0;
+}
+
+static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_dev_boot_debug_fops = {
+ .read = seq_read,
+ .write = cnss_dev_boot_debug_write,
+ .release = single_release,
+ .open = cnss_dev_boot_debug_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
+};
+
+static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
+{
+ struct cnss_plat_data *plat_priv = s->private;
+
+ mutex_lock(&plat_priv->dev_lock);
+ if (!plat_priv->diag_reg_read_buf) {
+ seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
+ mutex_unlock(&plat_priv->dev_lock);
+ return 0;
+ }
+
+ seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
+ plat_priv->diag_reg_read_addr,
+ plat_priv->diag_reg_read_mem_type,
+ plat_priv->diag_reg_read_len);
+
+ seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
+ plat_priv->diag_reg_read_buf,
+ plat_priv->diag_reg_read_len, false);
+
+ plat_priv->diag_reg_read_len = 0;
+ kfree(plat_priv->diag_reg_read_buf);
+ plat_priv->diag_reg_read_buf = NULL;
+ mutex_unlock(&plat_priv->dev_lock);
+
+ return 0;
+}
+
+static ssize_t cnss_reg_read_debug_write(struct file *fp,
+ const char __user *user_buf,
+ size_t count, loff_t *off)
+{
+ struct cnss_plat_data *plat_priv =
+ ((struct seq_file *)fp->private_data)->private;
+ char buf[64];
+ char *sptr, *token;
+ unsigned int len = 0;
+ u32 reg_offset, mem_type;
+ u32 data_len = 0;
+ u8 *reg_buf = NULL;
+ const char *delim = " ";
+ int ret = 0;
+
+ if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+ cnss_pr_err("Firmware is not ready yet\n");
+ return -EINVAL;
+ }
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ sptr = buf;
+
+ token = strsep(&sptr, delim);
+ if (!token)
+ return -EINVAL;
+
+ if (!sptr)
+ return -EINVAL;
+
+ if (kstrtou32(token, 0, &mem_type))
+ return -EINVAL;
+
+ token = strsep(&sptr, delim);
+ if (!token)
+ return -EINVAL;
+
+ if (!sptr)
+ return -EINVAL;
+
+ if (kstrtou32(token, 0, ®_offset))
+ return -EINVAL;
+
+ token = strsep(&sptr, delim);
+ if (!token)
+ return -EINVAL;
+
+ if (kstrtou32(token, 0, &data_len))
+ return -EINVAL;
+
+ if (data_len == 0 ||
+ data_len > QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01)
+ return -EINVAL;
+
+ mutex_lock(&plat_priv->dev_lock);
+ kfree(plat_priv->diag_reg_read_buf);
+ plat_priv->diag_reg_read_buf = NULL;
+
+ reg_buf = kzalloc(data_len, GFP_KERNEL);
+ if (!reg_buf) {
+ mutex_unlock(&plat_priv->dev_lock);
+ return -ENOMEM;
+ }
+
+ ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
+ mem_type, data_len,
+ reg_buf);
+ if (ret) {
+ kfree(reg_buf);
+ mutex_unlock(&plat_priv->dev_lock);
+ return ret;
+ }
+
+ plat_priv->diag_reg_read_addr = reg_offset;
+ plat_priv->diag_reg_read_mem_type = mem_type;
+ plat_priv->diag_reg_read_len = data_len;
+ plat_priv->diag_reg_read_buf = reg_buf;
+ mutex_unlock(&plat_priv->dev_lock);
+
+ return count;
+}
+
+static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cnss_reg_read_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_reg_read_debug_fops = {
+ .read = seq_read,
+ .write = cnss_reg_read_debug_write,
+ .open = cnss_reg_read_debug_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
+};
+
+static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
+{
+ seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
+
+ return 0;
+}
+
+static ssize_t cnss_reg_write_debug_write(struct file *fp,
+ const char __user *user_buf,
+ size_t count, loff_t *off)
+{
+ struct cnss_plat_data *plat_priv =
+ ((struct seq_file *)fp->private_data)->private;
+ char buf[64];
+ char *sptr, *token;
+ unsigned int len = 0;
+ u32 reg_offset, mem_type, reg_val;
+ const char *delim = " ";
+ int ret = 0;
+
+ if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+ cnss_pr_err("Firmware is not ready yet\n");
+ return -EINVAL;
+ }
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ sptr = buf;
+
+ token = strsep(&sptr, delim);
+ if (!token)
+ return -EINVAL;
+
+ if (!sptr)
+ return -EINVAL;
+
+ if (kstrtou32(token, 0, &mem_type))
+ return -EINVAL;
+
+ token = strsep(&sptr, delim);
+ if (!token)
+ return -EINVAL;
+
+ if (!sptr)
+ return -EINVAL;
+
+ if (kstrtou32(token, 0, ®_offset))
+ return -EINVAL;
+
+ token = strsep(&sptr, delim);
+ if (!token)
+ return -EINVAL;
+
+ if (kstrtou32(token, 0, ®_val))
+ return -EINVAL;
+
+ ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
+ sizeof(u32),
+ (u8 *)®_val);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cnss_reg_write_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_reg_write_debug_fops = {
+ .read = seq_read,
+ .write = cnss_reg_write_debug_write,
+ .open = cnss_reg_write_debug_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
+};
+
+#ifdef CONFIG_CNSS2_DEBUG
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+ struct dentry *root_dentry = plat_priv->root_dentry;
+
+ debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
+ &cnss_dev_boot_debug_fops);
+ debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
+ &cnss_reg_read_debug_fops);
+ debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
+ &cnss_reg_write_debug_fops);
+
+ return 0;
+}
+#else
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+ return 0;
+}
+#endif
+
+int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct dentry *root_dentry;
+
+ root_dentry = debugfs_create_dir("cnss", 0);
+ if (IS_ERR(root_dentry)) {
+ ret = PTR_ERR(root_dentry);
+ cnss_pr_err("Unable to create debugfs %d\n", ret);
+ goto out;
+ }
+
+ plat_priv->root_dentry = root_dentry;
+
+ debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
+ &cnss_pin_connect_fops);
+ debugfs_create_file("stats", 0644, root_dentry, plat_priv,
+ &cnss_stats_fops);
+
+ cnss_create_debug_only_node(plat_priv);
+
+out:
+ return ret;
+}
+
+void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
+{
+ debugfs_remove_recursive(plat_priv->root_dentry);
+}
+
+int cnss_debug_init(void)
+{
+ cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
+ "cnss", 0);
+ if (!cnss_ipc_log_context) {
+ cnss_pr_err("Unable to create IPC log context!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void cnss_debug_deinit(void)
+{
+ if (cnss_ipc_log_context) {
+ ipc_log_context_destroy(cnss_ipc_log_context);
+ cnss_ipc_log_context = NULL;
+ }
+}
diff --git a/drivers/net/wireless/cnss2/debug.h b/drivers/net/wireless/cnss2/debug.h
new file mode 100644
index 0000000..decc84a
--- /dev/null
+++ b/drivers/net/wireless/cnss2/debug.h
@@ -0,0 +1,69 @@
+/* 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
+ * 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 _CNSS_DEBUG_H
+#define _CNSS_DEBUG_H
+
+#include <linux/ipc_logging.h>
+#include <linux/printk.h>
+
+extern void *cnss_ipc_log_context;
+
+#define cnss_ipc_log_string(_x...) do { \
+ if (cnss_ipc_log_context) \
+ ipc_log_string(cnss_ipc_log_context, _x); \
+ } while (0)
+
+#define cnss_pr_err(_fmt, ...) do { \
+ pr_err("cnss: " _fmt, ##__VA_ARGS__); \
+ cnss_ipc_log_string("ERR: " _fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define cnss_pr_warn(_fmt, ...) do { \
+ pr_warn("cnss: " _fmt, ##__VA_ARGS__); \
+ cnss_ipc_log_string("WRN: " _fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define cnss_pr_info(_fmt, ...) do { \
+ pr_info("cnss: " _fmt, ##__VA_ARGS__); \
+ cnss_ipc_log_string("INF: " _fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define cnss_pr_dbg(_fmt, ...) do { \
+ pr_debug("cnss: " _fmt, ##__VA_ARGS__); \
+ cnss_ipc_log_string("DBG: " _fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#ifdef CONFIG_CNSS2_DEBUG
+#define CNSS_ASSERT(_condition) do { \
+ if (!(_condition)) { \
+ cnss_pr_err("ASSERT at line %d\n", \
+ __LINE__); \
+ BUG_ON(1); \
+ } \
+ } while (0)
+#else
+#define CNSS_ASSERT(_condition) do { \
+ if (!(_condition)) { \
+ cnss_pr_err("ASSERT at line %d\n", \
+ __LINE__); \
+ WARN_ON(1); \
+ } \
+ } while (0)
+#endif
+
+int cnss_debug_init(void);
+void cnss_debug_deinit(void);
+int cnss_debugfs_create(struct cnss_plat_data *plat_priv);
+void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv);
+
+#endif /* _CNSS_DEBUG_H */
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
new file mode 100644
index 0000000..bcea74a
--- /dev/null
+++ b/drivers/net/wireless/cnss2/main.c
@@ -0,0 +1,2368 @@
+/* Copyright (c) 2016-2018, 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/delay.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/rwsem.h>
+#include <linux/suspend.h>
+#include <linux/timer.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/subsystem_notif.h>
+
+#include "main.h"
+#include "debug.h"
+#include "pci.h"
+
+#define CNSS_DUMP_FORMAT_VER 0x11
+#define CNSS_DUMP_FORMAT_VER_V2 0x22
+#define CNSS_DUMP_MAGIC_VER_V2 0x42445953
+#define CNSS_DUMP_NAME "CNSS_WLAN"
+#define CNSS_DUMP_DESC_SIZE 0x1000
+#define CNSS_DUMP_SEG_VER 0x1
+#define WLAN_RECOVERY_DELAY 1000
+#define FILE_SYSTEM_READY 1
+#define FW_READY_TIMEOUT 20000
+#define FW_ASSERT_TIMEOUT 5000
+#define CNSS_EVENT_PENDING 2989
+#define WAKE_MSI_NAME "WAKE"
+
+static struct cnss_plat_data *plat_env;
+
+static DECLARE_RWSEM(cnss_pm_sem);
+
+static bool qmi_bypass;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(qmi_bypass, bool, 0600);
+MODULE_PARM_DESC(qmi_bypass, "Bypass QMI from platform driver");
+#endif
+
+static bool enable_waltest;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(enable_waltest, bool, 0600);
+MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
+#endif
+
+enum cnss_debug_quirks {
+ LINK_DOWN_SELF_RECOVERY,
+ SKIP_DEVICE_BOOT,
+ USE_CORE_ONLY_FW,
+ SKIP_RECOVERY,
+};
+
+unsigned long quirks;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(quirks, ulong, 0600);
+MODULE_PARM_DESC(quirks, "Debug quirks for the driver");
+#endif
+
+static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
+ "qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
+ "utfbd30.bin", "epping30.bin", "evicted30.bin"
+};
+
+static struct cnss_fw_files FW_FILES_DEFAULT = {
+ "qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin",
+ "utfbd.bin", "epping.bin", "evicted.bin"
+};
+
+struct cnss_driver_event {
+ struct list_head list;
+ enum cnss_driver_event_type type;
+ bool sync;
+ struct completion complete;
+ int ret;
+ void *data;
+};
+
+static enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
+{
+ if (!dev)
+ return CNSS_BUS_NONE;
+
+ if (!dev->bus)
+ return CNSS_BUS_NONE;
+
+ if (memcmp(dev->bus->name, "pci", 3) == 0)
+ return CNSS_BUS_PCI;
+ else
+ return CNSS_BUS_NONE;
+}
+
+static void cnss_set_plat_priv(struct platform_device *plat_dev,
+ struct cnss_plat_data *plat_priv)
+{
+ plat_env = plat_priv;
+}
+
+static struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
+ *plat_dev)
+{
+ return plat_env;
+}
+
+void *cnss_bus_dev_to_bus_priv(struct device *dev)
+{
+ if (!dev)
+ return NULL;
+
+ switch (cnss_get_dev_bus_type(dev)) {
+ case CNSS_BUS_PCI:
+ return cnss_get_pci_priv(to_pci_dev(dev));
+ default:
+ return NULL;
+ }
+}
+
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
+{
+ void *bus_priv;
+
+ if (!dev)
+ return cnss_get_plat_priv(NULL);
+
+ bus_priv = cnss_bus_dev_to_bus_priv(dev);
+ if (!bus_priv)
+ return NULL;
+
+ switch (cnss_get_dev_bus_type(dev)) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_priv_to_plat_priv(bus_priv);
+ default:
+ return NULL;
+ }
+}
+
+static int cnss_pm_notify(struct notifier_block *b,
+ unsigned long event, void *p)
+{
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ down_write(&cnss_pm_sem);
+ break;
+ case PM_POST_SUSPEND:
+ up_write(&cnss_pm_sem);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block cnss_pm_notifier = {
+ .notifier_call = cnss_pm_notify,
+};
+
+static void cnss_pm_stay_awake(struct cnss_plat_data *plat_priv)
+{
+ if (atomic_inc_return(&plat_priv->pm_count) != 1)
+ return;
+
+ cnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n",
+ plat_priv->driver_state,
+ atomic_read(&plat_priv->pm_count));
+ pm_stay_awake(&plat_priv->plat_dev->dev);
+}
+
+static void cnss_pm_relax(struct cnss_plat_data *plat_priv)
+{
+ int r = atomic_dec_return(&plat_priv->pm_count);
+
+ WARN_ON(r < 0);
+
+ if (r != 0)
+ return;
+
+ cnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n",
+ plat_priv->driver_state,
+ atomic_read(&plat_priv->pm_count));
+ pm_relax(&plat_priv->plat_dev->dev);
+}
+
+void cnss_lock_pm_sem(struct device *dev)
+{
+ down_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_lock_pm_sem);
+
+void cnss_release_pm_sem(struct device *dev)
+{
+ up_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_release_pm_sem);
+
+int cnss_get_fw_files_for_target(struct device *dev,
+ struct cnss_fw_files *pfw_files,
+ u32 target_type, u32 target_version)
+{
+ if (!pfw_files)
+ return -ENODEV;
+
+ switch (target_version) {
+ case QCA6174_REV3_VERSION:
+ case QCA6174_REV3_2_VERSION:
+ memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+ break;
+ default:
+ memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+ cnss_pr_err("Unknown target version, type: 0x%X, version: 0x%X",
+ target_type, target_version);
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files_for_target);
+
+int cnss_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_bus_bw_info *bus_bw_info;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ bus_bw_info = &plat_priv->bus_bw_info;
+ if (!bus_bw_info->bus_client)
+ return -EINVAL;
+
+ switch (bandwidth) {
+ case CNSS_BUS_WIDTH_NONE:
+ case CNSS_BUS_WIDTH_LOW:
+ case CNSS_BUS_WIDTH_MEDIUM:
+ case CNSS_BUS_WIDTH_HIGH:
+ ret = msm_bus_scale_client_update_request(
+ bus_bw_info->bus_client, bandwidth);
+ if (!ret)
+ bus_bw_info->current_bw_vote = bandwidth;
+ else
+ cnss_pr_err("Could not set bus bandwidth: %d, err = %d\n",
+ bandwidth, ret);
+ break;
+ default:
+ cnss_pr_err("Invalid bus bandwidth: %d", bandwidth);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(cnss_request_bus_bandwidth);
+
+int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ if (cap)
+ *cap = plat_priv->cap;
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_platform_cap);
+
+int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ void *bus_priv = cnss_bus_dev_to_bus_priv(dev);
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ ret = cnss_pci_get_bar_info(bus_priv, &info->va, &info->pa);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_soc_info);
+
+void cnss_request_pm_qos(struct device *dev, u32 qos_val)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+ if (!plat_priv)
+ return;
+
+ pm_qos_add_request(&plat_priv->qos_request, PM_QOS_CPU_DMA_LATENCY,
+ qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos);
+
+void cnss_remove_pm_qos(struct device *dev)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+ if (!plat_priv)
+ return;
+
+ pm_qos_remove_request(&plat_priv->qos_request);
+}
+EXPORT_SYMBOL(cnss_remove_pm_qos);
+
+int cnss_wlan_enable(struct device *dev,
+ struct cnss_wlan_enable_cfg *config,
+ enum cnss_driver_mode mode,
+ const char *host_version)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct wlfw_wlan_cfg_req_msg_v01 req;
+ u32 i;
+ int ret = 0;
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ return 0;
+
+ if (qmi_bypass)
+ return 0;
+
+ if (!config || !host_version) {
+ cnss_pr_err("Invalid config or host_version pointer\n");
+ return -EINVAL;
+ }
+
+ cnss_pr_dbg("Mode: %d, config: %pK, host_version: %s\n",
+ mode, config, host_version);
+
+ if (mode == CNSS_WALTEST || mode == CNSS_CCPM)
+ goto skip_cfg;
+
+ memset(&req, 0, sizeof(req));
+
+ req.host_version_valid = 1;
+ strlcpy(req.host_version, host_version,
+ QMI_WLFW_MAX_STR_LEN_V01 + 1);
+
+ req.tgt_cfg_valid = 1;
+ if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
+ req.tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
+ else
+ req.tgt_cfg_len = config->num_ce_tgt_cfg;
+ for (i = 0; i < req.tgt_cfg_len; i++) {
+ req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
+ req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
+ req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
+ req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
+ req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
+ }
+
+ req.svc_cfg_valid = 1;
+ if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
+ req.svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
+ else
+ req.svc_cfg_len = config->num_ce_svc_pipe_cfg;
+ for (i = 0; i < req.svc_cfg_len; i++) {
+ req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
+ req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
+ req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
+ }
+
+ req.shadow_reg_v2_valid = 1;
+ if (config->num_shadow_reg_v2_cfg >
+ QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
+ req.shadow_reg_v2_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
+ else
+ req.shadow_reg_v2_len = config->num_shadow_reg_v2_cfg;
+
+ memcpy(req.shadow_reg_v2, config->shadow_reg_v2_cfg,
+ sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01)
+ * req.shadow_reg_v2_len);
+
+ ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, &req);
+ if (ret)
+ goto out;
+
+skip_cfg:
+ ret = cnss_wlfw_wlan_mode_send_sync(plat_priv, mode);
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_enable);
+
+int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ return 0;
+
+ if (qmi_bypass)
+ return 0;
+
+ return cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
+}
+EXPORT_SYMBOL(cnss_wlan_disable);
+
+#ifdef CONFIG_CNSS2_DEBUG
+int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
+ u32 data_len, u8 *output)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ int ret = 0;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return -EINVAL;
+ }
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ return 0;
+
+ if (!output || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
+ cnss_pr_err("Invalid parameters for athdiag read: output %p, data_len %u\n",
+ output, data_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+ cnss_pr_err("Invalid state for athdiag read: 0x%lx\n",
+ plat_priv->driver_state);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, offset, mem_type,
+ data_len, output);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_athdiag_read);
+
+int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
+ u32 data_len, u8 *input)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ int ret = 0;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return -EINVAL;
+ }
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ return 0;
+
+ if (!input || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
+ cnss_pr_err("Invalid parameters for athdiag write: input %p, data_len %u\n",
+ input, data_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+ cnss_pr_err("Invalid state for athdiag write: 0x%lx\n",
+ plat_priv->driver_state);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, offset, mem_type,
+ data_len, input);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_athdiag_write);
+#else
+int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
+ u32 data_len, u8 *output)
+{
+ return -EPERM;
+}
+EXPORT_SYMBOL(cnss_athdiag_read);
+
+int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
+ u32 data_len, u8 *input)
+{
+ return -EPERM;
+}
+EXPORT_SYMBOL(cnss_athdiag_write);
+#endif
+
+int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ return 0;
+
+ return cnss_wlfw_ini_send_sync(plat_priv, fw_log_mode);
+}
+EXPORT_SYMBOL(cnss_set_fw_log_mode);
+
+u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+ int ret, num_vectors;
+ u32 user_base_data, base_vector;
+
+ ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
+ WAKE_MSI_NAME, &num_vectors,
+ &user_base_data, &base_vector);
+
+ if (ret) {
+ cnss_pr_err("WAKE MSI is not valid\n");
+ return 0;
+ }
+
+ return user_base_data;
+}
+
+static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ set_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+
+ ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
+ if (ret)
+ goto out;
+
+ ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
+ if (ret)
+ goto out;
+
+ ret = cnss_pci_load_m3(plat_priv->bus_priv);
+ if (ret)
+ goto out;
+
+ ret = cnss_wlfw_m3_dnld_send_sync(plat_priv);
+ if (ret)
+ goto out;
+
+ return 0;
+out:
+ return ret;
+}
+
+static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ cnss_pr_dbg("Skip driver probe\n");
+ goto out;
+ }
+
+ if (!plat_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev,
+ pci_priv->pci_device_id);
+ if (ret) {
+ cnss_pr_err("Failed to reinit host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+ ret = plat_priv->driver_ops->probe(pci_priv->pci_dev,
+ pci_priv->pci_device_id);
+ if (ret) {
+ cnss_pr_err("Failed to probe host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int cnss_driver_call_remove(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
+ test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Skip driver remove\n");
+ return 0;
+ }
+
+ if (!plat_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ return -EINVAL;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ plat_priv->driver_ops->shutdown(pci_priv->pci_dev);
+ } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ plat_priv->driver_ops->remove(pci_priv->pci_dev);
+ clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+}
+
+static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ del_timer(&plat_priv->fw_boot_timer);
+ set_bit(CNSS_FW_READY, &plat_priv->driver_state);
+
+ if (test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state)) {
+ clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ }
+
+ if (enable_waltest) {
+ ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
+ QMI_WLFW_WALTEST_V01);
+ } else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
+ ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
+ QMI_WLFW_CALIBRATION_V01);
+ } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ ret = cnss_driver_call_probe(plat_priv);
+ } else {
+ complete(&plat_priv->power_up_complete);
+ }
+
+ if (ret)
+ goto shutdown;
+
+ return 0;
+
+shutdown:
+ cnss_pci_stop_mhi(plat_priv->bus_priv);
+ cnss_suspend_pci_link(plat_priv->bus_priv);
+ cnss_power_off_device(plat_priv);
+
+ return ret;
+}
+
+static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
+{
+ switch (type) {
+ case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
+ return "SERVER_ARRIVE";
+ case CNSS_DRIVER_EVENT_SERVER_EXIT:
+ return "SERVER_EXIT";
+ case CNSS_DRIVER_EVENT_REQUEST_MEM:
+ return "REQUEST_MEM";
+ case CNSS_DRIVER_EVENT_FW_MEM_READY:
+ return "FW_MEM_READY";
+ case CNSS_DRIVER_EVENT_FW_READY:
+ return "FW_READY";
+ case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
+ return "COLD_BOOT_CAL_START";
+ case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
+ return "COLD_BOOT_CAL_DONE";
+ case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
+ return "REGISTER_DRIVER";
+ case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
+ return "UNREGISTER_DRIVER";
+ case CNSS_DRIVER_EVENT_RECOVERY:
+ return "RECOVERY";
+ case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
+ return "FORCE_FW_ASSERT";
+ case CNSS_DRIVER_EVENT_POWER_UP:
+ return "POWER_UP";
+ case CNSS_DRIVER_EVENT_POWER_DOWN:
+ return "POWER_DOWN";
+ case CNSS_DRIVER_EVENT_MAX:
+ return "EVENT_MAX";
+ }
+
+ return "UNKNOWN";
+};
+
+int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
+ enum cnss_driver_event_type type,
+ u32 flags, void *data)
+{
+ struct cnss_driver_event *event;
+ unsigned long irq_flags;
+ int gfp = GFP_KERNEL;
+ int ret = 0;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ cnss_pr_dbg("Posting event: %s(%d)%s, state: 0x%lx flags: 0x%0x\n",
+ cnss_driver_event_to_str(type), type,
+ flags ? "-sync" : "", plat_priv->driver_state, flags);
+
+ if (type >= CNSS_DRIVER_EVENT_MAX) {
+ cnss_pr_err("Invalid Event type: %d, can't post", type);
+ return -EINVAL;
+ }
+
+ if (in_interrupt() || irqs_disabled())
+ gfp = GFP_ATOMIC;
+
+ event = kzalloc(sizeof(*event), gfp);
+ if (!event)
+ return -ENOMEM;
+
+ cnss_pm_stay_awake(plat_priv);
+
+ event->type = type;
+ event->data = data;
+ init_completion(&event->complete);
+ event->ret = CNSS_EVENT_PENDING;
+ event->sync = !!(flags & CNSS_EVENT_SYNC);
+
+ spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
+ list_add_tail(&event->list, &plat_priv->event_list);
+ spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+
+ queue_work(plat_priv->event_wq, &plat_priv->event_work);
+
+ if (!(flags & CNSS_EVENT_SYNC))
+ goto out;
+
+ if (flags & CNSS_EVENT_UNINTERRUPTIBLE)
+ wait_for_completion(&event->complete);
+ else
+ ret = wait_for_completion_interruptible(&event->complete);
+
+ cnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
+ cnss_driver_event_to_str(type), type,
+ plat_priv->driver_state, ret, event->ret);
+ spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
+ if (ret == -ERESTARTSYS && event->ret == CNSS_EVENT_PENDING) {
+ event->sync = false;
+ spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+ ret = -EINTR;
+ goto out;
+ }
+ spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+
+ ret = event->ret;
+ kfree(event);
+
+out:
+ cnss_pm_relax(plat_priv);
+ return ret;
+}
+
+int cnss_power_up(struct device *dev)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ unsigned int timeout;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ cnss_pr_dbg("Powering up device\n");
+
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_POWER_UP,
+ CNSS_EVENT_SYNC, NULL);
+ if (ret)
+ goto out;
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ goto out;
+
+ timeout = cnss_get_qmi_timeout();
+
+ reinit_completion(&plat_priv->power_up_complete);
+ ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
+ msecs_to_jiffies(timeout) << 2);
+ if (!ret) {
+ cnss_pr_err("Timeout waiting for power up to complete\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_power_up);
+
+int cnss_power_down(struct device *dev)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ cnss_pr_dbg("Powering down device\n");
+
+ return cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_POWER_DOWN,
+ CNSS_EVENT_SYNC, NULL);
+}
+EXPORT_SYMBOL(cnss_power_down);
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ if (plat_priv->driver_ops) {
+ cnss_pr_err("Driver has already registered!\n");
+ return -EEXIST;
+ }
+
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
+ driver_ops);
+ return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
+{
+ struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return;
+ }
+
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+static int cnss_get_resources(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ ret = cnss_get_vreg(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to get vreg, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_get_pinctrl(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
+ goto out;
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static void cnss_put_resources(struct cnss_plat_data *plat_priv)
+{
+}
+
+static int cnss_modem_notifier_nb(struct notifier_block *nb,
+ unsigned long code,
+ void *ss_handle)
+{
+ struct cnss_plat_data *plat_priv =
+ container_of(nb, struct cnss_plat_data, modem_nb);
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+ struct cnss_esoc_info *esoc_info;
+ struct cnss_wlan_driver *driver_ops;
+
+ cnss_pr_dbg("Modem notifier: event %lu\n", code);
+
+ if (!pci_priv)
+ return NOTIFY_DONE;
+
+ esoc_info = &plat_priv->esoc_info;
+
+ if (code == SUBSYS_AFTER_POWERUP)
+ esoc_info->modem_current_status = 1;
+ else if (code == SUBSYS_BEFORE_SHUTDOWN)
+ esoc_info->modem_current_status = 0;
+ else
+ return NOTIFY_DONE;
+
+ driver_ops = plat_priv->driver_ops;
+ if (!driver_ops || !driver_ops->modem_status)
+ return NOTIFY_DONE;
+
+ driver_ops->modem_status(pci_priv->pci_dev,
+ esoc_info->modem_current_status);
+
+ return NOTIFY_OK;
+}
+
+static int cnss_register_esoc(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct device *dev;
+ struct cnss_esoc_info *esoc_info;
+ struct esoc_desc *esoc_desc;
+ const char *client_desc;
+
+ dev = &plat_priv->plat_dev->dev;
+ esoc_info = &plat_priv->esoc_info;
+
+ esoc_info->notify_modem_status =
+ of_property_read_bool(dev->of_node,
+ "qcom,notify-modem-status");
+
+ if (esoc_info->notify_modem_status)
+ goto out;
+
+ ret = of_property_read_string_index(dev->of_node, "esoc-names", 0,
+ &client_desc);
+ if (ret) {
+ cnss_pr_dbg("esoc-names is not defined in DT, skip!\n");
+ } else {
+ esoc_desc = devm_register_esoc_client(dev, client_desc);
+ if (IS_ERR_OR_NULL(esoc_desc)) {
+ ret = PTR_RET(esoc_desc);
+ cnss_pr_err("Failed to register esoc_desc, err = %d\n",
+ ret);
+ goto out;
+ }
+ esoc_info->esoc_desc = esoc_desc;
+ }
+
+ plat_priv->modem_nb.notifier_call = cnss_modem_notifier_nb;
+ esoc_info->modem_current_status = 0;
+ esoc_info->modem_notify_handler =
+ subsys_notif_register_notifier(esoc_info->esoc_desc ?
+ esoc_info->esoc_desc->name :
+ "modem", &plat_priv->modem_nb);
+ if (IS_ERR(esoc_info->modem_notify_handler)) {
+ ret = PTR_ERR(esoc_info->modem_notify_handler);
+ cnss_pr_err("Failed to register esoc notifier, err = %d\n",
+ ret);
+ goto unreg_esoc;
+ }
+
+ return 0;
+unreg_esoc:
+ if (esoc_info->esoc_desc)
+ devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
+out:
+ return ret;
+}
+
+static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
+{
+ struct device *dev;
+ struct cnss_esoc_info *esoc_info;
+
+ dev = &plat_priv->plat_dev->dev;
+ esoc_info = &plat_priv->esoc_info;
+
+ if (esoc_info->notify_modem_status)
+ subsys_notif_unregister_notifier(esoc_info->
+ modem_notify_handler,
+ &plat_priv->modem_nb);
+ if (esoc_info->esoc_desc)
+ devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
+}
+
+static int cnss_qca6174_powerup(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_resume_pci_link(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+ goto power_off;
+ }
+
+ ret = cnss_driver_call_probe(plat_priv);
+ if (ret)
+ goto suspend_link;
+
+ return 0;
+suspend_link:
+ cnss_suspend_pci_link(pci_priv);
+power_off:
+ cnss_power_off_device(plat_priv);
+out:
+ return ret;
+}
+
+static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ cnss_pm_request_resume(pci_priv);
+
+ cnss_driver_call_remove(plat_priv);
+
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
+ ret = cnss_suspend_pci_link(pci_priv);
+ if (ret)
+ cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+ cnss_power_off_device(plat_priv);
+
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ return ret;
+}
+
+static void cnss_qca6174_crash_shutdown(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ if (!plat_priv->driver_ops)
+ return;
+
+ plat_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
+}
+
+static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+ unsigned int timeout;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+ cnss_pci_clear_dump_info(pci_priv);
+ }
+
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_resume_pci_link(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+ goto power_off;
+ }
+
+ timeout = cnss_get_qmi_timeout();
+
+ ret = cnss_pci_start_mhi(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to start MHI, err = %d\n", ret);
+ if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
+ !pci_priv->pci_link_down_ind && timeout)
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout >> 1));
+ return 0;
+ }
+
+ if (test_bit(USE_CORE_ONLY_FW, &quirks)) {
+ clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ return 0;
+ }
+
+ cnss_set_pin_connect_status(plat_priv);
+
+ if (qmi_bypass) {
+ ret = cnss_driver_call_probe(plat_priv);
+ if (ret)
+ goto stop_mhi;
+ } else if (timeout) {
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout << 1));
+ }
+
+ return 0;
+
+stop_mhi:
+ cnss_pci_stop_mhi(pci_priv);
+ cnss_suspend_pci_link(pci_priv);
+power_off:
+ cnss_power_off_device(plat_priv);
+out:
+ return ret;
+}
+
+static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ cnss_pm_request_resume(pci_priv);
+
+ cnss_driver_call_remove(plat_priv);
+
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
+ cnss_pci_stop_mhi(pci_priv);
+
+ ret = cnss_suspend_pci_link(pci_priv);
+ if (ret)
+ cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+ cnss_power_off_device(plat_priv);
+
+ clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ return ret;
+}
+
+static void cnss_qca6290_crash_shutdown(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+ int ret = 0;
+
+ cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
+ plat_priv->driver_state);
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state))
+ return;
+
+ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
+ if (ret) {
+ cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
+ return;
+ }
+
+ cnss_pci_collect_dump_info(pci_priv);
+}
+
+static int cnss_powerup(struct cnss_plat_data *plat_priv)
+{
+ int ret;
+
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_powerup(plat_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_powerup(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%lx\n",
+ plat_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static int cnss_shutdown(struct cnss_plat_data *plat_priv)
+{
+ int ret;
+
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_shutdown(plat_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_shutdown(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%lx\n",
+ plat_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
+{
+ struct cnss_plat_data *plat_priv;
+
+ if (!subsys_desc->dev) {
+ cnss_pr_err("dev from subsys_desc is NULL\n");
+ return -ENODEV;
+ }
+
+ plat_priv = dev_get_drvdata(subsys_desc->dev);
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ if (!plat_priv->driver_state) {
+ cnss_pr_dbg("Powerup is ignored\n");
+ return 0;
+ }
+
+ return cnss_powerup(plat_priv);
+}
+
+static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
+ bool force_stop)
+{
+ struct cnss_plat_data *plat_priv;
+
+ if (!subsys_desc->dev) {
+ cnss_pr_err("dev from subsys_desc is NULL\n");
+ return -ENODEV;
+ }
+
+ plat_priv = dev_get_drvdata(subsys_desc->dev);
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ if (!plat_priv->driver_state) {
+ cnss_pr_dbg("shutdown is ignored\n");
+ return 0;
+ }
+
+ return cnss_shutdown(plat_priv);
+}
+
+static int cnss_qca6290_ramdump(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+ struct cnss_dump_data *dump_data = &info_v2->dump_data;
+ struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
+ struct ramdump_segment *ramdump_segs, *s;
+ int i, ret = 0;
+
+ if (!info_v2->dump_data_valid ||
+ dump_data->nentries == 0)
+ return 0;
+
+ ramdump_segs = kcalloc(dump_data->nentries,
+ sizeof(*ramdump_segs),
+ GFP_KERNEL);
+ if (!ramdump_segs)
+ return -ENOMEM;
+
+ s = ramdump_segs;
+ for (i = 0; i < dump_data->nentries; i++) {
+ s->address = dump_seg->address;
+ s->v_address = dump_seg->v_address;
+ s->size = dump_seg->size;
+ s++;
+ dump_seg++;
+ }
+
+ ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
+ dump_data->nentries);
+ kfree(ramdump_segs);
+
+ cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
+ cnss_pci_clear_dump_info(plat_priv->bus_priv);
+
+ return ret;
+}
+
+static int cnss_qca6174_ramdump(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_ramdump_info *ramdump_info;
+ struct ramdump_segment segment;
+
+ ramdump_info = &plat_priv->ramdump_info;
+ if (!ramdump_info->ramdump_size)
+ return -EINVAL;
+
+ memset(&segment, 0, sizeof(segment));
+ segment.v_address = ramdump_info->ramdump_va;
+ segment.size = ramdump_info->ramdump_size;
+ ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
+
+ return ret;
+}
+
+static int cnss_subsys_ramdump(int enable,
+ const struct subsys_desc *subsys_desc)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ if (!enable)
+ return 0;
+
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_ramdump(plat_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_ramdump(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%lx\n",
+ plat_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_ramdump_info *ramdump_info;
+
+ if (!plat_priv)
+ return NULL;
+
+ ramdump_info = &plat_priv->ramdump_info;
+ *size = ramdump_info->ramdump_size;
+
+ return ramdump_info->ramdump_va;
+}
+EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
+
+void cnss_device_crashed(struct device *dev)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_subsys_info *subsys_info;
+
+ if (!plat_priv)
+ return;
+
+ subsys_info = &plat_priv->subsys_info;
+ if (subsys_info->subsys_device) {
+ set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ subsys_set_crash_status(subsys_info->subsys_device, true);
+ subsystem_restart_dev(subsys_info->subsys_device);
+ }
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+
+static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
+{
+ struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return;
+ }
+
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ cnss_qca6174_crash_shutdown(plat_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ cnss_qca6290_crash_shutdown(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%lx\n",
+ plat_priv->device_id);
+ }
+}
+
+static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
+{
+ switch (reason) {
+ case CNSS_REASON_DEFAULT:
+ return "DEFAULT";
+ case CNSS_REASON_LINK_DOWN:
+ return "LINK_DOWN";
+ case CNSS_REASON_RDDM:
+ return "RDDM";
+ case CNSS_REASON_TIMEOUT:
+ return "TIMEOUT";
+ }
+
+ return "UNKNOWN";
+};
+
+static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
+ enum cnss_recovery_reason reason)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+ struct cnss_subsys_info *subsys_info =
+ &plat_priv->subsys_info;
+ int ret = 0;
+
+ plat_priv->recovery_count++;
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ goto self_recovery;
+
+ if (plat_priv->driver_ops &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
+ plat_priv->driver_ops->update_status(pci_priv->pci_dev,
+ CNSS_RECOVERY);
+
+ if (test_bit(SKIP_RECOVERY, &quirks)) {
+ cnss_pr_dbg("Skip device recovery\n");
+ return 0;
+ }
+
+ switch (reason) {
+ case CNSS_REASON_LINK_DOWN:
+ if (test_bit(LINK_DOWN_SELF_RECOVERY, &quirks))
+ goto self_recovery;
+ break;
+ case CNSS_REASON_RDDM:
+ clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM);
+ if (ret) {
+ cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
+ break;
+ }
+ cnss_pci_collect_dump_info(pci_priv);
+ break;
+ case CNSS_REASON_DEFAULT:
+ case CNSS_REASON_TIMEOUT:
+ break;
+ default:
+ cnss_pr_err("Unsupported recovery reason: %s(%d)\n",
+ cnss_recovery_reason_to_str(reason), reason);
+ break;
+ }
+
+ if (!subsys_info->subsys_device)
+ return 0;
+
+ subsys_set_crash_status(subsys_info->subsys_device, true);
+ subsystem_restart_dev(subsys_info->subsys_device);
+
+ return 0;
+
+self_recovery:
+ cnss_shutdown(plat_priv);
+ cnss_powerup(plat_priv);
+
+ return 0;
+}
+
+static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv,
+ void *data)
+{
+ struct cnss_recovery_data *recovery_data = data;
+ int ret = 0;
+
+ cnss_pr_dbg("Driver recovery is triggered with reason: %s(%d)\n",
+ cnss_recovery_reason_to_str(recovery_data->reason),
+ recovery_data->reason);
+
+ if (!plat_priv->driver_state) {
+ cnss_pr_err("Improper driver state, ignore recovery\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ cnss_pr_err("Recovery is already in progress\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ cnss_pr_err("Driver unload is in progress, ignore recovery\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+ cnss_pr_err("Driver load is in progress, ignore recovery\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+ default:
+ if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+ set_bit(CNSS_FW_BOOT_RECOVERY,
+ &plat_priv->driver_state);
+ } else if (test_bit(CNSS_DRIVER_LOADING,
+ &plat_priv->driver_state)) {
+ cnss_pr_err("Driver probe is in progress, ignore recovery\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+ }
+
+ set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ ret = cnss_do_recovery(plat_priv, recovery_data->reason);
+
+out:
+ kfree(data);
+ return ret;
+}
+
+int cnss_self_recovery(struct device *dev,
+ enum cnss_recovery_reason reason)
+{
+ cnss_schedule_recovery(dev, reason);
+ return 0;
+}
+EXPORT_SYMBOL(cnss_self_recovery);
+
+void cnss_schedule_recovery(struct device *dev,
+ enum cnss_recovery_reason reason)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_recovery_data *data;
+ int gfp = GFP_KERNEL;
+
+ if (in_interrupt() || irqs_disabled())
+ gfp = GFP_ATOMIC;
+
+ data = kzalloc(sizeof(*data), gfp);
+ if (!data)
+ return;
+
+ data->reason = reason;
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_RECOVERY,
+ 0, data);
+}
+EXPORT_SYMBOL(cnss_schedule_recovery);
+
+static int cnss_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+ int ret;
+
+ ret = cnss_pci_set_mhi_state(plat_priv->bus_priv,
+ CNSS_MHI_TRIGGER_RDDM);
+ if (ret) {
+ cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret);
+ cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+ CNSS_REASON_DEFAULT);
+ return 0;
+ }
+
+ if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(FW_ASSERT_TIMEOUT));
+ }
+
+ return 0;
+}
+
+int cnss_force_fw_assert(struct device *dev)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID) {
+ cnss_pr_info("Forced FW assert is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ cnss_pr_info("Recovery is already in progress, ignore forced FW assert\n");
+ return 0;
+ }
+
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
+ 0, NULL);
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_force_fw_assert);
+
+void fw_boot_timeout(unsigned long data)
+{
+ struct cnss_plat_data *plat_priv = (struct cnss_plat_data *)data;
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ cnss_pr_err("Timeout waiting for FW ready indication!\n");
+
+ cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+ CNSS_REASON_TIMEOUT);
+}
+
+static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv,
+ void *data)
+{
+ int ret = 0;
+
+ set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ plat_priv->driver_ops = data;
+
+ ret = cnss_powerup(plat_priv);
+ if (ret) {
+ clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ plat_priv->driver_ops = NULL;
+ }
+
+ return ret;
+}
+
+static int cnss_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
+{
+ set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+ cnss_shutdown(plat_priv);
+ plat_priv->driver_ops = NULL;
+
+ return 0;
+}
+
+static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
+ ret = cnss_powerup(plat_priv);
+ if (ret)
+ clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
+
+ return ret;
+}
+
+static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
+{
+ cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
+ cnss_shutdown(plat_priv);
+ clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
+
+ return 0;
+}
+
+static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
+{
+ return cnss_powerup(plat_priv);
+}
+
+static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
+{
+ cnss_shutdown(plat_priv);
+
+ return 0;
+}
+
+static void cnss_driver_event_work(struct work_struct *work)
+{
+ struct cnss_plat_data *plat_priv =
+ container_of(work, struct cnss_plat_data, event_work);
+ struct cnss_driver_event *event;
+ unsigned long flags;
+ int ret = 0;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return;
+ }
+
+ cnss_pm_stay_awake(plat_priv);
+
+ spin_lock_irqsave(&plat_priv->event_lock, flags);
+
+ while (!list_empty(&plat_priv->event_list)) {
+ event = list_first_entry(&plat_priv->event_list,
+ struct cnss_driver_event, list);
+ list_del(&event->list);
+ spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+ cnss_pr_dbg("Processing driver event: %s%s(%d), state: 0x%lx\n",
+ cnss_driver_event_to_str(event->type),
+ event->sync ? "-sync" : "", event->type,
+ plat_priv->driver_state);
+
+ switch (event->type) {
+ case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
+ ret = cnss_wlfw_server_arrive(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_SERVER_EXIT:
+ ret = cnss_wlfw_server_exit(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_REQUEST_MEM:
+ ret = cnss_pci_alloc_fw_mem(plat_priv->bus_priv);
+ if (ret)
+ break;
+ ret = cnss_wlfw_respond_mem_send_sync(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_FW_MEM_READY:
+ ret = cnss_fw_mem_ready_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_FW_READY:
+ ret = cnss_fw_ready_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
+ ret = cnss_cold_boot_cal_start_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
+ ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
+ ret = cnss_register_driver_hdlr(plat_priv,
+ event->data);
+ break;
+ case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
+ ret = cnss_unregister_driver_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_RECOVERY:
+ ret = cnss_driver_recovery_hdlr(plat_priv,
+ event->data);
+ break;
+ case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
+ ret = cnss_force_fw_assert_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_POWER_UP:
+ ret = cnss_power_up_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_POWER_DOWN:
+ ret = cnss_power_down_hdlr(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Invalid driver event type: %d",
+ event->type);
+ kfree(event);
+ spin_lock_irqsave(&plat_priv->event_lock, flags);
+ continue;
+ }
+
+ spin_lock_irqsave(&plat_priv->event_lock, flags);
+ if (event->sync) {
+ event->ret = ret;
+ complete(&event->complete);
+ continue;
+ }
+ spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+ kfree(event);
+
+ spin_lock_irqsave(&plat_priv->event_lock, flags);
+ }
+ spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+ cnss_pm_relax(plat_priv);
+}
+
+int cnss_register_subsys(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_subsys_info *subsys_info;
+
+ subsys_info = &plat_priv->subsys_info;
+
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ subsys_info->subsys_desc.name = "AR6320";
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ subsys_info->subsys_desc.name = "QCA6290";
+ break;
+ default:
+ cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ subsys_info->subsys_desc.owner = THIS_MODULE;
+ subsys_info->subsys_desc.powerup = cnss_subsys_powerup;
+ subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown;
+ subsys_info->subsys_desc.ramdump = cnss_subsys_ramdump;
+ subsys_info->subsys_desc.crash_shutdown = cnss_subsys_crash_shutdown;
+ subsys_info->subsys_desc.dev = &plat_priv->plat_dev->dev;
+
+ subsys_info->subsys_device = subsys_register(&subsys_info->subsys_desc);
+ if (IS_ERR(subsys_info->subsys_device)) {
+ ret = PTR_ERR(subsys_info->subsys_device);
+ cnss_pr_err("Failed to register subsys, err = %d\n", ret);
+ goto out;
+ }
+
+ subsys_info->subsys_handle =
+ subsystem_get(subsys_info->subsys_desc.name);
+ if (!subsys_info->subsys_handle) {
+ cnss_pr_err("Failed to get subsys_handle!\n");
+ ret = -EINVAL;
+ goto unregister_subsys;
+ } else if (IS_ERR(subsys_info->subsys_handle)) {
+ ret = PTR_ERR(subsys_info->subsys_handle);
+ cnss_pr_err("Failed to do subsystem_get, err = %d\n", ret);
+ goto unregister_subsys;
+ }
+
+ return 0;
+
+unregister_subsys:
+ subsys_unregister(subsys_info->subsys_device);
+out:
+ return ret;
+}
+
+void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_subsys_info *subsys_info;
+
+ subsys_info = &plat_priv->subsys_info;
+ subsystem_put(subsys_info->subsys_handle);
+ subsys_unregister(subsys_info->subsys_device);
+}
+
+static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_ramdump_info *ramdump_info;
+ struct msm_dump_entry dump_entry;
+
+ ramdump_info = &plat_priv->ramdump_info;
+ ramdump_info->dump_data.addr = ramdump_info->ramdump_pa;
+ ramdump_info->dump_data.len = ramdump_info->ramdump_size;
+ ramdump_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
+ ramdump_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+ strlcpy(ramdump_info->dump_data.name, CNSS_DUMP_NAME,
+ sizeof(ramdump_info->dump_data.name));
+ dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+ dump_entry.addr = virt_to_phys(&ramdump_info->dump_data);
+
+ return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+}
+
+static int cnss_qca6174_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct device *dev;
+ struct cnss_subsys_info *subsys_info;
+ struct cnss_ramdump_info *ramdump_info;
+ u32 ramdump_size = 0;
+
+ dev = &plat_priv->plat_dev->dev;
+ subsys_info = &plat_priv->subsys_info;
+ ramdump_info = &plat_priv->ramdump_info;
+
+ if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+ &ramdump_size) == 0) {
+ ramdump_info->ramdump_va = dma_alloc_coherent(dev, ramdump_size,
+ &ramdump_info->ramdump_pa, GFP_KERNEL);
+
+ if (ramdump_info->ramdump_va)
+ ramdump_info->ramdump_size = ramdump_size;
+ }
+
+ cnss_pr_dbg("ramdump va: %pK, pa: %pa\n",
+ ramdump_info->ramdump_va, &ramdump_info->ramdump_pa);
+
+ if (ramdump_info->ramdump_size == 0) {
+ cnss_pr_info("Ramdump will not be collected");
+ goto out;
+ }
+
+ ret = cnss_init_dump_entry(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
+ goto free_ramdump;
+ }
+
+ ramdump_info->ramdump_dev = create_ramdump_device(
+ subsys_info->subsys_desc.name, subsys_info->subsys_desc.dev);
+ if (!ramdump_info->ramdump_dev) {
+ cnss_pr_err("Failed to create ramdump device!");
+ ret = -ENOMEM;
+ goto free_ramdump;
+ }
+
+ return 0;
+free_ramdump:
+ dma_free_coherent(dev, ramdump_info->ramdump_size,
+ ramdump_info->ramdump_va, ramdump_info->ramdump_pa);
+out:
+ return ret;
+}
+
+static void cnss_qca6174_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+ struct device *dev;
+ struct cnss_ramdump_info *ramdump_info;
+
+ dev = &plat_priv->plat_dev->dev;
+ ramdump_info = &plat_priv->ramdump_info;
+
+ if (ramdump_info->ramdump_dev)
+ destroy_ramdump_device(ramdump_info->ramdump_dev);
+
+ if (ramdump_info->ramdump_va)
+ dma_free_coherent(dev, ramdump_info->ramdump_size,
+ ramdump_info->ramdump_va,
+ ramdump_info->ramdump_pa);
+}
+
+static int cnss_qca6290_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_subsys_info *subsys_info;
+ struct cnss_ramdump_info_v2 *info_v2;
+ struct cnss_dump_data *dump_data;
+ struct msm_dump_entry dump_entry;
+ struct device *dev = &plat_priv->plat_dev->dev;
+ u32 ramdump_size = 0;
+
+ subsys_info = &plat_priv->subsys_info;
+ info_v2 = &plat_priv->ramdump_info_v2;
+ dump_data = &info_v2->dump_data;
+
+ if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+ &ramdump_size) == 0)
+ info_v2->ramdump_size = ramdump_size;
+
+ cnss_pr_dbg("Ramdump size 0x%lx\n", info_v2->ramdump_size);
+
+ info_v2->dump_data_vaddr = kzalloc(CNSS_DUMP_DESC_SIZE, GFP_KERNEL);
+ if (!info_v2->dump_data_vaddr)
+ return -ENOMEM;
+
+ dump_data->paddr = virt_to_phys(info_v2->dump_data_vaddr);
+ dump_data->version = CNSS_DUMP_FORMAT_VER_V2;
+ dump_data->magic = CNSS_DUMP_MAGIC_VER_V2;
+ dump_data->seg_version = CNSS_DUMP_SEG_VER;
+ strlcpy(dump_data->name, CNSS_DUMP_NAME,
+ sizeof(dump_data->name));
+ dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+ dump_entry.addr = virt_to_phys(dump_data);
+
+ ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+ if (ret) {
+ cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
+ goto free_ramdump;
+ }
+
+ info_v2->ramdump_dev =
+ create_ramdump_device(subsys_info->subsys_desc.name,
+ subsys_info->subsys_desc.dev);
+ if (!info_v2->ramdump_dev) {
+ cnss_pr_err("Failed to create ramdump device!\n");
+ ret = -ENOMEM;
+ goto free_ramdump;
+ }
+
+ return 0;
+
+free_ramdump:
+ kfree(info_v2->dump_data_vaddr);
+ info_v2->dump_data_vaddr = NULL;
+ return ret;
+}
+
+static void cnss_qca6290_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_ramdump_info_v2 *info_v2;
+
+ info_v2 = &plat_priv->ramdump_info_v2;
+
+ if (info_v2->ramdump_dev)
+ destroy_ramdump_device(info_v2->ramdump_dev);
+
+ kfree(info_v2->dump_data_vaddr);
+ info_v2->dump_data_vaddr = NULL;
+ info_v2->dump_data_valid = false;
+}
+
+int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_register_ramdump(plat_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_register_ramdump(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+ ret = -ENODEV;
+ break;
+ }
+ return ret;
+}
+
+void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+ switch (plat_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ cnss_qca6174_unregister_ramdump(plat_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ cnss_qca6290_unregister_ramdump(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+ break;
+ }
+}
+
+static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_bus_bw_info *bus_bw_info;
+
+ bus_bw_info = &plat_priv->bus_bw_info;
+
+ bus_bw_info->bus_scale_table =
+ msm_bus_cl_get_pdata(plat_priv->plat_dev);
+ if (bus_bw_info->bus_scale_table) {
+ bus_bw_info->bus_client =
+ msm_bus_scale_register_client(
+ bus_bw_info->bus_scale_table);
+ if (!bus_bw_info->bus_client) {
+ cnss_pr_err("Failed to register bus scale client!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_bus_bw_info *bus_bw_info;
+
+ bus_bw_info = &plat_priv->bus_bw_info;
+
+ if (bus_bw_info->bus_client)
+ msm_bus_scale_unregister_client(bus_bw_info->bus_client);
+}
+
+static ssize_t cnss_fs_ready_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int fs_ready = 0;
+ struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%du", &fs_ready) != 1)
+ return -EINVAL;
+
+ cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n",
+ fs_ready, count);
+
+ if (qmi_bypass) {
+ cnss_pr_dbg("QMI is bypassed.\n");
+ return count;
+ }
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return count;
+ }
+
+ switch (plat_priv->device_id) {
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ break;
+ default:
+ cnss_pr_err("Not supported for device ID 0x%lx\n",
+ plat_priv->device_id);
+ return count;
+ }
+
+ if (fs_ready == FILE_SYSTEM_READY) {
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+ CNSS_EVENT_SYNC, NULL);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(fs_ready, 0220, NULL, cnss_fs_ready_store);
+
+static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
+ if (ret) {
+ cnss_pr_err("Failed to create device file, err = %d\n", ret);
+ goto out;
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv)
+{
+ device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
+}
+
+static int cnss_event_work_init(struct cnss_plat_data *plat_priv)
+{
+ spin_lock_init(&plat_priv->event_lock);
+ plat_priv->event_wq = alloc_workqueue("cnss_driver_event",
+ WQ_UNBOUND, 1);
+ if (!plat_priv->event_wq) {
+ cnss_pr_err("Failed to create event workqueue!\n");
+ return -EFAULT;
+ }
+
+ INIT_WORK(&plat_priv->event_work, cnss_driver_event_work);
+ INIT_LIST_HEAD(&plat_priv->event_list);
+
+ return 0;
+}
+
+static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv)
+{
+ destroy_workqueue(plat_priv->event_wq);
+}
+
+static const struct platform_device_id cnss_platform_id_table[] = {
+ { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
+ { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
+};
+
+static const struct of_device_id cnss_of_match_table[] = {
+ {
+ .compatible = "qcom,cnss",
+ .data = (void *)&cnss_platform_id_table[0]},
+ {
+ .compatible = "qcom,cnss-qca6290",
+ .data = (void *)&cnss_platform_id_table[1]},
+ { },
+};
+MODULE_DEVICE_TABLE(of, cnss_of_match_table);
+
+static int cnss_probe(struct platform_device *plat_dev)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv;
+ const struct of_device_id *of_id;
+ const struct platform_device_id *device_id;
+
+ if (cnss_get_plat_priv(plat_dev)) {
+ cnss_pr_err("Driver is already initialized!\n");
+ ret = -EEXIST;
+ goto out;
+ }
+
+ of_id = of_match_device(cnss_of_match_table, &plat_dev->dev);
+ if (!of_id || !of_id->data) {
+ cnss_pr_err("Failed to find of match device!\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ device_id = of_id->data;
+
+ plat_priv = devm_kzalloc(&plat_dev->dev, sizeof(*plat_priv),
+ GFP_KERNEL);
+ if (!plat_priv) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ plat_priv->plat_dev = plat_dev;
+ plat_priv->device_id = device_id->driver_data;
+ cnss_set_plat_priv(plat_dev, plat_priv);
+ platform_set_drvdata(plat_dev, plat_priv);
+
+ ret = cnss_get_resources(plat_priv);
+ if (ret)
+ goto reset_ctx;
+
+ if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) {
+ ret = cnss_power_on_device(plat_priv);
+ if (ret)
+ goto free_res;
+
+ ret = cnss_pci_init(plat_priv);
+ if (ret)
+ goto power_off;
+ }
+
+ ret = cnss_register_esoc(plat_priv);
+ if (ret)
+ goto deinit_pci;
+
+ ret = cnss_register_bus_scale(plat_priv);
+ if (ret)
+ goto unreg_esoc;
+
+ ret = cnss_create_sysfs(plat_priv);
+ if (ret)
+ goto unreg_bus_scale;
+
+ ret = cnss_event_work_init(plat_priv);
+ if (ret)
+ goto remove_sysfs;
+
+ ret = cnss_qmi_init(plat_priv);
+ if (ret)
+ goto deinit_event_work;
+
+ ret = cnss_debugfs_create(plat_priv);
+ if (ret)
+ goto deinit_qmi;
+
+ setup_timer(&plat_priv->fw_boot_timer,
+ fw_boot_timeout, (unsigned long)plat_priv);
+
+ register_pm_notifier(&cnss_pm_notifier);
+
+ ret = device_init_wakeup(&plat_dev->dev, true);
+ if (ret)
+ cnss_pr_err("Failed to init platform device wakeup source, err = %d\n",
+ ret);
+
+ init_completion(&plat_priv->power_up_complete);
+ mutex_init(&plat_priv->dev_lock);
+
+ cnss_pr_info("Platform driver probed successfully.\n");
+
+ return 0;
+
+deinit_qmi:
+ cnss_qmi_deinit(plat_priv);
+deinit_event_work:
+ cnss_event_work_deinit(plat_priv);
+remove_sysfs:
+ cnss_remove_sysfs(plat_priv);
+unreg_bus_scale:
+ cnss_unregister_bus_scale(plat_priv);
+unreg_esoc:
+ cnss_unregister_esoc(plat_priv);
+deinit_pci:
+ if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
+ cnss_pci_deinit(plat_priv);
+power_off:
+ if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
+ cnss_power_off_device(plat_priv);
+free_res:
+ cnss_put_resources(plat_priv);
+reset_ctx:
+ platform_set_drvdata(plat_dev, NULL);
+ cnss_set_plat_priv(plat_dev, NULL);
+out:
+ return ret;
+}
+
+static int cnss_remove(struct platform_device *plat_dev)
+{
+ struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
+
+ complete_all(&plat_priv->power_up_complete);
+ device_init_wakeup(&plat_dev->dev, false);
+ unregister_pm_notifier(&cnss_pm_notifier);
+ del_timer(&plat_priv->fw_boot_timer);
+ cnss_debugfs_destroy(plat_priv);
+ cnss_qmi_deinit(plat_priv);
+ cnss_event_work_deinit(plat_priv);
+ cnss_remove_sysfs(plat_priv);
+ cnss_unregister_bus_scale(plat_priv);
+ cnss_unregister_esoc(plat_priv);
+ cnss_pci_deinit(plat_priv);
+ cnss_put_resources(plat_priv);
+ platform_set_drvdata(plat_dev, NULL);
+ plat_env = NULL;
+
+ return 0;
+}
+
+static struct platform_driver cnss_platform_driver = {
+ .probe = cnss_probe,
+ .remove = cnss_remove,
+ .driver = {
+ .name = "cnss2",
+ .owner = THIS_MODULE,
+ .of_match_table = cnss_of_match_table,
+#ifdef CONFIG_CNSS_ASYNC
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+ },
+};
+
+static int __init cnss_initialize(void)
+{
+ int ret = 0;
+
+ cnss_debug_init();
+ ret = platform_driver_register(&cnss_platform_driver);
+ if (ret)
+ cnss_debug_deinit();
+
+ return ret;
+}
+
+static void __exit cnss_exit(void)
+{
+ platform_driver_unregister(&cnss_platform_driver);
+ cnss_debug_deinit();
+}
+
+module_init(cnss_initialize);
+module_exit(cnss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS2 Platform Driver");
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
new file mode 100644
index 0000000..81b5de8
--- /dev/null
+++ b/drivers/net/wireless/cnss2/main.h
@@ -0,0 +1,225 @@
+/* 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
+ * 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 _CNSS_MAIN_H
+#define _CNSS_MAIN_H
+
+#include <linux/esoc_client.h>
+#include <linux/etherdevice.h>
+#include <linux/msm-bus.h>
+#include <linux/pm_qos.h>
+#include <net/cnss2.h>
+#include <soc/qcom/memory_dump.h>
+#include <soc/qcom/subsystem_restart.h>
+
+#include "qmi.h"
+
+#define MAX_NO_OF_MAC_ADDR 4
+
+#define CNSS_EVENT_SYNC BIT(0)
+#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
+#define CNSS_EVENT_SYNC_UNINTERRUPTIBLE (CNSS_EVENT_SYNC | \
+ CNSS_EVENT_UNINTERRUPTIBLE)
+
+enum cnss_dev_bus_type {
+ CNSS_BUS_NONE = -1,
+ CNSS_BUS_PCI,
+};
+
+struct cnss_vreg_info {
+ struct regulator *reg;
+ const char *name;
+ u32 min_uv;
+ u32 max_uv;
+ u32 load_ua;
+ u32 delay_us;
+};
+
+struct cnss_pinctrl_info {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *bootstrap_active;
+ struct pinctrl_state *wlan_en_active;
+ struct pinctrl_state *wlan_en_sleep;
+};
+
+struct cnss_subsys_info {
+ struct subsys_device *subsys_device;
+ struct subsys_desc subsys_desc;
+ void *subsys_handle;
+};
+
+struct cnss_ramdump_info {
+ struct ramdump_device *ramdump_dev;
+ unsigned long ramdump_size;
+ void *ramdump_va;
+ phys_addr_t ramdump_pa;
+ struct msm_dump_data dump_data;
+};
+
+struct cnss_dump_seg {
+ unsigned long address;
+ void *v_address;
+ unsigned long size;
+ u32 type;
+};
+
+struct cnss_dump_data {
+ u32 version;
+ u32 magic;
+ char name[32];
+ phys_addr_t paddr;
+ int nentries;
+ u32 seg_version;
+};
+
+struct cnss_ramdump_info_v2 {
+ struct ramdump_device *ramdump_dev;
+ unsigned long ramdump_size;
+ void *dump_data_vaddr;
+ bool dump_data_valid;
+ struct cnss_dump_data dump_data;
+};
+
+struct cnss_esoc_info {
+ struct esoc_desc *esoc_desc;
+ bool notify_modem_status;
+ void *modem_notify_handler;
+ int modem_current_status;
+};
+
+struct cnss_bus_bw_info {
+ struct msm_bus_scale_pdata *bus_scale_table;
+ u32 bus_client;
+ int current_bw_vote;
+};
+
+struct cnss_fw_mem {
+ size_t size;
+ void *va;
+ phys_addr_t pa;
+ bool valid;
+};
+
+enum cnss_driver_event_type {
+ CNSS_DRIVER_EVENT_SERVER_ARRIVE,
+ CNSS_DRIVER_EVENT_SERVER_EXIT,
+ CNSS_DRIVER_EVENT_REQUEST_MEM,
+ CNSS_DRIVER_EVENT_FW_MEM_READY,
+ CNSS_DRIVER_EVENT_FW_READY,
+ CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+ CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+ CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+ CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+ CNSS_DRIVER_EVENT_RECOVERY,
+ CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
+ CNSS_DRIVER_EVENT_POWER_UP,
+ CNSS_DRIVER_EVENT_POWER_DOWN,
+ CNSS_DRIVER_EVENT_MAX,
+};
+
+enum cnss_driver_state {
+ CNSS_QMI_WLFW_CONNECTED,
+ CNSS_FW_MEM_READY,
+ CNSS_FW_READY,
+ CNSS_COLD_BOOT_CAL,
+ CNSS_DRIVER_LOADING,
+ CNSS_DRIVER_UNLOADING,
+ CNSS_DRIVER_PROBED,
+ CNSS_DRIVER_RECOVERY,
+ CNSS_FW_BOOT_RECOVERY,
+ CNSS_DEV_ERR_NOTIFY,
+ CNSS_DRIVER_DEBUG,
+};
+
+struct cnss_recovery_data {
+ enum cnss_recovery_reason reason;
+};
+
+enum cnss_pins {
+ CNSS_WLAN_EN,
+ CNSS_PCIE_TXP,
+ CNSS_PCIE_TXN,
+ CNSS_PCIE_RXP,
+ CNSS_PCIE_RXN,
+ CNSS_PCIE_REFCLKP,
+ CNSS_PCIE_REFCLKN,
+ CNSS_PCIE_RST,
+ CNSS_PCIE_WAKE,
+};
+
+struct cnss_pin_connect_result {
+ u32 fw_pwr_pin_result;
+ u32 fw_phy_io_pin_result;
+ u32 fw_rf_pin_result;
+ u32 host_pin_result;
+};
+
+struct cnss_plat_data {
+ struct platform_device *plat_dev;
+ void *bus_priv;
+ struct cnss_vreg_info *vreg_info;
+ struct cnss_pinctrl_info pinctrl_info;
+ struct cnss_subsys_info subsys_info;
+ struct cnss_ramdump_info ramdump_info;
+ struct cnss_ramdump_info_v2 ramdump_info_v2;
+ struct cnss_esoc_info esoc_info;
+ struct cnss_bus_bw_info bus_bw_info;
+ struct notifier_block modem_nb;
+ struct cnss_platform_cap cap;
+ struct pm_qos_request qos_request;
+ unsigned long device_id;
+ struct cnss_wlan_driver *driver_ops;
+ enum cnss_driver_status driver_status;
+ u32 recovery_count;
+ unsigned long driver_state;
+ struct list_head event_list;
+ spinlock_t event_lock; /* spinlock for driver work event handling */
+ struct work_struct event_work;
+ struct workqueue_struct *event_wq;
+ struct qmi_handle *qmi_wlfw_clnt;
+ struct work_struct qmi_recv_msg_work;
+ struct notifier_block qmi_wlfw_clnt_nb;
+ struct wlfw_rf_chip_info_s_v01 chip_info;
+ struct wlfw_rf_board_info_s_v01 board_info;
+ struct wlfw_soc_info_s_v01 soc_info;
+ struct wlfw_fw_version_info_s_v01 fw_version_info;
+ struct cnss_fw_mem fw_mem;
+ struct cnss_fw_mem m3_mem;
+ struct cnss_pin_connect_result pin_result;
+ struct dentry *root_dentry;
+ atomic_t pm_count;
+ struct timer_list fw_boot_timer;
+ struct completion power_up_complete;
+ struct mutex dev_lock; /* mutex for register access through debugfs */
+ u32 diag_reg_read_addr;
+ u32 diag_reg_read_mem_type;
+ u32 diag_reg_read_len;
+ u8 *diag_reg_read_buf;
+};
+
+void *cnss_bus_dev_to_bus_priv(struct device *dev);
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
+int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
+ enum cnss_driver_event_type type,
+ u32 flags, void *data);
+int cnss_get_vreg(struct cnss_plat_data *plat_priv);
+int cnss_get_pinctrl(struct cnss_plat_data *plat_priv);
+int cnss_power_on_device(struct cnss_plat_data *plat_priv);
+void cnss_power_off_device(struct cnss_plat_data *plat_priv);
+int cnss_register_subsys(struct cnss_plat_data *plat_priv);
+void cnss_unregister_subsys(struct cnss_plat_data *plat_priv);
+int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
+void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
+void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
+u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv);
+
+#endif /* _CNSS_MAIN_H */
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
new file mode 100644
index 0000000..3c5bc72
--- /dev/null
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -0,0 +1,1615 @@
+/* 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
+ * 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/firmware.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+
+#include "main.h"
+#include "debug.h"
+#include "pci.h"
+
+#define PCI_LINK_UP 1
+#define PCI_LINK_DOWN 0
+
+#define SAVE_PCI_CONFIG_SPACE 1
+#define RESTORE_PCI_CONFIG_SPACE 0
+
+#define PM_OPTIONS_DEFAULT 0
+#define PM_OPTIONS_LINK_DOWN \
+ (MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN)
+
+#define PCI_BAR_NUM 0
+
+#ifdef CONFIG_ARM_LPAE
+#define PCI_DMA_MASK 64
+#else
+#define PCI_DMA_MASK 32
+#endif
+
+#define MHI_NODE_NAME "qcom,mhi"
+
+#define MAX_M3_FILE_NAME_LENGTH 13
+#define DEFAULT_M3_FILE_NAME "m3.bin"
+
+static DEFINE_SPINLOCK(pci_link_down_lock);
+
+static unsigned int pci_link_down_panic;
+module_param(pci_link_down_panic, uint, 0600);
+MODULE_PARM_DESC(pci_link_down_panic,
+ "Trigger kernel panic when PCI link down is detected");
+
+static bool fbc_bypass;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(fbc_bypass, bool, 0600);
+MODULE_PARM_DESC(fbc_bypass,
+ "Bypass firmware download when loading WLAN driver");
+#endif
+
+static int cnss_set_pci_config_space(struct cnss_pci_data *pci_priv, bool save)
+{
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ bool link_down_or_recovery;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ link_down_or_recovery = pci_priv->pci_link_down_ind ||
+ (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state));
+
+ if (save) {
+ if (link_down_or_recovery) {
+ pci_priv->saved_state = NULL;
+ } else {
+ pci_save_state(pci_dev);
+ pci_priv->saved_state = pci_store_saved_state(pci_dev);
+ }
+ } else {
+ if (link_down_or_recovery) {
+ pci_load_saved_state(pci_dev, pci_priv->default_state);
+ pci_restore_state(pci_dev);
+ } else if (pci_priv->saved_state) {
+ pci_load_and_free_saved_state(pci_dev,
+ &pci_priv->saved_state);
+ pci_restore_state(pci_dev);
+ }
+ }
+
+ return 0;
+}
+
+static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+ ret = msm_pcie_pm_control(link_up ? MSM_PCIE_RESUME :
+ MSM_PCIE_SUSPEND,
+ pci_dev->bus->number,
+ pci_dev, NULL,
+ PM_OPTIONS_DEFAULT);
+ if (ret) {
+ cnss_pr_err("Failed to %s PCI link with default option, err = %d\n",
+ link_up ? "resume" : "suspend", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ cnss_pr_dbg("Suspending PCI link\n");
+ if (!pci_priv->pci_link_state) {
+ cnss_pr_info("PCI link is already suspended!\n");
+ goto out;
+ }
+
+ ret = cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
+ if (ret)
+ goto out;
+
+ pci_disable_device(pci_priv->pci_dev);
+
+ if (pci_priv->pci_dev->device != QCA6174_DEVICE_ID) {
+ if (pci_set_power_state(pci_priv->pci_dev, PCI_D3hot))
+ cnss_pr_err("Failed to set D3Hot, err = %d\n", ret);
+ }
+
+ ret = cnss_set_pci_link(pci_priv, PCI_LINK_DOWN);
+ if (ret)
+ goto out;
+
+ pci_priv->pci_link_state = PCI_LINK_DOWN;
+
+ return 0;
+out:
+ return ret;
+}
+
+int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ cnss_pr_dbg("Resuming PCI link\n");
+ if (pci_priv->pci_link_state) {
+ cnss_pr_info("PCI link is already resumed!\n");
+ goto out;
+ }
+
+ ret = cnss_set_pci_link(pci_priv, PCI_LINK_UP);
+ if (ret)
+ goto out;
+
+ pci_priv->pci_link_state = PCI_LINK_UP;
+
+ ret = cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
+ if (ret)
+ goto out;
+
+ ret = pci_enable_device(pci_priv->pci_dev);
+ if (ret) {
+ cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
+ goto out;
+ }
+
+ pci_set_master(pci_priv->pci_dev);
+
+ if (pci_priv->pci_link_down_ind)
+ pci_priv->pci_link_down_ind = false;
+
+ return 0;
+out:
+ return ret;
+}
+
+int cnss_pci_link_down(struct device *dev)
+{
+ unsigned long flags;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL!\n");
+ return -EINVAL;
+ }
+
+ if (pci_link_down_panic)
+ panic("cnss: PCI link is down!\n");
+
+ spin_lock_irqsave(&pci_link_down_lock, flags);
+ if (pci_priv->pci_link_down_ind) {
+ cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n");
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+ return -EINVAL;
+ }
+ pci_priv->pci_link_down_ind = true;
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+ cnss_pr_err("PCI link down is detected by host driver, schedule recovery!\n");
+
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_NOTIFY_LINK_ERROR);
+ cnss_schedule_recovery(dev, CNSS_REASON_LINK_DOWN);
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_pci_link_down);
+
+static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct device *dev;
+ struct dma_iommu_mapping *mapping;
+ int atomic_ctx = 1;
+ int s1_bypass = 1;
+
+ dev = &pci_priv->pci_dev->dev;
+
+ mapping = arm_iommu_create_mapping(&platform_bus_type,
+ pci_priv->smmu_iova_start,
+ pci_priv->smmu_iova_len);
+ if (IS_ERR(mapping)) {
+ ret = PTR_ERR(mapping);
+ cnss_pr_err("Failed to create SMMU mapping, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_ATOMIC,
+ &atomic_ctx);
+ if (ret) {
+ pr_err("Failed to set SMMU atomic_ctx attribute, err = %d\n",
+ ret);
+ goto release_mapping;
+ }
+
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ if (ret) {
+ pr_err("Failed to set SMMU s1_bypass attribute, err = %d\n",
+ ret);
+ goto release_mapping;
+ }
+
+ ret = arm_iommu_attach_device(dev, mapping);
+ if (ret) {
+ pr_err("Failed to attach SMMU device, err = %d\n", ret);
+ goto release_mapping;
+ }
+
+ pci_priv->smmu_mapping = mapping;
+
+ return ret;
+release_mapping:
+ arm_iommu_release_mapping(mapping);
+out:
+ return ret;
+}
+
+static void cnss_pci_deinit_smmu(struct cnss_pci_data *pci_priv)
+{
+ arm_iommu_detach_device(&pci_priv->pci_dev->dev);
+ arm_iommu_release_mapping(pci_priv->smmu_mapping);
+
+ pci_priv->smmu_mapping = NULL;
+}
+
+static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
+{
+ unsigned long flags;
+ struct pci_dev *pci_dev;
+ struct cnss_pci_data *pci_priv;
+
+ if (!notify)
+ return;
+
+ pci_dev = notify->user;
+ if (!pci_dev)
+ return;
+
+ pci_priv = cnss_get_pci_priv(pci_dev);
+ if (!pci_priv)
+ return;
+
+ switch (notify->event) {
+ case MSM_PCIE_EVENT_LINKDOWN:
+ if (pci_link_down_panic)
+ panic("cnss: PCI link is down!\n");
+
+ spin_lock_irqsave(&pci_link_down_lock, flags);
+ if (pci_priv->pci_link_down_ind) {
+ cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n");
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+ return;
+ }
+ pci_priv->pci_link_down_ind = true;
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+ cnss_pr_err("PCI link down, schedule recovery!\n");
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_NOTIFY_LINK_ERROR);
+ if (pci_dev->device == QCA6174_DEVICE_ID)
+ disable_irq(pci_dev->irq);
+ cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN);
+ break;
+ case MSM_PCIE_EVENT_WAKEUP:
+ if (cnss_pci_get_monitor_wake_intr(pci_priv) &&
+ cnss_pci_get_auto_suspended(pci_priv)) {
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ pm_request_resume(&pci_dev->dev);
+ }
+ break;
+ default:
+ cnss_pr_err("Received invalid PCI event: %d\n", notify->event);
+ }
+}
+
+static int cnss_reg_pci_event(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct msm_pcie_register_event *pci_event;
+
+ pci_event = &pci_priv->msm_pci_event;
+ pci_event->events = MSM_PCIE_EVENT_LINKDOWN |
+ MSM_PCIE_EVENT_WAKEUP;
+ pci_event->user = pci_priv->pci_dev;
+ pci_event->mode = MSM_PCIE_TRIGGER_CALLBACK;
+ pci_event->callback = cnss_pci_event_cb;
+ pci_event->options = MSM_PCIE_CONFIG_NO_RECOVERY;
+
+ ret = msm_pcie_register_event(pci_event);
+ if (ret)
+ cnss_pr_err("Failed to register MSM PCI event, err = %d\n",
+ ret);
+
+ return ret;
+}
+
+static void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv)
+{
+ msm_pcie_deregister_event(&pci_priv->msm_pci_event);
+}
+
+static int cnss_pci_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_plat_data *plat_priv;
+ struct cnss_wlan_driver *driver_ops;
+
+ pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+ if (!pci_priv)
+ goto out;
+
+ plat_priv = pci_priv->plat_priv;
+ if (!plat_priv)
+ goto out;
+
+ driver_ops = plat_priv->driver_ops;
+ if (driver_ops && driver_ops->suspend) {
+ ret = driver_ops->suspend(pci_dev, state);
+ if (ret) {
+ cnss_pr_err("Failed to suspend host driver, err = %d\n",
+ ret);
+ ret = -EAGAIN;
+ goto out;
+ }
+ }
+
+ if (pci_priv->pci_link_state) {
+ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND);
+ if (ret) {
+ if (driver_ops && driver_ops->resume)
+ driver_ops->resume(pci_dev);
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ cnss_set_pci_config_space(pci_priv,
+ SAVE_PCI_CONFIG_SPACE);
+ pci_disable_device(pci_dev);
+
+ ret = pci_set_power_state(pci_dev, PCI_D3hot);
+ if (ret)
+ cnss_pr_err("Failed to set D3Hot, err = %d\n",
+ ret);
+ }
+
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int cnss_pci_resume(struct device *dev)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_plat_data *plat_priv;
+ struct cnss_wlan_driver *driver_ops;
+
+ if (!pci_priv)
+ goto out;
+
+ plat_priv = pci_priv->plat_priv;
+ if (!plat_priv)
+ goto out;
+
+ if (pci_priv->pci_link_down_ind)
+ goto out;
+
+ ret = pci_enable_device(pci_dev);
+ if (ret)
+ cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
+
+ if (pci_priv->saved_state)
+ cnss_set_pci_config_space(pci_priv,
+ RESTORE_PCI_CONFIG_SPACE);
+
+ pci_set_master(pci_dev);
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+
+ driver_ops = plat_priv->driver_ops;
+ if (driver_ops && driver_ops->resume) {
+ ret = driver_ops->resume(pci_dev);
+ if (ret)
+ cnss_pr_err("Failed to resume host driver, err = %d\n",
+ ret);
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int cnss_pci_suspend_noirq(struct device *dev)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_plat_data *plat_priv;
+ struct cnss_wlan_driver *driver_ops;
+
+ if (!pci_priv)
+ goto out;
+
+ plat_priv = pci_priv->plat_priv;
+ if (!plat_priv)
+ goto out;
+
+ driver_ops = plat_priv->driver_ops;
+ if (driver_ops && driver_ops->suspend_noirq)
+ ret = driver_ops->suspend_noirq(pci_dev);
+
+out:
+ return ret;
+}
+
+static int cnss_pci_resume_noirq(struct device *dev)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_plat_data *plat_priv;
+ struct cnss_wlan_driver *driver_ops;
+
+ if (!pci_priv)
+ goto out;
+
+ plat_priv = pci_priv->plat_priv;
+ if (!plat_priv)
+ goto out;
+
+ driver_ops = plat_priv->driver_ops;
+ if (driver_ops && driver_ops->resume_noirq &&
+ !pci_priv->pci_link_down_ind)
+ ret = driver_ops->resume_noirq(pci_dev);
+
+out:
+ return ret;
+}
+
+static int cnss_pci_runtime_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_plat_data *plat_priv;
+ struct cnss_wlan_driver *driver_ops;
+
+ if (!pci_priv)
+ return -EAGAIN;
+
+ plat_priv = pci_priv->plat_priv;
+ if (!plat_priv)
+ return -EAGAIN;
+
+ if (pci_priv->pci_link_down_ind) {
+ cnss_pr_dbg("PCI link down recovery is in progress!\n");
+ return -EAGAIN;
+ }
+
+ cnss_pr_dbg("Runtime suspend start\n");
+
+ driver_ops = plat_priv->driver_ops;
+ if (driver_ops && driver_ops->runtime_ops &&
+ driver_ops->runtime_ops->runtime_suspend)
+ ret = driver_ops->runtime_ops->runtime_suspend(pci_dev);
+
+ cnss_pr_info("Runtime suspend status: %d\n", ret);
+
+ return ret;
+}
+
+static int cnss_pci_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_plat_data *plat_priv;
+ struct cnss_wlan_driver *driver_ops;
+
+ if (!pci_priv)
+ return -EAGAIN;
+
+ plat_priv = pci_priv->plat_priv;
+ if (!plat_priv)
+ return -EAGAIN;
+
+ if (pci_priv->pci_link_down_ind) {
+ cnss_pr_dbg("PCI link down recovery is in progress!\n");
+ return -EAGAIN;
+ }
+
+ cnss_pr_dbg("Runtime resume start\n");
+
+ driver_ops = plat_priv->driver_ops;
+ if (driver_ops && driver_ops->runtime_ops &&
+ driver_ops->runtime_ops->runtime_resume)
+ ret = driver_ops->runtime_ops->runtime_resume(pci_dev);
+
+ cnss_pr_info("Runtime resume status: %d\n", ret);
+
+ return ret;
+}
+
+static int cnss_pci_runtime_idle(struct device *dev)
+{
+ cnss_pr_dbg("Runtime idle\n");
+
+ pm_request_autosuspend(dev);
+
+ return -EBUSY;
+}
+
+int cnss_wlan_pm_control(struct device *dev, bool vote)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_pci_data *pci_priv;
+ struct pci_dev *pci_dev;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ pci_priv = plat_priv->bus_priv;
+ if (!pci_priv)
+ return -ENODEV;
+
+ pci_dev = pci_priv->pci_dev;
+
+ return msm_pcie_pm_control(vote ? MSM_PCIE_DISABLE_PC :
+ MSM_PCIE_ENABLE_PC,
+ pci_dev->bus->number, pci_dev,
+ NULL, PM_OPTIONS_DEFAULT);
+}
+EXPORT_SYMBOL(cnss_wlan_pm_control);
+
+int cnss_auto_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct pci_dev *pci_dev;
+ struct cnss_pci_data *pci_priv;
+ struct cnss_bus_bw_info *bus_bw_info;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ pci_priv = plat_priv->bus_priv;
+ if (!pci_priv)
+ return -ENODEV;
+
+ pci_dev = pci_priv->pci_dev;
+
+ if (pci_priv->pci_link_state) {
+ if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
+ pci_disable_device(pci_dev);
+
+ ret = pci_set_power_state(pci_dev, PCI_D3hot);
+ if (ret)
+ cnss_pr_err("Failed to set D3Hot, err = %d\n", ret);
+
+ cnss_pr_dbg("Suspending PCI link\n");
+ if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
+ cnss_pr_err("Failed to suspend PCI link!\n");
+ ret = -EAGAIN;
+ goto resume_mhi;
+ }
+
+ pci_priv->pci_link_state = PCI_LINK_DOWN;
+ }
+
+ cnss_pci_set_auto_suspended(pci_priv, 1);
+ cnss_pci_set_monitor_wake_intr(pci_priv, true);
+
+ bus_bw_info = &plat_priv->bus_bw_info;
+ msm_bus_scale_client_update_request(bus_bw_info->bus_client,
+ CNSS_BUS_WIDTH_NONE);
+
+ return 0;
+
+resume_mhi:
+ if (pci_enable_device(pci_dev))
+ cnss_pr_err("Failed to enable PCI device!\n");
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_auto_suspend);
+
+int cnss_auto_resume(struct device *dev)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct pci_dev *pci_dev;
+ struct cnss_pci_data *pci_priv;
+ struct cnss_bus_bw_info *bus_bw_info;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ pci_priv = plat_priv->bus_priv;
+ if (!pci_priv)
+ return -ENODEV;
+
+ pci_dev = pci_priv->pci_dev;
+ if (!pci_priv->pci_link_state) {
+ cnss_pr_dbg("Resuming PCI link\n");
+ if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) {
+ cnss_pr_err("Failed to resume PCI link!\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+ pci_priv->pci_link_state = PCI_LINK_UP;
+
+ ret = pci_enable_device(pci_dev);
+ if (ret)
+ cnss_pr_err("Failed to enable PCI device, err = %d\n",
+ ret);
+
+ cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
+ pci_set_master(pci_dev);
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+ }
+
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
+ bus_bw_info = &plat_priv->bus_bw_info;
+ msm_bus_scale_client_update_request(bus_bw_info->bus_client,
+ bus_bw_info->current_bw_vote);
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_auto_resume);
+
+int cnss_pm_request_resume(struct cnss_pci_data *pci_priv)
+{
+ struct pci_dev *pci_dev;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ pci_dev = pci_priv->pci_dev;
+ if (!pci_dev)
+ return -ENODEV;
+
+ return pm_request_resume(&pci_dev->dev);
+}
+
+int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+
+ if (!fw_mem->va && fw_mem->size) {
+ fw_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+ fw_mem->size, &fw_mem->pa,
+ GFP_KERNEL);
+ if (!fw_mem->va) {
+ cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx\n",
+ fw_mem->size);
+ fw_mem->size = 0;
+
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+
+ if (fw_mem->va && fw_mem->size) {
+ cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+ fw_mem->va, &fw_mem->pa, fw_mem->size);
+ dma_free_coherent(&pci_priv->pci_dev->dev, fw_mem->size,
+ fw_mem->va, fw_mem->pa);
+ fw_mem->va = NULL;
+ fw_mem->pa = 0;
+ fw_mem->size = 0;
+ }
+}
+
+int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+ char filename[MAX_M3_FILE_NAME_LENGTH];
+ const struct firmware *fw_entry;
+ int ret = 0;
+
+ if (!m3_mem->va && !m3_mem->size) {
+ snprintf(filename, sizeof(filename), DEFAULT_M3_FILE_NAME);
+
+ ret = request_firmware(&fw_entry, filename,
+ &pci_priv->pci_dev->dev);
+ if (ret) {
+ cnss_pr_err("Failed to load M3 image: %s\n", filename);
+ return ret;
+ }
+
+ m3_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+ fw_entry->size, &m3_mem->pa,
+ GFP_KERNEL);
+ if (!m3_mem->va) {
+ cnss_pr_err("Failed to allocate memory for M3, size: 0x%zx\n",
+ fw_entry->size);
+ release_firmware(fw_entry);
+ return -ENOMEM;
+ }
+
+ memcpy(m3_mem->va, fw_entry->data, fw_entry->size);
+ m3_mem->size = fw_entry->size;
+ release_firmware(fw_entry);
+ }
+
+ return 0;
+}
+
+static void cnss_pci_free_m3_mem(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+
+ if (m3_mem->va && m3_mem->size) {
+ cnss_pr_dbg("Freeing memory for M3, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+ m3_mem->va, &m3_mem->pa, m3_mem->size);
+ dma_free_coherent(&pci_priv->pci_dev->dev, m3_mem->size,
+ m3_mem->va, m3_mem->pa);
+ }
+
+ m3_mem->va = NULL;
+ m3_mem->pa = 0;
+ m3_mem->size = 0;
+}
+
+int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va,
+ phys_addr_t *pa)
+{
+ if (!pci_priv)
+ return -ENODEV;
+
+ *va = pci_priv->bar;
+ *pa = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM);
+
+ return 0;
+}
+
+static struct cnss_msi_config msi_config = {
+ .total_vectors = 32,
+ .total_users = 4,
+ .users = (struct cnss_msi_user[]) {
+ { .name = "MHI", .num_vectors = 2, .base_vector = 0 },
+ { .name = "CE", .num_vectors = 11, .base_vector = 2 },
+ { .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
+ { .name = "DP", .num_vectors = 18, .base_vector = 14 },
+ },
+};
+
+static int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv)
+{
+ pci_priv->msi_config = &msi_config;
+
+ return 0;
+}
+
+static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ int num_vectors;
+ struct cnss_msi_config *msi_config;
+ struct msi_desc *msi_desc;
+
+ ret = cnss_pci_get_msi_assignment(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to get MSI assignment, err = %d\n", ret);
+ goto out;
+ }
+
+ msi_config = pci_priv->msi_config;
+ if (!msi_config) {
+ cnss_pr_err("msi_config is NULL!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ num_vectors = pci_enable_msi_range(pci_dev,
+ msi_config->total_vectors,
+ msi_config->total_vectors);
+ if (num_vectors != msi_config->total_vectors) {
+ cnss_pr_err("Failed to get enough MSI vectors (%d), available vectors = %d",
+ msi_config->total_vectors, num_vectors);
+ ret = -EINVAL;
+ goto reset_msi_config;
+ }
+
+ msi_desc = irq_get_msi_desc(pci_dev->irq);
+ if (!msi_desc) {
+ cnss_pr_err("msi_desc is NULL!\n");
+ ret = -EINVAL;
+ goto disable_msi;
+ }
+
+ pci_priv->msi_ep_base_data = msi_desc->msg.data;
+ if (!pci_priv->msi_ep_base_data) {
+ cnss_pr_err("Got 0 MSI base data!\n");
+ CNSS_ASSERT(0);
+ }
+
+ cnss_pr_dbg("MSI base data is %d\n", pci_priv->msi_ep_base_data);
+
+ return 0;
+
+disable_msi:
+ pci_disable_msi(pci_priv->pci_dev);
+reset_msi_config:
+ pci_priv->msi_config = NULL;
+out:
+ return ret;
+}
+
+static void cnss_pci_disable_msi(struct cnss_pci_data *pci_priv)
+{
+ pci_disable_msi(pci_priv->pci_dev);
+}
+
+int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
+ int *num_vectors, u32 *user_base_data,
+ u32 *base_vector)
+{
+ struct cnss_pci_data *pci_priv = dev_get_drvdata(dev);
+ struct cnss_msi_config *msi_config;
+ int idx;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ msi_config = pci_priv->msi_config;
+ if (!msi_config) {
+ cnss_pr_err("MSI is not supported.\n");
+ return -EINVAL;
+ }
+
+ for (idx = 0; idx < msi_config->total_users; idx++) {
+ if (strcmp(user_name, msi_config->users[idx].name) == 0) {
+ *num_vectors = msi_config->users[idx].num_vectors;
+ *user_base_data = msi_config->users[idx].base_vector
+ + pci_priv->msi_ep_base_data;
+ *base_vector = msi_config->users[idx].base_vector;
+
+ cnss_pr_dbg("Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
+ user_name, *num_vectors, *user_base_data,
+ *base_vector);
+
+ return 0;
+ }
+ }
+
+ cnss_pr_err("Failed to find MSI assignment for %s!\n", user_name);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_get_user_msi_assignment);
+
+int cnss_get_msi_irq(struct device *dev, unsigned int vector)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+
+ return pci_dev->irq + vector;
+}
+EXPORT_SYMBOL(cnss_get_msi_irq);
+
+void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
+ u32 *msi_addr_high)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+
+ pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
+ msi_addr_low);
+
+ pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
+ msi_addr_high);
+}
+EXPORT_SYMBOL(cnss_get_msi_address);
+
+static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ u16 device_id;
+
+ pci_read_config_word(pci_dev, PCI_DEVICE_ID, &device_id);
+ if (device_id != pci_priv->pci_device_id->device) {
+ cnss_pr_err("PCI device ID mismatch, config ID: 0x%x, probe ID: 0x%x\n",
+ device_id, pci_priv->pci_device_id->device);
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = pci_assign_resource(pci_dev, PCI_BAR_NUM);
+ if (ret) {
+ pr_err("Failed to assign PCI resource, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = pci_enable_device(pci_dev);
+ if (ret) {
+ cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = pci_request_region(pci_dev, PCI_BAR_NUM, "cnss");
+ if (ret) {
+ cnss_pr_err("Failed to request PCI region, err = %d\n", ret);
+ goto disable_device;
+ }
+
+ ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
+ if (ret) {
+ cnss_pr_err("Failed to set PCI DMA mask (%d), err = %d\n",
+ ret, PCI_DMA_MASK);
+ goto release_region;
+ }
+
+ ret = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
+ if (ret) {
+ cnss_pr_err("Failed to set PCI consistent DMA mask (%d), err = %d\n",
+ ret, PCI_DMA_MASK);
+ goto release_region;
+ }
+
+ pci_set_master(pci_dev);
+
+ pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0);
+ if (!pci_priv->bar) {
+ cnss_pr_err("Failed to do PCI IO map!\n");
+ ret = -EIO;
+ goto clear_master;
+ }
+ return 0;
+
+clear_master:
+ pci_clear_master(pci_dev);
+release_region:
+ pci_release_region(pci_dev, PCI_BAR_NUM);
+disable_device:
+ pci_disable_device(pci_dev);
+out:
+ return ret;
+}
+
+static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv)
+{
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+ if (pci_priv->bar) {
+ pci_iounmap(pci_dev, pci_priv->bar);
+ pci_priv->bar = NULL;
+ }
+
+ pci_clear_master(pci_dev);
+ pci_release_region(pci_dev, PCI_BAR_NUM);
+ pci_disable_device(pci_dev);
+}
+
+static int cnss_mhi_pm_runtime_get(struct pci_dev *pci_dev)
+{
+ return pm_runtime_get(&pci_dev->dev);
+}
+
+static void cnss_mhi_pm_runtime_put_noidle(struct pci_dev *pci_dev)
+{
+ pm_runtime_put_noidle(&pci_dev->dev);
+}
+
+static char *cnss_mhi_state_to_str(enum cnss_mhi_state mhi_state)
+{
+ switch (mhi_state) {
+ case CNSS_MHI_INIT:
+ return "INIT";
+ case CNSS_MHI_DEINIT:
+ return "DEINIT";
+ case CNSS_MHI_POWER_ON:
+ return "POWER_ON";
+ case CNSS_MHI_POWER_OFF:
+ return "POWER_OFF";
+ case CNSS_MHI_SUSPEND:
+ return "SUSPEND";
+ case CNSS_MHI_RESUME:
+ return "RESUME";
+ case CNSS_MHI_TRIGGER_RDDM:
+ return "TRIGGER_RDDM";
+ case CNSS_MHI_RDDM:
+ return "RDDM";
+ case CNSS_MHI_RDDM_KERNEL_PANIC:
+ return "RDDM_KERNEL_PANIC";
+ case CNSS_MHI_NOTIFY_LINK_ERROR:
+ return "NOTIFY_LINK_ERROR";
+ default:
+ return "UNKNOWN";
+ }
+};
+
+static void *cnss_pci_collect_dump_seg(struct cnss_pci_data *pci_priv,
+ enum mhi_rddm_segment type,
+ void *start_addr)
+{
+ int count;
+ struct scatterlist *sg_list, *s;
+ unsigned int i;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_dump_data *dump_data =
+ &plat_priv->ramdump_info_v2.dump_data;
+ struct cnss_dump_seg *dump_seg = start_addr;
+
+ count = mhi_xfer_rddm(&pci_priv->mhi_dev, type, &sg_list);
+ if (count <= 0 || !sg_list) {
+ cnss_pr_err("Invalid dump_seg for type %u, count %u, sg_list %pK\n",
+ type, count, sg_list);
+ return start_addr;
+ }
+
+ cnss_pr_dbg("Collect dump seg: type %u, nentries %d\n", type, count);
+
+ for_each_sg(sg_list, s, count, i) {
+ dump_seg->address = sg_dma_address(s);
+ dump_seg->v_address = sg_virt(s);
+ dump_seg->size = s->length;
+ dump_seg->type = type;
+ cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n",
+ i, dump_seg->address,
+ dump_seg->v_address, dump_seg->size);
+ dump_seg++;
+ }
+
+ dump_data->nentries += count;
+
+ return dump_seg;
+}
+
+void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_dump_data *dump_data =
+ &plat_priv->ramdump_info_v2.dump_data;
+ void *start_addr, *end_addr;
+
+ dump_data->nentries = 0;
+
+ start_addr = plat_priv->ramdump_info_v2.dump_data_vaddr;
+ end_addr = cnss_pci_collect_dump_seg(pci_priv,
+ MHI_RDDM_FW_SEGMENT, start_addr);
+
+ start_addr = end_addr;
+ end_addr = cnss_pci_collect_dump_seg(pci_priv,
+ MHI_RDDM_RD_SEGMENT, start_addr);
+
+ if (dump_data->nentries > 0)
+ plat_priv->ramdump_info_v2.dump_data_valid = true;
+}
+
+void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ plat_priv->ramdump_info_v2.dump_data.nentries = 0;
+ plat_priv->ramdump_info_v2.dump_data_valid = false;
+}
+
+static void cnss_mhi_notify_status(enum MHI_CB_REASON reason, void *priv)
+{
+ struct cnss_pci_data *pci_priv = priv;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ enum cnss_recovery_reason cnss_reason = CNSS_REASON_RDDM;
+
+ if (!pci_priv)
+ return;
+
+ cnss_pr_dbg("MHI status cb is called with reason %d\n", reason);
+
+ set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+ del_timer(&plat_priv->fw_boot_timer);
+
+ if (reason == MHI_CB_SYS_ERROR)
+ cnss_reason = CNSS_REASON_TIMEOUT;
+
+ cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+ cnss_reason);
+}
+
+static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ struct mhi_device *mhi_dev = &pci_priv->mhi_dev;
+
+ mhi_dev->dev = &pci_priv->plat_priv->plat_dev->dev;
+ mhi_dev->pci_dev = pci_dev;
+
+ mhi_dev->resources[0].start = (resource_size_t)pci_priv->bar;
+ mhi_dev->resources[0].end = (resource_size_t)pci_priv->bar +
+ pci_resource_len(pci_dev, PCI_BAR_NUM);
+ mhi_dev->resources[0].flags =
+ pci_resource_flags(pci_dev, PCI_BAR_NUM);
+ mhi_dev->resources[0].name = "BAR";
+ cnss_pr_dbg("BAR start is %pa, BAR end is %pa\n",
+ &mhi_dev->resources[0].start, &mhi_dev->resources[0].end);
+
+ if (!mhi_dev->resources[1].start) {
+ mhi_dev->resources[1].start = pci_dev->irq;
+ mhi_dev->resources[1].end = pci_dev->irq + 1;
+ mhi_dev->resources[1].flags = IORESOURCE_IRQ;
+ mhi_dev->resources[1].name = "IRQ";
+ }
+ cnss_pr_dbg("IRQ start is %pa, IRQ end is %pa\n",
+ &mhi_dev->resources[1].start, &mhi_dev->resources[1].end);
+
+ mhi_dev->pm_runtime_get = cnss_mhi_pm_runtime_get;
+ mhi_dev->pm_runtime_put_noidle = cnss_mhi_pm_runtime_put_noidle;
+
+ mhi_dev->support_rddm = true;
+ mhi_dev->rddm_size = pci_priv->plat_priv->ramdump_info_v2.ramdump_size;
+ mhi_dev->status_cb = cnss_mhi_notify_status;
+
+ ret = mhi_register_device(mhi_dev, MHI_NODE_NAME, pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to register as MHI device, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void cnss_pci_unregister_mhi(struct cnss_pci_data *pci_priv)
+{
+}
+
+static enum mhi_dev_ctrl cnss_to_mhi_dev_state(enum cnss_mhi_state state)
+{
+ switch (state) {
+ case CNSS_MHI_INIT:
+ return MHI_DEV_CTRL_INIT;
+ case CNSS_MHI_DEINIT:
+ return MHI_DEV_CTRL_DE_INIT;
+ case CNSS_MHI_POWER_ON:
+ return MHI_DEV_CTRL_POWER_ON;
+ case CNSS_MHI_POWER_OFF:
+ return MHI_DEV_CTRL_POWER_OFF;
+ case CNSS_MHI_SUSPEND:
+ return MHI_DEV_CTRL_SUSPEND;
+ case CNSS_MHI_RESUME:
+ return MHI_DEV_CTRL_RESUME;
+ case CNSS_MHI_TRIGGER_RDDM:
+ return MHI_DEV_CTRL_TRIGGER_RDDM;
+ case CNSS_MHI_RDDM:
+ return MHI_DEV_CTRL_RDDM;
+ case CNSS_MHI_RDDM_KERNEL_PANIC:
+ return MHI_DEV_CTRL_RDDM_KERNEL_PANIC;
+ case CNSS_MHI_NOTIFY_LINK_ERROR:
+ return MHI_DEV_CTRL_NOTIFY_LINK_ERROR;
+ default:
+ cnss_pr_err("Unknown CNSS MHI state (%d)\n", state);
+ return -EINVAL;
+ }
+}
+
+static int cnss_pci_check_mhi_state_bit(struct cnss_pci_data *pci_priv,
+ enum cnss_mhi_state mhi_state)
+{
+ switch (mhi_state) {
+ case CNSS_MHI_INIT:
+ if (!test_bit(CNSS_MHI_INIT, &pci_priv->mhi_state))
+ return 0;
+ break;
+ case CNSS_MHI_DEINIT:
+ case CNSS_MHI_POWER_ON:
+ if (test_bit(CNSS_MHI_INIT, &pci_priv->mhi_state) &&
+ !test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state))
+ return 0;
+ break;
+ case CNSS_MHI_POWER_OFF:
+ case CNSS_MHI_SUSPEND:
+ if (test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state) &&
+ !test_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state))
+ return 0;
+ break;
+ case CNSS_MHI_RESUME:
+ if (test_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state))
+ return 0;
+ break;
+ case CNSS_MHI_TRIGGER_RDDM:
+ case CNSS_MHI_RDDM:
+ case CNSS_MHI_RDDM_KERNEL_PANIC:
+ case CNSS_MHI_NOTIFY_LINK_ERROR:
+ return 0;
+ default:
+ cnss_pr_err("Unhandled MHI state: %s(%d)\n",
+ cnss_mhi_state_to_str(mhi_state), mhi_state);
+ }
+
+ cnss_pr_err("Cannot set MHI state %s(%d) in current MHI state (0x%lx)\n",
+ cnss_mhi_state_to_str(mhi_state), mhi_state,
+ pci_priv->mhi_state);
+
+ return -EINVAL;
+}
+
+static void cnss_pci_set_mhi_state_bit(struct cnss_pci_data *pci_priv,
+ enum cnss_mhi_state mhi_state)
+{
+ switch (mhi_state) {
+ case CNSS_MHI_INIT:
+ set_bit(CNSS_MHI_INIT, &pci_priv->mhi_state);
+ break;
+ case CNSS_MHI_DEINIT:
+ clear_bit(CNSS_MHI_INIT, &pci_priv->mhi_state);
+ break;
+ case CNSS_MHI_POWER_ON:
+ set_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state);
+ break;
+ case CNSS_MHI_POWER_OFF:
+ clear_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state);
+ break;
+ case CNSS_MHI_SUSPEND:
+ set_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state);
+ break;
+ case CNSS_MHI_RESUME:
+ clear_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state);
+ break;
+ case CNSS_MHI_TRIGGER_RDDM:
+ case CNSS_MHI_RDDM:
+ case CNSS_MHI_RDDM_KERNEL_PANIC:
+ case CNSS_MHI_NOTIFY_LINK_ERROR:
+ break;
+ default:
+ cnss_pr_err("Unhandled MHI state (%d)\n", mhi_state);
+ }
+}
+
+int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv,
+ enum cnss_mhi_state mhi_state)
+{
+ int ret = 0;
+ enum mhi_dev_ctrl mhi_dev_state = cnss_to_mhi_dev_state(mhi_state);
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ if (pci_priv->device_id == QCA6174_DEVICE_ID)
+ return 0;
+
+ if (mhi_dev_state < 0) {
+ cnss_pr_err("Invalid MHI DEV state (%d)\n", mhi_dev_state);
+ return -EINVAL;
+ }
+
+ ret = cnss_pci_check_mhi_state_bit(pci_priv, mhi_state);
+ if (ret)
+ goto out;
+
+ cnss_pr_dbg("Setting MHI state: %s(%d)\n",
+ cnss_mhi_state_to_str(mhi_state), mhi_state);
+ ret = mhi_pm_control_device(&pci_priv->mhi_dev, mhi_dev_state);
+ if (ret) {
+ cnss_pr_err("Failed to set MHI state: %s(%d)\n",
+ cnss_mhi_state_to_str(mhi_state), mhi_state);
+ goto out;
+ }
+
+ cnss_pci_set_mhi_state_bit(pci_priv, mhi_state);
+
+out:
+ return ret;
+}
+
+int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ if (fbc_bypass)
+ return 0;
+
+ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_INIT);
+ if (ret)
+ goto out;
+
+ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON);
+ if (ret)
+ goto out;
+
+ return 0;
+
+out:
+ return ret;
+}
+
+void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL!\n");
+ return;
+ }
+
+ if (fbc_bypass)
+ return;
+
+ plat_priv = pci_priv->plat_priv;
+
+ cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_RESUME);
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF);
+
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state))
+ return;
+
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+}
+
+static int cnss_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ int ret = 0;
+ struct cnss_pci_data *pci_priv;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct resource *res;
+
+ cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n",
+ id->vendor, pci_dev->device);
+
+ switch (pci_dev->device) {
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ if (!mhi_is_device_ready(&plat_priv->plat_dev->dev,
+ MHI_NODE_NAME)) {
+ cnss_pr_err("MHI driver is not ready, defer PCI probe!\n");
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
+ break;
+ default:
+ break;
+ }
+
+ pci_priv = devm_kzalloc(&pci_dev->dev, sizeof(*pci_priv),
+ GFP_KERNEL);
+ if (!pci_priv) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pci_priv->pci_link_state = PCI_LINK_UP;
+ pci_priv->plat_priv = plat_priv;
+ pci_priv->pci_dev = pci_dev;
+ pci_priv->pci_device_id = id;
+ pci_priv->device_id = pci_dev->device;
+ cnss_set_pci_priv(pci_dev, pci_priv);
+ plat_priv->device_id = pci_dev->device;
+ plat_priv->bus_priv = pci_priv;
+
+ ret = cnss_register_subsys(plat_priv);
+ if (ret)
+ goto reset_ctx;
+
+ ret = cnss_register_ramdump(plat_priv);
+ if (ret)
+ goto unregister_subsys;
+
+ res = platform_get_resource_byname(plat_priv->plat_dev, IORESOURCE_MEM,
+ "smmu_iova_base");
+ if (res) {
+ pci_priv->smmu_iova_start = res->start;
+ pci_priv->smmu_iova_len = resource_size(res);
+ cnss_pr_dbg("smmu_iova_start: %pa, smmu_iova_len: %zu\n",
+ &pci_priv->smmu_iova_start,
+ pci_priv->smmu_iova_len);
+
+ ret = cnss_pci_init_smmu(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to init SMMU, err = %d\n", ret);
+ goto unregister_ramdump;
+ }
+ }
+
+ ret = cnss_reg_pci_event(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to register PCI event, err = %d\n", ret);
+ goto deinit_smmu;
+ }
+
+ ret = cnss_pci_enable_bus(pci_priv);
+ if (ret)
+ goto dereg_pci_event;
+
+ pci_save_state(pci_dev);
+ pci_priv->default_state = pci_store_saved_state(pci_dev);
+
+ switch (pci_dev->device) {
+ case QCA6174_DEVICE_ID:
+ pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET,
+ &pci_priv->revision_id);
+ ret = cnss_suspend_pci_link(pci_priv);
+ if (ret)
+ cnss_pr_err("Failed to suspend PCI link, err = %d\n",
+ ret);
+ cnss_power_off_device(plat_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_pci_enable_msi(pci_priv);
+ if (ret)
+ goto disable_bus;
+ ret = cnss_pci_register_mhi(pci_priv);
+ if (ret) {
+ cnss_pci_disable_msi(pci_priv);
+ goto disable_bus;
+ }
+ ret = cnss_suspend_pci_link(pci_priv);
+ if (ret)
+ cnss_pr_err("Failed to suspend PCI link, err = %d\n",
+ ret);
+ cnss_power_off_device(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown PCI device found: 0x%x\n",
+ pci_dev->device);
+ ret = -ENODEV;
+ goto disable_bus;
+ }
+
+ return 0;
+
+disable_bus:
+ cnss_pci_disable_bus(pci_priv);
+dereg_pci_event:
+ cnss_dereg_pci_event(pci_priv);
+deinit_smmu:
+ if (pci_priv->smmu_mapping)
+ cnss_pci_deinit_smmu(pci_priv);
+unregister_ramdump:
+ cnss_unregister_ramdump(plat_priv);
+unregister_subsys:
+ cnss_unregister_subsys(plat_priv);
+reset_ctx:
+ plat_priv->bus_priv = NULL;
+out:
+ return ret;
+}
+
+static void cnss_pci_remove(struct pci_dev *pci_dev)
+{
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_plat_data *plat_priv =
+ cnss_bus_dev_to_plat_priv(&pci_dev->dev);
+
+ cnss_pci_free_m3_mem(pci_priv);
+ cnss_pci_free_fw_mem(pci_priv);
+
+ switch (pci_dev->device) {
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ cnss_pci_unregister_mhi(pci_priv);
+ cnss_pci_disable_msi(pci_priv);
+ break;
+ default:
+ break;
+ }
+
+ pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state);
+
+ cnss_pci_disable_bus(pci_priv);
+ cnss_dereg_pci_event(pci_priv);
+ if (pci_priv->smmu_mapping)
+ cnss_pci_deinit_smmu(pci_priv);
+ cnss_unregister_ramdump(plat_priv);
+ cnss_unregister_subsys(plat_priv);
+ plat_priv->bus_priv = NULL;
+}
+
+static const struct pci_device_id cnss_pci_id_table[] = {
+ { QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { QCA6290_EMULATION_VENDOR_ID, QCA6290_EMULATION_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { QCA6290_VENDOR_ID, QCA6290_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, cnss_pci_id_table);
+
+static const struct dev_pm_ops cnss_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend, cnss_pci_resume)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend_noirq,
+ cnss_pci_resume_noirq)
+ SET_RUNTIME_PM_OPS(cnss_pci_runtime_suspend, cnss_pci_runtime_resume,
+ cnss_pci_runtime_idle)
+};
+
+struct pci_driver cnss_pci_driver = {
+ .name = "cnss_pci",
+ .id_table = cnss_pci_id_table,
+ .probe = cnss_pci_probe,
+ .remove = cnss_pci_remove,
+ .driver = {
+ .pm = &cnss_pm_ops,
+ },
+};
+
+int cnss_pci_init(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct device *dev = &plat_priv->plat_dev->dev;
+ u32 rc_num;
+
+ ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num);
+ if (ret) {
+ cnss_pr_err("Failed to find PCIe RC number, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = msm_pcie_enumerate(rc_num);
+ if (ret) {
+ cnss_pr_err("Failed to enable PCIe RC%x, err = %d\n",
+ rc_num, ret);
+ goto out;
+ }
+
+ ret = pci_register_driver(&cnss_pci_driver);
+ if (ret) {
+ cnss_pr_err("Failed to register to PCI framework, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+void cnss_pci_deinit(struct cnss_plat_data *plat_priv)
+{
+ pci_unregister_driver(&cnss_pci_driver);
+}
diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h
new file mode 100644
index 0000000..89edc60
--- /dev/null
+++ b/drivers/net/wireless/cnss2/pci.h
@@ -0,0 +1,143 @@
+/* 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
+ * 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 _CNSS_PCI_H
+#define _CNSS_PCI_H
+
+#include <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/msm_mhi.h>
+#include <linux/msm_pcie.h>
+#include <linux/pci.h>
+
+#include "main.h"
+
+#define QCA6174_VENDOR_ID 0x168C
+#define QCA6174_DEVICE_ID 0x003E
+#define QCA6174_REV_ID_OFFSET 0x08
+#define QCA6174_REV3_VERSION 0x5020000
+#define QCA6174_REV3_2_VERSION 0x5030000
+#define QCA6290_VENDOR_ID 0x17CB
+#define QCA6290_DEVICE_ID 0x1100
+#define QCA6290_EMULATION_VENDOR_ID 0x168C
+#define QCA6290_EMULATION_DEVICE_ID 0xABCD
+
+enum cnss_mhi_state {
+ CNSS_MHI_INIT,
+ CNSS_MHI_DEINIT,
+ CNSS_MHI_SUSPEND,
+ CNSS_MHI_RESUME,
+ CNSS_MHI_POWER_OFF,
+ CNSS_MHI_POWER_ON,
+ CNSS_MHI_TRIGGER_RDDM,
+ CNSS_MHI_RDDM,
+ CNSS_MHI_RDDM_KERNEL_PANIC,
+ CNSS_MHI_NOTIFY_LINK_ERROR,
+};
+
+struct cnss_msi_user {
+ char *name;
+ int num_vectors;
+ u32 base_vector;
+};
+
+struct cnss_msi_config {
+ int total_vectors;
+ int total_users;
+ struct cnss_msi_user *users;
+};
+
+struct cnss_pci_data {
+ struct pci_dev *pci_dev;
+ struct cnss_plat_data *plat_priv;
+ const struct pci_device_id *pci_device_id;
+ u32 device_id;
+ u16 revision_id;
+ bool pci_link_state;
+ bool pci_link_down_ind;
+ struct pci_saved_state *saved_state;
+ struct pci_saved_state *default_state;
+ struct msm_pcie_register_event msm_pci_event;
+ atomic_t auto_suspended;
+ bool monitor_wake_intr;
+ struct dma_iommu_mapping *smmu_mapping;
+ dma_addr_t smmu_iova_start;
+ size_t smmu_iova_len;
+ void __iomem *bar;
+ struct cnss_msi_config *msi_config;
+ u32 msi_ep_base_data;
+ struct mhi_device mhi_dev;
+ unsigned long mhi_state;
+};
+
+static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)
+{
+ pci_set_drvdata(pci_dev, data);
+}
+
+static inline struct cnss_pci_data *cnss_get_pci_priv(struct pci_dev *pci_dev)
+{
+ return pci_get_drvdata(pci_dev);
+}
+
+static inline struct cnss_plat_data *cnss_pci_priv_to_plat_priv(void *bus_priv)
+{
+ struct cnss_pci_data *pci_priv = bus_priv;
+
+ return pci_priv->plat_priv;
+}
+
+static inline void cnss_pci_set_monitor_wake_intr(void *bus_priv, bool val)
+{
+ struct cnss_pci_data *pci_priv = bus_priv;
+
+ pci_priv->monitor_wake_intr = val;
+}
+
+static inline bool cnss_pci_get_monitor_wake_intr(void *bus_priv)
+{
+ struct cnss_pci_data *pci_priv = bus_priv;
+
+ return pci_priv->monitor_wake_intr;
+}
+
+static inline void cnss_pci_set_auto_suspended(void *bus_priv, int val)
+{
+ struct cnss_pci_data *pci_priv = bus_priv;
+
+ atomic_set(&pci_priv->auto_suspended, val);
+}
+
+static inline int cnss_pci_get_auto_suspended(void *bus_priv)
+{
+ struct cnss_pci_data *pci_priv = bus_priv;
+
+ return atomic_read(&pci_priv->auto_suspended);
+}
+
+int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv);
+int cnss_resume_pci_link(struct cnss_pci_data *pci_priv);
+int cnss_pci_init(struct cnss_plat_data *plat_priv);
+void cnss_pci_deinit(struct cnss_plat_data *plat_priv);
+int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv);
+int cnss_pci_load_m3(struct cnss_pci_data *pci_priv);
+int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va,
+ phys_addr_t *pa);
+int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv,
+ enum cnss_mhi_state state);
+int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv);
+void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv);
+void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv);
+void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv);
+int cnss_pm_request_resume(struct cnss_pci_data *pci_priv);
+
+#endif /* _CNSS_PCI_H */
diff --git a/drivers/net/wireless/cnss2/power.c b/drivers/net/wireless/cnss2/power.c
new file mode 100644
index 0000000..8ed1507
--- /dev/null
+++ b/drivers/net/wireless/cnss2/power.c
@@ -0,0 +1,386 @@
+/* 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
+ * 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/delay.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include "main.h"
+#include "debug.h"
+
+static struct cnss_vreg_info cnss_vreg_info[] = {
+ {NULL, "vdd-wlan-core", 1300000, 1300000, 0, 0},
+ {NULL, "vdd-wlan-io", 1800000, 1800000, 0, 0},
+ {NULL, "vdd-wlan-xtal-aon", 0, 0, 0, 0},
+ {NULL, "vdd-wlan-xtal", 1800000, 1800000, 0, 2},
+ {NULL, "vdd-wlan", 0, 0, 0, 0},
+ {NULL, "vdd-wlan-sp2t", 2700000, 2700000, 0, 0},
+ {NULL, "wlan-ant-switch", 2700000, 2700000, 20000, 0},
+ {NULL, "wlan-soc-swreg", 1200000, 1200000, 0, 0},
+ {NULL, "vdd-wlan-en", 0, 0, 0, 10},
+};
+
+#define CNSS_VREG_INFO_SIZE ARRAY_SIZE(cnss_vreg_info)
+#define MAX_PROP_SIZE 32
+
+#define BOOTSTRAP_GPIO "qcom,enable-bootstrap-gpio"
+#define BOOTSTRAP_ACTIVE "bootstrap_active"
+#define WLAN_EN_GPIO "wlan-en-gpio"
+#define WLAN_EN_ACTIVE "wlan_en_active"
+#define WLAN_EN_SLEEP "wlan_en_sleep"
+
+#define BOOTSTRAP_DELAY 1000
+#define WLAN_ENABLE_DELAY 1000
+
+int cnss_get_vreg(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ int i;
+ struct cnss_vreg_info *vreg_info;
+ struct device *dev;
+ struct regulator *reg;
+ const __be32 *prop;
+ char prop_name[MAX_PROP_SIZE];
+ int len;
+
+ dev = &plat_priv->plat_dev->dev;
+
+ plat_priv->vreg_info = devm_kzalloc(dev, sizeof(cnss_vreg_info),
+ GFP_KERNEL);
+ if (!plat_priv->vreg_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(plat_priv->vreg_info, cnss_vreg_info, sizeof(cnss_vreg_info));
+
+ for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
+ vreg_info = &plat_priv->vreg_info[i];
+ reg = devm_regulator_get_optional(dev, vreg_info->name);
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+ if (ret == -ENODEV)
+ continue;
+ else if (ret == -EPROBE_DEFER)
+ cnss_pr_info("EPROBE_DEFER for regulator: %s\n",
+ vreg_info->name);
+ else
+ cnss_pr_err("Failed to get regulator %s, err = %d\n",
+ vreg_info->name, ret);
+ goto out;
+ }
+
+ vreg_info->reg = reg;
+
+ snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-info",
+ vreg_info->name);
+
+ prop = of_get_property(dev->of_node, prop_name, &len);
+ cnss_pr_dbg("Got regulator info, name: %s, len: %d\n",
+ prop_name, len);
+
+ if (!prop || len != (4 * sizeof(__be32))) {
+ cnss_pr_dbg("Property %s %s, use default\n", prop_name,
+ prop ? "invalid format" : "doesn't exist");
+ } else {
+ vreg_info->min_uv = be32_to_cpup(&prop[0]);
+ vreg_info->max_uv = be32_to_cpup(&prop[1]);
+ vreg_info->load_ua = be32_to_cpup(&prop[2]);
+ vreg_info->delay_us = be32_to_cpup(&prop[3]);
+ }
+
+ cnss_pr_dbg("Got regulator: %s, min_uv: %u, max_uv: %u, load_ua: %u, delay_us: %u\n",
+ vreg_info->name, vreg_info->min_uv,
+ vreg_info->max_uv, vreg_info->load_ua,
+ vreg_info->delay_us);
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static int cnss_vreg_on(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_vreg_info *vreg_info;
+ int i;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
+ vreg_info = &plat_priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ cnss_pr_dbg("Regulator %s is being enabled\n", vreg_info->name);
+
+ if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
+ ret = regulator_set_voltage(vreg_info->reg,
+ vreg_info->min_uv,
+ vreg_info->max_uv);
+
+ if (ret) {
+ cnss_pr_err("Failed to set voltage for regulator %s, min_uv: %u, max_uv: %u, err = %d\n",
+ vreg_info->name, vreg_info->min_uv,
+ vreg_info->max_uv, ret);
+ break;
+ }
+ }
+
+ if (vreg_info->load_ua) {
+ ret = regulator_set_load(vreg_info->reg,
+ vreg_info->load_ua);
+
+ if (ret < 0) {
+ cnss_pr_err("Failed to set load for regulator %s, load: %u, err = %d\n",
+ vreg_info->name, vreg_info->load_ua,
+ ret);
+ break;
+ }
+ }
+
+ if (vreg_info->delay_us)
+ udelay(vreg_info->delay_us);
+
+ ret = regulator_enable(vreg_info->reg);
+ if (ret) {
+ cnss_pr_err("Failed to enable regulator %s, err = %d\n",
+ vreg_info->name, ret);
+ break;
+ }
+ }
+
+ if (ret) {
+ for (; i >= 0; i--) {
+ vreg_info = &plat_priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ regulator_disable(vreg_info->reg);
+ if (vreg_info->load_ua)
+ regulator_set_load(vreg_info->reg, 0);
+ if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0)
+ regulator_set_voltage(vreg_info->reg, 0,
+ vreg_info->max_uv);
+ }
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cnss_vreg_off(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct cnss_vreg_info *vreg_info;
+ int i;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return -ENODEV;
+ }
+
+ for (i = CNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
+ vreg_info = &plat_priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ cnss_pr_dbg("Regulator %s is being disabled\n",
+ vreg_info->name);
+
+ ret = regulator_disable(vreg_info->reg);
+ if (ret)
+ cnss_pr_err("Failed to disable regulator %s, err = %d\n",
+ vreg_info->name, ret);
+
+ if (vreg_info->load_ua) {
+ ret = regulator_set_load(vreg_info->reg, 0);
+ if (ret < 0)
+ cnss_pr_err("Failed to set load for regulator %s, err = %d\n",
+ vreg_info->name, ret);
+ }
+
+ if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
+ ret = regulator_set_voltage(vreg_info->reg, 0,
+ vreg_info->max_uv);
+ if (ret)
+ cnss_pr_err("Failed to set voltage for regulator %s, err = %d\n",
+ vreg_info->name, ret);
+ }
+ }
+
+ return ret;
+}
+
+int cnss_get_pinctrl(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+ struct device *dev;
+ struct cnss_pinctrl_info *pinctrl_info;
+
+ dev = &plat_priv->plat_dev->dev;
+ pinctrl_info = &plat_priv->pinctrl_info;
+
+ pinctrl_info->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR_OR_NULL(pinctrl_info->pinctrl)) {
+ ret = PTR_ERR(pinctrl_info->pinctrl);
+ cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
+ goto out;
+ }
+
+ if (of_find_property(dev->of_node, BOOTSTRAP_GPIO, NULL)) {
+ pinctrl_info->bootstrap_active =
+ pinctrl_lookup_state(pinctrl_info->pinctrl,
+ BOOTSTRAP_ACTIVE);
+ if (IS_ERR_OR_NULL(pinctrl_info->bootstrap_active)) {
+ ret = PTR_ERR(pinctrl_info->bootstrap_active);
+ cnss_pr_err("Failed to get bootstrap active state, err = %d\n",
+ ret);
+ goto out;
+ }
+ }
+
+ if (of_find_property(dev->of_node, WLAN_EN_GPIO, NULL)) {
+ pinctrl_info->wlan_en_active =
+ pinctrl_lookup_state(pinctrl_info->pinctrl,
+ WLAN_EN_ACTIVE);
+ if (IS_ERR_OR_NULL(pinctrl_info->wlan_en_active)) {
+ ret = PTR_ERR(pinctrl_info->wlan_en_active);
+ cnss_pr_err("Failed to get wlan_en active state, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ pinctrl_info->wlan_en_sleep =
+ pinctrl_lookup_state(pinctrl_info->pinctrl,
+ WLAN_EN_SLEEP);
+ if (IS_ERR_OR_NULL(pinctrl_info->wlan_en_sleep)) {
+ ret = PTR_ERR(pinctrl_info->wlan_en_sleep);
+ cnss_pr_err("Failed to get wlan_en sleep state, err = %d\n",
+ ret);
+ goto out;
+ }
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
+ bool state)
+{
+ int ret = 0;
+ struct cnss_pinctrl_info *pinctrl_info;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ pinctrl_info = &plat_priv->pinctrl_info;
+
+ if (state) {
+ if (!IS_ERR_OR_NULL(pinctrl_info->bootstrap_active)) {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->
+ bootstrap_active);
+ if (ret) {
+ cnss_pr_err("Failed to select bootstrap active state, err = %d\n",
+ ret);
+ goto out;
+ }
+ udelay(BOOTSTRAP_DELAY);
+ }
+
+ if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_active)) {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->
+ wlan_en_active);
+ if (ret) {
+ cnss_pr_err("Failed to select wlan_en active state, err = %d\n",
+ ret);
+ goto out;
+ }
+ udelay(WLAN_ENABLE_DELAY);
+ }
+ } else {
+ if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_sleep)) {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->wlan_en_sleep);
+ if (ret) {
+ cnss_pr_err("Failed to select wlan_en sleep state, err = %d\n",
+ ret);
+ goto out;
+ }
+ }
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+int cnss_power_on_device(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ ret = cnss_vreg_on(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to turn on vreg, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_select_pinctrl_state(plat_priv, true);
+ if (ret) {
+ cnss_pr_err("Failed to select pinctrl state, err = %d\n", ret);
+ goto vreg_off;
+ }
+
+ return 0;
+vreg_off:
+ cnss_vreg_off(plat_priv);
+out:
+ return ret;
+}
+
+void cnss_power_off_device(struct cnss_plat_data *plat_priv)
+{
+ cnss_select_pinctrl_state(plat_priv, false);
+ cnss_vreg_off(plat_priv);
+}
+
+void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv)
+{
+ unsigned long pin_status = 0;
+
+ set_bit(CNSS_WLAN_EN, &pin_status);
+ set_bit(CNSS_PCIE_TXN, &pin_status);
+ set_bit(CNSS_PCIE_TXP, &pin_status);
+ set_bit(CNSS_PCIE_RXN, &pin_status);
+ set_bit(CNSS_PCIE_RXP, &pin_status);
+ set_bit(CNSS_PCIE_REFCLKN, &pin_status);
+ set_bit(CNSS_PCIE_REFCLKP, &pin_status);
+ set_bit(CNSS_PCIE_RST, &pin_status);
+
+ plat_priv->pin_result.host_pin_result = pin_status;
+}
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
new file mode 100644
index 0000000..f4344ae
--- /dev/null
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -0,0 +1,1037 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/qmi_encdec.h>
+#include <soc/qcom/msm_qmi_interface.h>
+
+#include "main.h"
+#include "debug.h"
+#include "qmi.h"
+
+#define WLFW_SERVICE_INS_ID_V01 1
+#define WLFW_CLIENT_ID 0x4b4e454c
+#define MAX_BDF_FILE_NAME 11
+#define DEFAULT_BDF_FILE_NAME "bdwlan.elf"
+#define BDF_FILE_NAME_PREFIX "bdwlan.e"
+
+#ifdef CONFIG_CNSS2_DEBUG
+static unsigned int qmi_timeout = 10000;
+module_param(qmi_timeout, uint, 0600);
+MODULE_PARM_DESC(qmi_timeout, "Timeout for QMI message in milliseconds");
+
+#define QMI_WLFW_TIMEOUT_MS qmi_timeout
+#else
+#define QMI_WLFW_TIMEOUT_MS 10000
+#endif
+
+static bool daemon_support;
+module_param(daemon_support, bool, 0600);
+MODULE_PARM_DESC(daemon_support, "User space has cnss-daemon support or not");
+
+static bool bdf_bypass;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(bdf_bypass, bool, 0600);
+MODULE_PARM_DESC(bdf_bypass, "If BDF is not found, send dummy BDF to FW");
+#endif
+
+enum cnss_bdf_type {
+ CNSS_BDF_BIN,
+ CNSS_BDF_ELF,
+};
+
+static char *cnss_qmi_mode_to_str(enum wlfw_driver_mode_enum_v01 mode)
+{
+ switch (mode) {
+ case QMI_WLFW_MISSION_V01:
+ return "MISSION";
+ case QMI_WLFW_FTM_V01:
+ return "FTM";
+ case QMI_WLFW_EPPING_V01:
+ return "EPPING";
+ case QMI_WLFW_WALTEST_V01:
+ return "WALTEST";
+ case QMI_WLFW_OFF_V01:
+ return "OFF";
+ case QMI_WLFW_CCPM_V01:
+ return "CCPM";
+ case QMI_WLFW_QVIT_V01:
+ return "QVIT";
+ case QMI_WLFW_CALIBRATION_V01:
+ return "CALIBRATION";
+ default:
+ return "UNKNOWN";
+ }
+};
+
+static void cnss_wlfw_clnt_notifier_work(struct work_struct *work)
+{
+ struct cnss_plat_data *plat_priv =
+ container_of(work, struct cnss_plat_data, qmi_recv_msg_work);
+ int ret = 0;
+
+ cnss_pr_dbg("Receiving QMI WLFW event in work queue context\n");
+
+ do {
+ ret = qmi_recv_msg(plat_priv->qmi_wlfw_clnt);
+ } while (ret == 0);
+
+ if (ret != -ENOMSG)
+ cnss_pr_err("Error receiving message: %d\n", ret);
+
+ cnss_pr_dbg("Receiving QMI event completed\n");
+}
+
+static void cnss_wlfw_clnt_notifier(struct qmi_handle *handle,
+ enum qmi_event_type event,
+ void *notify_priv)
+{
+ struct cnss_plat_data *plat_priv = notify_priv;
+
+ cnss_pr_dbg("Received QMI WLFW event: %d\n", event);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return;
+ }
+
+ switch (event) {
+ case QMI_RECV_MSG:
+ schedule_work(&plat_priv->qmi_recv_msg_work);
+ break;
+ case QMI_SERVER_EXIT:
+ break;
+ default:
+ cnss_pr_dbg("Unhandled QMI event: %d\n", event);
+ break;
+ }
+}
+
+static int cnss_wlfw_clnt_svc_event_notifier(struct notifier_block *nb,
+ unsigned long code, void *_cmd)
+{
+ struct cnss_plat_data *plat_priv =
+ container_of(nb, struct cnss_plat_data, qmi_wlfw_clnt_nb);
+ int ret = 0;
+
+ cnss_pr_dbg("Received QMI WLFW service event: %ld\n", code);
+
+ switch (code) {
+ case QMI_SERVER_ARRIVE:
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_SERVER_ARRIVE,
+ 0, NULL);
+ break;
+
+ case QMI_SERVER_EXIT:
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_SERVER_EXIT,
+ 0, NULL);
+ break;
+ default:
+ cnss_pr_dbg("Invalid QMI service event: %ld\n", code);
+ break;
+ }
+
+ return ret;
+}
+
+static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
+{
+ struct wlfw_host_cap_req_msg_v01 req;
+ struct wlfw_host_cap_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending host capability message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.daemon_support_valid = 1;
+ req.daemon_support = daemon_support;
+
+ cnss_pr_dbg("daemon_support is %d\n", req.daemon_support);
+
+ req.wake_msi = cnss_get_wake_msi(plat_priv);
+ if (req.wake_msi) {
+ cnss_pr_dbg("WAKE MSI base data is %d\n", req.wake_msi);
+ req.wake_msi_valid = 1;
+ }
+
+ req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01;
+ req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_HOST_CAP_RESP_V01;
+ resp_desc.ei_array = wlfw_host_cap_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send host capability request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("Host capability request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ return 0;
+out:
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)
+{
+ struct wlfw_ind_register_req_msg_v01 req;
+ struct wlfw_ind_register_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending indication register message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.client_id_valid = 1;
+ req.client_id = WLFW_CLIENT_ID;
+ req.fw_ready_enable_valid = 1;
+ req.fw_ready_enable = 1;
+ req.request_mem_enable_valid = 1;
+ req.request_mem_enable = 1;
+ req.fw_mem_ready_enable_valid = 1;
+ req.fw_mem_ready_enable = 1;
+ req.cold_boot_cal_done_enable_valid = 1;
+ req.cold_boot_cal_done_enable = 1;
+ req.pin_connect_result_enable_valid = 1;
+ req.pin_connect_result_enable = 1;
+
+ req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01;
+ req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_IND_REGISTER_RESP_V01;
+ resp_desc.ei_array = wlfw_ind_register_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send indication register request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("Indication register request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ return 0;
+out:
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv,
+ void *msg, unsigned int msg_len)
+{
+ struct msg_desc ind_desc;
+ struct wlfw_request_mem_ind_msg_v01 ind_msg;
+ struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+ int ret = 0;
+
+ ind_desc.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01;
+ ind_desc.max_msg_len = WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN;
+ ind_desc.ei_array = wlfw_request_mem_ind_msg_v01_ei;
+
+ ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+ if (ret < 0) {
+ cnss_pr_err("Failed to decode request memory indication, msg_len: %u, err = %d\n",
+ ret, msg_len);
+ return ret;
+ }
+
+ fw_mem->size = ind_msg.size;
+
+ cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
+ 0, NULL);
+
+ return 0;
+}
+
+static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv,
+ void *msg, unsigned int msg_len)
+{
+ struct msg_desc ind_desc;
+ struct wlfw_pin_connect_result_ind_msg_v01 ind_msg;
+ int ret = 0;
+
+ ind_desc.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01;
+ ind_desc.max_msg_len = WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN;
+ ind_desc.ei_array = wlfw_pin_connect_result_ind_msg_v01_ei;
+
+ ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+ if (ret < 0) {
+ cnss_pr_err("Failed to decode pin connect result indication, msg_len: %u, err = %d\n",
+ msg_len, ret);
+ return ret;
+ }
+ if (ind_msg.pwr_pin_result_valid)
+ plat_priv->pin_result.fw_pwr_pin_result =
+ ind_msg.pwr_pin_result;
+ if (ind_msg.phy_io_pin_result_valid)
+ plat_priv->pin_result.fw_phy_io_pin_result =
+ ind_msg.phy_io_pin_result;
+ if (ind_msg.rf_pin_result_valid)
+ plat_priv->pin_result.fw_rf_pin_result = ind_msg.rf_pin_result;
+
+ cnss_pr_dbg("Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n",
+ ind_msg.pwr_pin_result, ind_msg.phy_io_pin_result,
+ ind_msg.rf_pin_result);
+ return ret;
+}
+
+int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
+{
+ struct wlfw_respond_mem_req_msg_v01 req;
+ struct wlfw_respond_mem_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ if (!fw_mem->pa || !fw_mem->size) {
+ cnss_pr_err("Memory for FW is not available!\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+ fw_mem->va, &fw_mem->pa, fw_mem->size);
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.addr = fw_mem->pa;
+ req.size = fw_mem->size;
+
+ req_desc.max_msg_len = WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_RESPOND_MEM_REQ_V01;
+ req_desc.ei_array = wlfw_respond_mem_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_RESPOND_MEM_RESP_V01;
+ resp_desc.ei_array = wlfw_respond_mem_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send respond memory request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("Respond memory request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ return 0;
+out:
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
+{
+ struct wlfw_cap_req_msg_v01 req;
+ struct wlfw_cap_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending target capability message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req_desc.max_msg_len = WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_CAP_REQ_V01;
+ req_desc.ei_array = wlfw_cap_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_CAP_RESP_V01;
+ resp_desc.ei_array = wlfw_cap_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send target capability request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("Target capability request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ if (resp.chip_info_valid)
+ plat_priv->chip_info = resp.chip_info;
+ if (resp.board_info_valid)
+ plat_priv->board_info = resp.board_info;
+ else
+ plat_priv->board_info.board_id = 0xFF;
+ if (resp.soc_info_valid)
+ plat_priv->soc_info = resp.soc_info;
+ if (resp.fw_version_info_valid)
+ plat_priv->fw_version_info = resp.fw_version_info;
+
+ cnss_pr_dbg("Target capability: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x, fw_version: 0x%x, fw_build_timestamp: %s",
+ plat_priv->chip_info.chip_id,
+ plat_priv->chip_info.chip_family,
+ plat_priv->board_info.board_id, plat_priv->soc_info.soc_id,
+ plat_priv->fw_version_info.fw_version,
+ plat_priv->fw_version_info.fw_build_timestamp);
+
+ return 0;
+out:
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+ struct wlfw_bdf_download_req_msg_v01 *req;
+ struct wlfw_bdf_download_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ char filename[MAX_BDF_FILE_NAME];
+ const struct firmware *fw_entry;
+ const u8 *temp;
+ unsigned int remaining;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending BDF download message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (plat_priv->board_info.board_id == 0xFF)
+ snprintf(filename, sizeof(filename), DEFAULT_BDF_FILE_NAME);
+ else
+ snprintf(filename, sizeof(filename),
+ BDF_FILE_NAME_PREFIX "%02x",
+ plat_priv->board_info.board_id);
+
+ ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev);
+ if (ret) {
+ cnss_pr_err("Failed to load BDF: %s\n", filename);
+ if (bdf_bypass) {
+ cnss_pr_info("bdf_bypass is enabled, sending dummy BDF\n");
+ temp = filename;
+ remaining = MAX_BDF_FILE_NAME;
+ goto bypass_bdf;
+ } else {
+ goto err_req_fw;
+ }
+ }
+
+ temp = fw_entry->data;
+ remaining = fw_entry->size;
+
+bypass_bdf:
+ cnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining);
+
+ memset(&resp, 0, sizeof(resp));
+
+ req_desc.max_msg_len = WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_BDF_DOWNLOAD_REQ_V01;
+ req_desc.ei_array = wlfw_bdf_download_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_BDF_DOWNLOAD_RESP_V01;
+ resp_desc.ei_array = wlfw_bdf_download_resp_msg_v01_ei;
+
+ while (remaining) {
+ req->valid = 1;
+ req->file_id_valid = 1;
+ req->file_id = plat_priv->board_info.board_id;
+ req->total_size_valid = 1;
+ req->total_size = remaining;
+ req->seg_id_valid = 1;
+ req->data_valid = 1;
+ req->end_valid = 1;
+ req->bdf_type_valid = 1;
+ req->bdf_type = CNSS_BDF_ELF;
+
+ if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
+ req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
+ } else {
+ req->data_len = remaining;
+ req->end = 1;
+ }
+
+ memcpy(req->data, temp, req->data_len);
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc,
+ req, sizeof(*req), &resp_desc, &resp,
+ sizeof(resp), QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send BDF download request, err = %d\n",
+ ret);
+ goto err_send;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("BDF download request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto err_send;
+ }
+
+ remaining -= req->data_len;
+ temp += req->data_len;
+ req->seg_id++;
+ }
+
+err_send:
+ if (!bdf_bypass)
+ release_firmware(fw_entry);
+err_req_fw:
+ kfree(req);
+out:
+ if (ret)
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+ struct wlfw_m3_info_req_msg_v01 req;
+ struct wlfw_m3_info_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending M3 information message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ if (!m3_mem->pa || !m3_mem->size) {
+ cnss_pr_err("Memory for M3 is not available!\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cnss_pr_dbg("M3 memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+ m3_mem->va, &m3_mem->pa, m3_mem->size);
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.addr = plat_priv->m3_mem.pa;
+ req.size = plat_priv->m3_mem.size;
+
+ req_desc.max_msg_len = WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_M3_INFO_REQ_V01;
+ req_desc.ei_array = wlfw_m3_info_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_M3_INFO_RESP_V01;
+ resp_desc.ei_array = wlfw_m3_info_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send M3 information request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("M3 information request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
+ enum wlfw_driver_mode_enum_v01 mode)
+{
+ struct wlfw_wlan_mode_req_msg_v01 req;
+ struct wlfw_wlan_mode_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ int ret = 0;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n",
+ cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state);
+
+ if (mode == QMI_WLFW_OFF_V01 &&
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Recovery is in progress, ignore mode off request.\n");
+ return 0;
+ }
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.mode = mode;
+ req.hw_debug_valid = 1;
+ req.hw_debug = 0;
+
+ req_desc.max_msg_len = WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_WLAN_MODE_REQ_V01;
+ req_desc.ei_array = wlfw_wlan_mode_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_WLAN_MODE_RESP_V01;
+ resp_desc.ei_array = wlfw_wlan_mode_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ if (mode == QMI_WLFW_OFF_V01 && ret == -ENETRESET) {
+ cnss_pr_dbg("WLFW service is disconnected while sending mode off request.\n");
+ return 0;
+ }
+ cnss_pr_err("Failed to send mode request, mode: %s(%d), err: %d\n",
+ cnss_qmi_mode_to_str(mode), mode, ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("Mode request failed, mode: %s(%d), result: %d, err: %d\n",
+ cnss_qmi_mode_to_str(mode), mode, resp.resp.result,
+ resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ return 0;
+out:
+ if (mode != QMI_WLFW_OFF_V01)
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
+ struct wlfw_wlan_cfg_req_msg_v01 *data)
+{
+ struct wlfw_wlan_cfg_req_msg_v01 req;
+ struct wlfw_wlan_cfg_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending WLAN config message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ memcpy(&req, data, sizeof(req));
+
+ req_desc.max_msg_len = WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_WLAN_CFG_REQ_V01;
+ req_desc.ei_array = wlfw_wlan_cfg_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_WLAN_CFG_RESP_V01;
+ resp_desc.ei_array = wlfw_wlan_cfg_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send WLAN config request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("WLAN config request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ return 0;
+out:
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
+ u32 offset, u32 mem_type,
+ u32 data_len, u8 *data)
+{
+ struct wlfw_athdiag_read_req_msg_v01 req;
+ struct wlfw_athdiag_read_resp_msg_v01 *resp;
+ struct msg_desc req_desc, resp_desc;
+ int ret = 0;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ if (!plat_priv->qmi_wlfw_clnt)
+ return -EINVAL;
+
+ cnss_pr_dbg("athdiag read: state 0x%lx, offset %x, mem_type %x, data_len %u\n",
+ plat_priv->driver_state, offset, mem_type, data_len);
+
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ memset(&req, 0, sizeof(req));
+
+ req.offset = offset;
+ req.mem_type = mem_type;
+ req.data_len = data_len;
+
+ req_desc.max_msg_len = WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_ATHDIAG_READ_REQ_V01;
+ req_desc.ei_array = wlfw_athdiag_read_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_ATHDIAG_READ_RESP_V01;
+ resp_desc.ei_array = wlfw_athdiag_read_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+ sizeof(req), &resp_desc, resp, sizeof(*resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send athdiag read request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("athdiag read request failed, result: %d, err: %d\n",
+ resp->resp.result, resp->resp.error);
+ ret = resp->resp.result;
+ goto out;
+ }
+
+ if (!resp->data_valid || resp->data_len != data_len) {
+ cnss_pr_err("athdiag read data is invalid, data_valid = %u, data_len = %u\n",
+ resp->data_valid, resp->data_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ memcpy(data, resp->data, resp->data_len);
+
+out:
+ kfree(resp);
+ return ret;
+}
+
+int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
+ u32 offset, u32 mem_type,
+ u32 data_len, u8 *data)
+{
+ struct wlfw_athdiag_write_req_msg_v01 *req;
+ struct wlfw_athdiag_write_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ int ret = 0;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ if (!plat_priv->qmi_wlfw_clnt)
+ return -EINVAL;
+
+ cnss_pr_dbg("athdiag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %p\n",
+ plat_priv->driver_state, offset, mem_type, data_len, data);
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ memset(&resp, 0, sizeof(resp));
+
+ req->offset = offset;
+ req->mem_type = mem_type;
+ req->data_len = data_len;
+ memcpy(req->data, data, data_len);
+
+ req_desc.max_msg_len = WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_ATHDIAG_WRITE_REQ_V01;
+ req_desc.ei_array = wlfw_athdiag_write_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_ATHDIAG_WRITE_RESP_V01;
+ resp_desc.ei_array = wlfw_athdiag_write_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req,
+ sizeof(*req), &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send athdiag write request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("athdiag write request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+out:
+ kfree(req);
+ return ret;
+}
+
+int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
+ u8 fw_log_mode)
+{
+ int ret;
+ struct wlfw_ini_req_msg_v01 req;
+ struct wlfw_ini_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ cnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n",
+ plat_priv->driver_state, fw_log_mode);
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.enablefwlog_valid = 1;
+ req.enablefwlog = fw_log_mode;
+
+ req_desc.max_msg_len = WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_INI_REQ_V01;
+ req_desc.ei_array = wlfw_ini_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_INI_RESP_V01;
+ resp_desc.ei_array = wlfw_ini_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt,
+ &req_desc, &req, sizeof(req),
+ &resp_desc, &resp, sizeof(resp),
+ QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Send INI req failed fw_log_mode: %d, ret: %d\n",
+ fw_log_mode, ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("QMI INI request rejected, fw_log_mode:%d result:%d error:%d\n",
+ fw_log_mode, resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
+ unsigned int msg_id, void *msg,
+ unsigned int msg_len, void *ind_cb_priv)
+{
+ struct cnss_plat_data *plat_priv = ind_cb_priv;
+
+ cnss_pr_dbg("Received QMI WLFW indication, msg_id: 0x%x, msg_len: %d\n",
+ msg_id, msg_len);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL!\n");
+ return;
+ }
+
+ switch (msg_id) {
+ case QMI_WLFW_REQUEST_MEM_IND_V01:
+ cnss_wlfw_request_mem_ind_hdlr(plat_priv, msg, msg_len);
+ break;
+ case QMI_WLFW_FW_MEM_READY_IND_V01:
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_FW_MEM_READY,
+ 0, NULL);
+ break;
+ case QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01:
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+ 0, NULL);
+ break;
+ case QMI_WLFW_FW_READY_IND_V01:
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_FW_READY,
+ 0, NULL);
+ break;
+ case QMI_WLFW_PIN_CONNECT_RESULT_IND_V01:
+ cnss_qmi_pin_result_ind_hdlr(plat_priv, msg, msg_len);
+ break;
+ default:
+ cnss_pr_err("Invalid QMI WLFW indication, msg_id: 0x%x\n",
+ msg_id);
+ break;
+ }
+}
+
+unsigned int cnss_get_qmi_timeout(void)
+{
+ cnss_pr_dbg("QMI timeout is %u ms\n", QMI_WLFW_TIMEOUT_MS);
+
+ return QMI_WLFW_TIMEOUT_MS;
+}
+EXPORT_SYMBOL(cnss_get_qmi_timeout);
+
+int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ plat_priv->qmi_wlfw_clnt =
+ qmi_handle_create(cnss_wlfw_clnt_notifier, plat_priv);
+ if (!plat_priv->qmi_wlfw_clnt) {
+ cnss_pr_err("Failed to create QMI client handle!\n");
+ ret = -ENOMEM;
+ goto err_create_handle;
+ }
+
+ ret = qmi_connect_to_service(plat_priv->qmi_wlfw_clnt,
+ WLFW_SERVICE_ID_V01,
+ WLFW_SERVICE_VERS_V01,
+ WLFW_SERVICE_INS_ID_V01);
+ if (ret < 0) {
+ cnss_pr_err("Failed to connect to QMI WLFW service, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ ret = qmi_register_ind_cb(plat_priv->qmi_wlfw_clnt,
+ cnss_wlfw_clnt_ind, plat_priv);
+ if (ret < 0) {
+ cnss_pr_err("Failed to register QMI WLFW service indication callback, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ set_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
+
+ cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ ret = cnss_wlfw_host_cap_send_sync(plat_priv);
+ if (ret < 0)
+ goto out;
+
+ ret = cnss_wlfw_ind_register_send_sync(plat_priv);
+ if (ret < 0)
+ goto out;
+
+ return 0;
+out:
+ qmi_handle_destroy(plat_priv->qmi_wlfw_clnt);
+ plat_priv->qmi_wlfw_clnt = NULL;
+err_create_handle:
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ qmi_handle_destroy(plat_priv->qmi_wlfw_clnt);
+ plat_priv->qmi_wlfw_clnt = NULL;
+
+ clear_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
+
+ cnss_pr_info("QMI WLFW service disconnected, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ return 0;
+}
+
+int cnss_qmi_init(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ INIT_WORK(&plat_priv->qmi_recv_msg_work,
+ cnss_wlfw_clnt_notifier_work);
+
+ plat_priv->qmi_wlfw_clnt_nb.notifier_call =
+ cnss_wlfw_clnt_svc_event_notifier;
+
+ ret = qmi_svc_event_notifier_register(WLFW_SERVICE_ID_V01,
+ WLFW_SERVICE_VERS_V01,
+ WLFW_SERVICE_INS_ID_V01,
+ &plat_priv->qmi_wlfw_clnt_nb);
+ if (ret < 0)
+ cnss_pr_err("Failed to register QMI event notifier, err = %d\n",
+ ret);
+
+ return ret;
+}
+
+void cnss_qmi_deinit(struct cnss_plat_data *plat_priv)
+{
+ qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01,
+ WLFW_SERVICE_VERS_V01,
+ WLFW_SERVICE_INS_ID_V01,
+ &plat_priv->qmi_wlfw_clnt_nb);
+}
diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h
new file mode 100644
index 0000000..70d8d40
--- /dev/null
+++ b/drivers/net/wireless/cnss2/qmi.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CNSS_QMI_H
+#define _CNSS_QMI_H
+
+#include "wlan_firmware_service_v01.h"
+
+struct cnss_plat_data;
+
+int cnss_qmi_init(struct cnss_plat_data *plat_priv);
+void cnss_qmi_deinit(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
+ enum wlfw_driver_mode_enum_v01 mode);
+int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
+ struct wlfw_wlan_cfg_req_msg_v01 *data);
+int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
+ u32 offset, u32 mem_type,
+ u32 data_len, u8 *data);
+int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
+ u32 offset, u32 mem_type,
+ u32 data_len, u8 *data);
+int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
+ u8 fw_log_mode);
+
+#endif /* _CNSS_QMI_H */
diff --git a/drivers/net/wireless/cnss2/utils.c b/drivers/net/wireless/cnss2/utils.c
new file mode 100644
index 0000000..9ffe386
--- /dev/null
+++ b/drivers/net/wireless/cnss2/utils.c
@@ -0,0 +1,129 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define CNSS_MAX_CH_NUM 45
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(unsafe_channel_list_lock);
+static DEFINE_MUTEX(dfs_nol_info_lock);
+
+static struct cnss_unsafe_channel_list {
+ u16 unsafe_ch_count;
+ u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
+} unsafe_channel_list;
+
+static struct cnss_dfs_nol_info {
+ void *dfs_nol_info;
+ u16 dfs_nol_info_len;
+} dfs_nol_info;
+
+int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+ mutex_lock(&unsafe_channel_list_lock);
+ if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) {
+ mutex_unlock(&unsafe_channel_list_lock);
+ return -EINVAL;
+ }
+
+ unsafe_channel_list.unsafe_ch_count = ch_count;
+
+ if (ch_count != 0) {
+ memcpy((char *)unsafe_channel_list.unsafe_ch_list,
+ (char *)unsafe_ch_list, ch_count * sizeof(u16));
+ }
+ mutex_unlock(&unsafe_channel_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_set_wlan_unsafe_channel);
+
+int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
+ u16 *ch_count, u16 buf_len)
+{
+ mutex_lock(&unsafe_channel_list_lock);
+ if (!unsafe_ch_list || !ch_count) {
+ mutex_unlock(&unsafe_channel_list_lock);
+ return -EINVAL;
+ }
+
+ if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
+ mutex_unlock(&unsafe_channel_list_lock);
+ return -ENOMEM;
+ }
+
+ *ch_count = unsafe_channel_list.unsafe_ch_count;
+ memcpy((char *)unsafe_ch_list,
+ (char *)unsafe_channel_list.unsafe_ch_list,
+ unsafe_channel_list.unsafe_ch_count * sizeof(u16));
+ mutex_unlock(&unsafe_channel_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel);
+
+int cnss_wlan_set_dfs_nol(const void *info, u16 info_len)
+{
+ void *temp;
+ struct cnss_dfs_nol_info *dfs_info;
+
+ mutex_lock(&dfs_nol_info_lock);
+ if (!info || !info_len) {
+ mutex_unlock(&dfs_nol_info_lock);
+ return -EINVAL;
+ }
+
+ temp = kmalloc(info_len, GFP_KERNEL);
+ if (!temp) {
+ mutex_unlock(&dfs_nol_info_lock);
+ return -ENOMEM;
+ }
+
+ memcpy(temp, info, info_len);
+ dfs_info = &dfs_nol_info;
+ kfree(dfs_info->dfs_nol_info);
+
+ dfs_info->dfs_nol_info = temp;
+ dfs_info->dfs_nol_info_len = info_len;
+ mutex_unlock(&dfs_nol_info_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_wlan_set_dfs_nol);
+
+int cnss_wlan_get_dfs_nol(void *info, u16 info_len)
+{
+ int len;
+ struct cnss_dfs_nol_info *dfs_info;
+
+ mutex_lock(&dfs_nol_info_lock);
+ if (!info || !info_len) {
+ mutex_unlock(&dfs_nol_info_lock);
+ return -EINVAL;
+ }
+
+ dfs_info = &dfs_nol_info;
+
+ if (!dfs_info->dfs_nol_info || dfs_info->dfs_nol_info_len == 0) {
+ mutex_unlock(&dfs_nol_info_lock);
+ return -ENOENT;
+ }
+
+ len = min(info_len, dfs_info->dfs_nol_info_len);
+
+ memcpy(info, dfs_info->dfs_nol_info, len);
+ mutex_unlock(&dfs_nol_info_lock);
+
+ return len;
+}
+EXPORT_SYMBOL(cnss_wlan_get_dfs_nol);
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
new file mode 100644
index 0000000..7d6a771
--- /dev/null
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
@@ -0,0 +1,2221 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "wlan_firmware_service_v01.h"
+
+static struct elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ pipe_num),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_pipedir_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ pipe_dir),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ nentries),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ nbytes_max),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ flags),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ service_id),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_pipedir_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ pipe_dir),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ pipe_num),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+ id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_memory_region_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ region_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ secure_flag),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_rf_chip_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_chip_info_s_v01,
+ chip_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_chip_info_s_v01,
+ chip_family),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_rf_board_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_board_info_s_v01,
+ board_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_soc_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_soc_info_s_v01,
+ soc_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_fw_version_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_fw_version_info_s_v01,
+ fw_version),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_fw_version_info_s_v01,
+ fw_build_timestamp),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ind_register_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_ind_register_req_msg_v01,
+ fw_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_download_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_download_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_update_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_update_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ msa_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ msa_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ pin_connect_result_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ pin_connect_result_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ client_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ client_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ request_mem_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ request_mem_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_mem_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_mem_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ cold_boot_cal_done_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ cold_boot_cal_done_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ rejuvenate_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ rejuvenate_enable),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ind_register_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_ind_register_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_ind_register_resp_msg_v01,
+ fw_status_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_ind_register_resp_msg_v01,
+ fw_status),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_fw_ready_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_ready_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_pin_connect_result_ind_msg_v01,
+ pwr_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_pin_connect_result_ind_msg_v01,
+ pwr_pin_result),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct
+ wlfw_pin_connect_result_ind_msg_v01,
+ phy_io_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct
+ wlfw_pin_connect_result_ind_msg_v01,
+ phy_io_pin_result),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct
+ wlfw_pin_connect_result_ind_msg_v01,
+ rf_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct
+ wlfw_pin_connect_result_ind_msg_v01,
+ rf_pin_result),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_mode_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_driver_mode_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ mode),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ hw_debug_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ hw_debug),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ host_version_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ host_version),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_CE_V01,
+ .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg),
+ .ei_array = wlfw_ce_tgt_pipe_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SVC_V01,
+ .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg),
+ .ei_array = wlfw_ce_svc_pipe_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01,
+ .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg),
+ .ei_array = wlfw_shadow_reg_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01,
+ .elem_size = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2),
+ .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cap_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cap_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ chip_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ chip_info),
+ .ei_array = wlfw_rf_chip_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ board_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_rf_board_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ board_info),
+ .ei_array = wlfw_rf_board_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ soc_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_soc_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ soc_info),
+ .ei_array = wlfw_soc_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_version_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_fw_version_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_version_info),
+ .ei_array = wlfw_fw_version_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_build_id_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_build_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ num_macs_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ num_macs),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_bdf_download_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ valid),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ end),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ bdf_type_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ bdf_type),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_bdf_download_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_bdf_download_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_report_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ meta_data_len),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = QMI_WLFW_MAX_NUM_CAL_V01,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ meta_data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ xo_cal_data_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ xo_cal_data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_report_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_report_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct wlfw_initiate_cal_download_ind_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_download_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ valid),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ end),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_download_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_cal_download_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct
+ wlfw_initiate_cal_update_ind_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_initiate_cal_update_ind_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_update_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_update_req_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_update_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_update_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ end),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_info_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_msa_info_req_msg_v01,
+ msa_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_info_req_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_info_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ mem_region_info_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01,
+ .elem_size = sizeof(struct wlfw_memory_region_info_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ mem_region_info),
+ .ei_array = wlfw_memory_region_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_ready_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_ready_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ini_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ini_req_msg_v01,
+ enablefwlog_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ini_req_msg_v01,
+ enablefwlog),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ini_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_ini_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_read_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_athdiag_read_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_athdiag_read_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_athdiag_read_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_athdiag_read_resp_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_write_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct
+ wlfw_athdiag_write_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_athdiag_write_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct
+ wlfw_athdiag_write_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct
+ wlfw_athdiag_write_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_athdiag_write_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_vbatt_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_vbatt_req_msg_v01,
+ voltage_uv),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_vbatt_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_vbatt_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_mac_addr_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_mac_addr_req_msg_v01,
+ mac_addr_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAC_ADDR_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .is_array = STATIC_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_mac_addr_req_msg_v01,
+ mac_addr),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_mac_addr_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_mac_addr_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_host_cap_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ daemon_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ daemon_support),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ wake_msi_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ wake_msi),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_host_cap_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_host_cap_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_request_mem_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_request_mem_ind_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_respond_mem_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_respond_mem_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_respond_mem_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ cause_for_rejuvenation_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ cause_for_rejuvenation),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ requesting_sub_system_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ requesting_sub_system),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ line_number_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ line_number),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ function_name_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ function_name),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ wlfw_rejuvenate_ack_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_req_msg_v01,
+ mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_req_msg_v01,
+ mask),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ prev_mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ prev_mask),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ curr_mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ curr_mask),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_m3_info_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_m3_info_req_msg_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_m3_info_req_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_m3_info_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_m3_info_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_xo_cal_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_xo_cal_ind_msg_v01,
+ xo_cal_data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
new file mode 100644
index 0000000..9b56eb0
--- /dev/null
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
@@ -0,0 +1,657 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef WLAN_FIRMWARE_SERVICE_V01_H
+#define WLAN_FIRMWARE_SERVICE_V01_H
+
+#include <linux/qmi_encdec.h>
+#include <soc/qcom/msm_qmi_interface.h>
+
+#define WLFW_SERVICE_ID_V01 0x45
+#define WLFW_SERVICE_VERS_V01 0x01
+
+#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
+#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
+#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
+#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
+#define QMI_WLFW_M3_INFO_REQ_V01 0x003C
+#define QMI_WLFW_CAP_REQ_V01 0x0024
+#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
+#define QMI_WLFW_M3_INFO_RESP_V01 0x003C
+#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
+#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
+#define QMI_WLFW_XO_CAL_IND_V01 0x003D
+#define QMI_WLFW_INI_RESP_V01 0x002F
+#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
+#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
+#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
+#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
+#define QMI_WLFW_MSA_READY_IND_V01 0x002B
+#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
+#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
+#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
+#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0038
+#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
+#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
+#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
+#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036
+#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
+#define QMI_WLFW_FW_READY_IND_V01 0x0021
+#define QMI_WLFW_MSA_READY_RESP_V01 0x002E
+#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029
+#define QMI_WLFW_INI_REQ_V01 0x002F
+#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025
+#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A
+#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
+#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
+#define QMI_WLFW_CAP_RESP_V01 0x0024
+#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A
+#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
+#define QMI_WLFW_VBATT_REQ_V01 0x0032
+#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033
+#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036
+#define QMI_WLFW_VBATT_RESP_V01 0x0032
+#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
+#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
+#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
+#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
+#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
+
+#define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2
+#define QMI_WLFW_MAX_NUM_CAL_V01 5
+#define QMI_WLFW_MAX_DATA_SIZE_V01 6144
+#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_CE_V01 12
+#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
+#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
+#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
+#define QMI_WLFW_MAX_STR_LEN_V01 16
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
+#define QMI_WLFW_MAC_ADDR_SIZE_V01 6
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01 36
+#define QMI_WLFW_MAX_NUM_SVC_V01 24
+
+enum wlfw_driver_mode_enum_v01 {
+ WLFW_DRIVER_MODE_ENUM_MIN_VAL_V01 = INT_MIN,
+ QMI_WLFW_MISSION_V01 = 0,
+ QMI_WLFW_FTM_V01 = 1,
+ QMI_WLFW_EPPING_V01 = 2,
+ QMI_WLFW_WALTEST_V01 = 3,
+ QMI_WLFW_OFF_V01 = 4,
+ QMI_WLFW_CCPM_V01 = 5,
+ QMI_WLFW_QVIT_V01 = 6,
+ QMI_WLFW_CALIBRATION_V01 = 7,
+ WLFW_DRIVER_MODE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_cal_temp_id_enum_v01 {
+ WLFW_CAL_TEMP_ID_ENUM_MIN_VAL_V01 = INT_MIN,
+ QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0,
+ QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1,
+ QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2,
+ QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3,
+ QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4,
+ WLFW_CAL_TEMP_ID_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_pipedir_enum_v01 {
+ WLFW_PIPEDIR_ENUM_MIN_VAL_V01 = INT_MIN,
+ QMI_WLFW_PIPEDIR_NONE_V01 = 0,
+ QMI_WLFW_PIPEDIR_IN_V01 = 1,
+ QMI_WLFW_PIPEDIR_OUT_V01 = 2,
+ QMI_WLFW_PIPEDIR_INOUT_V01 = 3,
+ WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
+#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
+#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
+#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((u32)0x04)
+#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((u32)0x08)
+#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((u32)0x10)
+
+#define QMI_WLFW_ALREADY_REGISTERED_V01 ((u64)0x01ULL)
+#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL)
+#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL)
+#define QMI_WLFW_FW_MEM_READY_V01 ((u64)0x08ULL)
+
+#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL)
+
+struct wlfw_ce_tgt_pipe_cfg_s_v01 {
+ u32 pipe_num;
+ enum wlfw_pipedir_enum_v01 pipe_dir;
+ u32 nentries;
+ u32 nbytes_max;
+ u32 flags;
+};
+
+struct wlfw_ce_svc_pipe_cfg_s_v01 {
+ u32 service_id;
+ enum wlfw_pipedir_enum_v01 pipe_dir;
+ u32 pipe_num;
+};
+
+struct wlfw_shadow_reg_cfg_s_v01 {
+ u16 id;
+ u16 offset;
+};
+
+struct wlfw_shadow_reg_v2_cfg_s_v01 {
+ u32 addr;
+};
+
+struct wlfw_memory_region_info_s_v01 {
+ u64 region_addr;
+ u32 size;
+ u8 secure_flag;
+};
+
+struct wlfw_rf_chip_info_s_v01 {
+ u32 chip_id;
+ u32 chip_family;
+};
+
+struct wlfw_rf_board_info_s_v01 {
+ u32 board_id;
+};
+
+struct wlfw_soc_info_s_v01 {
+ u32 soc_id;
+};
+
+struct wlfw_fw_version_info_s_v01 {
+ u32 fw_version;
+ char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1];
+};
+
+struct wlfw_ind_register_req_msg_v01 {
+ u8 fw_ready_enable_valid;
+ u8 fw_ready_enable;
+ u8 initiate_cal_download_enable_valid;
+ u8 initiate_cal_download_enable;
+ u8 initiate_cal_update_enable_valid;
+ u8 initiate_cal_update_enable;
+ u8 msa_ready_enable_valid;
+ u8 msa_ready_enable;
+ u8 pin_connect_result_enable_valid;
+ u8 pin_connect_result_enable;
+ u8 client_id_valid;
+ u32 client_id;
+ u8 request_mem_enable_valid;
+ u8 request_mem_enable;
+ u8 fw_mem_ready_enable_valid;
+ u8 fw_mem_ready_enable;
+ u8 cold_boot_cal_done_enable_valid;
+ u8 cold_boot_cal_done_enable;
+ u8 rejuvenate_enable_valid;
+ u32 rejuvenate_enable;
+};
+
+#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 46
+extern struct elem_info wlfw_ind_register_req_msg_v01_ei[];
+
+struct wlfw_ind_register_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 fw_status_valid;
+ u64 fw_status;
+};
+
+#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_ind_register_resp_msg_v01_ei[];
+
+struct wlfw_fw_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_ready_ind_msg_v01_ei[];
+
+struct wlfw_msa_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_msa_ready_ind_msg_v01_ei[];
+
+struct wlfw_pin_connect_result_ind_msg_v01 {
+ u8 pwr_pin_result_valid;
+ u32 pwr_pin_result;
+ u8 phy_io_pin_result_valid;
+ u32 phy_io_pin_result;
+ u8 rf_pin_result_valid;
+ u32 rf_pin_result;
+};
+
+#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21
+extern struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[];
+
+struct wlfw_wlan_mode_req_msg_v01 {
+ enum wlfw_driver_mode_enum_v01 mode;
+ u8 hw_debug_valid;
+ u8 hw_debug;
+};
+
+#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_wlan_mode_req_msg_v01_ei[];
+
+struct wlfw_wlan_mode_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_req_msg_v01 {
+ u8 host_version_valid;
+ char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+ u8 tgt_cfg_valid;
+ u32 tgt_cfg_len;
+ struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01];
+ u8 svc_cfg_valid;
+ u32 svc_cfg_len;
+ struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01];
+ u8 shadow_reg_valid;
+ u32 shadow_reg_len;
+ struct wlfw_shadow_reg_cfg_s_v01
+ shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01];
+ u8 shadow_reg_v2_valid;
+ u32 shadow_reg_v2_len;
+ struct wlfw_shadow_reg_v2_cfg_s_v01
+ shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01];
+};
+
+#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803
+extern struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[];
+
+struct wlfw_cap_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cap_req_msg_v01_ei[];
+
+struct wlfw_cap_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 chip_info_valid;
+ struct wlfw_rf_chip_info_s_v01 chip_info;
+ u8 board_info_valid;
+ struct wlfw_rf_board_info_s_v01 board_info;
+ u8 soc_info_valid;
+ struct wlfw_soc_info_s_v01 soc_info;
+ u8 fw_version_info_valid;
+ struct wlfw_fw_version_info_s_v01 fw_version_info;
+ u8 fw_build_id_valid;
+ char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1];
+ u8 num_macs_valid;
+ u8 num_macs;
+};
+
+#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 207
+extern struct elem_info wlfw_cap_resp_msg_v01_ei[];
+
+struct wlfw_bdf_download_req_msg_v01 {
+ u8 valid;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+ u8 bdf_type_valid;
+ u8 bdf_type;
+};
+
+#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6182
+extern struct elem_info wlfw_bdf_download_req_msg_v01_ei[];
+
+struct wlfw_bdf_download_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_bdf_download_resp_msg_v01_ei[];
+
+struct wlfw_cal_report_req_msg_v01 {
+ u32 meta_data_len;
+ enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01];
+ u8 xo_cal_data_valid;
+ u8 xo_cal_data;
+};
+
+#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 28
+extern struct elem_info wlfw_cal_report_req_msg_v01_ei[];
+
+struct wlfw_cal_report_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_cal_report_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_download_ind_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+};
+
+#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[];
+
+struct wlfw_cal_download_req_msg_v01 {
+ u8 valid;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+};
+
+#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178
+extern struct elem_info wlfw_cal_download_req_msg_v01_ei[];
+
+struct wlfw_cal_download_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_cal_download_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_update_ind_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+ u32 total_size;
+};
+
+#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14
+extern struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[];
+
+struct wlfw_cal_update_req_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+ u32 seg_id;
+};
+
+#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14
+extern struct elem_info wlfw_cal_update_req_msg_v01_ei[];
+
+struct wlfw_cal_update_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+};
+
+#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181
+extern struct elem_info wlfw_cal_update_resp_msg_v01_ei[];
+
+struct wlfw_msa_info_req_msg_v01 {
+ u64 msa_addr;
+ u32 size;
+};
+
+#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_msa_info_req_msg_v01_ei[];
+
+struct wlfw_msa_info_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u32 mem_region_info_len;
+ struct wlfw_memory_region_info_s_v01
+ mem_region_info[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
+};
+
+#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37
+extern struct elem_info wlfw_msa_info_resp_msg_v01_ei[];
+
+struct wlfw_msa_ready_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_msa_ready_req_msg_v01_ei[];
+
+struct wlfw_msa_ready_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_msa_ready_resp_msg_v01_ei[];
+
+struct wlfw_ini_req_msg_v01 {
+ u8 enablefwlog_valid;
+ u8 enablefwlog;
+};
+
+#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct elem_info wlfw_ini_req_msg_v01_ei[];
+
+struct wlfw_ini_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_ini_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_read_req_msg_v01 {
+ u32 offset;
+ u32 mem_type;
+ u32 data_len;
+};
+
+#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21
+extern struct elem_info wlfw_athdiag_read_req_msg_v01_ei[];
+
+struct wlfw_athdiag_read_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
+extern struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_write_req_msg_v01 {
+ u32 offset;
+ u32 mem_type;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
+extern struct elem_info wlfw_athdiag_write_req_msg_v01_ei[];
+
+struct wlfw_athdiag_write_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[];
+
+struct wlfw_vbatt_req_msg_v01 {
+ u64 voltage_uv;
+};
+
+#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_vbatt_req_msg_v01_ei[];
+
+struct wlfw_vbatt_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_vbatt_resp_msg_v01_ei[];
+
+struct wlfw_mac_addr_req_msg_v01 {
+ u8 mac_addr_valid;
+ u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01];
+};
+
+#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9
+extern struct elem_info wlfw_mac_addr_req_msg_v01_ei[];
+
+struct wlfw_mac_addr_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[];
+
+struct wlfw_host_cap_req_msg_v01 {
+ u8 daemon_support_valid;
+ u8 daemon_support;
+ u8 wake_msi_valid;
+ u32 wake_msi;
+};
+
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_host_cap_req_msg_v01_ei[];
+
+struct wlfw_host_cap_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_host_cap_resp_msg_v01_ei[];
+
+struct wlfw_request_mem_ind_msg_v01 {
+ u32 size;
+};
+
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_request_mem_ind_msg_v01_ei[];
+
+struct wlfw_respond_mem_req_msg_v01 {
+ u64 addr;
+ u32 size;
+};
+
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_respond_mem_req_msg_v01_ei[];
+
+struct wlfw_respond_mem_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_respond_mem_resp_msg_v01_ei[];
+
+struct wlfw_fw_mem_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[];
+
+struct wlfw_cold_boot_cal_done_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_COLD_BOOT_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ind_msg_v01 {
+ u8 cause_for_rejuvenation_valid;
+ u8 cause_for_rejuvenation;
+ u8 requesting_sub_system_valid;
+ u8 requesting_sub_system;
+ u8 line_number_valid;
+ u16 line_number;
+ u8 function_name_valid;
+ char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
+};
+
+#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144
+extern struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_req_msg_v01 {
+ u8 mask_valid;
+ u64 mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 prev_mask_valid;
+ u64 prev_mask;
+ u8 curr_mask_valid;
+ u64 curr_mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29
+extern struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[];
+
+struct wlfw_m3_info_req_msg_v01 {
+ u64 addr;
+ u32 size;
+};
+
+#define WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_m3_info_req_msg_v01_ei[];
+
+struct wlfw_m3_info_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_m3_info_resp_msg_v01_ei[];
+
+struct wlfw_xo_cal_ind_msg_v01 {
+ u8 xo_cal_data;
+};
+
+#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
+extern struct elem_info wlfw_xo_cal_ind_msg_v01_ei[];
+
+#endif
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index eb05f5ef..69c8cb0 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -36,6 +36,7 @@
#include <linux/reset.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
+#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
@@ -121,6 +122,15 @@
#define PCIE20_PLR_IATU_LTAR 0x918
#define PCIE20_PLR_IATU_UTAR 0x91c
+#define PCIE_IATU_BASE(n) (n * 0x200)
+
+#define PCIE_IATU_CTRL1(n) (PCIE_IATU_BASE(n) + 0x00)
+#define PCIE_IATU_CTRL2(n) (PCIE_IATU_BASE(n) + 0x04)
+#define PCIE_IATU_LBAR(n) (PCIE_IATU_BASE(n) + 0x08)
+#define PCIE_IATU_UBAR(n) (PCIE_IATU_BASE(n) + 0x0c)
+#define PCIE_IATU_LAR(n) (PCIE_IATU_BASE(n) + 0x10)
+#define PCIE_IATU_LTAR(n) (PCIE_IATU_BASE(n) + 0x14)
+#define PCIE_IATU_UTAR(n) (PCIE_IATU_BASE(n) + 0x18)
#define PCIE20_PORT_LINK_CTRL_REG 0x710
#define PCIE20_GEN3_RELATED_REG 0x890
@@ -177,7 +187,7 @@
#define MAX_PROP_SIZE 32
#define MAX_RC_NAME_LEN 15
#define MSM_PCIE_MAX_VREG 4
-#define MSM_PCIE_MAX_CLK 12
+#define MSM_PCIE_MAX_CLK 13
#define MSM_PCIE_MAX_PIPE_CLK 1
#define MAX_RC_NUM 3
#define MAX_DEVICE_NUM 20
@@ -185,7 +195,6 @@
#define PCIE_TLP_RD_SIZE 0x5
#define PCIE_MSI_NR_IRQS 256
#define MSM_PCIE_MAX_MSI 32
-#define MAX_MSG_LEN 80
#define PCIE_LOG_PAGES (50)
#define PCIE_CONF_SPACE_DW 1024
#define PCIE_CLEAR 0xDEADBEEF
@@ -217,6 +226,9 @@
#endif
#define PCIE_LOWER_ADDR(addr) ((u32)((addr) & 0xffffffff))
+#define PCIE_BUS_PRIV_DATA(bus) \
+ (struct msm_pcie_dev_t *)(bus->sysdata)
+
/* Config Space Offsets */
#define BDF_OFFSET(bus, devfn) \
((bus << 24) | (devfn << 16))
@@ -287,6 +299,7 @@
MSM_PCIE_RES_PHY,
MSM_PCIE_RES_DM_CORE,
MSM_PCIE_RES_ELBI,
+ MSM_PCIE_RES_IATU,
MSM_PCIE_RES_CONF,
MSM_PCIE_RES_IO,
MSM_PCIE_RES_BARS,
@@ -363,6 +376,76 @@
MSM_PCIE_NO_WAKE_ENUMERATION = BIT(1)
};
+enum msm_pcie_debugfs_option {
+ MSM_PCIE_OUTPUT_PCIE_INFO,
+ MSM_PCIE_DISABLE_LINK,
+ MSM_PCIE_ENABLE_LINK,
+ MSM_PCIE_DISABLE_ENABLE_LINK,
+ MSM_PCIE_DUMP_SHADOW_REGISTER,
+ MSM_PCIE_DISABLE_L0S,
+ MSM_PCIE_ENABLE_L0S,
+ MSM_PCIE_DISABLE_L1,
+ MSM_PCIE_ENABLE_L1,
+ MSM_PCIE_DISABLE_L1SS,
+ MSM_PCIE_ENABLE_L1SS,
+ MSM_PCIE_ENUMERATION,
+ MSM_PCIE_READ_PCIE_REGISTER,
+ MSM_PCIE_WRITE_PCIE_REGISTER,
+ MSM_PCIE_DUMP_PCIE_REGISTER_SPACE,
+ MSM_PCIE_ALLOCATE_DDR_MAP_LBAR,
+ MSM_PCIE_FREE_DDR_UNMAP_LBAR,
+ MSM_PCIE_OUTPUT_DDR_LBAR_ADDRESS,
+ MSM_PCIE_CONFIGURE_LOOPBACK,
+ MSM_PCIE_SETUP_LOOPBACK_IATU,
+ MSM_PCIE_READ_DDR,
+ MSM_PCIE_READ_LBAR,
+ MSM_PCIE_WRITE_DDR,
+ MSM_PCIE_WRITE_LBAR,
+ MSM_PCIE_DISABLE_AER,
+ MSM_PCIE_ENABLE_AER,
+ MSM_PCIE_GPIO_STATUS,
+ MSM_PCIE_ASSERT_PERST,
+ MSM_PCIE_DEASSERT_PERST,
+ MSM_PCIE_KEEP_RESOURCES_ON,
+ MSM_PCIE_FORCE_GEN1,
+ MSM_PCIE_MAX_DEBUGFS_OPTION
+};
+
+static const char * const
+ msm_pcie_debugfs_option_desc[MSM_PCIE_MAX_DEBUGFS_OPTION] = {
+ "OUTPUT PCIE INFO",
+ "DISABLE LINK",
+ "ENABLE LINK",
+ "DISABLE AND ENABLE LINK",
+ "DUMP PCIE SHADOW REGISTER",
+ "DISABLE L0S",
+ "ENABLE L0S",
+ "DISABLE L1",
+ "ENABLE L1",
+ "DISABLE L1SS",
+ "ENABLE L1SS",
+ "ENUMERATE",
+ "READ A PCIE REGISTER",
+ "WRITE TO PCIE REGISTER",
+ "DUMP PCIE REGISTER SPACE",
+ "ALLOCATE DDR AND MAP LBAR",
+ "FREE DDR AND UNMAP LBAR",
+ "OUTPUT DDR AND LBAR VIR ADDRESS",
+ "CONFIGURE PCIE LOOPBACK",
+ "SETUP LOOPBACK IATU",
+ "READ DDR",
+ "READ LBAR",
+ "WRITE DDR",
+ "WRITE LBAR",
+ "SET AER ENABLE FLAG",
+ "CLEAR AER ENABLE FLAG",
+ "OUTPUT PERST AND WAKE GPIO STATUS",
+ "ASSERT PERST",
+ "DE-ASSERT PERST",
+ "SET KEEP_RESOURCES_ON FLAG",
+ "FORCE GEN 1 SPEED FOR LINK TRAINING"
+};
+
/* gpio info structure */
struct msm_pcie_gpio_info_t {
char *name;
@@ -452,6 +535,7 @@
void __iomem *parf;
void __iomem *phy;
void __iomem *elbi;
+ void __iomem *iatu;
void __iomem *dm_core;
void __iomem *conf;
void __iomem *bars;
@@ -520,10 +604,8 @@
bool enumerated;
struct work_struct handle_wake_work;
struct mutex recovery_lock;
- spinlock_t linkdown_lock;
spinlock_t wakeup_lock;
- spinlock_t global_irq_lock;
- spinlock_t aer_lock;
+ spinlock_t irq_lock;
ulong linkdown_counter;
ulong link_turned_on_counter;
ulong link_turned_off_counter;
@@ -589,13 +671,32 @@
module_param_named(keep_resources_on, msm_pcie_keep_resources_on,
int, 0644);
+/*
+ * For each bit set, force the corresponding root complex
+ * to do link training at gen1 speed.
+ */
+static int msm_pcie_force_gen1;
+module_param_named(force_gen1, msm_pcie_force_gen1,
+ int, 0644);
+
+
+/*
+ * For each bit set in BIT[3:0] determines which corresponding
+ * root complex will use the value in BIT[31:4] to override the
+ * default (LINK_UP_CHECK_MAX_COUNT) max check count for link training.
+ * Each iteration is LINK_UP_TIMEOUT_US_MIN long.
+ */
+static int msm_pcie_link_check_max_count;
+module_param_named(link_check_max_count, msm_pcie_link_check_max_count,
+ int, 0644);
+
/* debugfs values */
-static u32 rc_sel;
+static u32 rc_sel = BIT(0);
static u32 base_sel;
static u32 wr_offset;
static u32 wr_mask;
static u32 wr_value;
-static ulong corr_counter_limit = 5;
+static u32 corr_counter_limit = 5;
/* Table to track info of PCIe devices */
static struct msm_pcie_device_info
@@ -677,6 +778,7 @@
{NULL, "pcie_0_ldo", 0, false, true},
{NULL, "pcie_0_smmu_clk", 0, false, false},
{NULL, "pcie_0_slv_q2a_axi_clk", 0, false, false},
+ {NULL, "pcie_0_sleep_clk", 0, false, false},
{NULL, "pcie_phy_refgen_clk", 0, false, false},
{NULL, "pcie_tbu_clk", 0, false, false},
{NULL, "pcie_phy_cfg_ahb_clk", 0, false, false},
@@ -691,6 +793,7 @@
{NULL, "pcie_1_ldo", 0, false, true},
{NULL, "pcie_1_smmu_clk", 0, false, false},
{NULL, "pcie_1_slv_q2a_axi_clk", 0, false, false},
+ {NULL, "pcie_1_sleep_clk", 0, false, false},
{NULL, "pcie_phy_refgen_clk", 0, false, false},
{NULL, "pcie_tbu_clk", 0, false, false},
{NULL, "pcie_phy_cfg_ahb_clk", 0, false, false},
@@ -705,6 +808,7 @@
{NULL, "pcie_2_ldo", 0, false, true},
{NULL, "pcie_2_smmu_clk", 0, false, false},
{NULL, "pcie_2_slv_q2a_axi_clk", 0, false, false},
+ {NULL, "pcie_2_sleep_clk", 0, false, false},
{NULL, "pcie_phy_refgen_clk", 0, false, false},
{NULL, "pcie_tbu_clk", 0, false, false},
{NULL, "pcie_phy_cfg_ahb_clk", 0, false, false},
@@ -732,6 +836,7 @@
{"phy", NULL, NULL},
{"dm_core", NULL, NULL},
{"elbi", NULL, NULL},
+ {"iatu", NULL, NULL},
{"conf", NULL, NULL},
{"io", NULL, NULL},
{"bars", NULL, NULL},
@@ -768,36 +873,21 @@
};
static int msm_pcie_config_device(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l0s_disable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l0s_enable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1_disable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1_enable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1ss_disable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1ss_enable(struct pci_dev *dev, void *pdev);
static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev,
struct pci_dev *pdev, bool enable);
#ifdef CONFIG_ARM
-#define PCIE_BUS_PRIV_DATA(bus) \
- (((struct pci_sys_data *)bus->sysdata)->private_data)
-
-static struct pci_sys_data msm_pcie_sys_data[MAX_RC_NUM];
-
-static inline void *msm_pcie_setup_sys_data(struct msm_pcie_dev_t *dev)
-{
- msm_pcie_sys_data[dev->rc_idx].domain = dev->rc_idx;
- msm_pcie_sys_data[dev->rc_idx].private_data = dev;
-
- return &msm_pcie_sys_data[dev->rc_idx];
-}
-
static inline void msm_pcie_fixup_irqs(struct msm_pcie_dev_t *dev)
{
pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
}
#else
-#define PCIE_BUS_PRIV_DATA(bus) \
- (struct msm_pcie_dev_t *)(bus->sysdata)
-
-static inline void *msm_pcie_setup_sys_data(struct msm_pcie_dev_t *dev)
-{
- return dev;
-}
-
static inline void msm_pcie_fixup_irqs(struct msm_pcie_dev_t *dev)
{
}
@@ -1236,56 +1326,24 @@
static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
u32 testcase)
{
- phys_addr_t dbi_base_addr =
- dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
+ u32 dbi_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
phys_addr_t loopback_lbar_phy =
- dbi_base_addr + LOOPBACK_BASE_ADDR_OFFSET;
+ dev->res[MSM_PCIE_RES_DM_CORE].resource->start +
+ LOOPBACK_BASE_ADDR_OFFSET;
static uint32_t loopback_val = 0x1;
- static u64 loopback_ddr_phy;
+ static dma_addr_t loopback_ddr_phy;
static uint32_t *loopback_ddr_vir;
static void __iomem *loopback_lbar_vir;
int ret, i;
u32 base_sel_size = 0;
- u32 val = 0;
- u32 current_offset = 0;
- u32 ep_l1sub_ctrl1_offset = 0;
- u32 ep_l1sub_cap_reg1_offset = 0;
- u32 ep_link_ctrlstts_offset = 0;
- u32 ep_dev_ctrl2stts2_offset = 0;
-
- if (testcase >= 5 && testcase <= 10) {
- current_offset =
- readl_relaxed(dev->conf + PCIE_CAP_PTR_OFFSET) & 0xff;
-
- while (current_offset) {
- val = readl_relaxed(dev->conf + current_offset);
- if ((val & 0xff) == PCIE20_CAP_ID) {
- ep_link_ctrlstts_offset = current_offset +
- 0x10;
- ep_dev_ctrl2stts2_offset = current_offset +
- 0x28;
- break;
- }
- current_offset = (val >> 8) & 0xff;
- }
-
- if (!ep_link_ctrlstts_offset)
- PCIE_DBG(dev,
- "RC%d endpoint does not support PCIe capability registers\n",
- dev->rc_idx);
- else
- PCIE_DBG(dev,
- "RC%d: ep_link_ctrlstts_offset: 0x%x\n",
- dev->rc_idx, ep_link_ctrlstts_offset);
- }
switch (testcase) {
- case 0: /* output status */
+ case MSM_PCIE_OUTPUT_PCIE_INFO:
PCIE_DBG_FS(dev, "\n\nPCIe: Status for RC%d:\n",
dev->rc_idx);
msm_pcie_show_status(dev);
break;
- case 1: /* disable link */
+ case MSM_PCIE_DISABLE_LINK:
PCIE_DBG_FS(dev,
"\n\nPCIe: RC%d: disable link\n\n", dev->rc_idx);
ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0,
@@ -1298,7 +1356,7 @@
PCIE_DBG_FS(dev, "PCIe:%s:disabled link\n",
__func__);
break;
- case 2: /* enable link and recover config space for RC and EP */
+ case MSM_PCIE_ENABLE_LINK:
PCIE_DBG_FS(dev,
"\n\nPCIe: RC%d: enable link and recover config space\n\n",
dev->rc_idx);
@@ -1313,10 +1371,7 @@
msm_pcie_recover_config(dev->dev);
}
break;
- case 3: /*
- * disable and enable link, recover config space for
- * RC and EP
- */
+ case MSM_PCIE_DISABLE_ENABLE_LINK:
PCIE_DBG_FS(dev,
"\n\nPCIe: RC%d: disable and enable link then recover config space\n\n",
dev->rc_idx);
@@ -1339,7 +1394,7 @@
msm_pcie_recover_config(dev->dev);
}
break;
- case 4: /* dump shadow registers for RC and EP */
+ case MSM_PCIE_DUMP_SHADOW_REGISTER:
PCIE_DBG_FS(dev,
"\n\nPCIe: RC%d: dumping RC shadow registers\n",
dev->rc_idx);
@@ -1350,236 +1405,97 @@
dev->rc_idx);
msm_pcie_shadow_dump(dev, false);
break;
- case 5: /* disable L0s */
+ case MSM_PCIE_DISABLE_L0S:
PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n",
dev->rc_idx);
- msm_pcie_write_mask(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS,
- BIT(0), 0);
- msm_pcie_write_mask(dev->conf +
- ep_link_ctrlstts_offset,
- BIT(0), 0);
- if (dev->shadow_en) {
- dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS);
- dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset);
+ if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+ struct pci_bus *bus, *c_bus;
+ struct list_head *children = &dev->dev->bus->children;
+
+ msm_pcie_config_l0s_disable(dev->dev, dev);
+
+ list_for_each_entry_safe(bus, c_bus, children, node)
+ pci_walk_bus(bus,
+ &msm_pcie_config_l0s_disable, dev);
}
- PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS));
- PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset));
+ dev->l0s_supported = false;
break;
- case 6: /* enable L0s */
+ case MSM_PCIE_ENABLE_L0S:
PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L0s\n\n",
dev->rc_idx);
- msm_pcie_write_mask(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS,
- 0, BIT(0));
- msm_pcie_write_mask(dev->conf +
- ep_link_ctrlstts_offset,
- 0, BIT(0));
- if (dev->shadow_en) {
- dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS);
- dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset);
+ dev->l0s_supported = true;
+ if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+ struct pci_bus *bus, *c_bus;
+ struct list_head *children = &dev->dev->bus->children;
+
+ list_for_each_entry_safe(bus, c_bus, children, node)
+ pci_walk_bus(bus,
+ &msm_pcie_config_l0s_enable, dev);
+
+ msm_pcie_config_l0s_enable(dev->dev, dev);
}
- PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS));
- PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset));
break;
- case 7: /* disable L1 */
+ case MSM_PCIE_DISABLE_L1:
PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1\n\n",
dev->rc_idx);
- msm_pcie_write_mask(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS,
- BIT(1), 0);
- msm_pcie_write_mask(dev->conf +
- ep_link_ctrlstts_offset,
- BIT(1), 0);
- if (dev->shadow_en) {
- dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS);
- dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset);
+ if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+ struct pci_bus *bus, *c_bus;
+ struct list_head *children = &dev->dev->bus->children;
+
+ msm_pcie_config_l1_disable(dev->dev, dev);
+
+ list_for_each_entry_safe(bus, c_bus, children, node)
+ pci_walk_bus(bus,
+ &msm_pcie_config_l1_disable, dev);
}
- PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS));
- PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset));
+ dev->l1_supported = false;
break;
- case 8: /* enable L1 */
+ case MSM_PCIE_ENABLE_L1:
PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1\n\n",
dev->rc_idx);
- msm_pcie_write_mask(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS,
- 0, BIT(1));
- msm_pcie_write_mask(dev->conf +
- ep_link_ctrlstts_offset,
- 0, BIT(1));
- if (dev->shadow_en) {
- dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS);
- dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset);
+ dev->l1_supported = true;
+ if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+ struct pci_bus *bus, *c_bus;
+ struct list_head *children = &dev->dev->bus->children;
+
+ list_for_each_entry_safe(bus, c_bus, children, node)
+ pci_walk_bus(bus,
+ &msm_pcie_config_l1_enable, dev);
+
+ msm_pcie_config_l1_enable(dev->dev, dev);
}
- PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_CAP_LINKCTRLSTATUS));
- PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
- readl_relaxed(dev->conf +
- ep_link_ctrlstts_offset));
break;
- case 9: /* disable L1ss */
+ case MSM_PCIE_DISABLE_L1SS:
PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1ss\n\n",
dev->rc_idx);
- current_offset = PCIE_EXT_CAP_OFFSET;
- while (current_offset) {
- val = readl_relaxed(dev->conf + current_offset);
- if ((val & 0xffff) == L1SUB_CAP_ID) {
- ep_l1sub_ctrl1_offset =
- current_offset + 0x8;
- break;
- }
- current_offset = val >> 20;
- }
- if (!ep_l1sub_ctrl1_offset) {
- PCIE_DBG_FS(dev,
- "PCIe: RC%d endpoint does not support l1ss registers\n",
- dev->rc_idx);
- break;
- }
+ if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+ struct pci_bus *bus, *c_bus;
+ struct list_head *children = &dev->dev->bus->children;
- PCIE_DBG_FS(dev, "PCIe: RC%d: ep_l1sub_ctrl1_offset: 0x%x\n",
- dev->rc_idx, ep_l1sub_ctrl1_offset);
+ msm_pcie_config_l1ss_disable(dev->dev, dev);
- msm_pcie_write_reg_field(dev->dm_core,
- PCIE20_L1SUB_CONTROL1,
- 0xf, 0);
- msm_pcie_write_mask(dev->dm_core +
- PCIE20_DEVICE_CONTROL2_STATUS2,
- BIT(10), 0);
- msm_pcie_write_reg_field(dev->conf,
- ep_l1sub_ctrl1_offset,
- 0xf, 0);
- msm_pcie_write_mask(dev->conf +
- ep_dev_ctrl2stts2_offset,
- BIT(10), 0);
- if (dev->shadow_en) {
- dev->rc_shadow[PCIE20_L1SUB_CONTROL1 / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_L1SUB_CONTROL1);
- dev->rc_shadow[PCIE20_DEVICE_CONTROL2_STATUS2 / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_DEVICE_CONTROL2_STATUS2);
- dev->ep_shadow[0][ep_l1sub_ctrl1_offset / 4] =
- readl_relaxed(dev->conf +
- ep_l1sub_ctrl1_offset);
- dev->ep_shadow[0][ep_dev_ctrl2stts2_offset / 4] =
- readl_relaxed(dev->conf +
- ep_dev_ctrl2stts2_offset);
+ list_for_each_entry_safe(bus, c_bus, children, node)
+ pci_walk_bus(bus,
+ &msm_pcie_config_l1ss_disable, dev);
}
- PCIE_DBG_FS(dev, "PCIe: RC's L1SUB_CONTROL1:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_L1SUB_CONTROL1));
- PCIE_DBG_FS(dev, "PCIe: RC's DEVICE_CONTROL2_STATUS2:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_DEVICE_CONTROL2_STATUS2));
- PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CONTROL1:0x%x\n",
- readl_relaxed(dev->conf +
- ep_l1sub_ctrl1_offset));
- PCIE_DBG_FS(dev, "PCIe: EP's DEVICE_CONTROL2_STATUS2:0x%x\n",
- readl_relaxed(dev->conf +
- ep_dev_ctrl2stts2_offset));
+ dev->l1ss_supported = false;
break;
- case 10: /* enable L1ss */
+ case MSM_PCIE_ENABLE_L1SS:
PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1ss\n\n",
dev->rc_idx);
- current_offset = PCIE_EXT_CAP_OFFSET;
- while (current_offset) {
- val = readl_relaxed(dev->conf + current_offset);
- if ((val & 0xffff) == L1SUB_CAP_ID) {
- ep_l1sub_cap_reg1_offset =
- current_offset + 0x4;
- ep_l1sub_ctrl1_offset =
- current_offset + 0x8;
- break;
- }
- current_offset = val >> 20;
+ dev->l1ss_supported = true;
+ if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+ struct pci_bus *bus, *c_bus;
+ struct list_head *children = &dev->dev->bus->children;
+
+ list_for_each_entry_safe(bus, c_bus, children, node)
+ pci_walk_bus(bus,
+ &msm_pcie_config_l1ss_enable, dev);
+
+ msm_pcie_config_l1ss_enable(dev->dev, dev);
}
- if (!ep_l1sub_ctrl1_offset) {
- PCIE_DBG_FS(dev,
- "PCIe: RC%d endpoint does not support l1ss registers\n",
- dev->rc_idx);
- break;
- }
-
- val = readl_relaxed(dev->conf +
- ep_l1sub_cap_reg1_offset);
-
- PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CAPABILITY_REG_1: 0x%x\n",
- val);
- PCIE_DBG_FS(dev, "PCIe: RC%d: ep_l1sub_ctrl1_offset: 0x%x\n",
- dev->rc_idx, ep_l1sub_ctrl1_offset);
-
- val &= 0xf;
-
- msm_pcie_write_reg_field(dev->dm_core,
- PCIE20_L1SUB_CONTROL1,
- 0xf, val);
- msm_pcie_write_mask(dev->dm_core +
- PCIE20_DEVICE_CONTROL2_STATUS2,
- 0, BIT(10));
- msm_pcie_write_reg_field(dev->conf,
- ep_l1sub_ctrl1_offset,
- 0xf, val);
- msm_pcie_write_mask(dev->conf +
- ep_dev_ctrl2stts2_offset,
- 0, BIT(10));
- if (dev->shadow_en) {
- dev->rc_shadow[PCIE20_L1SUB_CONTROL1 / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_L1SUB_CONTROL1);
- dev->rc_shadow[PCIE20_DEVICE_CONTROL2_STATUS2 / 4] =
- readl_relaxed(dev->dm_core +
- PCIE20_DEVICE_CONTROL2_STATUS2);
- dev->ep_shadow[0][ep_l1sub_ctrl1_offset / 4] =
- readl_relaxed(dev->conf +
- ep_l1sub_ctrl1_offset);
- dev->ep_shadow[0][ep_dev_ctrl2stts2_offset / 4] =
- readl_relaxed(dev->conf +
- ep_dev_ctrl2stts2_offset);
- }
- PCIE_DBG_FS(dev, "PCIe: RC's L1SUB_CONTROL1:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_L1SUB_CONTROL1));
- PCIE_DBG_FS(dev, "PCIe: RC's DEVICE_CONTROL2_STATUS2:0x%x\n",
- readl_relaxed(dev->dm_core +
- PCIE20_DEVICE_CONTROL2_STATUS2));
- PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CONTROL1:0x%x\n",
- readl_relaxed(dev->conf +
- ep_l1sub_ctrl1_offset));
- PCIE_DBG_FS(dev, "PCIe: EP's DEVICE_CONTROL2_STATUS2:0x%x\n",
- readl_relaxed(dev->conf +
- ep_dev_ctrl2stts2_offset));
break;
- case 11: /* enumerate PCIe */
+ case MSM_PCIE_ENUMERATION:
PCIE_DBG_FS(dev, "\n\nPCIe: attempting to enumerate RC%d\n\n",
dev->rc_idx);
if (dev->enumerated)
@@ -1596,7 +1512,41 @@
dev->rc_idx);
}
break;
- case 12: /* write a value to a register */
+ case MSM_PCIE_READ_PCIE_REGISTER:
+ PCIE_DBG_FS(dev,
+ "\n\nPCIe: RC%d: read a PCIe register\n\n",
+ dev->rc_idx);
+ if (!base_sel) {
+ PCIE_DBG_FS(dev, "Invalid base_sel: 0x%x\n", base_sel);
+ break;
+ }
+
+ PCIE_DBG_FS(dev, "base: %s: 0x%pK\nwr_offset: 0x%x\n",
+ dev->res[base_sel - 1].name,
+ dev->res[base_sel - 1].base,
+ wr_offset);
+
+ base_sel_size = resource_size(dev->res[base_sel - 1].resource);
+
+ if (wr_offset > base_sel_size - 4 ||
+ msm_pcie_check_align(dev, wr_offset)) {
+ PCIE_DBG_FS(dev,
+ "PCIe: RC%d: Invalid wr_offset: 0x%x. wr_offset should be no more than 0x%x\n",
+ dev->rc_idx, wr_offset, base_sel_size - 4);
+ } else {
+ phys_addr_t wr_register =
+ dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
+
+ wr_register += wr_offset;
+ PCIE_DBG_FS(dev,
+ "PCIe: RC%d: register: 0x%pa value: 0x%x\n",
+ dev->rc_idx, &wr_register,
+ readl_relaxed(dev->res[base_sel - 1].base +
+ wr_offset));
+ }
+
+ break;
+ case MSM_PCIE_WRITE_PCIE_REGISTER:
PCIE_DBG_FS(dev,
"\n\nPCIe: RC%d: writing a value to a register\n\n",
dev->rc_idx);
@@ -1607,7 +1557,7 @@
}
PCIE_DBG_FS(dev,
- "base: %s: 0x%p\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n",
+ "base: %s: 0x%pK\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n",
dev->res[base_sel - 1].name,
dev->res[base_sel - 1].base,
wr_offset, wr_mask, wr_value);
@@ -1624,7 +1574,7 @@
wr_offset, wr_mask, wr_value);
break;
- case 13: /* dump all registers of base_sel */
+ case MSM_PCIE_DUMP_PCIE_REGISTER_SPACE:
if (!base_sel) {
PCIE_DBG_FS(dev, "Invalid base_sel: 0x%x\n", base_sel);
break;
@@ -1657,7 +1607,7 @@
readl_relaxed(dev->res[base_sel - 1].base + (i + 28)));
}
break;
- case 14:
+ case MSM_PCIE_ALLOCATE_DDR_MAP_LBAR:
PCIE_DBG_FS(dev,
"PCIe: RC%d: Allocate 4K DDR memory and map LBAR.\n",
dev->rc_idx);
@@ -1673,25 +1623,25 @@
"PCIe: RC%d: VIR DDR memory address: 0x%pK\n",
dev->rc_idx, loopback_ddr_vir);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PHY DDR memory address: 0x%llx\n",
- dev->rc_idx, loopback_ddr_phy);
+ "PCIe: RC%d: PHY DDR memory address: %pad\n",
+ dev->rc_idx, &loopback_ddr_phy);
}
- PCIE_DBG_FS(dev, "PCIe: RC%d: map LBAR: 0x%llx\n",
- dev->rc_idx, loopback_lbar_phy);
+ PCIE_DBG_FS(dev, "PCIe: RC%d: map LBAR: %pa\n",
+ dev->rc_idx, &loopback_lbar_phy);
loopback_lbar_vir = devm_ioremap(&dev->pdev->dev,
loopback_lbar_phy, SZ_4K);
if (!loopback_lbar_vir) {
- PCIE_DBG_FS(dev, "PCIe: RC%d: failed to map 0x%llx\n",
- dev->rc_idx, loopback_lbar_phy);
+ PCIE_DBG_FS(dev, "PCIe: RC%d: failed to map %pa\n",
+ dev->rc_idx, &loopback_lbar_phy);
} else {
PCIE_DBG_FS(dev,
- "PCIe: RC%d: successfully mapped 0x%llx to 0x%pK\n",
- dev->rc_idx, loopback_lbar_phy,
+ "PCIe: RC%d: successfully mapped %pa to 0x%pK\n",
+ dev->rc_idx, &loopback_lbar_phy,
loopback_lbar_vir);
}
break;
- case 15:
+ case MSM_PCIE_FREE_DDR_UNMAP_LBAR:
PCIE_DBG_FS(dev,
"PCIe: RC%d: Release 4K DDR memory and unmap LBAR.\n",
dev->rc_idx);
@@ -1708,7 +1658,7 @@
loopback_lbar_vir = NULL;
}
break;
- case 16:
+ case MSM_PCIE_OUTPUT_DDR_LBAR_ADDRESS:
PCIE_DBG_FS(dev,
"PCIe: RC%d: Print DDR and LBAR addresses.\n",
dev->rc_idx);
@@ -1721,19 +1671,19 @@
}
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PHY DDR address: 0x%llx\n",
- dev->rc_idx, loopback_ddr_phy);
+ "PCIe: RC%d: PHY DDR address: %pad\n",
+ dev->rc_idx, &loopback_ddr_phy);
PCIE_DBG_FS(dev,
"PCIe: RC%d: VIR DDR address: 0x%pK\n",
dev->rc_idx, loopback_ddr_vir);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PHY LBAR address: 0x%llx\n",
- dev->rc_idx, loopback_lbar_phy);
+ "PCIe: RC%d: PHY LBAR address: %pa\n",
+ dev->rc_idx, &loopback_lbar_phy);
PCIE_DBG_FS(dev,
"PCIe: RC%d: VIR LBAR address: 0x%pK\n",
dev->rc_idx, loopback_lbar_vir);
break;
- case 17:
+ case MSM_PCIE_CONFIGURE_LOOPBACK:
PCIE_DBG_FS(dev,
"PCIe: RC%d: Configure Loopback.\n",
dev->rc_idx);
@@ -1741,7 +1691,7 @@
writel_relaxed(0x10000,
dev->dm_core + PCIE20_GEN3_RELATED_REG);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: 0x%llx: 0x%x\n",
+ "PCIe: RC%d: 0x%x: 0x%x\n",
dev->rc_idx,
dbi_base_addr + PCIE20_GEN3_RELATED_REG,
readl_relaxed(dev->dm_core +
@@ -1750,7 +1700,7 @@
writel_relaxed(0x80000001,
dev->dm_core + PCIE20_PIPE_LOOPBACK_CONTROL);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: 0x%llx: 0x%x\n",
+ "PCIe: RC%d: 0x%x: 0x%x\n",
dev->rc_idx,
dbi_base_addr + PCIE20_PIPE_LOOPBACK_CONTROL,
readl_relaxed(dev->dm_core +
@@ -1759,13 +1709,13 @@
writel_relaxed(0x00010124,
dev->dm_core + PCIE20_PORT_LINK_CTRL_REG);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: 0x%llx: 0x%x\n",
+ "PCIe: RC%d: 0x%x: 0x%x\n",
dev->rc_idx,
dbi_base_addr + PCIE20_PORT_LINK_CTRL_REG,
readl_relaxed(dev->dm_core +
PCIE20_PORT_LINK_CTRL_REG));
break;
- case 18:
+ case MSM_PCIE_SETUP_LOOPBACK_IATU:
PCIE_DBG_FS(dev, "PCIe: RC%d: Setup iATU.\n", dev->rc_idx);
if (!loopback_ddr_vir) {
@@ -1777,57 +1727,57 @@
writel_relaxed(0x0, dev->dm_core + PCIE20_PLR_IATU_VIEWPORT);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_VIEWPORT:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_VIEWPORT:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_VIEWPORT,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_VIEWPORT));
writel_relaxed(0x0, dev->dm_core + PCIE20_PLR_IATU_CTRL1);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_CTRL1:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_CTRL1:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_CTRL1,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL1));
writel_relaxed(loopback_lbar_phy,
dev->dm_core + PCIE20_PLR_IATU_LBAR);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_LBAR:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_LBAR:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_LBAR,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LBAR));
writel_relaxed(0x0, dev->dm_core + PCIE20_PLR_IATU_UBAR);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_UBAR:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_UBAR:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_UBAR,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UBAR));
writel_relaxed(loopback_lbar_phy + 0xfff,
dev->dm_core + PCIE20_PLR_IATU_LAR);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_LAR:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_LAR:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_LAR,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LAR));
writel_relaxed(loopback_ddr_phy,
dev->dm_core + PCIE20_PLR_IATU_LTAR);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_LTAR:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_LTAR:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_LTAR,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LTAR));
writel_relaxed(0, dev->dm_core + PCIE20_PLR_IATU_UTAR);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_UTAR:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_UTAR:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_UTAR,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UTAR));
writel_relaxed(0x80000000,
dev->dm_core + PCIE20_PLR_IATU_CTRL2);
PCIE_DBG_FS(dev,
- "PCIe: RC%d: PCIE20_PLR_IATU_CTRL2:\t0x%llx: 0x%x\n",
+ "PCIe: RC%d: PCIE20_PLR_IATU_CTRL2:\t0x%x: 0x%x\n",
dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_CTRL2,
readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL2));
break;
- case 19:
+ case MSM_PCIE_READ_DDR:
PCIE_DBG_FS(dev,
"PCIe: RC%d: Read DDR values.\n",
dev->rc_idx);
@@ -1853,7 +1803,7 @@
loopback_ddr_vir[i + 7]);
}
break;
- case 20:
+ case MSM_PCIE_READ_LBAR:
PCIE_DBG_FS(dev,
"PCIe: RC%d: Read LBAR values.\n",
dev->rc_idx);
@@ -1879,7 +1829,7 @@
readl_relaxed(loopback_lbar_vir + (i + 28)));
}
break;
- case 21:
+ case MSM_PCIE_WRITE_DDR:
PCIE_DBG_FS(dev, "PCIe: RC%d: Write 0x%x to DDR.\n",
dev->rc_idx, loopback_val);
@@ -1898,7 +1848,7 @@
else
loopback_val++;
break;
- case 22:
+ case MSM_PCIE_WRITE_LBAR:
PCIE_DBG_FS(dev, "PCIe: RC%d: Write 0x%x to LBAR.\n",
dev->rc_idx, loopback_val);
@@ -1933,6 +1883,53 @@
else
loopback_val++;
break;
+ case MSM_PCIE_DISABLE_AER:
+ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: clear AER enable flag\n\n",
+ dev->rc_idx);
+ dev->aer_enable = false;
+ break;
+ case MSM_PCIE_ENABLE_AER:
+ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: set AER enable flag\n\n",
+ dev->rc_idx);
+ dev->aer_enable = true;
+ break;
+ case MSM_PCIE_GPIO_STATUS:
+ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: PERST and WAKE status\n\n",
+ dev->rc_idx);
+ PCIE_DBG_FS(dev,
+ "PCIe: RC%d: PERST: gpio%u value: %d\n",
+ dev->rc_idx, dev->gpio[MSM_PCIE_GPIO_PERST].num,
+ gpio_get_value(dev->gpio[MSM_PCIE_GPIO_PERST].num));
+ PCIE_DBG_FS(dev,
+ "PCIe: RC%d: WAKE: gpio%u value: %d\n",
+ dev->rc_idx, dev->gpio[MSM_PCIE_GPIO_WAKE].num,
+ gpio_get_value(dev->gpio[MSM_PCIE_GPIO_WAKE].num));
+ break;
+ case MSM_PCIE_ASSERT_PERST:
+ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: assert PERST\n\n",
+ dev->rc_idx);
+ gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num,
+ dev->gpio[MSM_PCIE_GPIO_PERST].on);
+ usleep_range(dev->perst_delay_us_min, dev->perst_delay_us_max);
+ break;
+ case MSM_PCIE_DEASSERT_PERST:
+ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: de-assert PERST\n\n",
+ dev->rc_idx);
+ gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num,
+ 1 - dev->gpio[MSM_PCIE_GPIO_PERST].on);
+ usleep_range(dev->perst_delay_us_min, dev->perst_delay_us_max);
+ break;
+ case MSM_PCIE_KEEP_RESOURCES_ON:
+ PCIE_DBG_FS(dev,
+ "\n\nPCIe: RC%d: set keep resources on flag\n\n",
+ dev->rc_idx);
+ msm_pcie_keep_resources_on |= BIT(dev->rc_idx);
+ break;
+ case MSM_PCIE_FORCE_GEN1:
+ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: set force gen1 flag\n\n",
+ dev->rc_idx);
+ msm_pcie_force_gen1 |= BIT(dev->rc_idx);
+ break;
default:
PCIE_DBG_FS(dev, "Invalid testcase: %d.\n", testcase);
break;
@@ -1950,8 +1947,10 @@
return -ENODEV;
}
- if (option == 12 || option == 13) {
- if (!base || base > 5) {
+ if (option == MSM_PCIE_READ_PCIE_REGISTER ||
+ option == MSM_PCIE_WRITE_PCIE_REGISTER ||
+ option == MSM_PCIE_DUMP_PCIE_REGISTER_SPACE) {
+ if (!base || base >= MSM_PCIE_MAX_RES) {
PCIE_DBG_FS(pdev, "Invalid base_sel: 0x%x\n", base);
PCIE_DBG_FS(pdev,
"PCIe: base_sel is still 0x%x\n", base_sel);
@@ -1961,7 +1960,8 @@
base_sel = base;
PCIE_DBG_FS(pdev, "PCIe: base_sel is now 0x%x\n", base_sel);
- if (option == 12) {
+ if (option == MSM_PCIE_READ_PCIE_REGISTER ||
+ option == MSM_PCIE_WRITE_PCIE_REGISTER) {
wr_offset = offset;
wr_mask = mask;
wr_value = value;
@@ -1976,7 +1976,7 @@
}
pdev = PCIE_BUS_PRIV_DATA(dev->bus);
- rc_sel = 1 << pdev->rc_idx;
+ rc_sel = BIT(pdev->rc_idx);
msm_pcie_sel_debug_testcase(pdev, option);
@@ -2041,59 +2041,87 @@
static u32 rc_sel_max;
-static ssize_t msm_pcie_cmd_debug(struct file *file,
+static int msm_pcie_debugfs_parse_input(const char __user *buf,
+ size_t count, unsigned int *data)
+{
+ unsigned long ret;
+ char *str, *str_temp;
+
+ str = kmalloc(count + 1, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+
+ ret = copy_from_user(str, buf, count);
+ if (ret) {
+ kfree(str);
+ return -EFAULT;
+ }
+
+ str[count] = 0;
+ str_temp = str;
+
+ ret = get_option(&str_temp, data);
+ kfree(str);
+ if (ret != 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int msm_pcie_debugfs_case_show(struct seq_file *m, void *v)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_DEBUGFS_OPTION; i++)
+ seq_printf(m, "\t%d:\t %s\n", i,
+ msm_pcie_debugfs_option_desc[i]);
+
+ return 0;
+}
+
+static int msm_pcie_debugfs_case_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, msm_pcie_debugfs_case_show, NULL);
+}
+
+static ssize_t msm_pcie_debugfs_case_select(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
+ int i, ret;
unsigned int testcase = 0;
- int i;
- u32 size = sizeof(str) < count ? sizeof(str) : count;
- memset(str, 0, size);
- ret = copy_from_user(str, buf, size);
+ ret = msm_pcie_debugfs_parse_input(buf, count, &testcase);
if (ret)
- return -EFAULT;
-
- for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
- testcase = (testcase * 10) + (str[i] - '0');
-
- if (!rc_sel)
- rc_sel = 1;
+ return ret;
pr_alert("PCIe: TEST: %d\n", testcase);
for (i = 0; i < MAX_RC_NUM; i++) {
- if (!((rc_sel >> i) & 0x1))
- continue;
- msm_pcie_sel_debug_testcase(&msm_pcie_dev[i], testcase);
+ if (rc_sel & BIT(i))
+ msm_pcie_sel_debug_testcase(&msm_pcie_dev[i], testcase);
}
return count;
}
-static const struct file_operations msm_pcie_cmd_debug_ops = {
- .write = msm_pcie_cmd_debug,
+static const struct file_operations msm_pcie_debugfs_case_ops = {
+ .open = msm_pcie_debugfs_case_open,
+ .release = single_release,
+ .read = seq_read,
+ .write = msm_pcie_debugfs_case_select,
};
-static ssize_t msm_pcie_set_rc_sel(struct file *file,
+static ssize_t msm_pcie_debugfs_rc_select(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
- int i;
+ int i, ret;
u32 new_rc_sel = 0;
- u32 size = sizeof(str) < count ? sizeof(str) : count;
- memset(str, 0, size);
- ret = copy_from_user(str, buf, size);
+ ret = msm_pcie_debugfs_parse_input(buf, count, &new_rc_sel);
if (ret)
- return -EFAULT;
-
- for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
- new_rc_sel = (new_rc_sel * 10) + (str[i] - '0');
+ return ret;
if ((!new_rc_sel) || (new_rc_sel > rc_sel_max)) {
pr_alert("PCIe: invalid value for rc_sel: 0x%x\n", new_rc_sel);
@@ -2104,232 +2132,151 @@
}
pr_alert("PCIe: the following RC(s) will be tested:\n");
- for (i = 0; i < MAX_RC_NUM; i++) {
- if (!rc_sel) {
+ for (i = 0; i < MAX_RC_NUM; i++)
+ if (rc_sel & BIT(i))
pr_alert("RC %d\n", i);
- break;
- } else if (rc_sel & (1 << i)) {
- pr_alert("RC %d\n", i);
- }
- }
return count;
}
-static const struct file_operations msm_pcie_rc_sel_ops = {
- .write = msm_pcie_set_rc_sel,
+static const struct file_operations msm_pcie_debugfs_rc_select_ops = {
+ .write = msm_pcie_debugfs_rc_select,
};
-static ssize_t msm_pcie_set_base_sel(struct file *file,
+static ssize_t msm_pcie_debugfs_base_select(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
- int i;
+ int ret;
u32 new_base_sel = 0;
- char *base_sel_name;
- u32 size = sizeof(str) < count ? sizeof(str) : count;
- memset(str, 0, size);
- ret = copy_from_user(str, buf, size);
+ ret = msm_pcie_debugfs_parse_input(buf, count, &new_base_sel);
if (ret)
- return -EFAULT;
+ return ret;
- for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
- new_base_sel = (new_base_sel * 10) + (str[i] - '0');
-
- if (!new_base_sel || new_base_sel > 5) {
+ if (!new_base_sel || new_base_sel > MSM_PCIE_MAX_RES) {
pr_alert("PCIe: invalid value for base_sel: 0x%x\n",
new_base_sel);
pr_alert("PCIe: base_sel is still 0x%x\n", base_sel);
} else {
base_sel = new_base_sel;
pr_alert("PCIe: base_sel is now 0x%x\n", base_sel);
+ pr_alert("%s\n", msm_pcie_res_info[base_sel - 1].name);
}
- switch (base_sel) {
- case 1:
- base_sel_name = "PARF";
- break;
- case 2:
- base_sel_name = "PHY";
- break;
- case 3:
- base_sel_name = "RC CONFIG SPACE";
- break;
- case 4:
- base_sel_name = "ELBI";
- break;
- case 5:
- base_sel_name = "EP CONFIG SPACE";
- break;
- default:
- base_sel_name = "INVALID";
- break;
- }
-
- pr_alert("%s\n", base_sel_name);
-
return count;
}
-static const struct file_operations msm_pcie_base_sel_ops = {
- .write = msm_pcie_set_base_sel,
+static const struct file_operations msm_pcie_debugfs_base_select_ops = {
+ .write = msm_pcie_debugfs_base_select,
};
-static ssize_t msm_pcie_set_linkdown_panic(struct file *file,
+static ssize_t msm_pcie_debugfs_linkdown_panic(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
+ int i, ret;
u32 new_linkdown_panic = 0;
- int i;
- memset(str, 0, sizeof(str));
- ret = copy_from_user(str, buf, sizeof(str));
+ ret = msm_pcie_debugfs_parse_input(buf, count, &new_linkdown_panic);
if (ret)
- return -EFAULT;
+ return ret;
- for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
- new_linkdown_panic = (new_linkdown_panic * 10) + (str[i] - '0');
+ new_linkdown_panic = !!new_linkdown_panic;
- if (new_linkdown_panic <= 1) {
- for (i = 0; i < MAX_RC_NUM; i++) {
- if (!rc_sel) {
- msm_pcie_dev[0].linkdown_panic =
- new_linkdown_panic;
- PCIE_DBG_FS(&msm_pcie_dev[0],
- "PCIe: RC0: linkdown_panic is now %d\n",
- msm_pcie_dev[0].linkdown_panic);
- break;
- } else if (rc_sel & (1 << i)) {
- msm_pcie_dev[i].linkdown_panic =
- new_linkdown_panic;
- PCIE_DBG_FS(&msm_pcie_dev[i],
- "PCIe: RC%d: linkdown_panic is now %d\n",
- i, msm_pcie_dev[i].linkdown_panic);
- }
+ for (i = 0; i < MAX_RC_NUM; i++) {
+ if (rc_sel & BIT(i)) {
+ msm_pcie_dev[i].linkdown_panic =
+ new_linkdown_panic;
+ PCIE_DBG_FS(&msm_pcie_dev[i],
+ "PCIe: RC%d: linkdown_panic is now %d\n",
+ i, msm_pcie_dev[i].linkdown_panic);
}
- } else {
- pr_err("PCIe: Invalid input for linkdown_panic: %d. Please enter 0 or 1.\n",
- new_linkdown_panic);
}
return count;
}
-static const struct file_operations msm_pcie_linkdown_panic_ops = {
- .write = msm_pcie_set_linkdown_panic,
+static const struct file_operations msm_pcie_debugfs_linkdown_panic_ops = {
+ .write = msm_pcie_debugfs_linkdown_panic,
};
-static ssize_t msm_pcie_set_wr_offset(struct file *file,
+static ssize_t msm_pcie_debugfs_wr_offset(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
- int i;
- u32 size = sizeof(str) < count ? sizeof(str) : count;
-
- memset(str, 0, size);
- ret = copy_from_user(str, buf, size);
- if (ret)
- return -EFAULT;
+ int ret;
wr_offset = 0;
- for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
- wr_offset = (wr_offset * 10) + (str[i] - '0');
+
+ ret = msm_pcie_debugfs_parse_input(buf, count, &wr_offset);
+ if (ret)
+ return ret;
pr_alert("PCIe: wr_offset is now 0x%x\n", wr_offset);
return count;
}
-static const struct file_operations msm_pcie_wr_offset_ops = {
- .write = msm_pcie_set_wr_offset,
+static const struct file_operations msm_pcie_debugfs_wr_offset_ops = {
+ .write = msm_pcie_debugfs_wr_offset,
};
-static ssize_t msm_pcie_set_wr_mask(struct file *file,
+static ssize_t msm_pcie_debugfs_wr_mask(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
- int i;
- u32 size = sizeof(str) < count ? sizeof(str) : count;
-
- memset(str, 0, size);
- ret = copy_from_user(str, buf, size);
- if (ret)
- return -EFAULT;
+ int ret;
wr_mask = 0;
- for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
- wr_mask = (wr_mask * 10) + (str[i] - '0');
+
+ ret = msm_pcie_debugfs_parse_input(buf, count, &wr_mask);
+ if (ret)
+ return ret;
pr_alert("PCIe: wr_mask is now 0x%x\n", wr_mask);
return count;
}
-static const struct file_operations msm_pcie_wr_mask_ops = {
- .write = msm_pcie_set_wr_mask,
+static const struct file_operations msm_pcie_debugfs_wr_mask_ops = {
+ .write = msm_pcie_debugfs_wr_mask,
};
-static ssize_t msm_pcie_set_wr_value(struct file *file,
+static ssize_t msm_pcie_debugfs_wr_value(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
- int i;
- u32 size = sizeof(str) < count ? sizeof(str) : count;
-
- memset(str, 0, size);
- ret = copy_from_user(str, buf, size);
- if (ret)
- return -EFAULT;
+ int ret;
wr_value = 0;
- for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
- wr_value = (wr_value * 10) + (str[i] - '0');
+
+ ret = msm_pcie_debugfs_parse_input(buf, count, &wr_value);
+ if (ret)
+ return ret;
pr_alert("PCIe: wr_value is now 0x%x\n", wr_value);
return count;
}
-static const struct file_operations msm_pcie_wr_value_ops = {
- .write = msm_pcie_set_wr_value,
+static const struct file_operations msm_pcie_debugfs_wr_value_ops = {
+ .write = msm_pcie_debugfs_wr_value,
};
-static ssize_t msm_pcie_set_boot_option(struct file *file,
+static ssize_t msm_pcie_debugfs_boot_option(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
+ int i, ret;
u32 new_boot_option = 0;
- int i;
- memset(str, 0, sizeof(str));
- ret = copy_from_user(str, buf, sizeof(str));
+ ret = msm_pcie_debugfs_parse_input(buf, count, &new_boot_option);
if (ret)
- return -EFAULT;
+ return ret;
- for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
- new_boot_option = (new_boot_option * 10) + (str[i] - '0');
-
- if (new_boot_option <= 1) {
+ if (new_boot_option <= (BIT(0) | BIT(1))) {
for (i = 0; i < MAX_RC_NUM; i++) {
- if (!rc_sel) {
- msm_pcie_dev[0].boot_option = new_boot_option;
- PCIE_DBG_FS(&msm_pcie_dev[0],
- "PCIe: RC0: boot_option is now 0x%x\n",
- msm_pcie_dev[0].boot_option);
- break;
- } else if (rc_sel & (1 << i)) {
+ if (rc_sel & BIT(i)) {
msm_pcie_dev[i].boot_option = new_boot_option;
PCIE_DBG_FS(&msm_pcie_dev[i],
"PCIe: RC%d: boot_option is now 0x%x\n",
@@ -2344,42 +2291,25 @@
return count;
}
-static const struct file_operations msm_pcie_boot_option_ops = {
- .write = msm_pcie_set_boot_option,
+static const struct file_operations msm_pcie_debugfs_boot_option_ops = {
+ .write = msm_pcie_debugfs_boot_option,
};
-static ssize_t msm_pcie_set_aer_enable(struct file *file,
+static ssize_t msm_pcie_debugfs_aer_enable(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
+ int i, ret;
u32 new_aer_enable = 0;
- u32 temp_rc_sel;
- int i;
- memset(str, 0, sizeof(str));
- ret = copy_from_user(str, buf, sizeof(str));
+ ret = msm_pcie_debugfs_parse_input(buf, count, &new_aer_enable);
if (ret)
- return -EFAULT;
+ return ret;
- for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
- new_aer_enable = (new_aer_enable * 10) + (str[i] - '0');
-
- if (new_aer_enable > 1) {
- pr_err(
- "PCIe: Invalid input for aer_enable: %d. Please enter 0 or 1.\n",
- new_aer_enable);
- return count;
- }
-
- if (rc_sel)
- temp_rc_sel = rc_sel;
- else
- temp_rc_sel = 0x1;
+ new_aer_enable = !!new_aer_enable;
for (i = 0; i < MAX_RC_NUM; i++) {
- if (temp_rc_sel & (1 << i)) {
+ if (rc_sel & BIT(i)) {
msm_pcie_dev[i].aer_enable = new_aer_enable;
PCIE_DBG_FS(&msm_pcie_dev[i],
"PCIe: RC%d: aer_enable is now %d\n",
@@ -2400,35 +2330,29 @@
return count;
}
-static const struct file_operations msm_pcie_aer_enable_ops = {
- .write = msm_pcie_set_aer_enable,
+static const struct file_operations msm_pcie_debugfs_aer_enable_ops = {
+ .write = msm_pcie_debugfs_aer_enable,
};
-static ssize_t msm_pcie_set_corr_counter_limit(struct file *file,
+static ssize_t msm_pcie_debugfs_corr_counter_limit(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long ret;
- char str[MAX_MSG_LEN];
- int i;
- u32 size = sizeof(str) < count ? sizeof(str) : count;
-
- memset(str, 0, size);
- ret = copy_from_user(str, buf, size);
- if (ret)
- return -EFAULT;
+ int ret;
corr_counter_limit = 0;
- for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
- corr_counter_limit = (corr_counter_limit * 10) + (str[i] - '0');
- pr_info("PCIe: corr_counter_limit is now %lu\n", corr_counter_limit);
+ ret = msm_pcie_debugfs_parse_input(buf, count, &corr_counter_limit);
+ if (ret)
+ return ret;
+
+ pr_info("PCIe: corr_counter_limit is now %u\n", corr_counter_limit);
return count;
}
-static const struct file_operations msm_pcie_corr_counter_limit_ops = {
- .write = msm_pcie_set_corr_counter_limit,
+static const struct file_operations msm_pcie_debugfs_corr_counter_limit_ops = {
+ .write = msm_pcie_debugfs_corr_counter_limit,
};
static void msm_pcie_debugfs_init(void)
@@ -2444,7 +2368,7 @@
dfile_rc_sel = debugfs_create_file("rc_sel", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_rc_sel_ops);
+ &msm_pcie_debugfs_rc_select_ops);
if (!dfile_rc_sel || IS_ERR(dfile_rc_sel)) {
pr_err("PCIe: fail to create the file for debug_fs rc_sel.\n");
goto rc_sel_error;
@@ -2452,7 +2376,7 @@
dfile_case = debugfs_create_file("case", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_cmd_debug_ops);
+ &msm_pcie_debugfs_case_ops);
if (!dfile_case || IS_ERR(dfile_case)) {
pr_err("PCIe: fail to create the file for debug_fs case.\n");
goto case_error;
@@ -2460,7 +2384,7 @@
dfile_base_sel = debugfs_create_file("base_sel", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_base_sel_ops);
+ &msm_pcie_debugfs_base_select_ops);
if (!dfile_base_sel || IS_ERR(dfile_base_sel)) {
pr_err("PCIe: fail to create the file for debug_fs base_sel.\n");
goto base_sel_error;
@@ -2468,7 +2392,7 @@
dfile_linkdown_panic = debugfs_create_file("linkdown_panic", 0644,
dent_msm_pcie, NULL,
- &msm_pcie_linkdown_panic_ops);
+ &msm_pcie_debugfs_linkdown_panic_ops);
if (!dfile_linkdown_panic || IS_ERR(dfile_linkdown_panic)) {
pr_err("PCIe: fail to create the file for debug_fs linkdown_panic.\n");
goto linkdown_panic_error;
@@ -2476,7 +2400,7 @@
dfile_wr_offset = debugfs_create_file("wr_offset", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_wr_offset_ops);
+ &msm_pcie_debugfs_wr_offset_ops);
if (!dfile_wr_offset || IS_ERR(dfile_wr_offset)) {
pr_err("PCIe: fail to create the file for debug_fs wr_offset.\n");
goto wr_offset_error;
@@ -2484,7 +2408,7 @@
dfile_wr_mask = debugfs_create_file("wr_mask", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_wr_mask_ops);
+ &msm_pcie_debugfs_wr_mask_ops);
if (!dfile_wr_mask || IS_ERR(dfile_wr_mask)) {
pr_err("PCIe: fail to create the file for debug_fs wr_mask.\n");
goto wr_mask_error;
@@ -2492,7 +2416,7 @@
dfile_wr_value = debugfs_create_file("wr_value", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_wr_value_ops);
+ &msm_pcie_debugfs_wr_value_ops);
if (!dfile_wr_value || IS_ERR(dfile_wr_value)) {
pr_err("PCIe: fail to create the file for debug_fs wr_value.\n");
goto wr_value_error;
@@ -2500,7 +2424,7 @@
dfile_boot_option = debugfs_create_file("boot_option", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_boot_option_ops);
+ &msm_pcie_debugfs_boot_option_ops);
if (!dfile_boot_option || IS_ERR(dfile_boot_option)) {
pr_err("PCIe: fail to create the file for debug_fs boot_option.\n");
goto boot_option_error;
@@ -2508,15 +2432,15 @@
dfile_aer_enable = debugfs_create_file("aer_enable", 0664,
dent_msm_pcie, NULL,
- &msm_pcie_aer_enable_ops);
+ &msm_pcie_debugfs_aer_enable_ops);
if (!dfile_aer_enable || IS_ERR(dfile_aer_enable)) {
pr_err("PCIe: fail to create the file for debug_fs aer_enable.\n");
goto aer_enable_error;
}
dfile_corr_counter_limit = debugfs_create_file("corr_counter_limit",
- 0664, dent_msm_pcie, NULL,
- &msm_pcie_corr_counter_limit_ops);
+ 0664, dent_msm_pcie, NULL,
+ &msm_pcie_debugfs_corr_counter_limit_ops);
if (!dfile_corr_counter_limit || IS_ERR(dfile_corr_counter_limit)) {
pr_err("PCIe: fail to create the file for debug_fs corr_counter_limit.\n");
goto corr_counter_limit_error;
@@ -2588,9 +2512,38 @@
unsigned long host_addr, u32 host_end,
unsigned long target_addr)
{
- void __iomem *pcie20 = dev->dm_core;
+ void __iomem *iatu_base = dev->iatu ? dev->iatu : dev->dm_core;
- if (dev->shadow_en) {
+ u32 iatu_viewport_offset;
+ u32 iatu_ctrl1_offset;
+ u32 iatu_ctrl2_offset;
+ u32 iatu_lbar_offset;
+ u32 iatu_ubar_offset;
+ u32 iatu_lar_offset;
+ u32 iatu_ltar_offset;
+ u32 iatu_utar_offset;
+
+ if (dev->iatu) {
+ iatu_viewport_offset = 0;
+ iatu_ctrl1_offset = PCIE_IATU_CTRL1(nr);
+ iatu_ctrl2_offset = PCIE_IATU_CTRL2(nr);
+ iatu_lbar_offset = PCIE_IATU_LBAR(nr);
+ iatu_ubar_offset = PCIE_IATU_UBAR(nr);
+ iatu_lar_offset = PCIE_IATU_LAR(nr);
+ iatu_ltar_offset = PCIE_IATU_LTAR(nr);
+ iatu_utar_offset = PCIE_IATU_UTAR(nr);
+ } else {
+ iatu_viewport_offset = PCIE20_PLR_IATU_VIEWPORT;
+ iatu_ctrl1_offset = PCIE20_PLR_IATU_CTRL1;
+ iatu_ctrl2_offset = PCIE20_PLR_IATU_CTRL2;
+ iatu_lbar_offset = PCIE20_PLR_IATU_LBAR;
+ iatu_ubar_offset = PCIE20_PLR_IATU_UBAR;
+ iatu_lar_offset = PCIE20_PLR_IATU_LAR;
+ iatu_ltar_offset = PCIE20_PLR_IATU_LTAR;
+ iatu_utar_offset = PCIE20_PLR_IATU_UTAR;
+ }
+
+ if (dev->shadow_en && iatu_viewport_offset) {
dev->rc_shadow[PCIE20_PLR_IATU_VIEWPORT / 4] =
nr;
dev->rc_shadow[PCIE20_PLR_IATU_CTRL1 / 4] =
@@ -2610,28 +2563,30 @@
}
/* select region */
- writel_relaxed(nr, pcie20 + PCIE20_PLR_IATU_VIEWPORT);
- /* ensure that hardware locks it */
- wmb();
+ if (iatu_viewport_offset) {
+ writel_relaxed(nr, iatu_base + iatu_viewport_offset);
+ /* ensure that hardware locks it */
+ wmb();
+ }
/* switch off region before changing it */
- writel_relaxed(0, pcie20 + PCIE20_PLR_IATU_CTRL2);
+ writel_relaxed(0, iatu_base + iatu_ctrl2_offset);
/* and wait till it propagates to the hardware */
wmb();
- writel_relaxed(type, pcie20 + PCIE20_PLR_IATU_CTRL1);
+ writel_relaxed(type, iatu_base + iatu_ctrl1_offset);
writel_relaxed(lower_32_bits(host_addr),
- pcie20 + PCIE20_PLR_IATU_LBAR);
+ iatu_base + iatu_lbar_offset);
writel_relaxed(upper_32_bits(host_addr),
- pcie20 + PCIE20_PLR_IATU_UBAR);
- writel_relaxed(host_end, pcie20 + PCIE20_PLR_IATU_LAR);
+ iatu_base + iatu_ubar_offset);
+ writel_relaxed(host_end, iatu_base + iatu_lar_offset);
writel_relaxed(lower_32_bits(target_addr),
- pcie20 + PCIE20_PLR_IATU_LTAR);
+ iatu_base + iatu_ltar_offset);
writel_relaxed(upper_32_bits(target_addr),
- pcie20 + PCIE20_PLR_IATU_UTAR);
+ iatu_base + iatu_utar_offset);
/* ensure that changes propagated to the hardware */
wmb();
- writel_relaxed(BIT(31), pcie20 + PCIE20_PLR_IATU_CTRL2);
+ writel_relaxed(BIT(31), iatu_base + iatu_ctrl2_offset);
/* ensure that changes propagated to the hardware */
wmb();
@@ -2641,22 +2596,24 @@
dev->pcidev_table[nr].bdf >> 24,
dev->pcidev_table[nr].bdf >> 19 & 0x1f,
dev->pcidev_table[nr].bdf >> 16 & 0x07);
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_VIEWPORT:0x%x\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_VIEWPORT));
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_CTRL1:0x%x\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL1));
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_LBAR:0x%x\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LBAR));
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_UBAR:0x%x\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UBAR));
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_LAR:0x%x\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LAR));
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_LTAR:0x%x\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LTAR));
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_UTAR:0x%x\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UTAR));
- PCIE_DBG2(dev, "PCIE20_PLR_IATU_CTRL2:0x%x\n\n",
- readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL2));
+ if (iatu_viewport_offset)
+ PCIE_DBG2(dev, "IATU_VIEWPORT:0x%x\n",
+ readl_relaxed(dev->dm_core +
+ PCIE20_PLR_IATU_VIEWPORT));
+ PCIE_DBG2(dev, "IATU_CTRL1:0x%x\n",
+ readl_relaxed(iatu_base + iatu_ctrl1_offset));
+ PCIE_DBG2(dev, "IATU_LBAR:0x%x\n",
+ readl_relaxed(iatu_base + iatu_lbar_offset));
+ PCIE_DBG2(dev, "IATU_UBAR:0x%x\n",
+ readl_relaxed(iatu_base + iatu_ubar_offset));
+ PCIE_DBG2(dev, "IATU_LAR:0x%x\n",
+ readl_relaxed(iatu_base + iatu_lar_offset));
+ PCIE_DBG2(dev, "IATU_LTAR:0x%x\n",
+ readl_relaxed(iatu_base + iatu_ltar_offset));
+ PCIE_DBG2(dev, "IATU_UTAR:0x%x\n",
+ readl_relaxed(iatu_base + iatu_utar_offset));
+ PCIE_DBG2(dev, "IATU_CTRL2:0x%x\n\n",
+ readl_relaxed(iatu_base + iatu_ctrl2_offset));
}
}
@@ -3387,8 +3344,8 @@
PCIE_DBG(dev, "RC%d: entry\n", dev->rc_idx);
- cnt = of_property_count_strings((&pdev->dev)->of_node,
- "clock-names");
+ cnt = of_property_count_elems_of_size((&pdev->dev)->of_node,
+ "max-clock-frequency-hz", sizeof(u32));
if (cnt > 0) {
clkfreq = kzalloc((MSM_PCIE_MAX_CLK + MSM_PCIE_MAX_PIPE_CLK) *
sizeof(*clkfreq), GFP_KERNEL);
@@ -3706,6 +3663,7 @@
dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
dev->phy = dev->res[MSM_PCIE_RES_PHY].base;
dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
+ dev->iatu = dev->res[MSM_PCIE_RES_IATU].base;
dev->dm_core = dev->res[MSM_PCIE_RES_DM_CORE].base;
dev->conf = dev->res[MSM_PCIE_RES_CONF].base;
dev->bars = dev->res[MSM_PCIE_RES_BARS].base;
@@ -3726,6 +3684,7 @@
{
dev->parf = NULL;
dev->elbi = NULL;
+ dev->iatu = NULL;
dev->dm_core = NULL;
dev->conf = NULL;
dev->bars = NULL;
@@ -3771,6 +3730,7 @@
long int retries = 0;
int link_check_count = 0;
unsigned long ep_up_timeout = 0;
+ u32 link_check_max_count;
PCIE_DBG(dev, "RC%d: entry\n", dev->rc_idx);
@@ -3937,6 +3897,11 @@
if (dev->max_link_speed == GEN3_SPEED)
msm_pcie_setup_gen3(dev);
+ if (msm_pcie_force_gen1 & BIT(dev->rc_idx))
+ msm_pcie_write_reg_field(dev->dm_core,
+ PCIE20_CAP + PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCAP_SLS, GEN1_SPEED);
+
/* set max tlp read size */
msm_pcie_write_reg_field(dev->dm_core, PCIE20_DEVICE_CONTROL_STATUS,
0x7000, dev->tlp_rd_size);
@@ -3946,6 +3911,11 @@
PCIE_DBG(dev, "%s", "check if link is up\n");
+ if (msm_pcie_link_check_max_count & BIT(dev->rc_idx))
+ link_check_max_count = msm_pcie_link_check_max_count >> 4;
+ else
+ link_check_max_count = LINK_UP_CHECK_MAX_COUNT;
+
/* Wait for up to 100ms for the link to come up */
do {
usleep_range(LINK_UP_TIMEOUT_US_MIN, LINK_UP_TIMEOUT_US_MAX);
@@ -3954,7 +3924,7 @@
dev->rc_idx, (val >> 12) & 0x3f);
} while ((!(val & XMLH_LINK_UP) ||
!msm_pcie_confirm_linkup(dev, false, false, NULL))
- && (link_check_count++ < LINK_UP_CHECK_MAX_COUNT));
+ && (link_check_count++ < link_check_max_count));
if ((val & XMLH_LINK_UP) &&
msm_pcie_confirm_linkup(dev, false, false, NULL)) {
@@ -4330,9 +4300,7 @@
}
bus = pci_create_root_bus(&dev->pdev->dev, 0,
- &msm_pcie_ops,
- msm_pcie_setup_sys_data(dev),
- &res);
+ &msm_pcie_ops, dev, &res);
if (!bus) {
PCIE_ERR(dev,
"PCIe: failed to create root bus for RC%d\n",
@@ -4344,7 +4312,7 @@
scan_ret = pci_scan_child_bus(bus);
PCIE_DBG(dev,
"PCIe: RC%d: The max subordinate bus number discovered is %d\n",
- dev->rc_idx, ret);
+ dev->rc_idx, scan_ret);
msm_pcie_fixup_irqs(dev);
pci_assign_unassigned_bus_resources(bus);
@@ -4529,7 +4497,6 @@
u32 ep_dev_ctrlstts_offset = 0;
int i, j, ep_src_bdf = 0;
void __iomem *ep_base = NULL;
- unsigned long irqsave_flags;
PCIE_DBG2(dev,
"AER Interrupt handler fired for RC%d irq %d\nrc_corr_counter: %lu\nrc_non_fatal_counter: %lu\nrc_fatal_counter: %lu\nep_corr_counter: %lu\nep_non_fatal_counter: %lu\nep_fatal_counter: %lu\n",
@@ -4538,16 +4505,6 @@
dev->ep_corr_counter, dev->ep_non_fatal_counter,
dev->ep_fatal_counter);
- spin_lock_irqsave(&dev->aer_lock, irqsave_flags);
-
- if (dev->suspending) {
- PCIE_DBG2(dev,
- "PCIe: RC%d is currently suspending.\n",
- dev->rc_idx);
- spin_unlock_irqrestore(&dev->aer_lock, irqsave_flags);
- return IRQ_HANDLED;
- }
-
uncorr_val = readl_relaxed(dev->dm_core +
PCIE20_AER_UNCORR_ERR_STATUS_REG);
corr_val = readl_relaxed(dev->dm_core +
@@ -4661,7 +4618,6 @@
PCIE20_AER_ROOT_ERR_STATUS_REG,
0x7f, 0x7f);
- spin_unlock_irqrestore(&dev->aer_lock, irqsave_flags);
return IRQ_HANDLED;
}
@@ -4709,11 +4665,8 @@
static irqreturn_t handle_linkdown_irq(int irq, void *data)
{
struct msm_pcie_dev_t *dev = data;
- unsigned long irqsave_flags;
int i;
- spin_lock_irqsave(&dev->linkdown_lock, irqsave_flags);
-
dev->linkdown_counter++;
PCIE_DBG(dev,
@@ -4754,8 +4707,6 @@
}
}
- spin_unlock_irqrestore(&dev->linkdown_lock, irqsave_flags);
-
return IRQ_HANDLED;
}
@@ -4799,7 +4750,15 @@
unsigned long irqsave_flags;
u32 status = 0;
- spin_lock_irqsave(&dev->global_irq_lock, irqsave_flags);
+ spin_lock_irqsave(&dev->irq_lock, irqsave_flags);
+
+ if (dev->suspending) {
+ PCIE_DBG2(dev,
+ "PCIe: RC%d is currently suspending.\n",
+ dev->rc_idx);
+ spin_unlock_irqrestore(&dev->irq_lock, irqsave_flags);
+ return IRQ_HANDLED;
+ }
status = readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_STATUS) &
readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK);
@@ -4838,13 +4797,14 @@
}
}
- spin_unlock_irqrestore(&dev->global_irq_lock, irqsave_flags);
+ spin_unlock_irqrestore(&dev->irq_lock, irqsave_flags);
return IRQ_HANDLED;
}
static void msm_pcie_unmap_qgic_addr(struct msm_pcie_dev_t *dev,
- struct pci_dev *pdev)
+ struct pci_dev *pdev,
+ struct msi_desc *entry)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
int bypass_en = 0;
@@ -4858,30 +4818,20 @@
iommu_domain_get_attr(domain, DOMAIN_ATTR_S1_BYPASS, &bypass_en);
if (!bypass_en) {
- int ret;
- phys_addr_t pcie_base_addr =
- dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
- dma_addr_t iova = rounddown(pcie_base_addr, PAGE_SIZE);
+ dma_addr_t iova = entry->msg.address_lo;
- ret = iommu_unmap(domain, iova, PAGE_SIZE);
- if (ret != PAGE_SIZE)
- PCIE_ERR(dev,
- "PCIe: RC%d: failed to unmap QGIC address. ret = %d\n",
- dev->rc_idx, ret);
+ PCIE_DBG(dev, "PCIe: RC%d: unmap QGIC MSI IOVA\n", dev->rc_idx);
+
+ dma_unmap_resource(&pdev->dev, iova, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, 0);
}
}
-static void msm_pcie_destroy_irq(unsigned int irq, struct pci_dev *pdev)
+static void msm_pcie_destroy_irq(struct msi_desc *entry, unsigned int irq)
{
int pos;
- struct msi_desc *entry = irq_get_msi_desc(irq);
- struct msi_desc *firstentry;
struct msm_pcie_dev_t *dev;
- u32 nvec;
- int firstirq;
-
- if (!pdev)
- pdev = irq_get_chip_data(irq);
+ struct pci_dev *pdev = msi_desc_to_pci_dev(entry);
if (!pdev) {
pr_err("PCIe: pci device is null. IRQ:%d\n", irq);
@@ -4894,24 +4844,10 @@
return;
}
- if (!entry) {
- PCIE_ERR(dev, "PCIe: RC%d: msi desc is null. IRQ:%d\n",
- dev->rc_idx, irq);
- return;
- }
-
- firstentry = first_pci_msi_entry(pdev);
- if (!firstentry) {
- PCIE_ERR(dev,
- "PCIe: RC%d: firstentry msi desc is null. IRQ:%d\n",
- dev->rc_idx, irq);
- return;
- }
-
- firstirq = firstentry->irq;
- nvec = (1 << entry->msi_attrib.multiple);
-
if (dev->msi_gicm_addr) {
+ int firstirq = entry->irq;
+ u32 nvec = (1 << entry->msi_attrib.multiple);
+
PCIE_DBG(dev, "destroy QGIC based irq %d\n", irq);
if (irq < firstirq || irq > firstirq + nvec - 1) {
@@ -4921,7 +4857,7 @@
return;
}
if (irq == firstirq + nvec - 1)
- msm_pcie_unmap_qgic_addr(dev, pdev);
+ msm_pcie_unmap_qgic_addr(dev, pdev, entry);
pos = irq - firstirq;
} else {
PCIE_DBG(dev, "destroy default MSI irq %d\n", irq);
@@ -4940,8 +4876,12 @@
/* hookup to linux pci msi framework */
void arch_teardown_msi_irq(unsigned int irq)
{
+ struct msi_desc *entry = irq_get_msi_desc(irq);
+
PCIE_GEN_DBG("irq %d deallocated\n", irq);
- msm_pcie_destroy_irq(irq, NULL);
+
+ if (entry)
+ msm_pcie_destroy_irq(entry, irq);
}
void arch_teardown_msi_irqs(struct pci_dev *dev)
@@ -4961,7 +4901,7 @@
continue;
nvec = 1 << entry->msi_attrib.multiple;
for (i = 0; i < nvec; i++)
- msm_pcie_destroy_irq(entry->irq + i, dev);
+ msm_pcie_destroy_irq(entry, entry->irq + i);
}
}
@@ -5075,9 +5015,8 @@
struct msi_msg *msg)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
- struct iommu_domain_geometry geometry;
- int fastmap_en = 0, bypass_en = 0;
- dma_addr_t iova, addr;
+ int bypass_en = 0;
+ dma_addr_t iova;
msg->address_hi = 0;
msg->address_lo = dev->msi_gicm_addr;
@@ -5099,35 +5038,15 @@
if (bypass_en)
return 0;
- iommu_domain_get_attr(domain, DOMAIN_ATTR_FAST, &fastmap_en);
- if (fastmap_en) {
- iommu_domain_get_attr(domain, DOMAIN_ATTR_GEOMETRY, &geometry);
- iova = geometry.aperture_start;
- PCIE_DBG(dev,
- "PCIe: RC%d: Use client's IOVA 0x%llx to map QGIC MSI address\n",
- dev->rc_idx, iova);
- } else {
- phys_addr_t pcie_base_addr;
-
- /*
- * Use PCIe DBI address as the IOVA since client cannot
- * use this address for their IOMMU mapping. This will
- * prevent any conflicts between PCIe host and
- * client's mapping.
- */
- pcie_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
- iova = rounddown(pcie_base_addr, PAGE_SIZE);
- }
-
- addr = dma_map_resource(&pdev->dev, dev->msi_gicm_addr, PAGE_SIZE,
+ iova = dma_map_resource(&pdev->dev, dev->msi_gicm_addr, PAGE_SIZE,
DMA_BIDIRECTIONAL, 0);
- if (dma_mapping_error(&pdev->dev, addr)) {
+ if (dma_mapping_error(&pdev->dev, iova)) {
PCIE_ERR(dev, "PCIe: RC%d: failed to map QGIC address",
dev->rc_idx);
return -EIO;
}
- msg->address_lo = iova + addr;
+ msg->address_lo = iova;
return 0;
}
@@ -5415,6 +5334,22 @@
PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val);
}
+static int msm_pcie_config_l0s_disable(struct pci_dev *pdev, void *dev)
+{
+ struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+ msm_pcie_config_l0s(pcie_dev, pdev, false);
+ return 0;
+}
+
+static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev)
+{
+ struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+ msm_pcie_config_l0s(pcie_dev, pdev, true);
+ return 0;
+}
+
static void msm_pcie_config_l1(struct msm_pcie_dev_t *dev,
struct pci_dev *pdev, bool enable)
{
@@ -5441,6 +5376,22 @@
PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val);
}
+static int msm_pcie_config_l1_disable(struct pci_dev *pdev, void *dev)
+{
+ struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+ msm_pcie_config_l1(pcie_dev, pdev, false);
+ return 0;
+}
+
+static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev)
+{
+ struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+ msm_pcie_config_l1(pcie_dev, pdev, true);
+ return 0;
+}
+
static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev,
struct pci_dev *pdev, bool enable)
{
@@ -5510,6 +5461,22 @@
dev->rc_idx, val2);
}
+static int msm_pcie_config_l1ss_disable(struct pci_dev *pdev, void *dev)
+{
+ struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+ msm_pcie_config_l1ss(pcie_dev, pdev, false);
+ return 0;
+}
+
+static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev)
+{
+ struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+ msm_pcie_config_l1ss(pcie_dev, pdev, true);
+ return 0;
+}
+
static void msm_pcie_config_clock_power_management(struct msm_pcie_dev_t *dev,
struct pci_dev *pdev)
{
@@ -6193,10 +6160,8 @@
mutex_init(&msm_pcie_dev[i].enumerate_lock);
mutex_init(&msm_pcie_dev[i].setup_lock);
mutex_init(&msm_pcie_dev[i].recovery_lock);
- spin_lock_init(&msm_pcie_dev[i].linkdown_lock);
spin_lock_init(&msm_pcie_dev[i].wakeup_lock);
- spin_lock_init(&msm_pcie_dev[i].global_irq_lock);
- spin_lock_init(&msm_pcie_dev[i].aer_lock);
+ spin_lock_init(&msm_pcie_dev[i].irq_lock);
msm_pcie_dev[i].drv_ready = false;
}
for (i = 0; i < MAX_RC_NUM * MAX_DEVICE_NUM; i++) {
@@ -6261,9 +6226,9 @@
PCIE_DBG(pcie_dev, "RC%d: entry\n", pcie_dev->rc_idx);
- spin_lock_irqsave(&pcie_dev->aer_lock, irqsave_flags);
+ spin_lock_irqsave(&pcie_dev->irq_lock, irqsave_flags);
pcie_dev->suspending = true;
- spin_unlock_irqrestore(&pcie_dev->aer_lock, irqsave_flags);
+ spin_unlock_irqrestore(&pcie_dev->irq_lock, irqsave_flags);
if (!pcie_dev->power_on) {
PCIE_DBG(pcie_dev,
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 6117d4d..4abd8f1 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -152,6 +152,14 @@
numbers in the kernel log along with the PMIC option status. The PMIC
type is mapped to a QTI chip part number and logged as well.
+config GPIO_USB_DETECT
+ tristate "GPIO-based USB VBUS Detection"
+ depends on POWER_SUPPLY
+ help
+ This driver supports external USB VBUS detection circuitry whose
+ output is connected to a GPIO. The driver in turn notifies the
+ USB driver of VBUS presence/disconnection using the power_supply
+ framework.
config MSM_MHI_DEV
tristate "Modem Device Interface Driver"
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index bee32c2..d0f0216f 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_SPS) += sps/
obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o
obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
+obj-$(CONFIG_GPIO_USB_DETECT) += gpio-usbdetect.o
obj-$(CONFIG_EP_PCIE) += ep_pcie/
obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/
obj-$(CONFIG_USB_BAM) += usb_bam.o
diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c
new file mode 100644
index 0000000..6730d4a
--- /dev/null
+++ b/drivers/platform/msm/gpio-usbdetect.c
@@ -0,0 +1,266 @@
+/* Copyright (c) 2013-2015, 2017-2018, 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/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/extcon.h>
+#include <linux/regulator/consumer.h>
+
+struct gpio_usbdetect {
+ struct platform_device *pdev;
+ struct regulator *vin;
+ int vbus_det_irq;
+ int id_det_irq;
+ int gpio;
+ struct extcon_dev *extcon_dev;
+ int vbus_state;
+ bool id_state;
+};
+
+static const unsigned int gpio_usb_extcon_table[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
+static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data)
+{
+ struct gpio_usbdetect *usb = data;
+ union extcon_property_value val;
+
+ usb->vbus_state = gpio_get_value(usb->gpio);
+ if (usb->vbus_state) {
+ dev_dbg(&usb->pdev->dev, "setting vbus notification\n");
+ val.intval = true;
+ extcon_set_property(usb->extcon_dev, EXTCON_USB,
+ EXTCON_PROP_USB_SS, val);
+ extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1);
+ } else {
+ dev_dbg(&usb->pdev->dev, "setting vbus removed notification\n");
+ extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t gpio_usbdetect_id_irq(int irq, void *data)
+{
+ struct gpio_usbdetect *usb = data;
+ int ret;
+
+ ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL,
+ &usb->id_state);
+ if (ret < 0) {
+ dev_err(&usb->pdev->dev, "unable to read ID IRQ LINE\n");
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data)
+{
+ struct gpio_usbdetect *usb = data;
+ bool curr_id_state;
+ static int prev_id_state = -EINVAL;
+ union extcon_property_value val;
+
+ curr_id_state = usb->id_state;
+ if (curr_id_state == prev_id_state) {
+ dev_dbg(&usb->pdev->dev, "no change in ID state\n");
+ return IRQ_HANDLED;
+ }
+
+ if (curr_id_state) {
+ dev_dbg(&usb->pdev->dev, "stopping usb host\n");
+ extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 0);
+ enable_irq(usb->vbus_det_irq);
+ } else {
+ dev_dbg(&usb->pdev->dev, "starting usb HOST\n");
+ disable_irq(usb->vbus_det_irq);
+ val.intval = true;
+ extcon_set_property(usb->extcon_dev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_SS, val);
+ extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1);
+ }
+
+ prev_id_state = curr_id_state;
+ return IRQ_HANDLED;
+}
+
+static const u32 gpio_usb_extcon_exclusive[] = {0x3, 0};
+
+static int gpio_usbdetect_probe(struct platform_device *pdev)
+{
+ struct gpio_usbdetect *usb;
+ int rc;
+
+ usb = devm_kzalloc(&pdev->dev, sizeof(*usb), GFP_KERNEL);
+ if (!usb)
+ return -ENOMEM;
+
+ usb->pdev = pdev;
+
+ usb->extcon_dev = devm_extcon_dev_allocate(&pdev->dev,
+ gpio_usb_extcon_table);
+ if (IS_ERR(usb->extcon_dev)) {
+ dev_err(&pdev->dev, "failed to allocate a extcon device\n");
+ return PTR_ERR(usb->extcon_dev);
+ }
+
+ usb->extcon_dev->mutually_exclusive = gpio_usb_extcon_exclusive;
+ rc = devm_extcon_dev_register(&pdev->dev, usb->extcon_dev);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ return rc;
+ }
+
+ rc = extcon_set_property_capability(usb->extcon_dev,
+ EXTCON_USB, EXTCON_PROP_USB_SS);
+ rc |= extcon_set_property_capability(usb->extcon_dev,
+ EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to register extcon props rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (of_get_property(pdev->dev.of_node, "vin-supply", NULL)) {
+ usb->vin = devm_regulator_get(&pdev->dev, "vin");
+ if (IS_ERR(usb->vin)) {
+ dev_err(&pdev->dev, "Failed to get VIN regulator: %ld\n",
+ PTR_ERR(usb->vin));
+ return PTR_ERR(usb->vin);
+ }
+ }
+
+ if (usb->vin) {
+ rc = regulator_enable(usb->vin);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed to enable VIN regulator: %d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ usb->gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,vbus-det-gpio", 0);
+ if (usb->gpio < 0) {
+ dev_err(&pdev->dev, "Failed to get gpio: %d\n", usb->gpio);
+ rc = usb->gpio;
+ goto error;
+ }
+
+ rc = gpio_request(usb->gpio, "vbus-det-gpio");
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to request gpio: %d\n", rc);
+ goto error;
+ }
+
+ usb->vbus_det_irq = gpio_to_irq(usb->gpio);
+ if (usb->vbus_det_irq < 0) {
+ dev_err(&pdev->dev, "get vbus_det_irq failed\n");
+ rc = usb->vbus_det_irq;
+ goto error;
+ }
+
+ rc = devm_request_threaded_irq(&pdev->dev, usb->vbus_det_irq,
+ NULL, gpio_usbdetect_vbus_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT, "vbus_det_irq", usb);
+ if (rc) {
+ dev_err(&pdev->dev, "request for vbus_det_irq failed: %d\n",
+ rc);
+ goto error;
+ }
+
+ usb->id_det_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
+ if (usb->id_det_irq < 0) {
+ dev_err(&pdev->dev, "get id_det_irq failed\n");
+ rc = usb->id_det_irq;
+ goto error;
+ }
+
+ rc = devm_request_threaded_irq(&pdev->dev, usb->id_det_irq,
+ gpio_usbdetect_id_irq,
+ gpio_usbdetect_id_irq_thread,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT, "id_det_irq", usb);
+ if (rc) {
+ dev_err(&pdev->dev, "request for id_det_irq failed: %d\n", rc);
+ goto error;
+ }
+
+ enable_irq_wake(usb->vbus_det_irq);
+ enable_irq_wake(usb->id_det_irq);
+ dev_set_drvdata(&pdev->dev, usb);
+
+ if (usb->id_det_irq) {
+ gpio_usbdetect_id_irq(usb->id_det_irq, usb);
+ if (!usb->id_state) {
+ gpio_usbdetect_id_irq_thread(usb->id_det_irq, usb);
+ return 0;
+ }
+ }
+
+ /* Read and report initial VBUS state */
+ gpio_usbdetect_vbus_irq(usb->vbus_det_irq, usb);
+
+ return 0;
+
+error:
+ if (usb->vin)
+ regulator_disable(usb->vin);
+ return rc;
+}
+
+static int gpio_usbdetect_remove(struct platform_device *pdev)
+{
+ struct gpio_usbdetect *usb = dev_get_drvdata(&pdev->dev);
+
+ disable_irq_wake(usb->vbus_det_irq);
+ disable_irq(usb->vbus_det_irq);
+ disable_irq_wake(usb->id_det_irq);
+ disable_irq(usb->id_det_irq);
+ if (usb->vin)
+ regulator_disable(usb->vin);
+
+ return 0;
+}
+
+static const struct of_device_id of_match_table[] = {
+ { .compatible = "qcom,gpio-usbdetect", },
+ {}
+};
+
+static struct platform_driver gpio_usbdetect_driver = {
+ .driver = {
+ .name = "qcom,gpio-usbdetect",
+ .of_match_table = of_match_table,
+ },
+ .probe = gpio_usbdetect_probe,
+ .remove = gpio_usbdetect_remove,
+};
+
+module_driver(gpio_usbdetect_driver, platform_driver_register,
+ platform_driver_unregister);
+
+MODULE_DESCRIPTION("GPIO USB VBUS Detection driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index d274490..1335c45 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018 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
@@ -741,10 +741,6 @@
&ipa3_usb_ctx->ttype_ctx[ttype];
int result;
- /* create PM resources for the first tethering protocol only */
- if (ipa3_usb_ctx->num_init_prot > 0)
- return 0;
-
memset(&ttype_ctx->pm_ctx.reg_params, 0,
sizeof(ttype_ctx->pm_ctx.reg_params));
ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
@@ -1024,11 +1020,11 @@
return 0;
teth_prot_init_fail:
- if ((IPA3_USB_IS_TTYPE_DPL(ttype))
- || (ipa3_usb_ctx->num_init_prot == 0)) {
- if (ipa_pm_is_used()) {
- ipa3_usb_deregister_pm(ttype);
- } else {
+ if (ipa_pm_is_used()) {
+ ipa3_usb_deregister_pm(ttype);
+ } else {
+ if ((IPA3_USB_IS_TTYPE_DPL(ttype))
+ || (ipa3_usb_ctx->num_init_prot == 0)) {
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
false;
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
@@ -1332,6 +1328,10 @@
chan_params.chan_scratch.xdci.outstanding_threshold =
((params->teth_prot == IPA_USB_MBIM) ? 1 : 2) *
chan_params.chan_params.re_size;
+
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+ chan_params.chan_scratch.xdci.outstanding_threshold = 0;
+
/* max_outstanding_tre is set in ipa3_request_gsi_channel() */
result = ipa3_request_gsi_channel(&chan_params, out_params);
if (result) {
@@ -2462,13 +2462,14 @@
goto bad_params;
}
- if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
- (ipa3_usb_ctx->num_init_prot == 0)) {
- if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
- IPA_USB_ERR("failed to change state to invalid\n");
- if (ipa_pm_is_used()) {
- ipa3_usb_deregister_pm(ttype);
- } else {
+ if (ipa_pm_is_used()) {
+ ipa3_usb_deregister_pm(ttype);
+ } else {
+ if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
+ (ipa3_usb_ctx->num_init_prot == 0)) {
+ if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
+ IPA_USB_ERR(
+ "failed to change state to invalid\n");
ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 8872c24..901b51b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -714,6 +714,10 @@
sizeof(union __packed gsi_channel_scratch));
ep->chan_scratch.xdci.max_outstanding_tre =
params->chan_params.re_size * gsi_ep_cfg_ptr->ipa_if_tlv;
+
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+ ep->chan_scratch.xdci.max_outstanding_tre = 0;
+
gsi_res = gsi_write_channel_scratch(ep->gsi_chan_hdl,
params->chan_scratch);
if (gsi_res != GSI_STATUS_SUCCESS) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 3aaae8d..f105c36 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -236,6 +236,8 @@
return;
}
sys->len_pending_xfer = 0;
+ /* make sure TAG process is sent before clocks are gated */
+ ipa3_ctx->tag_process_before_gating = true;
}
@@ -419,6 +421,9 @@
hrtimer_start(&sys->db_timer, time, HRTIMER_MODE_REL);
}
+ /* make sure TAG process is sent before clocks are gated */
+ ipa3_ctx->tag_process_before_gating = true;
+
return 0;
failure_dma_map:
@@ -3679,6 +3684,12 @@
ch_scratch.gpi.max_outstanding_tre = gsi_ep_info->ipa_if_tlv *
GSI_CHAN_RE_SIZE_16B;
ch_scratch.gpi.outstanding_threshold = 2 * GSI_CHAN_RE_SIZE_16B;
+
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+ ch_scratch.gpi.max_outstanding_tre = 0;
+ ch_scratch.gpi.outstanding_threshold = 0;
+ }
+
result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("failed to write scratch %d\n", result);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index cb970ba..82cd8187 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018 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
@@ -302,6 +302,10 @@
ep_cfg->ipa_if_tlv * ch_props.re_size;
ch_scratch.mhi.outstanding_threshold =
min(ep_cfg->ipa_if_tlv / 2, 8) * ch_props.re_size;
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+ ch_scratch.mhi.max_outstanding_tre = 0;
+ ch_scratch.mhi.outstanding_threshold = 0;
+ }
ch_scratch.mhi.oob_mod_threshold = 4;
if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT ||
params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
index bafc3ca..80a39b5 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -240,7 +240,7 @@
struct ipa_pm_client *client;
/* Create a basic array to hold throughputs*/
- for (i = 0, n = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+ for (i = 1, n = 0; i < IPA_PM_MAX_CLIENTS; i++) {
client = ipa_pm_ctx->clients[i];
if (client != NULL && IPA_PM_STATE_ACTIVE(client->state)) {
/* default case */
@@ -414,7 +414,6 @@
complete_all(&client->complete);
if (dec_clk) {
- ipa_set_tag_process_before_gating(true);
if (!client->skip_clk_vote)
IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
@@ -465,7 +464,6 @@
client->state = IPA_PM_DEACTIVATED;
IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
spin_unlock_irqrestore(&client->state_lock, flags);
- ipa_set_tag_process_before_gating(true);
if (!client->skip_clk_vote)
IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
@@ -489,7 +487,8 @@
n = -ENOBUFS;
- for (i = IPA_PM_MAX_CLIENTS - 1; i >= 0; i--) {
+ /* 0 is not a valid handle */
+ for (i = IPA_PM_MAX_CLIENTS - 1; i >= 1; i--) {
if (ipa_pm_ctx->clients[i] == NULL) {
n = i;
continue;
@@ -1043,7 +1042,7 @@
return -EINVAL;
}
- for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+ for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
client = ipa_pm_ctx->clients[i];
if (client == NULL)
@@ -1073,7 +1072,6 @@
IPA_PM_DBG_STATE(client->hdl, client->name,
client->state);
spin_unlock_irqrestore(&client->state_lock, flags);
- ipa_set_tag_process_before_gating(true);
if (!client->skip_clk_vote)
IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
deactivate_client(client->hdl);
@@ -1126,7 +1124,6 @@
spin_unlock_irqrestore(&client->state_lock, flags);
/* else case (Deactivates all Activated cases)*/
- ipa_set_tag_process_before_gating(true);
if (!client->skip_clk_vote)
IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
@@ -1280,7 +1277,7 @@
cnt += result;
- for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+ for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
client = ipa_pm_ctx->clients[i];
if (client == NULL)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
index b2f203a..205e7a5 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,7 +16,7 @@
#include <linux/msm_ipa.h>
/* internal to ipa */
-#define IPA_PM_MAX_CLIENTS 10
+#define IPA_PM_MAX_CLIENTS 11 /* actual max is value -1 since we start from 1*/
#define IPA_PM_MAX_EX_CL 64
#define IPA_PM_THRESHOLD_MAX 5
#define IPA_PM_EXCEPTION_MAX 2
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index de3711e..1782fdc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3993,6 +3993,7 @@
}
kfree(tag_desc);
tag_desc = NULL;
+ ipa3_ctx->tag_process_before_gating = false;
IPADBG("waiting for TAG response\n");
res = wait_for_completion_timeout(&comp->comp, timeout);
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
index 246f32e..929242a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -253,7 +253,7 @@
(struct wan_ioctl_set_data_quota *)param);
if (rc != 0) {
IPAWANERR("WAN_IOC_SET_DATA_QUOTA failed\n");
- if (retval == -ENODEV)
+ if (rc == -ENODEV)
retval = -ENODEV;
else
retval = -EFAULT;
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index 0be35b3..9fc5a4a 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -50,6 +50,8 @@
#define ATTW_MAX_MS 32
#define LCDB_BST_OUTPUT_VOLTAGE_REG 0x41
+#define PM660_BST_OUTPUT_VOLTAGE_MASK GENMASK(4, 0)
+#define BST_OUTPUT_VOLTAGE_MASK GENMASK(5, 0)
#define LCDB_MODULE_RDY_REG 0x45
#define MODULE_RDY_BIT BIT(7)
@@ -71,7 +73,8 @@
#define LCDB_PS_CTL_REG 0x50
#define EN_PS_BIT BIT(7)
-#define PS_THRESHOLD_MASK GENMASK(1, 0)
+#define PM660_PS_THRESH_MASK GENMASK(1, 0)
+#define PS_THRESH_MASK GENMASK(2, 0)
#define MIN_BST_PS_MA 50
#define MAX_BST_PS_MA 80
@@ -83,6 +86,20 @@
#define LCDB_BST_VREG_OK_CTL_REG 0x55
#define BST_VREG_OK_DEB_MASK GENMASK(1, 0)
+#define LCDB_BST_SS_CTL_REG 0x5B
+#define BST_SS_TIME_MASK GENMASK(1, 0)
+#define BST_PRECHG_SHORT_ALARM_SHIFT 2
+#define BST_PRECHARGE_DONE_DEB_BIT BIT(4)
+#define BST_SS_TIME_OVERRIDE_SHIFT 5
+
+#define BST_SS_TIME_OVERRIDE_0MS 0
+#define BST_SS_TIME_OVERRIDE_0P5_MS 1
+#define BST_SS_TIME_OVERRIDE_1MS 2
+#define BST_SS_TIME_OVERRIDE_2MS 3
+
+#define EN_BST_PRECHG_SHORT_ALARM 0
+#define DIS_BST_PRECHG_SHORT_ALARM 1
+
#define LCDB_SOFT_START_CTL_REG 0x5F
#define LCDB_MISC_CTL_REG 0x60
@@ -147,7 +164,8 @@
#define MIN_SOFT_START_US 0
#define MAX_SOFT_START_US 2000
-#define BST_HEADROOM_DEFAULT_MV 200
+#define PM660_BST_HEADROOM_DEFAULT_MV 200
+#define BST_HEADROOM_DEFAULT_MV 150
struct ldo_regulator {
struct regulator_desc rdesc;
@@ -222,6 +240,7 @@
u16 address;
u8 value;
bool sec_access;
+ bool valid;
};
enum lcdb_module {
@@ -262,6 +281,8 @@
LCDB_LDO_SOFT_START_CTL,
LCDB_NCP_PD_CTL,
LCDB_NCP_SOFT_START_CTL,
+ LCDB_BST_SS_CTL,
+ LCDB_LDO_VREG_OK_CTL,
LCDB_SETTING_MAX,
};
@@ -286,10 +307,11 @@
810,
};
-#define SETTING(_id, _sec_access) \
+#define SETTING(_id, _sec_access, _valid) \
[_id] = { \
.address = _id##_REG, \
.sec_access = _sec_access, \
+ .valid = _valid \
} \
static bool is_between(int value, int min, int max)
@@ -334,12 +356,16 @@
{
int rc;
u8 val = SECURE_UNLOCK_VALUE;
+ u8 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
mutex_lock(&lcdb->read_write_mutex);
- rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG, val);
- if (rc < 0) {
- pr_err("Failed to unlock register rc=%d\n", rc);
- goto fail_write;
+ if (pmic_subtype == PM660L_SUBTYPE) {
+ rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG,
+ val);
+ if (rc < 0) {
+ pr_err("Failed to unlock register rc=%d\n", rc);
+ goto fail_write;
+ }
}
rc = regmap_write(lcdb->regmap, addr, value);
if (rc < 0)
@@ -397,61 +423,174 @@
return rc;
}
+static struct settings lcdb_settings_pm660l[] = {
+ SETTING(LCDB_BST_PD_CTL, false, true),
+ SETTING(LCDB_RDSON_MGMNT, false, true),
+ SETTING(LCDB_MISC_CTL, false, true),
+ SETTING(LCDB_SOFT_START_CTL, false, true),
+ SETTING(LCDB_PFM_CTL, false, true),
+ SETTING(LCDB_PWRUP_PWRDN_CTL, true, true),
+ SETTING(LCDB_LDO_PD_CTL, false, true),
+ SETTING(LCDB_LDO_SOFT_START_CTL, false, true),
+ SETTING(LCDB_NCP_PD_CTL, false, true),
+ SETTING(LCDB_NCP_SOFT_START_CTL, false, true),
+ SETTING(LCDB_BST_SS_CTL, false, false),
+ SETTING(LCDB_LDO_VREG_OK_CTL, false, false),
+};
+
+/* For PMICs like pmi632/pm855L */
static struct settings lcdb_settings[] = {
- SETTING(LCDB_BST_PD_CTL, false),
- SETTING(LCDB_RDSON_MGMNT, false),
- SETTING(LCDB_MISC_CTL, false),
- SETTING(LCDB_SOFT_START_CTL, false),
- SETTING(LCDB_PFM_CTL, false),
- SETTING(LCDB_PWRUP_PWRDN_CTL, true),
- SETTING(LCDB_LDO_PD_CTL, false),
- SETTING(LCDB_LDO_SOFT_START_CTL, false),
- SETTING(LCDB_NCP_PD_CTL, false),
- SETTING(LCDB_NCP_SOFT_START_CTL, false),
+ SETTING(LCDB_BST_PD_CTL, false, true),
+ SETTING(LCDB_RDSON_MGMNT, false, false),
+ SETTING(LCDB_MISC_CTL, false, false),
+ SETTING(LCDB_SOFT_START_CTL, false, false),
+ SETTING(LCDB_PFM_CTL, false, false),
+ SETTING(LCDB_PWRUP_PWRDN_CTL, false, true),
+ SETTING(LCDB_LDO_PD_CTL, false, true),
+ SETTING(LCDB_LDO_SOFT_START_CTL, false, true),
+ SETTING(LCDB_NCP_PD_CTL, false, true),
+ SETTING(LCDB_NCP_SOFT_START_CTL, false, true),
+ SETTING(LCDB_BST_SS_CTL, false, true),
+ SETTING(LCDB_LDO_VREG_OK_CTL, false, true),
};
static int qpnp_lcdb_save_settings(struct qpnp_lcdb *lcdb)
{
- int i, rc = 0;
+ int i, size, rc = 0;
+ struct settings *setting;
+ u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
- for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) {
- rc = qpnp_lcdb_read(lcdb, lcdb->base +
- lcdb_settings[i].address,
- &lcdb_settings[i].value, 1);
- if (rc < 0) {
- pr_err("Failed to read lcdb register address=%x\n",
- lcdb_settings[i].address);
- return rc;
+ if (pmic_subtype == PM660L_SUBTYPE) {
+ setting = lcdb_settings_pm660l;
+ size = ARRAY_SIZE(lcdb_settings_pm660l);
+ } else {
+ setting = lcdb_settings;
+ size = ARRAY_SIZE(lcdb_settings);
+ }
+
+ for (i = 0; i < size; i++) {
+ if (setting[i].valid) {
+ rc = qpnp_lcdb_read(lcdb, lcdb->base +
+ setting[i].address,
+ &setting[i].value, 1);
+ if (rc < 0) {
+ pr_err("Failed to read lcdb register address=%x\n",
+ setting[i].address);
+ return rc;
+ }
}
}
- return rc;
+ return 0;
}
static int qpnp_lcdb_restore_settings(struct qpnp_lcdb *lcdb)
{
- int i, rc = 0;
+ int i, size, rc = 0;
+ struct settings *setting;
+ u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
- for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) {
- if (lcdb_settings[i].sec_access)
- rc = qpnp_lcdb_secure_write(lcdb, lcdb->base +
- lcdb_settings[i].address,
- lcdb_settings[i].value);
- else
- rc = qpnp_lcdb_write(lcdb, lcdb->base +
- lcdb_settings[i].address,
- &lcdb_settings[i].value, 1);
- if (rc < 0) {
- pr_err("Failed to write register address=%x\n",
- lcdb_settings[i].address);
- return rc;
+ if (pmic_subtype == PM660L_SUBTYPE) {
+ setting = lcdb_settings_pm660l;
+ size = ARRAY_SIZE(lcdb_settings_pm660l);
+ } else {
+ setting = lcdb_settings;
+ size = ARRAY_SIZE(lcdb_settings);
+ }
+
+ for (i = 0; i < size; i++) {
+ if (setting[i].valid) {
+ if (setting[i].sec_access)
+ rc = qpnp_lcdb_secure_write(lcdb, lcdb->base +
+ setting[i].address,
+ setting[i].value);
+ else
+ rc = qpnp_lcdb_write(lcdb, lcdb->base +
+ setting[i].address,
+ &setting[i].value, 1);
+ if (rc < 0) {
+ pr_err("Failed to write register address=%x\n",
+ setting[i].address);
+ return rc;
+ }
}
}
+ return 0;
+}
+
+static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb)
+{
+ int rc;
+ u8 val;
+
+ if (!lcdb->settings_saved) {
+ rc = qpnp_lcdb_save_settings(lcdb);
+ if (rc < 0) {
+ pr_err("Failed to save LCDB settings rc=%d\n", rc);
+ return rc;
+ }
+ lcdb->settings_saved = true;
+ }
+
+ val = HWEN_RDY_BIT;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to hw_enable lcdb rc= %d\n", rc);
+ return rc;
+ }
+
+ val = (BST_SS_TIME_OVERRIDE_1MS << BST_SS_TIME_OVERRIDE_SHIFT) |
+ (DIS_BST_PRECHG_SHORT_ALARM << BST_PRECHG_SHORT_ALARM_SHIFT);
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1);
+ if (rc < 0)
+ return rc;
+
+ val = 0;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_SOFT_START_CTL_REG,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+
+ val = 0;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_SOFT_START_CTL_REG,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+
+ val = BOOST_DIS_PULLDOWN_BIT | BOOST_PD_STRENGTH_BIT;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+
+ val = LDO_DIS_PULLDOWN_BIT | LDO_PD_STRENGTH_BIT;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_PD_CTL_REG,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+
+ val = NCP_DIS_PULLDOWN_BIT | NCP_PD_STRENGTH_BIT;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_PD_CTL_REG,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+
+ val = 0;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_PWRUP_PWRDN_CTL_REG,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+
+ val = 0;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_VREG_OK_CTL_REG,
+ &val, 1);
+
return rc;
}
-static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb)
+static int qpnp_lcdb_ttw_enter_pm660l(struct qpnp_lcdb *lcdb)
{
int rc;
u8 val;
@@ -491,7 +630,7 @@
val = 0;
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_SOFT_START_CTL_REG,
- &val, 1);
+ &val, 1);
if (rc < 0) {
pr_err("Failed to set LCDB_SOFT_START rc=%d\n", rc);
return rc;
@@ -715,12 +854,17 @@
{
int rc = 0;
u8 val;
+ u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
if (!lcdb->lcdb_enabled)
return 0;
if (lcdb->ttw_enable) {
- rc = qpnp_lcdb_ttw_enter(lcdb);
+ if (pmic_subtype == PM660L_SUBTYPE)
+ rc = qpnp_lcdb_ttw_enter_pm660l(lcdb);
+ else
+ rc = qpnp_lcdb_ttw_enter(lcdb);
+
if (rc < 0) {
pr_err("Failed to enable TTW mode rc=%d\n", rc);
return rc;
@@ -859,8 +1003,9 @@
int voltage_mv, u8 type)
{
int rc = 0;
- u8 val = 0;
+ u8 val, mask = 0;
int bst_voltage_mv;
+ u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
struct ldo_regulator *ldo = &lcdb->ldo;
struct ncp_regulator *ncp = &lcdb->ncp;
struct bst_params *bst = &lcdb->bst;
@@ -877,10 +1022,11 @@
if (bst_voltage_mv != bst->voltage_mv) {
val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV,
VOLTAGE_STEP_50_MV);
-
+ mask = (pmic_subtype == PM660L_SUBTYPE) ?
+ PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
LCDB_BST_OUTPUT_VOLTAGE_REG,
- SET_OUTPUT_VOLTAGE_MASK, val);
+ mask, val);
if (rc < 0) {
pr_err("Failed to set boost voltage %d mv rc=%d\n",
bst_voltage_mv, rc);
@@ -898,7 +1044,8 @@
int *voltage_mv)
{
int rc;
- u8 val = 0;
+ u8 val, mask = 0;
+ u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG,
&val, 1);
@@ -907,7 +1054,9 @@
return rc;
}
- val &= SET_OUTPUT_VOLTAGE_MASK;
+ mask = (pmic_subtype == PM660L_SUBTYPE) ?
+ PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
+ val &= mask;
*voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV;
return 0;
@@ -1369,6 +1518,8 @@
{
int rc = 0;
struct device_node *node = lcdb->bst.node;
+ u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
+ u16 default_headroom_mv;
/* Boost PD configuration */
lcdb->bst.pd = -EINVAL;
@@ -1402,11 +1553,14 @@
return -EINVAL;
}
+ default_headroom_mv = (pmic_subtype == PM660L_SUBTYPE) ?
+ PM660_BST_HEADROOM_DEFAULT_MV :
+ BST_HEADROOM_DEFAULT_MV;
/* Boost head room configuration */
of_property_read_u16(node, "qcom,bst-headroom-mv",
&lcdb->bst.headroom_mv);
- if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV)
- lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
+ if (lcdb->bst.headroom_mv < default_headroom_mv)
+ lcdb->bst.headroom_mv = default_headroom_mv;
return 0;
}
@@ -1624,7 +1778,8 @@
static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb)
{
int rc = 0;
- u8 val = 0;
+ u8 val, mask = 0;
+ u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
/* configure parameters only if LCDB is disabled */
if (!is_lcdb_enabled(lcdb)) {
@@ -1677,13 +1832,13 @@
}
if (lcdb->bst.ps_threshold != -EINVAL) {
+ mask = (pmic_subtype == PM660L_SUBTYPE) ?
+ PM660_PS_THRESH_MASK : PS_THRESH_MASK;
val = (lcdb->bst.ps_threshold - MIN_BST_PS_MA) / 10;
- val = (lcdb->bst.ps_threshold & PS_THRESHOLD_MASK) |
- EN_PS_BIT;
+ val = (lcdb->bst.ps_threshold & mask) | EN_PS_BIT;
rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
LCDB_PS_CTL_REG,
- PS_THRESHOLD_MASK | EN_PS_BIT,
- val);
+ mask | EN_PS_BIT, val);
if (rc < 0) {
pr_err("Failed to configure BST PS threshold rc=%d",
rc);
@@ -1706,16 +1861,24 @@
}
lcdb->bst.vreg_ok_dbc_us = dbc_us[val & VREG_OK_DEB_MASK];
- rc = qpnp_lcdb_read(lcdb, lcdb->base +
- LCDB_SOFT_START_CTL_REG, &val, 1);
- if (rc < 0) {
- pr_err("Failed to read ncp_soft_start_ctl rc=%d\n", rc);
- return rc;
+ if (pmic_subtype == PM660L_SUBTYPE) {
+ rc = qpnp_lcdb_read(lcdb, lcdb->base +
+ LCDB_SOFT_START_CTL_REG, &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to read lcdb_soft_start_ctl rc=%d\n",
+ rc);
+ return rc;
+ }
+ lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200;
+ } else {
+ rc = qpnp_lcdb_read(lcdb, lcdb->base +
+ LCDB_BST_SS_CTL_REG, &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to read bst_soft_start_ctl rc=%d\n", rc);
+ return rc;
+ }
+ lcdb->bst.soft_start_us = soft_start_us[val & SOFT_START_MASK];
}
- lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200;
-
- if (!lcdb->bst.headroom_mv)
- lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
return 0;
}
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index f34b714..87d1aac 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -75,6 +75,7 @@
obj-y += subsystem_notif.o
obj-y += subsystem_restart.o
obj-y += ramdump.o
+ obj-y += microdump_collector.o
endif
obj-$(CONFIG_MSM_JTAGV8) += jtagv8.o jtagv8-etm.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index dd436da..614b53a 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -596,25 +596,6 @@
strlcpy(do_cleanup_data->name, ss_info->edge,
do_cleanup_data->name_len + 1);
- ret = glink_queue_rx_intent(handle, do_cleanup_data,
- sizeof(struct cleanup_done_msg));
- if (ret) {
- GLINK_SSR_ERR(
- "%s %s: %s, ret[%d], resp. remaining[%d]\n",
- "<SSR>", __func__,
- "queue_rx_intent failed", ret,
- atomic_read(&responses_remaining));
- kfree(do_cleanup_data);
-
- if (!strcmp(ss_leaf_entry->ssr_name, "rpm"))
- panic("%s: Could not queue intent for RPM!\n",
- __func__);
- atomic_dec(&responses_remaining);
- kref_put(&ss_leaf_entry->cb_data->cb_kref,
- cb_data_release);
- continue;
- }
-
if (strcmp(ss_leaf_entry->ssr_name, "rpm"))
ret = glink_tx(handle, do_cleanup_data,
do_cleanup_data,
@@ -640,6 +621,24 @@
cb_data_release);
continue;
}
+ ret = glink_queue_rx_intent(handle, do_cleanup_data,
+ sizeof(struct cleanup_done_msg));
+ if (ret) {
+ GLINK_SSR_ERR(
+ "%s %s: %s, ret[%d], resp. remaining[%d]\n",
+ "<SSR>", __func__,
+ "queue_rx_intent failed", ret,
+ atomic_read(&responses_remaining));
+ kfree(do_cleanup_data);
+
+ if (!strcmp(ss_leaf_entry->ssr_name, "rpm"))
+ panic("%s: Could not queue intent for RPM!\n",
+ __func__);
+ atomic_dec(&responses_remaining);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
+ continue;
+ }
sequence_number++;
kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
}
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 95004a1..a28644d 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -1111,6 +1111,9 @@
if (test_bit(HW_ALWAYS_ON, &quirks))
return 0;
+ if (test_bit(ICNSS_FW_DOWN, &priv->state))
+ return 0;
+
icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state);
spin_lock(&priv->on_off_lock);
diff --git a/drivers/soc/qcom/microdump_collector.c b/drivers/soc/qcom/microdump_collector.c
new file mode 100644
index 0000000..47f3336
--- /dev/null
+++ b/drivers/soc/qcom/microdump_collector.c
@@ -0,0 +1,159 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/smem.h>
+
+/*
+ * This program collects the data from SMEM regions whenever the modem crashes
+ * and stores it in /dev/ramdump_microdump_modem so as to expose it to
+ * user space.
+ */
+
+struct microdump_data {
+ struct ramdump_device *microdump_dev;
+ void *microdump_modem_notify_handler;
+ struct notifier_block microdump_modem_ssr_nb;
+};
+
+static struct microdump_data *drv;
+
+static int microdump_modem_notifier_nb(struct notifier_block *nb,
+ unsigned long code, void *data)
+{
+ int ret = 0;
+ unsigned int size_reason = 0, size_data = 0;
+ char *crash_reason = NULL;
+ char *crash_data = NULL;
+ unsigned int smem_id = 611;
+ struct ramdump_segment segment[2];
+
+ if (code == SUBSYS_RAMDUMP_NOTIFICATION) {
+
+ memset(segment, 0, sizeof(segment));
+
+ crash_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size_reason
+ , 0, SMEM_ANY_HOST_FLAG);
+ if (IS_ERR_OR_NULL(crash_reason)) {
+ pr_err("%s: Error in getting SMEM_reason pointer\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ segment[0].v_address = crash_reason;
+ segment[0].size = size_reason;
+
+ crash_data = smem_get_entry(smem_id, &size_data, SMEM_MODEM, 0);
+ if (IS_ERR_OR_NULL(crash_data)) {
+ pr_err("%s: Error in getting SMEM_data pointer\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ segment[1].v_address = crash_data;
+ segment[1].size = size_data;
+
+ ret = do_ramdump(drv->microdump_dev, segment, 2);
+ if (ret)
+ pr_err("%s: do_ramdump() failed\n", __func__);
+ }
+
+ return ret;
+}
+
+static int microdump_modem_ssr_register_notifier(struct microdump_data *drv)
+{
+ int ret = 0;
+
+ drv->microdump_modem_ssr_nb.notifier_call = microdump_modem_notifier_nb;
+
+ drv->microdump_modem_notify_handler =
+ subsys_notif_register_notifier("modem",
+ &drv->microdump_modem_ssr_nb);
+
+ if (IS_ERR(drv->microdump_modem_notify_handler)) {
+ pr_err("Modem register notifier failed: %ld\n",
+ PTR_ERR(drv->microdump_modem_notify_handler));
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void microdump_modem_ssr_unregister_notifier(struct microdump_data *drv)
+{
+ subsys_notif_unregister_notifier(drv->microdump_modem_notify_handler,
+ &drv->microdump_modem_ssr_nb);
+ drv->microdump_modem_notify_handler = NULL;
+}
+
+/*
+ * microdump_init() - Registers kernel module for microdump collector
+ *
+ * Creates device file /dev/ramdump_microdump_modem and registers handler for
+ * modem SSR events.
+ *
+ * Returns 0 on success and negative error code in case of errors
+ */
+static int __init microdump_init(void)
+{
+ int ret = -ENOMEM;
+
+ drv = kzalloc(sizeof(struct microdump_data), GFP_KERNEL);
+ if (!drv)
+ goto out;
+
+ drv->microdump_dev = create_ramdump_device("microdump_modem", NULL);
+ if (!drv->microdump_dev) {
+ pr_err("%s: Unable to create a microdump_modem ramdump device\n"
+ , __func__);
+ ret = -ENODEV;
+ goto out_kfree;
+ }
+
+ ret = microdump_modem_ssr_register_notifier(drv);
+ if (ret) {
+ destroy_ramdump_device(drv->microdump_dev);
+ goto out_kfree;
+ }
+ return ret;
+out_kfree:
+ pr_err("%s: Failed to register microdump collector\n", __func__);
+ kfree(drv);
+ drv = NULL;
+out:
+ return ret;
+}
+
+static void __exit microdump_exit(void)
+{
+ if (!drv)
+ return;
+
+ if (!IS_ERR(drv->microdump_modem_notify_handler))
+ microdump_modem_ssr_unregister_notifier(drv);
+
+ if (drv->microdump_dev)
+ destroy_ramdump_device(drv->microdump_dev);
+
+ kfree(drv);
+}
+
+module_init(microdump_init);
+module_exit(microdump_exit);
+
+MODULE_DESCRIPTION("Microdump Collector");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 5a110bb..c00749c 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -550,9 +550,9 @@
struct tcs_cmd *cmdlist_sleep = NULL;
struct rpmh_client *cur_mbox = NULL;
struct list_head *cur_bcm_clist = NULL;
- int *n_active = NULL;
- int *n_wake = NULL;
- int *n_sleep = NULL;
+ int n_active[VCD_MAX_CNT];
+ int n_wake[VCD_MAX_CNT];
+ int n_sleep[VCD_MAX_CNT];
int cnt_vcd = 0;
int cnt_active = 0;
int cnt_wake = 0;
@@ -573,8 +573,15 @@
cur_mbox = cur_rsc->rscdev->mbox;
cur_bcm_clist = cur_rsc->rscdev->bcm_clist;
+ cmdlist_active = cur_rsc->rscdev->cmdlist_active;
+ cmdlist_wake = cur_rsc->rscdev->cmdlist_wake;
+ cmdlist_sleep = cur_rsc->rscdev->cmdlist_sleep;
for (i = 0; i < VCD_MAX_CNT; i++) {
+ n_active[i] = 0;
+ n_wake[i] = 0;
+ n_sleep[i] = 0;
+
if (list_empty(&cur_bcm_clist[i]))
continue;
list_for_each_entry(cur_bcm, &cur_bcm_clist[i], link) {
@@ -600,27 +607,6 @@
if (!cnt_active)
goto exit_msm_bus_commit_data;
- n_active = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
- if (!n_active)
- return -ENOMEM;
-
- n_wake = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
- if (!n_wake)
- return -ENOMEM;
-
- n_sleep = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
- if (!n_sleep)
- return -ENOMEM;
-
- if (cnt_active)
- cmdlist_active = kcalloc(cnt_active, sizeof(struct tcs_cmd),
- GFP_KERNEL);
- if (cnt_sleep && cnt_wake) {
- cmdlist_wake = kcalloc(cnt_wake, sizeof(struct tcs_cmd),
- GFP_KERNEL);
- cmdlist_sleep = kcalloc(cnt_sleep, sizeof(struct tcs_cmd),
- GFP_KERNEL);
- }
bcm_cnt = tcs_cmd_list_gen(n_active, n_wake, n_sleep, cmdlist_active,
cmdlist_wake, cmdlist_sleep, cur_bcm_clist);
@@ -654,8 +640,6 @@
if (ret)
MSM_BUS_ERR("%s: error sending wake sets: %d\n",
__func__, ret);
- kfree(n_wake);
- kfree(cmdlist_wake);
}
if (cnt_sleep) {
ret = rpmh_write_batch(cur_mbox, RPMH_SLEEP_STATE,
@@ -663,14 +647,8 @@
if (ret)
MSM_BUS_ERR("%s: error sending sleep sets: %d\n",
__func__, ret);
- kfree(n_sleep);
- kfree(cmdlist_sleep);
}
- kfree(cmdlist_active);
- kfree(n_active);
-
-
list_for_each_entry_safe(node, node_tmp, clist, link) {
if (unlikely(node->node_info->defer_qos))
msm_bus_dev_init_qos(&node->dev, NULL);
@@ -1168,6 +1146,41 @@
return ret;
}
+static int msm_bus_postcon_setup(struct device *bus_dev, void *data)
+{
+ struct msm_bus_node_device_type *bus_node = NULL;
+ struct msm_bus_rsc_device_type *rscdev;
+
+ bus_node = to_msm_bus_node(bus_dev);
+ if (!bus_node) {
+ MSM_BUS_ERR("%s: Can't get device info", __func__);
+ return -ENODEV;
+ }
+
+ if (bus_node->node_info->is_rsc_dev) {
+ rscdev = bus_node->rscdev;
+ rscdev->cmdlist_active = devm_kcalloc(bus_dev,
+ rscdev->num_bcm_devs,
+ sizeof(struct tcs_cmd), GFP_KERNEL);
+ if (!rscdev->cmdlist_active)
+ return -ENOMEM;
+
+ rscdev->cmdlist_wake = devm_kcalloc(bus_dev,
+ rscdev->num_bcm_devs,
+ sizeof(struct tcs_cmd), GFP_KERNEL);
+ if (!rscdev->cmdlist_wake)
+ return -ENOMEM;
+
+ rscdev->cmdlist_sleep = devm_kcalloc(bus_dev,
+ rscdev->num_bcm_devs,
+ sizeof(struct tcs_cmd), GFP_KERNEL);
+ if (!rscdev->cmdlist_sleep)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static int msm_bus_init_clk(struct device *bus_dev,
struct msm_bus_node_device_type *pdata)
{
@@ -1641,6 +1654,7 @@
goto exit_setup_dev_conn;
}
rsc_node = to_msm_bus_node(bus_node->node_info->rsc_devs[j]);
+ rsc_node->rscdev->num_bcm_devs++;
}
exit_setup_dev_conn:
@@ -1771,6 +1785,13 @@
goto exit_device_probe;
}
+ ret = bus_for_each_dev(&msm_bus_type, NULL, NULL,
+ msm_bus_postcon_setup);
+ if (ret) {
+ MSM_BUS_ERR("%s: Error post connection setup", __func__);
+ goto exit_device_probe;
+ }
+
/*
* Setup the QoS for the nodes, don't check the error codes as we
* defer QoS programming to the first transaction in cases of failure
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
index 8929959..b023f72 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -88,6 +88,10 @@
int req_state;
uint32_t acv[NUM_CTX];
uint32_t query_acv[NUM_CTX];
+ struct tcs_cmd *cmdlist_active;
+ struct tcs_cmd *cmdlist_wake;
+ struct tcs_cmd *cmdlist_sleep;
+ int num_bcm_devs;
};
struct msm_bus_bcm_device_type {
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index e0f912d..ee6c4cd 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -411,7 +411,7 @@
/* In case of any failure where reclaiming MBA and DP memory
* could not happen, free the memory here
*/
- if (drv->q6->mba_dp_virt) {
+ if (drv->q6->mba_dp_virt && !drv->mba_mem_dev_fixed) {
if (pil->subsys_vmid > 0)
pil_assign_mem_to_linux(pil, drv->q6->mba_dp_phys,
drv->q6->mba_dp_size);
@@ -648,7 +648,7 @@
{
struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
struct modem_data *md = dev_get_drvdata(pil->dev);
- const struct firmware *fw, *dp_fw = NULL;
+ const struct firmware *fw = NULL, *dp_fw = NULL;
char fw_name_legacy[10] = "mba.b00";
char fw_name[10] = "mba.mbn";
char *dp_name = "msadp";
@@ -660,6 +660,8 @@
struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev;
trace_pil_func(__func__);
+ if (drv->mba_dp_virt && md->mba_mem_dev_fixed)
+ goto mss_reset;
fw_name_p = drv->non_elf_image ? fw_name_legacy : fw_name;
ret = request_firmware(&fw, fw_name_p, pil->dev);
if (ret) {
@@ -749,17 +751,19 @@
goto err_mba_data;
}
}
+ if (dp_fw)
+ release_firmware(dp_fw);
+ release_firmware(fw);
+ dp_fw = NULL;
+ fw = NULL;
+mss_reset:
ret = pil_mss_reset(pil);
if (ret) {
dev_err(pil->dev, "MBA boot failed(rc:%d)\n", ret);
goto err_mss_reset;
}
- if (dp_fw)
- release_firmware(dp_fw);
- release_firmware(fw);
-
return 0;
err_mss_reset:
@@ -772,7 +776,8 @@
err_invalid_fw:
if (dp_fw)
release_firmware(dp_fw);
- release_firmware(fw);
+ if (fw)
+ release_firmware(fw);
drv->mba_dp_virt = NULL;
return ret;
}
@@ -851,10 +856,12 @@
if (pil->subsys_vmid > 0)
pil_assign_mem_to_linux(pil, drv->q6->mba_dp_phys,
drv->q6->mba_dp_size);
- dma_free_attrs(dma_dev, drv->q6->mba_dp_size,
+ if (drv->q6->mba_dp_virt && !drv->mba_mem_dev_fixed) {
+ dma_free_attrs(dma_dev, drv->q6->mba_dp_size,
drv->q6->mba_dp_virt, drv->q6->mba_dp_phys,
drv->attrs_dma);
- drv->q6->mba_dp_virt = NULL;
+ drv->q6->mba_dp_virt = NULL;
+ }
}
return ret;
@@ -921,7 +928,7 @@
}
if (drv->q6) {
- if (drv->q6->mba_dp_virt) {
+ if (drv->q6->mba_dp_virt && !drv->mba_mem_dev_fixed) {
/* Reclaim MBA and DP (if allocated) memory. */
if (pil->subsys_vmid > 0)
pil_assign_mem_to_linux(pil,
diff --git a/drivers/soc/qcom/qmp-debugfs-client.c b/drivers/soc/qcom/qmp-debugfs-client.c
index 578e7f0..d7a473e 100644
--- a/drivers/soc/qcom/qmp-debugfs-client.c
+++ b/drivers/soc/qcom/qmp-debugfs-client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -20,37 +20,55 @@
#include <linux/platform_device.h>
#include <linux/mailbox/qmp.h>
#include <linux/uaccess.h>
+#include <linux/mailbox_controller.h>
#define MAX_MSG_SIZE 96 /* Imposed by the remote*/
+struct qmp_debugfs_data {
+ struct qmp_pkt pkt;
+ char buf[MAX_MSG_SIZE + 1];
+};
+
+static struct qmp_debugfs_data data_pkt[MBOX_TX_QUEUE_LEN];
static struct mbox_chan *chan;
static struct mbox_client *cl;
+static DEFINE_MUTEX(qmp_debugfs_mutex);
+
static ssize_t aop_msg_write(struct file *file, const char __user *userstr,
size_t len, loff_t *pos)
{
- char buf[MAX_MSG_SIZE + 1] = {0};
- struct qmp_pkt pkt;
+ static int count;
int rc;
if (!len || (len > MAX_MSG_SIZE))
return len;
- rc = copy_from_user(buf, userstr, len);
+ mutex_lock(&qmp_debugfs_mutex);
+
+ if (count >= MBOX_TX_QUEUE_LEN)
+ count = 0;
+
+ memset(&(data_pkt[count]), 0, sizeof(data_pkt[count]));
+ rc = copy_from_user(data_pkt[count].buf, userstr, len);
if (rc) {
pr_err("%s copy from user failed, rc=%d\n", __func__, rc);
+ mutex_unlock(&qmp_debugfs_mutex);
return len;
}
/*
* Controller expects a 4 byte aligned buffer
*/
- pkt.size = (len + 0x3) & ~0x3;
- pkt.data = buf;
+ data_pkt[count].pkt.size = (len + 0x3) & ~0x3;
+ data_pkt[count].pkt.data = data_pkt[count].buf;
- if (mbox_send_message(chan, &pkt) < 0)
+ if (mbox_send_message(chan, &(data_pkt[count].pkt)) < 0)
pr_err("Failed to send qmp request\n");
+ else
+ count++;
+ mutex_unlock(&qmp_debugfs_mutex);
return len;
}
@@ -68,7 +86,7 @@
cl->dev = &pdev->dev;
cl->tx_block = true;
- cl->tx_tout = 100;
+ cl->tx_tout = 1000;
cl->knows_txdone = false;
chan = mbox_request_channel(cl, 0);
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 492b68c..cab7178 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -666,7 +666,7 @@
if (unlikely(!is_scm_armv8()))
return -ENODEV;
- ret = allocate_extra_arg_buffer(desc, GFP_KERNEL);
+ ret = allocate_extra_arg_buffer(desc, GFP_NOIO);
if (ret)
return ret;
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 82dea32..556882c 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -652,6 +652,55 @@
return "UNKNOWN SOC TYPE";
}
+const char * __init arch_read_machine_name(void)
+{
+ static char msm_machine_name[256] = "Qualcomm Technologies, Inc. ";
+ static bool string_generated;
+ u32 len = 0;
+ const char *name;
+
+ if (string_generated)
+ return msm_machine_name;
+
+ len = strlen(msm_machine_name);
+ name = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "qcom,msm-name", NULL);
+ if (name)
+ len += snprintf(msm_machine_name + len,
+ sizeof(msm_machine_name) - len,
+ "%s", name);
+ else
+ goto no_prop_path;
+
+ name = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "qcom,pmic-name", NULL);
+ if (name) {
+ len += snprintf(msm_machine_name + len,
+ sizeof(msm_machine_name) - len,
+ "%s", " ");
+ len += snprintf(msm_machine_name + len,
+ sizeof(msm_machine_name) - len,
+ "%s", name);
+ } else
+ goto no_prop_path;
+
+ name = of_flat_dt_get_machine_name();
+ if (name) {
+ len += snprintf(msm_machine_name + len,
+ sizeof(msm_machine_name) - len,
+ "%s", " ");
+ len += snprintf(msm_machine_name + len,
+ sizeof(msm_machine_name) - len,
+ "%s", name);
+ } else
+ goto no_prop_path;
+
+ string_generated = true;
+ return msm_machine_name;
+no_prop_path:
+ return of_flat_dt_get_machine_name();
+}
+
uint32_t socinfo_get_raw_id(void)
{
return socinfo ?
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 58a9308..e796526 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -726,7 +726,6 @@
memset(mas->gsi, 0,
(sizeof(struct spi_geni_gsi) * NUM_SPI_XFER));
geni_se_select_mode(mas->base, GSI_DMA);
- dmaengine_resume(mas->tx);
ret = spi_geni_map_buf(mas, spi_msg);
} else {
dev_err(mas->dev, "%s: Couldn't select mode %d", __func__,
@@ -743,10 +742,8 @@
mas->cur_speed_hz = 0;
mas->cur_word_len = 0;
- if (mas->cur_xfer_mode == GSI_DMA) {
- dmaengine_pause(mas->tx);
+ if (mas->cur_xfer_mode == GSI_DMA)
spi_geni_unmap_buf(mas, spi_msg);
- }
return 0;
}
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 80c3f91..f8a9a2f 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -2591,11 +2591,9 @@
case PM_POST_SUSPEND:
atomic_set(&in_suspend, 0);
list_for_each_entry(tz, &thermal_tz_list, node) {
- mutex_lock(&tz->lock);
thermal_zone_device_reset(tz);
- mod_delayed_work(system_freezable_power_efficient_wq,
- &tz->poll_queue, 0);
- mutex_unlock(&tz->lock);
+ thermal_zone_device_update(tz,
+ THERMAL_EVENT_UNSPECIFIED);
}
break;
default:
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 8718af8..80fdfad 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -90,6 +90,7 @@
return ERR_PTR(-ENOMEM);
}
d_instantiate(dentry, inode);
+ dentry->d_flags |= DCACHE_RCUACCESS;
dentry->d_fsdata = (void *)ns->ops;
d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
if (d) {
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 3e060d9..9a079a6 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -338,6 +338,7 @@
* %CHAN_PATH_SCALING5: ratio of {1, 8}
* %CHAN_PATH_SCALING6: ratio of {10, 81} The actual ratio is (1/8.1).
* %CHAN_PATH_SCALING7: ratio of {1, 10}
+ * %CHAN_PATH_SCALING8: ratio of {1, 16}
* %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
*
* The pre-scaling is applied for signals to be within the voltage range
@@ -352,6 +353,7 @@
PATH_SCALING5,
PATH_SCALING6,
PATH_SCALING7,
+ PATH_SCALING8,
PATH_SCALING_NONE,
};
@@ -380,6 +382,12 @@
* %SCALE_QRD_SKUT1_BATT_THERM: Conversion to temperature(decidegC) based on
* btm parameters for SKUT1
* %SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
+ * %SCALE_BATT_THERM_TEMP: Conversion to temperature(decidegC) based on btm
+ * parameters.
+ * %SCALE_CHRG_TEMP: Conversion for charger temp.
+ * %SCALE_DIE_TEMP: Conversion for die temp.
+ * %SCALE_I_DEFAULT: Default scaling to convert raw adc code to current (uA).
+ * %SCALE_USBIN_I: Conversion for USB input current.
* %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
@@ -397,6 +405,11 @@
SCALE_NCP_03WF683_THERM,
SCALE_QRD_SKUT1_BATT_THERM,
SCALE_PMI_CHG_TEMP = 16,
+ SCALE_BATT_THERM_TEMP,
+ SCALE_CHRG_TEMP,
+ SCALE_DIE_TEMP,
+ SCALE_I_DEFAULT,
+ SCALE_USBIN_I,
SCALE_NONE,
};
@@ -1125,7 +1138,8 @@
{1, 20},
{1, 8},
{10, 81},
- {1, 10}
+ {1, 10},
+ {1, 16}
};
/**
@@ -1347,6 +1361,23 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_iadc_scale_default() - Scales the pre-calibrated digital output
+ * of current ADC to the ADC reference and compensates for the
+ * gain and offset.
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital output of the ADC.
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: Individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: Physical result to be stored.
+ */
+int32_t qpnp_iadc_scale_default(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_pmic_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Performs the AMUX out as 2mV/K and returns
@@ -1384,6 +1415,23 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC.
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital output of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_batt_therm(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature in decidegC.
@@ -1401,6 +1449,61 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_chrg_temp() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. The voltage measured by HKADC is related to
+ * the junction temperature according to
+ * Tj = 377.5 degC - (V_adc / 0.004)
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital output of the ADC.
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: Individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_chrg_temp(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_die_temp() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. The voltage measured by HKADC is related to
+ * the junction temperature according to
+ * Tj = -273.15 degC + (V_adc / 0.002)
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital output of the ADC.
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: Individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_die_temp(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_usbin_curr() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset.
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital output of the ADC.
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: Individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_usbin_curr(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_qrd_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature in decidegC.
@@ -1906,6 +2009,12 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_iadc_scale_default(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_pmic_therm(struct qpnp_vadc_chip *vadc,
int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
@@ -1918,12 +2027,36 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_batt_therm(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *vadc,
int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_chrg_temp(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_die_temp(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_usbin_curr(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_qrd_batt_therm(
struct qpnp_vadc_chip *vadc, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
diff --git a/include/net/cnss2.h b/include/net/cnss2.h
new file mode 100644
index 0000000..ca2de60
--- /dev/null
+++ b/include/net/cnss2.h
@@ -0,0 +1,193 @@
+/* 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
+ * 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 _NET_CNSS2_H
+#define _NET_CNSS2_H
+
+#include <linux/pci.h>
+
+#define CNSS_MAX_FILE_NAME 20
+#define CNSS_MAX_TIMESTAMP_LEN 32
+
+/*
+ * Temporary change for compilation, will be removed
+ * after WLAN host driver switched to use new APIs
+ */
+#define CNSS_API_WITH_DEV
+
+enum cnss_bus_width_type {
+ CNSS_BUS_WIDTH_NONE,
+ CNSS_BUS_WIDTH_LOW,
+ CNSS_BUS_WIDTH_MEDIUM,
+ CNSS_BUS_WIDTH_HIGH
+};
+
+enum cnss_platform_cap_flag {
+ CNSS_HAS_EXTERNAL_SWREG = 0x01,
+ CNSS_HAS_UART_ACCESS = 0x02,
+};
+
+struct cnss_platform_cap {
+ u32 cap_flag;
+};
+
+struct cnss_fw_files {
+ char image_file[CNSS_MAX_FILE_NAME];
+ char board_data[CNSS_MAX_FILE_NAME];
+ char otp_data[CNSS_MAX_FILE_NAME];
+ char utf_file[CNSS_MAX_FILE_NAME];
+ char utf_board_data[CNSS_MAX_FILE_NAME];
+ char epping_file[CNSS_MAX_FILE_NAME];
+ char evicted_data[CNSS_MAX_FILE_NAME];
+};
+
+struct cnss_soc_info {
+ void __iomem *va;
+ phys_addr_t pa;
+ uint32_t chip_id;
+ uint32_t chip_family;
+ uint32_t board_id;
+ uint32_t soc_id;
+ uint32_t fw_version;
+ char fw_build_timestamp[CNSS_MAX_TIMESTAMP_LEN + 1];
+};
+
+struct cnss_wlan_runtime_ops {
+ int (*runtime_suspend)(struct pci_dev *pdev);
+ int (*runtime_resume)(struct pci_dev *pdev);
+};
+
+struct cnss_wlan_driver {
+ char *name;
+ int (*probe)(struct pci_dev *pdev, const struct pci_device_id *id);
+ void (*remove)(struct pci_dev *pdev);
+ int (*reinit)(struct pci_dev *pdev, const struct pci_device_id *id);
+ void (*shutdown)(struct pci_dev *pdev);
+ void (*crash_shutdown)(struct pci_dev *pdev);
+ int (*suspend)(struct pci_dev *pdev, pm_message_t state);
+ int (*resume)(struct pci_dev *pdev);
+ int (*suspend_noirq)(struct pci_dev *pdev);
+ int (*resume_noirq)(struct pci_dev *pdev);
+ void (*modem_status)(struct pci_dev *, int state);
+ void (*update_status)(struct pci_dev *pdev, uint32_t status);
+ struct cnss_wlan_runtime_ops *runtime_ops;
+ const struct pci_device_id *id_table;
+};
+
+enum cnss_driver_status {
+ CNSS_UNINITIALIZED,
+ CNSS_INITIALIZED,
+ CNSS_LOAD_UNLOAD,
+ CNSS_RECOVERY,
+};
+
+struct cnss_ce_tgt_pipe_cfg {
+ u32 pipe_num;
+ u32 pipe_dir;
+ u32 nentries;
+ u32 nbytes_max;
+ u32 flags;
+ u32 reserved;
+};
+
+struct cnss_ce_svc_pipe_cfg {
+ u32 service_id;
+ u32 pipe_dir;
+ u32 pipe_num;
+};
+
+struct cnss_shadow_reg_cfg {
+ u16 ce_id;
+ u16 reg_offset;
+};
+
+struct cnss_shadow_reg_v2_cfg {
+ u32 addr;
+};
+
+struct cnss_wlan_enable_cfg {
+ u32 num_ce_tgt_cfg;
+ struct cnss_ce_tgt_pipe_cfg *ce_tgt_cfg;
+ u32 num_ce_svc_pipe_cfg;
+ struct cnss_ce_svc_pipe_cfg *ce_svc_cfg;
+ u32 num_shadow_reg_cfg;
+ struct cnss_shadow_reg_cfg *shadow_reg_cfg;
+ u32 num_shadow_reg_v2_cfg;
+ struct cnss_shadow_reg_v2_cfg *shadow_reg_v2_cfg;
+};
+
+enum cnss_driver_mode {
+ CNSS_MISSION,
+ CNSS_FTM,
+ CNSS_EPPING,
+ CNSS_WALTEST,
+ CNSS_OFF,
+ CNSS_CCPM,
+ CNSS_QVIT,
+ CNSS_CALIBRATION,
+};
+
+enum cnss_recovery_reason {
+ CNSS_REASON_DEFAULT,
+ CNSS_REASON_LINK_DOWN,
+ CNSS_REASON_RDDM,
+ CNSS_REASON_TIMEOUT,
+};
+
+extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
+extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
+extern void cnss_device_crashed(struct device *dev);
+extern int cnss_pci_link_down(struct device *dev);
+extern void cnss_schedule_recovery(struct device *dev,
+ enum cnss_recovery_reason reason);
+extern int cnss_self_recovery(struct device *dev,
+ enum cnss_recovery_reason reason);
+extern int cnss_force_fw_assert(struct device *dev);
+extern void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size);
+extern int cnss_get_fw_files_for_target(struct device *dev,
+ struct cnss_fw_files *pfw_files,
+ u32 target_type, u32 target_version);
+extern int cnss_get_platform_cap(struct device *dev,
+ struct cnss_platform_cap *cap);
+extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info);
+extern int cnss_request_bus_bandwidth(struct device *dev, int bandwidth);
+extern int cnss_power_up(struct device *dev);
+extern int cnss_power_down(struct device *dev);
+extern void cnss_request_pm_qos(struct device *dev, u32 qos_val);
+extern void cnss_remove_pm_qos(struct device *dev);
+extern void cnss_lock_pm_sem(struct device *dev);
+extern void cnss_release_pm_sem(struct device *dev);
+extern int cnss_wlan_pm_control(struct device *dev, bool vote);
+extern int cnss_auto_suspend(struct device *dev);
+extern int cnss_auto_resume(struct device *dev);
+extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
+ int *num_vectors,
+ uint32_t *user_base_data,
+ uint32_t *base_vector);
+extern int cnss_get_msi_irq(struct device *dev, unsigned int vector);
+extern void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low,
+ uint32_t *msi_addr_high);
+extern int cnss_wlan_enable(struct device *dev,
+ struct cnss_wlan_enable_cfg *config,
+ enum cnss_driver_mode mode,
+ const char *host_version);
+extern int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode);
+extern unsigned int cnss_get_qmi_timeout(void);
+extern int cnss_athdiag_read(struct device *dev, uint32_t offset,
+ uint32_t mem_type, uint32_t data_len,
+ uint8_t *output);
+extern int cnss_athdiag_write(struct device *dev, uint32_t offset,
+ uint32_t mem_type, uint32_t data_len,
+ uint8_t *input);
+extern int cnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode);
+
+#endif /* _NET_CNSS2_H */
diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h
index 87f25b0..f5af604 100644
--- a/include/uapi/media/cam_sensor.h
+++ b/include/uapi/media/cam_sensor.h
@@ -119,20 +119,20 @@
*
* @slave_addr : OIS i2c slave address
* @i2c_freq_mode : i2c frequency mode
+ * @cmd_type : Explains type of command
* @ois_fw_flag : indicates if fw is present or not
* @is_ois_calib : indicates the calibration data is available
* @ois_name : OIS name
* @opcode : opcode
- * @cmd_type : Explains type of command
*/
struct cam_cmd_ois_info {
uint16_t slave_addr;
uint8_t i2c_freq_mode;
+ uint8_t cmd_type;
uint8_t ois_fw_flag;
uint8_t is_ois_calib;
char ois_name[MAX_OIS_NAME_SIZE];
struct cam_ois_opcode opcode;
- uint8_t cmd_type;
} __attribute__((packed));
/**
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index b263bf3..5edfe66 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -230,7 +230,7 @@
if ((unsigned int)end > IPV6_MAXPLEN) {
pr_debug("offset is too large.\n");
- return -1;
+ return -EINVAL;
}
ecn = ip6_frag_ecn(ipv6_hdr(skb));
@@ -263,7 +263,7 @@
* this case. -DaveM
*/
pr_debug("end of fragment not rounded to 8 bytes.\n");
- return -1;
+ return -EPROTO;
}
if (end > fq->q.len) {
/* Some bits beyond end -> corruption. */
@@ -357,7 +357,7 @@
discard_fq:
inet_frag_kill(&fq->q, &nf_frags);
err:
- return -1;
+ return -EINVAL;
}
/*
@@ -566,6 +566,7 @@
int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
{
+ u16 savethdr = skb->transport_header;
struct net_device *dev = skb->dev;
int fhoff, nhoff, ret;
struct frag_hdr *fhdr;
@@ -599,8 +600,12 @@
spin_lock_bh(&fq->q.lock);
- if (nf_ct_frag6_queue(fq, skb, fhdr, nhoff) < 0) {
- ret = -EINVAL;
+ ret = nf_ct_frag6_queue(fq, skb, fhdr, nhoff);
+ if (ret < 0) {
+ if (ret == -EPROTO) {
+ skb->transport_header = savethdr;
+ ret = 0;
+ }
goto out_unlock;
}