Merge "usb: dwc3-msm: Initialize mutex before registering extcon"
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index d11af52..ac9489f 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -54,6 +54,7 @@
| ARM | Cortex-A57 | #852523 | N/A |
| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 |
| ARM | Cortex-A72 | #853709 | N/A |
+| ARM | Cortex-A55 | #1024718 | ARM64_ERRATUM_1024718 |
| ARM | MMU-500 | #841119,#826419 | N/A |
| | | | |
| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 |
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index d150116..1b8b7cf 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -175,6 +175,9 @@
- VR device:
compatible = "qcom,qvr"
+- SVR device:
+ compatible = "qcom,svr"
+
- HDK device:
compatible = "qcom,hdk"
@@ -295,6 +298,7 @@
compatible = "qcom,sda845-mtp"
compatible = "qcom,sda845-qrd"
compatible = "qcom,sda845-hdk"
+compatible = "qcom,sda845-svr"
compatible = "qcom,sdm670-rumi"
compatible = "qcom,sdm670-cdp"
compatible = "qcom,sdm670-mtp"
diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
index 36e1a69..a53eba5 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
@@ -4,15 +4,28 @@
It tells about the individual masters information at any given
time like "system sleep counts", "system sleep last entered at"
and "system sleep accumulated duration" etc. These stats can be
-show to the user using the debugfs interface of the kernel.
+displayed using the sysfs interface.
To achieve this, device tree node has been added.
+Additionally, RPMH master stats also maintains application processor's
+master stats. It uses profiling units to calculate power down and power
+up stats.
+
The required properties for rpmh-master-stats are:
-- compatible: "qcom,rpmh-master-stats".
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,rpmh-master-stats-v1".
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Specifies physical address of start of profiling unit.
Example:
qcom,rpmh-master-stats {
compatible = "qcom,rpmh-master-stats";
+ reg = <0xb221200 0x60>;
};
diff --git a/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
new file mode 100644
index 0000000..0149ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
@@ -0,0 +1,57 @@
+* Qualcomm Technologies, Inc. Connectivity SubSystem Platform Driver
+
+This platform driver adds support for the CNSS subsystem used for SDIO
+based Wi-Fi devices. It also adds support to manage two 1.8V voltage
+regulators and WLAN power enable 3.3V regulators. The main purpose of this
+device tree entry below is to invoke the CNSS SDIO platform driver
+and provide handle to the WLAN power enable 3.3V pmic GPIO and two 1.8V
+PMIC voltage regulator resources.
+
+Required properties:
+ - compatible: "qcom,cnss_sdio"
+ - reg: memory resource to save firmware dump, optional.
+ - reg-names: memory resource name.
+ - subsys-name: cnss sdio subsytem device name, required.
+ - vdd-wlan-supply: phandle to the WLAN vdd regulator device tree node.
+ - vdd-wlan-dsrc-supply: phandle to the WLAN dsrc vdd regulator device tree node.
+ - vdd-wlan-io-supply: phandle to the WLAN IO regulator device tree node.
+ - vdd-wlan-xtal-supply: phandle to the WLAM XTAL regulator device tree node.
+
+Optional properties:
+ - pinctrl-names: Names corresponding to the numbered pinctrl states
+ - pinctrl-<n>: Pinctrl states as described in
+ bindings/pinctrl/pinctrl-bindings.txt
+ - qcom,is-antenna-shared: Enabled for Platforms with both sdio and pcie QCA
+ Chipsets are attached.
+ - qcom,cnss-enable-bus-bandwidth: Boolean - Define this property when target
+ support to vote for bus bandwidth.
+ - qcom,msm-bus,name: client name for msm bus register.
+ - qcom,msm-bus,num-cases: number of cases for bus scaling.
+ - qcom,msm-bus,num-paths: number of paths for bus scale vector.
+ - qcom,msm-bus,vectors-KBps: bus scale vector table.
+ - qcom,skip-wlan-en-toggle: Boolean property to be enabled for platforms where
+ wlan_en toggling is not supported.
+Example:
+ qcom,cnss-sdio {
+ compatible = "qcom,cnss_sdio";
+ reg = <0x87a00000, 0x200000>;
+ reg-names = "ramdump";
+ subsys-name = "AR6320";
+ vdd-wlan-supply = <&rome_vreg>;
+ vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>;
+ vdd-wlan-io-supply = <&mdm9607_l11>;
+ vdd-wlan-xtal-supply = <&mdm9607_l2>;
+ qcom,is-antenna-shared;
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&cnss_sdio_active>;
+ pinctrl-1 = <&cnss_sdio_sleep>;
+ qcom,cnss-enable-bus-bandwidth;
+ qcom,msm-bus,name = "msm-cnss";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <79 512 0 0>, /* No vote */
+ <79 512 6250 200000>, /* 50 Mbps */
+ <79 512 25000 200000>, /* 200 Mbps */
+ <79 512 2048000 4096000>; /* MAX */
+ };
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index a89b834..0f40cbce 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -66,6 +66,10 @@
- qcom,dsi-display: Specifies dsi display is present
- qcom,hdmi-display: Specifies hdmi is present
- qcom,dp-display: Specified dp is present
+- ports: This video port is used when external bridge is present. The connection is modelled
+ using the OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+ Video port 0 is for the bridge output. The remote endpoint phandle should be
+ mipi_dsi_device device node.
- qcom,<type>-supply-entries: A node that lists the elements of the supply used by the
a particular "type" of DSI module. The module "types"
can be "core", "ctrl", and "phy". Within the same type,
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 493a1aa..7bcb2dc 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi-panel
+Qualcomm Technologies, Inc. mdss-dsi-panel
mdss-dsi-panel is a dsi panel device which supports panels that
are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
index 2f74f7f..8b593a9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi
+Qualcomm Technologies, Inc. mdss-dsi
mdss-dsi is the master DSI device which supports multiple DSI host controllers that
are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index c474b88..3d649e5 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS EDP
+Qualcomm Technologies, Inc. MDSS EDP
MDSS EDP is a edp driver which supports panels that are compatible with
VESA EDP display interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index e33d358..3661221 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS MDP
+Qualcomm Technologies, Inc. MDSS MDP
MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to
drive user interface to different panel interfaces. MDP driver is the core of
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index 2c193c2..6b9238c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS pll for DSI/EDP/HDMI
+Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI
mdss-pll is a pll controller device which supports pll devices that are
compatiable with MIPI display serial interface specification, HDMI and edp.
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index 7f95ed4..285a14f 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -1,4 +1,4 @@
-* Qualcomm HDMI Tx
+* Qualcomm Technologies, Inc. HDMI Tx
Required properties:
- cell-index: hdmi tx controller index
diff --git a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
index b399145..c679fe6 100644
--- a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
@@ -42,6 +42,7 @@
currently supported names are:
- gfx3d_user : Used for the 'normal' GPU address space.
- gfx3d_secure : Used for the content protection address space.
+ - gfx3d_secure_alt : Used for the content protection address space for alternative SID.
Each sub node has the following required properties:
- compatible : "qcom,smmu-kgsl-cb"
@@ -83,4 +84,9 @@
compatible = "qcom,smmu-kgsl-cb";
iommus = <&kgsl_smmu 2>;
};
+
+ gfx3d_secure_alt: gfx3d_secure_alt {
+ compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
+ };
};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 55cd383..375e929 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -130,6 +130,13 @@
mask - mask for the relevant bits in the efuse register.
shift - number of bits to right shift to get the disable_gpu
fuse bit value.
+
+- qcom,soc-hw-rev-efuse: SOC hardware revision fuse information in the format
+ <offset bit_position mask>
+ offset - offset of the efuse register from the base.
+ bit_position - hardware revision starting bit in the efuse register.
+ mask - mask for the relevant bits in the efuse register.
+
- qcom,highest-bank-bit:
Specify the bit of the highest DDR bank. This
is programmed into protected registers and also
@@ -200,6 +207,9 @@
- qcom,gpu-quirk-limit-uche-gbif-rw:
Limit number of read and write transactions from UCHE block to
GBIF to avoid possible deadlock between GBIF, SMMU and MEMNOC.
+- qcom,gpu-quirk-mmu-secure-cb-alt:
+ Select alternate secure context bank to generate SID1 for
+ secure playback.
KGSL Memory Pools:
- qcom,gpu-mempools: Container for sets of GPU mempools.Multiple sets
@@ -230,7 +240,7 @@
Defines a SOC hardware revision.
Properties:
-- reg:
+- qcom,soc-hw-revision:
Identifier for the hardware revision - must match the value read
from the hardware.
- qcom,chipid:
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
index 176f9e1..169f848 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
@@ -182,6 +182,10 @@
be edge triggered. Otherwise, it is level triggered.
- qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe
signal polarity is set to active-low, else it is active-high.
+- qcom,symmetry-en : Boolean property to specify if the flash LEDs under a
+ switch node are controlled symmetrically. This needs
+ to be specified if a group of flash LED channels are
+ connected to a single LED.
Example:
qcom,leds@d300 {
compatible = "qcom,qpnp-flash-led-v2";
@@ -302,6 +306,7 @@
qcom,led-mask = <3>;
qcom,default-led-trigger =
"switch0_trigger";
+ qcom,symmetry-en;
};
pmi8998_switch1: qcom,led_switch_1 {
diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt
index d272b7f..73cd1db 100644
--- a/Documentation/devicetree/bindings/platform/msm/ipa.txt
+++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt
@@ -135,6 +135,8 @@
- qcom,additional-mapping: specifies any addtional mapping needed for this
context bank. The format is <iova pa size>
+- qcom,ipa-q6-smem-size: specifies the Q6 SMEM partition size
+
IPA SMP2P sub nodes
-compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
index 8e17f80..65c3cb8 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
@@ -114,12 +114,6 @@
SOC. If this property is not specified, then auto recharge will
be based off battery voltage.
-- qcom,micro-usb
- Usage: optional
- Value type: <empty>
- Definition: Boolean flag which indicates that the platform only support
- micro usb port.
-
- qcom,suspend-input-on-debug-batt
Usage: optional
Value type: <empty>
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67ffaed..6ff6e9b 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -19,6 +19,7 @@
should be "qcom,sdm630-tsens" for 630 TSENS driver.
should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
should be "qcom,tsens24xx" for 2.4 TSENS controller.
+ should be "qcom,msm8937-tsens" for 8937 TSENS driver.
The compatible property is used to identify the respective controller to use
for the corresponding SoC.
- reg : offset and length of the TSENS registers with associated property in reg-names
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index c51581d..8f6af4c 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -1,7 +1,9 @@
dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb \
sdxpoorwills-cdp.dtb \
- sdxpoorwills-mtp.dtb
+ sdxpoorwills-mtp.dtb \
+ sdxpoorwills-pcie-ep-cdp.dtb \
+ sdxpoorwills-pcie-ep-mtp.dtb
targets += dtbs
targets += $(addprefix ../, $(dtb-y))
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 261829f..38137a2 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
@@ -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
@@ -12,10 +12,7 @@
/dts-v1/;
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
-#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+#include "sdxpoorwills-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP";
@@ -23,132 +20,3 @@
"qcom,sdxpoorwills", "qcom,cdp";
qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>;
};
-
-&serial_uart {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_console_active>;
- status = "ok";
-};
-
-&qnand_1 {
- status = "ok";
-};
-
-&sdhc_1 {
- vdd-supply = <&vreg_sd_mmc>;
-
- vdd-io-supply = <&pmxpoorwills_l7>;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <200 10000>;
-
- pinctrl-names = "active", "sleep";
- pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
- pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
- qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
- 200000000>;
- qcom,devfreq,freq-table = <50000000 200000000>;
-
- cd-gpios = <&tlmm 93 0x1>;
-
- status = "ok";
-};
-
-&pmxpoorwills_vadc {
- 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>;
- };
-
- 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 = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@4d {
- label = "pa_therm1";
- reg = <0x4d>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@4e {
- label = "pa_therm2";
- reg = <0x4e>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@4f {
- label = "mdm_case_therm";
- reg = <0x4f>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@52 {
- label = "ambient_therm";
- reg = <0x52>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-};
-
-&i2c_3 {
- status = "okay";
- #include "smb138x.dtsi"
-};
-
-&smb138x {
- pinctrl-names = "default";
- pinctrl-0 = <&smb_int_default>;
- interrupt-parent = <&tlmm>;
- interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
- smb1381_charger: qcom,smb1381-charger@1000 {
- compatible = "qcom,smb138x-charger";
- qcom,use-extcon;
- };
-};
-
-&smb138x_vbus {
- status = "okay";
-};
-
-&usb {
- status = "okay";
- extcon = <&smb1381_charger>;
-};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
new file mode 100644
index 0000000..b5944d1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
@@ -0,0 +1,144 @@
+/* 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 "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+
+&serial_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_console_active>;
+ status = "ok";
+};
+
+&qnand_1 {
+ status = "ok";
+};
+
+&sdhc_1 {
+ vdd-supply = <&vreg_sd_mmc>;
+
+ vdd-io-supply = <&pmxpoorwills_l7>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 10000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
+ cd-gpios = <&tlmm 93 0x1>;
+
+ status = "ok";
+};
+
+&pmxpoorwills_vadc {
+ 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>;
+ };
+
+ 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 = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "pa_therm1";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4e {
+ label = "pa_therm2";
+ reg = <0x4e>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "mdm_case_therm";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@52 {
+ label = "ambient_therm";
+ reg = <0x52>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
+
+&i2c_3 {
+ status = "okay";
+ #include "smb138x.dtsi"
+};
+
+&smb138x {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+ smb1381_charger: qcom,smb1381-charger@1000 {
+ compatible = "qcom,smb138x-charger";
+ qcom,use-extcon;
+ };
+};
+
+&smb138x_vbus {
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+ extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index cba6262..a0bcdc9 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
@@ -12,10 +12,7 @@
/dts-v1/;
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
-#include "sdxpoorwills-mtp-audio-overlay.dtsi"
+#include "sdxpoorwills-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP";
@@ -23,132 +20,3 @@
"qcom,sdxpoorwills", "qcom,mtp";
qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>;
};
-
-&serial_uart {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_console_active>;
- status = "ok";
-};
-
-&qnand_1 {
- status = "ok";
-};
-
-&sdhc_1 {
- vdd-supply = <&vreg_sd_mmc>;
-
- vdd-io-supply = <&pmxpoorwills_l7>;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <200 10000>;
-
- pinctrl-names = "active", "sleep";
- pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
- pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
- qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
- 200000000>;
- qcom,devfreq,freq-table = <50000000 200000000>;
-
- cd-gpios = <&tlmm 93 0x1>;
-
- status = "ok";
-};
-
-&pmxpoorwills_vadc {
- 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>;
- };
-
- 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 = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@4d {
- label = "pa_therm1";
- reg = <0x4d>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@4e {
- label = "pa_therm2";
- reg = <0x4e>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@4f {
- label = "mdm_case_therm";
- reg = <0x4f>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@52 {
- label = "ambient_therm";
- reg = <0x52>;
- qcom,decimation = <2>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-};
-
-&i2c_3 {
- status = "okay";
- #include "smb138x.dtsi"
-};
-
-&smb138x {
- pinctrl-names = "default";
- pinctrl-0 = <&smb_int_default>;
- interrupt-parent = <&tlmm>;
- interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
- smb1381_charger: qcom,smb1381-charger@1000 {
- compatible = "qcom,smb138x-charger";
- qcom,use-extcon;
- };
-};
-
-&smb138x_vbus {
- status = "okay";
-};
-
-&usb {
- status = "okay";
- extcon = <&smb1381_charger>;
-};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
new file mode 100644
index 0000000..63cc3a4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
@@ -0,0 +1,144 @@
+/* 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 "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-mtp-audio-overlay.dtsi"
+
+&serial_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_console_active>;
+ status = "ok";
+};
+
+&qnand_1 {
+ status = "ok";
+};
+
+&sdhc_1 {
+ vdd-supply = <&vreg_sd_mmc>;
+
+ vdd-io-supply = <&pmxpoorwills_l7>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 10000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
+ cd-gpios = <&tlmm 93 0x1>;
+
+ status = "ok";
+};
+
+&pmxpoorwills_vadc {
+ 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>;
+ };
+
+ 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 = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "pa_therm1";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4e {
+ label = "pa_therm2";
+ reg = <0x4e>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "mdm_case_therm";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@52 {
+ label = "ambient_therm";
+ reg = <0x52>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
+
+&i2c_3 {
+ status = "okay";
+ #include "smb138x.dtsi"
+};
+
+&smb138x {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+ smb1381_charger: qcom,smb1381-charger@1000 {
+ compatible = "qcom,smb138x-charger";
+ qcom,use-extcon;
+ };
+};
+
+&smb138x_vbus {
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+ extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
index 194bfeb..8339f9a 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
@@ -1,5 +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
@@ -13,12 +12,11 @@
/dts-v1/;
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdxpoorwills-cdp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
- compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
- qcom,board-id = <8 4>;
-
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP CDP";
+ compatible = "qcom,sdxpoorwills-cdp",
+ "qcom,sdxpoorwills", "qcom,cdp";
+ qcom,board-id = <1 0x1>, <1 0x101>;
};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
index 194bfeb..2240133 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
@@ -1,5 +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
@@ -13,12 +12,11 @@
/dts-v1/;
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdxpoorwills-mtp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
- compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
- qcom,board-id = <8 4>;
-
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP MTP";
+ compatible = "qcom,sdxpoorwills-mtp",
+ "qcom,sdxpoorwills", "qcom,mtp";
+ qcom,board-id = <8 0x1>, <8 0x101>;
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index deed94d..6c172c1 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -984,6 +984,44 @@
};
};
+ pcie_ep {
+ pcie_ep_clkreq_default: pcie_ep_clkreq_default {
+ mux {
+ pins = "gpio56";
+ function = "pcie_clkreq";
+ };
+ config {
+ pins = "gpio56";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ pcie_ep_perst_default: pcie_ep_perst_default {
+ mux {
+ pins = "gpio57";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio57";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ pcie_ep_wake_default: pcie_ep_wake_default {
+ mux {
+ pins = "gpio53";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio53";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
wcd9xxx_intr {
wcd_intr_default: wcd_intr_default{
mux {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index c9a5d1b..c23d48b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -283,6 +283,142 @@
reg = <0x00137004 0x4>;
};
+ pcie_ep: qcom,pcie@40002000 {
+ compatible = "qcom,pcie-ep";
+
+ reg = <0x40002000 0x1000>,
+ <0x40000000 0xf1d>,
+ <0x40000f20 0xa8>,
+ <0x40001000 0x1000>,
+ <0x01c00000 0x2000>,
+ <0x01c02000 0x1000>,
+ <0x01c04000 0x1000>;
+ reg-names = "msi", "dm_core", "elbi", "iatu", "parf",
+ "phy", "mmio";
+
+ #address-cells = <0>;
+ interrupt-parent = <&pcie_ep>;
+ interrupts = <0>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 140 0>;
+ interrupt-names = "int_global";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_ep_clkreq_default &pcie_ep_perst_default
+ &pcie_ep_wake_default>;
+
+ clkreq-gpio = <&tlmm 56 0>;
+ 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>;
+
+ qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>;
+ qcom,vreg-0.9-voltage-level = <872000 872000 24000>;
+
+ clocks = <&clock_gcc GCC_PCIE_PIPE_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_AUX_CLK>,
+ <&clock_gcc GCC_PCIE_0_CLKREF_CLK>,
+ <&clock_gcc GCC_PCIE_SLEEP_CLK>,
+ <&clock_gcc GCC_PCIE_SLV_Q2A_AXI_CLK>;
+
+ clock-names = "pcie_0_pipe_clk", "pcie_0_cfg_ahb_clk",
+ "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+ "pcie_0_aux_clk", "pcie_0_ldo",
+ "pcie_0_sleep_clk",
+ "pcie_0_slv_q2a_axi_clk";
+
+ resets = <&clock_gcc GCC_PCIE_BCR>,
+ <&clock_gcc GCC_PCIE_PHY_BCR>;
+
+ reset-names = "pcie_0_core_reset",
+ "pcie_0_phy_reset";
+
+ qcom,msm-bus,name = "pcie-ep";
+ 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>;
+
+ qcom,pcie-link-speed = <2>;
+ qcom,pcie-phy-ver = <6>;
+ qcom,pcie-active-config;
+ qcom,pcie-aggregated-irq;
+ qcom,pcie-mhi-a7-irq;
+ qcom,phy-status-reg = <0x814>;
+
+ qcom,phy-init = <0x840 0x001 0x0 0x1
+ 0x094 0x000 0x0 0x1
+ 0x058 0x00f 0x0 0x1
+ 0x0a4 0x042 0x0 0x1
+ 0x110 0x024 0x0 0x1
+ 0x1bc 0x011 0x0 0x1
+ 0x0bc 0x019 0x0 0x1
+ 0x0b0 0x004 0x0 0x1
+ 0x0ac 0x0ff 0x0 0x1
+ 0x158 0x001 0x0 0x1
+ 0x074 0x028 0x0 0x1
+ 0x07c 0x00d 0x0 0x1
+ 0x084 0x000 0x0 0x1
+ 0x1b0 0x01d 0x0 0x1
+ 0x1ac 0x056 0x0 0x1
+ 0x04c 0x007 0x0 0x1
+ 0x050 0x007 0x0 0x1
+ 0x0f0 0x003 0x0 0x1
+ 0x0ec 0x0fb 0x0 0x1
+ 0x00c 0x002 0x0 0x1
+ 0x29c 0x012 0x0 0x1
+ 0x284 0x005 0x0 0x1
+ 0x234 0x0d9 0x0 0x1
+ 0x238 0x0cc 0x0 0x1
+ 0x51c 0x003 0x0 0x1
+ 0x518 0x01c 0x0 0x1
+ 0x524 0x014 0x0 0x1
+ 0x4ec 0x00e 0x0 0x1
+ 0x4f0 0x04a 0x0 0x1
+ 0x4f4 0x00f 0x0 0x1
+ 0x5b4 0x004 0x0 0x1
+ 0x434 0x07f 0x0 0x1
+ 0x444 0x070 0x0 0x1
+ 0x510 0x017 0x0 0x1
+ 0x4d8 0x001 0x0 0x1
+ 0x598 0x0e0 0x0 0x1
+ 0x59c 0x0c8 0x0 0x1
+ 0x5a0 0x0c8 0x0 0x1
+ 0x5a4 0x009 0x0 0x1
+ 0x5a8 0x0b1 0x0 0x1
+ 0x584 0x024 0x0 0x1
+ 0x588 0x0e4 0x0 0x1
+ 0x58c 0x0ec 0x0 0x1
+ 0x590 0x039 0x0 0x1
+ 0x594 0x036 0x0 0x1
+ 0x570 0x0ef 0x0 0x1
+ 0x574 0x0ef 0x0 0x1
+ 0x578 0x02f 0x0 0x1
+ 0x57c 0x0d3 0x0 0x1
+ 0x580 0x040 0x0 0x1
+ 0x4fc 0x000 0x0 0x1
+ 0x4f8 0x0c0 0x0 0x1
+ 0x9a4 0x001 0x0 0x1
+ 0x840 0x001 0x0 0x1
+ 0x848 0x001 0x0 0x1
+ 0x8a0 0x011 0x0 0x1
+ 0x988 0x088 0x0 0x1
+ 0x998 0x008 0x0 0x1
+ 0x8dc 0x00d 0x0 0x1
+ 0x800 0x000 0x0 0x1
+ 0x844 0x003 0x0 0x1>;
+
+ status = "disabled";
+ };
+
gdsc_emac: qcom,gdsc@147004 {
compatible = "qcom,gdsc";
regulator-name = "gdsc_emac";
@@ -606,8 +742,6 @@
qcom,mhi-event-ring-id-limits = <9 10>; /* start and end */
qcom,modem-cfg-emb-pipe-flt;
qcom,use-ipa-pm;
- qcom,arm-smmu;
- qcom,smmu-fast-map;
qcom,bandwidth-vote-for-ipa;
qcom,msm-bus,name = "ipa";
qcom,msm-bus,num-cases = <5>;
@@ -746,30 +880,6 @@
compatible = "qcom,smp2pgpio-map-ipa-1-in";
gpios = <&smp2pgpio_ipa_1_in 0 0>;
};
-
- ipa_smmu_ap: ipa_smmu_ap {
- compatible = "qcom,ipa-smmu-ap-cb";
- iommus = <&apps_smmu 0x5E0 0x0>;
- qcom,iova-mapping = <0x20000000 0x40000000>;
- qcom,additional-mapping =
- /* modem tables in IMEM */
- <0x14686000 0x14686000 0x3000>;
- qcom,ipa-q6-smem-size = <16384>;
- };
-
- ipa_smmu_wlan: ipa_smmu_wlan {
- compatible = "qcom,ipa-smmu-wlan-cb";
- iommus = <&apps_smmu 0x5E1 0x0>;
- qcom,additional-mapping =
- /* ipa-uc ram */
- <0x1E60000 0x1E60000 0xA000>;
- };
-
- ipa_smmu_uc: ipa_smmu_uc {
- compatible = "qcom,ipa-smmu-uc-cb";
- iommus = <&apps_smmu 0x5E2 0x0>;
- qcom,iova-mapping = <0x40000000 0x20000000>;
- };
};
qmp_aop: qcom,qmp-aop@c300000 {
@@ -801,6 +911,11 @@
qcom,bark-time = <11000>;
qcom,pet-time = <10000>;
};
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>;
+ };
};
#include "pmxpoorwills.dtsi"
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 98c0aa6..d1dc88e 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -302,6 +302,7 @@
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
@@ -351,6 +352,7 @@
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
@@ -358,7 +360,33 @@
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
@@ -367,6 +395,21 @@
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_PARANOID_SD_INIT=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 38e79f5..2029932 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -312,6 +312,7 @@
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
@@ -362,6 +363,7 @@
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
@@ -369,7 +371,33 @@
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
@@ -378,6 +406,21 @@
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_RING_BUFFER=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 865406f..1cde900 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -387,6 +387,7 @@
CONFIG_FAULT_INJECTION_DEBUG_FS=y
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_DEBUG_USER=y
CONFIG_CORESIGHT=y
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 28dcd44..dad9fcb 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/sched_energy.h>
#include <asm/cputype.h>
#include <asm/topology.h>
@@ -505,125 +506,31 @@
update_cpu_capacity(cpuid);
}
-/*
- * ARM TC2 specific energy cost model data. There are no unit requirements for
- * the data. Data can be normalized to any reference point, but the
- * normalization must be consistent. That is, one bogo-joule/watt must be the
- * same quantity for all data, but we don't care what it is.
- */
-static struct idle_state idle_states_cluster_a7[] = {
- { .power = 25 }, /* arch_cpu_idle() (active idle) = WFI */
- { .power = 25 }, /* WFI */
- { .power = 10 }, /* cluster-sleep-l */
- };
-
-static struct idle_state idle_states_cluster_a15[] = {
- { .power = 70 }, /* arch_cpu_idle() (active idle) = WFI */
- { .power = 70 }, /* WFI */
- { .power = 25 }, /* cluster-sleep-b */
- };
-
-static struct capacity_state cap_states_cluster_a7[] = {
- /* Cluster only power */
- { .cap = 150, .power = 2967, }, /* 350 MHz */
- { .cap = 172, .power = 2792, }, /* 400 MHz */
- { .cap = 215, .power = 2810, }, /* 500 MHz */
- { .cap = 258, .power = 2815, }, /* 600 MHz */
- { .cap = 301, .power = 2919, }, /* 700 MHz */
- { .cap = 344, .power = 2847, }, /* 800 MHz */
- { .cap = 387, .power = 3917, }, /* 900 MHz */
- { .cap = 430, .power = 4905, }, /* 1000 MHz */
- };
-
-static struct capacity_state cap_states_cluster_a15[] = {
- /* Cluster only power */
- { .cap = 426, .power = 7920, }, /* 500 MHz */
- { .cap = 512, .power = 8165, }, /* 600 MHz */
- { .cap = 597, .power = 8172, }, /* 700 MHz */
- { .cap = 682, .power = 8195, }, /* 800 MHz */
- { .cap = 768, .power = 8265, }, /* 900 MHz */
- { .cap = 853, .power = 8446, }, /* 1000 MHz */
- { .cap = 938, .power = 11426, }, /* 1100 MHz */
- { .cap = 1024, .power = 15200, }, /* 1200 MHz */
- };
-
-static struct sched_group_energy energy_cluster_a7 = {
- .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a7),
- .idle_states = idle_states_cluster_a7,
- .nr_cap_states = ARRAY_SIZE(cap_states_cluster_a7),
- .cap_states = cap_states_cluster_a7,
-};
-
-static struct sched_group_energy energy_cluster_a15 = {
- .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a15),
- .idle_states = idle_states_cluster_a15,
- .nr_cap_states = ARRAY_SIZE(cap_states_cluster_a15),
- .cap_states = cap_states_cluster_a15,
-};
-
-static struct idle_state idle_states_core_a7[] = {
- { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
- { .power = 0 }, /* WFI */
- { .power = 0 }, /* cluster-sleep-l */
- };
-
-static struct idle_state idle_states_core_a15[] = {
- { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
- { .power = 0 }, /* WFI */
- { .power = 0 }, /* cluster-sleep-b */
- };
-
-static struct capacity_state cap_states_core_a7[] = {
- /* Power per cpu */
- { .cap = 150, .power = 187, }, /* 350 MHz */
- { .cap = 172, .power = 275, }, /* 400 MHz */
- { .cap = 215, .power = 334, }, /* 500 MHz */
- { .cap = 258, .power = 407, }, /* 600 MHz */
- { .cap = 301, .power = 447, }, /* 700 MHz */
- { .cap = 344, .power = 549, }, /* 800 MHz */
- { .cap = 387, .power = 761, }, /* 900 MHz */
- { .cap = 430, .power = 1024, }, /* 1000 MHz */
- };
-
-static struct capacity_state cap_states_core_a15[] = {
- /* Power per cpu */
- { .cap = 426, .power = 2021, }, /* 500 MHz */
- { .cap = 512, .power = 2312, }, /* 600 MHz */
- { .cap = 597, .power = 2756, }, /* 700 MHz */
- { .cap = 682, .power = 3125, }, /* 800 MHz */
- { .cap = 768, .power = 3524, }, /* 900 MHz */
- { .cap = 853, .power = 3846, }, /* 1000 MHz */
- { .cap = 938, .power = 5177, }, /* 1100 MHz */
- { .cap = 1024, .power = 6997, }, /* 1200 MHz */
- };
-
-static struct sched_group_energy energy_core_a7 = {
- .nr_idle_states = ARRAY_SIZE(idle_states_core_a7),
- .idle_states = idle_states_core_a7,
- .nr_cap_states = ARRAY_SIZE(cap_states_core_a7),
- .cap_states = cap_states_core_a7,
-};
-
-static struct sched_group_energy energy_core_a15 = {
- .nr_idle_states = ARRAY_SIZE(idle_states_core_a15),
- .idle_states = idle_states_core_a15,
- .nr_cap_states = ARRAY_SIZE(cap_states_core_a15),
- .cap_states = cap_states_core_a15,
-};
-
/* sd energy functions */
static inline
const struct sched_group_energy * const cpu_cluster_energy(int cpu)
{
- return cpu_topology[cpu].socket_id ? &energy_cluster_a7 :
- &energy_cluster_a15;
+ struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1];
+
+ if (sched_is_energy_aware() && !sge) {
+ pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu);
+ return NULL;
+ }
+
+ return sge;
}
static inline
const struct sched_group_energy * const cpu_core_energy(int cpu)
{
- return cpu_topology[cpu].socket_id ? &energy_core_a7 :
- &energy_core_a15;
+ struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0];
+
+ if (sched_is_energy_aware() && !sge) {
+ pr_warn("Invalid sched_group_energy for CPU%d\n", cpu);
+ return NULL;
+ }
+
+ return sge;
}
static inline int cpu_corepower_flags(void)
@@ -688,4 +595,5 @@
/* Set scheduler topology descriptor */
set_sched_topology(arm_topology);
+ init_sched_energy_costs();
}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 32a80d6..cf5311f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -432,6 +432,20 @@
If unsure, say Y.
+config ARM64_ERRATUM_1024718
+ bool "Cortex-A55: 1024718: Update of DBM/AP bits without break before make might result in incorrect update"
+ default y
+ help
+ This option adds work around for Arm Cortex-A55 Erratum 1024718.
+
+ Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect
+ update of the hardware dirty bit when the DBM/AP bits are updated
+ without a break-before-make. The work around is to disable the usage
+ of hardware DBM locally on the affected cores. CPUs not affected by
+ erratum will continue to use the feature.
+
+ If unsure, say Y.
+
config CAVIUM_ERRATUM_22375
bool "Cavium erratum 22375, 24313"
default y
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index b7640d3..1de858e 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -181,6 +181,24 @@
This enables support for the sdm632 chipset. If you do not
wish to build a kernel that runs on this chipset, say 'N' here.
+config ARCH_SDM429
+ bool "Enable Support for Qualcomm Technologies Inc. SDM429"
+ depends on ARCH_QCOM
+ select CPU_FREQ_QCOM
+ select COMMON_CLK_MSM
+ help
+ This enables support for the sdm429 chipset. If you do not
+ wish to build a kernel that runs on this chipset, say 'N' here.
+
+config ARCH_SDM439
+ bool "Enable Support for Qualcomm Technologies Inc. SDM439"
+ depends on ARCH_QCOM
+ select CPU_FREQ_QCOM
+ select COMMON_CLK_MSM
+ help
+ This enables support for the sdm439 chipset. If you do not
+ wish to build a kernel that runs on this chipset, say 'N' here.
+
config ARCH_ROCKCHIP
bool "Rockchip Platforms"
select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 1390a7b..7e5cdf2 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -34,12 +34,14 @@
sda845-v2-mtp-overlay.dtbo \
sda845-v2-qrd-overlay.dtbo \
sda845-v2-hdk-overlay.dtbo \
+ sda845-v2-svr-overlay.dtbo \
sda845-v2-4k-panel-mtp-overlay.dtbo \
sda845-v2-4k-panel-cdp-overlay.dtbo \
sda845-v2-4k-panel-qrd-overlay.dtbo \
sda845-v2.1-cdp-overlay.dtbo \
sda845-v2.1-mtp-overlay.dtbo \
sda845-v2.1-qrd-overlay.dtbo \
+ sda845-v2.1-svr-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 \
@@ -77,12 +79,14 @@
sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
sda845-v2-hdk-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-svr-overlay.dtbo-base := sda845-v2.dtb
sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb
sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb
sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb
sda845-v2.1-cdp-overlay.dtbo-base := sda845-v2.1.dtb
sda845-v2.1-mtp-overlay.dtbo-base := sda845-v2.1.dtb
sda845-v2.1-qrd-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-svr-overlay.dtbo-base := sda845-v2.1.dtb
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
@@ -169,7 +173,7 @@
qcs605-cdp-overlay.dtbo-base := qcs605.dtb
qcs605-mtp-overlay.dtbo-base := qcs605.dtb
qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb
-qcs605-lc-mtp-overlay.dtbo-base := qcs605.dtb
+qcs605-lc-mtp-overlay.dtbo-base := qcs605-lc.dtb
qcs605-360camera-overlay.dtbo-base := qcs605.dtb
else
@@ -201,8 +205,7 @@
qcs605-360camera.dtb \
qcs605-mtp.dtb \
qcs605-cdp.dtb \
- qcs605-external-codec-mtp.dtb \
- qcs605-lc-mtp.dtb
+ qcs605-external-codec-mtp.dtb
endif
ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dts b/arch/arm64/boot/dts/qcom/apq8053.dts
index bf9e2f2..6bb67c3 100644
--- a/arch/arm64/boot/dts/qcom/apq8053.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053.dts
@@ -14,6 +14,8 @@
/dts-v1/;
#include "apq8053.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
/ {
model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
new file mode 100644
index 0000000..77f2a1d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
@@ -0,0 +1,133 @@
+/* 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.
+ */
+
+&mdss_mdp {
+ dsi_hx8399c_truly_vid: qcom,mdss_dsi_hx8399c_truly_video{
+ qcom,mdss-dsi-panel-name =
+ "hx8399c video mode dsi truly panel";
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <2160>;
+ qcom,mdss-dsi-h-front-porch = <24>;
+ qcom,mdss-dsi-h-back-porch = <24>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <40>;
+ qcom,mdss-dsi-v-front-porch = <36>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [
+ 39 01 00 00 00 00 04
+ b9 ff 83 99
+ 39 01 00 00 00 00 02
+ d2 88
+ 39 01 00 00 00 00 10
+ b1 02 04 74 94 01 32 33
+ 11 11 e6 5d 56 73 02 02
+ 39 01 00 00 00 00 10
+ b2 00 80 80 cc 05 07 5a
+ 11 10 10 00 1e 70 03 D4
+ 39 01 00 00 00 00 2d
+ b4 00 ff 59 59 0c ac 00
+ 00 0c 00 07 0a 00 28 07
+ 08 0c 21 03 00 00 00 ae
+ 87 59 59 0c ac 00 00 0c
+ 00 07 0a 00 28 07 08 0c
+ 01 00 00 ae 01
+ 39 01 00 00 05 00 22
+ d3 00 00 01 01 00 00 10
+ 10 00 00 03 00 03 00 08
+ 78 08 78 00 00 00 00 00
+ 24 02 05 05 03 00 00 00
+ 05 40
+ 39 01 00 00 05 00 21
+ d5 20 20 19 19 18 18 02
+ 03 00 01 24 24 18 18 18
+ 18 24 24 00 00 00 00 00
+ 00 00 00 2f 2f 30 30 31
+ 31
+ 39 01 00 00 05 00 21
+ d6 24 24 18 18 19 19 01
+ 00 03 02 24 24 18 18 18
+ 18 20 20 40 40 40 40 40
+ 40 40 40 2f 2f 30 30 31
+ 31
+ 39 01 00 00 00 00 02
+ bd 00
+ 39 01 00 00 00 00 11
+ d8 aa aa aa aa aa aa aa
+ aa aa ba aa aa aa ba aa
+ aa
+ 39 01 00 00 00 00 02
+ bd 01
+ 39 01 00 00 00 00 11
+ d8 82 ea aa aa 82 ea aa
+ aa 82 ea aa aa 82 ea aa
+ aa
+ 39 01 00 00 00 00 02
+ bd 02
+ 39 01 00 00 00 00 09
+ d8 ff ff c0 3f ff ff c0
+ 3f
+ 39 01 00 00 00 00 02
+ bd 00
+ 39 01 00 00 05 00 37
+ e0 08 2a 39 35 74 7c 87
+ 7f 84 8a 8e 91 93 96 9b
+ 9c 9e a5 a6 ae a1 af b2
+ 5c 58 63 74 08 2a 39 35
+ 74 7c 87 7f 84 8a 8e 91
+ 93 96 9b 9c 9e a5 a6 ae
+ a1 af b2 5c 58 63 74
+ 39 01 00 00 00 00 03
+ b6 7e 7e
+ 39 01 00 00 00 00 02
+ cc 08
+ 39 01 00 00 00 00 06
+ c7 00 08 00 01 08
+ 39 01 00 00 00 00 03
+ c0 25 5a
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 14 00 02 29 00];
+ qcom,mdss-dsi-off-command = [
+ 05 01 00 00 14 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-lane-map = "lane_map_0123";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-tx-eot-append;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-t-clk-post = <0x0e>;
+ qcom,mdss-dsi-t-clk-pre = <0x31>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-lp11-init;
+ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
new file mode 100644
index 0000000..3a5d272
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
@@ -0,0 +1,50 @@
+/* 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.
+ */
+
+&mdss_mdp {
+ dsi_dual_test_cmd: qcom,mdss_dsi_test_oled_cmd {
+ qcom,mdss-dsi-panel-name =
+ "Dual test cmd mode DSI amoled non-DSC panel";
+ qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,adjust-timer-wakeup-ms = <1>;
+ qcom,mdss-dsi-reset-sequence = <1 2>, <0 2>, <1 2>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-te-pin-select = <1>;
+ qcom,mdss-dsi-wr-mem-start = <0x2c>;
+ qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+ qcom,mdss-dsi-te-dcs-command = <1>;
+ qcom,mdss-dsi-te-check-enable;
+ qcom,mdss-dsi-te-using-te-pin;
+ qcom,mdss-dsi-hfp-power-mode;
+ qcom,mdss-dsi-hbp-power-mode;
+ qcom,mdss-dsi-hsa-power-mode;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
new file mode 100644
index 0000000..5c379d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+qcom,fg-gen3-batterydata-demo-3600mah {
+ qcom,faschg-current-ma = <5000>;
+ qcom,max-voltage-uv = <4350000>;
+ qcom,nom-batt-capacity-mah = <3600>;
+ qcom,batt-id-kohm = <100>;
+ qcom,battery-beta = <3435>;
+ qcom,battery-type = "fg-gen3-batterydata-demo-3600mah";
+ qcom,checksum = <0xA401>;
+ qcom,gui-version = "PMI8998GUI - 2.0.0.54";
+ qcom,fg-profile-data = [
+ B2 1F 79 05
+ 86 0A 36 06
+ 8D 1D 6F F4
+ 39 12 9A 14
+ DC 18 91 22
+ 26 3C EB 4B
+ 5D 00 00 00
+ 11 00 00 00
+ 00 00 78 BC
+ 26 CD 48 C2
+ 1E 00 08 00
+ 78 C5 64 E5
+ 95 FC 1D F3
+ E1 F5 ED 0B
+ 33 FD 8C 2B
+ 1E 06 09 20
+ 27 00 14 00
+ D8 1F 77 05
+ 8B 0A 57 FC
+ 59 1D 8B 00
+ 33 03 78 0C
+ 0F 19 ED 22
+ 6B 45 21 53
+ 5A 00 00 00
+ 0E 00 00 00
+ 00 00 F7 07
+ 55 C2 AA AA
+ 1A 00 00 00
+ B1 EA 64 E5
+ 7C 06 93 F2
+ 71 FD 9E 03
+ 80 0A 7A 22
+ CF 33 CC FF
+ 07 10 00 00
+ 6F 0E 99 45
+ 1A 00 40 00
+ 13 01 0A FA
+ FF 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
index d0eff96..3da16e4 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
@@ -33,11 +33,11 @@
};
};
-&pmi8950_fg {
+&qpnp_fg {
qcom,battery-data = <&mtp_batterydata>;
};
-&pmi8950_charger {
+&qpnp_smbcharger {
qcom,battery-data = <&mtp_batterydata>;
qcom,chg-led-sw-controls;
qcom,chg-led-support;
diff --git a/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
new file mode 100644
index 0000000..d5537e9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
@@ -0,0 +1,229 @@
+/* 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
+ * 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 {
+ qcom,smp2p-modem@0xb011008 {
+ compatible = "qcom,smp2p";
+ reg = <0xb011008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-wcnss@0xb011008 {
+ compatible = "qcom,smp2p";
+ reg = <0xb011008 0x4>;
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <0 143 1>;
+ };
+
+ qcom,smp2p-adsp@0xb011008 {
+ compatible = "qcom,smp2p";
+ reg = <0xb011008 0x4>;
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 291 1>;
+ };
+
+ smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+ gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+ gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+ /* ssr - inbound entry from mss. */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to mss */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - inbound entry from lpass. */
+ smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to lpass */
+ smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - inbound entry from wcnss. */
+ smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to wcnss */
+ smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index 285727d..baa6ad5 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -121,6 +121,7 @@
#include "msm8937-pinctrl.dtsi"
#include "msm8937-cpu.dtsi"
#include "msm8937-ion.dtsi"
+#include "msm8937-smp2p.dtsi"
&soc {
#address-cells = <1>;
@@ -234,6 +235,174 @@
qcom,pipe-attr-ee;
};
+ thermal_zones: thermal-zones {
+ aoss0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 0>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-core-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 1>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdss-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 2>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ camera-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 3>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpuss-0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu2-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu3-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu4-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 8>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc0_cpu0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 9>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 10>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+ };
+
+ tsens0: tsens@4a8000 {
+ compatible = "qcom,msm8937-tsens";
+ reg = <0x4a8000 0x1000>,
+ <0x4a9000 0x1000>,
+ <0xa4000 0x1000>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical", "tsens_eeprom_physical";
+ interrupts = <0 184 0>;
+ interrupt-names = "tsens-upper-lower";
+ #thermal-sensor-cells = <1>;
+ };
+
slim_msm: slim@c140000{
cell-index = <1>;
compatible = "qcom,slim-ngd";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
index 34004b0..00203a2 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
@@ -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
@@ -32,5 +32,11 @@
memory-region = <&qseecom_mem>;
qcom,ion-heap-type = "DMA";
};
+
+ qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+ reg = <19>;
+ memory-region = <&qseecom_ta_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
index 4fa5cd1..28a6b74 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -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
@@ -23,6 +23,7 @@
#include "dsi-panel-truly-wuxga-video.dtsi"
#include "dsi-panel-lt8912-480p-video.dtsi"
#include "dsi-panel-lt8912-1080p-video.dtsi"
+#include "dsi-panel-hx8399c-fhd-plus-video.dtsi"
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -55,6 +56,9 @@
23 1e 08 09 05 03 04 a0
23 1e 08 09 05 03 04 a0
23 1a 08 09 05 03 04 a0];
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+
};
&dsi_truly_1080_cmd {
@@ -63,6 +67,8 @@
23 1e 08 09 05 03 04 a0
23 1e 08 09 05 03 04 a0
23 1a 08 09 05 03 04 a0];
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "bta_check";
};
&dsi_r69006_1080p_video {
@@ -81,6 +87,27 @@
24 1b 08 09 05 03 04 a0];
};
+&dsi_hx8399c_truly_vid {
+ qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1c 08 09 05 03 04 a0];
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-status-read-length = <4>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+ qcom,mdss-dsi-min-refresh-rate = <55>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update =
+ "dfps_immediate_porch_mode_vfp";
+};
+
&dsi_adv7533_1080p {
qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
24 1f 08 09 05 03 04 a0
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
index 49956df..c6ae512 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
@@ -20,3 +20,21 @@
model = "MTP";
qcom,board-id = <8 0>;
};
+
+/{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&qpnp_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+ qcom,battery-data = <&mtp_batterydata>;
+ qcom,chg-led-sw-controls;
+ qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index b53f7b8..97c6db3 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -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
@@ -33,16 +33,12 @@
};
};
-&pmi8950_fg {
+&qpnp_fg {
qcom,battery-data = <&mtp_batterydata>;
};
-&pmi8950_charger {
+&qpnp_smbcharger {
qcom,battery-data = <&mtp_batterydata>;
qcom,chg-led-sw-controls;
qcom,chg-led-support;
};
-
-&usb3 {
- extcon = <&pmi8950_charger>;
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
index a9f64a4..5ec92ae 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
@@ -14,6 +14,8 @@
/dts-v1/;
#include "msm8953.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
index a208e1a..80050c4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
@@ -24,10 +24,10 @@
&usb3 {
vbus_dwc3-supply = <&smbcharger_charger_otg>;
- extcon = <&pmi8937_charger>;
+ extcon = <&qpnp_smbcharger>;
};
-&pmi8937_charger {
+&qpnp_smbcharger {
qcom,external-typec;
qcom,typec-psy-name = "typec";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
index e9c80a0d..ba5c3c7 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
@@ -14,6 +14,8 @@
/dts-v1/;
#include "msm8953.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
index 28fc0d7..c36dd1b 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
@@ -24,7 +24,7 @@
&usb3 {
vbus_dwc3-supply = <&smbcharger_charger_otg>;
- extcon = <&pmi8940_charger>;
+ extcon = <&qpnp_smbcharger>;
};
&labibb {
@@ -36,7 +36,7 @@
qcom,qpnp-ibb-discharge-resistor = <32>;
};
-&pmi8940_charger {
+&qpnp_smbcharger {
qcom,external-typec;
qcom,typec-psy-name = "typec";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
index 139ef1e..d81a0a5 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -29,10 +29,10 @@
&usb3 {
vbus_dwc3-supply = <&smbcharger_charger_otg>;
- extcon = <&pmi8950_charger>;
+ extcon = <&qpnp_smbcharger>;
};
-&pmi8950_charger {
+&qpnp_smbcharger {
qcom,external-typec;
qcom,typec-psy-name = "typec";
};
@@ -46,23 +46,3 @@
lab-supply = <&lab_regulator>;
ibb-supply = <&ibb_regulator>;
};
-
-&dsi_panel_pwr_supply {
- qcom,panel-supply-entry@2 {
- reg = <2>;
- qcom,supply-name = "lab";
- qcom,supply-min-voltage = <4600000>;
- qcom,supply-max-voltage = <6000000>;
- 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 = <4600000>;
- qcom,supply-max-voltage = <6000000>;
- qcom,supply-enable-load = <100000>;
- qcom,supply-disable-load = <100>;
- qcom,supply-post-on-sleep = <10>;
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
new file mode 100644
index 0000000..e82e2c8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
@@ -0,0 +1,227 @@
+/* Copyright (c) 2015-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.
+ */
+&soc {
+ qcom,smp2p-modem@0x0b011008 {
+ compatible = "qcom,smp2p";
+ reg = <0x0b011008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-wcnss@0x0b011008 {
+ compatible = "qcom,smp2p";
+ reg = <0x0b011008 0x4>;
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <0 143 1>;
+ };
+
+ qcom,smp2p-adsp@0x0b011008 {
+ compatible = "qcom,smp2p";
+ reg = <0x0b011008 0x4>;
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 291 1>;
+ };
+
+ smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+ gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+ gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+ /* ssr - inbound entry from mss. */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to mss */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - inbound entry from lpass. */
+ smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to lpass */
+ smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
new file mode 100644
index 0000000..cb8cdf2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
@@ -0,0 +1,197 @@
+/* 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
+ * 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 {
+ qcom,vidc@1d00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0x01d00000 0xff000>,
+ <0x000a4124 0x4>,
+ <0x000a0164 0x4>;
+ reg-names = "vidc", "efuse", "efuse2";
+ qcom,platform-version = <0x00180000 0x13>;
+ qcom,capability-version = <0x00002000 0x0d>;
+ interrupts = <0 44 0>;
+ /* Regulators */
+ venus-supply = <&gdsc_venus>;
+ venus-core0-supply = <&gdsc_venus_core0>;
+ /* Clocks */
+ clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_ahb_clk>,
+ <&clock_gcc clk_gcc_venus0_axi_clk>;
+ clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0 0x0 0x0>;
+ qcom,hfi = "venus";
+ qcom,hfi-version = "3xx";
+ qcom,reg-presets = <0xe0020 0x05555556>,
+ <0xe0024 0x05555556>,
+ <0x80124 0x00000003>;
+ qcom,qdss-presets = <0x825000 0x1000>,
+ <0x826000 0x1000>,
+ <0x821000 0x1000>,
+ <0x802000 0x1000>,
+ <0x9180000 0x1000>,
+ <0x9181000 0x1000>;
+ qcom,max-hw-load = <1044480>; /* 4096 x 2176 @ 30 fps */
+ qcom,slave-side-cp;
+ qcom,sw-power-collapse;
+ qcom,firmware-name = "venus";
+ qcom,pm-qos-latency-us = <213>;
+ qcom,dcvs-tbl =
+ /* Dec UHD@30 H.264, HEVC, VP8, VP9 - NOM to NOM+*/
+ <816000 816000 979200 0x3f00000c>,
+
+ /* Enc 3840x1920@30 H.264/HEVC Turbo to Nom+ */
+ <855000 821100 979200 0x4000004>,
+
+ /* Enc True4K@24 H.264/HEVC Nom to Nom+ */
+ <816000 720000 835584 0x4000004>;
+ qcom,dcvs-limit =
+ <28800 24>, /* Encoder 3840x1920 */
+ <32400 24>; /* Decoder UHD */
+ qcom,allowed-clock-rates = <465000000 400000000
+ 360000000 310000000 228570000 114290000>;
+ qcom,clock-freq-tbl {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,cycles-per-mb = <863>;
+ qcom,low-power-mode-factor = <35616>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xf3ffffff>;
+ qcom,cycles-per-mb = <355>;
+ };
+ qcom,profile-hevcdec {
+ qcom,codec-mask = <0x0c000000>;
+ qcom,cycles-per-mb = <400>;
+ };
+ };
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus = <&apps_iommu 0x800 0x01>,
+ <&apps_iommu 0x807 0x00>,
+ <&apps_iommu 0x808 0x07>,
+ <&apps_iommu 0x810 0x01>,
+ <&apps_iommu 0x828 0x01>,
+ <&apps_iommu 0x82c 0x01>,
+ <&apps_iommu 0x821 0x10>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x5dc00000 0x7f000000
+ 0xdcc00000 0x1000000>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus = <&apps_iommu 0x900 0x0>,
+ <&apps_iommu 0x902 0x8>,
+ <&apps_iommu 0x909 0x2>,
+ <&apps_iommu 0x90e 0x0>,
+ <&apps_iommu 0x926 0x0>,
+ <&apps_iommu 0x929 0x2>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x12c00000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus = <&apps_iommu 0x904 0x8>,
+ <&apps_iommu 0x910 0x0>,
+ <&apps_iommu 0x92c 0x0>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus = <&apps_iommu 0x908 0x0>,
+ <&apps_iommu 0x905 0xa>,
+ <&apps_iommu 0x925 0x8>,
+ <&apps_iommu 0x928 0x0>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+
+ /* Buses */
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "venus-ddr-gov";
+ qcom,bus-range-kbps = <1000 2365000>;
+ };
+
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1 1>;
+ };
+ };
+
+ venus-ddr-gov {
+ compatible = "qcom,msm-vidc,governor,table";
+ name = "venus-ddr-gov";
+ status = "ok";
+ qcom,bus-freq-table {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,load-busfreq-tbl =
+ <979200 1044000>, /* UHD30E */
+ <864000 887000>, /* 720p240LPE */
+ <489600 666000>, /* 1080p60E */
+ <432000 578000>, /* 720p120E */
+ <244800 346000>, /* 1080p30E */
+ <216000 293000>, /* 720p60E */
+ <108000 151000>, /* 720p30E */
+ <0 0>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,load-busfreq-tbl =
+ <979200 2365000>, /* UHD30D */
+ <864000 1978000>, /* 720p240D */
+ <489600 1133000>, /* 1080p60D */
+ <432000 994000>, /* 720p120D */
+ <244800 580000>, /* 1080p30D */
+ <216000 501000>, /* 720p60E */
+ <108000 255000>, /* 720p30D */
+ <0 0>;
+ };
+ qcom,profile-dec-ubwc {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,ubwc-mode;
+ qcom,load-busfreq-tbl =
+ <979200 1892000>, /* UHD30D */
+ <864000 1554000>, /* 720p240D */
+ <489600 895000>, /* 1080p60D */
+ <432000 781000>, /* 720p120D */
+ <244800 460000>, /* 1080p30D */
+ <216000 301000>, /* 720p60E */
+ <108000 202000>, /* 720p30D */
+ <0 0>;
+ };
+ };
+ };
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts
index ddf2218..2f6cbc4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953.dts
@@ -14,6 +14,8 @@
/dts-v1/;
#include "msm8953.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 2861fd5..90eb0bb 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -103,6 +103,14 @@
compatible = "shared-dma-pool";
reusable;
alignment = <0 0x400000>;
+ size = <0 0x0400000>;
+ };
+
+ qseecom_ta_mem: qseecom_ta_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
size = <0 0x1000000>;
};
@@ -164,9 +172,11 @@
#include "msm8953-coresight.dtsi"
#include "msm8953-ion.dtsi"
#include "msm-arm-smmu-8953.dtsi"
+#include "msm8953-vidc.dtsi"
#include "msm8953-gpu.dtsi"
#include "msm8953-mdss.dtsi"
#include "msm8953-mdss-pll.dtsi"
+#include "msm8953-smp2p.dtsi"
&soc {
#address-cells = <1>;
@@ -1160,6 +1170,11 @@
reg = <0x94c 200>;
};
+
+ diag_dload@c8 {
+ compatible = "qcom,msm-imem-diag-dload";
+ reg = <0xc8 200>;
+ };
};
qcom,memshare {
@@ -1876,6 +1891,11 @@
qcom,wcnss-adc_tm = <&pm8953_adc_tm>;
};
+ ssc_sensors: qcom,msm-ssc-sensors {
+ compatible = "qcom,msm-ssc-sensors";
+ status = "ok";
+ };
+
};
#include "pm8953-rpm-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index e5963ef..3561656 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -214,6 +214,151 @@
#gpio-cells = <2>;
qcom,gpios-disallowed = <1>;
};
+
+ pmi632_charger: qcom,qpnp-smb5 {
+ compatible = "qcom,qpnp-smb5";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,pmic-revid = <&pmi632_revid>;
+ dpdm-supply = <&qusb_phy>;
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts =
+ <0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x6 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x10 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+ interrupt-names = "chgr-error",
+ "chg-state-change",
+ "step-chg-state-change",
+ "step-chg-soc-update-fail",
+ "step-chg-soc-update-req",
+ "fg-fvcal-qualified",
+ "vph-alarm",
+ "vph-drop-prechg";
+ };
+
+ qcom,dcdc@1100 {
+ reg = <0x1100 0x100>;
+ interrupts =
+ <0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x11 0x3 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "otg-fail",
+ "otg-oc-disable-sw",
+ "otg-oc-hiccup",
+ "bsm-active",
+ "high-duty-cycle",
+ "input-current-limiting",
+ "concurrent-mode-disable",
+ "switcher-power-ok";
+ };
+
+ qcom,batif@1200 {
+ reg = <0x1200 0x100>;
+ interrupts =
+ <0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x12 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+ interrupt-names = "bat-temp",
+ "all-chnl-conv-done",
+ "bat-ov",
+ "bat-low",
+ "bat-therm-or-id-missing",
+ "bat-terminal-missing",
+ "buck-oc",
+ "vph-ov";
+ };
+
+ qcom,usb@1300 {
+ reg = <0x1300 0x100>;
+ interrupts =
+ <0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x4 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x13 0x5 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "usbin-collapse",
+ "usbin-vashdn",
+ "usbin-uv",
+ "usbin-ov",
+ "usbin-plugin",
+ "usbin-revi-change",
+ "usbin-src-change",
+ "usbin-icl-change";
+ };
+
+ qcom,typec@1500 {
+ reg = <0x1500 0x100>;
+ interrupts =
+ <0x2 0x15 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x15 0x1 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x15 0x3 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x15 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x15 0x6 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "typec-or-rid-detect-change",
+ "typec-vpd-detect",
+ "typec-cc-state-change",
+ "typec-vconn-oc",
+ "typec-vbus-change",
+ "typec-attach-detach",
+ "typec-legacy-cable-detect",
+ "typec-try-snk-src-detect";
+ };
+
+ qcom,misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts =
+ <0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x16 0x2 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x16 0x3 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x16 0x4 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+ <0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "wdog-snarl",
+ "wdog-bark",
+ "aicl-fail",
+ "aicl-done",
+ "smb-en",
+ "imp-trigger",
+ "temp-change",
+ "temp-change-smb";
+ };
+
+ smb5_vbus: qcom,smb5-vbus {
+ regulator-name = "smb5-vbus";
+ };
+ };
};
pmi632_3: qcom,pmi632@3 {
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index a7aa08a..c72225d 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -153,7 +153,7 @@
#gpio-cells = <2>;
};
- pmi8937_charger: qcom,qpnp-smbcharger {
+ qpnp_smbcharger: qcom,qpnp-smbcharger {
compatible = "qcom,qpnp-smbcharger";
#address-cells = <1>;
#size-cells = <1>;
@@ -268,7 +268,7 @@
};
};
- pmi8937_fg: qcom,fg {
+ qpnp_fg: qcom,fg {
compatible = "qcom,qpnp-fg";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
index c6d5c87..d83145c 100644
--- a/arch/arm64/boot/dts/qcom/pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
@@ -152,7 +152,7 @@
#gpio-cells = <2>;
};
- pmi8940_charger: qcom,qpnp-smbcharger {
+ qpnp_smbcharger: qcom,qpnp-smbcharger {
compatible = "qcom,qpnp-smbcharger";
#address-cells = <1>;
#size-cells = <1>;
@@ -264,7 +264,7 @@
};
};
- pmi8940_fg: qcom,fg {
+ qpnp_fg: qcom,fg {
compatible = "qcom,qpnp-fg";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index 4e82cfe..e3388c1 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -168,7 +168,7 @@
#gpio-cells = <2>;
};
- pmi8950_charger: qcom,qpnp-smbcharger {
+ qpnp_smbcharger: qcom,qpnp-smbcharger {
compatible = "qcom,qpnp-smbcharger";
#address-cells = <1>;
#size-cells = <1>;
@@ -284,7 +284,7 @@
};
};
- pmi8950_fg: qcom,fg {
+ qpnp_fg: qcom,fg {
compatible = "qcom,qpnp-fg";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
index 01471b6..1429880 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
@@ -1,5 +1,5 @@
/*
- * 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
@@ -32,3 +32,47 @@
<0x0001001b 0x0102001a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&cam_cci {
+ /delete-node/ qcom,cam-sensor@1;
+ qcom,cam-sensor@1 {
+ cell-index = <1>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x1>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <90>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ eeprom-src = <&eeprom_rear_aux>;
+ cam_vio-supply = <&camera_vio_ldo>;
+ cam_vana-supply = <&camera_vana_ldo>;
+ cam_vdig-supply = <&camera_ldo>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <1352000 1800000 2850000 0>;
+ rgltr-max-voltage = <1352000 1800000 2850000 0>;
+ rgltr-load-current = <105000 0 80000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 28 0>;
+ gpio-reset = <1>;
+ gpio-req-tbl-num = <0 1>;
+ gpio-req-tbl-flags = <1 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
index ea10fa0..6c6012e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
@@ -1,5 +1,5 @@
/*
- * 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
@@ -26,3 +26,47 @@
<0x0001001b 0x0102001a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&cam_cci {
+ /delete-node/ qcom,cam-sensor@1;
+ qcom,cam-sensor@1 {
+ cell-index = <1>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x1>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <90>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ eeprom-src = <&eeprom_rear_aux>;
+ cam_vio-supply = <&camera_vio_ldo>;
+ cam_vana-supply = <&camera_vana_ldo>;
+ cam_vdig-supply = <&camera_ldo>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <1352000 1800000 2850000 0>;
+ rgltr-max-voltage = <1352000 1800000 2850000 0>;
+ rgltr-load-current = <105000 0 80000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 28 0>;
+ gpio-reset = <1>;
+ gpio-req-tbl-num = <0 1>;
+ gpio-req-tbl-flags = <1 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
index 025d9a2..d0b5bf3 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.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
@@ -10,196 +10,16 @@
* GNU General Public License for more details.
*/
-#include "pm8005.dtsi"
-#include "sdm670-pmic-overlay.dtsi"
-#include "qcs605-pm660-pm8005-regulator.dtsi"
+#include "qcs605-lc-pmic-overlay.dtsi"
-/ {
- cpus {
- /delete-node/ cpu@200;
- /delete-node/ cpu@300;
- /delete-node/ cpu@400;
- /delete-node/ cpu@500;
-
- cpu-map {
- cluster0 {
- /delete-node/ core2;
- /delete-node/ core3;
- /delete-node/ core4;
- /delete-node/ core5;
- };
- };
- };
-
-
+&qupv3_se9_2uart {
+ status = "disabled";
};
-&soc {
- /delete-node/ jtagmm@7240000;
- /delete-node/ jtagmm@7340000;
- /delete-node/ jtagmm@7440000;
- /delete-node/ jtagmm@7540000;
- /delete-node/ cti@7220000;
- /delete-node/ cti@7320000;
- /delete-node/ cti@7420000;
- /delete-node/ cti@7520000;
- /delete-node/ etm@7240000;
- /delete-node/ etm@7340000;
- /delete-node/ etm@7440000;
- /delete-node/ etm@7540000;
- cpuss_dump {
- /delete-node/ qcom,l1_i_cache200;
- /delete-node/ qcom,l1_i_cache300;
- /delete-node/ qcom,l1_i_cache400;
- /delete-node/ qcom,l1_i_cache500;
- /delete-node/ qcom,l1_d_cache200;
- /delete-node/ qcom,l1_d_cache300;
- /delete-node/ qcom,l1_d_cache400;
- /delete-node/ qcom,l1_d_cache500;
- /delete-node/ qcom,l1_tlb_dump200;
- /delete-node/ qcom,l1_tlb_dump300;
- /delete-node/ qcom,l1_tlb_dump400;
- /delete-node/ qcom,l1_tlb_dump500;
- };
-
- devfreq_memlat_0: qcom,cpu0-memlat-mon {
- qcom,cpulist = <&CPU0 &CPU1>;
- };
-
- devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
- qcom,cpulist = <&CPU0 &CPU1>;
- };
- devfreq_compute0: qcom,devfreq-compute0 {
- qcom,cpulist = <&CPU0 &CPU1>;
- };
-
- funnel_apss: funnel@7800000 {
- ports {
- /delete-node/ port@3;
- /delete-node/ port@4;
- /delete-node/ port@5;
- /delete-node/ port@6;
- };
- };
-
- qcom,lpm-levels {
- qcom,pm-cluster@0 {
- qcom,pm-cpu@0 {
- qcom,cpu = <&CPU0 &CPU1>;
- };
- };
- };
+&qupv3_se12_2uart {
+ status = "ok";
};
-&pm660_temp_alarm {
- cooling-maps {
- /delete-node/ trip0_cpu2;
- /delete-node/ trip0_cpu3;
- /delete-node/ trip0_cpu4;
- /delete-node/ trip0_cpu5;
- /delete-node/ trip1_cpu2;
- /delete-node/ trip1_cpu3;
- /delete-node/ trip1_cpu4;
- /delete-node/ trip1_cpu5;
- };
-};
-
-&thermal_zones {
-
- xo-therm-cpu-step {
- cooling-maps {
- /delete-node/ skin_cpu2;
- /delete-node/ skin_cpu3;
- /delete-node/ skin_cpu4;
- /delete-node/ skin_cpu5;
- };
- };
-};
-
-&spmi_bus {
- /delete-node/ qcom,pm660l@2;
- /delete-node/ qcom,pm660l@3;
-};
-
-&thermal_zones {
- pm660l_tz {
- /delete-property/ thermal-sensors;
- };
-};
-
-&soc {
- qcom,turing@8300000 {
- /delete-property/ vdd_cx-supply;
- };
-
- qcom,lpass@62400000 {
- /delete-property/ vdd_cx-supply;
- };
-};
-
-&clock_cpucc {
- /delete-property/ vdd_l3_mx_ao-supply;
- /delete-property/ vdd_pwrcl_mx_ao-supply;
-};
-
-&clock_gcc {
- /delete-property/ vdd_cx-supply;
- /delete-property/ vdd_cx_ao-supply;
-};
-
-&clock_videocc {
- /delete-property/ vdd_cx-supply;
-};
-
-&clock_camcc {
- /delete-property/ vdd_mx-supply;
- /delete-property/ vdd_cx-supply;
-};
-
-&clock_dispcc {
- /delete-property/ vdd_cx-supply;
-};
-
-&clock_gpucc {
- /delete-property/ vdd_mx-supply;
- /delete-property/ vdd_cx-supply;
-};
-
-&pil_modem {
- /delete-property/ vdd_mx-supply;
- /delete-property/ vdd_cx-supply;
- /delete-property/ vdd_mss-supply;
-};
-
-&clock_gfx {
- /delete-property/ vdd_gfx-supply;
-};
-
-&gpu_gx_gdsc {
- /delete-property/ parent-supply;
-};
-
-&mdss_dsi_phy0 {
- /delete-property/ vdda-0p9-supply;
-};
-
-&mdss_dsi_phy1 {
- /delete-property/ vdda-0p9-supply;
-};
-
-&sde_dp {
- /delete-property/ vdda-0p9-supply;
-};
-
-&qusb_phy0 {
- /delete-property/ vdd-supply;
- /delete-property/ vdda33-supply;
-};
-
-&usb_qmp_dp_phy {
- /delete-property/ vdd-supply;
-};
-
-&pm660_pdphy {
- /delete-property/ vdd-pdphy-supply;
+&qupv3_se8_spi {
+ status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
new file mode 100644
index 0000000..2436687
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
@@ -0,0 +1,260 @@
+/* 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.
+ */
+
+&pm660_0 {
+ pm660_charger: qcom,qpnp-smb2 {
+ compatible = "qcom,qpnp-smb2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #cooling-cells = <2>;
+
+ qcom,pmic-revid = <&pm660_revid>;
+
+ io-channels = <&pm660_rradc 8>,
+ <&pm660_rradc 10>,
+ <&pm660_rradc 3>,
+ <&pm660_rradc 4>;
+ io-channel-names = "charger_temp",
+ "charger_temp_max",
+ "usbin_i",
+ "usbin_v";
+
+ qcom,wipower-max-uw = <5000000>;
+
+ dpdm-supply = <&qusb_phy0>;
+
+ qcom,thermal-mitigation
+ = <3000000 2500000 2000000 1500000
+ 1000000 500000>;
+ qcom,auto-recharge-soc;
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts =
+ <0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "chg-error",
+ "chg-state-change",
+ "step-chg-state-change",
+ "step-chg-soc-update-fail",
+ "step-chg-soc-update-request";
+ };
+
+ qcom,otg@1100 {
+ reg = <0x1100 0x100>;
+ interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "otg-fail",
+ "otg-overcurrent",
+ "otg-oc-dis-sw-sts",
+ "testmode-change-detect";
+ };
+
+ qcom,bat-if@1200 {
+ reg = <0x1200 0x100>;
+ interrupts =
+ <0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "bat-temp",
+ "bat-ocp",
+ "bat-ov",
+ "bat-low",
+ "bat-therm-or-id-missing",
+ "bat-terminal-missing";
+ };
+
+ qcom,usb-chgpth@1300 {
+ reg = <0x1300 0x100>;
+ interrupts =
+ <0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "usbin-collapse",
+ "usbin-lt-3p6v",
+ "usbin-uv",
+ "usbin-ov",
+ "usbin-plugin",
+ "usbin-src-change",
+ "usbin-icl-change",
+ "type-c-change";
+ };
+
+ qcom,dc-chgpth@1400 {
+ reg = <0x1400 0x100>;
+ interrupts =
+ <0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "dcin-collapse",
+ "dcin-lt-3p6v",
+ "dcin-uv",
+ "dcin-ov",
+ "dcin-plugin",
+ "div2-en-dg",
+ "dcin-icl-change";
+ };
+
+ qcom,chgr-misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts =
+ <0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+ <0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "wdog-snarl",
+ "wdog-bark",
+ "aicl-fail",
+ "aicl-done",
+ "high-duty-cycle",
+ "input-current-limiting",
+ "temperature-change",
+ "switcher-power-ok";
+ };
+ smb2_vbus: qcom,smb2-vbus {
+ regulator-name = "smb2-vbus";
+ };
+
+ smb2_vconn: qcom,smb2-vconn {
+ regulator-name = "smb2-vconn";
+ };
+ };
+
+ pm660_rradc: rradc@4500 {
+ compatible = "qcom,rradc";
+ reg = <0x4500 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+ qcom,pmic-revid = <&pm660_revid>;
+ };
+
+ pm660_fg: qpnp,fg {
+ compatible = "qcom,fg-gen3";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,pmic-revid = <&pm660_revid>;
+ io-channels = <&pm660_rradc 0>,
+ <&pm660_rradc 7>;
+ io-channel-names = "rradc_batt_id",
+ "rradc_die_temp";
+ qcom,rradc-base = <0x4500>;
+ qcom,fg-esr-timer-awake = <64 96>;
+ qcom,fg-esr-timer-asleep = <224 256>;
+ qcom,fg-esr-timer-charging = <0 96>;
+ qcom,cycle-counter-en;
+ qcom,hold-soc-while-full;
+ qcom,fg-auto-recharge-soc;
+ qcom,fg-recharge-soc-thr = <98>;
+ status = "okay";
+
+ qcom,fg-batt-soc@4000 {
+ status = "okay";
+ reg = <0x4000 0x100>;
+ interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x2
+ IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x40 0x3
+ IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x5
+ IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "soc-update",
+ "soc-ready",
+ "bsoc-delta",
+ "msoc-delta",
+ "msoc-low",
+ "msoc-empty",
+ "msoc-high",
+ "msoc-full";
+ };
+
+ qcom,fg-batt-info@4100 {
+ status = "okay";
+ reg = <0x4100 0x100>;
+ interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "vbatt-pred-delta",
+ "vbatt-low",
+ "esr-delta",
+ "batt-missing",
+ "batt-temp-delta";
+ };
+
+ qcom,fg-memif@4400 {
+ status = "okay";
+ reg = <0x4400 0x100>;
+ interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "ima-rdy",
+ "mem-xcp",
+ "dma-grant";
+ };
+ };
+};
+
+&pm660_1 {
+ pm660_haptics: qcom,haptics@c000 {
+ compatible = "qcom,qpnp-haptics";
+ reg = <0xc000 0x100>;
+ interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "hap-sc-irq", "hap-play-irq";
+ qcom,pmic-revid = <&pm660_revid>;
+ qcom,pmic-misc = <&pm660_misc>;
+ qcom,misc-clk-trim-error-reg = <0xf3>;
+ qcom,actuator-type = <0>;
+ qcom,play-mode = "direct";
+ qcom,vmax-mv = <3200>;
+ qcom,ilim-ma = <800>;
+ qcom,sc-dbc-cycles = <8>;
+ qcom,wave-play-rate-us = <6667>;
+ qcom,en-brake;
+ qcom,lra-high-z = "opt0";
+ qcom,lra-auto-res-mode = "qwd";
+ qcom,lra-res-cal-period = <4>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc.dts
similarity index 67%
rename from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
rename to arch/arm64/boot/dts/qcom/qcs605-lc.dts
index 194bfeb..88d838e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dts
@@ -1,5 +1,5 @@
/*
- * 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
@@ -13,12 +13,10 @@
/dts-v1/;
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "qcs605-lc.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
- compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+ model = "Qualcomm Technologies, Inc. QCS605 LC SoC";
+ compatible = "qcom,qcs605";
qcom,board-id = <8 4>;
-
};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
new file mode 100644
index 0000000..2db6129
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
@@ -0,0 +1,207 @@
+/*
+ * 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 "qcs605.dtsi"
+#include "pm8005.dtsi"
+#include "qcs605-pm660-pm8005-regulator.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 SoC";
+ compatible = "qcom,qcs605";
+
+ cpus {
+ /delete-node/ cpu@200;
+ /delete-node/ cpu@300;
+ /delete-node/ cpu@400;
+ /delete-node/ cpu@500;
+
+ cpu-map {
+ cluster0 {
+ /delete-node/ core2;
+ /delete-node/ core3;
+ /delete-node/ core4;
+ /delete-node/ core5;
+ };
+ };
+ };
+};
+
+&soc {
+ /delete-node/ jtagmm@7240000;
+ /delete-node/ jtagmm@7340000;
+ /delete-node/ jtagmm@7440000;
+ /delete-node/ jtagmm@7540000;
+ /delete-node/ cti@7220000;
+ /delete-node/ cti@7320000;
+ /delete-node/ cti@7420000;
+ /delete-node/ cti@7520000;
+ /delete-node/ etm@7240000;
+ /delete-node/ etm@7340000;
+ /delete-node/ etm@7440000;
+ /delete-node/ etm@7540000;
+ cpuss_dump {
+ /delete-node/ qcom,l1_i_cache200;
+ /delete-node/ qcom,l1_i_cache300;
+ /delete-node/ qcom,l1_i_cache400;
+ /delete-node/ qcom,l1_i_cache500;
+ /delete-node/ qcom,l1_d_cache200;
+ /delete-node/ qcom,l1_d_cache300;
+ /delete-node/ qcom,l1_d_cache400;
+ /delete-node/ qcom,l1_d_cache500;
+ /delete-node/ qcom,l1_tlb_dump200;
+ /delete-node/ qcom,l1_tlb_dump300;
+ /delete-node/ qcom,l1_tlb_dump400;
+ /delete-node/ qcom,l1_tlb_dump500;
+ };
+
+ devfreq_memlat_0: qcom,cpu0-memlat-mon {
+ qcom,cpulist = <&CPU0 &CPU1>;
+ };
+
+ devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+ qcom,cpulist = <&CPU0 &CPU1>;
+ };
+ devfreq_compute0: qcom,devfreq-compute0 {
+ qcom,cpulist = <&CPU0 &CPU1>;
+ };
+
+ funnel_apss: funnel@7800000 {
+ ports {
+ /delete-node/ port@3;
+ /delete-node/ port@4;
+ /delete-node/ port@5;
+ /delete-node/ port@6;
+ };
+ };
+
+ qcom,lpm-levels {
+ qcom,pm-cluster@0 {
+ qcom,pm-cpu@0 {
+ qcom,cpu = <&CPU0 &CPU1>;
+ };
+ };
+ };
+};
+
+&pm660_temp_alarm {
+ cooling-maps {
+ /delete-node/ trip0_cpu2;
+ /delete-node/ trip0_cpu3;
+ /delete-node/ trip0_cpu4;
+ /delete-node/ trip0_cpu5;
+ /delete-node/ trip1_cpu2;
+ /delete-node/ trip1_cpu3;
+ /delete-node/ trip1_cpu4;
+ /delete-node/ trip1_cpu5;
+ };
+};
+
+&thermal_zones {
+
+ xo-therm-cpu-step {
+ cooling-maps {
+ /delete-node/ skin_cpu2;
+ /delete-node/ skin_cpu3;
+ /delete-node/ skin_cpu4;
+ /delete-node/ skin_cpu5;
+ };
+ };
+};
+
+&spmi_bus {
+ /delete-node/ qcom,pm660l@2;
+ /delete-node/ qcom,pm660l@3;
+};
+
+&thermal_zones {
+ pm660l_tz {
+ /delete-property/ thermal-sensors;
+ };
+};
+
+&soc {
+ qcom,turing@8300000 {
+ /delete-property/ vdd_cx-supply;
+ };
+
+ qcom,lpass@62400000 {
+ /delete-property/ vdd_cx-supply;
+ };
+};
+
+&clock_cpucc {
+ /delete-property/ vdd_l3_mx_ao-supply;
+ /delete-property/ vdd_pwrcl_mx_ao-supply;
+};
+
+&clock_gcc {
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_cx_ao-supply;
+};
+
+&clock_videocc {
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_camcc {
+ /delete-property/ vdd_mx-supply;
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_dispcc {
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_gpucc {
+ /delete-property/ vdd_mx-supply;
+ /delete-property/ vdd_cx-supply;
+};
+
+&pil_modem {
+ /delete-property/ vdd_mx-supply;
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_mss-supply;
+};
+
+&clock_gfx {
+ /delete-property/ vdd_gfx-supply;
+};
+
+&gpu_gx_gdsc {
+ /delete-property/ parent-supply;
+};
+
+&mdss_dsi_phy0 {
+ /delete-property/ vdda-0p9-supply;
+};
+
+&mdss_dsi_phy1 {
+ /delete-property/ vdda-0p9-supply;
+};
+
+&sde_dp {
+ /delete-property/ vdda-0p9-supply;
+};
+
+&qusb_phy0 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdda33-supply;
+};
+
+&usb_qmp_dp_phy {
+ /delete-property/ vdd-supply;
+};
+
+&pm660_pdphy {
+ /delete-property/ vdd-pdphy-supply;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
new file mode 100644
index 0000000..c76ef2b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
@@ -0,0 +1,97 @@
+/* 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.
+ */
+
+&cam_sensor_mclk0_active{
+ /* MCLK0 */
+ mux {
+ pins = "gpio13";
+ function = "cam_mclk";
+ };
+
+ config {
+ pins = "gpio13";
+ bias-disable; /* No PULL */
+ drive-strength = <8>; /* 2 MA */
+ };
+};
+
+&cam_sensor_mclk0_suspend {
+ /* MCLK0 */
+ mux {
+ pins = "gpio13";
+ function = "cam_mclk";
+ };
+
+ config {
+ pins = "gpio13";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <8>; /* 2 MA */
+ };
+};
+
+&cam_sensor_rear_active {
+ /* RESET, AVDD LDO */
+ mux {
+ pins = "gpio8","gpio79";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio8","gpio79";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+};
+
+&cam_sensor_rear_suspend {
+ /* RESET, AVDD LDO */
+ mux {
+ pins = "gpio8","gpio79";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio8","gpio79";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <2>; /* 2 MA */
+ output-low;
+ };
+};
+
+&cam_sensor_front_active{
+ /* RESET AVDD_LDO*/
+ mux {
+ pins = "gpio26", "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio26", "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+};
+
+&cam_sensor_front_suspend{
+ /* RESET */
+ mux {
+ pins = "gpio26", "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio26", "gpio8";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <2>; /* 2 MA */
+ output-low;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
new file mode 100644
index 0000000..fa82be2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
@@ -0,0 +1,548 @@
+/* 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 "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+#include "sda845-svr-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-svr.dtsi"
+#include "smb1355.dtsi"
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+
+&vendor {
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pm8998_s3>;
+ qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+ qca,bt-vdd-core-supply = <&pm8998_l7>;
+ qca,bt-vdd-pa-supply = <&pm8998_l17>;
+ qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
+
+ svr_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "fg-gen3-batterydata-demo-3600mah.dtsi"
+ };
+};
+
+&pmi8998_pdphy {
+ vbus-supply = <&smb2_vbus>;
+};
+
+&qupv3_se6_4uart {
+ status = "ok";
+};
+
+&pmi8998_fg {
+ qcom,battery-data = <&svr_batterydata>;
+ qcom,fg-bmd-en-delay-ms = <300>;
+};
+
+&pmi8998_charger {
+ qcom,battery-data = <&svr_batterydata>;
+ qcom,sw-jeita-enable;
+};
+
+&qupv3_se10_i2c {
+ status = "ok";
+};
+
+&smb1355_charger_0 {
+ status = "ok";
+ qcom,disable-ctm;
+};
+
+&smb1355_charger_1 {
+ status = "ok";
+ qcom,disable-ctm;
+};
+
+&soc {
+ qcom,qbt1000 {
+ status = "disabled";
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_vol_up_default
+ &key_home_default
+ &key_cam_focus_default>;
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ home {
+ label = "home"; /* BACK Key*/
+ gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <158>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ key_cam_focus {
+ label = "Confirm"; /* Confirm Key*/
+ gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <28>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+
+ dsi_panel_pwr_supply_amoled: dsi_panel_pwr_supply_amoled {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1880000>;
+ qcom,supply-max-voltage = <1880000>;
+ qcom,supply-enable-load = <62000>;
+ qcom,supply-disable-load = <80>;
+ qcom,supply-post-on-sleep = <20>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <20>;
+ };
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "oled-vdda";
+ qcom,supply-min-voltage = <3312000>;
+ qcom,supply-max-voltage = <3312000>;
+ qcom,supply-enable-load = <857000>;
+ qcom,supply-disable-load = <0>;
+ qcom,supply-post-on-sleep = <0>;
+ };
+ };
+};
+
+&sde_rscc {
+ status = "disabled";
+};
+
+&mdss_dsi0 {
+ oled-vdda-supply = <&pm8998_l22>;
+};
+
+&mdss_dsi1 {
+ oled-vdda-supply = <&pm8998_l22>;
+};
+
+&pmi8998_wled {
+ status = "ok";
+ qcom,disp-type-amoled;
+ qcom,avdd-target-voltage-mv = <7600>;
+};
+
+&labibb {
+ status = "ok";
+ qcom,qpnp-labibb-mode = "amoled";
+ qcom,swire-control;
+};
+
+&ibb_regulator {
+ status = "ok";
+ qcom,qpnp-ibb-init-amoled-voltage = <4600000>;
+ qcom,qpnp-ibb-discharge-resistor = <300>;
+};
+
+&lab_regulator {
+ status = "ok";
+ qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+};
+
+&mdss_mdp {
+ connectors = <&sde_wb &sde_dp>;
+};
+
+&dsi_dual_test_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0e>;
+ qcom,mdss-dsi-t-clk-pre = <0x35>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings =
+ [00 24 09 09 26 24 09 09 06 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <2 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_dual_test_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply_amoled>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <255>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_dual_test_cmd_display {
+ qcom,dsi-display-active;
+};
+
+&snd_934x {
+ qcom,msm-mbhc-hphl-swh = <0>;
+};
+
+&pmi8998_haptics {
+ qcom,vmax-mv = <2400>;
+ qcom,lra-auto-mode;
+ status = "okay";
+};
+
+&qupv3_se9_2uart {
+ status = "ok";
+};
+
+&mdss_mdp {
+ #cooling-cells = <2>;
+};
+
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
+ vccq2-supply = <&pm8998_s4>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8998_l21>;
+ qcom,vdd-voltage-level = <2950000 2960000>;
+ qcom,vdd-current-level = <200 800000>;
+
+ vdd-io-supply = <&pm8998_l13>;
+ qcom,vdd-io-voltage-level = <1808000 2960000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep", "ds_400KHz",
+ "ds_50MHz", "ds_100MHz", "ds_200MHz";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>;
+ pinctrl-2 = <&sdc2_clk_ds_400KHz
+ &sdc2_cmd_ds_400KHz &sdc2_data_ds_400KHz>;
+ pinctrl-3 = <&sdc2_clk_ds_50MHz
+ &sdc2_cmd_ds_50MHz &sdc2_data_ds_50MHz>;
+ pinctrl-4 = <&sdc2_clk_ds_100MHz
+ &sdc2_cmd_ds_100MHz &sdc2_data_ds_100MHz>;
+ pinctrl-5 = <&sdc2_clk_ds_200MHz
+ &sdc2_cmd_ds_200MHz &sdc2_data_ds_200MHz>;
+
+ cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+
+ status = "ok";
+};
+
+&pmi8998_switch1 {
+ pinctrl-names = "led_enable", "led_disable";
+ pinctrl-0 = <&flash_led3_front_en>;
+ pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_switch2 {
+ pinctrl-names = "led_enable", "led_disable";
+ pinctrl-0 = <&flash_led3_iris_en>;
+ pinctrl-1 = <&flash_led3_iris_dis>;
+};
+
+&vendor {
+ extcon_usb1: extcon_usb1 {
+ compatible = "linux,extcon-usb-gpio";
+ vbus-gpio = <&pmi8998_gpios 8 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_vbus_det_default>;
+ };
+};
+
+&qupv3_se9_2uart {
+ status = "ok";
+};
+
+&qupv3_se8_spi {
+ status = "ok";
+};
+
+&qupv3_se10_i2c {
+ status = "ok";
+};
+
+&qupv3_se6_4uart {
+ status = "ok";
+};
+
+&usb1 {
+ status = "okay";
+ extcon = <&extcon_usb1>;
+};
+
+&qusb_phy1 {
+ status = "okay";
+};
+
+&ext_5v_boost {
+ status = "ok";
+};
+
+&usb_qmp_phy {
+ status = "okay";
+};
+
+&pm8998_vadc {
+ 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>;
+ };
+
+ chan@85 {
+ label = "vcoin";
+ reg = <0x85>;
+ 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>;
+ };
+
+ 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 = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4f {
+ label = "pa_therm1";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+&pm8998_adc_tm {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x60>;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm1";
+ reg = <0x4f>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x80>;
+ qcom,thermal-node;
+ };
+};
+
+&thermal_zones {
+ xo-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_adc_tm 0x4c>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ msm-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_adc_tm 0x4d>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ pa-therm1-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_adc_tm 0x4f>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ quiet-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_adc_tm 0x51>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+};
+
+&wil6210 {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
new file mode 100644
index 0000000..1c6db6f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
@@ -0,0 +1,31 @@
+/* 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 "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+ compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
similarity index 60%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
index 194bfeb..1d7bf7d 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
@@ -1,5 +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
@@ -11,14 +10,16 @@
* GNU General Public License for more details.
*/
+
/dts-v1/;
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sda845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
+#include "sda845-svr.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
- compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
- qcom,board-id = <8 4>;
-
+ model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+ compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <8 2>;
};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
new file mode 100644
index 0000000..b4326a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
@@ -0,0 +1,32 @@
+/* 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 "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sda845 v2.1 SVR";
+ compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+ qcom,msm-id = <341 0x20001>;
+ qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
index 040b4ba..5744390 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
@@ -24,3 +24,21 @@
qcom,board-id = <8 0>;
qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
};
+
+/{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&qpnp_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+ qcom,battery-data = <&mtp_batterydata>;
+ qcom,chg-led-sw-controls;
+ qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
index 700e950..eb6a692 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
@@ -14,6 +14,8 @@
/dts-v1/;
#include "sdm450.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
index f50d177..cfdd4e9 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
@@ -14,6 +14,8 @@
/dts-v1/;
#include "sdm450.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 0a98528..9e2981a 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -12,8 +12,98 @@
*/
#include "msm8953-qrd.dtsi"
+#include "msm8953-mdss-panels.dtsi"
+
+&qusb_phy {
+ qcom,qusb-phy-init-seq = <0x78 0x80
+ 0xb3 0x84
+ 0x83 0x88
+ 0xc7 0x8c
+ 0x14 0x9c
+ 0x30 0x08
+ 0x79 0x0c
+ 0x21 0x10
+ 0x00 0x90
+ 0x9f 0x1c
+ 0x00 0x18>;
+};
&i2c_3 {
status = "disabled";
};
+&tlmm {
+ pmx_mdss {
+ mdss_dsi_active: mdss_dsi_active {
+ mux {
+ pins = "gpio61";
+ };
+ config {
+ pins = "gpio61";
+ };
+ };
+ mdss_dsi_suspend: mdss_dsi_suspend {
+ mux {
+ pins = "gpio61";
+ };
+ config {
+ pins = "gpio61";
+ };
+ };
+ };
+};
+
+&dsi_panel_pwr_supply {
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ 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 = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <10>;
+ };
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+ /delete-property/ vdd-supply;
+
+ qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+ qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-te-gpio = <&tlmm 24 0>;
+ qcom,platform-reset-gpio = <&tlmm 61 0>;
+};
+
+&mdss_dsi1 {
+ status = "disabled";
+};
+
+&dsi_hx8399c_truly_vid {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts
index b829b81..6cdf897 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450.dts
@@ -14,6 +14,8 @@
/dts-v1/;
#include "sdm450.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.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
@@ -22,10 +22,20 @@
status = "ok";
};
- led_flash_front: qcom,camera-flash@1 {
+ led_flash_rear_aux: qcom,camera-flash@1 {
cell-index = <1>;
reg = <0x01 0x00>;
compatible = "qcom,camera-flash";
+ flash-source = <&pm660l_flash0 &pm660l_flash1>;
+ torch-source = <&pm660l_torch0 &pm660l_torch1>;
+ switch-source = <&pm660l_switch0>;
+ status = "ok";
+ };
+
+ led_flash_front: qcom,camera-flash@2 {
+ cell-index = <2>;
+ reg = <0x02 0x00>;
+ compatible = "qcom,camera-flash";
flash-source = <&pm660l_flash2>;
torch-source = <&pm660l_torch2>;
switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
sensor-position-roll = <90>;
sensor-position-pitch = <0>;
sensor-position-yaw = <180>;
+ led-flash-src = <&led_flash_rear_aux>;
eeprom-src = <&eeprom_rear_aux>;
cam_vio-supply = <&camera_vio_ldo>;
cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-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
@@ -22,10 +22,20 @@
status = "ok";
};
- led_flash_front: qcom,camera-flash@1 {
+ led_flash_rear_aux: qcom,camera-flash@1 {
cell-index = <1>;
reg = <0x01 0x00>;
compatible = "qcom,camera-flash";
+ flash-source = <&pm660l_flash0 &pm660l_flash1>;
+ torch-source = <&pm660l_torch0 &pm660l_torch1>;
+ switch-source = <&pm660l_switch0>;
+ status = "ok";
+ };
+
+ led_flash_front: qcom,camera-flash@2 {
+ cell-index = <2>;
+ reg = <0x02 0x00>;
+ compatible = "qcom,camera-flash";
flash-source = <&pm660l_flash2>;
torch-source = <&pm660l_torch2>;
switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
sensor-position-roll = <90>;
sensor-position-pitch = <0>;
sensor-position-yaw = <180>;
+ led-flash-src = <&led_flash_rear_aux>;
eeprom-src = <&eeprom_rear_aux>;
cam_vio-supply = <&camera_vio_ldo>;
cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
index 7ab99a3..c8f7ac0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
@@ -1,5 +1,5 @@
/*
- * 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
@@ -22,6 +22,16 @@
status = "ok";
};
+ led_flash_rear_aux: qcom,camera-flash@1 {
+ cell-index = <1>;
+ reg = <0x01 0x00>;
+ compatible = "qcom,camera-flash";
+ flash-source = <&pm660l_flash0 &pm660l_flash1>;
+ torch-source = <&pm660l_torch0 &pm660l_torch1>;
+ switch-source = <&pm660l_switch0>;
+ status = "ok";
+ };
+
actuator_regulator: gpio-regulator@0 {
compatible = "regulator-fixed";
reg = <0x00 0x00>;
@@ -386,7 +396,7 @@
sensor-position-roll = <90>;
sensor-position-pitch = <0>;
sensor-position-yaw = <180>;
- led-flash-src = <&led_flash_rear>;
+ led-flash-src = <&led_flash_rear_aux>;
actuator-src = <&actuator_rear_aux>;
eeprom-src = <&eeprom_rear_aux>;
cam_vio-supply = <&cam_iovdd_gpio_regulator>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index 75a2762..9acef75 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -134,6 +134,28 @@
qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>;
+ qcom,soc-hw-rev-efuse = <0x414c 28 0x3>;
+
+ qcom,soc-hw-revisions {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,soc-hw-revisions";
+
+ qcom,soc-hw-revision-0 {
+ qcom,soc-hw-revision = <0>;
+ qcom,chipid = <0x06010500>;
+ qcom,gpu-quirk-hfi-use-reg;
+ qcom,gpu-quirk-limit-uche-gbif-rw;
+ qcom,gpu-quirk-mmu-secure-cb-alt;
+ };
+
+ qcom,soc-hw-revision-1 {
+ qcom,soc-hw-revision = <1>;
+ qcom,chipid = <0x06010501>;
+ qcom,gpu-quirk-hfi-use-reg;
+ };
+ };
+
qcom,gpu-coresights {
#address-cells = <1>;
#size-cells = <0>;
@@ -485,6 +507,11 @@
gfx3d_secure: gfx3d_secure {
compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 2>;
+ };
+
+ gfx3d_secure_alt: gfx3d_secure_alt {
+ compatible = "qcom,smmu-kgsl-cb";
iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
index 5bf8df7..c54b8db 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm.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
@@ -186,7 +186,8 @@
reg-names = "phys_addr_base", "offset_addr";
};
- qcom,rpmh-master-stats {
- compatible = "qcom,rpmh-master-stats";
+ qcom,rpmh-master-stats@b221200 {
+ compatible = "qcom,rpmh-master-stats-v1";
+ reg = <0xb221200 0x60>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 6b24593..9d3f37d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -684,6 +684,5 @@
regulator-enable-ramp-delay = <5>;
proxy-supply = <&refgen>;
qcom,proxy-consumer-enable;
- regulator-always-on;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index 007f937..a3f7b8e 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -831,7 +831,7 @@
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
- qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
qcom,mdss-dsi-panel-status-value = <0x9c>;
qcom,mdss-dsi-panel-on-check-value = <0x9c>;
qcom,mdss-dsi-panel-status-read-length = <1>;
@@ -849,6 +849,18 @@
&dsi_hx8399_truly_cmd {
qcom,mdss-dsi-t-clk-post = <0x0E>;
qcom,mdss-dsi-t-clk-pre = <0x30>;
+ qcom,mdss-dsi-min-refresh-rate = <55>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update =
+ "dfps_immediate_porch_mode_vfp";
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-status-read-length = <4>;
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08
diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index f6fa948..9903d19 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.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
@@ -138,7 +138,8 @@
0x254 /* QUSB2PHY_TEST1 */
0x198 /* PLL_BIAS_CONTROL_2 */
0x228 /* QUSB2PHY_SQ_CTRL1 */
- 0x22c>; /* QUSB2PHY_SQ_CTRL2 */
+ 0x22c /* QUSB2PHY_SQ_CTRL2 */
+ 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..365b383
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+&soc {
+ led_flash_rear: qcom,camera-flash@0 {
+ cell-index = <0>;
+ reg = <0x00 0x00>;
+ compatible = "qcom,camera-flash";
+ flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+ torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+ switch-source = <&pmi8998_switch0>;
+ status = "ok";
+ };
+
+ led_flash_front: qcom,camera-flash@1 {
+ cell-index = <1>;
+ reg = <0x01 0x00>;
+ compatible = "qcom,camera-flash";
+ flash-source = <&pmi8998_flash2>;
+ torch-source = <&pmi8998_torch2>;
+ switch-source = <&pmi8998_switch1>;
+ status = "ok";
+ };
+
+ actuator_regulator: gpio-regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0x00 0x00>;
+ regulator-name = "actuator_regulator";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-enable-ramp-delay = <100>;
+ enable-active-high;
+ gpio = <&tlmm 27 0>;
+ vin-supply = <&pmi8998_bob>;
+ };
+
+ camera_rear_ldo: gpio-regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <0x01 0x00>;
+ regulator-name = "camera_rear_ldo";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-enable-ramp-delay = <135>;
+ enable-active-high;
+ gpio = <&pm8998_gpios 12 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_rear_dvdd_en_default>;
+ vin-supply = <&pm8998_s3>;
+ };
+
+ camera_ldo: gpio-regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <0x02 0x00>;
+ regulator-name = "camera_ldo";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-enable-ramp-delay = <233>;
+ enable-active-high;
+ gpio = <&pm8998_gpios 9 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_dvdd_en_default>;
+ vin-supply = <&pm8998_s3>;
+ };
+};
+
+&cam_cci {
+ actuator_rear: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ cci-master = <0>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <2800000>;
+ rgltr-max-voltage = <2800000>;
+ rgltr-load-current = <0>;
+ };
+
+ actuator_front: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ cci-master = <1>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <2800000>;
+ rgltr-max-voltage = <2800000>;
+ rgltr-load-current = <0>;
+ };
+
+ ois_rear: qcom,ois@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,ois";
+ cci-master = <0>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <2800000>;
+ rgltr-max-voltage = <2800000>;
+ rgltr-load-current = <0>;
+ status = "ok";
+ };
+
+ eeprom_rear: qcom,eeprom@0 {
+ cell-index = <0>;
+ reg = <0>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&camera_rear_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-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 80 0>,
+ <&tlmm 79 0>,
+ <&tlmm 27 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-vaf = <3>;
+ gpio-req-tbl-num = <0 1 2 3>;
+ gpio-req-tbl-flags = <1 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VANA0",
+ "CAM_VAF";
+ sensor-position = <0>;
+ sensor-mode = <0>;
+ cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ eeprom_rear_aux: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,eeprom";
+ cam_vdig-supply = <&camera_ldo>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ 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-load-current = <105000 0 80000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1";
+ sensor-position = <0>;
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ eeprom_front: qcom,eeprom@2 {
+ cell-index = <2>;
+ reg = <0x2>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ 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 2812000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VANA1";
+ sensor-position = <1>;
+ sensor-mode = <1>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@0 {
+ cell-index = <0>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x0>;
+ csiphy-sd-index = <0>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ led-flash-src = <&led_flash_rear>;
+ actuator-src = <&actuator_rear>;
+ ois-src = <&ois_rear>;
+ eeprom-src = <&eeprom_rear>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&camera_rear_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-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 80 0>,
+ <&tlmm 79 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VANA";
+ sensor-mode = <0>;
+ cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@1 {
+ cell-index = <1>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x1>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <90>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ eeprom-src = <&eeprom_rear_aux>;
+ cam_vdig-supply = <&camera_ldo>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ 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-load-current = <105000 0 80000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_front_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_front_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@2 {
+ cell-index = <2>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x02>;
+ csiphy-sd-index = <2>;
+ sensor-position-roll = <90>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <0>;
+ eeprom-src = <&eeprom_front>;
+ actuator-src = <&actuator_front>;
+ led-flash-src = <&led_flash_front>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ 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 2812000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VANA1";
+ sensor-mode = <1>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
new file mode 100644
index 0000000..d387f93
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
@@ -0,0 +1,479 @@
+/*
+ * 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.
+ */
+
+&soc {
+ led_flash_rear: qcom,camera-flash@0 {
+ cell-index = <0>;
+ reg = <0x00 0x00>;
+ compatible = "qcom,camera-flash";
+ flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+ torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+ switch-source = <&pmi8998_switch0>;
+ status = "ok";
+ };
+
+ led_flash_rear_aux: qcom,camera-flash@1 {
+ cell-index = <1>;
+ reg = <0x01 0x00>;
+ compatible = "qcom,camera-flash";
+ flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+ torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+ switch-source = <&pmi8998_switch0>;
+ status = "ok";
+ };
+
+ led_flash_front: qcom,camera-flash@2 {
+ cell-index = <2>;
+ reg = <0x02 0x00>;
+ compatible = "qcom,camera-flash";
+ flash-source = <&pmi8998_flash2>;
+ torch-source = <&pmi8998_torch2>;
+ switch-source = <&pmi8998_switch1>;
+ status = "ok";
+ };
+
+ led_flash_iris: qcom,camera-flash@3 {
+ cell-index = <3>;
+ reg = <0x03 0x00>;
+ compatible = "qcom,camera-flash";
+ flash-source = <&pmi8998_flash2>;
+ torch-source = <&pmi8998_torch2>;
+ switch-source = <&pmi8998_switch2>;
+ status = "ok";
+ };
+
+ actuator_regulator: gpio-regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0x00 0x00>;
+ regulator-name = "actuator_regulator";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-enable-ramp-delay = <100>;
+ enable-active-high;
+ gpio = <&tlmm 27 0>;
+ vin-supply = <&pmi8998_bob>;
+ };
+
+ camera_rear_ldo: gpio-regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <0x01 0x00>;
+ regulator-name = "camera_rear_ldo";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-enable-ramp-delay = <135>;
+ enable-active-high;
+ gpio = <&pm8998_gpios 12 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_rear_dvdd_en_default>;
+ vin-supply = <&pm8998_s3>;
+ };
+
+ camera_ldo: gpio-regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <0x02 0x00>;
+ regulator-name = "camera_ldo";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-enable-ramp-delay = <233>;
+ enable-active-high;
+ gpio = <&pm8998_gpios 9 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_dvdd_en_default>;
+ vin-supply = <&pm8998_s3>;
+ };
+};
+
+&cam_cci {
+ qcom,cam-res-mgr {
+ compatible = "qcom,cam-res-mgr";
+ status = "ok";
+ shared-gpios = <9>;
+ 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 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ cci-master = <0>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <2800000>;
+ rgltr-max-voltage = <2800000>;
+ rgltr-load-current = <0>;
+ };
+
+ actuator_rear_aux: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ cci-master = <1>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <2800000>;
+ rgltr-max-voltage = <2800000>;
+ rgltr-load-current = <0>;
+ };
+
+ actuator_front: qcom,actuator@2 {
+ cell-index = <2>;
+ reg = <0x2>;
+ compatible = "qcom,actuator";
+ cci-master = <1>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <2800000>;
+ rgltr-max-voltage = <2800000>;
+ rgltr-load-current = <0>;
+ };
+
+ ois_rear: qcom,ois@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,ois";
+ cci-master = <0>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <2800000>;
+ rgltr-max-voltage = <2800000>;
+ rgltr-load-current = <0>;
+ status = "ok";
+ };
+
+ eeprom_rear: qcom,eeprom@0 {
+ cell-index = <0>;
+ reg = <0>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&camera_rear_ldo>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk", "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+ rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+ rgltr-load-current = <0 80000 105000 0 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 80 0>,
+ <&tlmm 79 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VANA0";
+ sensor-position = <0>;
+ sensor-mode = <0>;
+ cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ eeprom_rear_aux: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,eeprom";
+ cam_vdig-supply = <&camera_ldo>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk", "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <1050000 0 3312000 0 2800000>;
+ rgltr-max-voltage = <1050000 0 3600000 0 2800000>;
+ rgltr-load-current = <105000 0 80000 0 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1";
+ sensor-position = <0>;
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ eeprom_front: qcom,eeprom@2 {
+ cell-index = <2>;
+ reg = <0x2>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&camera_ldo>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk", "cam_vaf";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+ rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+ rgltr-load-current = <0 80000 105000 0 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_front_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_front_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 28 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VANA2";
+ sensor-position = <1>;
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@0 {
+ cell-index = <0>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x0>;
+ csiphy-sd-index = <0>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ led-flash-src = <&led_flash_rear>;
+ actuator-src = <&actuator_rear>;
+ ois-src = <&ois_rear>;
+ eeprom-src = <&eeprom_rear>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&pm8998_l9>;
+ cam_vio-supply = <&pm8998_l8>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1704000 1200000>;
+ rgltr-max-voltage = <0 3600000 2928000 1248000>;
+ rgltr-load-current = <0 80000 105000 1200000>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 8 0>,
+ <&tlmm 115 0>,
+ <&tlmm 95 0 >,
+ <&tlmm 97 0>;
+ gpio-reset = <1>;
+ gpio-vio = <2>;
+ gpio-vana = <3>;
+ gpio-vdig = <4>;
+ gpio-req-tbl-num = <0 1 2 3 4>;
+ gpio-req-tbl-flags = <1 0 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VIO",
+ "CAM_VANA",
+ "CAM_VDIG";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@1 {
+ cell-index = <1>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x1>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ actuator-src = <&actuator_rear_aux>;
+ led-flash-src = <&led_flash_rear_aux>;
+ eeprom-src = <&eeprom_rear_aux>;
+ cam_vdig-supply = <&camera_ldo>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ 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-load-current = <105000 0 80000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "disabled";
+ clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@2 {
+ cell-index = <2>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x02>;
+ csiphy-sd-index = <2>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <0>;
+ eeprom-src = <&eeprom_front>;
+ actuator-src = <&actuator_front>;
+ led-flash-src = <&led_flash_front>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&pm8998_lvs1>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1800000 0>;
+ rgltr-max-voltage = <0 3600000 1800000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_front_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_front_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 26 0>,
+ <&tlmm 132 0>,
+ <&tlmm 133 0>,
+ <&tlmm 90 0>,
+ <&tlmm 40 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-vdig = <3>;
+ gpio-vio = <4>;
+ gpio-standby = <5>;
+ gpio-req-tbl-num = <0 1 2 3 4 5>;
+ gpio-req-tbl-flags = <1 0 0 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET2",
+ "CAM_VANA2",
+ "CAM_VDIG2",
+ "CAM_VIO2",
+ "CAM_STANDBY2";
+ sensor-mode = <0>;
+ cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@3 {
+ cell-index = <3>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x03>;
+ csiphy-sd-index = <3>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <0>;
+ led-flash-src = <&led_flash_iris>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ 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-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk3_active
+ &cam_sensor_iris_active>;
+ pinctrl-1 = <&cam_sensor_mclk3_suspend
+ &cam_sensor_iris_suspend>;
+ gpios = <&tlmm 16 0>,
+ <&tlmm 9 0>,
+ <&tlmm 8 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK3",
+ "CAM_RESET3",
+ "CAM_VANA1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index 1c7269a..d6be6d4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -72,6 +72,13 @@
ibb-supply = <&lcdb_ncp_vreg>;
};
+&dsi_dual_test_cmd_display {
+ /delete-property/ vddio-supply;
+ /delete-property/ lab-supply;
+ /delete-property/ ibb-supply;
+ /delete-property/ oled-vdda-supply;
+};
+
&sde_dp {
status = "disabled";
/delete-property/ vdda-1p2-supply;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index ee10cfc..929239a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.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
@@ -140,7 +140,8 @@
reg-names = "phys_addr_base", "offset_addr";
};
- qcom,rpmh-master-stats {
- compatible = "qcom,rpmh-master-stats";
+ qcom,rpmh-master-stats@b221200 {
+ compatible = "qcom,rpmh-master-stats-v1";
+ reg = <0xb221200 0x60>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index bd8ae70..6034b6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -12,6 +12,7 @@
#include "sdm845-pmic-overlay.dtsi"
#include "sdm845-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-qrd.dtsi"
#include "smb1355.dtsi"
#include <dt-bindings/gpio/gpio.h>
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index dd4e0b1..8b67649 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.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
@@ -28,6 +28,7 @@
#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi"
#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi"
#include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi"
+#include "dsi-panel-test-dualmipi-oled-cmd.dtsi"
#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
&soc {
@@ -476,6 +477,31 @@
ibb-supply = <&ibb_regulator>;
};
+ dsi_dual_test_cmd_display: qcom,dsi-display@17 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_dual_test_cmd";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+
+ qcom,dsi-panel = <&dsi_dual_test_cmd>;
+ vddio-supply = <&pm8998_l14>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+ oled-vdda-supply = <&pm8998_l22>;
+ };
+
sde_wb: qcom,wb-display@0 {
compatible = "qcom,wb-display";
cell-index = <0>;
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 532bfac..4f4f1ae 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -55,6 +55,8 @@
CONFIG_ARCH_MSM8937=y
CONFIG_ARCH_SDM450=y
CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
CONFIG_PREEMPT=y
@@ -322,6 +324,7 @@
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
CONFIG_QPNP_TYPEC=y
CONFIG_MSM_APM=y
@@ -356,14 +359,19 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
CONFIG_QCOM_KGSL=y
CONFIG_DRM=y
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
CONFIG_DRM_SDE_RSC=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_LOGO=y
@@ -428,6 +436,7 @@
CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
@@ -470,6 +479,7 @@
CONFIG_QPNP_COINCELL=y
CONFIG_QPNP_REVID=y
CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MAILBOX=y
CONFIG_ARM_SMMU=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index ede64f0..50f3754 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -59,6 +59,8 @@
CONFIG_ARCH_MSM8937=y
CONFIG_ARCH_SDM450=y
CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
CONFIG_PREEMPT=y
@@ -332,6 +334,7 @@
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
CONFIG_QPNP_TYPEC=y
CONFIG_MSM_APM=y
@@ -366,8 +369,8 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
CONFIG_QCOM_KGSL=y
@@ -375,6 +378,11 @@
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
CONFIG_DRM_SDE_RSC=y
CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_LOGO=y
@@ -439,6 +447,7 @@
CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
@@ -482,6 +491,7 @@
CONFIG_QPNP_COINCELL=y
CONFIG_QPNP_REVID=y
CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MAILBOX=y
CONFIG_ARM_SMMU=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 667377f..2c4366b 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -524,6 +524,7 @@
CONFIG_MSM_GLADIATOR_ERP=y
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
CONFIG_QPNP_PBS=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_QCOM_MINIDUMP=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 11c95ea..ff3bb70 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -573,6 +573,8 @@
CONFIG_EXT4_ENCRYPTION=y
CONFIG_EXT4_FS_ENCRYPTION=y
CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 6aa09e5..af1dd30 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -524,6 +524,7 @@
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_QCOM_BUS_SCALING=y
CONFIG_QCOM_BUS_CONFIG_RPMH=y
@@ -590,6 +591,8 @@
CONFIG_EXT4_ENCRYPTION=y
CONFIG_EXT4_FS_ENCRYPTION=y
CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 46d0448..88a4d1e 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -25,6 +25,7 @@
#include <asm/asm-offsets.h>
#include <asm/cpufeature.h>
+#include <asm/cputype.h>
#include <asm/page.h>
#include <asm/pgtable-hwdef.h>
#include <asm/ptrace.h>
@@ -452,4 +453,43 @@
mrs \rd, sp_el0
.endm
+/*
+ * Check the MIDR_EL1 of the current CPU for a given model and a range of
+ * variant/revision. See asm/cputype.h for the macros used below.
+ *
+ * model: MIDR_CPU_MODEL of CPU
+ * rv_min: Minimum of MIDR_CPU_VAR_REV()
+ * rv_max: Maximum of MIDR_CPU_VAR_REV()
+ * res: Result register.
+ * tmp1, tmp2, tmp3: Temporary registers
+ *
+ * Corrupts: res, tmp1, tmp2, tmp3
+ * Returns: 0, if the CPU id doesn't match. Non-zero otherwise
+ */
+ .macro cpu_midr_match model, rv_min, rv_max, res, tmp1, tmp2, tmp3
+ mrs \res, midr_el1
+ mov_q \tmp1, (MIDR_REVISION_MASK | MIDR_VARIANT_MASK)
+ mov_q \tmp2, MIDR_CPU_MODEL_MASK
+ and \tmp3, \res, \tmp2 // Extract model
+ and \tmp1, \res, \tmp1 // rev & variant
+ mov_q \tmp2, \model
+ cmp \tmp3, \tmp2
+ cset \res, eq
+ cbz \res, .Ldone\@ // Model matches ?
+
+ .if (\rv_min != 0) // Skip min check if rv_min == 0
+ mov_q \tmp3, \rv_min
+ cmp \tmp1, \tmp3
+ cset \res, ge
+ .endif // \rv_min != 0
+ /* Skip rv_max check if rv_min == rv_max && rv_min != 0 */
+ .if ((\rv_min != \rv_max) || \rv_min == 0)
+ mov_q \tmp2, \rv_max
+ cmp \tmp1, \tmp2
+ cset \tmp2, le
+ and \res, \res, \tmp2
+ .endif
+.Ldone\@:
+ .endm
+
#endif /* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index ddbf3b1..c088c4f 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -56,6 +56,9 @@
(0xf << MIDR_ARCHITECTURE_SHIFT) | \
((partnum) << MIDR_PARTNUM_SHIFT))
+#define MIDR_CPU_VAR_REV(var, rev) \
+ (((var) << MIDR_VARIANT_SHIFT) | (rev))
+
#define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
MIDR_ARCHITECTURE_MASK)
@@ -79,7 +82,9 @@
#define ARM_CPU_PART_CORTEX_A53 0xD03
#define ARM_CPU_PART_CORTEX_A73 0xD09
#define ARM_CPU_PART_CORTEX_A75 0xD0A
+#define ARM_CPU_PART_KRYO3S 0x803
#define ARM_CPU_PART_KRYO3G 0x802
+#define ARM_CPU_PART_CORTEX_A55 0xD05
#define APM_CPU_PART_POTENZA 0x000
@@ -93,7 +98,9 @@
#define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
#define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
#define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
+#define MIDR_KRYO3S MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3S)
#define MIDR_KRYO3G MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3G)
+#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 653359b..c7b3ba68 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -180,8 +180,9 @@
/* Cortex-A57 r0p0 - r1p2 */
.desc = "ARM erratum 832075",
.capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
- MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
- (1 << MIDR_VARIANT_SHIFT) | 2),
+ MIDR_RANGE(MIDR_CORTEX_A57,
+ MIDR_CPU_VAR_REV(0, 0),
+ MIDR_CPU_VAR_REV(1, 2)),
},
#endif
#ifdef CONFIG_ARM64_ERRATUM_834220
@@ -189,8 +190,9 @@
/* Cortex-A57 r0p0 - r1p2 */
.desc = "ARM erratum 834220",
.capability = ARM64_WORKAROUND_834220,
- MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
- (1 << MIDR_VARIANT_SHIFT) | 2),
+ MIDR_RANGE(MIDR_CORTEX_A57,
+ MIDR_CPU_VAR_REV(0, 0),
+ MIDR_CPU_VAR_REV(1, 2)),
},
#endif
#ifdef CONFIG_ARM64_ERRATUM_845719
@@ -214,8 +216,9 @@
/* Cavium ThunderX, T88 pass 1.x - 2.1 */
.desc = "Cavium erratum 27456",
.capability = ARM64_WORKAROUND_CAVIUM_27456,
- MIDR_RANGE(MIDR_THUNDERX, 0x00,
- (1 << MIDR_VARIANT_SHIFT) | 1),
+ MIDR_RANGE(MIDR_THUNDERX,
+ MIDR_CPU_VAR_REV(0, 0),
+ MIDR_CPU_VAR_REV(1, 1)),
},
{
/* Cavium ThunderX, T81 pass 1.0 */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 80ff3df5..5cf4c64 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -722,13 +722,11 @@
static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused)
{
u32 midr = read_cpuid_id();
- u32 rv_min, rv_max;
/* Cavium ThunderX pass 1.x and 2.x */
- rv_min = 0;
- rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK;
-
- return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max);
+ return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX,
+ MIDR_CPU_VAR_REV(0, 0),
+ MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
}
static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 28bedd7..2e69a14 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -293,6 +293,12 @@
cbz x9, 2f
cmp x9, #2
b.lt 1f
+#ifdef CONFIG_ARM64_ERRATUM_1024718
+ /* Disable hardware DBM on Kryo3S */
+ cpu_midr_match MIDR_KRYO3S, MIDR_CPU_VAR_REV(7, 12), \
+ MIDR_CPU_VAR_REV(7, 13), x1, x2, x3, x4
+ cbnz x1, 1f
+#endif
orr x10, x10, #TCR_HD // hardware Dirty flag update
1: orr x10, x10, #TCR_HA // hardware Access flag update
2:
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 23cf293..a469eb9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1163,18 +1163,31 @@
struct list_head *start, *temp;
struct diag_dci_client_tbl *entry = NULL;
- length = *(uint16_t *)(buf + 1); /* total length of event series */
- if (length == 0) {
- pr_err("diag: Incoming dci event length is invalid\n");
+ if (!buf) {
+ pr_err("diag: In %s buffer is NULL\n", __func__);
return;
}
/*
- * Move directly to the start of the event series. 1 byte for
- * event code and 2 bytes for the length field.
+ * 1 byte for event code and 2 bytes for the length field.
* The length field indicates the total length removing the cmd_code
* and the length field. The event parsing in that case should happen
* till the end.
*/
+ if (len < 3) {
+ pr_err("diag: In %s invalid len: %d\n", __func__, len);
+ return;
+ }
+ length = *(uint16_t *)(buf + 1); /* total length of event series */
+ if ((length == 0) || (len != (length + 3))) {
+ pr_err("diag: Incoming dci event length: %d is invalid\n",
+ length);
+ return;
+ }
+ /*
+ * Move directly to the start of the event series.
+ * The event parsing should happen from start of event
+ * series till the end.
+ */
temp_len = 3;
while (temp_len < length) {
event_id_packet = *(uint16_t *)(buf + temp_len);
@@ -1191,30 +1204,60 @@
* necessary.
*/
timestamp_len = 8;
- memcpy(timestamp, buf + temp_len + 2, timestamp_len);
+ if ((temp_len + timestamp_len + 2) <= len)
+ memcpy(timestamp, buf + temp_len + 2,
+ timestamp_len);
+ else {
+ pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+ __func__, len, temp_len);
+ return;
+ }
}
/* 13th and 14th bit represent the payload length */
if (((event_id_packet & 0x6000) >> 13) == 3) {
payload_len_field = 1;
- payload_len = *(uint8_t *)
+ if ((temp_len + timestamp_len + 3) <= len) {
+ payload_len = *(uint8_t *)
(buf + temp_len + 2 + timestamp_len);
- if (payload_len < (MAX_EVENT_SIZE - 13)) {
- /* copy the payload length and the payload */
+ } else {
+ pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+ __func__, len, temp_len);
+ return;
+ }
+ if ((payload_len < (MAX_EVENT_SIZE - 13)) &&
+ ((temp_len + timestamp_len + payload_len + 3) <= len)) {
+ /*
+ * Copy the payload length and the payload
+ * after skipping temp_len bytes for already
+ * parsed packet, timestamp_len for timestamp
+ * buffer, 2 bytes for event_id_packet.
+ */
memcpy(event_data + 12, buf + temp_len + 2 +
timestamp_len, 1);
memcpy(event_data + 13, buf + temp_len + 2 +
timestamp_len + 1, payload_len);
} else {
- pr_err("diag: event > %d, payload_len = %d\n",
- (MAX_EVENT_SIZE - 13), payload_len);
+ pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+ (MAX_EVENT_SIZE - 13), payload_len, temp_len);
return;
}
} else {
payload_len_field = 0;
payload_len = (event_id_packet & 0x6000) >> 13;
- /* copy the payload */
- memcpy(event_data + 12, buf + temp_len + 2 +
+ /*
+ * Copy the payload after skipping temp_len bytes
+ * for already parsed packet, timestamp_len for
+ * timestamp buffer, 2 bytes for event_id_packet.
+ */
+ if ((payload_len < (MAX_EVENT_SIZE - 12)) &&
+ ((temp_len + timestamp_len + payload_len + 2) <= len))
+ memcpy(event_data + 12, buf + temp_len + 2 +
timestamp_len, payload_len);
+ else {
+ pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+ (MAX_EVENT_SIZE - 12), payload_len, temp_len);
+ return;
+ }
}
/* Before copying the data to userspace, check if we are still
@@ -1340,19 +1383,19 @@
pr_err("diag: In %s buffer is NULL\n", __func__);
return;
}
-
- /* The first six bytes for the incoming log packet contains
- * Command code (2), the length of the packet (2) and the length
- * of the log (2)
+ /*
+ * The first eight bytes for the incoming log packet contains
+ * Command code (2), the length of the packet (2), the length
+ * of the log (2) and log code (2)
*/
- log_code = *(uint16_t *)(buf + 6);
- read_bytes += sizeof(uint16_t) + 6;
- if (read_bytes > len) {
- pr_err("diag: Invalid length in %s, len: %d, read: %d",
- __func__, len, read_bytes);
+ if (len < 8) {
+ pr_err("diag: In %s invalid len: %d\n", __func__, len);
return;
}
+ log_code = *(uint16_t *)(buf + 6);
+ read_bytes += sizeof(uint16_t) + 6;
+
/* parse through log mask table of each client and check mask */
mutex_lock(&driver->dci_mutex);
list_for_each_safe(start, temp, &driver->dci_client_list) {
@@ -1379,6 +1422,10 @@
pr_err("diag: In %s buffer is NULL\n", __func__);
return;
}
+ if (len < (EXT_HDR_LEN + sizeof(uint8_t))) {
+ pr_err("diag: In %s invalid len: %d\n", __func__, len);
+ return;
+ }
version = *(uint8_t *)buf + 1;
if (version < EXT_HDR_VERSION) {
@@ -1390,10 +1437,6 @@
pkt = buf + EXT_HDR_LEN;
pkt_cmd_code = *(uint8_t *)pkt;
len -= EXT_HDR_LEN;
- if (len < 0) {
- pr_err("diag: %s, Invalid length len: %d\n", __func__, len);
- return;
- }
switch (pkt_cmd_code) {
case LOG_CMD_CODE:
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0ee052b..70e8414 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -149,6 +149,32 @@
EXPORT_SYMBOL(drm_bridge_detach);
/**
+ * drm_bridge_connector_init - call bridge's connector_init callback to allow
+ * the bridge to update connector's behavior.
+ * @bridge: bridge control structure
+ * @connector: connector control structure
+ *
+ * Calls ->connector_init() &drm_bridge_funcs op for the bridge.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ int ret = 0;
+
+ if (!bridge || !connector)
+ return -EINVAL;
+
+ if (bridge->funcs->connector_init)
+ ret = bridge->funcs->connector_init(bridge, connector);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_bridge_connector_init);
+
+/**
* DOC: bridge callbacks
*
* The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index 1fd10d9..fa80317 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -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
@@ -239,8 +239,7 @@
*
* return: error code in case of failure or 0 for success.
*/
-int dsi_display_clk_ctrl(void *handle,
- enum dsi_clk_type clk_type, enum dsi_clk_state clk_state);
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state);
/**
* dsi_clk_set_link_frequencies() - set frequencies for link clks
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index 38eba8d..bff8627 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.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
@@ -1071,8 +1071,7 @@
DEFINE_MUTEX(dsi_mngr_clk_mutex);
-int dsi_display_clk_ctrl(void *handle,
- enum dsi_clk_type clk_type, enum dsi_clk_state clk_state)
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state)
{
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 6fb7105..0113c83 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -401,6 +401,21 @@
return rc;
}
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl)
+{
+ struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state;
+
+ if (!state) {
+ pr_err("Invalid host state for DSI controller\n");
+ return -EINVAL;
+ }
+
+ if (!state->host_initialized)
+ return true;
+
+ return false;
+}
+
static void dsi_ctrl_update_state(struct dsi_ctrl *dsi_ctrl,
enum dsi_ctrl_driver_ops op,
u32 op_state)
@@ -1072,10 +1087,10 @@
cmdbuf = (u8 *)(dsi_ctrl->vaddr);
+ msm_gem_sync(dsi_ctrl->tx_cmd_buf);
for (cnt = 0; cnt < length; cnt++)
cmdbuf[dsi_ctrl->cmd_len + cnt] = buffer[cnt];
- msm_gem_sync(dsi_ctrl->tx_cmd_buf);
dsi_ctrl->cmd_len += length;
if (!(msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) {
@@ -3294,6 +3309,25 @@
return misr;
}
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl)
+{
+ if (!dsi_ctrl || !dsi_ctrl->hw.ops.error_intr_ctrl
+ || !dsi_ctrl->hw.ops.clear_error_status) {
+ pr_err("Invalid params\n");
+ return;
+ }
+
+ /*
+ * Mask DSI error status interrupts and clear error status
+ * register
+ */
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+ dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false);
+ dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+ DSI_ERROR_INTERRUPT_COUNT);
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+}
+
/**
* dsi_ctrl_irq_update() - Put a irq vote to process DSI error
* interrupts at any time.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index 537bdc3..9636dbe 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -549,6 +549,16 @@
enum dsi_engine_state state);
/**
+ * dsi_ctrl_validate_host_state() - validate DSI ctrl host state
+ * @dsi_ctrl: DSI Controller handle.
+ *
+ * Validate DSI cotroller host state
+ *
+ * Return: boolean indicating whether host is not initalized.
+ */
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl);
+
+/**
* dsi_ctrl_set_vid_engine_state() - set video engine state
* @dsi_ctrl: DSI Controller handle.
* @state: Engine state.
@@ -713,6 +723,13 @@
void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable);
/**
+ * dsi_ctrl_mask_error_status_interrupts() - API to mask dsi ctrl error status
+ * interrupts
+ * @dsi_ctrl: DSI controller handle.
+ */
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl);
+
+/**
* dsi_ctrl_irq_update() - Put a irq vote to process DSI error
* interrupts at any time.
* @dsi_ctrl: DSI controller handle.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index c8edb09..fd18905 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -16,6 +16,7 @@
#include <linux/list.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/err.h>
#include "msm_drv.h"
@@ -51,6 +52,40 @@
static struct dsi_display *main_display;
+static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display)
+{
+ int i;
+ struct dsi_display_ctrl *ctrl;
+
+ if (!display)
+ return;
+
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl)
+ continue;
+ dsi_ctrl_mask_error_status_interrupts(ctrl->ctrl);
+ }
+}
+
+static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
+{
+ int i;
+ struct dsi_display_ctrl *ctrl;
+
+ if (!display)
+ return;
+
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl)
+ continue;
+ dsi_ctrl_irq_update(ctrl->ctrl, en);
+ }
+}
+
void dsi_rect_intersect(const struct dsi_rect *r1,
const struct dsi_rect *r2,
struct dsi_rect *result)
@@ -88,8 +123,11 @@
panel = dsi_display->panel;
- if (!dsi_panel_initialized(panel))
- return -EINVAL;
+ mutex_lock(&panel->panel_lock);
+ if (!dsi_panel_initialized(panel)) {
+ rc = -EINVAL;
+ goto error;
+ }
panel->bl_config.bl_level = bl_lvl;
@@ -124,6 +162,7 @@
}
error:
+ mutex_unlock(&panel->panel_lock);
return rc;
}
@@ -390,9 +429,17 @@
struct dsi_cmd_desc *cmds;
u32 flags = 0;
- if (!panel)
+ if (!panel || !ctrl || !ctrl->ctrl)
return -EINVAL;
+ /*
+ * When DSI controller is not in initialized state, we do not want to
+ * report a false ESD failure and hence we defer until next read
+ * happen.
+ */
+ if (dsi_ctrl_validate_host_state(ctrl->ctrl))
+ return 1;
+
/* acquire panel_lock to make sure no commands are in progress */
dsi_panel_acquire_panel_lock(panel);
@@ -497,6 +544,11 @@
}
}
exit:
+ if (rc <= 0) {
+ dsi_display_ctrl_irq_update(display, false);
+ dsi_display_mask_ctrl_error_interrupts(display);
+ }
+
dsi_display_cmd_engine_disable(display);
done:
return rc;
@@ -865,6 +917,62 @@
return rc;
}
+static ssize_t debugfs_esd_trigger_check(struct file *file,
+ const char __user *user_buf,
+ size_t user_len,
+ loff_t *ppos)
+{
+ struct dsi_display *display = file->private_data;
+ char *buf;
+ int rc = 0;
+ u32 esd_trigger;
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ if (user_len > sizeof(u32))
+ return -EINVAL;
+
+ buf = kzalloc(user_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, user_len)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ buf[user_len] = '\0'; /* terminate the string */
+
+ if (kstrtouint(buf, 10, &esd_trigger)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (esd_trigger != 1) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ display->esd_trigger = esd_trigger;
+
+ if (display->esd_trigger) {
+ rc = dsi_panel_trigger_esd_attack(display->panel);
+ if (rc) {
+ pr_err("Failed to trigger ESD attack\n");
+ return rc;
+ }
+ }
+
+ rc = user_len;
+error:
+ kfree(buf);
+ return rc;
+}
+
static ssize_t debugfs_misr_read(struct file *file,
char __user *user_buf,
size_t user_len,
@@ -941,6 +1049,11 @@
.write = debugfs_misr_setup,
};
+static const struct file_operations esd_trigger_fops = {
+ .open = simple_open,
+ .write = debugfs_esd_trigger_check,
+};
+
static int dsi_display_debugfs_init(struct dsi_display *display)
{
int rc = 0;
@@ -968,6 +1081,18 @@
goto error_remove_dir;
}
+ dump_file = debugfs_create_file("esd_trigger",
+ 0644,
+ dir,
+ display,
+ &esd_trigger_fops);
+ if (IS_ERR_OR_NULL(dump_file)) {
+ rc = PTR_ERR(dump_file);
+ pr_err("[%s] debugfs for esd trigger file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
misr_data = debugfs_create_file("misr_data",
0600,
dir,
@@ -2162,15 +2287,111 @@
return rc;
}
+/* initialize dsi_panel using ext bridge's setting */
+static int dsi_display_populate_ext_bridge_config(struct dsi_display *display,
+ struct mipi_dsi_device *dsi)
+{
+ struct dsi_panel *panel = display->panel;
+
+ if (!panel) {
+ pr_err("Invalid param\n");
+ return -EINVAL;
+ }
+
+ pr_debug("DSI[%s]: channel=%d, lanes=%d, format=%d, mode_flags=%lx\n",
+ dsi->name, dsi->channel, dsi->lanes,
+ dsi->format, dsi->mode_flags);
+
+ panel->host_config.data_lanes = 0;
+ if (dsi->lanes > 0)
+ panel->host_config.data_lanes |= DSI_DATA_LANE_0;
+ if (dsi->lanes > 1)
+ panel->host_config.data_lanes |= DSI_DATA_LANE_1;
+ if (dsi->lanes > 2)
+ panel->host_config.data_lanes |= DSI_DATA_LANE_2;
+ if (dsi->lanes > 3)
+ panel->host_config.data_lanes |= DSI_DATA_LANE_3;
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB888:
+ panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB888;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666_LOOSE;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ default:
+ panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB565;
+ break;
+ }
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ panel->panel_mode = DSI_OP_VIDEO_MODE;
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+ panel->video_config.traffic_mode =
+ DSI_VIDEO_TRAFFIC_BURST_MODE;
+ else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+ panel->video_config.traffic_mode =
+ DSI_VIDEO_TRAFFIC_SYNC_PULSES;
+ else
+ panel->video_config.traffic_mode =
+ DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS;
+
+ panel->video_config.hsa_lp11_en =
+ dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA;
+ panel->video_config.hbp_lp11_en =
+ dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP;
+ panel->video_config.hfp_lp11_en =
+ dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP;
+ panel->video_config.pulse_mode_hsa_he =
+ dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE;
+ panel->video_config.bllp_lp11_en =
+ dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BLLP;
+ panel->video_config.eof_bllp_lp11_en =
+ dsi->mode_flags & MIPI_DSI_MODE_VIDEO_EOF_BLLP;
+ } else {
+ panel->panel_mode = DSI_OP_CMD_MODE;
+ pr_err("command mode not supported by ext bridge\n");
+ return -ENOTSUPP;
+ }
+
+ /* TODO: add calc for these 2 values */
+ panel->host_config.t_clk_post = 0x03;
+ panel->host_config.t_clk_pre = 0x24;
+
+ panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN;
+
+ return 0;
+}
+
static int dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *dsi)
{
- return 0;
+ struct dsi_display *display = to_dsi_display(host);
+ int ret = 0;
+
+ if (!host || !dsi) {
+ pr_err("Invalid param\n");
+ return -EINVAL;
+ }
+
+ pr_debug("host attach\n");
+
+ if (dsi_display_has_ext_bridge(display))
+ ret = dsi_display_populate_ext_bridge_config(display, dsi);
+
+ return ret;
}
+
static int dsi_host_detach(struct mipi_dsi_host *host,
struct mipi_dsi_device *dsi)
{
+ pr_debug("host detach\n");
return 0;
}
@@ -2468,23 +2689,6 @@
}
}
-static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
-{
- int i;
- struct dsi_display_ctrl *ctrl;
-
- if (!display)
- return;
-
- for (i = 0; (i < display->ctrl_count) &&
- (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
- ctrl = &display->ctrl[i];
- if (!ctrl)
- continue;
- dsi_ctrl_irq_update(ctrl->ctrl, en);
- }
-}
-
int dsi_pre_clkoff_cb(void *priv,
enum dsi_clk_type clk,
enum dsi_clk_state new_state)
@@ -2847,11 +3051,31 @@
of_node = of_parse_phandle(display->pdev->dev.of_node,
"qcom,dsi-panel", 0);
if (!of_node) {
- pr_err("No Panel device present\n");
- rc = -ENODEV;
- goto error;
+ struct device_node *endpoint;
+
+ endpoint = of_graph_get_next_endpoint(
+ display->pdev->dev.of_node, NULL);
+ if (!endpoint) {
+ pr_err("no endpoint for ext bridge\n");
+ rc = -ENODEV;
+ goto error;
+ }
+
+ of_node = of_graph_get_remote_port_parent(endpoint);
+ of_node_put(endpoint);
+ if (!of_node) {
+ pr_err("no valid ext bridge\n");
+ rc = -ENODEV;
+ goto error;
+ }
+ of_node_put(of_node);
+
+ display->panel_of = of_node;
+ /* TODO: split support */
+ display->type = DSI_DISPLAY_EXT_BRIDGE;
} else {
display->panel_of = of_node;
+ display->type = DSI_DISPLAY_SINGLE;
}
error:
@@ -2863,6 +3087,8 @@
int rc = 0;
int i;
struct dsi_display_ctrl *ctrl;
+ enum dsi_panel_type panel_type =
+ dsi_display_has_ext_bridge(display) ? EXT_BRIDGE : DSI_PANEL;
for (i = 0; i < display->ctrl_count; i++) {
ctrl = &display->ctrl[i];
@@ -2885,7 +3111,8 @@
}
display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of,
- display->cmdline_topology);
+ display->cmdline_topology, panel_type);
+
if (IS_ERR_OR_NULL(display->panel)) {
rc = PTR_ERR(display->panel);
pr_err("failed to get panel, rc=%d\n", rc);
@@ -3300,9 +3527,9 @@
struct dsi_display_mode_priv_info *priv_info;
priv_info = mode->priv_info;
- if (!priv_info) {
+ if (!dsi_display_has_ext_bridge(display) && !priv_info) {
pr_err("[%s] failed to get private info of the display mode",
- display->name);
+ display->name);
return -EINVAL;
}
@@ -3339,7 +3566,8 @@
}
}
- if (priv_info->phy_timing_len) {
+ /* ext bridge calculates these timing params by phy driver */
+ if (priv_info && priv_info->phy_timing_len) {
for (i = 0; i < display->ctrl_count; i++) {
ctrl = &display->ctrl[i];
rc = dsi_phy_set_timing_params(ctrl->phy,
@@ -3424,6 +3652,12 @@
{
int rc = 0;
+ /* Continuous splash not supported by external bridge */
+ if (dsi_display_has_ext_bridge(display)) {
+ display->is_cont_splash_enabled = false;
+ return 0;
+ }
+
/* Vote for gdsc required to read register address space */
display->cont_splash_client = sde_power_client_create(display->phandle,
@@ -3436,7 +3670,9 @@
return -EINVAL;
}
- /* Verify whether continuous splash is enabled or not */
+ /*
+ * Verify whether continuous splash is enabled or not.
+ */
display->is_cont_splash_enabled =
dsi_display_get_cont_splash_status(display);
if (!display->is_cont_splash_enabled) {
@@ -4029,7 +4265,7 @@
}
if (display->bridge) {
- pr_err("display is already initialize\n");
+ pr_err("display is already initialized\n");
goto error;
}
@@ -4048,6 +4284,56 @@
return rc;
}
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+ struct drm_encoder *enc, struct drm_connector *connector)
+{
+ int rc = 0;
+ struct drm_bridge *ext_bridge;
+ struct msm_drm_private *priv = NULL;
+
+ if (!display || !display->drm_dev || !enc) {
+ pr_err("invalid param(s)\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&display->display_lock);
+ priv = display->drm_dev->dev_private;
+
+ if (!priv) {
+ pr_err("Private data is not present\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!display->bridge) {
+ pr_err("dsi bridge is not initialize\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ ext_bridge = of_drm_find_bridge(display->panel_of);
+ if (!ext_bridge) {
+ pr_err("ext brige not found\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* update connector ops in ext bridge */
+ drm_bridge_connector_init(ext_bridge, connector);
+
+ /* insert ext bridge to the bridge chain */
+ display->bridge->base.next = ext_bridge;
+ ext_bridge->encoder = enc;
+ priv->bridges[priv->num_bridges++] = ext_bridge;
+
+ drm_bridge_attach(display->drm_dev, ext_bridge);
+
+error:
+ mutex_unlock(&display->display_lock);
+ return rc;
+
+}
+
int dsi_display_drm_bridge_deinit(struct dsi_display *display)
{
int rc = 0;
@@ -4127,6 +4413,44 @@
return rc;
}
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp)
+{
+ struct dsi_display *display;
+ int i;
+
+ if (!info || !disp) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ display = disp;
+ if (!display->panel) {
+ pr_err("invalid display panel\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&display->display_lock);
+
+ memset(info, 0, sizeof(struct msm_display_info));
+
+ info->intf_type = DRM_MODE_CONNECTOR_DSI;
+ info->num_of_h_tiles = display->ctrl_count;
+ for (i = 0; i < info->num_of_h_tiles; i++)
+ info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
+
+ /*
+ * TODO: these info need come from ext bridge.
+ * using drm_connector->status, connector->polled.
+ */
+ info->is_connected = true;
+ info->is_primary = true;
+ info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE |
+ MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG);
+
+ mutex_unlock(&display->display_lock);
+ return 0;
+}
+
static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
u32 *count)
{
@@ -4851,12 +5175,15 @@
mode = display->panel->cur_mode;
if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
+ if (display->is_cont_splash_enabled) {
+ pr_err("DMS is not supposed to be set on first frame\n");
+ return -EINVAL;
+ }
/* update dsi ctrl for new mode */
rc = dsi_display_pre_switch(display);
if (rc)
pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
- display->name, rc);
-
+ display->name, rc);
goto error;
}
@@ -4990,6 +5317,9 @@
struct dsi_rect req_roi = { 0 };
int rc = 0;
+ if (dsi_display_has_ext_bridge(display))
+ return 0;
+
cur_mode = display->panel->cur_mode;
if (!cur_mode)
return 0;
@@ -5043,6 +5373,9 @@
if (!display || !rois || !display->panel)
return -EINVAL;
+ if (dsi_display_has_ext_bridge(display))
+ return 0;
+
cur_mode = display->panel->cur_mode;
if (!cur_mode)
return 0;
@@ -5197,7 +5530,7 @@
}
}
- if (mode->priv_info->dsc_enabled) {
+ if (mode->priv_info && mode->priv_info->dsc_enabled) {
mode->priv_info->dsc.pic_width *= display->ctrl_count;
rc = dsi_panel_update_pps(display->panel);
if (rc) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 4cfd4a9..53004e4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -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
@@ -160,6 +160,7 @@
* @root: Debugfs root directory
* @misr_enable Frame MISR enable/disable
* @misr_frame_count Number of frames to accumulate the MISR value
+ * @esd_trigger field indicating ESD trigger through debugfs
*/
struct dsi_display {
struct platform_device *pdev;
@@ -218,6 +219,7 @@
bool misr_enable;
u32 misr_frame_count;
+ u32 esd_trigger;
/* multiple dsi error handlers */
struct workqueue_struct *err_workq;
struct work_struct fifo_underflow_work;
@@ -225,6 +227,18 @@
struct work_struct lp_rx_timeout_work;
};
+/**
+ * dsi_display_has_ext_bridge() - check whether display has ext bridge
+ * connected.
+ *
+ * Return: True - ext bridge, False - no ext bridge.
+ */
+static inline bool dsi_display_has_ext_bridge(const struct dsi_display *display)
+{
+ return display->type == DSI_DISPLAY_EXT_BRIDGE ||
+ display->type == DSI_DISPLAY_SPLIT_EXT_BRIDGE;
+}
+
int dsi_display_dev_probe(struct platform_device *pdev);
int dsi_display_dev_remove(struct platform_device *pdev);
@@ -288,6 +302,19 @@
int dsi_display_drm_bridge_deinit(struct dsi_display *display);
/**
+ * dsi_display_drm_ext_bridge_init() - initializes DRM bridge for ext bridge
+ * @display: Handle to the display.
+ * @enc: Pointer to the encoder object which is connected to the
+ * display.
+ * @connector: Pointer to the connector object which is connected to
+ * the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+ struct drm_encoder *enc, struct drm_connector *connector);
+
+/**
* dsi_display_get_info() - returns the display properties
* @info: Pointer to the structure where info is stored.
* @disp: Handle to the display.
@@ -297,6 +324,15 @@
int dsi_display_get_info(struct msm_display_info *info, void *disp);
/**
+ * dsi_display_ext_bridge_get_info() - returns the ext bridge's display info
+ * @info: Pointer to the structure where info is stored.
+ * @disp: Handle to the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp);
+
+/**
* dsi_display_get_mode_count() - get number of modes supported by the display
* @display: Handle to display.
* @count: Number of modes supported
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index a1e4685..5b47865 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.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
@@ -63,6 +63,11 @@
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
if (msm_is_mode_seamless_vrr(drm_mode))
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
+
+ dsi_mode->timing.h_sync_polarity =
+ !!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
+ dsi_mode->timing.v_sync_polarity =
+ !!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC);
}
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
@@ -101,6 +106,11 @@
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
+ if (dsi_mode->timing.h_sync_polarity)
+ drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ if (dsi_mode->timing.v_sync_polarity)
+ drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+
drm_mode_set_name(drm_mode);
}
@@ -288,17 +298,23 @@
convert_to_dsi_mode(mode, &dsi_mode);
- /*
- * retrieve dsi mode from dsi driver's cache since not safe to take
- * the drm mode config mutex in all paths
- */
- rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
- if (rc)
- return rc;
+ /* external bridge doesn't use priv_info and dsi_mode_flags */
+ if (!dsi_display_has_ext_bridge(display)) {
+ /*
+ * retrieve dsi mode from dsi driver's cache since not safe to
+ * take the drm mode config mutex in all paths
+ */
+ rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
+ if (rc)
+ return rc;
- /* propagate the private info to the adjusted_mode derived dsi mode */
- dsi_mode.priv_info = panel_dsi_mode->priv_info;
- dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+ /*
+ * propagate the private info to the adjusted_mode derived dsi
+ * mode
+ */
+ dsi_mode.priv_info = panel_dsi_mode->priv_info;
+ dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+ }
rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode,
DSI_VALIDATE_FLAG_ALLOW_ADJUST);
@@ -377,6 +393,35 @@
return 0;
}
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info,
+ u32 max_mixer_width, void *display)
+{
+ struct msm_display_topology *topology;
+ struct dsi_display_mode dsi_mode;
+ struct dsi_mode_info *timing;
+
+ if (!drm_mode || !mode_info)
+ return -EINVAL;
+
+ convert_to_dsi_mode(drm_mode, &dsi_mode);
+
+ memset(mode_info, 0, sizeof(*mode_info));
+
+ timing = &dsi_mode.timing;
+ mode_info->frame_rate = dsi_mode.timing.refresh_rate;
+ mode_info->vtotal = DSI_V_TOTAL(timing);
+
+ topology = &mode_info->topology;
+ topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? 2 : 1;
+ topology->num_enc = 0;
+ topology->num_intf = topology->num_lm;
+
+ mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+
+ return 0;
+}
+
static const struct drm_bridge_funcs dsi_bridge_ops = {
.attach = dsi_bridge_attach,
.mode_fixup = dsi_bridge_mode_fixup,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index ec58479..2bad8c0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -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
@@ -86,6 +86,18 @@
void *display);
/**
+ * dsi_conn_ext_bridge_get_mode_info - retrieve information on the mode selected
+ * @drm_mode: Display mode set for the display
+ * @mode_info: Out parameter. information of the mode.
+ * @max_mixer_width: max width supported by HW layer mixer
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+ struct msm_mode_info *mode_info, u32 max_mixer_width,
+ void *display);
+
+/**
* dsi_conn_mode_valid - callback to determine if specified mode is valid
* @connector: Pointer to drm connector structure
* @mode: Pointer to drm mode structure
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index eaeeb52..d8b90e3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -32,6 +32,7 @@
#define MAX_TOPOLOGY 5
#define DSI_PANEL_DEFAULT_LABEL "Default dsi panel"
+#define EXT_BRIDGE_DEFAULT_LABEL "Default ext bridge"
#define DEFAULT_MDP_TRANSFER_TIME 14000
@@ -321,6 +322,30 @@
return rc;
}
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel)
+{
+ struct dsi_panel_reset_config *r_config;
+
+ if (!panel) {
+ pr_err("Invalid panel param\n");
+ return -EINVAL;
+ }
+
+ r_config = &panel->reset_config;
+ if (!r_config) {
+ pr_err("Invalid panel reset configuration\n");
+ return -EINVAL;
+ }
+
+ if (gpio_is_valid(r_config->reset_gpio)) {
+ gpio_set_value(r_config->reset_gpio, 0);
+ pr_info("GPIO pulled low to simulate ESD\n");
+ return 0;
+ }
+ pr_err("failed to pull down gpio\n");
+ return -EINVAL;
+}
+
static int dsi_panel_reset(struct dsi_panel *panel)
{
int rc = 0;
@@ -480,6 +505,9 @@
if (!panel || !panel->cur_mode)
return -EINVAL;
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mode = panel->cur_mode;
cmds = mode->priv_info->cmd_sets[type].cmds;
@@ -610,13 +638,10 @@
dsi = &panel->mipi_device;
- mutex_lock(&panel->panel_lock);
-
rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl);
if (rc < 0)
pr_err("failed to update dcs backlight:%d\n", bl_lvl);
- mutex_unlock(&panel->panel_lock);
return rc;
}
@@ -625,13 +650,16 @@
int rc = 0;
struct dsi_backlight_config *bl = &panel->bl_config;
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
pr_debug("backlight type:%d lvl:%d\n", bl->type, bl_lvl);
switch (bl->type) {
case DSI_BACKLIGHT_WLED:
led_trigger_event(bl->wled, bl_lvl);
break;
case DSI_BACKLIGHT_DCS:
- dsi_panel_update_backlight(panel, bl_lvl);
+ rc = dsi_panel_update_backlight(panel, bl_lvl);
break;
default:
pr_err("Backlight type(%d) not supported\n", bl->type);
@@ -2713,7 +2741,8 @@
struct dsi_panel *dsi_panel_get(struct device *parent,
struct device_node *of_node,
- int topology_override)
+ int topology_override,
+ enum dsi_panel_type type)
{
struct dsi_panel *panel;
int rc = 0;
@@ -2722,68 +2751,85 @@
if (!panel)
return ERR_PTR(-ENOMEM);
- panel->name = of_get_property(of_node, "qcom,mdss-dsi-panel-name",
- NULL);
- if (!panel->name)
- panel->name = DSI_PANEL_DEFAULT_LABEL;
+ if (type == DSI_PANEL) {
+ panel->name = of_get_property(of_node,
+ "qcom,mdss-dsi-panel-name", NULL);
+ if (!panel->name)
+ panel->name = DSI_PANEL_DEFAULT_LABEL;
- rc = dsi_panel_parse_host_config(panel, of_node);
- if (rc) {
- pr_err("failed to parse host configuration, rc=%d\n", rc);
+ rc = dsi_panel_parse_host_config(panel, of_node);
+ if (rc) {
+ pr_err("failed to parse host configuration, rc=%d\n",
+ rc);
+ goto error;
+ }
+
+ rc = dsi_panel_parse_panel_mode(panel, of_node);
+ if (rc) {
+ pr_err("failed to parse panel mode configuration, rc=%d\n",
+ rc);
+ goto error;
+ }
+
+ rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps,
+ of_node, panel->name);
+ if (rc)
+ pr_err("failed to parse dfps configuration, rc=%d\n",
+ rc);
+
+ rc = dsi_panel_parse_phy_props(&panel->phy_props,
+ of_node, panel->name);
+ if (rc) {
+ pr_err("failed to parse panel physical dimension, rc=%d\n",
+ rc);
+ goto error;
+ }
+
+ rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
+ if (rc)
+ pr_err("failed to parse power config, rc=%d\n", rc);
+
+ rc = dsi_panel_parse_gpios(panel, of_node);
+ if (rc)
+ pr_err("failed to parse panel gpios, rc=%d\n", rc);
+
+ rc = dsi_panel_parse_bl_config(panel, of_node);
+ if (rc)
+ pr_err("failed to parse backlight config, rc=%d\n", rc);
+
+
+ rc = dsi_panel_parse_misc_features(panel, of_node);
+ if (rc)
+ pr_err("failed to parse misc features, rc=%d\n", rc);
+
+ rc = dsi_panel_parse_hdr_config(panel, of_node);
+ if (rc)
+ pr_err("failed to parse hdr config, rc=%d\n", rc);
+
+ rc = dsi_panel_get_mode_count(panel, of_node);
+ if (rc) {
+ pr_err("failed to get mode count, rc=%d\n", rc);
+ goto error;
+ }
+
+ rc = dsi_panel_parse_dms_info(panel, of_node);
+ if (rc)
+ pr_debug("failed to get dms info, rc=%d\n", rc);
+
+ rc = dsi_panel_parse_esd_config(panel, of_node);
+ if (rc)
+ pr_debug("failed to parse esd config, rc=%d\n", rc);
+
+ panel->type = DSI_PANEL;
+ } else if (type == EXT_BRIDGE) {
+ panel->name = EXT_BRIDGE_DEFAULT_LABEL;
+ panel->type = EXT_BRIDGE;
+ } else {
+ pr_err("invalid panel type\n");
+ rc = -ENOTSUPP;
goto error;
}
- rc = dsi_panel_parse_panel_mode(panel, of_node);
- if (rc) {
- pr_err("failed to parse panel mode configuration, rc=%d\n", rc);
- goto error;
- }
-
- rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps, of_node, panel->name);
- if (rc)
- pr_err("failed to parse dfps configuration, rc=%d\n", rc);
-
- rc = dsi_panel_parse_phy_props(&panel->phy_props, of_node, panel->name);
- if (rc) {
- pr_err("failed to parse panel physical dimension, rc=%d\n", rc);
- goto error;
- }
-
- rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
- if (rc)
- pr_err("failed to parse power config, rc=%d\n", rc);
-
- rc = dsi_panel_parse_gpios(panel, of_node);
- if (rc)
- pr_err("failed to parse panel gpios, rc=%d\n", rc);
-
- rc = dsi_panel_parse_bl_config(panel, of_node);
- if (rc)
- pr_err("failed to parse backlight config, rc=%d\n", rc);
-
-
- rc = dsi_panel_parse_misc_features(panel, of_node);
- if (rc)
- pr_err("failed to parse misc features, rc=%d\n", rc);
-
- rc = dsi_panel_parse_hdr_config(panel, of_node);
- if (rc)
- pr_err("failed to parse hdr config, rc=%d\n", rc);
-
- rc = dsi_panel_get_mode_count(panel, of_node);
- if (rc) {
- pr_err("failed to get mode count, rc=%d\n", rc);
- goto error;
- }
-
- rc = dsi_panel_parse_dms_info(panel, of_node);
- if (rc)
- pr_debug("failed to get dms info, rc=%d\n", rc);
-
- rc = dsi_panel_parse_esd_config(panel, of_node);
- if (rc)
- pr_debug("failed to parse esd config, rc=%d\n", rc);
-
panel->panel_of_node = of_node;
drm_panel_init(&panel->drm_panel);
mutex_init(&panel->panel_lock);
@@ -2797,7 +2843,8 @@
void dsi_panel_put(struct dsi_panel *panel)
{
/* free resources allocated for ESD check */
- dsi_panel_esd_config_deinit(&panel->esd_config);
+ if (panel->type == DSI_PANEL)
+ dsi_panel_esd_config_deinit(&panel->esd_config);
kfree(panel);
}
@@ -2813,6 +2860,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
dev = &panel->mipi_device;
@@ -2877,6 +2927,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_bl_unregister(panel);
@@ -3005,6 +3058,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
mode->priv_info = kzalloc(sizeof(*mode->priv_info), GFP_KERNEL);
@@ -3112,10 +3168,12 @@
memcpy(&config->video_timing, &mode->timing,
sizeof(config->video_timing));
- config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
- config->video_timing.dsc = &mode->priv_info->dsc;
- config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+ if (mode->priv_info) {
+ config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
+ config->video_timing.dsc = &mode->priv_info->dsc;
+ config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+ }
config->esc_clk_rate_hz = 19200000;
mutex_unlock(&panel->panel_lock);
return rc;
@@ -3130,6 +3188,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
/* If LP11_INIT is set, panel will be powered up during prepare() */
@@ -3158,6 +3219,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
priv_info = panel->cur_mode->priv_info;
@@ -3193,6 +3257,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
if (rc)
@@ -3211,6 +3278,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2);
if (rc)
@@ -3229,6 +3299,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
if (rc)
@@ -3247,6 +3320,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
if (panel->lp11_init) {
@@ -3357,6 +3433,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
priv_info = panel->cur_mode->priv_info;
set = &priv_info->cmd_sets[DSI_CMD_SET_ROI];
@@ -3392,6 +3471,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH);
@@ -3412,6 +3494,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_TIMING_SWITCH);
@@ -3432,6 +3517,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON);
@@ -3453,6 +3541,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_ON);
@@ -3475,6 +3566,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_OFF);
@@ -3498,6 +3592,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_OFF);
@@ -3522,6 +3619,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_OFF);
@@ -3553,6 +3653,9 @@
return -EINVAL;
}
+ if (panel->type == EXT_BRIDGE)
+ return 0;
+
mutex_lock(&panel->panel_lock);
if (!panel->lp11_init) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 06199f4..3b226b0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -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
@@ -140,8 +140,15 @@
u32 groups;
};
+enum dsi_panel_type {
+ DSI_PANEL = 0,
+ EXT_BRIDGE,
+ DSI_PANEL_TYPE_MAX,
+};
+
struct dsi_panel {
const char *name;
+ enum dsi_panel_type type;
struct device_node *panel_of_node;
struct mipi_dsi_device mipi_device;
@@ -204,7 +211,10 @@
struct dsi_panel *dsi_panel_get(struct device *parent,
struct device_node *of_node,
- int topology_override);
+ int topology_override,
+ enum dsi_panel_type type);
+
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel);
void dsi_panel_put(struct dsi_panel *panel);
@@ -269,4 +279,10 @@
void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
+struct dsi_panel *dsi_panel_ext_bridge_get(struct device *parent,
+ struct device_node *of_node,
+ int topology_override);
+
+void dsi_panel_ext_bridge_put(struct dsi_panel *panel);
+
#endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 655390b..21b67d9 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -68,6 +68,7 @@
struct sde_connector *c_conn;
int bl_lvl;
struct drm_event event;
+ int rc = 0;
brightness = bd->props.brightness;
@@ -93,10 +94,10 @@
event.length = sizeof(u32);
msm_mode_object_event_notify(&c_conn->base.base,
c_conn->base.dev, &event, (u8 *)&brightness);
- c_conn->ops.set_backlight(c_conn->display, bl_lvl);
+ rc = c_conn->ops.set_backlight(c_conn->display, bl_lvl);
}
- return 0;
+ return rc;
}
static int sde_backlight_device_get_brightness(struct backlight_device *bd)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 1ee75c4..8d2f115 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -4581,10 +4581,13 @@
{
struct drm_encoder *encoder;
struct sde_crtc_state *cstate;
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_smmu_state_data *smmu_state;
uint32_t secure;
uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
int encoder_cnt = 0, i;
int rc;
+ bool is_video_mode = false;
if (!crtc || !state) {
SDE_ERROR("invalid arguments\n");
@@ -4642,6 +4645,37 @@
}
}
+
+ drm_for_each_encoder(encoder, crtc->dev) {
+ if (encoder->crtc != crtc)
+ continue;
+
+ is_video_mode |= sde_encoder_check_mode(encoder,
+ MSM_DISPLAY_CAP_VID_MODE);
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ smmu_state = &sde_crtc->smmu_state;
+ /*
+ * In video mode check for null commit before transition
+ * from secure to non secure and vice versa
+ */
+ if (is_video_mode && smmu_state &&
+ state->plane_mask && crtc->state->plane_mask &&
+ ((fb_sec_dir && ((smmu_state->state == ATTACHED) &&
+ (secure == SDE_DRM_SEC_ONLY))) ||
+ (fb_ns && ((smmu_state->state == DETACHED) ||
+ (smmu_state->state == DETACH_ALL_REQ))))) {
+
+ SDE_EVT32(DRMID(&sde_crtc->base), fb_ns, fb_sec_dir,
+ smmu_state->state, crtc->state->plane_mask,
+ crtc->state->plane_mask);
+ SDE_DEBUG("crtc %d, Invalid secure transition %x\n",
+ crtc->base.id, smmu_state->state);
+ return -EINVAL;
+
+ }
+
SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id);
return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 6ccf957..02d593b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.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
@@ -474,6 +474,7 @@
struct sde_hw_blk_reg_map hw;
memset(&hw, 0, sizeof(hw));
+ msm_gem_sync(cfg->dma_buf->buf);
cmd1 = (cfg->op == REG_DMA_READ) ?
(dspp_read_sel[cfg->block_select] << 30) : 0;
cmd1 |= (cfg->last_command) ? BIT(24) : 0;
@@ -481,7 +482,6 @@
cmd1 |= (cfg->op == REG_DMA_WRITE) ? (BIT(22)) : 0;
cmd1 |= (SIZE_DWORD(cfg->dma_buf->index) & MAX_DWORDS_SZ);
- msm_gem_sync(cfg->dma_buf->buf);
SET_UP_REG_DMA_REG(hw, reg_dma);
SDE_REG_WRITE(&hw, REG_DMA_OP_MODE_OFF, BIT(0));
SDE_REG_WRITE(&hw, reg_dma_clear_status_off,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 5d3835c..5895a4d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -952,6 +952,17 @@
.config_hdr = dp_connector_config_hdr,
.cmd_transfer = NULL,
};
+ static const struct sde_connector_ops ext_bridge_ops = {
+ .set_info_blob = dsi_conn_set_info_blob,
+ .mode_valid = dsi_conn_mode_valid,
+ .get_info = dsi_display_ext_bridge_get_info,
+ .soft_reset = dsi_display_soft_reset,
+ .clk_ctrl = dsi_display_clk_ctrl,
+ .get_mode_info = dsi_conn_ext_bridge_get_mode_info,
+ .get_dst_format = dsi_display_get_dst_format,
+ .enable_event = dsi_conn_enable_event,
+ .cmd_transfer = NULL,
+ };
struct msm_display_info info;
struct drm_encoder *encoder;
void *display, *connector;
@@ -976,39 +987,95 @@
display = sde_kms->dsi_displays[i];
encoder = NULL;
- memset(&info, 0x0, sizeof(info));
- rc = dsi_display_get_info(&info, display);
- if (rc) {
- SDE_ERROR("dsi get_info %d failed\n", i);
- continue;
- }
+ if (!dsi_display_has_ext_bridge(display)) {
+ memset(&info, 0x0, sizeof(info));
+ rc = dsi_display_get_info(&info, display);
+ if (rc) {
+ SDE_ERROR("dsi get_info %d failed\n", i);
+ continue;
+ }
- encoder = sde_encoder_init(dev, &info);
- if (IS_ERR_OR_NULL(encoder)) {
- SDE_ERROR("encoder init failed for dsi %d\n", i);
- continue;
- }
+ encoder = sde_encoder_init(dev, &info);
+ if (IS_ERR_OR_NULL(encoder)) {
+ SDE_ERROR("encoder init failed for dsi %d\n",
+ i);
+ continue;
+ }
- rc = dsi_display_drm_bridge_init(display, encoder);
- if (rc) {
- SDE_ERROR("dsi bridge %d init failed, %d\n", i, rc);
- sde_encoder_destroy(encoder);
- continue;
- }
+ rc = dsi_display_drm_bridge_init(display, encoder);
+ if (rc) {
+ SDE_ERROR("dsi bridge %d init failed, %d\n",
+ i, rc);
+ sde_encoder_destroy(encoder);
+ continue;
+ }
- connector = sde_connector_init(dev,
- encoder,
- 0,
- display,
- &dsi_ops,
- DRM_CONNECTOR_POLL_HPD,
- DRM_MODE_CONNECTOR_DSI);
- if (connector) {
- priv->encoders[priv->num_encoders++] = encoder;
+ connector = sde_connector_init(dev,
+ encoder,
+ NULL,
+ display,
+ &dsi_ops,
+ DRM_CONNECTOR_POLL_HPD,
+ DRM_MODE_CONNECTOR_DSI);
+ if (connector) {
+ priv->encoders[priv->num_encoders++] = encoder;
+ } else {
+ SDE_ERROR("dsi %d connector init failed\n", i);
+ dsi_display_drm_bridge_deinit(display);
+ sde_encoder_destroy(encoder);
+ }
} else {
- SDE_ERROR("dsi %d connector init failed\n", i);
- dsi_display_drm_bridge_deinit(display);
- sde_encoder_destroy(encoder);
+ memset(&info, 0x0, sizeof(info));
+ rc = dsi_display_ext_bridge_get_info(&info, display);
+ if (rc) {
+ SDE_ERROR("ext get_info %d failed\n", i);
+ continue;
+ }
+
+ encoder = sde_encoder_init(dev, &info);
+ if (IS_ERR_OR_NULL(encoder)) {
+ SDE_ERROR("encoder init failed for ext %d\n",
+ i);
+ continue;
+ }
+
+ rc = dsi_display_drm_bridge_init(display, encoder);
+ if (rc) {
+ SDE_ERROR("dsi bridge %d init failed for ext\n",
+ i);
+ sde_encoder_destroy(encoder);
+ continue;
+ }
+
+ connector = sde_connector_init(dev,
+ encoder,
+ NULL,
+ display,
+ &ext_bridge_ops,
+ DRM_CONNECTOR_POLL_HPD,
+ DRM_MODE_CONNECTOR_DSI);
+ if (connector) {
+ priv->encoders[priv->num_encoders++] = encoder;
+ } else {
+ SDE_ERROR("connector init %d failed for ext\n",
+ i);
+ dsi_display_drm_bridge_deinit(display);
+ sde_encoder_destroy(encoder);
+ continue;
+ }
+
+ rc = dsi_display_drm_ext_bridge_init(display,
+ encoder, connector);
+ if (rc) {
+ struct drm_connector *conn = connector;
+
+ SDE_ERROR("ext bridge %d init failed, %d\n",
+ i, rc);
+ conn->funcs->destroy(connector);
+ dsi_display_drm_bridge_deinit(display);
+ sde_encoder_destroy(encoder);
+ continue;
+ }
}
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f7f3e9e..ab9f203 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -19,7 +19,6 @@
#include <linux/input.h>
#include <linux/io.h>
#include <soc/qcom/scm.h>
-#include <linux/nvmem-consumer.h>
#include <linux/msm-bus-board.h>
#include <linux/msm-bus.h>
@@ -745,64 +744,33 @@
{ ADRENO_QUIRK_SECVID_SET_ONCE, "qcom,gpu-quirk-secvid-set-once" },
{ ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW,
"qcom,gpu-quirk-limit-uche-gbif-rw" },
+ { ADRENO_QUIRK_MMU_SECURE_CB_ALT, "qcom,gpu-quirk-mmu-secure-cb-alt" },
};
-#if defined(CONFIG_NVMEM) && defined(CONFIG_QCOM_QFPROM)
static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
+adreno_get_soc_hw_revision_node(struct adreno_device *adreno_dev,
+ struct platform_device *pdev)
{
struct device_node *node, *child;
- struct nvmem_cell *cell;
- ssize_t len;
- u32 *buf, hw_rev, rev;
+ unsigned int rev;
node = of_find_node_by_name(pdev->dev.of_node, "qcom,soc-hw-revisions");
if (node == NULL)
- goto err;
-
- /* read the soc hw revision and select revision node */
- cell = nvmem_cell_get(&pdev->dev, "minor_rev");
- if (IS_ERR_OR_NULL(cell)) {
- if (PTR_ERR(cell) == -EPROBE_DEFER)
- return (void *)cell;
-
- KGSL_CORE_ERR("Unable to get nvmem cell: ret=%ld\n",
- PTR_ERR(cell));
- goto err;
- }
-
- buf = nvmem_cell_read(cell, &len);
- nvmem_cell_put(cell);
-
- if (IS_ERR_OR_NULL(buf)) {
- KGSL_CORE_ERR("Unable to read nvmem cell: ret=%ld\n",
- PTR_ERR(buf));
- goto err;
- }
-
- hw_rev = *buf;
- kfree(buf);
+ return NULL;
for_each_child_of_node(node, child) {
- if (of_property_read_u32(child, "reg", &rev))
+ if (of_property_read_u32(child, "qcom,soc-hw-revision", &rev))
continue;
- if (rev == hw_rev)
+ if (rev == adreno_dev->soc_hw_rev)
return child;
}
-err:
- /* fall back to parent node */
- return pdev->dev.of_node;
+ KGSL_DRV_WARN(KGSL_DEVICE(adreno_dev),
+ "No matching SOC HW revision found for efused HW rev=%u\n",
+ adreno_dev->soc_hw_rev);
+ return NULL;
}
-#else
-static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
-{
- return pdev->dev.of_node;
-}
-#endif
-
static int adreno_update_soc_hw_revision_quirks(
struct adreno_device *adreno_dev, struct platform_device *pdev)
@@ -810,9 +778,9 @@
struct device_node *node;
int i;
- node = adreno_get_soc_hw_revision_node(pdev);
- if (IS_ERR(node))
- return PTR_ERR(node);
+ node = adreno_get_soc_hw_revision_node(adreno_dev, pdev);
+ if (node == NULL)
+ node = pdev->dev.of_node;
/* get chip id, fall back to parent if revision node does not have it */
if (of_property_read_u32(node, "qcom,chipid", &adreno_dev->chipid))
@@ -1131,6 +1099,36 @@
KGSL_DRV_WARN(device, "cx_dbgc ioremap failed\n");
}
+static void adreno_efuse_read_soc_hw_rev(struct adreno_device *adreno_dev)
+{
+ unsigned int val;
+ unsigned int soc_hw_rev[3];
+ int ret;
+
+ if (of_property_read_u32_array(
+ KGSL_DEVICE(adreno_dev)->pdev->dev.of_node,
+ "qcom,soc-hw-rev-efuse", soc_hw_rev, 3))
+ return;
+
+ ret = adreno_efuse_map(adreno_dev);
+ if (ret) {
+ KGSL_CORE_ERR(
+ "Unable to map hardware revision fuse: ret=%d\n", ret);
+ return;
+ }
+
+ ret = adreno_efuse_read_u32(adreno_dev, soc_hw_rev[0], &val);
+ adreno_efuse_unmap(adreno_dev);
+
+ if (ret) {
+ KGSL_CORE_ERR(
+ "Unable to read hardware revision fuse: ret=%d\n", ret);
+ return;
+ }
+
+ adreno_dev->soc_hw_rev = (val >> soc_hw_rev[1]) & soc_hw_rev[2];
+}
+
static bool adreno_is_gpu_disabled(struct adreno_device *adreno_dev)
{
unsigned int row0;
@@ -1179,11 +1177,10 @@
return -ENODEV;
}
- status = adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
- if (status) {
- device->pdev = NULL;
- return status;
- }
+ /* Identify SOC hardware revision to be used */
+ adreno_efuse_read_soc_hw_rev(adreno_dev);
+
+ adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
/* Get the chip ID from the DT and set up target specific parameters */
adreno_identify_gpu(adreno_dev);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 82b06fe..8785d62 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -150,6 +150,8 @@
* between GBIF, SMMU and MEMNOC.
*/
#define ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW BIT(8)
+/* Select alternate secure context bank for mmu */
+#define ADRENO_QUIRK_MMU_SECURE_CB_ALT BIT(9)
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0
@@ -465,6 +467,7 @@
* @gpuhtw_llc_slice: GPU pagetables system cache slice descriptor
* @gpuhtw_llc_slice_enable: To enable the GPUHTW system cache slice or not
* @zap_loaded: Used to track if zap was successfully loaded or not
+ * @soc_hw_rev: Indicate which SOC hardware revision to use
*/
struct adreno_device {
struct kgsl_device dev; /* Must be first field in this struct */
@@ -537,6 +540,7 @@
void *gpuhtw_llc_slice;
bool gpuhtw_llc_slice_enable;
unsigned int zap_loaded;
+ unsigned int soc_hw_rev;
};
/**
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 472f78e..9a878fb 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.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
@@ -2253,6 +2253,14 @@
atomic_add(halt, &adreno_dev->halt);
+ /*
+ * At this point it is safe to assume that we recovered. Setting
+ * this field allows us to take a new snapshot for the next failure
+ * if we are prioritizing the first unrecoverable snapshot.
+ */
+ if (device->snapshot)
+ device->snapshot->recovered = true;
+
return 1;
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 5168d9e..a8075fe 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -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
@@ -261,7 +261,8 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
- int i, status;
+ int i;
+ int status = -ENOMEM;
if (!adreno_is_a3xx(adreno_dev)) {
status = kgsl_allocate_global(device, &device->scratch,
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7c3bff7..b6a2edb 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.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
@@ -303,6 +303,7 @@
u32 snapshot_faultcount; /* Total number of faults since boot */
bool force_panic; /* Force panic after snapshot dump */
+ bool prioritize_unrecoverable; /* Overwrite with new GMU snapshots */
/* Use CP Crash dumper to get GPU snapshot*/
bool snapshot_crashdumper;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 60c56a06..c4296c8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -2527,6 +2527,7 @@
} kgsl_iommu_cbs[] = {
{ KGSL_IOMMU_CONTEXT_USER, "gfx3d_user", },
{ KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure" },
+ { KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure_alt" },
};
static int _kgsl_iommu_cb_probe(struct kgsl_device *device,
@@ -2534,12 +2535,20 @@
{
struct platform_device *pdev = of_find_device_by_node(node);
struct kgsl_iommu_context *ctx = NULL;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
for (i = 0; i < ARRAY_SIZE(kgsl_iommu_cbs); i++) {
if (!strcmp(node->name, kgsl_iommu_cbs[i].name)) {
int id = kgsl_iommu_cbs[i].id;
+ if (ADRENO_QUIRK(adreno_dev,
+ ADRENO_QUIRK_MMU_SECURE_CB_ALT)) {
+ if (!strcmp(node->name, "gfx3d_secure"))
+ continue;
+ } else if (!strcmp(node->name, "gfx3d_secure_alt"))
+ continue;
+
ctx = &iommu->ctx[id];
ctx->id = id;
ctx->cb_num = -1;
@@ -2550,8 +2559,8 @@
}
if (ctx == NULL) {
- KGSL_CORE_ERR("dt: Unknown context label %s\n", node->name);
- return -EINVAL;
+ KGSL_CORE_ERR("dt: Unused context label %s\n", node->name);
+ return 0;
}
if (ctx->id == KGSL_IOMMU_CONTEXT_SECURE)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7509ceb..2cd132e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2222,7 +2222,7 @@
int kgsl_pwrctrl_init(struct kgsl_device *device)
{
- int i, k, m, n = 0, result;
+ int i, k, m, n = 0, result, freq;
struct platform_device *pdev = device->pdev;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct device_node *ocmem_bus_node;
@@ -2269,7 +2269,7 @@
pwr->wakeup_maxpwrlevel = 0;
for (i = 0; i < pwr->num_pwrlevels; i++) {
- unsigned int freq = pwr->pwrlevels[i].gpu_freq;
+ freq = pwr->pwrlevels[i].gpu_freq;
if (freq > 0)
freq = clk_round_rate(pwr->grp_clks[0], freq);
@@ -2282,11 +2282,10 @@
kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
- if (pwr->grp_clks[6] != NULL)
+ freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ);
+ if (freq > 0)
kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[6],
- clk_round_rate(pwr->grp_clks[6],
- KGSL_RBBMTIMER_CLK_FREQ),
- clocks[6]);
+ freq, clocks[6]);
_isense_clk_set_rate(pwr, pwr->num_pwrlevels - 1);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 33ce60d..5e41611 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.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
@@ -663,7 +663,8 @@
* Overwrite a non-GMU fault snapshot if a GMU fault occurs.
*/
if (device->snapshot != NULL) {
- if (!gmu_fault || !device->snapshot->recovered)
+ if (!device->prioritize_unrecoverable ||
+ !device->snapshot->recovered)
return;
/*
@@ -954,6 +955,28 @@
return (ssize_t) ret < 0 ? ret : count;
}
+/* Show the prioritize_unrecoverable status */
+static ssize_t prioritize_unrecoverable_show(
+ struct kgsl_device *device, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ device->prioritize_unrecoverable);
+}
+
+/* Store the priority value to prioritize unrecoverable */
+static ssize_t prioritize_unrecoverable_store(
+ struct kgsl_device *device, const char *buf, size_t count)
+{
+ unsigned int val = 0;
+ int ret = 0;
+
+ ret = kgsl_sysfs_store(buf, &val);
+ if (!ret && device)
+ device->prioritize_unrecoverable = (bool) val;
+
+ return (ssize_t) ret < 0 ? ret : count;
+}
+
/* Show the snapshot_crashdumper request status */
static ssize_t snapshot_crashdumper_show(struct kgsl_device *device, char *buf)
{
@@ -1026,6 +1049,8 @@
static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store);
+static SNAPSHOT_ATTR(prioritize_unrecoverable, 0644,
+ prioritize_unrecoverable_show, prioritize_unrecoverable_store);
static SNAPSHOT_ATTR(snapshot_crashdumper, 0644, snapshot_crashdumper_show,
snapshot_crashdumper_store);
static SNAPSHOT_ATTR(snapshot_legacy, 0644, snapshot_legacy_show,
@@ -1110,6 +1135,7 @@
device->snapshot = NULL;
device->snapshot_faultcount = 0;
device->force_panic = 0;
+ device->prioritize_unrecoverable = true;
device->snapshot_crashdumper = 1;
device->snapshot_legacy = 0;
@@ -1135,6 +1161,11 @@
if (ret)
goto done;
+ ret = sysfs_create_file(&device->snapshot_kobj,
+ &attr_prioritize_unrecoverable.attr);
+ if (ret)
+ goto done;
+
ret = sysfs_create_file(&device->snapshot_kobj,
&attr_snapshot_crashdumper.attr);
if (ret)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 85df514..868be8b 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -4396,8 +4396,12 @@
smmu->arch_ops = data->arch_ops;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- smmu->phys_addr = res->start;
+ if (res == NULL) {
+ dev_err(dev, "no MEM resource info\n");
+ return -EINVAL;
+ }
+
+ smmu->phys_addr = res->start;
smmu->base = devm_ioremap_resource(dev, res);
if (IS_ERR(smmu->base))
return PTR_ERR(smmu->base);
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index f3f9a1a..abb695d 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -171,6 +171,7 @@
};
enum flash_led_type {
+ FLASH_LED_TYPE_UNKNOWN,
FLASH_LED_TYPE_FLASH,
FLASH_LED_TYPE_TORCH,
};
@@ -204,13 +205,13 @@
int prev_current_ma;
u8 duration;
u8 id;
- u8 type;
u8 ires_idx;
u8 default_ires_idx;
u8 hdrm_val;
u8 current_reg_val;
u8 strobe_ctrl;
u8 strobe_sel;
+ enum flash_led_type type;
bool led_on;
};
@@ -225,6 +226,7 @@
int led_mask;
bool regulator_on;
bool enabled;
+ bool symmetry_en;
};
/*
@@ -1091,6 +1093,71 @@
return 0;
}
+static int qpnp_flash_led_symmetry_config(struct flash_switch_data *snode)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+ int i, total_curr_ma = 0, num_leds = 0, prgm_current_ma;
+ enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (snode->led_mask & BIT(led->fnode[i].id)) {
+ if (led->fnode[i].type == FLASH_LED_TYPE_FLASH &&
+ led->fnode[i].led_on)
+ type = FLASH_LED_TYPE_FLASH;
+
+ if (led->fnode[i].type == FLASH_LED_TYPE_TORCH &&
+ led->fnode[i].led_on)
+ type = FLASH_LED_TYPE_TORCH;
+ }
+ }
+
+ if (type == FLASH_LED_TYPE_UNKNOWN) {
+ pr_err("Incorrect type possibly because of no active LEDs\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if ((snode->led_mask & BIT(led->fnode[i].id)) &&
+ (led->fnode[i].type == type)) {
+ total_curr_ma += led->fnode[i].current_ma;
+ num_leds++;
+ }
+ }
+
+ if (num_leds > 0 && total_curr_ma > 0) {
+ prgm_current_ma = total_curr_ma / num_leds;
+ } else {
+ pr_err("Incorrect configuration, num_leds: %d total_curr_ma: %d\n",
+ num_leds, total_curr_ma);
+ return -EINVAL;
+ }
+
+ if (prgm_current_ma == 0) {
+ pr_warn("prgm_curr_ma cannot be 0\n");
+ return 0;
+ }
+
+ pr_debug("num_leds: %d total: %d prgm_curr_ma: %d\n", num_leds,
+ total_curr_ma, prgm_current_ma);
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (snode->led_mask & BIT(led->fnode[i].id) &&
+ led->fnode[i].current_ma != prgm_current_ma &&
+ led->fnode[i].type == type) {
+ qpnp_flash_led_node_set(&led->fnode[i],
+ prgm_current_ma);
+ pr_debug("%s LED %d current: %d code: %d ires_ua: %d\n",
+ (type == FLASH_LED_TYPE_FLASH) ?
+ "flash" : "torch",
+ led->fnode[i].id, prgm_current_ma,
+ led->fnode[i].current_reg_val,
+ led->fnode[i].ires_ua);
+ }
+ }
+
+ return 0;
+}
+
static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
{
struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
@@ -1109,6 +1176,15 @@
}
/* Iterate over all active leds for this switch node */
+ if (snode->symmetry_en) {
+ rc = qpnp_flash_led_symmetry_config(snode);
+ if (rc < 0) {
+ pr_err("Failed to configure current symmetrically, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
val = 0;
for (i = 0; i < led->num_fnodes; i++)
if (led->fnode[i].led_on &&
@@ -1707,6 +1783,8 @@
return rc;
}
+ snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
+
if (snode->led_mask < 1 || snode->led_mask > 7) {
pr_err("Invalid value for led-mask\n");
return -EINVAL;
diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c
index fad36ea..764657a 100644
--- a/drivers/leds/leds-qpnp-haptics.c
+++ b/drivers/leds/leds-qpnp-haptics.c
@@ -482,7 +482,8 @@
{
int rc = 0;
u32 delay_us = HAPTICS_BACK_EMF_DELAY_US;
- u8 val, auto_res_mode_qwd;
+ u8 val;
+ bool auto_res_mode_qwd;
if (chip->act_type != HAP_LRA)
return 0;
@@ -496,7 +497,7 @@
/*
* Do not enable auto resonance if auto mode is enabled and auto
- * resonance mode is QWD, meaning short pattern.
+ * resonance mode is QWD, meaning long pattern.
*/
if (chip->lra_auto_mode && auto_res_mode_qwd && enable) {
pr_debug("auto_mode enabled, not enabling auto_res\n");
@@ -1232,7 +1233,7 @@
ares_cfg.lra_qwd_drive_duration = 0;
ares_cfg.calibrate_at_eop = 0;
} else {
- ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
+ ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
ares_cfg.lra_qwd_drive_duration = -EINVAL;
ares_cfg.calibrate_at_eop = -EINVAL;
}
@@ -1242,16 +1243,13 @@
if (rc < 0)
return rc;
- rc = qpnp_haptics_brake_config(chip, brake_pat);
- if (rc < 0)
- return rc;
-
/* enable play_irq for buffer mode */
if (chip->play_irq >= 0 && !chip->play_irq_en) {
enable_irq(chip->play_irq);
chip->play_irq_en = true;
}
+ brake_pat[0] = BRAKE_VMAX;
chip->play_mode = HAP_BUFFER;
chip->wave_shape = HAP_WAVE_SQUARE;
} else {
@@ -1264,7 +1262,7 @@
ares_cfg.lra_qwd_drive_duration = 0;
ares_cfg.calibrate_at_eop = 1;
} else {
- ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
+ ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX;
ares_cfg.lra_qwd_drive_duration = -EINVAL;
ares_cfg.calibrate_at_eop = -EINVAL;
@@ -1275,11 +1273,6 @@
if (rc < 0)
return rc;
- brake_pat[0] = 0x3;
- rc = qpnp_haptics_brake_config(chip, brake_pat);
- if (rc < 0)
- return rc;
-
/* enable play_irq for direct mode */
if (chip->play_irq >= 0 && chip->play_irq_en) {
disable_irq(chip->play_irq);
@@ -1303,6 +1296,10 @@
return rc;
}
+ rc = qpnp_haptics_brake_config(chip, brake_pat);
+ if (rc < 0)
+ return rc;
+
rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip),
HAP_LRA_RES_TYPE_MASK, chip->wave_shape);
if (rc < 0)
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
index df50ca5..82e3b40 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
@@ -22,11 +22,16 @@
#include "venus_boot.h"
#include "soc/qcom/secure_buffer.h"
#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
enum clock_properties {
CLOCK_PROP_HAS_SCALING = 1 << 0,
};
+struct regulator *gdsc_venus;
+struct regulator *gdsc_venus_core0;
+
static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
{
return NULL;
@@ -59,6 +64,118 @@
return 0;
}
+static int venus_regulator_setup(struct msm_vidc_platform_resources *res)
+{
+ const char *reg_name = "venus";
+ const char *reg_name_core0 = "venus-core0";
+ int rc = 0;
+
+ gdsc_venus = devm_regulator_get(&res->pdev->dev, reg_name);
+ if (IS_ERR(gdsc_venus))
+ dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+
+ rc = regulator_enable(gdsc_venus);
+ if (rc)
+ dprintk(VIDC_ERR, "Venus GDSC enable failed\n");
+
+ gdsc_venus_core0 = devm_regulator_get(&res->pdev->dev, reg_name_core0);
+ if (IS_ERR(gdsc_venus_core0))
+ dprintk(VIDC_ERR, "Failed to get Venus-Core0 GDSC\n");
+
+ rc = regulator_enable(gdsc_venus_core0);
+ if (rc)
+ dprintk(VIDC_ERR, "Venus-Core0 GDSC enable failed\n");
+
+ dprintk(VIDC_DBG, "Vensu, Venus-Core0 GDSC's are enabled\n");
+ return rc;
+}
+
+
+static int venus_clock_setup(struct msm_vidc_platform_resources *res,
+ unsigned long rate)
+{
+ int i, rc = 0;
+ struct clock_info *cl;
+ struct clk *clk = NULL;
+
+ dprintk(VIDC_DBG, " %s In\n", __func__);
+ for (i = 0; i < res->clock_set.count; i++) {
+ cl = &res->clock_set.clock_tbl[i];
+ if (!cl->has_scaling)
+ continue;
+
+ clk = clk_get(&res->pdev->dev, cl->name);
+ rc = clk_set_rate(clk, clk_round_rate(clk, rate));
+
+ if (rc)
+ dprintk(VIDC_ERR,
+ "%s: Failed to set clock rate %s: %d\n",
+ __func__, cl->name, rc);
+
+ dprintk(VIDC_DBG, "%s clock set clock rate to %lu\n",
+ cl->name, rate);
+ }
+
+ dprintk(VIDC_DBG, " %s exit\n", __func__);
+ return rc;
+}
+
+static int venus_clock_prepare_enable(struct msm_vidc_platform_resources *res)
+{
+ int i, rc = 0;
+ struct clock_info *cl;
+ struct clk *clk = NULL;
+
+ dprintk(VIDC_DBG, " %s In\n", __func__);
+ for (i = 0; i < res->clock_set.count; i++) {
+ cl = &res->clock_set.clock_tbl[i];
+ clk = clk_get(&res->pdev->dev, cl->name);
+ rc = clk_prepare_enable(clk);
+
+ if (rc) {
+ dprintk(VIDC_ERR, "failed to enable %s clock\n",
+ cl->name);
+ for (i--; i >= 0; i--) {
+ cl = &res->clock_set.clock_tbl[i];
+ clk = clk_get(&res->pdev->dev, cl->name);
+ clk_disable_unprepare(clk);
+ dprintk(VIDC_ERR, "clock %s unprepared\n",
+ cl->name);
+ }
+ return rc;
+ }
+ dprintk(VIDC_DBG, " Clock : %s enabled\n", cl->name);
+ }
+
+ dprintk(VIDC_DBG, " %s exit\n", __func__);
+ return rc;
+}
+
+static void venus_clk_disable_unprepare(struct msm_vidc_platform_resources *res)
+{
+ int i;
+ struct clock_info *cl;
+ struct clk *clk = NULL;
+
+ for (i = 0; i < res->clock_set.count; i++) {
+ cl = &res->clock_set.clock_tbl[i];
+ clk = clk_get(&res->pdev->dev, cl->name);
+ dprintk(VIDC_DBG, "clock %s unprepared\n", cl->name);
+ clk_disable_unprepare(clk);
+ }
+
+ if (gdsc_venus) {
+ regulator_disable(gdsc_venus);
+ dprintk(VIDC_DBG, "Venus Regulator disabled\n");
+ gdsc_venus = NULL;
+ }
+ if (gdsc_venus_core0) {
+ regulator_disable(gdsc_venus_core0);
+ dprintk(VIDC_DBG, "Venus-Core0 Regulator disabled\n");
+ gdsc_venus_core0 = NULL;
+ }
+}
+
static inline enum imem_type read_imem_type(struct platform_device *pdev)
{
bool is_compatible(char *compat)
@@ -843,6 +960,8 @@
bus->dev = dev;
dprintk(VIDC_DBG, "Found bus %s [%d->%d] with governor %s\n",
bus->name, bus->master, bus->slave, bus->governor);
+
+ venus_clk_disable_unprepare(res);
err_bus:
return rc;
}
@@ -1232,6 +1351,12 @@
of_property_read_u32(pdev->dev.of_node,
"qcom,max-secure-instances",
&res->max_secure_inst_count);
+
+ venus_regulator_setup(res);
+ venus_clock_setup(res, 0);
+ venus_clock_prepare_enable(res);
+ venus_clock_setup(res, 1);
+
return rc;
err_setup_legacy_cb:
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index eab93cc..a86d9f1 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.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
@@ -2216,13 +2216,24 @@
}
*data->hdcp_ctx = handle;
- /* Cache the client ctx to be used later
- * HDCP driver probe happens earlier than
+
+ /* Cache the client ctx to be used later if
+ * Misc HDCP driver probe happens later than
* SDE driver probe hence caching it to
* be used later.
*/
-
drv_client_handle = handle;
+
+ /* if misc HDCP driver probe happens earlier
+ * than SDE driver probe store the client
+ * handle to be used to sysfs notifications.
+ */
+
+ if (hdcp_drv_mgr && !hdcp_drv_mgr->handle) {
+ if (drv_client_handle)
+ hdcp_drv_mgr->handle = drv_client_handle;
+ }
+
handle->thread = kthread_run(kthread_worker_fn,
&handle->worker, "hdcp_tz_lib");
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b5ad125..232b4ae 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1848,7 +1848,7 @@
return ret;
}
-static int __qseecom_process_blocked_on_listener_legacy(
+static int __qseecom_process_reentrancy_blocked_on_listener(
struct qseecom_command_scm_resp *resp,
struct qseecom_registered_app_list *ptr_app,
struct qseecom_dev_handle *data)
@@ -1857,10 +1857,11 @@
int ret = 0;
struct qseecom_continue_blocked_request_ireq ireq;
struct qseecom_command_scm_resp continue_resp;
- bool found_app = false;
- unsigned long flags;
+ unsigned int session_id;
sigset_t new_sigset;
sigset_t old_sigset;
+ unsigned long flags;
+ bool found_app = false;
if (!resp || !data) {
pr_err("invalid resp or data pointer\n");
@@ -1891,140 +1892,81 @@
}
}
- list_ptr = __qseecom_find_svc(resp->data);
- if (!list_ptr) {
- pr_err("Invalid listener ID\n");
- ret = -ENODATA;
- goto exit;
- }
- pr_debug("lsntr %d in_use = %d\n",
- resp->data, list_ptr->listener_in_use);
- ptr_app->blocked_on_listener_id = resp->data;
-
- /* sleep until listener is available */
- sigfillset(&new_sigset);
- sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
-
do {
- qseecom.app_block_ref_cnt++;
- ptr_app->app_blocked = true;
- mutex_unlock(&app_access_lock);
- wait_event_freezable(
- list_ptr->listener_block_app_wq,
- !list_ptr->listener_in_use);
- mutex_lock(&app_access_lock);
- ptr_app->app_blocked = false;
- qseecom.app_block_ref_cnt--;
- } while (list_ptr->listener_in_use);
-
- sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
- ptr_app->blocked_on_listener_id = 0;
- /* notify the blocked app that listener is available */
- pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n",
- resp->data, data->client.app_id,
- data->client.app_name);
- ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
- ireq.app_or_session_id = data->client.app_id;
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- &ireq, sizeof(ireq),
- &continue_resp, sizeof(continue_resp));
- if (ret) {
- pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n",
- data->client.app_id,
- data->client.app_name, ret);
- goto exit;
- }
- /*
- * After TZ app is unblocked, then continue to next case
- * for incomplete request processing
- */
- resp->result = QSEOS_RESULT_INCOMPLETE;
-exit:
- return ret;
-}
-
-static int __qseecom_process_blocked_on_listener_smcinvoke(
- struct qseecom_command_scm_resp *resp, uint32_t app_id)
-{
- struct qseecom_registered_listener_list *list_ptr;
- int ret = 0;
- struct qseecom_continue_blocked_request_ireq ireq;
- struct qseecom_command_scm_resp continue_resp;
- unsigned int session_id;
- sigset_t new_sigset;
- sigset_t old_sigset;
-
- if (!resp) {
- pr_err("invalid resp pointer\n");
- ret = -EINVAL;
- goto exit;
- }
- session_id = resp->resp_type;
- list_ptr = __qseecom_find_svc(resp->data);
- if (!list_ptr) {
- pr_err("Invalid listener ID\n");
- ret = -ENODATA;
- goto exit;
- }
- pr_debug("lsntr %d in_use = %d\n",
- resp->data, list_ptr->listener_in_use);
-
- /* sleep until listener is available */
- sigfillset(&new_sigset);
- sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
-
- do {
- qseecom.app_block_ref_cnt++;
- mutex_unlock(&app_access_lock);
- wait_event_freezable(
- list_ptr->listener_block_app_wq,
- !list_ptr->listener_in_use);
- mutex_lock(&app_access_lock);
- qseecom.app_block_ref_cnt--;
- } while (list_ptr->listener_in_use);
-
- sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
- /* notify TZ that listener is available */
- pr_warn("Lsntr %d is available, unblock session(%d) in TZ\n",
- resp->data, session_id);
- ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
- ireq.app_or_session_id = session_id;
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- &ireq, sizeof(ireq),
- &continue_resp, sizeof(continue_resp));
- if (ret) {
- /* retry with legacy cmd */
- qseecom.smcinvoke_support = false;
- ireq.app_or_session_id = app_id;
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- &ireq, sizeof(ireq),
- &continue_resp, sizeof(continue_resp));
- qseecom.smcinvoke_support = true;
- if (ret) {
- pr_err("cont block req for app %d or session %d fail\n",
- app_id, session_id);
+ session_id = resp->resp_type;
+ list_ptr = __qseecom_find_svc(resp->data);
+ if (!list_ptr) {
+ pr_err("Invalid listener ID %d\n", resp->data);
+ ret = -ENODATA;
goto exit;
}
+ ptr_app->blocked_on_listener_id = resp->data;
+
+ pr_warn("Lsntr %d in_use %d, block session(%d) app(%d)\n",
+ resp->data, list_ptr->listener_in_use,
+ session_id, data->client.app_id);
+
+ /* sleep until listener is available */
+ sigfillset(&new_sigset);
+ sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+
+ do {
+ qseecom.app_block_ref_cnt++;
+ ptr_app->app_blocked = true;
+ mutex_unlock(&app_access_lock);
+ wait_event_freezable(
+ list_ptr->listener_block_app_wq,
+ !list_ptr->listener_in_use);
+ mutex_lock(&app_access_lock);
+ ptr_app->app_blocked = false;
+ qseecom.app_block_ref_cnt--;
+ } while (list_ptr->listener_in_use);
+
+ sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+
+ ptr_app->blocked_on_listener_id = 0;
+ pr_warn("Lsntr %d is available, unblock session(%d) app(%d)\n",
+ resp->data, session_id, data->client.app_id);
+
+ /* notify TZ that listener is available */
+ ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
+
+ if (qseecom.smcinvoke_support)
+ ireq.app_or_session_id = session_id;
+ else
+ ireq.app_or_session_id = data->client.app_id;
+
+ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+ &ireq, sizeof(ireq),
+ &continue_resp, sizeof(continue_resp));
+ if (ret && qseecom.smcinvoke_support) {
+ /* retry with legacy cmd */
+ qseecom.smcinvoke_support = false;
+ ireq.app_or_session_id = data->client.app_id;
+ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+ &ireq, sizeof(ireq),
+ &continue_resp, sizeof(continue_resp));
+ qseecom.smcinvoke_support = true;
+ if (ret) {
+ pr_err("unblock app %d or session %d fail\n",
+ data->client.app_id, session_id);
+ goto exit;
+ }
+ }
+ resp->result = continue_resp.result;
+ resp->resp_type = continue_resp.resp_type;
+ resp->data = continue_resp.data;
+ pr_debug("unblock resp = %d\n", resp->result);
+ } while (resp->result == QSEOS_RESULT_BLOCKED_ON_LISTENER);
+
+ if (resp->result != QSEOS_RESULT_INCOMPLETE) {
+ pr_err("Unexpected unblock resp %d\n", resp->result);
+ ret = -EINVAL;
}
- resp->result = QSEOS_RESULT_INCOMPLETE;
exit:
return ret;
}
-static int __qseecom_process_reentrancy_blocked_on_listener(
- struct qseecom_command_scm_resp *resp,
- struct qseecom_registered_app_list *ptr_app,
- struct qseecom_dev_handle *data)
-{
- if (!qseecom.smcinvoke_support)
- return __qseecom_process_blocked_on_listener_legacy(
- resp, ptr_app, data);
- else
- return __qseecom_process_blocked_on_listener_smcinvoke(
- resp, data->client.app_id);
-}
static int __qseecom_reentrancy_process_incomplete_cmd(
struct qseecom_dev_handle *data,
struct qseecom_command_scm_resp *resp)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5ed9b72..0abc7a3 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1916,7 +1916,11 @@
err = PTR_ERR(buf);
}
} else {
- val = *buf;
+ /*
+ * 30 bits from bit offset 0 would be read.
+ * We're interested in bits 28:29
+ */
+ val = (*buf >> 28) & 0x3;
kfree(buf);
}
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 75faeb1..bb2270b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -108,20 +108,8 @@
for it's internal usage and release it to back to pre allocated pool.
This memory is allocated at the cold boot time.
-config CLD_LL_CORE
- tristate "QTI core WLAN driver for QCA6174 chipset"
- select NL80211_TESTMODE
- select WEXT_CORE
- select WEXT_PRIV
- select WEXT_SPY
- select WIRELESS_EXT
- ---help---
- This section contains the necessary modules needed to enable the
- core WLAN driver for QTI QCA6174 chipset.
- Select Y to compile the driver in order to have WLAN functionality
- support.
-
source "drivers/net/wireless/cnss2/Kconfig"
+source "drivers/net/wireless/cnss/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 4ffbd10..5c33140 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -27,8 +27,7 @@
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_CNSS2) += cnss2/
-
+obj-$(CONFIG_CNSS) += cnss/
obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
-
obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
obj-$(CONFIG_CNSS_GENL) += cnss_genl/
diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig
new file mode 100644
index 0000000..0b37af6
--- /dev/null
+++ b/drivers/net/wireless/cnss/Kconfig
@@ -0,0 +1,116 @@
+config CNSS
+ tristate "CNSS driver for wifi module"
+ select CNSS_UTILS
+ select CRYPTO
+ select CRYPTO_HASH
+ select CRYPTO_BLKCIPHER
+ ---help---
+ This module adds support for the CNSS connectivity subsystem used
+ for wifi devices based on the QCA AR6320 chipset.
+ This driver also adds support to integrate WLAN module to subsystem
+ restart framework.
+
+config CNSS_SDIO
+ bool "Enable/disable cnss sdio platform driver for wifi module"
+ depends on CNSS
+ depends on MMC
+ ---help---
+ This module adds support for the CNSS wlan module interfaced
+ with SDIO bus.
+ This driver also adds support to integrate WLAN module to subsystem
+ restart framework, power on WLAN chip and registered the WLAN module
+ as a SDIO client device.
+
+config CNSS_PCI
+ bool "Enable/disable cnss pci platform driver for wifi module"
+ depends on CNSS
+ depends on PCI
+ ---help---
+ This module adds support for the CNSS wlan module interfaced
+ with PCIe bus.
+ This driver also adds support to integrate WLAN module to subsystem
+ restart framework, power on WLAN chip and registered the WLAN module
+ as a PCIe client device.
+
+config CNSS_ASYNC
+ bool "Enable/disable cnss pci platform driver asynchronous probe"
+ depends on CNSS_PCI
+ ---help---
+ If enabled, CNSS PCI platform driver would do asynchronous probe.
+ Using asynchronous probe will allow CNSS PCI platform driver to
+ probe in parallel with other device drivers and will help to
+ reduce kernel boot time.
+
+config CNSS_MAC_BUG
+ bool "Enable/disable 0-4K memory initialization for QCA6174"
+ depends on CNSS
+ ---help---
+ If enabled, 0-4K memory is reserved for QCA6174 to address
+ a MAC HW bug. MAC would do an invalid pointer fetch based on
+ the data, that was read from 0 to 4K. So fill it with zero's;
+ to an address for which PCIe root complex would honor the read
+ without any errors.
+
+config CLD_DEBUG
+ bool "Enable/disable CLD debug features"
+ help
+ WLAN CLD driver uses this config to enable certain debug features.
+ Some of the debug features may affect performance or may compromise
+ on security.
+
+ Say N, if you are building a release kernel for production use.
+ Only say Y, if you are building a kernel with debug support.
+
+config CLD_HL_SDIO_CORE
+ tristate "Qualcomm Technologies Inc. Core wlan driver for QCA SDIO interface"
+ select WIRELESS_EXT
+ select WEXT_PRIV
+ select WEXT_CORE
+ select WEXT_SPY
+ select NL80211_TESTMODE
+ depends on ARCH_QCOM
+ depends on MMC
+
+config CLD_LL_CORE
+ tristate "Qualcomm Technologies Inc. Core wlan driver"
+ select NL80211_TESTMODE
+ select WEXT_CORE
+ select WEXT_PRIV
+ select WEXT_SPY
+ select WIRELESS_EXT
+ ---help---
+ This section contains the necessary modules needed to enable the
+ core WLAN driver for Qualcomm Technologies Inc QCA6174 chipset.
+ Select Y to compile the driver in order to have WLAN functionality
+ support.
+
+config CNSS_SECURE_FW
+ bool "Enable/Disable Memory Allocation for Secure Firmware Feature"
+ depends on CNSS
+ ---help---
+ CLD Driver can use this for holding local copy of firmware
+ binaries which is used for sha crypto computation.
+ The Memory Allocation is done only if this Config Parameter is
+ enabled
+
+config BUS_AUTO_SUSPEND
+ bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers"
+ depends on CNSS
+ 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.
+
+source "drivers/net/wireless/cnss/logger/Kconfig"
+
+config WLAN_FEATURE_RX_WAKELOCK
+ bool "Enable RX wake lock feature"
+ help
+ Enable WLAN_FEATURE_HOLD_RX_WAKELOCK which is required to take rx
+ wakelock when driver receives packets from fw.
diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile
new file mode 100644
index 0000000..38ad562
--- /dev/null
+++ b/drivers/net/wireless/cnss/Makefile
@@ -0,0 +1,6 @@
+# Makefile for CNSS platform driver
+
+obj-$(CONFIG_CNSS_PCI) += cnss_pci.o
+obj-$(CONFIG_CNSS_SDIO) += cnss_sdio.o
+obj-$(CONFIG_CNSS) += cnss_common.o
+obj-$(CONFIG_CNSS_LOGGER) += logger/
diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c
new file mode 100644
index 0000000..a1731b0
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.c
@@ -0,0 +1,450 @@
+/* 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
+ * 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/export.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <net/cfg80211.h>
+
+#define AR6320_REV1_VERSION 0x5000000
+#define AR6320_REV1_1_VERSION 0x5000001
+#define AR6320_REV1_3_VERSION 0x5000003
+#define AR6320_REV2_1_VERSION 0x5010000
+#define AR6320_REV3_VERSION 0x5020000
+#define AR6320_REV3_2_VERSION 0x5030000
+#define AR900B_DEV_VERSION 0x1000000
+#define QCA9377_REV1_1_VERSION 0x5020001
+
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_1 = {
+ "qwlan11.bin", "bdwlan11.bin", "otp11.bin", "utf11.bin",
+ "utfbd11.bin", "epping11.bin", "evicted11.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_2_0 = {
+ "qwlan20.bin", "bdwlan20.bin", "otp20.bin", "utf20.bin",
+ "utfbd20.bin", "epping20.bin", "evicted20.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_3 = {
+ "qwlan13.bin", "bdwlan13.bin", "otp13.bin", "utf13.bin",
+ "utfbd13.bin", "epping13.bin", "evicted13.bin"};
+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"};
+
+enum cnss_dev_bus_type {
+ CNSS_BUS_NONE = -1,
+ CNSS_BUS_PCI,
+ CNSS_BUS_SDIO
+};
+
+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;
+
+static enum cnss_cc_src cnss_cc_source = CNSS_SOURCE_CORE;
+
+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);
+
+void cnss_init_work(struct work_struct *work, work_func_t func)
+{
+ INIT_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_work);
+
+void cnss_flush_work(void *work)
+{
+ struct work_struct *cnss_work = work;
+
+ cancel_work_sync(cnss_work);
+}
+EXPORT_SYMBOL(cnss_flush_work);
+
+void cnss_flush_delayed_work(void *dwork)
+{
+ struct delayed_work *cnss_dwork = dwork;
+
+ cancel_delayed_work_sync(cnss_dwork);
+}
+EXPORT_SYMBOL(cnss_flush_delayed_work);
+
+void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name)
+{
+ wakeup_source_init(ws, name);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_init);
+
+void cnss_pm_wake_lock(struct wakeup_source *ws)
+{
+ __pm_stay_awake(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock);
+
+void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec)
+{
+ __pm_wakeup_event(ws, msec);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_timeout);
+
+void cnss_pm_wake_lock_release(struct wakeup_source *ws)
+{
+ __pm_relax(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_release);
+
+void cnss_pm_wake_lock_destroy(struct wakeup_source *ws)
+{
+ wakeup_source_trash(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_destroy);
+
+void cnss_get_monotonic_boottime(struct timespec *ts)
+{
+ get_monotonic_boottime(ts);
+}
+EXPORT_SYMBOL(cnss_get_monotonic_boottime);
+
+void cnss_get_boottime(struct timespec *ts)
+{
+ ktime_get_ts(ts);
+}
+EXPORT_SYMBOL(cnss_get_boottime);
+
+void cnss_init_delayed_work(struct delayed_work *work, work_func_t func)
+{
+ INIT_DELAYED_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_delayed_work);
+
+int cnss_vendor_cmd_reply(struct sk_buff *skb)
+{
+ return cfg80211_vendor_cmd_reply(skb);
+}
+EXPORT_SYMBOL(cnss_vendor_cmd_reply);
+
+int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu)
+{
+ return set_cpus_allowed_ptr(task, cpumask_of(cpu));
+}
+EXPORT_SYMBOL(cnss_set_cpus_allowed_ptr);
+
+/* wlan prop driver cannot invoke show_stack
+ * function directly, so to invoke this function it
+ * call wcnss_dump_stack function
+ */
+void cnss_dump_stack(struct task_struct *task)
+{
+ show_stack(task, NULL);
+}
+EXPORT_SYMBOL(cnss_dump_stack);
+
+struct cnss_dev_platform_ops *cnss_get_platform_ops(struct device *dev)
+{
+ if (!dev)
+ return NULL;
+ else
+ return dev->platform_data;
+}
+
+int cnss_common_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->request_bus_bandwidth)
+ return pf_ops->request_bus_bandwidth(bandwidth);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_request_bus_bandwidth);
+
+void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->get_virt_ramdump_mem)
+ return pf_ops->get_virt_ramdump_mem(size);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_virt_ramdump_mem);
+
+void cnss_common_device_self_recovery(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->device_self_recovery)
+ pf_ops->device_self_recovery();
+}
+EXPORT_SYMBOL(cnss_common_device_self_recovery);
+
+void cnss_common_schedule_recovery_work(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->schedule_recovery_work)
+ pf_ops->schedule_recovery_work();
+}
+EXPORT_SYMBOL(cnss_common_schedule_recovery_work);
+
+void cnss_common_device_crashed(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->device_crashed)
+ pf_ops->device_crashed();
+}
+EXPORT_SYMBOL(cnss_common_device_crashed);
+
+u8 *cnss_common_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->get_wlan_mac_address)
+ return pf_ops->get_wlan_mac_address(num);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_wlan_mac_address);
+
+int cnss_common_set_wlan_mac_address(
+ struct device *dev, const u8 *in, u32 len)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->set_wlan_mac_address)
+ return pf_ops->set_wlan_mac_address(in, len);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_set_wlan_mac_address);
+
+int cnss_power_up(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->power_up)
+ return pf_ops->power_up(dev);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_up);
+
+int cnss_power_down(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->power_down)
+ return pf_ops->power_down(dev);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_down);
+
+void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+ u32 size, u32 tufello_dual_fw)
+{
+ if (tufello_dual_fw)
+ memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+ else
+ memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+}
+EXPORT_SYMBOL(cnss_get_qca9377_fw_files);
+
+int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+ u32 target_type, u32 target_version)
+{
+ if (!pfw_files)
+ return -ENODEV;
+
+ switch (target_version) {
+ case AR6320_REV1_VERSION:
+ case AR6320_REV1_1_VERSION:
+ memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_1, sizeof(*pfw_files));
+ break;
+ case AR6320_REV1_3_VERSION:
+ memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_3, sizeof(*pfw_files));
+ break;
+ case AR6320_REV2_1_VERSION:
+ memcpy(pfw_files, &FW_FILES_QCA6174_FW_2_0, sizeof(*pfw_files));
+ break;
+ case AR6320_REV3_VERSION:
+ case AR6320_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));
+ pr_err("%s default version 0x%X 0x%X", __func__,
+ target_type, target_version);
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files_for_target);
+
+void cnss_set_cc_source(enum cnss_cc_src cc_source)
+{
+ cnss_cc_source = cc_source;
+}
+EXPORT_SYMBOL(cnss_set_cc_source);
+
+enum cnss_cc_src cnss_get_cc_source(void)
+{
+ return cnss_cc_source;
+}
+EXPORT_SYMBOL(cnss_get_cc_source);
+
+const char *cnss_wlan_get_evicted_data_file(void)
+{
+ return FW_FILES_QCA6174_FW_3_0.evicted_data;
+}
+
+int cnss_common_register_tsf_captured_handler(struct device *dev,
+ irq_handler_t handler, void *ctx)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->register_tsf_captured_handler)
+ return pf_ops->register_tsf_captured_handler(handler, ctx);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_register_tsf_captured_handler);
+
+int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+ void *ctx)
+{
+ struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+ if (pf_ops && pf_ops->unregister_tsf_captured_handler)
+ return pf_ops->unregister_tsf_captured_handler(ctx);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_unregister_tsf_captured_handler);
diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h
new file mode 100644
index 0000000..7013aba
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.h
@@ -0,0 +1,65 @@
+/* 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.
+ */
+
+#ifndef _NET_CNSS_COMMON_H_
+#define _NET_CNSS_COMMON_H_
+
+/* max 20mhz channel count */
+#define CNSS_MAX_CH_NUM 45
+
+struct cnss_cap_tsf_info {
+ int irq_num;
+ void *context;
+ irq_handler_t irq_handler;
+};
+
+struct cnss_dev_platform_ops {
+ int (*request_bus_bandwidth)(int bandwidth);
+ void* (*get_virt_ramdump_mem)(unsigned long *size);
+ void (*device_self_recovery)(void);
+ void (*schedule_recovery_work)(void);
+ void (*device_crashed)(void);
+ u8 * (*get_wlan_mac_address)(u32 *num);
+ int (*set_wlan_mac_address)(const u8 *in, u32 len);
+ int (*power_up)(struct device *dev);
+ int (*power_down)(struct device *dev);
+ int (*register_tsf_captured_handler)(irq_handler_t handler,
+ void *adapter);
+ int (*unregister_tsf_captured_handler)(void *adapter);
+};
+
+int cnss_pci_request_bus_bandwidth(int bandwidth);
+int cnss_sdio_request_bus_bandwidth(int bandwidth);
+
+void cnss_sdio_device_crashed(void);
+void cnss_pci_device_crashed(void);
+
+void cnss_pci_device_self_recovery(void);
+void cnss_sdio_device_self_recovery(void);
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size);
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size);
+
+void cnss_sdio_schedule_recovery_work(void);
+void cnss_pci_schedule_recovery_work(void);
+
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len);
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len);
+
+u8 *cnss_pci_get_wlan_mac_address(u32 *num);
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num);
+int cnss_sdio_power_up(struct device *dev);
+int cnss_sdio_power_down(struct device *dev);
+int cnss_pcie_power_up(struct device *dev);
+int cnss_pcie_power_down(struct device *dev);
+const char *cnss_wlan_get_evicted_data_file(void);
+#endif /* _NET_CNSS_COMMON_H_ */
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
new file mode 100644
index 0000000..8797e68
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -0,0 +1,3835 @@
+/* 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
+ * 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 <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/pm_qos.h>
+#include <linux/pm_runtime.h>
+#include <linux/esoc_client.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/log2.h>
+#include <linux/etherdevice.h>
+#include <linux/msm_pcie.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <net/cfg80211.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include <net/cnss_prealloc.h>
+#endif
+
+#define subsys_to_drv(d) container_of(d, struct cnss_data, subsys_desc)
+
+#define VREG_ON 1
+#define VREG_OFF 0
+#define WLAN_EN_HIGH 1
+#define WLAN_EN_LOW 0
+#define PCIE_LINK_UP 1
+#define PCIE_LINK_DOWN 0
+#define WLAN_BOOTSTRAP_HIGH 1
+#define WLAN_BOOTSTRAP_LOW 0
+#define CNSS_DUMP_FORMAT_VER 0x11
+#define CNSS_DUMP_MAGIC_VER_V2 0x42445953
+#define CNSS_DUMP_NAME "CNSS_WLAN"
+
+#define QCA6174_VENDOR_ID (0x168C)
+#define QCA6174_DEVICE_ID (0x003E)
+#define BEELINER_DEVICE_ID (0x0040)
+#define QCA6174_REV_ID_OFFSET (0x08)
+#define QCA6174_FW_1_1 (0x11)
+#define QCA6174_FW_1_3 (0x13)
+#define QCA6174_FW_2_0 (0x20)
+#define QCA6174_FW_3_0 (0x30)
+#define QCA6174_FW_3_2 (0x32)
+#define BEELINER_FW (0x00)
+
+#define QCA6180_VENDOR_ID (0x168C)
+#define QCA6180_DEVICE_ID (0x0041)
+#define QCA6180_REV_ID_OFFSET (0x08)
+
+#define WLAN_EN_VREG_NAME "vdd-wlan-en"
+#define WLAN_VREG_NAME "vdd-wlan"
+#define WLAN_VREG_IO_NAME "vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME "vdd-wlan-xtal"
+#define WLAN_VREG_XTAL_AON_NAME "vdd-wlan-xtal-aon"
+#define WLAN_VREG_CORE_NAME "vdd-wlan-core"
+#define WLAN_VREG_SP2T_NAME "vdd-wlan-sp2t"
+#define WLAN_SWREG_NAME "wlan-soc-swreg"
+#define WLAN_ANT_SWITCH_NAME "wlan-ant-switch"
+#define WLAN_EN_GPIO_NAME "wlan-en-gpio"
+#define WLAN_BOOTSTRAP_GPIO_NAME "wlan-bootstrap-gpio"
+#define PM_OPTIONS 0
+#define PM_OPTIONS_SUSPEND_LINK_DOWN \
+ (MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN)
+#define PM_OPTIONS_RESUME_LINK_DOWN \
+ (MSM_PCIE_CONFIG_NO_CFG_RESTORE)
+
+#define SOC_SWREG_VOLT_MAX 1200000
+#define SOC_SWREG_VOLT_MIN 1200000
+#define WLAN_ANT_SWITCH_VOLT_MAX 2700000
+#define WLAN_ANT_SWITCH_VOLT_MIN 2700000
+#define WLAN_ANT_SWITCH_CURR 20000
+#define WLAN_VREG_IO_MAX 1800000
+#define WLAN_VREG_IO_MIN 1800000
+#define WLAN_VREG_XTAL_MAX 1800000
+#define WLAN_VREG_XTAL_MIN 1800000
+#define WLAN_VREG_CORE_MAX 1300000
+#define WLAN_VREG_CORE_MIN 1300000
+#define WLAN_VREG_SP2T_MAX 2700000
+#define WLAN_VREG_SP2T_MIN 2700000
+
+#define POWER_ON_DELAY 2
+#define WLAN_VREG_IO_DELAY_MIN 100
+#define WLAN_VREG_IO_DELAY_MAX 1000
+#define WLAN_ENABLE_DELAY 10
+#define PCIE_SWITCH_DELAY 20
+#define WLAN_RECOVERY_DELAY 1
+#define PCIE_ENABLE_DELAY 100
+#define WLAN_BOOTSTRAP_DELAY 10
+#define EVICT_BIN_MAX_SIZE (512 * 1024)
+
+static DEFINE_SPINLOCK(pci_link_down_lock);
+
+#define FW_NAME_FIXED_LEN (6)
+#define MAX_NUM_OF_SEGMENTS (16)
+#define MAX_INDEX_FILE_SIZE (512)
+#define FW_FILENAME_LENGTH (13)
+#define TYPE_LENGTH (4)
+#define PER_FILE_DATA (21)
+#define MAX_IMAGE_SIZE (2 * 1024 * 1024)
+#define FW_IMAGE_FTM (0x01)
+#define FW_IMAGE_MISSION (0x02)
+#define FW_IMAGE_BDATA (0x03)
+#define FW_IMAGE_PRINT (0x04)
+
+#define SEG_METADATA (0x01)
+#define SEG_NON_PAGED (0x02)
+#define SEG_LOCKED_PAGE (0x03)
+#define SEG_UNLOCKED_PAGE (0x04)
+#define SEG_NON_SECURE_DATA (0x05)
+
+#define BMI_TEST_SETUP (0x09)
+
+struct cnss_wlan_gpio_info {
+ char *name;
+ u32 num;
+ bool state;
+ bool init;
+ bool prop;
+};
+
+struct cnss_wlan_vreg_info {
+ struct regulator *wlan_en_reg;
+ struct regulator *wlan_reg;
+ struct regulator *soc_swreg;
+ struct regulator *ant_switch;
+ struct regulator *wlan_reg_io;
+ struct regulator *wlan_reg_xtal;
+ struct regulator *wlan_reg_xtal_aon;
+ struct regulator *wlan_reg_core;
+ struct regulator *wlan_reg_sp2t;
+ bool state;
+};
+
+struct segment_memory {
+ dma_addr_t dma_region;
+ void *cpu_region;
+ u32 size;
+};
+
+/* FW image descriptor lists */
+struct image_desc_hdr {
+ u8 image_id;
+ u8 reserved[3];
+ u32 segments_cnt;
+};
+
+struct segment_desc {
+ u8 segment_id;
+ u8 segment_idx;
+ u8 flags[2];
+ u32 addr_count;
+ u32 addr_low;
+ u32 addr_high;
+};
+
+struct region_desc {
+ u32 addr_low;
+ u32 addr_high;
+ u32 size;
+ u32 reserved;
+};
+
+struct index_file {
+ u32 type;
+ u32 segment_idx;
+ u8 file_name[13];
+};
+
+struct cnss_dual_wifi {
+ bool is_dual_wifi_enabled;
+};
+
+/**
+ * struct wlan_mac_addr - Structure to hold WLAN MAC Address
+ * @mac_addr: MAC address
+ */
+#define MAX_NO_OF_MAC_ADDR 4
+struct cnss_wlan_mac_addr {
+ u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
+ u32 no_of_mac_addr_set;
+};
+
+/* device_info is expected to be fully populated after cnss_config is invoked.
+ * The function pointer callbacks are expected to be non null as well.
+ */
+static struct cnss_data {
+ struct platform_device *pldev;
+ struct subsys_device *subsys;
+ struct subsys_desc subsysdesc;
+ struct cnss_wlan_mac_addr wlan_mac_addr;
+ bool is_wlan_mac_set;
+ bool ramdump_dynamic;
+ struct ramdump_device *ramdump_dev;
+ unsigned long ramdump_size;
+ void *ramdump_addr;
+ phys_addr_t ramdump_phys;
+ struct msm_dump_data dump_data;
+ struct cnss_wlan_driver *driver;
+ struct pci_dev *pdev;
+ const struct pci_device_id *id;
+ struct dma_iommu_mapping *smmu_mapping;
+ dma_addr_t smmu_iova_start;
+ size_t smmu_iova_len;
+ struct cnss_wlan_vreg_info vreg_info;
+ bool wlan_en_vreg_support;
+ struct cnss_wlan_gpio_info gpio_info;
+ bool pcie_link_state;
+ bool pcie_link_down_ind;
+ bool pci_register_again;
+ bool notify_modem_status;
+ struct pci_saved_state *saved_state;
+ u16 revision_id;
+ bool recovery_in_progress;
+ atomic_t fw_available;
+ struct codeswap_codeseg_info *cnss_seg_info;
+ /* Virtual Address of the DMA page */
+ void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS];
+ struct cnss_fw_files fw_files;
+ struct pm_qos_request qos_request;
+ void *modem_notify_handler;
+ int modem_current_status;
+ struct msm_bus_scale_pdata *bus_scale_table;
+ u32 bus_client;
+ int current_bandwidth_vote;
+ void *subsys_handle;
+ struct esoc_desc *esoc_desc;
+ struct cnss_platform_cap cap;
+ struct msm_pcie_register_event event_reg;
+ struct wakeup_source ws;
+ u32 recovery_count;
+ enum cnss_driver_status driver_status;
+#ifdef CONFIG_CNSS_SECURE_FW
+ void *fw_mem;
+#endif
+ u32 device_id;
+ int fw_image_setup;
+ u32 bmi_test;
+ void *fw_cpu;
+ dma_addr_t fw_dma;
+ u32 fw_dma_size;
+ u32 fw_seg_count;
+ struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS];
+ /* Firmware setup complete lock */
+ struct mutex fw_setup_stat_lock;
+ void *bdata_cpu;
+ dma_addr_t bdata_dma;
+ u32 bdata_dma_size;
+ u32 bdata_seg_count;
+ struct segment_memory bdata_seg_mem[MAX_NUM_OF_SEGMENTS];
+ int wlan_bootstrap_gpio;
+ atomic_t auto_suspended;
+ bool monitor_wake_intr;
+ struct cnss_dual_wifi dual_wifi_info;
+ struct cnss_dev_platform_ops platform_ops;
+} *penv;
+
+static unsigned int pcie_link_down_panic;
+module_param(pcie_link_down_panic, uint, 0600);
+MODULE_PARM_DESC(pcie_link_down_panic,
+ "Trigger kernel panic when PCIe link down is detected");
+
+static void cnss_put_wlan_enable_gpio(void)
+{
+ struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+ struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+ if (penv->wlan_en_vreg_support)
+ regulator_put(vreg_info->wlan_en_reg);
+ else
+ gpio_free(gpio_info->num);
+}
+
+static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info)
+{
+ int ret;
+
+ if (vreg_info->wlan_reg_core) {
+ ret = regulator_enable(vreg_info->wlan_reg_core);
+ if (ret) {
+ pr_err("%s: regulator enable failed for wlan_reg_core\n",
+ __func__);
+ goto error_enable_reg_core;
+ }
+ }
+
+ if (vreg_info->wlan_reg_io) {
+ ret = regulator_enable(vreg_info->wlan_reg_io);
+ if (ret) {
+ pr_err("%s: regulator enable failed for wlan_reg_io\n",
+ __func__);
+ goto error_enable_reg_io;
+ }
+
+ usleep_range(WLAN_VREG_IO_DELAY_MIN, WLAN_VREG_IO_DELAY_MAX);
+ }
+
+ if (vreg_info->wlan_reg_xtal_aon) {
+ ret = regulator_enable(vreg_info->wlan_reg_xtal_aon);
+ if (ret) {
+ pr_err("%s: wlan_reg_xtal_aon enable failed\n",
+ __func__);
+ goto error_enable_reg_xtal_aon;
+ }
+ }
+
+ if (vreg_info->wlan_reg_xtal) {
+ ret = regulator_enable(vreg_info->wlan_reg_xtal);
+ if (ret) {
+ pr_err("%s: regulator enable failed for wlan_reg_xtal\n",
+ __func__);
+ goto error_enable_reg_xtal;
+ }
+ }
+
+ ret = regulator_enable(vreg_info->wlan_reg);
+ if (ret) {
+ pr_err("%s: regulator enable failed for WLAN power\n",
+ __func__);
+ goto error_enable;
+ }
+
+ if (vreg_info->wlan_reg_sp2t) {
+ ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+ if (ret) {
+ pr_err("%s: regulator enable failed for wlan_reg_sp2t\n",
+ __func__);
+ goto error_enable_reg_sp2t;
+ }
+ }
+
+ if (vreg_info->ant_switch) {
+ ret = regulator_enable(vreg_info->ant_switch);
+ if (ret) {
+ pr_err("%s: regulator enable failed for ant_switch\n",
+ __func__);
+ goto error_enable_ant_switch;
+ }
+ }
+
+ if (vreg_info->soc_swreg) {
+ ret = regulator_enable(vreg_info->soc_swreg);
+ if (ret) {
+ pr_err("%s: regulator enable failed for external soc-swreg\n",
+ __func__);
+ goto error_enable_soc_swreg;
+ }
+ }
+
+ return ret;
+
+error_enable_soc_swreg:
+ if (vreg_info->ant_switch)
+ regulator_disable(vreg_info->ant_switch);
+error_enable_ant_switch:
+ if (vreg_info->wlan_reg_sp2t)
+ regulator_disable(vreg_info->wlan_reg_sp2t);
+error_enable_reg_sp2t:
+ regulator_disable(vreg_info->wlan_reg);
+error_enable:
+ if (vreg_info->wlan_reg_xtal)
+ regulator_disable(vreg_info->wlan_reg_xtal);
+error_enable_reg_xtal:
+ if (vreg_info->wlan_reg_xtal_aon)
+ regulator_disable(vreg_info->wlan_reg_xtal_aon);
+error_enable_reg_xtal_aon:
+ if (vreg_info->wlan_reg_io)
+ regulator_disable(vreg_info->wlan_reg_io);
+error_enable_reg_io:
+ if (vreg_info->wlan_reg_core)
+ regulator_disable(vreg_info->wlan_reg_core);
+error_enable_reg_core:
+ return ret;
+}
+
+static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info)
+{
+ int ret;
+
+ if (vreg_info->soc_swreg) {
+ ret = regulator_disable(vreg_info->soc_swreg);
+ if (ret) {
+ pr_err("%s: regulator disable failed for external soc-swreg\n",
+ __func__);
+ goto error_disable;
+ }
+ }
+
+ if (vreg_info->ant_switch) {
+ ret = regulator_disable(vreg_info->ant_switch);
+ if (ret) {
+ pr_err("%s: regulator disable failed for ant_switch\n",
+ __func__);
+ goto error_disable;
+ }
+ }
+
+ if (vreg_info->wlan_reg_sp2t) {
+ ret = regulator_disable(vreg_info->wlan_reg_sp2t);
+ if (ret) {
+ pr_err("%s: regulator disable failed for wlan_reg_sp2t\n",
+ __func__);
+ goto error_disable;
+ }
+ }
+
+ ret = regulator_disable(vreg_info->wlan_reg);
+ if (ret) {
+ pr_err("%s: regulator disable failed for WLAN power\n",
+ __func__);
+ goto error_disable;
+ }
+
+ if (vreg_info->wlan_reg_xtal) {
+ ret = regulator_disable(vreg_info->wlan_reg_xtal);
+ if (ret) {
+ pr_err("%s: regulator disable failed for wlan_reg_xtal\n",
+ __func__);
+ goto error_disable;
+ }
+ }
+
+ if (vreg_info->wlan_reg_xtal_aon) {
+ ret = regulator_disable(vreg_info->wlan_reg_xtal_aon);
+ if (ret) {
+ pr_err("%s: wlan_reg_xtal_aon disable failed\n",
+ __func__);
+ goto error_disable;
+ }
+ }
+
+ if (vreg_info->wlan_reg_io) {
+ ret = regulator_disable(vreg_info->wlan_reg_io);
+ if (ret) {
+ pr_err("%s: regulator disable failed for wlan_reg_io\n",
+ __func__);
+ goto error_disable;
+ }
+ }
+
+ if (vreg_info->wlan_reg_core) {
+ ret = regulator_disable(vreg_info->wlan_reg_core);
+ if (ret) {
+ pr_err("%s: regulator disable failed for wlan_reg_core\n",
+ __func__);
+ goto error_disable;
+ }
+ }
+
+error_disable:
+ return ret;
+}
+
+static int cnss_wlan_vreg_set(struct cnss_wlan_vreg_info *vreg_info, bool state)
+{
+ int ret = 0;
+
+ if (vreg_info->state == state) {
+ pr_debug("Already wlan vreg state is %s\n",
+ state ? "enabled" : "disabled");
+ goto out;
+ }
+
+ if (state)
+ ret = cnss_wlan_vreg_on(vreg_info);
+ else
+ ret = cnss_wlan_vreg_off(vreg_info);
+
+ if (ret)
+ goto out;
+
+ pr_debug("%s: wlan vreg is now %s\n", __func__,
+ state ? "enabled" : "disabled");
+ vreg_info->state = state;
+
+out:
+ return ret;
+}
+
+static int cnss_wlan_gpio_init(struct cnss_wlan_gpio_info *info)
+{
+ int ret = 0;
+
+ ret = gpio_request(info->num, info->name);
+
+ if (ret) {
+ pr_err("can't get gpio %s ret %d\n", info->name, ret);
+ goto err_gpio_req;
+ }
+
+ ret = gpio_direction_output(info->num, info->init);
+
+ if (ret) {
+ pr_err("can't set gpio direction %s ret %d\n", info->name, ret);
+ goto err_gpio_dir;
+ }
+ info->state = info->init;
+
+ return ret;
+
+err_gpio_dir:
+ gpio_free(info->num);
+
+err_gpio_req:
+
+ return ret;
+}
+
+static int cnss_wlan_bootstrap_gpio_init(void)
+{
+ int ret = 0;
+
+ ret = gpio_request(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_GPIO_NAME);
+ if (ret) {
+ pr_err("%s: Can't get GPIO %s, ret = %d\n",
+ __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+ goto out;
+ }
+
+ ret = gpio_direction_output(penv->wlan_bootstrap_gpio,
+ WLAN_BOOTSTRAP_HIGH);
+ if (ret) {
+ pr_err("%s: Can't set GPIO %s direction, ret = %d\n",
+ __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+ gpio_free(penv->wlan_bootstrap_gpio);
+ goto out;
+ }
+
+ msleep(WLAN_BOOTSTRAP_DELAY);
+out:
+ return ret;
+}
+
+static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state)
+{
+ if (!info->prop)
+ return;
+
+ if (info->state == state) {
+ pr_debug("Already %s gpio is %s\n",
+ info->name, state ? "high" : "low");
+ return;
+ }
+
+ gpio_set_value(info->num, state);
+ info->state = state;
+
+ pr_debug("%s: %s gpio is now %s\n", __func__,
+ info->name, info->state ? "enabled" : "disabled");
+}
+
+static int cnss_configure_wlan_en_gpio(bool state)
+{
+ int ret = 0;
+ struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+ struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+ if (penv->wlan_en_vreg_support) {
+ if (state)
+ ret = regulator_enable(vreg_info->wlan_en_reg);
+ else
+ ret = regulator_disable(vreg_info->wlan_en_reg);
+ } else {
+ cnss_wlan_gpio_set(gpio_info, state);
+ }
+
+ msleep(WLAN_ENABLE_DELAY);
+ return ret;
+}
+
+static void cnss_disable_xtal_ldo(struct platform_device *pdev)
+{
+ struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+ if (info->wlan_reg_xtal) {
+ regulator_disable(info->wlan_reg_xtal);
+ regulator_put(info->wlan_reg_xtal);
+ }
+
+ if (info->wlan_reg_xtal_aon) {
+ regulator_disable(info->wlan_reg_xtal_aon);
+ regulator_put(info->wlan_reg_xtal_aon);
+ }
+}
+
+static int cnss_enable_xtal_ldo(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+ if (!of_get_property(pdev->dev.of_node,
+ WLAN_VREG_XTAL_AON_NAME "-supply", NULL))
+ goto enable_xtal;
+
+ info->wlan_reg_xtal_aon = regulator_get(&pdev->dev,
+ WLAN_VREG_XTAL_AON_NAME);
+ if (IS_ERR(info->wlan_reg_xtal_aon)) {
+ ret = PTR_ERR(info->wlan_reg_xtal_aon);
+ pr_err("%s: XTAL AON Regulator get failed err:%d\n", __func__,
+ ret);
+ return ret;
+ }
+
+ ret = regulator_enable(info->wlan_reg_xtal_aon);
+ if (ret) {
+ pr_err("%s: VREG_XTAL_ON enable failed\n", __func__);
+ goto end;
+ }
+
+enable_xtal:
+
+ if (!of_get_property(pdev->dev.of_node,
+ WLAN_VREG_XTAL_NAME "-supply", NULL))
+ goto out_disable_xtal_aon;
+
+ info->wlan_reg_xtal = regulator_get(&pdev->dev, WLAN_VREG_XTAL_NAME);
+
+ if (IS_ERR(info->wlan_reg_xtal)) {
+ ret = PTR_ERR(info->wlan_reg_xtal);
+ pr_err("%s XTAL Regulator get failed err:%d\n", __func__, ret);
+ goto out_disable_xtal_aon;
+ }
+
+ ret = regulator_set_voltage(info->wlan_reg_xtal, WLAN_VREG_XTAL_MIN,
+ WLAN_VREG_XTAL_MAX);
+ if (ret) {
+ pr_err("%s: Set wlan_vreg_xtal failed\n", __func__);
+ goto out_put_xtal;
+ }
+
+ ret = regulator_enable(info->wlan_reg_xtal);
+ if (ret) {
+ pr_err("%s: Enable wlan_vreg_xtal failed\n", __func__);
+ goto out_put_xtal;
+ }
+
+ return 0;
+
+out_put_xtal:
+ if (info->wlan_reg_xtal)
+ regulator_put(info->wlan_reg_xtal);
+
+out_disable_xtal_aon:
+ if (info->wlan_reg_xtal_aon)
+ regulator_disable(info->wlan_reg_xtal_aon);
+
+end:
+ if (info->wlan_reg_xtal_aon)
+ regulator_put(info->wlan_reg_xtal_aon);
+
+ return ret;
+}
+
+static int cnss_get_wlan_enable_gpio(
+ struct cnss_wlan_gpio_info *gpio_info,
+ struct platform_device *pdev)
+{
+ int ret = 0;
+ struct device *dev = &pdev->dev;
+
+ if (!of_find_property(dev->of_node, gpio_info->name, NULL)) {
+ gpio_info->prop = false;
+ return -ENODEV;
+ }
+
+ gpio_info->prop = true;
+ ret = of_get_named_gpio(dev->of_node, gpio_info->name, 0);
+ if (ret >= 0) {
+ gpio_info->num = ret;
+ } else {
+ if (ret == -EPROBE_DEFER)
+ pr_debug("get WLAN_EN GPIO probe defer\n");
+ else
+ pr_err(
+ "can't get gpio %s ret %d", gpio_info->name, ret);
+ }
+
+ ret = cnss_wlan_gpio_init(gpio_info);
+ if (ret)
+ pr_err("gpio init failed\n");
+
+ return ret;
+}
+
+static int cnss_get_wlan_bootstrap_gpio(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct device_node *node = (&pdev->dev)->of_node;
+
+ if (!of_find_property(node, WLAN_BOOTSTRAP_GPIO_NAME, NULL))
+ return ret;
+
+ penv->wlan_bootstrap_gpio =
+ of_get_named_gpio(node, WLAN_BOOTSTRAP_GPIO_NAME, 0);
+ if (penv->wlan_bootstrap_gpio > 0) {
+ ret = cnss_wlan_bootstrap_gpio_init();
+ } else {
+ ret = penv->wlan_bootstrap_gpio;
+ pr_err(
+ "%s: Can't get GPIO %s, ret = %d",
+ __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+ }
+
+ return ret;
+}
+
+static int cnss_wlan_get_resources(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+ struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+ struct device_node *node = pdev->dev.of_node;
+
+ if (of_get_property(node, WLAN_VREG_CORE_NAME "-supply", NULL)) {
+ vreg_info->wlan_reg_core = regulator_get(&pdev->dev,
+ WLAN_VREG_CORE_NAME);
+ if (IS_ERR(vreg_info->wlan_reg_core)) {
+ ret = PTR_ERR(vreg_info->wlan_reg_core);
+
+ if (ret == -EPROBE_DEFER) {
+ pr_err("%s: wlan_reg_core probe deferred\n",
+ __func__);
+ } else {
+ pr_err("%s: Get wlan_reg_core failed\n",
+ __func__);
+ }
+ goto err_reg_core_get;
+ }
+
+ ret = regulator_set_voltage(vreg_info->wlan_reg_core,
+ WLAN_VREG_CORE_MIN,
+ WLAN_VREG_CORE_MAX);
+ if (ret) {
+ pr_err("%s: Set wlan_reg_core failed\n", __func__);
+ goto err_reg_core_set;
+ }
+
+ ret = regulator_enable(vreg_info->wlan_reg_core);
+ if (ret) {
+ pr_err("%s: Enable wlan_reg_core failed\n", __func__);
+ goto err_reg_core_enable;
+ }
+ }
+
+ if (of_get_property(node, WLAN_VREG_IO_NAME "-supply", NULL)) {
+ vreg_info->wlan_reg_io = regulator_get(&pdev->dev,
+ WLAN_VREG_IO_NAME);
+ if (!IS_ERR(vreg_info->wlan_reg_io)) {
+ ret = regulator_set_voltage(vreg_info->wlan_reg_io,
+ WLAN_VREG_IO_MIN,
+ WLAN_VREG_IO_MAX);
+ if (ret) {
+ pr_err("%s: Set wlan_vreg_io failed\n",
+ __func__);
+ goto err_reg_io_set;
+ }
+
+ ret = regulator_enable(vreg_info->wlan_reg_io);
+ if (ret) {
+ pr_err("%s: Enable wlan_vreg_io failed\n",
+ __func__);
+ goto err_reg_io_enable;
+ }
+
+ usleep_range(WLAN_VREG_IO_DELAY_MIN,
+ WLAN_VREG_IO_DELAY_MAX);
+ }
+ }
+
+ if (cnss_enable_xtal_ldo(pdev))
+ goto err_reg_xtal_enable;
+
+ vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME);
+
+ if (IS_ERR(vreg_info->wlan_reg)) {
+ if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER)
+ pr_err("%s: vreg probe defer\n", __func__);
+ else
+ pr_err("%s: vreg regulator get failed\n", __func__);
+ ret = PTR_ERR(vreg_info->wlan_reg);
+ goto err_reg_get;
+ }
+
+ ret = regulator_enable(vreg_info->wlan_reg);
+
+ if (ret) {
+ pr_err("%s: vreg initial vote failed\n", __func__);
+ goto err_reg_enable;
+ }
+
+ if (of_get_property(node, WLAN_VREG_SP2T_NAME "-supply", NULL)) {
+ vreg_info->wlan_reg_sp2t =
+ regulator_get(&pdev->dev, WLAN_VREG_SP2T_NAME);
+ if (!IS_ERR(vreg_info->wlan_reg_sp2t)) {
+ ret = regulator_set_voltage(vreg_info->wlan_reg_sp2t,
+ WLAN_VREG_SP2T_MIN,
+ WLAN_VREG_SP2T_MAX);
+ if (ret) {
+ pr_err("%s: Set wlan_vreg_sp2t failed\n",
+ __func__);
+ goto err_reg_sp2t_set;
+ }
+
+ ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+ if (ret) {
+ pr_err("%s: Enable wlan_vreg_sp2t failed\n",
+ __func__);
+ goto err_reg_sp2t_enable;
+ }
+ }
+ }
+
+ if (of_get_property(node, WLAN_ANT_SWITCH_NAME "-supply", NULL)) {
+ vreg_info->ant_switch =
+ regulator_get(&pdev->dev, WLAN_ANT_SWITCH_NAME);
+ if (!IS_ERR(vreg_info->ant_switch)) {
+ ret = regulator_set_voltage(vreg_info->ant_switch,
+ WLAN_ANT_SWITCH_VOLT_MIN,
+ WLAN_ANT_SWITCH_VOLT_MAX);
+ if (ret < 0) {
+ pr_err("%s: Set ant_switch voltage failed\n",
+ __func__);
+ goto err_ant_switch_set;
+ }
+
+ ret = regulator_set_load(vreg_info->ant_switch,
+ WLAN_ANT_SWITCH_CURR);
+ if (ret < 0) {
+ pr_err("%s: Set ant_switch current failed\n",
+ __func__);
+ goto err_ant_switch_set;
+ }
+
+ ret = regulator_enable(vreg_info->ant_switch);
+ if (ret < 0) {
+ pr_err("%s: Enable ant_switch failed\n",
+ __func__);
+ goto err_ant_switch_enable;
+ }
+ }
+ }
+
+ if (of_find_property(node, "qcom,wlan-uart-access", NULL))
+ penv->cap.cap_flag |= CNSS_HAS_UART_ACCESS;
+
+ if (of_get_property(node, WLAN_SWREG_NAME "-supply", NULL)) {
+ vreg_info->soc_swreg = regulator_get(&pdev->dev,
+ WLAN_SWREG_NAME);
+ if (IS_ERR(vreg_info->soc_swreg)) {
+ pr_err("%s: soc-swreg node not found\n",
+ __func__);
+ goto err_reg_get2;
+ }
+ ret = regulator_set_voltage(vreg_info->soc_swreg,
+ SOC_SWREG_VOLT_MIN,
+ SOC_SWREG_VOLT_MAX);
+ if (ret) {
+ pr_err("%s: vreg initial voltage set failed on soc-swreg\n",
+ __func__);
+ goto err_reg_set;
+ }
+ ret = regulator_enable(vreg_info->soc_swreg);
+ if (ret) {
+ pr_err("%s: vreg initial vote failed\n", __func__);
+ goto err_reg_enable2;
+ }
+ penv->cap.cap_flag |= CNSS_HAS_EXTERNAL_SWREG;
+ }
+
+ penv->wlan_en_vreg_support =
+ of_property_read_bool(node, "qcom,wlan-en-vreg-support");
+ if (penv->wlan_en_vreg_support) {
+ vreg_info->wlan_en_reg =
+ regulator_get(&pdev->dev, WLAN_EN_VREG_NAME);
+ if (IS_ERR(vreg_info->wlan_en_reg)) {
+ pr_err("%s:wlan_en vreg get failed\n", __func__);
+ ret = PTR_ERR(vreg_info->wlan_en_reg);
+ goto err_wlan_en_reg_get;
+ }
+ }
+
+ if (!penv->wlan_en_vreg_support) {
+ ret = cnss_get_wlan_enable_gpio(gpio_info, pdev);
+ if (ret) {
+ pr_err(
+ "%s:Failed to config the WLAN_EN gpio\n", __func__);
+ goto err_gpio_wlan_en;
+ }
+ }
+ vreg_info->state = VREG_ON;
+
+ ret = cnss_get_wlan_bootstrap_gpio(pdev);
+ if (ret) {
+ pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__);
+ goto err_gpio_wlan_bootstrap;
+ }
+
+ return ret;
+
+err_gpio_wlan_bootstrap:
+ cnss_put_wlan_enable_gpio();
+err_gpio_wlan_en:
+err_wlan_en_reg_get:
+ vreg_info->wlan_en_reg = NULL;
+ if (vreg_info->soc_swreg)
+ regulator_disable(vreg_info->soc_swreg);
+ vreg_info->state = VREG_OFF;
+
+err_reg_enable2:
+err_reg_set:
+ if (vreg_info->soc_swreg)
+ regulator_put(vreg_info->soc_swreg);
+
+err_reg_get2:
+ if (vreg_info->ant_switch)
+ regulator_disable(vreg_info->ant_switch);
+
+err_ant_switch_enable:
+err_ant_switch_set:
+ if (vreg_info->ant_switch)
+ regulator_put(vreg_info->ant_switch);
+ if (vreg_info->wlan_reg_sp2t)
+ regulator_disable(vreg_info->wlan_reg_sp2t);
+
+err_reg_sp2t_enable:
+err_reg_sp2t_set:
+ if (vreg_info->wlan_reg_sp2t)
+ regulator_put(vreg_info->wlan_reg_sp2t);
+ regulator_disable(vreg_info->wlan_reg);
+
+err_reg_enable:
+ regulator_put(vreg_info->wlan_reg);
+err_reg_get:
+ cnss_disable_xtal_ldo(pdev);
+
+err_reg_xtal_enable:
+ if (vreg_info->wlan_reg_io)
+ regulator_disable(vreg_info->wlan_reg_io);
+
+err_reg_io_enable:
+err_reg_io_set:
+ if (vreg_info->wlan_reg_io)
+ regulator_put(vreg_info->wlan_reg_io);
+ if (vreg_info->wlan_reg_core)
+ regulator_disable(vreg_info->wlan_reg_core);
+
+err_reg_core_enable:
+err_reg_core_set:
+ if (vreg_info->wlan_reg_core)
+ regulator_put(vreg_info->wlan_reg_core);
+
+err_reg_core_get:
+ return ret;
+}
+
+static void cnss_wlan_release_resources(void)
+{
+ struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+ struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+ if (penv->wlan_bootstrap_gpio > 0)
+ gpio_free(penv->wlan_bootstrap_gpio);
+ cnss_put_wlan_enable_gpio();
+ gpio_info->state = WLAN_EN_LOW;
+ gpio_info->prop = false;
+ cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+ if (vreg_info->soc_swreg)
+ regulator_put(vreg_info->soc_swreg);
+ if (vreg_info->ant_switch)
+ regulator_put(vreg_info->ant_switch);
+ if (vreg_info->wlan_reg_sp2t)
+ regulator_put(vreg_info->wlan_reg_sp2t);
+ regulator_put(vreg_info->wlan_reg);
+ if (vreg_info->wlan_reg_xtal)
+ regulator_put(vreg_info->wlan_reg_xtal);
+ if (vreg_info->wlan_reg_xtal_aon)
+ regulator_put(vreg_info->wlan_reg_xtal_aon);
+ if (vreg_info->wlan_reg_io)
+ regulator_put(vreg_info->wlan_reg_io);
+ if (vreg_info->wlan_reg_core)
+ regulator_put(vreg_info->wlan_reg_core);
+ vreg_info->state = VREG_OFF;
+}
+
+static u8 cnss_get_pci_dev_bus_number(struct pci_dev *pdev)
+{
+ return pdev->bus->number;
+}
+
+void cnss_setup_fw_files(u16 revision)
+{
+ switch (revision) {
+ case QCA6174_FW_1_1:
+ strlcpy(penv->fw_files.image_file, "qwlan11.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.board_data, "bdwlan11.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.otp_data, "otp11.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_file, "utf11.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_board_data, "utfbd11.bin",
+ CNSS_MAX_FILE_NAME);
+ break;
+
+ case QCA6174_FW_1_3:
+ strlcpy(penv->fw_files.image_file, "qwlan13.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.board_data, "bdwlan13.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.otp_data, "otp13.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_file, "utf13.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_board_data, "utfbd13.bin",
+ CNSS_MAX_FILE_NAME);
+ break;
+
+ case QCA6174_FW_2_0:
+ strlcpy(penv->fw_files.image_file, "qwlan20.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.board_data, "bdwlan20.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.otp_data, "otp20.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_file, "utf20.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_board_data, "utfbd20.bin",
+ CNSS_MAX_FILE_NAME);
+ break;
+
+ case QCA6174_FW_3_0:
+ case QCA6174_FW_3_2:
+ strlcpy(penv->fw_files.image_file, "qwlan30.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.board_data, "bdwlan30.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.otp_data, "otp30.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_file, "utf30.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_board_data, "utfbd30.bin",
+ CNSS_MAX_FILE_NAME);
+ break;
+
+ default:
+ strlcpy(penv->fw_files.image_file, "qwlan.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.board_data, "bdwlan.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.otp_data, "otp.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_file, "utf.bin",
+ CNSS_MAX_FILE_NAME);
+ strlcpy(penv->fw_files.utf_board_data, "utfbd.bin",
+ CNSS_MAX_FILE_NAME);
+ break;
+ }
+}
+
+int cnss_get_fw_files(struct cnss_fw_files *pfw_files)
+{
+ if (!penv || !pfw_files)
+ return -ENODEV;
+
+ *pfw_files = penv->fw_files;
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+ penv->fw_mem = devm_kzalloc(&pdev->dev, MAX_FIRMWARE_SIZE, GFP_KERNEL);
+}
+#else
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+}
+#endif
+
+static int get_image_file(const u8 *index_info, u8 *file_name,
+ u32 *type, u32 *segment_idx)
+{
+ if (!file_name || !index_info || !type)
+ return -EINVAL;
+
+ memcpy(type, index_info, TYPE_LENGTH);
+ memcpy(segment_idx, index_info + TYPE_LENGTH, TYPE_LENGTH);
+ memcpy(file_name, index_info + TYPE_LENGTH + TYPE_LENGTH,
+ FW_FILENAME_LENGTH);
+
+ pr_debug("%u: %u: %s", *type, *segment_idx, file_name);
+
+ return PER_FILE_DATA;
+}
+
+static void print_allocated_image_table(void)
+{
+ u32 seg = 0, count = 0;
+ u8 *dump_addr;
+ struct segment_memory *pseg_mem = penv->fw_seg_mem;
+ struct segment_memory *p_bdata_seg_mem = penv->bdata_seg_mem;
+
+ pr_debug("%s: Dumping FW IMAGE\n", __func__);
+ while (seg++ < penv->fw_seg_count) {
+ dump_addr = (u8 *)pseg_mem->cpu_region +
+ sizeof(struct region_desc);
+ for (count = 0; count < pseg_mem->size -
+ sizeof(struct region_desc); count++)
+ pr_debug("%02x", dump_addr[count]);
+
+ pseg_mem++;
+ }
+
+ seg = 0;
+ pr_debug("%s: Dumping BOARD DATA\n", __func__);
+ while (seg++ < penv->bdata_seg_count) {
+ dump_addr = (u8 *)p_bdata_seg_mem->cpu_region +
+ sizeof(struct region_desc);
+ for (count = 0; count < p_bdata_seg_mem->size -
+ sizeof(struct region_desc); count++)
+ pr_debug("%02x ", dump_addr[count]);
+
+ p_bdata_seg_mem++;
+ }
+}
+
+static void free_allocated_image_table(void)
+{
+ struct device *dev = &penv->pdev->dev;
+ struct segment_memory *pseg_mem;
+ u32 seg = 0;
+
+ /* free fw memroy */
+ pseg_mem = penv->fw_seg_mem;
+ while (seg++ < penv->fw_seg_count) {
+ dma_free_coherent(dev, pseg_mem->size,
+ pseg_mem->cpu_region, pseg_mem->dma_region);
+ pseg_mem++;
+ }
+ if (penv->fw_cpu)
+ dma_free_coherent(dev,
+ sizeof(struct segment_desc) *
+ MAX_NUM_OF_SEGMENTS,
+ penv->fw_cpu, penv->fw_dma);
+ penv->fw_seg_count = 0;
+ penv->fw_dma = 0;
+ penv->fw_cpu = NULL;
+ penv->fw_dma_size = 0;
+
+ /* free bdata memory */
+ seg = 0;
+ pseg_mem = penv->bdata_seg_mem;
+ while (seg++ < penv->bdata_seg_count) {
+ dma_free_coherent(dev, pseg_mem->size,
+ pseg_mem->cpu_region,
+ pseg_mem->dma_region);
+ pseg_mem++;
+ }
+ if (penv->bdata_cpu)
+ dma_free_coherent(dev,
+ sizeof(struct segment_desc) *
+ MAX_NUM_OF_SEGMENTS,
+ penv->bdata_cpu, penv->bdata_dma);
+ penv->bdata_seg_count = 0;
+ penv->bdata_dma = 0;
+ penv->bdata_cpu = NULL;
+ penv->bdata_dma_size = 0;
+}
+
+static int cnss_setup_fw_image_table(int mode)
+{
+ struct image_desc_hdr *image_hdr;
+ struct segment_desc *pseg = NULL;
+ const struct firmware *fw_index, *fw_image;
+ struct device *dev = NULL;
+ char reserved[3] = "";
+ u8 image_file[FW_FILENAME_LENGTH] = "";
+ u8 index_file[FW_FILENAME_LENGTH] = "";
+ u8 index_info[MAX_INDEX_FILE_SIZE] = "";
+ size_t image_desc_size = 0, file_size = 0;
+ size_t index_pos = 0, image_pos = 0;
+ struct region_desc *reg_desc = NULL;
+ u32 type = 0;
+ u32 segment_idx = 0;
+ uintptr_t address;
+ int ret = 0;
+ dma_addr_t dma_addr;
+ void *vaddr = NULL;
+ dma_addr_t paddr;
+ struct segment_memory *pseg_mem;
+ u32 *pseg_count;
+
+ if (!penv || !penv->pdev) {
+ pr_err("cnss: invalid penv or pdev or dev\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ dev = &penv->pdev->dev;
+
+ /* meta data file has image details */
+ switch (mode) {
+ case FW_IMAGE_FTM:
+ ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qftm.bin");
+ pseg_mem = penv->fw_seg_mem;
+ pseg_count = &penv->fw_seg_count;
+ break;
+ case FW_IMAGE_MISSION:
+ ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qwlan.bin");
+ pseg_mem = penv->fw_seg_mem;
+ pseg_count = &penv->fw_seg_count;
+ break;
+ case FW_IMAGE_BDATA:
+ ret = scnprintf(index_file, FW_FILENAME_LENGTH, "bdwlan.bin");
+ pseg_mem = penv->bdata_seg_mem;
+ pseg_count = &penv->bdata_seg_count;
+ break;
+ default:
+ pr_err("%s: Unknown meta data file type 0x%x\n",
+ __func__, mode);
+ ret = -EINVAL;
+ }
+ if (ret < 0)
+ goto err;
+
+ image_desc_size = sizeof(struct image_desc_hdr) +
+ sizeof(struct segment_desc) * MAX_NUM_OF_SEGMENTS;
+
+ vaddr = dma_alloc_coherent(dev, image_desc_size,
+ &paddr, GFP_KERNEL);
+
+ if (!vaddr) {
+ pr_err("cnss: image desc allocation failure\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ memset(vaddr, 0, image_desc_size);
+
+ image_hdr = (struct image_desc_hdr *)vaddr;
+ image_hdr->image_id = mode;
+ memcpy(image_hdr->reserved, reserved, 3);
+
+ pr_err("cnss: request meta data file %s\n", index_file);
+ ret = request_firmware(&fw_index, index_file, dev);
+ if (ret || !fw_index || !fw_index->data || !fw_index->size) {
+ pr_err("cnss: meta data file open failure %s\n", index_file);
+ goto err_free;
+ }
+
+ if (fw_index->size > MAX_INDEX_FILE_SIZE) {
+ pr_err("cnss: meta data file has invalid size %s: %zu\n",
+ index_file, fw_index->size);
+ release_firmware(fw_index);
+ goto err_free;
+ }
+
+ memcpy(index_info, fw_index->data, fw_index->size);
+ file_size = fw_index->size;
+ release_firmware(fw_index);
+
+ while (file_size >= PER_FILE_DATA && image_pos < image_desc_size &&
+ image_hdr->segments_cnt < MAX_NUM_OF_SEGMENTS) {
+ ret = get_image_file(index_info + index_pos,
+ image_file, &type, &segment_idx);
+ if (ret == -EINVAL)
+ goto err_free;
+
+ file_size -= ret;
+ index_pos += ret;
+ pseg = vaddr + image_pos +
+ sizeof(struct image_desc_hdr);
+
+ switch (type) {
+ case SEG_METADATA:
+ case SEG_NON_PAGED:
+ case SEG_LOCKED_PAGE:
+ case SEG_UNLOCKED_PAGE:
+ case SEG_NON_SECURE_DATA:
+
+ image_hdr->segments_cnt++;
+ pseg->segment_id = type;
+ pseg->segment_idx = (u8)(segment_idx & 0xff);
+ memcpy(pseg->flags, reserved, 2);
+
+ ret = request_firmware(&fw_image, image_file, dev);
+ if (ret || !fw_image || !fw_image->data ||
+ !fw_image->size) {
+ pr_err("cnss: image file read failed %s",
+ image_file);
+ goto err_free;
+ }
+ if (fw_image->size > MAX_IMAGE_SIZE) {
+ pr_err("cnss: %s: image file invalid size %zu\n",
+ image_file, fw_image->size);
+ release_firmware(fw_image);
+ ret = -EINVAL;
+ goto err_free;
+ }
+ reg_desc =
+ dma_alloc_coherent(dev,
+ sizeof(struct region_desc) +
+ fw_image->size,
+ &dma_addr, GFP_KERNEL);
+ if (!reg_desc) {
+ pr_err("cnss: region allocation failure\n");
+ ret = -ENOMEM;
+ release_firmware(fw_image);
+ goto err_free;
+ }
+ address = (uintptr_t)dma_addr;
+ pseg->addr_low = address & 0xFFFFFFFF;
+ pseg->addr_high = 0x00;
+ /* one region for one image file */
+ pseg->addr_count = 1;
+ memcpy((u8 *)reg_desc + sizeof(struct region_desc),
+ fw_image->data, fw_image->size);
+ address += sizeof(struct region_desc);
+ reg_desc->addr_low = address & 0xFFFFFFFF;
+ reg_desc->addr_high = 0x00;
+ reg_desc->reserved = 0;
+ reg_desc->size = fw_image->size;
+
+ pseg_mem[*pseg_count].dma_region = dma_addr;
+ pseg_mem[*pseg_count].cpu_region = reg_desc;
+ pseg_mem[*pseg_count].size =
+ sizeof(struct region_desc) + fw_image->size;
+
+ release_firmware(fw_image);
+ (*pseg_count)++;
+ break;
+
+ default:
+ pr_err("cnss: Unknown segment %d", type);
+ ret = -EINVAL;
+ goto err_free;
+ }
+ image_pos += sizeof(struct segment_desc);
+ }
+ if (mode != FW_IMAGE_BDATA) {
+ penv->fw_cpu = vaddr;
+ penv->fw_dma = paddr;
+ penv->fw_dma_size = sizeof(struct image_desc_hdr) +
+ sizeof(struct segment_desc) * image_hdr->segments_cnt;
+ } else {
+ penv->bdata_cpu = vaddr;
+ penv->bdata_dma = paddr;
+ penv->bdata_dma_size = sizeof(struct image_desc_hdr) +
+ sizeof(struct segment_desc) * image_hdr->segments_cnt;
+ }
+ pr_info("%s: Mode %d: Image setup table built on host", __func__, mode);
+
+ return file_size;
+err_free:
+ free_allocated_image_table();
+err:
+ pr_err("cnss: image file setup failed %d\n", ret);
+ return ret;
+}
+
+int cnss_get_fw_image(struct image_desc_info *image_desc_info)
+{
+ if (!image_desc_info || !penv ||
+ !penv->fw_seg_count || !penv->bdata_seg_count)
+ return -EINVAL;
+
+ mutex_lock(&penv->fw_setup_stat_lock);
+ image_desc_info->fw_addr = penv->fw_dma;
+ image_desc_info->fw_size = penv->fw_dma_size;
+ image_desc_info->bdata_addr = penv->bdata_dma;
+ image_desc_info->bdata_size = penv->bdata_dma_size;
+ mutex_unlock(&penv->fw_setup_stat_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_image);
+
+static ssize_t wlan_setup_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!penv)
+ return -ENODEV;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", penv->revision_id);
+}
+
+static DEVICE_ATTR(wlan_setup, 0400,
+ wlan_setup_show, NULL);
+
+static int cnss_wlan_is_codeswap_supported(u16 revision)
+{
+ switch (revision) {
+ case QCA6174_FW_3_0:
+ case QCA6174_FW_3_2:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static int cnss_smmu_init(struct device *dev)
+{
+ struct dma_iommu_mapping *mapping;
+ int atomic_ctx = 1;
+ int ret;
+
+ mapping = arm_iommu_create_mapping(&platform_bus_type,
+ penv->smmu_iova_start,
+ penv->smmu_iova_len);
+ if (IS_ERR(mapping)) {
+ ret = PTR_ERR(mapping);
+ pr_err("%s: create mapping failed, err = %d\n", __func__, ret);
+ goto map_fail;
+ }
+
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_ATOMIC,
+ &atomic_ctx);
+ if (ret) {
+ pr_err("%s: set atomic_ctx attribute failed, err = %d\n",
+ __func__, ret);
+ goto set_attr_fail;
+ }
+
+ ret = arm_iommu_attach_device(dev, mapping);
+ if (ret) {
+ pr_err("%s: attach device failed, err = %d\n", __func__, ret);
+ goto attach_fail;
+ }
+
+ penv->smmu_mapping = mapping;
+
+ return ret;
+
+attach_fail:
+set_attr_fail:
+ arm_iommu_release_mapping(mapping);
+map_fail:
+ return ret;
+}
+
+static void cnss_smmu_remove(struct device *dev)
+{
+ arm_iommu_detach_device(dev);
+ arm_iommu_release_mapping(penv->smmu_mapping);
+
+ penv->smmu_mapping = NULL;
+}
+
+#ifdef CONFIG_PCI_MSM
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+ return pci_store_saved_state(dev);
+}
+
+int cnss_msm_pcie_pm_control(
+ enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+ struct pci_dev *pdev, u32 options)
+{
+ return msm_pcie_pm_control(pm_opt, bus_num, pdev, NULL, options);
+}
+
+int cnss_pci_load_and_free_saved_state(
+ struct pci_dev *dev, struct pci_saved_state **state)
+{
+ return pci_load_and_free_saved_state(dev, state);
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+ return msm_pcie_shadow_control(dev, enable);
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+ return msm_pcie_deregister_event(reg);
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+ return msm_pcie_recover_config(dev);
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+ return msm_pcie_register_event(reg);
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+ return msm_pcie_enumerate(rc_idx);
+}
+#else /* !defined CONFIG_PCI_MSM */
+
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+ return NULL;
+}
+
+int cnss_msm_pcie_pm_control(
+ enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+ struct pci_dev *pdev, u32 options)
+{
+ return -ENODEV;
+}
+
+int cnss_pci_load_and_free_saved_state(
+ struct pci_dev *dev, struct pci_saved_state **state)
+{
+ return 0;
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+ return -ENODEV;
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+ return -ENODEV;
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+ return -ENODEV;
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+ return -ENODEV;
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+ return -EPROBE_DEFER;
+}
+#endif
+
+static void cnss_pcie_set_platform_ops(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+ pf_ops->request_bus_bandwidth = cnss_pci_request_bus_bandwidth;
+ pf_ops->get_virt_ramdump_mem = cnss_pci_get_virt_ramdump_mem;
+ pf_ops->device_self_recovery = cnss_pci_device_self_recovery;
+ pf_ops->schedule_recovery_work = cnss_pci_schedule_recovery_work;
+ pf_ops->device_crashed = cnss_pci_device_crashed;
+ pf_ops->get_wlan_mac_address = cnss_pci_get_wlan_mac_address;
+ pf_ops->set_wlan_mac_address = cnss_pcie_set_wlan_mac_address;
+ pf_ops->power_up = cnss_pcie_power_up;
+ pf_ops->power_down = cnss_pcie_power_down;
+
+ dev->platform_data = pf_ops;
+}
+
+static void cnss_pcie_reset_platform_ops(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+ memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+ dev->platform_data = NULL;
+}
+
+static int cnss_wlan_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret = 0;
+ struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+ void *cpu_addr;
+ dma_addr_t dma_handle;
+ struct codeswap_codeseg_info *cnss_seg_info = NULL;
+ struct device *dev = &pdev->dev;
+
+ cnss_pcie_set_platform_ops(dev);
+ penv->pdev = pdev;
+ penv->id = id;
+ atomic_set(&penv->fw_available, 0);
+ penv->device_id = pdev->device;
+
+ if (penv->smmu_iova_len) {
+ ret = cnss_smmu_init(&pdev->dev);
+ if (ret) {
+ pr_err("%s: SMMU init failed, err = %d\n",
+ __func__, ret);
+ goto smmu_init_fail;
+ }
+ }
+
+ if (penv->pci_register_again) {
+ pr_debug("%s: PCI re-registration complete\n", __func__);
+ penv->pci_register_again = false;
+ return 0;
+ }
+
+ switch (pdev->device) {
+ case QCA6180_DEVICE_ID:
+ pci_read_config_word(pdev, QCA6180_REV_ID_OFFSET,
+ &penv->revision_id);
+ break;
+
+ case QCA6174_DEVICE_ID:
+ pci_read_config_word(pdev, QCA6174_REV_ID_OFFSET,
+ &penv->revision_id);
+ cnss_setup_fw_files(penv->revision_id);
+ break;
+
+ default:
+ pr_err("cnss: unknown device found %d\n", pdev->device);
+ ret = -EPROBE_DEFER;
+ goto err_unknown;
+ }
+
+ if (penv->pcie_link_state) {
+ pci_save_state(pdev);
+ penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+ ret = cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS);
+ if (ret) {
+ pr_err("Failed to shutdown PCIe link\n");
+ goto err_pcie_suspend;
+ }
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+ }
+
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+
+ if (ret) {
+ pr_err("can't turn off wlan vreg\n");
+ goto err_pcie_suspend;
+ }
+
+ mutex_lock(&penv->fw_setup_stat_lock);
+ cnss_wlan_fw_mem_alloc(pdev);
+ mutex_unlock(&penv->fw_setup_stat_lock);
+
+ ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup);
+
+ if (ret) {
+ pr_err("Can't Create Device file\n");
+ goto err_pcie_suspend;
+ }
+
+ if (cnss_wlan_is_codeswap_supported(penv->revision_id)) {
+ pr_debug("Code-swap not enabled: %d\n", penv->revision_id);
+ goto err_pcie_suspend;
+ }
+
+ cpu_addr = dma_alloc_coherent(dev, EVICT_BIN_MAX_SIZE,
+ &dma_handle, GFP_KERNEL);
+ if (!cpu_addr || !dma_handle) {
+ pr_err("cnss: Memory Alloc failed for codeswap feature\n");
+ goto err_pcie_suspend;
+ }
+
+ memset(cpu_addr, 0, EVICT_BIN_MAX_SIZE);
+ cnss_seg_info = devm_kzalloc(dev, sizeof(*cnss_seg_info),
+ GFP_KERNEL);
+ if (!cnss_seg_info)
+ goto end_dma_alloc;
+
+ memset(cnss_seg_info, 0, sizeof(*cnss_seg_info));
+ cnss_seg_info->codeseg_busaddr[0] = (void *)dma_handle;
+ penv->codeseg_cpuaddr[0] = cpu_addr;
+ cnss_seg_info->codeseg_size = EVICT_BIN_MAX_SIZE;
+ cnss_seg_info->codeseg_total_bytes = EVICT_BIN_MAX_SIZE;
+ cnss_seg_info->num_codesegs = 1;
+ cnss_seg_info->codeseg_size_log2 = ilog2(EVICT_BIN_MAX_SIZE);
+
+ penv->cnss_seg_info = cnss_seg_info;
+ pr_debug("%s: Successfully allocated memory for CODESWAP\n", __func__);
+
+ return ret;
+
+end_dma_alloc:
+ dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle);
+err_unknown:
+err_pcie_suspend:
+smmu_init_fail:
+ cnss_pcie_reset_platform_ops(dev);
+ return ret;
+}
+
+static void cnss_wlan_pci_remove(struct pci_dev *pdev)
+{
+ struct device *dev;
+
+ if (!penv)
+ return;
+
+ dev = &penv->pldev->dev;
+ cnss_pcie_reset_platform_ops(dev);
+ device_remove_file(dev, &dev_attr_wlan_setup);
+
+ if (penv->smmu_mapping)
+ cnss_smmu_remove(&pdev->dev);
+}
+
+static int cnss_wlan_pci_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct cnss_wlan_driver *wdriver;
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+ if (!penv)
+ goto out;
+
+ if (!penv->pcie_link_state)
+ goto out;
+
+ wdriver = penv->driver;
+ if (!wdriver)
+ goto out;
+
+ if (wdriver->suspend) {
+ ret = wdriver->suspend(pdev, state);
+
+ if (penv->pcie_link_state) {
+ pci_save_state(pdev);
+ penv->saved_state = cnss_pci_store_saved_state(pdev);
+ }
+ }
+ penv->monitor_wake_intr = false;
+
+out:
+ return ret;
+}
+
+static int cnss_wlan_pci_resume(struct device *dev)
+{
+ int ret = 0;
+ struct cnss_wlan_driver *wdriver;
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ if (!penv)
+ goto out;
+
+ if (!penv->pcie_link_state)
+ goto out;
+
+ wdriver = penv->driver;
+ if (!wdriver)
+ goto out;
+
+ if (wdriver->resume && !penv->pcie_link_down_ind) {
+ if (penv->saved_state)
+ cnss_pci_load_and_free_saved_state(
+ pdev, &penv->saved_state);
+ pci_restore_state(pdev);
+
+ ret = wdriver->resume(pdev);
+ }
+
+out:
+ return ret;
+}
+
+static int cnss_wlan_runtime_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct cnss_wlan_driver *wdrv;
+
+ if (!penv)
+ return -EAGAIN;
+
+ if (penv->pcie_link_down_ind) {
+ pr_debug("PCI link down recovery is in progress\n");
+ return -EAGAIN;
+ }
+
+ pr_debug("cnss: runtime suspend start\n");
+
+ wdrv = penv->driver;
+
+ if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_suspend)
+ ret = wdrv->runtime_ops->runtime_suspend(to_pci_dev(dev));
+
+ pr_info("cnss: runtime suspend status: %d\n", ret);
+
+ return ret;
+}
+
+static int cnss_wlan_runtime_resume(struct device *dev)
+{
+ struct cnss_wlan_driver *wdrv;
+ int ret = 0;
+
+ if (!penv)
+ return -EAGAIN;
+
+ if (penv->pcie_link_down_ind) {
+ pr_debug("PCI link down recovery is in progress\n");
+ return -EAGAIN;
+ }
+
+ pr_debug("cnss: runtime resume start\n");
+
+ wdrv = penv->driver;
+
+ if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_resume)
+ ret = wdrv->runtime_ops->runtime_resume(to_pci_dev(dev));
+
+ pr_info("cnss: runtime resume status: %d\n", ret);
+
+ return ret;
+}
+
+static int cnss_wlan_runtime_idle(struct device *dev)
+{
+ pr_debug("cnss: runtime idle\n");
+
+ pm_request_autosuspend(dev);
+
+ return -EBUSY;
+}
+
+static DECLARE_RWSEM(cnss_pm_sem);
+
+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 const struct pci_device_id cnss_wlan_pci_id_table[] = {
+ { QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { QCA6174_VENDOR_ID, BEELINER_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { QCA6180_VENDOR_ID, QCA6180_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, cnss_wlan_pci_id_table);
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops cnss_wlan_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cnss_wlan_pci_suspend, cnss_wlan_pci_resume)
+ SET_RUNTIME_PM_OPS(cnss_wlan_runtime_suspend, cnss_wlan_runtime_resume,
+ cnss_wlan_runtime_idle)
+};
+#endif
+
+struct pci_driver cnss_wlan_pci_driver = {
+ .name = "cnss_wlan_pci",
+ .id_table = cnss_wlan_pci_id_table,
+ .probe = cnss_wlan_pci_probe,
+ .remove = cnss_wlan_pci_remove,
+#ifdef CONFIG_PM
+ .driver = {
+ .pm = &cnss_wlan_pm_ops,
+ },
+#endif
+};
+
+static ssize_t fw_image_setup_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!penv)
+ return -ENODEV;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", penv->fw_image_setup);
+}
+
+static ssize_t fw_image_setup_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int val;
+ int ret;
+
+ if (!penv)
+ return -ENODEV;
+
+ mutex_lock(&penv->fw_setup_stat_lock);
+ pr_info("%s: Firmware setup in progress\n", __func__);
+
+ if (kstrtoint(buf, 0, &val)) {
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ return -EINVAL;
+ }
+
+ if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION ||
+ val == FW_IMAGE_BDATA) {
+ pr_info("%s: fw image setup triggered %d\n", __func__, val);
+ ret = cnss_setup_fw_image_table(val);
+ if (ret != 0) {
+ pr_err("%s: Invalid parsing of FW image files %d\n",
+ __func__, ret);
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ return -EINVAL;
+ }
+ penv->fw_image_setup = val;
+ } else if (val == FW_IMAGE_PRINT) {
+ print_allocated_image_table();
+ } else if (val == BMI_TEST_SETUP) {
+ penv->bmi_test = val;
+ }
+
+ pr_info("%s: Firmware setup completed\n", __func__);
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ return count;
+}
+
+static DEVICE_ATTR(fw_image_setup, 0600,
+ fw_image_setup_show, fw_image_setup_store);
+
+void cnss_pci_recovery_work_handler(struct work_struct *recovery)
+{
+ cnss_pci_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_pci_recovery_work, cnss_pci_recovery_work_handler);
+
+void cnss_schedule_recovery_work(void)
+{
+ schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_schedule_recovery_work);
+
+static inline void __cnss_disable_irq(void *data)
+{
+ struct pci_dev *pdev = data;
+
+ disable_irq(pdev->irq);
+}
+
+void cnss_pci_events_cb(struct msm_pcie_notify *notify)
+{
+ unsigned long flags;
+
+ if (!notify)
+ return;
+
+ switch (notify->event) {
+ case MSM_PCIE_EVENT_LINKDOWN:
+ if (pcie_link_down_panic)
+ panic("PCIe link is down\n");
+
+ spin_lock_irqsave(&pci_link_down_lock, flags);
+ if (penv->pcie_link_down_ind) {
+ pr_debug("PCI link down recovery is in progress, ignore\n");
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+ return;
+ }
+ penv->pcie_link_down_ind = true;
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+ pr_err("PCI link down, schedule recovery\n");
+ __cnss_disable_irq(notify->user);
+ schedule_work(&cnss_pci_recovery_work);
+ break;
+
+ case MSM_PCIE_EVENT_WAKEUP:
+ if (penv->monitor_wake_intr &&
+ atomic_read(&penv->auto_suspended)) {
+ penv->monitor_wake_intr = false;
+ pm_request_resume(&penv->pdev->dev);
+ }
+ break;
+
+ default:
+ pr_err("cnss: invalid event from PCIe callback %d\n",
+ notify->event);
+ }
+}
+
+void cnss_wlan_pci_link_down(void)
+{
+ unsigned long flags;
+
+ if (pcie_link_down_panic)
+ panic("PCIe link is down\n");
+
+ spin_lock_irqsave(&pci_link_down_lock, flags);
+ if (penv->pcie_link_down_ind) {
+ pr_debug("PCI link down recovery is in progress, ignore\n");
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+ return;
+ }
+ penv->pcie_link_down_ind = true;
+ spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+ pr_err("PCI link down detected by host driver, schedule recovery\n");
+ schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_wlan_pci_link_down);
+
+int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+ return cnss_msm_pcie_shadow_control(dev, enable);
+}
+EXPORT_SYMBOL(cnss_pcie_shadow_control);
+
+int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg)
+{
+ struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info;
+
+ mutex_lock(&penv->fw_setup_stat_lock);
+ if (!cnss_seg_info) {
+ swap_seg = NULL;
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ return -ENOENT;
+ }
+
+ if (!atomic_read(&penv->fw_available)) {
+ pr_debug("%s: fw is not available\n", __func__);
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ return -ENOENT;
+ }
+
+ *swap_seg = *cnss_seg_info;
+ mutex_unlock(&penv->fw_setup_stat_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_codeswap_struct);
+
+static void cnss_wlan_memory_expansion(void)
+{
+ struct device *dev;
+ const struct firmware *fw_entry;
+ const char *filename;
+ u32 fw_entry_size, size_left, dma_size_left, length;
+ char *fw_temp;
+ char *fw_data;
+ char *dma_virt_addr;
+ struct codeswap_codeseg_info *cnss_seg_info;
+ u32 total_length = 0;
+ struct pci_dev *pdev;
+
+ mutex_lock(&penv->fw_setup_stat_lock);
+ filename = cnss_wlan_get_evicted_data_file();
+ pdev = penv->pdev;
+ dev = &pdev->dev;
+ cnss_seg_info = penv->cnss_seg_info;
+
+ if (!cnss_seg_info) {
+ pr_debug("cnss: cnss_seg_info is NULL\n");
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ goto end;
+ }
+
+ if (atomic_read(&penv->fw_available)) {
+ pr_debug("cnss: fw code already copied to host memory\n");
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ goto end;
+ }
+
+ if (request_firmware(&fw_entry, filename, dev) != 0) {
+ pr_debug("cnss: failed to get fw: %s\n", filename);
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ goto end;
+ }
+
+ if (!fw_entry || !fw_entry->data) {
+ pr_err("%s: INVALID FW entries\n", __func__);
+ mutex_unlock(&penv->fw_setup_stat_lock);
+ goto release_fw;
+ }
+
+ dma_virt_addr = (char *)penv->codeseg_cpuaddr[0];
+ fw_data = (u8 *)fw_entry->data;
+ fw_temp = fw_data;
+ fw_entry_size = fw_entry->size;
+ if (fw_entry_size > EVICT_BIN_MAX_SIZE)
+ fw_entry_size = EVICT_BIN_MAX_SIZE;
+ size_left = fw_entry_size;
+ dma_size_left = EVICT_BIN_MAX_SIZE;
+ while ((size_left && fw_temp) && (dma_size_left > 0)) {
+ fw_temp = fw_temp + 4;
+ size_left = size_left - 4;
+ length = *(int *)fw_temp;
+ if ((length > size_left || length <= 0) ||
+ (dma_size_left <= 0 || length > dma_size_left)) {
+ pr_err("cnss: wrong length read:%d\n",
+ length);
+ break;
+ }
+ fw_temp = fw_temp + 4;
+ size_left = size_left - 4;
+ memcpy(dma_virt_addr, fw_temp, length);
+ dma_size_left = dma_size_left - length;
+ size_left = size_left - length;
+ fw_temp = fw_temp + length;
+ dma_virt_addr = dma_virt_addr + length;
+ total_length += length;
+ pr_debug("cnss: bytes_left to copy: fw:%d; dma_page:%d\n",
+ size_left, dma_size_left);
+ }
+ pr_debug("cnss: total_bytes copied: %d\n", total_length);
+ cnss_seg_info->codeseg_total_bytes = total_length;
+
+ atomic_set(&penv->fw_available, 1);
+ mutex_unlock(&penv->fw_setup_stat_lock);
+
+release_fw:
+ release_firmware(fw_entry);
+end:
+ return;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_pci_get_wlan_mac_address(u32 *num)
+{
+ struct cnss_wlan_mac_addr *addr = NULL;
+
+ if (!penv) {
+ pr_err("%s: Invalid Platform Driver Context\n", __func__);
+ goto end;
+ }
+
+ if (!penv->is_wlan_mac_set) {
+ pr_info("%s: Platform Driver doesn't have any mac address\n",
+ __func__);
+ goto end;
+ }
+
+ addr = &penv->wlan_mac_addr;
+ *num = addr->no_of_mac_addr_set;
+ return &addr->mac_addr[0][0];
+
+end:
+ *num = 0;
+ return NULL;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+ struct cnss_wlan_mac_addr *addr = NULL;
+
+ if (!penv) {
+ pr_err("%s: Invalid Platform Driver Context\n", __func__);
+ goto end;
+ }
+
+ if (!penv->is_wlan_mac_set) {
+ pr_info("%s: Platform Driver doesn't have any mac address\n",
+ __func__);
+ goto end;
+ }
+
+ addr = &penv->wlan_mac_addr;
+ *num = addr->no_of_mac_addr_set;
+ return &addr->mac_addr[0][0];
+end:
+ *num = 0;
+ return NULL;
+}
+EXPORT_SYMBOL(cnss_get_wlan_mac_address);
+
+/**
+ * cnss_pcie_set_wlan_mac_address() - API to get two wlan mac address
+ * @in: Input buffer with wlan mac addresses
+ * @len: Size of the buffer passed
+ *
+ * API to store wlan mac address passed by the caller. The stored mac
+ * addresses are used by the wlan functional driver to program wlan HW.
+ *
+ * Return: kernel error code.
+ */
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len)
+{
+ u32 no_of_mac_addr;
+ struct cnss_wlan_mac_addr *addr = NULL;
+ int iter = 0;
+ u8 *temp = NULL;
+
+ if (len == 0 || (len % ETH_ALEN) != 0) {
+ pr_err("%s: Invalid Length:%d\n", __func__, len);
+ return -EINVAL;
+ }
+
+ no_of_mac_addr = len / ETH_ALEN;
+
+ if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
+ pr_err("%s: Num of supported MAC addresses are:%d given:%d\n",
+ __func__, MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
+ return -EINVAL;
+ }
+
+ if (!penv) {
+ pr_err("%s: Invalid CNSS Platform Context\n", __func__);
+ return -ENOENT;
+ }
+
+ if (penv->is_wlan_mac_set) {
+ pr_info("%s: Already MAC address are configured\n", __func__);
+ return 0;
+ }
+
+ penv->is_wlan_mac_set = true;
+ addr = &penv->wlan_mac_addr;
+ addr->no_of_mac_addr_set = no_of_mac_addr;
+ temp = &addr->mac_addr[0][0];
+
+ for (; iter < no_of_mac_addr; ++iter, temp += ETH_ALEN, in +=
+ ETH_ALEN) {
+ ether_addr_copy(temp, in);
+ pr_debug("%s MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ __func__, temp[0], temp[1], temp[2], temp[3], temp[4],
+ temp[5]);
+ }
+ return 0;
+}
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver)
+{
+ int ret = 0;
+ int probe_again = 0;
+ struct cnss_wlan_driver *wdrv;
+ struct cnss_wlan_vreg_info *vreg_info;
+ struct cnss_wlan_gpio_info *gpio_info;
+ struct pci_dev *pdev;
+
+ if (!penv)
+ return -ENODEV;
+
+ vreg_info = &penv->vreg_info;
+ gpio_info = &penv->gpio_info;
+ pdev = penv->pdev;
+
+ if (!penv->driver) {
+ penv->driver = driver;
+ wdrv = penv->driver;
+ } else {
+ pr_err("driver already registered\n");
+ return -EEXIST;
+ }
+
+again:
+ ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+ if (ret) {
+ pr_err("wlan vreg ON failed\n");
+ goto err_wlan_vreg_on;
+ }
+
+ msleep(POWER_ON_DELAY);
+
+ if (penv->wlan_bootstrap_gpio > 0) {
+ gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+ msleep(WLAN_BOOTSTRAP_DELAY);
+ }
+
+ cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+
+ if (!pdev) {
+ pr_debug("%s: invalid pdev. register pci device\n", __func__);
+ ret = pci_register_driver(&cnss_wlan_pci_driver);
+
+ if (ret) {
+ pr_err("%s: pci registration failed\n", __func__);
+ goto err_pcie_reg;
+ }
+ pdev = penv->pdev;
+ if (!pdev) {
+ pr_err("%s: pdev is still invalid\n", __func__);
+ goto err_pcie_reg;
+ }
+ }
+
+ penv->event_reg.events = MSM_PCIE_EVENT_LINKDOWN |
+ MSM_PCIE_EVENT_WAKEUP;
+ penv->event_reg.user = pdev;
+ penv->event_reg.mode = MSM_PCIE_TRIGGER_CALLBACK;
+ penv->event_reg.callback = cnss_pci_events_cb;
+ penv->event_reg.options = MSM_PCIE_CONFIG_NO_RECOVERY;
+ ret = cnss_msm_pcie_register_event(&penv->event_reg);
+ if (ret)
+ pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+ if (!penv->pcie_link_state && !penv->pcie_link_down_ind) {
+ ret = cnss_msm_pcie_pm_control(
+ MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS);
+ if (ret) {
+ pr_err("PCIe link bring-up failed\n");
+ goto err_pcie_link_up;
+ }
+ penv->pcie_link_state = PCIE_LINK_UP;
+ } else if (!penv->pcie_link_state && penv->pcie_link_down_ind) {
+ ret = cnss_msm_pcie_pm_control(
+ MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+ if (ret) {
+ pr_err("PCIe link bring-up failed (link down option)\n");
+ goto err_pcie_link_up;
+ }
+ penv->pcie_link_state = PCIE_LINK_UP;
+
+ ret = cnss_msm_pcie_recover_config(pdev);
+ if (ret) {
+ pr_err("cnss: PCI link failed to recover\n");
+ goto err_pcie_link_up;
+ }
+ penv->pcie_link_down_ind = false;
+ }
+
+ if (!cnss_wlan_is_codeswap_supported(penv->revision_id))
+ cnss_wlan_memory_expansion();
+
+ if (wdrv->probe) {
+ if (penv->saved_state)
+ cnss_pci_load_and_free_saved_state(
+ pdev, &penv->saved_state);
+
+ pci_restore_state(pdev);
+
+ ret = wdrv->probe(pdev, penv->id);
+ if (ret) {
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
+
+ if (probe_again > 3) {
+ pr_err("Failed to probe WLAN\n");
+ goto err_wlan_probe;
+ }
+ pci_save_state(pdev);
+ penv->saved_state = cnss_pci_store_saved_state(pdev);
+ cnss_msm_pcie_deregister_event(&penv->event_reg);
+ cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND,
+ cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS);
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+ msleep(POWER_ON_DELAY);
+ probe_again++;
+ goto again;
+ }
+ }
+
+ if (penv->notify_modem_status && wdrv->modem_status)
+ wdrv->modem_status(pdev, penv->modem_current_status);
+
+ return ret;
+
+err_wlan_probe:
+ pci_save_state(pdev);
+ penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+err_pcie_link_up:
+ cnss_msm_pcie_deregister_event(&penv->event_reg);
+ if (penv->pcie_link_state) {
+ cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS);
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+ }
+
+err_pcie_reg:
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+ if (penv->pdev) {
+ pr_err("%d: Unregistering PCI device\n", __LINE__);
+ pci_unregister_driver(&cnss_wlan_pci_driver);
+ penv->pdev = NULL;
+ penv->pci_register_again = true;
+ }
+
+err_wlan_vreg_on:
+ penv->driver = NULL;
+
+ return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver)
+{
+ struct cnss_wlan_driver *wdrv;
+ struct cnss_wlan_vreg_info *vreg_info;
+ struct cnss_wlan_gpio_info *gpio_info;
+ struct pci_dev *pdev;
+
+ if (!penv)
+ return;
+
+ wdrv = penv->driver;
+ vreg_info = &penv->vreg_info;
+ gpio_info = &penv->gpio_info;
+ pdev = penv->pdev;
+
+ if (!wdrv) {
+ pr_err("driver not registered\n");
+ return;
+ }
+
+ if (penv->bus_client)
+ msm_bus_scale_client_update_request(penv->bus_client,
+ CNSS_BUS_WIDTH_NONE);
+
+ if (!pdev) {
+ pr_err("%d: invalid pdev\n", __LINE__);
+ goto cut_power;
+ }
+
+ if (wdrv->remove)
+ wdrv->remove(pdev);
+
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
+
+ cnss_msm_pcie_deregister_event(&penv->event_reg);
+
+ if (penv->pcie_link_state && !penv->pcie_link_down_ind) {
+ pci_save_state(pdev);
+ penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+ if (cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS)) {
+ pr_err("Failed to shutdown PCIe link\n");
+ return;
+ }
+ } else if (penv->pcie_link_state && penv->pcie_link_down_ind) {
+ penv->saved_state = NULL;
+
+ if (cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+ pr_err("Failed to shutdown PCIe link (with linkdown option)\n");
+ return;
+ }
+ }
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+ penv->driver_status = CNSS_UNINITIALIZED;
+ penv->monitor_wake_intr = false;
+ atomic_set(&penv->auto_suspended, 0);
+
+cut_power:
+ penv->driver = NULL;
+
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+ pr_err("wlan vreg OFF failed\n");
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+#ifdef CONFIG_PCI_MSM
+int cnss_wlan_pm_control(bool vote)
+{
+ if (!penv || !penv->pdev)
+ return -ENODEV;
+
+ return cnss_msm_pcie_pm_control(
+ vote ? MSM_PCIE_DISABLE_PC : MSM_PCIE_ENABLE_PC,
+ cnss_get_pci_dev_bus_number(penv->pdev),
+ penv->pdev, PM_OPTIONS);
+}
+EXPORT_SYMBOL(cnss_wlan_pm_control);
+#endif
+
+void cnss_lock_pm_sem(void)
+{
+ down_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_lock_pm_sem);
+
+void cnss_release_pm_sem(void)
+{
+ up_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_release_pm_sem);
+
+void cnss_pci_schedule_recovery_work(void)
+{
+ schedule_work(&cnss_pci_recovery_work);
+}
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size)
+{
+ if (!penv || !penv->pldev)
+ return NULL;
+
+ *size = penv->ramdump_size;
+
+ return penv->ramdump_addr;
+}
+
+void cnss_pci_device_crashed(void)
+{
+ if (penv && penv->subsys) {
+ subsys_set_crash_status(penv->subsys, true);
+ subsystem_restart_dev(penv->subsys);
+ }
+}
+
+void *cnss_get_virt_ramdump_mem(unsigned long *size)
+{
+ if (!penv || !penv->pldev)
+ return NULL;
+
+ *size = penv->ramdump_size;
+
+ return penv->ramdump_addr;
+}
+EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
+
+void cnss_device_crashed(void)
+{
+ if (penv && penv->subsys) {
+ subsys_set_crash_status(penv->subsys, true);
+ subsystem_restart_dev(penv->subsys);
+ }
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+
+static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+ struct cnss_wlan_driver *wdrv;
+ struct pci_dev *pdev;
+ struct cnss_wlan_vreg_info *vreg_info;
+ struct cnss_wlan_gpio_info *gpio_info;
+ int ret = 0;
+
+ if (!penv)
+ return -ENODEV;
+
+ penv->recovery_in_progress = true;
+ wdrv = penv->driver;
+ pdev = penv->pdev;
+ vreg_info = &penv->vreg_info;
+ gpio_info = &penv->gpio_info;
+
+ if (!pdev) {
+ ret = -EINVAL;
+ goto cut_power;
+ }
+
+ if (wdrv && wdrv->shutdown)
+ wdrv->shutdown(pdev);
+
+ if (penv->pcie_link_state) {
+ if (cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+ pr_debug("cnss: Failed to shutdown PCIe link\n");
+ ret = -EFAULT;
+ }
+ penv->saved_state = NULL;
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+ }
+
+cut_power:
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+ pr_err("cnss: Failed to set WLAN VREG_OFF\n");
+
+ return ret;
+}
+
+static int cnss_powerup(const struct subsys_desc *subsys)
+{
+ struct cnss_wlan_driver *wdrv;
+ struct pci_dev *pdev;
+ struct cnss_wlan_vreg_info *vreg_info;
+ struct cnss_wlan_gpio_info *gpio_info;
+ int ret = 0;
+
+ if (!penv)
+ return -ENODEV;
+
+ if (!penv->driver)
+ goto out;
+
+ wdrv = penv->driver;
+ pdev = penv->pdev;
+ vreg_info = &penv->vreg_info;
+ gpio_info = &penv->gpio_info;
+
+ ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+ if (ret) {
+ pr_err("cnss: Failed to set WLAN VREG_ON\n");
+ goto err_wlan_vreg_on;
+ }
+
+ msleep(POWER_ON_DELAY);
+ cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+ /**
+ * Some platforms have wifi and other PCIE card attached with PCIE
+ * switch on the same RC like P5459 board(ROME 3.2 PCIE card + Ethernet
+ * PCI), it will need extra time to stable the signals when do SSR,
+ * otherwise fail to create the PCIE link, so add PCIE_SWITCH_DELAY.
+ */
+ msleep(PCIE_SWITCH_DELAY);
+
+ if (!pdev) {
+ pr_err("%d: invalid pdev\n", __LINE__);
+ goto err_pcie_link_up;
+ }
+
+ if (!penv->pcie_link_state) {
+ ret = cnss_msm_pcie_pm_control(
+ MSM_PCIE_RESUME,
+ cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+ if (ret) {
+ pr_err("cnss: Failed to bring-up PCIe link\n");
+ goto err_pcie_link_up;
+ }
+ penv->pcie_link_state = PCIE_LINK_UP;
+ ret = cnss_msm_pcie_recover_config(penv->pdev);
+ if (ret) {
+ pr_err("cnss: PCI link failed to recover\n");
+ goto err_pcie_link_up;
+ }
+ penv->pcie_link_down_ind = false;
+ }
+
+ if (wdrv && wdrv->reinit) {
+ if (penv->saved_state)
+ cnss_pci_load_and_free_saved_state(
+ pdev, &penv->saved_state);
+
+ pci_restore_state(pdev);
+
+ ret = wdrv->reinit(pdev, penv->id);
+ if (ret) {
+ pr_err("%d: Failed to do reinit\n", __LINE__);
+ goto err_wlan_reinit;
+ }
+ } else {
+ pr_err("%d: wdrv->reinit is invalid\n", __LINE__);
+ goto err_pcie_link_up;
+ }
+
+ if (penv->notify_modem_status && wdrv->modem_status)
+ wdrv->modem_status(pdev, penv->modem_current_status);
+
+out:
+ penv->recovery_in_progress = false;
+ return ret;
+
+err_wlan_reinit:
+ pci_save_state(pdev);
+ penv->saved_state = cnss_pci_store_saved_state(pdev);
+ cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND,
+ cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS);
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+
+err_pcie_link_up:
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+ if (penv->pdev) {
+ pr_err("%d: Unregistering pci device\n", __LINE__);
+ pci_unregister_driver(&cnss_wlan_pci_driver);
+ penv->pdev = NULL;
+ penv->pci_register_again = true;
+ }
+
+err_wlan_vreg_on:
+ return ret;
+}
+
+void cnss_pci_device_self_recovery(void)
+{
+ if (!penv)
+ return;
+
+ if (penv->recovery_in_progress) {
+ pr_err("cnss: Recovery already in progress\n");
+ return;
+ }
+
+ if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+ pr_err("cnss: load unload in progress\n");
+ return;
+ }
+
+ penv->recovery_count++;
+ penv->recovery_in_progress = true;
+ cnss_pm_wake_lock(&penv->ws);
+ cnss_shutdown(NULL, false);
+ msleep(WLAN_RECOVERY_DELAY);
+ cnss_powerup(NULL);
+ cnss_pm_wake_lock_release(&penv->ws);
+ penv->recovery_in_progress = false;
+}
+
+static int cnss_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct ramdump_segment segment;
+
+ if (!penv)
+ return -ENODEV;
+
+ if (!penv->ramdump_size)
+ return -ENOENT;
+
+ if (!enable)
+ return 0;
+
+ memset(&segment, 0, sizeof(segment));
+ segment.v_address = penv->ramdump_addr;
+ segment.size = penv->ramdump_size;
+
+ return do_ramdump(penv->ramdump_dev, &segment, 1);
+}
+
+static void cnss_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct cnss_wlan_driver *wdrv;
+ struct pci_dev *pdev;
+
+ if (!penv)
+ return;
+
+ wdrv = penv->driver;
+ pdev = penv->pdev;
+
+ if (pdev && wdrv && wdrv->crash_shutdown)
+ wdrv->crash_shutdown(pdev);
+}
+
+void cnss_device_self_recovery(void)
+{
+ if (!penv)
+ return;
+
+ if (penv->recovery_in_progress) {
+ pr_err("cnss: Recovery already in progress\n");
+ return;
+ }
+ if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+ pr_err("cnss: load unload in progress\n");
+ return;
+ }
+ penv->recovery_count++;
+ penv->recovery_in_progress = true;
+ cnss_pm_wake_lock(&penv->ws);
+ cnss_shutdown(NULL, false);
+ msleep(WLAN_RECOVERY_DELAY);
+ cnss_powerup(NULL);
+ cnss_pm_wake_lock_release(&penv->ws);
+ penv->recovery_in_progress = false;
+}
+EXPORT_SYMBOL(cnss_device_self_recovery);
+
+static int cnss_modem_notifier_nb(struct notifier_block *this,
+ unsigned long code,
+ void *ss_handle)
+{
+ struct cnss_wlan_driver *wdrv;
+ struct pci_dev *pdev;
+
+ pr_debug("%s: Modem-Notify: event %lu\n", __func__, code);
+
+ if (!penv)
+ return NOTIFY_DONE;
+
+ if (code == SUBSYS_AFTER_POWERUP)
+ penv->modem_current_status = 1;
+ else if (code == SUBSYS_BEFORE_SHUTDOWN)
+ penv->modem_current_status = 0;
+ else
+ return NOTIFY_DONE;
+
+ wdrv = penv->driver;
+ pdev = penv->pdev;
+
+ if (!wdrv || !pdev || !wdrv->modem_status)
+ return NOTIFY_DONE;
+
+ wdrv->modem_status(pdev, penv->modem_current_status);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block mnb = {
+ .notifier_call = cnss_modem_notifier_nb,
+};
+
+static int cnss_init_dump_entry(void)
+{
+ struct msm_dump_entry dump_entry;
+
+ if (!penv)
+ return -ENODEV;
+
+ if (!penv->ramdump_dynamic)
+ return 0;
+
+ penv->dump_data.addr = penv->ramdump_phys;
+ penv->dump_data.len = penv->ramdump_size;
+ penv->dump_data.version = CNSS_DUMP_FORMAT_VER;
+ penv->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+ strlcpy(penv->dump_data.name, CNSS_DUMP_NAME,
+ sizeof(penv->dump_data.name));
+ dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+ dump_entry.addr = virt_to_phys(&penv->dump_data);
+
+ return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+}
+
+static int cnss_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct esoc_desc *desc;
+ const char *client_desc;
+ struct device *dev = &pdev->dev;
+ u32 rc_num;
+ struct resource *res;
+ u32 ramdump_size = 0;
+ u32 smmu_iova_address[2];
+
+ if (penv)
+ return -ENODEV;
+
+ penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL);
+ if (!penv)
+ return -ENOMEM;
+
+ penv->pldev = pdev;
+ penv->esoc_desc = NULL;
+
+ penv->gpio_info.name = WLAN_EN_GPIO_NAME;
+ penv->gpio_info.num = 0;
+ penv->gpio_info.state = WLAN_EN_LOW;
+ penv->gpio_info.init = WLAN_EN_LOW;
+ penv->gpio_info.prop = false;
+ penv->vreg_info.wlan_reg = NULL;
+ penv->vreg_info.state = VREG_OFF;
+ penv->pci_register_again = false;
+ mutex_init(&penv->fw_setup_stat_lock);
+
+ ret = cnss_wlan_get_resources(pdev);
+ if (ret)
+ goto err_get_wlan_res;
+
+ ret = cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+ if (ret) {
+ pr_err("%s: Failed to enable WLAN enable gpio\n", __func__);
+ goto err_get_rc;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num);
+ if (ret) {
+ pr_err("%s: Failed to find PCIe RC number\n", __func__);
+ goto err_get_rc;
+ }
+
+ ret = cnss_msm_pcie_enumerate(rc_num);
+ if (ret) {
+ pr_err("%s: Failed to enable PCIe RC%x\n", __func__, rc_num);
+ goto err_pcie_enumerate;
+ }
+
+ penv->pcie_link_state = PCIE_LINK_UP;
+
+ penv->notify_modem_status =
+ of_property_read_bool(dev->of_node,
+ "qcom,notify-modem-status");
+
+ if (penv->notify_modem_status) {
+ ret = of_property_read_string_index(dev->of_node, "esoc-names",
+ 0, &client_desc);
+ if (ret) {
+ pr_debug("%s: esoc-names is not defined in DT, SKIP\n",
+ __func__);
+ } else {
+ desc = devm_register_esoc_client(dev, client_desc);
+ if (IS_ERR_OR_NULL(desc)) {
+ ret = PTR_RET(desc);
+ pr_err("%s: can't find esoc desc\n", __func__);
+ goto err_esoc_reg;
+ }
+ penv->esoc_desc = desc;
+ }
+ }
+
+ penv->subsysdesc.name = "AR6320";
+ penv->subsysdesc.owner = THIS_MODULE;
+ penv->subsysdesc.shutdown = cnss_shutdown;
+ penv->subsysdesc.powerup = cnss_powerup;
+ penv->subsysdesc.ramdump = cnss_ramdump;
+ penv->subsysdesc.crash_shutdown = cnss_crash_shutdown;
+ penv->subsysdesc.dev = &pdev->dev;
+ penv->subsys = subsys_register(&penv->subsysdesc);
+ if (IS_ERR(penv->subsys)) {
+ ret = PTR_ERR(penv->subsys);
+ goto err_subsys_reg;
+ }
+
+ penv->subsys_handle = subsystem_get(penv->subsysdesc.name);
+
+ if (of_property_read_bool(dev->of_node, "qcom,is-dual-wifi-enabled"))
+ penv->dual_wifi_info.is_dual_wifi_enabled = true;
+
+ if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+ &ramdump_size) == 0) {
+ penv->ramdump_addr = dma_alloc_coherent(&pdev->dev,
+ ramdump_size, &penv->ramdump_phys, GFP_KERNEL);
+
+ if (penv->ramdump_addr)
+ penv->ramdump_size = ramdump_size;
+ penv->ramdump_dynamic = true;
+ } else {
+ res = platform_get_resource_byname(penv->pldev,
+ IORESOURCE_MEM, "ramdump");
+ if (res) {
+ penv->ramdump_phys = res->start;
+ ramdump_size = resource_size(res);
+ penv->ramdump_addr = ioremap(penv->ramdump_phys,
+ ramdump_size);
+
+ if (penv->ramdump_addr)
+ penv->ramdump_size = ramdump_size;
+
+ penv->ramdump_dynamic = false;
+ }
+ }
+
+ pr_debug("%s: ramdump addr: %p, phys: %pa\n", __func__,
+ penv->ramdump_addr, &penv->ramdump_phys);
+
+ if (penv->ramdump_size == 0) {
+ pr_info("%s: CNSS ramdump will not be collected\n", __func__);
+ goto skip_ramdump;
+ }
+
+ ret = cnss_init_dump_entry();
+ if (ret) {
+ pr_err("%s: Dump table setup failed: %d\n", __func__, ret);
+ goto err_ramdump_create;
+ }
+
+ penv->ramdump_dev = create_ramdump_device(penv->subsysdesc.name,
+ penv->subsysdesc.dev);
+ if (!penv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump_create;
+ }
+
+skip_ramdump:
+ penv->modem_current_status = 0;
+
+ if (penv->notify_modem_status) {
+ penv->modem_notify_handler =
+ subsys_notif_register_notifier(penv->esoc_desc ?
+ penv->esoc_desc->name :
+ "modem", &mnb);
+ if (IS_ERR(penv->modem_notify_handler)) {
+ ret = PTR_ERR(penv->modem_notify_handler);
+ pr_err("%s: Register notifier Failed\n", __func__);
+ goto err_notif_modem;
+ }
+ }
+
+ if (of_property_read_u32_array(dev->of_node,
+ "qcom,wlan-smmu-iova-address",
+ smmu_iova_address, 2) == 0) {
+ penv->smmu_iova_start = smmu_iova_address[0];
+ penv->smmu_iova_len = smmu_iova_address[1];
+ }
+
+ ret = pci_register_driver(&cnss_wlan_pci_driver);
+ if (ret)
+ goto err_pci_reg;
+
+ penv->bus_scale_table = 0;
+ penv->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+
+ if (penv->bus_scale_table) {
+ penv->bus_client =
+ msm_bus_scale_register_client(penv->bus_scale_table);
+
+ if (!penv->bus_client) {
+ pr_err("Failed to register with bus_scale client\n");
+ goto err_bus_reg;
+ }
+ }
+ cnss_pm_wake_lock_init(&penv->ws, "cnss_wlock");
+
+ register_pm_notifier(&cnss_pm_notifier);
+
+#ifdef CONFIG_CNSS_MAC_BUG
+ /* 0-4K memory is reserved for QCA6174 to address a MAC HW bug.
+ * MAC would do an invalid pointer fetch based on the data
+ * that was read from 0 to 4K. So fill it with zero's (to an
+ * address for which PCIe RC honored the read without any errors).
+ */
+ memset(phys_to_virt(0), 0, SZ_4K);
+#endif
+
+ ret = device_create_file(dev, &dev_attr_fw_image_setup);
+ if (ret) {
+ pr_err("cnss: fw_image_setup sys file creation failed\n");
+ goto err_bus_reg;
+ }
+ pr_debug("cnss: Platform driver probed successfully.\n");
+ return ret;
+
+err_bus_reg:
+ if (penv->bus_scale_table)
+ msm_bus_cl_clear_pdata(penv->bus_scale_table);
+ pci_unregister_driver(&cnss_wlan_pci_driver);
+
+err_pci_reg:
+ if (penv->notify_modem_status)
+ subsys_notif_unregister_notifier
+ (penv->modem_notify_handler, &mnb);
+
+err_notif_modem:
+ if (penv->ramdump_dev)
+ destroy_ramdump_device(penv->ramdump_dev);
+
+err_ramdump_create:
+ if (penv->ramdump_addr) {
+ if (penv->ramdump_dynamic) {
+ dma_free_coherent(&pdev->dev, penv->ramdump_size,
+ penv->ramdump_addr,
+ penv->ramdump_phys);
+ } else {
+ iounmap(penv->ramdump_addr);
+ }
+ }
+
+ if (penv->subsys_handle)
+ subsystem_put(penv->subsys_handle);
+
+ subsys_unregister(penv->subsys);
+
+err_subsys_reg:
+ if (penv->esoc_desc)
+ devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+
+err_esoc_reg:
+err_pcie_enumerate:
+err_get_rc:
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ cnss_wlan_release_resources();
+
+err_get_wlan_res:
+ penv = NULL;
+
+ return ret;
+}
+
+static int cnss_remove(struct platform_device *pdev)
+{
+ unregister_pm_notifier(&cnss_pm_notifier);
+ device_remove_file(&pdev->dev, &dev_attr_fw_image_setup);
+
+ cnss_pm_wake_lock_destroy(&penv->ws);
+
+ if (penv->bus_client)
+ msm_bus_scale_unregister_client(penv->bus_client);
+
+ if (penv->bus_scale_table)
+ msm_bus_cl_clear_pdata(penv->bus_scale_table);
+
+ if (penv->ramdump_addr) {
+ if (penv->ramdump_dynamic) {
+ dma_free_coherent(&pdev->dev, penv->ramdump_size,
+ penv->ramdump_addr,
+ penv->ramdump_phys);
+ } else {
+ iounmap(penv->ramdump_addr);
+ }
+ }
+
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ if (penv->wlan_bootstrap_gpio > 0)
+ gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+ cnss_wlan_release_resources();
+
+ return 0;
+}
+
+static const struct of_device_id cnss_dt_match[] = {
+ {.compatible = "qcom,cnss"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, cnss_dt_match);
+
+static struct platform_driver cnss_driver = {
+ .probe = cnss_probe,
+ .remove = cnss_remove,
+ .driver = {
+ .name = "cnss",
+ .owner = THIS_MODULE,
+ .of_match_table = cnss_dt_match,
+#ifdef CONFIG_CNSS_ASYNC
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+ },
+};
+
+static int __init cnss_initialize(void)
+{
+ return platform_driver_register(&cnss_driver);
+}
+
+static void __exit cnss_exit(void)
+{
+ struct platform_device *pdev = penv->pldev;
+
+ if (penv->ramdump_dev)
+ destroy_ramdump_device(penv->ramdump_dev);
+ if (penv->notify_modem_status)
+ subsys_notif_unregister_notifier(penv->modem_notify_handler,
+ &mnb);
+ subsys_unregister(penv->subsys);
+ if (penv->esoc_desc)
+ devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+ platform_driver_unregister(&cnss_driver);
+}
+
+void cnss_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+ if (!penv) {
+ pr_err("%s: penv is NULL\n", __func__);
+ return;
+ }
+
+ pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos_type);
+
+void cnss_request_pm_qos(u32 qos_val)
+{
+ if (!penv) {
+ pr_err("%s: penv is NULL\n", __func__);
+ return;
+ }
+
+ pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos);
+
+void cnss_remove_pm_qos(void)
+{
+ if (!penv) {
+ pr_err("%s: penv is NULL\n", __func__);
+ return;
+ }
+
+ pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_remove_pm_qos);
+
+void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+ if (!penv) {
+ pr_err("%s: penv is NULL\n", __func__);
+ return;
+ }
+
+ pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos_type);
+
+void cnss_pci_request_pm_qos(u32 qos_val)
+{
+ if (!penv) {
+ pr_err("%s: penv is NULL\n", __func__);
+ return;
+ }
+
+ pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos);
+
+void cnss_pci_remove_pm_qos(void)
+{
+ if (!penv) {
+ pr_err("%s: penv is NULL\n", __func__);
+ return;
+ }
+
+ pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_pci_remove_pm_qos);
+
+int cnss_pci_request_bus_bandwidth(int bandwidth)
+{
+ int ret = 0;
+
+ if (!penv)
+ return -ENODEV;
+
+ if (!penv->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(
+ penv->bus_client, bandwidth);
+ if (!ret) {
+ penv->current_bandwidth_vote = bandwidth;
+ } else {
+ pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+ __func__, bandwidth, ret);
+ }
+ break;
+
+ default:
+ pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+int cnss_request_bus_bandwidth(int bandwidth)
+{
+ int ret = 0;
+
+ if (!penv)
+ return -ENODEV;
+
+ if (!penv->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(
+ penv->bus_client, bandwidth);
+ if (!ret) {
+ penv->current_bandwidth_vote = bandwidth;
+ } else {
+ pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+ __func__, bandwidth, ret);
+ }
+ break;
+
+ default:
+ pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cnss_request_bus_bandwidth);
+
+int cnss_get_platform_cap(struct cnss_platform_cap *cap)
+{
+ if (!penv)
+ return -ENODEV;
+
+ if (cap)
+ *cap = penv->cap;
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_platform_cap);
+
+void cnss_set_driver_status(enum cnss_driver_status driver_status)
+{
+ penv->driver_status = driver_status;
+}
+EXPORT_SYMBOL(cnss_set_driver_status);
+
+int cnss_get_bmi_setup(void)
+{
+ if (!penv)
+ return -ENODEV;
+
+ return penv->bmi_test;
+}
+EXPORT_SYMBOL(cnss_get_bmi_setup);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+int cnss_get_sha_hash(const u8 *data, u32 data_len, u8 *hash_idx, u8 *out)
+{
+ struct scatterlist sg;
+ struct hash_desc desc;
+ int ret = 0;
+
+ if (!out) {
+ pr_err("memory for output buffer is not allocated\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ desc.tfm = crypto_alloc_hash(hash_idx, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(desc.tfm)) {
+ pr_err("crypto_alloc_hash failed:%ld\n", PTR_ERR(desc.tfm));
+ ret = PTR_ERR(desc.tfm);
+ goto end;
+ }
+
+ sg_init_one(&sg, data, data_len);
+ ret = crypto_hash_digest(&desc, &sg, sg.length, out);
+ crypto_free_hash(desc.tfm);
+end:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_get_sha_hash);
+
+void *cnss_get_fw_ptr(void)
+{
+ if (!penv)
+ return NULL;
+
+ return penv->fw_mem;
+}
+EXPORT_SYMBOL(cnss_get_fw_ptr);
+#endif
+
+int cnss_auto_suspend(void)
+{
+ int ret = 0;
+ struct pci_dev *pdev;
+
+ if (!penv || !penv->driver)
+ return -ENODEV;
+
+ pdev = penv->pdev;
+
+ if (penv->pcie_link_state) {
+ pci_save_state(pdev);
+ penv->saved_state = cnss_pci_store_saved_state(pdev);
+ pci_disable_device(pdev);
+ ret = pci_set_power_state(pdev, PCI_D3hot);
+ if (ret)
+ pr_err("%s: Set D3Hot failed: %d\n", __func__, ret);
+ if (cnss_msm_pcie_pm_control(
+ MSM_PCIE_SUSPEND,
+ cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS)) {
+ pr_err("%s: Failed to shutdown PCIe link\n", __func__);
+ ret = -EAGAIN;
+ goto out;
+ }
+ }
+ atomic_set(&penv->auto_suspended, 1);
+ penv->monitor_wake_intr = true;
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+
+ msm_bus_scale_client_update_request(penv->bus_client,
+ CNSS_BUS_WIDTH_NONE);
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_auto_suspend);
+
+int cnss_auto_resume(void)
+{
+ int ret = 0;
+ struct pci_dev *pdev;
+
+ if (!penv || !penv->driver)
+ return -ENODEV;
+
+ pdev = penv->pdev;
+ if (!penv->pcie_link_state) {
+ if (cnss_msm_pcie_pm_control(
+ MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+ pdev, PM_OPTIONS)) {
+ pr_err("%s: Failed to resume PCIe link\n", __func__);
+ ret = -EAGAIN;
+ goto out;
+ }
+ ret = pci_enable_device(pdev);
+ if (ret)
+ pr_err("%s: enable device failed: %d\n", __func__, ret);
+ penv->pcie_link_state = PCIE_LINK_UP;
+ }
+
+ if (penv->saved_state)
+ cnss_pci_load_and_free_saved_state(pdev, &penv->saved_state);
+
+ pci_restore_state(pdev);
+ pci_set_master(pdev);
+
+ atomic_set(&penv->auto_suspended, 0);
+
+ msm_bus_scale_client_update_request(penv->bus_client,
+ penv->current_bandwidth_vote);
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cnss_auto_resume);
+
+int cnss_pm_runtime_request(struct device *dev,
+ enum cnss_runtime_request request)
+{
+ int ret = 0;
+
+ switch (request) {
+ case CNSS_PM_RUNTIME_GET:
+ ret = pm_runtime_get(dev);
+ break;
+ case CNSS_PM_RUNTIME_PUT:
+ ret = pm_runtime_put(dev);
+ break;
+ case CNSS_PM_RUNTIME_MARK_LAST_BUSY:
+ pm_runtime_mark_last_busy(dev);
+ break;
+ case CNSS_PM_RUNTIME_RESUME:
+ ret = pm_runtime_resume(dev);
+ break;
+ case CNSS_PM_RUNTIME_PUT_AUTO:
+ ret = pm_runtime_put_autosuspend(dev);
+ break;
+ case CNSS_PM_RUNTIME_PUT_NOIDLE:
+ pm_runtime_put_noidle(dev);
+ break;
+ case CNSS_PM_REQUEST_RESUME:
+ ret = pm_request_resume(dev);
+ break;
+ case CNSS_PM_GET_NORESUME:
+ pm_runtime_get_noresume(dev);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(cnss_pm_runtime_request);
+
+void cnss_runtime_init(struct device *dev, int auto_delay)
+{
+ pm_runtime_set_autosuspend_delay(dev, auto_delay);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_allow(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_noidle(dev);
+ pm_suspend_ignore_children(dev, true);
+}
+EXPORT_SYMBOL(cnss_runtime_init);
+
+void cnss_runtime_exit(struct device *dev)
+{
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+}
+EXPORT_SYMBOL(cnss_runtime_exit);
+
+static void __cnss_set_pcie_monitor_intr(struct device *dev, bool val)
+{
+ penv->monitor_wake_intr = val;
+}
+
+static void __cnss_set_auto_suspend(struct device *dev, int val)
+{
+ atomic_set(&penv->auto_suspended, val);
+}
+
+static int __cnss_resume_link(struct device *dev, u32 flags)
+{
+ int ret;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+
+ ret = cnss_msm_pcie_pm_control(MSM_PCIE_RESUME, bus_num, pdev, flags);
+ if (ret)
+ pr_err("%s: PCIe link resume failed with flags:%d bus_num:%d\n",
+ __func__, flags, bus_num);
+
+ penv->pcie_link_state = PCIE_LINK_UP;
+
+ return ret;
+}
+
+static int __cnss_suspend_link(struct device *dev, u32 flags)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+ int ret;
+
+ if (!penv->pcie_link_state)
+ return 0;
+
+ ret = cnss_msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus_num, pdev, flags);
+ if (ret) {
+ pr_err("%s: Failed to suspend link\n", __func__);
+ return ret;
+ }
+
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+
+ return ret;
+}
+
+static int __cnss_pcie_recover_config(struct device *dev)
+{
+ int ret;
+
+ ret = cnss_msm_pcie_recover_config(to_pci_dev(dev));
+ if (ret)
+ pr_err("%s: PCIe Recover config failed\n", __func__);
+
+ return ret;
+}
+
+static int __cnss_event_reg(struct device *dev)
+{
+ int ret;
+ struct msm_pcie_register_event *event_reg;
+
+ event_reg = &penv->event_reg;
+
+ event_reg->events = MSM_PCIE_EVENT_LINKDOWN |
+ MSM_PCIE_EVENT_WAKEUP;
+ event_reg->user = to_pci_dev(dev);
+ event_reg->mode = MSM_PCIE_TRIGGER_CALLBACK;
+ event_reg->callback = cnss_pci_events_cb;
+ event_reg->options = MSM_PCIE_CONFIG_NO_RECOVERY;
+
+ ret = cnss_msm_pcie_register_event(event_reg);
+ if (ret)
+ pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+ return ret;
+}
+
+static void __cnss_event_dereg(struct device *dev)
+{
+ cnss_msm_pcie_deregister_event(&penv->event_reg);
+}
+
+static struct pci_dev *__cnss_get_pcie_dev(struct device *dev)
+{
+ int ret;
+ struct pci_dev *pdev = penv->pdev;
+
+ if (pdev)
+ return pdev;
+
+ ret = pci_register_driver(&cnss_wlan_pci_driver);
+ if (ret) {
+ pr_err("%s: pci re-registration failed\n", __func__);
+ return NULL;
+ }
+
+ pdev = penv->pdev;
+
+ return pdev;
+}
+
+static int __cnss_pcie_power_up(struct device *dev)
+{
+ struct cnss_wlan_vreg_info *vreg_info;
+ struct cnss_wlan_gpio_info *gpio_info;
+ int ret;
+
+ vreg_info = &penv->vreg_info;
+ gpio_info = &penv->gpio_info;
+
+ ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+ if (ret) {
+ pr_err("%s: WLAN VREG ON Failed\n", __func__);
+ return ret;
+ }
+
+ msleep(POWER_ON_DELAY);
+
+ if (penv->wlan_bootstrap_gpio > 0) {
+ gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+ msleep(WLAN_BOOTSTRAP_DELAY);
+ }
+
+ cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+ return 0;
+}
+
+static int __cnss_pcie_power_down(struct device *dev)
+{
+ struct cnss_wlan_vreg_info *vreg_info;
+ struct cnss_wlan_gpio_info *gpio_info;
+ int ret;
+
+ vreg_info = &penv->vreg_info;
+ gpio_info = &penv->gpio_info;
+
+ cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+ if (penv->wlan_bootstrap_gpio > 0)
+ gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+
+ ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+ if (ret)
+ pr_err("%s: Failed to turn off 3.3V regulator\n", __func__);
+
+ return ret;
+}
+
+static int __cnss_suspend_link_state(struct device *dev)
+{
+ int ret;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int link_ind;
+
+ if (!penv->pcie_link_state) {
+ pr_debug("%s: Link is already suspended\n", __func__);
+ return 0;
+ }
+
+ link_ind = penv->pcie_link_down_ind;
+
+ if (!link_ind)
+ pci_save_state(pdev);
+
+ penv->saved_state = link_ind ? NULL : cnss_pci_store_saved_state(pdev);
+
+ ret = link_ind ? __cnss_suspend_link(dev, PM_OPTIONS_SUSPEND_LINK_DOWN)
+ : __cnss_suspend_link(dev, PM_OPTIONS);
+ if (ret) {
+ pr_err("%s: Link Suspend failed in state:%s\n", __func__,
+ link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+ return ret;
+ }
+
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+
+ return 0;
+}
+
+static int __cnss_restore_pci_config_space(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int ret = 0;
+
+ if (penv->saved_state)
+ ret = cnss_pci_load_and_free_saved_state(pdev,
+ &penv->saved_state);
+ pci_restore_state(pdev);
+
+ return ret;
+}
+
+static int __cnss_resume_link_state(struct device *dev)
+{
+ int ret;
+ int link_ind;
+
+ if (penv->pcie_link_state) {
+ pr_debug("%s: Link is already in active state\n", __func__);
+ return 0;
+ }
+
+ link_ind = penv->pcie_link_down_ind;
+
+ ret = link_ind ? __cnss_resume_link(dev, PM_OPTIONS_RESUME_LINK_DOWN) :
+ __cnss_resume_link(dev, PM_OPTIONS);
+
+ if (ret) {
+ pr_err("%s: Resume Link failed in link state:%s\n", __func__,
+ link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+ return ret;
+ }
+
+ penv->pcie_link_state = PCIE_LINK_UP;
+
+ ret = link_ind ? __cnss_pcie_recover_config(dev) :
+ __cnss_restore_pci_config_space(dev);
+
+ if (ret) {
+ pr_err("%s: Link Recovery Config Failed link_state:%s\n",
+ __func__, link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+ penv->pcie_link_state = PCIE_LINK_DOWN;
+ return ret;
+ }
+
+ penv->pcie_link_down_ind = false;
+ return ret;
+}
+
+int cnss_pcie_power_up(struct device *dev)
+{
+ int ret;
+ struct pci_dev *pdev;
+
+ if (!penv) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ ret = __cnss_pcie_power_up(dev);
+ if (ret) {
+ pr_err("%s: Power UP Failed\n", __func__);
+ return ret;
+ }
+
+ pdev = __cnss_get_pcie_dev(dev);
+ if (!pdev) {
+ pr_err("%s: PCIe Dev is NULL\n", __func__);
+ goto power_down;
+ }
+
+ ret = __cnss_event_reg(dev);
+
+ if (ret)
+ pr_err("%s: PCIe event registration failed\n", __func__);
+
+ ret = __cnss_resume_link_state(dev);
+
+ if (ret) {
+ pr_err("%s: Link Bring Up Failed\n", __func__);
+ goto event_dereg;
+ }
+
+ __cnss_set_pcie_monitor_intr(dev, true);
+
+ return ret;
+
+event_dereg:
+ __cnss_event_dereg(dev);
+power_down:
+ __cnss_pcie_power_down(dev);
+ pr_err("%s: Device Power Up Failed Fatal Error\n", __func__);
+ return ret;
+}
+
+static void __cnss_vote_bus_width(struct device *dev, u32 option)
+{
+ if (penv->bus_client)
+ msm_bus_scale_client_update_request(penv->bus_client, option);
+}
+
+int cnss_pcie_power_down(struct device *dev)
+{
+ int ret;
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ if (!penv) {
+ pr_err("%s: Invalid Platform data\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!pdev) {
+ pr_err("%s: Invalid Pdev, Cut Power to device\n", __func__);
+ __cnss_pcie_power_down(dev);
+ return -ENODEV;
+ }
+
+ __cnss_vote_bus_width(dev, CNSS_BUS_WIDTH_NONE);
+ __cnss_event_dereg(dev);
+
+ ret = __cnss_suspend_link_state(dev);
+
+ if (ret) {
+ pr_err("%s: Suspend Link failed\n", __func__);
+ return ret;
+ }
+
+ __cnss_set_pcie_monitor_intr(dev, false);
+ __cnss_set_auto_suspend(dev, 0);
+
+ ret = __cnss_pcie_power_down(dev);
+ if (ret)
+ pr_err("%s: Power Down Failed\n", __func__);
+
+ return ret;
+}
+
+module_init(cnss_initialize);
+module_exit(cnss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS Driver");
diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c
new file mode 100644
index 0000000..c35ba38
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_sdio.c
@@ -0,0 +1,1564 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "cnss_sdio:%s:%d:: " fmt, __func__, __LINE__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <linux/pm_qos.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#define WLAN_VREG_NAME "vdd-wlan"
+#define WLAN_VREG_DSRC_NAME "vdd-wlan-dsrc"
+#define WLAN_VREG_IO_NAME "vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME "vdd-wlan-xtal"
+#define WLAN_GPIO_CAPTSF_NAME "qcom,cap-tsf-gpio"
+
+#define WLAN_VREG_IO_MAX 1800000
+#define WLAN_VREG_IO_MIN 1800000
+#define WLAN_VREG_XTAL_MAX 1800000
+#define WLAN_VREG_XTAL_MIN 1800000
+#define POWER_ON_DELAY 4
+
+/* Values for Dynamic Ramdump Collection*/
+#define CNSS_DUMP_FORMAT_VER 0x11
+#define CNSS_DUMP_MAGIC_VER_V2 0x42445953
+#define CNSS_DUMP_NAME "CNSS_WLAN_SDIO"
+#define CNSS_PINCTRL_SLEEP_STATE "sleep"
+#define CNSS_PINCTRL_ACTIVE_STATE "active"
+
+#define CNSS_HW_SLEEP 0
+#define CNSS_HW_ACTIVE 1
+
+struct cnss_sdio_regulator {
+ struct regulator *wlan_io;
+ struct regulator *wlan_xtal;
+ struct regulator *wlan_vreg;
+ struct regulator *wlan_vreg_dsrc;
+};
+
+struct cnss_sdio_info {
+ struct cnss_sdio_wlan_driver *wdrv;
+ struct sdio_func *func;
+ struct mmc_card *card;
+ struct mmc_host *host;
+ struct device *dev;
+ const struct sdio_device_id *id;
+ bool skip_wlan_en_toggle;
+ bool cnss_hw_state;
+ struct cnss_cap_tsf_info cap_tsf_info;
+};
+
+struct cnss_ssr_info {
+ struct subsys_device *subsys;
+ struct subsys_desc subsysdesc;
+ void *subsys_handle;
+ struct ramdump_device *ramdump_dev;
+ unsigned long ramdump_size;
+ void *ramdump_addr;
+ phys_addr_t ramdump_phys;
+ struct msm_dump_data dump_data;
+ bool ramdump_dynamic;
+ char subsys_name[10];
+};
+
+struct cnss_wlan_pinctrl_info {
+ bool is_antenna_shared;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *sleep;
+ struct pinctrl_state *active;
+};
+
+struct cnss_sdio_bus_bandwidth {
+ struct msm_bus_scale_pdata *bus_scale_table;
+ u32 bus_client;
+ int current_bandwidth_vote;
+};
+
+static struct cnss_sdio_data {
+ struct cnss_sdio_regulator regulator;
+ struct platform_device *pdev;
+ struct cnss_sdio_info cnss_sdio_info;
+ struct cnss_ssr_info ssr_info;
+ struct pm_qos_request qos_request;
+ struct cnss_wlan_pinctrl_info pinctrl_info;
+ struct cnss_sdio_bus_bandwidth bus_bandwidth;
+ struct cnss_dev_platform_ops platform_ops;
+} *cnss_pdata;
+
+#define WLAN_RECOVERY_DELAY 1
+/* cnss sdio subsytem device name, required property */
+#define CNSS_SUBSYS_NAME_KEY "subsys-name"
+
+/* SDIO manufacturer ID and Codes */
+#define MANUFACTURER_ID_AR6320_BASE 0x500
+#define MANUFACTURER_ID_QCA9377_BASE 0x700
+#define MANUFACTURER_CODE 0x271
+
+static const struct sdio_device_id ar6k_id_table[] = {
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))},
+ {},
+};
+MODULE_DEVICE_TABLE(sdio, ar6k_id_table);
+
+void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+ if (!cnss_pdata)
+ return;
+
+ pr_debug("PM QoS value: %d\n", qos_val);
+ pm_qos_add_request(&cnss_pdata->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos_type);
+
+int cnss_sdio_request_bus_bandwidth(int bandwidth)
+{
+ int ret;
+ struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ bus_bandwidth = &cnss_pdata->bus_bandwidth;
+ if (!bus_bandwidth->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_bandwidth->bus_client, bandwidth);
+ if (!ret) {
+ bus_bandwidth->current_bandwidth_vote = bandwidth;
+ } else {
+ pr_debug(
+ "could not set bus bandwidth %d, ret = %d\n",
+ bandwidth, ret);
+ }
+ break;
+ default:
+ pr_debug("Invalid request %d\n", bandwidth);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+void cnss_sdio_request_pm_qos(u32 qos_val)
+{
+ if (!cnss_pdata)
+ return;
+
+ pr_debug("PM QoS value: %d\n", qos_val);
+ pm_qos_add_request(
+ &cnss_pdata->qos_request,
+ PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos);
+
+void cnss_sdio_remove_pm_qos(void)
+{
+ if (!cnss_pdata)
+ return;
+
+ pm_qos_remove_request(&cnss_pdata->qos_request);
+ pr_debug("PM QoS removed\n");
+}
+EXPORT_SYMBOL(cnss_sdio_remove_pm_qos);
+
+static int cnss_put_hw_resources(struct device *dev)
+{
+ int ret = -EINVAL;
+ struct cnss_sdio_info *info;
+ struct mmc_host *host;
+
+ if (!cnss_pdata)
+ return ret;
+
+ info = &cnss_pdata->cnss_sdio_info;
+
+ if (info->skip_wlan_en_toggle) {
+ pr_debug("HW doesn't support wlan toggling\n");
+ return 0;
+ }
+
+ if (info->cnss_hw_state == CNSS_HW_SLEEP) {
+ pr_debug("HW resources are already released\n");
+ return 0;
+ }
+
+ host = info->host;
+
+ if (!host) {
+ pr_err("MMC host is invalid\n");
+ return ret;
+ }
+
+ if (!cnss_pdata->regulator.wlan_vreg) {
+ pr_debug("wlan_vreg regulator is invalid\n");
+ return 0;
+ }
+
+ ret = mmc_power_save_host(host);
+ if (ret) {
+ pr_err("Failed to Power Save Host err:%d\n",
+ ret);
+ return ret;
+ }
+
+ regulator_disable(cnss_pdata->regulator.wlan_vreg);
+ info->cnss_hw_state = CNSS_HW_SLEEP;
+
+ return ret;
+}
+
+static int cnss_get_hw_resources(struct device *dev)
+{
+ int ret = -EINVAL;
+ struct mmc_host *host;
+ struct cnss_sdio_info *info;
+
+ if (!cnss_pdata)
+ return ret;
+
+ info = &cnss_pdata->cnss_sdio_info;
+
+ if (info->skip_wlan_en_toggle) {
+ pr_debug("HW doesn't support wlan toggling\n");
+ return 0;
+ }
+
+ if (info->cnss_hw_state == CNSS_HW_ACTIVE) {
+ pr_debug("HW resources are already active\n");
+ return 0;
+ }
+
+ host = info->host;
+
+ if (!host) {
+ pr_err("MMC Host is Invalid; Enumeration Failed\n");
+ return ret;
+ }
+
+ if (!cnss_pdata->regulator.wlan_vreg) {
+ pr_debug("wlan_vreg regulator is invalid\n");
+ return 0;
+ }
+
+ ret = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+ if (ret) {
+ pr_err("Failed to enable wlan vreg\n");
+ return ret;
+ }
+
+ ret = mmc_power_restore_host(host);
+ if (ret) {
+ pr_err("Failed to restore host power ret:%d\n",
+ ret);
+ regulator_disable(cnss_pdata->regulator.wlan_vreg);
+ return ret;
+ }
+
+ info->cnss_hw_state = CNSS_HW_ACTIVE;
+ return ret;
+}
+
+static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+ struct cnss_sdio_info *cnss_info;
+ struct cnss_sdio_wlan_driver *wdrv;
+ int ret = 0;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ cnss_info = &cnss_pdata->cnss_sdio_info;
+ wdrv = cnss_info->wdrv;
+ if (!wdrv)
+ return 0;
+ if (!wdrv->shutdown)
+ return 0;
+
+ wdrv->shutdown(cnss_info->func);
+ ret = cnss_put_hw_resources(cnss_info->dev);
+
+ if (ret)
+ pr_err("Failed to put hw resources\n");
+
+ return ret;
+}
+
+static int cnss_sdio_powerup(const struct subsys_desc *subsys)
+{
+ struct cnss_sdio_info *cnss_info;
+ struct cnss_sdio_wlan_driver *wdrv;
+ int ret = 0;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ cnss_info = &cnss_pdata->cnss_sdio_info;
+ wdrv = cnss_info->wdrv;
+
+ if (!wdrv)
+ return 0;
+
+ if (!wdrv->reinit)
+ return 0;
+
+ ret = cnss_get_hw_resources(cnss_info->dev);
+ if (ret) {
+ pr_err("Failed to power up HW\n");
+ return ret;
+ }
+
+ ret = wdrv->reinit(cnss_info->func, cnss_info->id);
+ if (ret)
+ pr_err("wlan reinit error=%d\n", ret);
+
+ return ret;
+}
+
+static void cnss_sdio_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct cnss_sdio_info *cnss_info;
+ struct cnss_sdio_wlan_driver *wdrv;
+
+ if (!cnss_pdata)
+ return;
+
+ cnss_info = &cnss_pdata->cnss_sdio_info;
+ wdrv = cnss_info->wdrv;
+ if (wdrv && wdrv->crash_shutdown)
+ wdrv->crash_shutdown(cnss_info->func);
+}
+
+static int cnss_sdio_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct cnss_ssr_info *ssr_info;
+ struct ramdump_segment segment;
+ int ret;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ if (!cnss_pdata->ssr_info.ramdump_size)
+ return -ENOENT;
+
+ if (!enable)
+ return 0;
+
+ ssr_info = &cnss_pdata->ssr_info;
+
+ memset(&segment, 0, sizeof(segment));
+ segment.v_address = ssr_info->ramdump_addr;
+ segment.size = ssr_info->ramdump_size;
+ ret = do_ramdump(ssr_info->ramdump_dev, &segment, 1);
+ if (ret)
+ pr_err("do_ramdump failed error=%d\n", ret);
+ return ret;
+}
+
+static int cnss_subsys_init(void)
+{
+ struct cnss_ssr_info *ssr_info;
+ int ret = 0;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ ssr_info = &cnss_pdata->ssr_info;
+ ssr_info->subsysdesc.name = ssr_info->subsys_name;
+ ssr_info->subsysdesc.owner = THIS_MODULE;
+ ssr_info->subsysdesc.shutdown = cnss_sdio_shutdown;
+ ssr_info->subsysdesc.powerup = cnss_sdio_powerup;
+ ssr_info->subsysdesc.ramdump = cnss_sdio_ramdump;
+ ssr_info->subsysdesc.crash_shutdown = cnss_sdio_crash_shutdown;
+ ssr_info->subsysdesc.dev = &cnss_pdata->pdev->dev;
+ ssr_info->subsys = subsys_register(&ssr_info->subsysdesc);
+ if (IS_ERR(ssr_info->subsys)) {
+ ret = PTR_ERR(ssr_info->subsys);
+ ssr_info->subsys = NULL;
+ dev_err(&cnss_pdata->pdev->dev, "Failed to subsys_register error=%d\n",
+ ret);
+ goto err_subsys_reg;
+ }
+ ssr_info->subsys_handle = subsystem_get(ssr_info->subsysdesc.name);
+ if (IS_ERR(ssr_info->subsys_handle)) {
+ ret = PTR_ERR(ssr_info->subsys_handle);
+ ssr_info->subsys_handle = NULL;
+ dev_err(&cnss_pdata->pdev->dev, "Failed to subsystem_get error=%d\n",
+ ret);
+ goto err_subsys_get;
+ }
+ return 0;
+err_subsys_get:
+ subsys_unregister(ssr_info->subsys);
+ ssr_info->subsys = NULL;
+err_subsys_reg:
+ return ret;
+}
+
+static void cnss_subsys_exit(void)
+{
+ struct cnss_ssr_info *ssr_info;
+
+ if (!cnss_pdata)
+ return;
+
+ ssr_info = &cnss_pdata->ssr_info;
+ if (ssr_info->subsys_handle)
+ subsystem_put(ssr_info->subsys_handle);
+ ssr_info->subsys_handle = NULL;
+ if (ssr_info->subsys)
+ subsys_unregister(ssr_info->subsys);
+ ssr_info->subsys = NULL;
+}
+
+static int cnss_configure_dump_table(struct cnss_ssr_info *ssr_info)
+{
+ struct msm_dump_entry dump_entry;
+ int ret;
+
+ ssr_info->dump_data.addr = ssr_info->ramdump_phys;
+ ssr_info->dump_data.len = ssr_info->ramdump_size;
+ ssr_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
+ ssr_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+ strlcpy(ssr_info->dump_data.name, CNSS_DUMP_NAME,
+ sizeof(ssr_info->dump_data.name));
+
+ dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+ dump_entry.addr = virt_to_phys(&ssr_info->dump_data);
+
+ ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+ if (ret)
+ pr_err("Dump table setup failed: %d\n", ret);
+
+ return ret;
+}
+
+static int cnss_configure_ramdump(void)
+{
+ struct cnss_ssr_info *ssr_info;
+ int ret = 0;
+ struct resource *res;
+ const char *name;
+ u32 ramdump_size = 0;
+ struct device *dev;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ dev = &cnss_pdata->pdev->dev;
+
+ ssr_info = &cnss_pdata->ssr_info;
+
+ ret = of_property_read_string(dev->of_node, CNSS_SUBSYS_NAME_KEY,
+ &name);
+ if (ret) {
+ pr_err("cnss missing DT key '%s'\n",
+ CNSS_SUBSYS_NAME_KEY);
+ ret = -ENODEV;
+ goto err_subsys_name_query;
+ }
+
+ strlcpy(ssr_info->subsys_name, name, sizeof(ssr_info->subsys_name));
+
+ if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+ &ramdump_size) == 0) {
+ ssr_info->ramdump_addr = dma_alloc_coherent(dev, ramdump_size,
+ &ssr_info->ramdump_phys,
+ GFP_KERNEL);
+ if (ssr_info->ramdump_addr)
+ ssr_info->ramdump_size = ramdump_size;
+ ssr_info->ramdump_dynamic = true;
+ } else {
+ res = platform_get_resource_byname(cnss_pdata->pdev,
+ IORESOURCE_MEM, "ramdump");
+ if (res) {
+ ssr_info->ramdump_phys = res->start;
+ ramdump_size = resource_size(res);
+ ssr_info->ramdump_addr = ioremap(ssr_info->ramdump_phys,
+ ramdump_size);
+ if (ssr_info->ramdump_addr)
+ ssr_info->ramdump_size = ramdump_size;
+ ssr_info->ramdump_dynamic = false;
+ }
+ }
+
+ pr_info("ramdump addr: %p, phys: %pa subsys:'%s'\n",
+ ssr_info->ramdump_addr, &ssr_info->ramdump_phys,
+ ssr_info->subsys_name);
+
+ if (ssr_info->ramdump_size == 0) {
+ pr_info("CNSS ramdump will not be collected\n");
+ return 0;
+ }
+
+ if (ssr_info->ramdump_dynamic) {
+ ret = cnss_configure_dump_table(ssr_info);
+ if (ret)
+ goto err_configure_dump_table;
+ }
+
+ ssr_info->ramdump_dev = create_ramdump_device(ssr_info->subsys_name,
+ dev);
+ if (!ssr_info->ramdump_dev) {
+ ret = -ENOMEM;
+ pr_err("ramdump dev create failed: error=%d\n",
+ ret);
+ goto err_configure_dump_table;
+ }
+
+ return 0;
+
+err_configure_dump_table:
+ if (ssr_info->ramdump_dynamic)
+ dma_free_coherent(dev, ssr_info->ramdump_size,
+ ssr_info->ramdump_addr,
+ ssr_info->ramdump_phys);
+ else
+ iounmap(ssr_info->ramdump_addr);
+
+ ssr_info->ramdump_addr = NULL;
+ ssr_info->ramdump_size = 0;
+err_subsys_name_query:
+ return ret;
+}
+
+static void cnss_ramdump_cleanup(void)
+{
+ struct cnss_ssr_info *ssr_info;
+ struct device *dev;
+
+ if (!cnss_pdata)
+ return;
+
+ dev = &cnss_pdata->pdev->dev;
+ ssr_info = &cnss_pdata->ssr_info;
+ if (ssr_info->ramdump_addr) {
+ if (ssr_info->ramdump_dynamic)
+ dma_free_coherent(dev, ssr_info->ramdump_size,
+ ssr_info->ramdump_addr,
+ ssr_info->ramdump_phys);
+ else
+ iounmap(ssr_info->ramdump_addr);
+ }
+
+ ssr_info->ramdump_addr = NULL;
+ if (ssr_info->ramdump_dev)
+ destroy_ramdump_device(ssr_info->ramdump_dev);
+ ssr_info->ramdump_dev = NULL;
+}
+
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size)
+{
+ if (!cnss_pdata || !cnss_pdata->pdev)
+ return NULL;
+
+ *size = cnss_pdata->ssr_info.ramdump_size;
+
+ return cnss_pdata->ssr_info.ramdump_addr;
+}
+
+void cnss_sdio_device_self_recovery(void)
+{
+ cnss_sdio_shutdown(NULL, false);
+ msleep(WLAN_RECOVERY_DELAY);
+ cnss_sdio_powerup(NULL);
+}
+
+void cnss_sdio_device_crashed(void)
+{
+ struct cnss_ssr_info *ssr_info;
+
+ if (!cnss_pdata)
+ return;
+ ssr_info = &cnss_pdata->ssr_info;
+ if (ssr_info->subsys) {
+ subsys_set_crash_status(ssr_info->subsys, true);
+ subsystem_restart_dev(ssr_info->subsys);
+ }
+}
+
+static void cnss_sdio_recovery_work_handler(struct work_struct *recovery)
+{
+ cnss_sdio_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_sdio_recovery_work, cnss_sdio_recovery_work_handler);
+
+void cnss_sdio_schedule_recovery_work(void)
+{
+ schedule_work(&cnss_sdio_recovery_work);
+}
+
+/**
+ * cnss_get_restart_level() - cnss get restart level API
+ *
+ * Wlan sdio function driver uses this API to get the current
+ * subsystem restart level.
+ *
+ * Return: CNSS_RESET_SOC - "SYSTEM", restart system
+ * CNSS_RESET_SUBSYS_COUPLED - "RELATED",restart subsystem
+ */
+int cnss_get_restart_level(void)
+{
+ struct cnss_ssr_info *ssr_info;
+ int level;
+
+ if (!cnss_pdata)
+ return CNSS_RESET_SOC;
+ ssr_info = &cnss_pdata->ssr_info;
+ if (!ssr_info->subsys)
+ return CNSS_RESET_SOC;
+ level = subsys_get_restart_level(ssr_info->subsys);
+ switch (level) {
+ case RESET_SOC:
+ return CNSS_RESET_SOC;
+ case RESET_SUBSYS_COUPLED:
+ return CNSS_RESET_SUBSYS_COUPLED;
+ default:
+ return CNSS_RESET_SOC;
+ }
+}
+EXPORT_SYMBOL(cnss_get_restart_level);
+
+static inline int cnss_get_tsf_cap_irq(struct device *dev)
+{
+ int irq = -EINVAL;
+ int gpio;
+
+ if (!dev)
+ return -ENODEV;
+
+ gpio = of_get_named_gpio(dev->of_node, WLAN_GPIO_CAPTSF_NAME, 0);
+ if (gpio >= 0)
+ irq = gpio_to_irq(gpio);
+
+ return irq;
+}
+
+static int cnss_sdio_register_tsf_captured_handler(irq_handler_t handler,
+ void *ctx)
+{
+ struct cnss_cap_tsf_info *tsf_info;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+ if (tsf_info->irq_num < 0)
+ return -ENOTSUPP;
+
+ tsf_info->irq_handler = handler;
+ tsf_info->context = ctx;
+ return 0;
+}
+
+static int cnss_sdio_unregister_tsf_captured_handler(void *ctx)
+{
+ struct cnss_cap_tsf_info *tsf_info;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+ if (tsf_info->irq_num < 0)
+ return -ENOTSUPP;
+
+ if (ctx == tsf_info->context) {
+ tsf_info->irq_handler = NULL;
+ tsf_info->context = NULL;
+ }
+ return 0;
+}
+
+static irqreturn_t cnss_sdio_tsf_captured_handler(int irq, void *ctx)
+{
+ struct cnss_cap_tsf_info *tsf_info;
+
+ if (!cnss_pdata)
+ return IRQ_HANDLED;
+
+ tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+ if (tsf_info->irq_num < 0 || tsf_info->irq_num != irq ||
+ !tsf_info->irq_handler || !tsf_info->context)
+ return IRQ_HANDLED;
+
+ return tsf_info->irq_handler(irq, tsf_info->context);
+}
+
+static void cnss_sdio_tsf_init(struct device *dev,
+ struct cnss_cap_tsf_info *tsf_info)
+{
+ int ret, irq;
+
+ tsf_info->irq_num = -EINVAL;
+ tsf_info->irq_handler = NULL;
+ tsf_info->context = NULL;
+
+ irq = cnss_get_tsf_cap_irq(dev);
+ if (irq < 0) {
+ dev_err(dev, "%s: fail to get irq: %d\n", __func__, irq);
+ return;
+ }
+
+ ret = request_irq(irq, cnss_sdio_tsf_captured_handler,
+ IRQF_SHARED | IRQF_TRIGGER_RISING, dev_name(dev),
+ (void *)tsf_info);
+ dev_err(dev, "%s: request irq[%d] for dev: %s, result: %d\n",
+ __func__, irq, dev_name(dev), ret);
+ if (!ret)
+ tsf_info->irq_num = irq;
+}
+
+static void cnss_sdio_tsf_deinit(struct cnss_cap_tsf_info *tsf_info)
+{
+ int irq = tsf_info->irq_num;
+
+ if (irq < 0)
+ return;
+
+ free_irq(irq, (void *)tsf_info);
+
+ tsf_info->irq_num = -EINVAL;
+ tsf_info->irq_handler = NULL;
+ tsf_info->context = NULL;
+}
+
+static void cnss_sdio_set_platform_ops(struct device *dev)
+{
+ struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+
+ pf_ops->power_up = cnss_sdio_power_up;
+ pf_ops->power_down = cnss_sdio_power_down;
+ pf_ops->device_crashed = cnss_sdio_device_crashed;
+ pf_ops->get_virt_ramdump_mem = cnss_sdio_get_virt_ramdump_mem;
+ pf_ops->device_self_recovery = cnss_sdio_device_self_recovery;
+ pf_ops->get_wlan_mac_address = cnss_sdio_get_wlan_mac_address;
+ pf_ops->set_wlan_mac_address = cnss_sdio_set_wlan_mac_address;
+ pf_ops->schedule_recovery_work = cnss_sdio_schedule_recovery_work;
+ pf_ops->request_bus_bandwidth = cnss_sdio_request_bus_bandwidth;
+ pf_ops->register_tsf_captured_handler =
+ cnss_sdio_register_tsf_captured_handler;
+ pf_ops->unregister_tsf_captured_handler =
+ cnss_sdio_unregister_tsf_captured_handler;
+ dev->platform_data = pf_ops;
+}
+
+static int cnss_sdio_wlan_inserted(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct cnss_sdio_info *info;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ info = &cnss_pdata->cnss_sdio_info;
+
+ info->func = func;
+ info->card = func->card;
+ info->host = func->card->host;
+ info->id = id;
+ info->dev = &func->dev;
+ cnss_sdio_set_platform_ops(info->dev);
+
+ cnss_put_hw_resources(cnss_pdata->cnss_sdio_info.dev);
+
+ pr_info("SDIO Device is Probed\n");
+ return 0;
+}
+
+static void cnss_sdio_wlan_removed(struct sdio_func *func)
+{
+ struct cnss_sdio_info *info;
+
+ if (!cnss_pdata)
+ return;
+
+ info = &cnss_pdata->cnss_sdio_info;
+
+ info->host = NULL;
+ info->card = NULL;
+ info->func = NULL;
+ info->id = NULL;
+}
+
+#if defined(CONFIG_PM)
+static int cnss_sdio_wlan_suspend(struct device *dev)
+{
+ struct cnss_sdio_wlan_driver *wdrv;
+ struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+ struct sdio_func *func;
+
+ int error = 0;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ bus_bandwidth = &cnss_pdata->bus_bandwidth;
+ if (bus_bandwidth->bus_client) {
+ msm_bus_scale_client_update_request(
+ bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+ }
+
+ func = cnss_pdata->cnss_sdio_info.func;
+ wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+ if (!wdrv) {
+ /* This can happen when no wlan driver loaded (no register to
+ * platform driver).
+ */
+ sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ pr_debug("wlan driver not registered\n");
+ return 0;
+ }
+ if (wdrv->suspend) {
+ error = wdrv->suspend(dev);
+ if (error)
+ pr_err("wlan suspend failed error=%d\n", error);
+ }
+
+ return error;
+}
+
+static int cnss_sdio_wlan_resume(struct device *dev)
+{
+ struct cnss_sdio_wlan_driver *wdrv;
+ struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+ int error = 0;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ bus_bandwidth = &cnss_pdata->bus_bandwidth;
+ if (bus_bandwidth->bus_client) {
+ msm_bus_scale_client_update_request(
+ bus_bandwidth->bus_client,
+ bus_bandwidth->current_bandwidth_vote);
+ }
+
+ wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+ if (!wdrv) {
+ /* This can happen when no wlan driver loaded (no register to
+ * platform driver).
+ */
+ pr_debug("wlan driver not registered\n");
+ return 0;
+ }
+ if (wdrv->resume) {
+ error = wdrv->resume(dev);
+ if (error)
+ pr_err("wlan resume failed error=%d\n", error);
+ }
+ return error;
+}
+#endif
+
+#if defined(CONFIG_PM)
+static const struct dev_pm_ops cnss_ar6k_device_pm_ops = {
+ .suspend = cnss_sdio_wlan_suspend,
+ .resume = cnss_sdio_wlan_resume,
+};
+#endif /* CONFIG_PM */
+
+static struct sdio_driver cnss_ar6k_driver = {
+ .name = "cnss_ar6k_wlan",
+ .id_table = ar6k_id_table,
+ .probe = cnss_sdio_wlan_inserted,
+ .remove = cnss_sdio_wlan_removed,
+#if defined(CONFIG_PM)
+ .drv = {
+ .pm = &cnss_ar6k_device_pm_ops,
+ }
+#endif
+};
+
+static int cnss_set_pinctrl_state(struct cnss_sdio_data *pdata, bool state)
+{
+ struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+ if (!info->is_antenna_shared)
+ return 0;
+
+ if (!info->pinctrl)
+ return -EIO;
+
+ return state ? pinctrl_select_state(info->pinctrl, info->active) :
+ pinctrl_select_state(info->pinctrl, info->sleep);
+}
+
+int cnss_sdio_configure_spdt(bool state)
+{
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ return cnss_set_pinctrl_state(cnss_pdata, state);
+}
+EXPORT_SYMBOL(cnss_sdio_configure_spdt);
+
+/**
+ * cnss_sdio_wlan_register_driver() - cnss wlan register API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to register callback
+ * functions to cnss_sido platform driver. The callback will
+ * be invoked by corresponding wrapper function of this cnss
+ * platform driver.
+ */
+int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver)
+{
+ struct cnss_sdio_info *cnss_info;
+ struct device *dev;
+ int error = -EINVAL;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ cnss_info = &cnss_pdata->cnss_sdio_info;
+ dev = cnss_info->dev;
+
+ if (cnss_info->wdrv) {
+ pr_debug("wdrv already existed\n");
+ return error;
+ }
+
+ if (!driver)
+ return error;
+
+ error = cnss_get_hw_resources(dev);
+ if (error) {
+ pr_err("Failed to restore power err:%d\n", error);
+ return error;
+ }
+
+ error = cnss_set_pinctrl_state(cnss_pdata, PINCTRL_ACTIVE);
+ if (error) {
+ pr_err("Fail to set pinctrl to active state\n");
+ cnss_put_hw_resources(dev);
+ goto put_hw;
+ }
+
+ /* The HW resources are released in unregister logic if probe fails */
+ error = driver->probe ? driver->probe(cnss_info->func,
+ cnss_info->id) : error;
+ if (error) {
+ pr_err("wlan probe failed error=%d\n", error);
+ /**
+ * Check memory leak in skb pre-alloc memory pool
+ * Reset the skb memory pool
+ */
+ goto pinctrl_sleep;
+ }
+
+ cnss_info->wdrv = driver;
+
+ return error;
+
+pinctrl_sleep:
+ cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+put_hw:
+ return error;
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_register_driver);
+
+/**
+ * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to detach it from cnss_sido
+ * platform driver.
+ */
+void
+cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver)
+{
+ struct cnss_sdio_info *cnss_info;
+ struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+ if (!cnss_pdata)
+ return;
+
+ bus_bandwidth = &cnss_pdata->bus_bandwidth;
+ if (bus_bandwidth->bus_client) {
+ msm_bus_scale_client_update_request(
+ bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+ }
+
+ cnss_info = &cnss_pdata->cnss_sdio_info;
+ if (!cnss_info->wdrv) {
+ pr_err("driver not registered\n");
+ return;
+ }
+
+ if (!driver)
+ return;
+
+ if (!driver->remove)
+ return;
+
+ driver->remove(cnss_info->func);
+
+ cnss_info->wdrv = NULL;
+ cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+ cnss_put_hw_resources(cnss_info->dev);
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver);
+
+/**
+ * cnss_wlan_query_oob_status() - cnss wlan query oob status API
+ *
+ * Wlan sdio function driver uses this API to check whether oob is
+ * supported in platform driver.
+ *
+ * Return: 0 means oob is supported, others means unsupported.
+ */
+int cnss_wlan_query_oob_status(void)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_query_oob_status);
+
+/**
+ * cnss_wlan_register_oob_irq_handler() - cnss wlan register oob callback API
+ * @handler: oob callback function pointer which registered to platform driver.
+ * @pm_oob : parameter which registered to platform driver.
+ *
+ * Wlan sdio function driver uses this API to register oob callback
+ * function to platform driver.
+ *
+ * Return: 0 means register successfully, others means failure.
+ */
+int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler, void *pm_oob)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_register_oob_irq_handler);
+
+/**
+ * cnss_wlan_unregister_oob_irq_handler() - unregister oob callback API
+ * @pm_oob: parameter which unregistered from platform driver.
+ *
+ * Wlan sdio function driver uses this API to unregister oob callback
+ * function from platform driver.
+ *
+ * Return: 0 means unregister successfully, others means failure.
+ */
+int cnss_wlan_unregister_oob_irq_handler(void *pm_oob)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_oob_irq_handler);
+
+static void cnss_sdio_reset_platform_ops(void)
+{
+ struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+ struct cnss_sdio_info *sdio_info = &cnss_pdata->cnss_sdio_info;
+
+ memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+ if (sdio_info->dev)
+ sdio_info->dev->platform_data = NULL;
+}
+
+static int cnss_sdio_wlan_init(void)
+{
+ int error = 0;
+
+ error = sdio_register_driver(&cnss_ar6k_driver);
+ if (error) {
+ cnss_sdio_reset_platform_ops();
+ pr_err("registered fail error=%d\n", error);
+ } else {
+ pr_debug("registered success\n");
+ }
+
+ return error;
+}
+
+static void cnss_sdio_wlan_exit(void)
+{
+ if (!cnss_pdata)
+ return;
+
+ cnss_sdio_reset_platform_ops();
+ sdio_unregister_driver(&cnss_ar6k_driver);
+}
+
+static void cnss_sdio_deinit_bus_bandwidth(void)
+{
+ struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+ bus_bandwidth = &cnss_pdata->bus_bandwidth;
+ if (bus_bandwidth->bus_client) {
+ msm_bus_scale_client_update_request(bus_bandwidth->bus_client,
+ CNSS_BUS_WIDTH_NONE);
+ msm_bus_scale_unregister_client(bus_bandwidth->bus_client);
+ }
+}
+
+static int cnss_sdio_configure_wlan_enable_regulator(void)
+{
+ int error;
+ struct device *dev = &cnss_pdata->pdev->dev;
+
+ if (of_get_property(
+ cnss_pdata->pdev->dev.of_node,
+ WLAN_VREG_NAME "-supply", NULL)) {
+ cnss_pdata->regulator.wlan_vreg = regulator_get(
+ &cnss_pdata->pdev->dev, WLAN_VREG_NAME);
+ if (IS_ERR(cnss_pdata->regulator.wlan_vreg)) {
+ error = PTR_ERR(cnss_pdata->regulator.wlan_vreg);
+ dev_err(dev, "VDD-VREG get failed error=%d\n", error);
+ return error;
+ }
+
+ error = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+ if (error) {
+ dev_err(dev, "VDD-VREG enable failed error=%d\n",
+ error);
+ goto err_vdd_vreg_regulator;
+ }
+ }
+
+ return 0;
+
+err_vdd_vreg_regulator:
+ regulator_put(cnss_pdata->regulator.wlan_vreg);
+
+ return error;
+}
+
+static int cnss_sdio_configure_wlan_enable_dsrc_regulator(void)
+{
+ int error;
+ struct device *dev = &cnss_pdata->pdev->dev;
+
+ if (of_get_property(
+ cnss_pdata->pdev->dev.of_node,
+ WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+ cnss_pdata->regulator.wlan_vreg_dsrc = regulator_get(
+ &cnss_pdata->pdev->dev, WLAN_VREG_DSRC_NAME);
+ if (IS_ERR(cnss_pdata->regulator.wlan_vreg_dsrc)) {
+ error = PTR_ERR(cnss_pdata->regulator.wlan_vreg_dsrc);
+ dev_err(dev, "VDD-VREG-DSRC get failed error=%d\n",
+ error);
+ return error;
+ }
+
+ error = regulator_enable(cnss_pdata->regulator.wlan_vreg_dsrc);
+ if (error) {
+ dev_err(dev, "VDD-VREG-DSRC enable failed error=%d\n",
+ error);
+ goto err_vdd_vreg_dsrc_regulator;
+ }
+ }
+
+ return 0;
+
+err_vdd_vreg_dsrc_regulator:
+ regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+
+ return error;
+}
+
+static int cnss_sdio_configure_regulator(void)
+{
+ int error;
+ struct device *dev = &cnss_pdata->pdev->dev;
+
+ if (of_get_property(
+ cnss_pdata->pdev->dev.of_node,
+ WLAN_VREG_IO_NAME "-supply", NULL)) {
+ cnss_pdata->regulator.wlan_io = regulator_get(
+ &cnss_pdata->pdev->dev, WLAN_VREG_IO_NAME);
+ if (IS_ERR(cnss_pdata->regulator.wlan_io)) {
+ error = PTR_ERR(cnss_pdata->regulator.wlan_io);
+ dev_err(dev, "VDD-IO get failed error=%d\n", error);
+ return error;
+ }
+
+ error = regulator_set_voltage(
+ cnss_pdata->regulator.wlan_io,
+ WLAN_VREG_IO_MIN, WLAN_VREG_IO_MAX);
+ if (error) {
+ dev_err(dev, "VDD-IO set failed error=%d\n", error);
+ goto err_vdd_io_regulator;
+ } else {
+ error = regulator_enable(cnss_pdata->regulator.wlan_io);
+ if (error) {
+ dev_err(dev, "VDD-IO enable failed error=%d\n",
+ error);
+ goto err_vdd_io_regulator;
+ }
+ }
+ }
+
+ if (of_get_property(
+ cnss_pdata->pdev->dev.of_node,
+ WLAN_VREG_XTAL_NAME "-supply", NULL)) {
+ cnss_pdata->regulator.wlan_xtal = regulator_get(
+ &cnss_pdata->pdev->dev, WLAN_VREG_XTAL_NAME);
+ if (IS_ERR(cnss_pdata->regulator.wlan_xtal)) {
+ error = PTR_ERR(cnss_pdata->regulator.wlan_xtal);
+ dev_err(dev, "VDD-XTAL get failed error=%d\n", error);
+ goto err_vdd_xtal_regulator;
+ }
+
+ error = regulator_set_voltage(
+ cnss_pdata->regulator.wlan_xtal,
+ WLAN_VREG_XTAL_MIN, WLAN_VREG_XTAL_MAX);
+ if (error) {
+ dev_err(dev, "VDD-XTAL set failed error=%d\n", error);
+ goto err_vdd_xtal_regulator;
+ } else {
+ error = regulator_enable(
+ cnss_pdata->regulator.wlan_xtal);
+ if (error) {
+ dev_err(dev, "VDD-XTAL enable failed err=%d\n",
+ error);
+ goto err_vdd_xtal_regulator;
+ }
+ }
+ }
+
+ return 0;
+
+err_vdd_xtal_regulator:
+ regulator_put(cnss_pdata->regulator.wlan_xtal);
+err_vdd_io_regulator:
+ regulator_put(cnss_pdata->regulator.wlan_io);
+ return error;
+}
+
+static void cnss_sdio_release_resource(void)
+{
+ if (cnss_pdata->regulator.wlan_xtal)
+ regulator_put(cnss_pdata->regulator.wlan_xtal);
+ if (cnss_pdata->regulator.wlan_vreg)
+ regulator_put(cnss_pdata->regulator.wlan_vreg);
+ if (cnss_pdata->regulator.wlan_io)
+ regulator_put(cnss_pdata->regulator.wlan_io);
+ if (cnss_pdata->regulator.wlan_vreg_dsrc)
+ regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+}
+
+static int cnss_sdio_pinctrl_init(struct cnss_sdio_data *pdata,
+ struct platform_device *pdev)
+{
+ int ret = 0;
+ struct device *dev = &pdev->dev;
+ struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+ if (!of_find_property(dev->of_node, "qcom,is-antenna-shared", NULL))
+ return 0;
+
+ info->is_antenna_shared = true;
+ info->pinctrl = devm_pinctrl_get(dev);
+ if ((IS_ERR_OR_NULL(info->pinctrl))) {
+ dev_err(dev, "%s: Failed to get pinctrl\n", __func__);
+ return PTR_ERR(info->pinctrl);
+ }
+
+ info->sleep = pinctrl_lookup_state(info->pinctrl,
+ CNSS_PINCTRL_SLEEP_STATE);
+ if (IS_ERR_OR_NULL(info->sleep)) {
+ dev_err(dev, "%s: Fail to get sleep state for pin\n", __func__);
+ ret = PTR_ERR(info->sleep);
+ goto release_pinctrl;
+ }
+
+ info->active = pinctrl_lookup_state(info->pinctrl,
+ CNSS_PINCTRL_ACTIVE_STATE);
+ if (IS_ERR_OR_NULL(info->active)) {
+ dev_err(dev, "%s: Fail to get active state for pin\n",
+ __func__);
+ ret = PTR_ERR(info->active);
+ goto release_pinctrl;
+ }
+
+ ret = cnss_set_pinctrl_state(pdata, PINCTRL_SLEEP);
+
+ if (ret) {
+ dev_err(dev, "%s: Fail to set pin in sleep state\n", __func__);
+ goto release_pinctrl;
+ }
+
+ return ret;
+
+release_pinctrl:
+ devm_pinctrl_put(info->pinctrl);
+ info->is_antenna_shared = false;
+ return ret;
+}
+
+static int cnss_sdio_init_bus_bandwidth(void)
+{
+ int ret = 0;
+ struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+ struct device *dev = &cnss_pdata->pdev->dev;
+
+ bus_bandwidth = &cnss_pdata->bus_bandwidth;
+ bus_bandwidth->bus_scale_table = msm_bus_cl_get_pdata(cnss_pdata->pdev);
+ if (!bus_bandwidth->bus_scale_table) {
+ dev_err(dev, "Failed to get the bus scale platform data\n");
+ ret = -EINVAL;
+ }
+
+ bus_bandwidth->bus_client = msm_bus_scale_register_client(
+ bus_bandwidth->bus_scale_table);
+ if (!bus_bandwidth->bus_client) {
+ dev_err(dev, "Failed to register with bus_scale client\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int cnss_sdio_probe(struct platform_device *pdev)
+{
+ int error;
+ struct device *dev = &pdev->dev;
+ struct cnss_sdio_info *info;
+
+ if (pdev->dev.of_node) {
+ cnss_pdata = devm_kzalloc(
+ &pdev->dev, sizeof(*cnss_pdata), GFP_KERNEL);
+ if (!cnss_pdata)
+ return -ENOMEM;
+ } else {
+ cnss_pdata = pdev->dev.platform_data;
+ }
+
+ if (!cnss_pdata)
+ return -EINVAL;
+
+ cnss_pdata->pdev = pdev;
+ info = &cnss_pdata->cnss_sdio_info;
+
+ error = cnss_sdio_pinctrl_init(cnss_pdata, pdev);
+ if (error) {
+ dev_err(&pdev->dev, "Fail to configure pinctrl err:%d\n",
+ error);
+ return error;
+ }
+
+ error = cnss_sdio_configure_regulator();
+ if (error) {
+ dev_err(&pdev->dev, "Failed to configure voltage regulator error=%d\n",
+ error);
+ return error;
+ }
+
+ if (of_get_property(
+ cnss_pdata->pdev->dev.of_node,
+ WLAN_VREG_NAME "-supply", NULL)) {
+ error = cnss_sdio_configure_wlan_enable_regulator();
+ if (error) {
+ dev_err(&pdev->dev,
+ "Failed to enable wlan enable regulator error=%d\n",
+ error);
+ goto err_wlan_enable_regulator;
+ }
+ }
+
+ if (of_get_property(
+ cnss_pdata->pdev->dev.of_node,
+ WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+ error = cnss_sdio_configure_wlan_enable_dsrc_regulator();
+ if (error) {
+ dev_err(&pdev->dev,
+ "Failed to enable wlan dsrc enable regulator\n");
+ goto err_wlan_dsrc_enable_regulator;
+ }
+ }
+
+ info->skip_wlan_en_toggle = of_property_read_bool(dev->of_node,
+ "qcom,skip-wlan-en-toggle");
+ info->cnss_hw_state = CNSS_HW_ACTIVE;
+
+ cnss_sdio_tsf_init(dev, &info->cap_tsf_info);
+
+ error = cnss_sdio_wlan_init();
+ if (error) {
+ dev_err(&pdev->dev, "cnss wlan init failed error=%d\n", error);
+ goto err_wlan_dsrc_enable_regulator;
+ }
+
+ error = cnss_configure_ramdump();
+ if (error) {
+ dev_err(&pdev->dev, "Failed to configure ramdump error=%d\n",
+ error);
+ goto err_ramdump_create;
+ }
+
+ error = cnss_subsys_init();
+ if (error) {
+ dev_err(&pdev->dev, "Failed to cnss_subsys_init error=%d\n",
+ error);
+ goto err_subsys_init;
+ }
+
+ if (of_property_read_bool(
+ pdev->dev.of_node, "qcom,cnss-enable-bus-bandwidth")) {
+ error = cnss_sdio_init_bus_bandwidth();
+ if (error) {
+ dev_err(&pdev->dev, "Failed to init bus bandwidth\n");
+ goto err_bus_bandwidth_init;
+ }
+ }
+
+ dev_info(&pdev->dev, "CNSS SDIO Driver registered");
+ return 0;
+
+err_bus_bandwidth_init:
+ cnss_subsys_exit();
+err_subsys_init:
+ cnss_ramdump_cleanup();
+err_ramdump_create:
+ cnss_sdio_wlan_exit();
+err_wlan_dsrc_enable_regulator:
+ info->cnss_hw_state = CNSS_HW_SLEEP;
+ regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+err_wlan_enable_regulator:
+ regulator_put(cnss_pdata->regulator.wlan_xtal);
+ regulator_put(cnss_pdata->regulator.wlan_io);
+ cnss_pdata = NULL;
+ return error;
+}
+
+static int cnss_sdio_remove(struct platform_device *pdev)
+{
+ struct cnss_sdio_info *info;
+ struct cnss_cap_tsf_info *tsf_info;
+
+ if (!cnss_pdata)
+ return -ENODEV;
+
+ info = &cnss_pdata->cnss_sdio_info;
+ tsf_info = &info->cap_tsf_info;
+
+ cnss_sdio_tsf_deinit(tsf_info);
+ cnss_sdio_deinit_bus_bandwidth();
+ cnss_sdio_wlan_exit();
+ cnss_subsys_exit();
+ cnss_ramdump_cleanup();
+ cnss_put_hw_resources(info->dev);
+ cnss_sdio_release_resource();
+ cnss_pdata = NULL;
+ return 0;
+}
+
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len)
+{
+ return 0;
+}
+
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num)
+{
+ *num = 0;
+ return NULL;
+}
+
+int cnss_sdio_power_down(struct device *dev)
+{
+ return 0;
+}
+
+int cnss_sdio_power_up(struct device *dev)
+{
+ return 0;
+}
+
+static const struct of_device_id cnss_sdio_dt_match[] = {
+ {.compatible = "qcom,cnss_sdio"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, cnss_sdio_dt_match);
+
+static struct platform_driver cnss_sdio_driver = {
+ .probe = cnss_sdio_probe,
+ .remove = cnss_sdio_remove,
+ .driver = {
+ .name = "cnss_sdio",
+ .owner = THIS_MODULE,
+ .of_match_table = cnss_sdio_dt_match,
+ },
+};
+
+static int __init cnss_sdio_init(void)
+{
+ return platform_driver_register(&cnss_sdio_driver);
+}
+
+static void __exit cnss_sdio_exit(void)
+{
+ platform_driver_unregister(&cnss_sdio_driver);
+}
+
+module_init(cnss_sdio_init);
+module_exit(cnss_sdio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS SDIO Driver");
diff --git a/drivers/net/wireless/cnss/logger/Kconfig b/drivers/net/wireless/cnss/logger/Kconfig
new file mode 100644
index 0000000..85b6992
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Kconfig
@@ -0,0 +1,6 @@
+config CNSS_LOGGER
+ tristate "CNSS Logging Service Driver"
+ ---help---
+ This module adds support for the CNSS Logging Service for CLD
+ driver, including the netlink socket service registration, transmit,
+ event receive.
diff --git a/drivers/net/wireless/cnss/logger/Makefile b/drivers/net/wireless/cnss/logger/Makefile
new file mode 100644
index 0000000..1e296a3
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_CNSS_LOGGER) += logger.o
+
+logger-y += main.o \
+ nl_service.o
+
+logger-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/net/wireless/cnss/logger/debugfs.c b/drivers/net/wireless/cnss/logger/debugfs.c
new file mode 100644
index 0000000..027d630
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/debugfs.c
@@ -0,0 +1,134 @@
+/* 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/module.h>
+#include <linux/debugfs.h>
+
+#include "logger.h"
+
+#define CNSS_LOGGER_STATE_DUMP_BUFFER (2 * 1024) /* 2KB */
+
+static int logger_state_dump_device(struct logger_device *dev, char *buf,
+ int buf_len)
+{
+ int len = 0;
+ struct logger_event_handler *cur;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "==============================================\n");
+
+ len += scnprintf(buf + len, buf_len - len,
+ "driver [%s] is registered with radio index: %d\n",
+ dev->name, dev->radio_idx);
+
+ if (list_empty(&dev->event_list)) {
+ len += scnprintf(buf + len, buf_len - len,
+ "No event registered\n");
+ return len;
+ }
+
+ list_for_each_entry(cur, &dev->event_list, list) {
+ len += scnprintf(buf + len, buf_len - len,
+ "\t event %d\n", cur->event);
+ }
+ len += scnprintf(buf + len, buf_len - len, "\n");
+
+ return len;
+}
+
+static int logger_state_dump(struct logger_context *ctx, char *buf, int buf_len)
+{
+ int len = 0;
+ struct logger_device *cur;
+
+ if (list_empty(&ctx->dev_list)) {
+ len += scnprintf(buf + len, buf_len - len,
+ "=======================\n");
+ len += scnprintf(buf + len, buf_len - len,
+ "No driver registered\n");
+ return 0;
+ }
+
+ list_for_each_entry(cur, &ctx->dev_list, list)
+ len += logger_state_dump_device(cur, (buf + len), buf_len);
+
+ return 0;
+}
+
+static int logger_state_open(struct inode *inode, struct file *file)
+{
+ struct logger_context *ctx = inode->i_private;
+ void *buf;
+ int ret;
+
+ mutex_lock(&ctx->con_mutex);
+
+ buf = kmalloc(CNSS_LOGGER_STATE_DUMP_BUFFER, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto error_unlock;
+ }
+
+ ret = logger_state_dump(ctx, buf, CNSS_LOGGER_STATE_DUMP_BUFFER);
+ if (ret)
+ goto error_free;
+
+ file->private_data = buf;
+ mutex_unlock(&ctx->con_mutex);
+ return 0;
+
+error_free:
+ kfree(buf);
+
+error_unlock:
+ mutex_unlock(&ctx->con_mutex);
+
+ return ret;
+}
+
+static int logger_state_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static ssize_t logger_state_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ unsigned int len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_logger_state = {
+ .open = logger_state_open,
+ .release = logger_state_release,
+ .read = logger_state_read,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+void logger_debugfs_init(struct logger_context *ctx)
+{
+ if (!ctx->debugfs_entry)
+ ctx->debugfs_entry = debugfs_create_dir("cnss_logger", NULL);
+
+ debugfs_create_file("state", 0400, ctx->debugfs_entry, ctx,
+ &fops_logger_state);
+}
+
+void logger_debugfs_remove(struct logger_context *ctx)
+{
+ debugfs_remove(ctx->debugfs_entry);
+}
+
diff --git a/drivers/net/wireless/cnss/logger/logger.h b/drivers/net/wireless/cnss/logger/logger.h
new file mode 100644
index 0000000..6531ac6
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/logger.h
@@ -0,0 +1,102 @@
+/* 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.
+ */
+#ifndef _LOGGER_H_
+#define _LOGGER_H_
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+
+#define CNSS_LOGGER_NL_MCAST_GRP_ID 0x01
+#define CNSS_LOGGER_NL_MAX_PAYLOAD 256
+#define CNSS_LOGGER_BROADCAST_ID 255
+
+/**
+ * struct aninlmsg - the wireless service message header
+ * @nlh: the netlink message header
+ * @radio: the radio index of this message
+ * @wmsg: the pointer to the wireless message data
+ */
+struct aninlmsg {
+ struct nlmsghdr *nlh;
+ int radio;
+ void *wmsg;
+};
+
+/**
+ * struct logger_event_handler - the logger event handler structure
+ * @list: the event list associated to the same device
+ * @event: the event number
+ * @radio_idx: the callback handler
+ */
+struct logger_event_handler {
+ struct list_head list;
+
+ int event;
+ int (*cb)(struct sk_buff *skb);
+};
+
+/**
+ * struct logger_device - the logger device structure
+ * @list: the device list registered to logger module
+ * @event_list: the event list registered to this device
+ * @ctx: the pointer to the logger context
+ * @wiphy: the wiphy that associated to the device
+ * @name: the name of the device driver module
+ * @radio_idx: the radio index assigned to this device
+ */
+struct logger_device {
+ struct list_head list;
+ struct list_head event_list;
+
+ struct logger_context *ctx;
+ struct wiphy *wiphy;
+ char name[MODULE_NAME_LEN];
+ int radio_idx;
+};
+
+/**
+ * struct logger_context - the main context block for logger module
+ * @dev_list: this is the list to maintain the devices that registered
+ * to use the logger module feature
+ * @nl_sock: the netlink socket to share accros the module
+ * @con_mutex: the mutex to protect concurrent access
+ * @data_lock: the lock to protect shared data
+ * @radio_mask: this mask would maintain the radio index assign and release
+ */
+struct logger_context {
+ struct list_head dev_list;
+
+ struct sock *nl_sock;
+ struct mutex con_mutex; /* concurrent access mutex */
+ spinlock_t data_lock;
+ unsigned long radio_mask; /* support up to 4 drivers registration? */
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_entry;
+#endif
+};
+
+int logger_netlink_init(struct logger_context *ctx);
+int logger_netlink_deinit(struct logger_context *ctx);
+struct logger_context *logger_get_ctx(void);
+
+#ifdef CONFIG_DEBUG_FS
+void logger_debugfs_init(struct logger_context *ctx);
+void logger_debugfs_remove(struct logger_context *ctx);
+#else
+static inline void logger_debugfs_init(struct logger_context *ctx) {}
+static inline void logger_debugfs_remove(struct logger_context *ctx) {}
+#endif
+
+#endif /* _LOGGER_H_ */
diff --git a/drivers/net/wireless/cnss/logger/main.c b/drivers/net/wireless/cnss/logger/main.c
new file mode 100644
index 0000000..4013e69
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/main.c
@@ -0,0 +1,55 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static struct logger_context *ctx;
+
+struct logger_context *logger_get_ctx(void)
+{
+ return ctx;
+}
+
+static int __init logger_module_init(void)
+{
+ int ret;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ret = logger_netlink_init(ctx);
+
+ mutex_init(&ctx->con_mutex);
+ spin_lock_init(&ctx->data_lock);
+ logger_debugfs_init(ctx);
+
+ return ret;
+}
+
+static void __exit logger_module_exit(void)
+{
+ logger_debugfs_remove(ctx);
+ logger_netlink_deinit(ctx);
+
+ kfree(ctx);
+}
+
+module_init(logger_module_init);
+module_exit(logger_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS Logging Service Driver");
diff --git a/drivers/net/wireless/cnss/logger/nl_service.c b/drivers/net/wireless/cnss/logger/nl_service.c
new file mode 100644
index 0000000..4ea76ae
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/nl_service.c
@@ -0,0 +1,476 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "cnss_logger: %s: "fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static DEFINE_MUTEX(logger_sem);
+
+/**
+ * logger_get_radio_idx() - to get the radio index
+ * @ctx: the logger context pointer
+ *
+ * Return: the first available radio index, otherwise failure code
+ */
+static int logger_get_radio_idx(struct logger_context *ctx)
+{
+ int i;
+
+ for (i = 0; i < sizeof(ctx->radio_mask); i++) {
+ if (!test_and_set_bit(i, &ctx->radio_mask))
+ return i;
+ }
+ return -EINVAL;
+}
+
+/**
+ * logger_put_radio_idx() - to release the radio index
+ * @radio: the radio index to release
+ *
+ * Return: None
+ */
+static void logger_put_radio_idx(struct logger_context *ctx, int radio)
+{
+ clear_bit(radio, &ctx->radio_mask);
+}
+
+/**
+ * logger_get_device() - to get the logger device per radio index
+ * @radio: the radio index
+ *
+ * Return: the logger_device pointer, otherwise return NULL.
+ */
+static struct logger_device *logger_get_device(int radio)
+{
+ struct logger_device *dev;
+ struct logger_context *ctx;
+
+ ctx = logger_get_ctx();
+ if (!ctx)
+ return NULL;
+
+ list_for_each_entry(dev, &ctx->dev_list, list) {
+ if (dev->radio_idx == radio)
+ return dev;
+ }
+ return NULL;
+}
+
+/**
+ * logger_device_is_registered() - to check if device has been registered
+ * @dev: pointer to logger device
+ * @wiphy: the wiphy pointer of the device to register
+ *
+ * This helper function is to check if this device has been registered.
+ *
+ * Return: NULL if it has not, otherwise return the logger_device pointer.
+ */
+static struct logger_device *logger_device_is_registered(
+ struct logger_context *ctx,
+ struct wiphy *wiphy)
+{
+ struct logger_device *dev;
+
+ list_for_each_entry(dev, &ctx->dev_list, list) {
+ if (dev->wiphy == wiphy)
+ return dev;
+ }
+ return NULL;
+}
+
+/**
+ * logger_dispatch_skb() - to dispatch the skb to devices
+ * @skb: the socket buffer received and to dispatch
+ *
+ * The function will look up the header of the skb, and dispatch the skb
+ * to the associated event and device that registered.
+ *
+ * Return: 0 if successfully dispatch, otherwise failure code
+ */
+static int logger_dispatch_skb(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ struct logger_context *ctx;
+ struct logger_device *cur;
+ struct logger_event_handler *evt;
+ int handled = 0;
+
+ ctx = logger_get_ctx();
+ if (!ctx)
+ return -ENOENT;
+
+ pr_info("skb_len: %d, skb_data_len: %d\n",
+ skb->len, skb->data_len);
+
+ if (skb->len < sizeof(struct nlmsghdr))
+ return 0;
+
+ nlh = (struct nlmsghdr *)skb->data;
+ list_for_each_entry(cur, &ctx->dev_list, list) {
+ list_for_each_entry(evt, &cur->event_list, list) {
+ if (nlh->nlmsg_type == evt->event) {
+ if (evt->cb) {
+ handled = 1;
+ evt->cb(skb);
+ }
+ /* Break inside loop, next dev */
+ break;
+ }
+ }
+ }
+
+ if (!handled)
+ pr_info("Not handled msg type: %d\n", nlh->nlmsg_type);
+
+ return 0;
+}
+
+/**
+ * logger_flush_event_handle() - to flush the event handle associate to device
+ * @dev: pointer to logger device
+ *
+ * The function will clean up all the event handle's resource, take it out
+ * from the list, and free the memory allocated.
+ *
+ * Return: None
+ */
+static void logger_flush_event_handle(struct logger_device *dev)
+{
+ struct list_head *pos, *temp;
+ struct logger_event_handler *cur;
+
+ list_for_each_safe(pos, temp, &dev->event_list) {
+ cur = container_of(pos, struct logger_event_handler, list);
+ pr_info("radio: %d, event: %d unregistered\n",
+ dev->radio_idx, cur->event);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+}
+
+/**
+ * logger_flush_devices() - to flush the devices infomration
+ * @dev: pointer to logger device
+ *
+ * The helper function to flush the device information, all the device clean
+ * up prcoess should be starting from here.
+ *
+ * Return: None
+ */
+static void logger_flush_devices(struct logger_device *dev)
+{
+ pr_info("driver: [%s] and radio-%d is unregistered\n",
+ dev->name, dev->radio_idx);
+ logger_flush_event_handle(dev);
+ logger_put_radio_idx(dev->ctx, dev->radio_idx);
+ list_del(&dev->list);
+ kfree(dev);
+}
+
+/**
+ * logger_register_device_event() - register the evet to device
+ * @dev: pointer to logger device
+ * @event: the event to register
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if register successfully, otherwise the failure code
+ */
+static int logger_register_device_event(struct logger_device *dev, int event,
+ int (*cb)(struct sk_buff *skb))
+{
+ struct logger_event_handler *cur;
+
+ list_for_each_entry(cur, &dev->event_list, list) {
+ if (cur->event == event) {
+ pr_info("event %d, is already added\n", event);
+ return 0;
+ }
+ }
+
+ cur = kmalloc(sizeof(*cur), GFP_KERNEL);
+ if (!cur)
+ return -ENOMEM;
+
+ cur->event = event;
+ cur->cb = cb;
+
+ pr_info("radio: %d, event: %d\n", dev->radio_idx, cur->event);
+ list_add_tail(&cur->list, &dev->event_list);
+
+ return 0;
+}
+
+/**
+ * logger_unregister_device_event() - unregister the evet from device
+ * @dev: pointer to logger device
+ * @event: the event to unregister
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if unregister successfully, otherwise the failure code
+ */
+static int logger_unregister_device_event(struct logger_device *dev, int event,
+ int (*cb)(struct sk_buff *skb))
+{
+ struct list_head *pos, *temp;
+ struct logger_event_handler *cur;
+
+ list_for_each_safe(pos, temp, &dev->event_list) {
+ cur = container_of(pos, struct logger_event_handler, list);
+ if (cur->event == event && cur->cb == cb) {
+ pr_info("radio: %d, event: %d\n",
+ dev->radio_idx, cur->event);
+ list_del(&cur->list);
+ kfree(cur);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * logger_skb_input() - the callback to receive the skb
+ * @skb: the receive socket buffer
+ *
+ * Return: None
+ */
+static void logger_skb_input(struct sk_buff *skb)
+{
+ mutex_lock(&logger_sem);
+ logger_dispatch_skb(skb);
+ mutex_unlock(&logger_sem);
+}
+
+/**
+ * cnss_logger_event_register() - register the event
+ * @radio: the radio index to register
+ * @event: the event to register
+ * @cb: the callback
+ *
+ * This function is used to register event associated to the radio index.
+ *
+ * Return: 0 if register success, otherwise failure code
+ */
+int cnss_logger_event_register(int radio, int event,
+ int (*cb)(struct sk_buff *skb))
+{
+ int ret = -ENOENT;
+ struct logger_device *dev;
+
+ dev = logger_get_device(radio);
+ if (dev)
+ ret = logger_register_device_event(dev, event, cb);
+
+ return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_register);
+
+/**
+ * cnss_logger_event_unregister() - unregister the event
+ * @radio: the radio index to unregister
+ * @event: the event to unregister
+ * @cb: the callback
+ *
+ * This function is used to unregister the event from cnss logger module.
+ *
+ * Return: 0 if unregister success, otherwise failure code
+ */
+int cnss_logger_event_unregister(int radio, int event,
+ int (*cb)(struct sk_buff *skb))
+{
+ int ret = -ENOENT;
+ struct logger_device *dev;
+
+ dev = logger_get_device(radio);
+ if (dev)
+ ret = logger_unregister_device_event(dev, event, cb);
+
+ return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_unregister);
+
+/**
+ * cnss_logger_device_register() - register the driver
+ * @wiphy: the wiphy device to unregister
+ * @name: the module name of the driver
+ *
+ * This function is used to register the driver to cnss logger module,
+ * this will indicate the existence of the driver, and also assign the
+ * radio index for further operation.
+ *
+ * Return: the radio index if register successful, otherwise failure code
+ */
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name)
+{
+ int radio;
+ struct logger_context *ctx;
+ struct logger_device *new;
+
+ ctx = logger_get_ctx();
+ if (!ctx)
+ return -ENOENT;
+
+ /* sanity check, already registered? */
+ new = logger_device_is_registered(ctx, wiphy);
+ if (new)
+ return new->radio_idx;
+
+ radio = logger_get_radio_idx(ctx);
+ if (radio < 0) {
+ pr_err("driver registration is full\n");
+ return -ENOMEM;
+ }
+
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
+ if (!new) {
+ logger_put_radio_idx(ctx, radio);
+ return -ENOMEM;
+ }
+
+ new->radio_idx = radio;
+ new->wiphy = wiphy;
+ new->ctx = ctx;
+ strlcpy(new->name, name, sizeof(new->name));
+ INIT_LIST_HEAD(&new->event_list);
+
+ list_add(&new->list, &ctx->dev_list);
+
+ pr_info("driver: [%s] is registered as radio-%d\n",
+ new->name, new->radio_idx);
+
+ return new->radio_idx;
+}
+EXPORT_SYMBOL(cnss_logger_device_register);
+
+/**
+ * cnss_logger_device_unregister() - unregister the driver
+ * @radio: the radio to unregister
+ * @wiphy: the wiphy device to unregister
+ *
+ * This function is used to unregister the driver from cnss logger module.
+ * This will disable the driver to access the interface in cnss logger,
+ * and also all the related events that registered will be reset.
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+ struct logger_context *ctx;
+ struct logger_device *cur;
+ struct list_head *pos, *temp;
+
+ ctx = logger_get_ctx();
+ if (!ctx)
+ return -ENOENT;
+
+ list_for_each_safe(pos, temp, &ctx->dev_list) {
+ cur = list_entry(pos, struct logger_device, list);
+ if (cur->radio_idx == radio && cur->wiphy == wiphy) {
+ logger_flush_devices(cur);
+ break;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cnss_logger_device_unregister);
+
+/**
+ * cnss_logger_nl_ucast() - nl interface to unicast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the flag to indicate if this is a nonblock call
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag)
+{
+ struct logger_context *ctx;
+
+ ctx = logger_get_ctx();
+ if (!ctx) {
+ dev_kfree_skb(skb);
+ return -ENOENT;
+ }
+
+ return netlink_unicast(ctx->nl_sock, skb, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_ucast);
+
+/**
+ * cnss_logger_nl_bcast() - nl interface to broadcast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the gfp_t flag
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag)
+{
+ struct logger_context *ctx;
+
+ ctx = logger_get_ctx();
+ if (!ctx) {
+ dev_kfree_skb(skb);
+ return -ENOENT;
+ }
+
+ return netlink_broadcast(ctx->nl_sock, skb, 0, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_bcast);
+
+/**
+ * logger_netlink_init() - initialize the netlink socket
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: the netlink handle if success, otherwise failure code
+ */
+int logger_netlink_init(struct logger_context *ctx)
+{
+ struct netlink_kernel_cfg cfg = {
+ .groups = CNSS_LOGGER_NL_MCAST_GRP_ID,
+ .input = logger_skb_input,
+ };
+
+ ctx->nl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
+ if (!ctx->nl_sock) {
+ pr_err("cnss_logger: Cannot create netlink socket");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&ctx->dev_list);
+
+ return 0;
+}
+
+/**
+ * logger_netlink_deinit() - release the netlink socket and other resource
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int logger_netlink_deinit(struct logger_context *ctx)
+{
+ struct list_head *pos, *temp;
+ struct logger_device *dev;
+
+ netlink_kernel_release(ctx->nl_sock);
+ list_for_each_safe(pos, temp, &ctx->dev_list) {
+ dev = container_of(pos, struct logger_device, list);
+ logger_flush_devices(dev);
+ }
+ return 0;
+}
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
index c02aabf..00ca8dc4 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
@@ -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
@@ -53,6 +53,8 @@
#define PCIE20_PARF_DBI_BASE_ADDR_HI 0x354
#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x358
#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI 0x35C
+#define PCIE20_PARF_ATU_BASE_ADDR 0x634
+#define PCIE20_PARF_ATU_BASE_ADDR_HI 0x638
#define PCIE20_PARF_DEVICE_TYPE 0x1000
#define PCIE20_ELBI_VERSION 0x00
@@ -98,6 +100,24 @@
#define PCIE20_PLR_IATU_LTAR 0x918
#define PCIE20_PLR_IATU_UTAR 0x91c
+#define PCIE20_IATU_BASE(n) (n * 0x200)
+
+#define PCIE20_IATU_O_CTRL1(n) (PCIE20_IATU_BASE(n) + 0x00)
+#define PCIE20_IATU_O_CTRL2(n) (PCIE20_IATU_BASE(n) + 0x04)
+#define PCIE20_IATU_O_LBAR(n) (PCIE20_IATU_BASE(n) + 0x08)
+#define PCIE20_IATU_O_UBAR(n) (PCIE20_IATU_BASE(n) + 0x0c)
+#define PCIE20_IATU_O_LAR(n) (PCIE20_IATU_BASE(n) + 0x10)
+#define PCIE20_IATU_O_LTAR(n) (PCIE20_IATU_BASE(n) + 0x14)
+#define PCIE20_IATU_O_UTAR(n) (PCIE20_IATU_BASE(n) + 0x18)
+
+#define PCIE20_IATU_I_CTRL1(n) (PCIE20_IATU_BASE(n) + 0x100)
+#define PCIE20_IATU_I_CTRL2(n) (PCIE20_IATU_BASE(n) + 0x104)
+#define PCIE20_IATU_I_LBAR(n) (PCIE20_IATU_BASE(n) + 0x108)
+#define PCIE20_IATU_I_UBAR(n) (PCIE20_IATU_BASE(n) + 0x10c)
+#define PCIE20_IATU_I_LAR(n) (PCIE20_IATU_BASE(n) + 0x110)
+#define PCIE20_IATU_I_LTAR(n) (PCIE20_IATU_BASE(n) + 0x114)
+#define PCIE20_IATU_I_UTAR(n) (PCIE20_IATU_BASE(n) + 0x118)
+
#define PCIE20_MHICFG 0x110
#define PCIE20_BHI_EXECENV 0x228
@@ -129,7 +149,7 @@
#define EP_PCIE_LOG_PAGES 50
#define EP_PCIE_MAX_VREG 2
-#define EP_PCIE_MAX_CLK 5
+#define EP_PCIE_MAX_CLK 7
#define EP_PCIE_MAX_PIPE_CLK 1
#define EP_PCIE_MAX_RESET 2
@@ -202,6 +222,7 @@
EP_PCIE_RES_MSI,
EP_PCIE_RES_DM_CORE,
EP_PCIE_RES_ELBI,
+ EP_PCIE_RES_IATU,
EP_PCIE_MAX_RES,
};
@@ -292,6 +313,7 @@
void __iomem *msi;
void __iomem *dm_core;
void __iomem *elbi;
+ void __iomem *iatu;
struct msm_bus_scale_pdata *bus_scale_table;
u32 bus_client;
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
index e48409b..055f026 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.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
@@ -68,6 +68,8 @@
{NULL, "pcie_0_slv_axi_clk", 0, true},
{NULL, "pcie_0_aux_clk", 1000000, true},
{NULL, "pcie_0_ldo", 0, true},
+ {NULL, "pcie_0_sleep_clk", 0, false},
+ {NULL, "pcie_0_slv_q2a_axi_clk", 0, false},
};
static struct ep_pcie_clk_info_t
@@ -82,12 +84,13 @@
};
static const struct ep_pcie_res_info_t ep_pcie_res_info[EP_PCIE_MAX_RES] = {
- {"parf", 0, 0},
- {"phy", 0, 0},
- {"mmio", 0, 0},
- {"msi", 0, 0},
- {"dm_core", 0, 0},
- {"elbi", 0, 0}
+ {"parf", NULL, NULL},
+ {"phy", NULL, NULL},
+ {"mmio", NULL, NULL},
+ {"msi", NULL, NULL},
+ {"dm_core", NULL, NULL},
+ {"elbi", NULL, NULL},
+ {"iatu", NULL, NULL},
};
static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = {
@@ -318,8 +321,8 @@
break;
}
EP_PCIE_DBG(dev,
- "PCIe V%d: set rate for clk %s.\n",
- dev->rev, info->name);
+ "PCIe V%d: set rate %d for clk %s.\n",
+ dev->rev, info->freq, info->name);
}
rc = clk_prepare_enable(info->hdl);
@@ -528,6 +531,47 @@
0xf, dev->link_speed);
}
+ if (dev->active_config) {
+ struct resource *dbi = dev->res[EP_PCIE_RES_DM_CORE].resource;
+ u32 dbi_lo = dbi->start;
+
+ EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
+
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
+ 0, BIT(0));
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
+ 0x200);
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
+ 0x0);
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
+ 0x100);
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
+ dbi_lo);
+
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: DBI base:0x%x.\n", dev->rev,
+ readl_relaxed(dev->parf + PCIE20_PARF_DBI_BASE_ADDR));
+
+ if (dev->phy_rev >= 6) {
+ struct resource *atu =
+ dev->res[EP_PCIE_RES_IATU].resource;
+ u32 atu_lo = atu->start;
+
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: configure MSB of ATU base for flipping and LSB as 0x%x.\n",
+ dev->rev, atu_lo);
+ ep_pcie_write_reg(dev->parf,
+ PCIE20_PARF_ATU_BASE_ADDR_HI, 0x100);
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_ATU_BASE_ADDR,
+ atu_lo);
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: LSB of ATU base:0x%x.\n",
+ dev->rev, readl_relaxed(dev->parf
+ + PCIE20_PARF_ATU_BASE_ADDR));
+ }
+ }
+
/* Read halts write */
ep_pcie_write_mask(dev->parf + PCIE20_PARF_AXI_MSTR_RD_HALT_NO_WRITES,
0, BIT(0));
@@ -646,13 +690,6 @@
dev->rev,
readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK));
}
-
- if (dev->active_config) {
- ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
-
- EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
- ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
- }
}
static void ep_pcie_config_inbound_iatu(struct ep_pcie_dev_t *dev)
@@ -671,6 +708,26 @@
ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_LOWER, lower);
ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_UPPER, 0x0);
+ if (dev->phy_rev >= 6) {
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL1(0), 0x0);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_LTAR(0), lower);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_UTAR(0), 0x0);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL2(0),
+ 0xc0000000);
+
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: Inbound iATU configuration.\n", dev->rev);
+ EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL1(0):0x%x\n",
+ readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL1(0)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_I_LTAR(0):0x%x\n",
+ readl_relaxed(dev->iatu + PCIE20_IATU_I_LTAR(0)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_I_UTAR(0):0x%x\n",
+ readl_relaxed(dev->iatu + PCIE20_IATU_I_UTAR(0)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL2(0):0x%x\n",
+ readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL2(0)));
+ return;
+ }
+
/* program inbound address translation using region 0 */
ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, 0x80000000);
/* set region to mem type */
@@ -701,6 +758,49 @@
"PCIe V%d: region:%d; lower:0x%x; limit:0x%x; target_lower:0x%x; target_upper:0x%x\n",
dev->rev, region, lower, limit, tgt_lower, tgt_upper);
+ if (dev->phy_rev >= 6) {
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_CTRL1(region),
+ 0x0);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LBAR(region),
+ lower);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UBAR(region),
+ upper);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LAR(region),
+ limit);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LTAR(region),
+ tgt_lower);
+ ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UTAR(region),
+ tgt_upper);
+ ep_pcie_write_mask(dev->iatu + PCIE20_IATU_O_CTRL2(region),
+ 0, BIT(31));
+
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: Outbound iATU configuration.\n", dev->rev);
+ EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL1:0x%x\n",
+ readl_relaxed(dev->iatu
+ + PCIE20_IATU_O_CTRL1(region)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_O_LBAR:0x%x\n",
+ readl_relaxed(dev->iatu +
+ PCIE20_IATU_O_LBAR(region)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_O_UBAR:0x%x\n",
+ readl_relaxed(dev->iatu +
+ PCIE20_IATU_O_UBAR(region)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_O_LAR:0x%x\n",
+ readl_relaxed(dev->iatu +
+ PCIE20_IATU_O_LAR(region)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_O_LTAR:0x%x\n",
+ readl_relaxed(dev->iatu +
+ PCIE20_IATU_O_LTAR(region)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_O_UTAR:0x%x\n",
+ readl_relaxed(dev->iatu +
+ PCIE20_IATU_O_UTAR(region)));
+ EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL2:0x%x\n",
+ readl_relaxed(dev->iatu +
+ PCIE20_IATU_O_CTRL2(region)));
+
+ return;
+ }
+
/* program outbound address translation using an input region */
ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, region);
/* set region to mem type */
@@ -813,12 +913,10 @@
ret = of_property_read_u32_array(
(&pdev->dev)->of_node,
"max-clock-frequency-hz", clkfreq, cnt);
- if (ret) {
- EP_PCIE_ERR(dev,
- "PCIe V%d: invalid max-clock-frequency-hz property:%d\n",
+ if (ret)
+ EP_PCIE_DBG2(dev,
+ "PCIe V%d: cannot get max-clock-frequency-hz property from DT:%d\n",
dev->rev, ret);
- goto out;
- }
}
for (i = 0; i < EP_PCIE_MAX_VREG; i++) {
@@ -1037,6 +1135,7 @@
dev->msi = dev->res[EP_PCIE_RES_MSI].base;
dev->dm_core = dev->res[EP_PCIE_RES_DM_CORE].base;
dev->elbi = dev->res[EP_PCIE_RES_ELBI].base;
+ dev->iatu = dev->res[EP_PCIE_RES_IATU].base;
out:
kfree(clkfreq);
@@ -1051,6 +1150,7 @@
dev->phy = NULL;
dev->mmio = NULL;
dev->msi = NULL;
+ dev->iatu = NULL;
if (dev->bus_client) {
msm_bus_scale_unregister_client(dev->bus_client);
@@ -1319,18 +1419,8 @@
}
checkbme:
- if (dev->active_config) {
- ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
- 0, BIT(0));
- ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
- 0x200);
- ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
- 0x0);
- ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
- 0x100);
- ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
- 0x7FFFE000);
- }
+ if (dev->active_config)
+ ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
if (!(opt & EP_PCIE_OPT_ENUM_ASYNC)) {
/* Wait for up to 1000ms for BME to be set */
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
index 776ef08..f813bb9 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.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
@@ -35,6 +35,11 @@
"PCIe V%d: PHY V%d: Initializing 10nm QMP phy - 100MHz\n",
dev->rev, dev->phy_rev);
break;
+ case 6:
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PHY V%d: Initializing 7nm QMP phy - 100MHz\n",
+ dev->rev, dev->phy_rev);
+ break;
default:
EP_PCIE_ERR(dev,
"PCIe V%d: Unexpected phy version %d is caught!\n",
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index e20ddba..bf498f9 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.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
@@ -3230,6 +3230,18 @@
return ret;
}
+/**
+ * ipa_pm_is_used() - Returns if IPA PM framework is used
+ */
+bool ipa_pm_is_used(void)
+{
+ bool ret;
+
+ IPA_API_DISPATCH_RETURN(ipa_pm_is_used);
+
+ return ret;
+}
+
static const struct dev_pm_ops ipa_pm_ops = {
.suspend_noirq = ipa_ap_suspend,
.resume_noirq = ipa_ap_resume,
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index f3e62b8..79d0c70 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -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
@@ -421,6 +421,8 @@
int (*ipa_get_smmu_params)(struct ipa_smmu_in_params *in,
struct ipa_smmu_out_params *out);
int (*ipa_is_vlan_mode)(enum ipa_vlan_ifaces iface, bool *res);
+
+ bool (*ipa_pm_is_used)(void);
};
#ifdef CONFIG_IPA
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 52ffa52..78d1c96 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3925,7 +3925,6 @@
ipa_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
ipa_ctx->use_dma_zone = resource_p->use_dma_zone;
ipa_ctx->tethered_flow_control = resource_p->tethered_flow_control;
- ipa_ctx->use_ipa_pm = resource_p->use_ipa_pm;
/* Setting up IPA RX Polling Timeout Seconds */
ipa_rx_timeout_min_max_calc(&ipa_ctx->ipa_rx_min_timeout_usec,
@@ -4451,20 +4450,12 @@
return result;
}
-bool ipa_pm_is_used(void)
-{
- return (ipa_ctx) ? ipa_ctx->use_ipa_pm : false;
-}
-
static int get_ipa_dts_configuration(struct platform_device *pdev,
struct ipa_plat_drv_res *ipa_drv_res)
{
int result;
struct resource *resource;
- ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
- "qcom,use-ipa-pm");
- IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
/* initialize ipa_res */
ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index ec4942f..91017a5 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -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
@@ -1206,7 +1206,6 @@
int num_ipa_cne_evt_req;
struct mutex ipa_cne_evt_lock;
bool ipa_uc_monitor_holb;
- bool use_ipa_pm;
};
/**
@@ -1263,7 +1262,6 @@
u32 ipa_rx_polling_sleep_msec;
u32 ipa_polling_iteration;
bool ipa_uc_monitor_holb;
- bool use_ipa_pm;
};
struct ipa_mem_partition {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index e06f6cf..27120c8 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -4984,6 +4984,11 @@
ipa_ctx->tag_process_before_gating = val;
}
+static bool ipa2_pm_is_used(void)
+{
+ return false;
+}
+
int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
struct ipa_api_controller *api_ctrl)
{
@@ -5159,6 +5164,7 @@
api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes;
api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes;
api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes;
+ api_ctrl->ipa_pm_is_used = ipa2_pm_is_used;
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 01c0736..0dd0b7b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -5381,11 +5381,6 @@
return result;
}
-bool ipa_pm_is_used(void)
-{
- return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
-}
-
static int get_ipa_dts_pm_info(struct platform_device *pdev,
struct ipa3_plat_drv_res *ipa_drv_res)
{
@@ -5973,6 +5968,7 @@
int bypass = 1;
u32 iova_ap_mapping[2];
u32 add_map_size;
+ u32 q6_smem_size;
const u32 *add_map;
void *smem_addr;
int i;
@@ -6089,9 +6085,18 @@
}
}
- /* map SMEM memory for IPA table accesses */
- smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
- SMEM_MODEM, 0);
+ result = of_property_read_u32_array(dev->of_node,
+ "qcom,ipa-q6-smem-size", &q6_smem_size, 1);
+ if (result) {
+ IPADBG("ipa q6 smem size = %d\n", IPA_SMEM_SIZE);
+ /* map SMEM memory for IPA table accesses */
+ smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
+ SMEM_MODEM, 0);
+ } else {
+ IPADBG("ipa q6 smem size = %d\n", q6_smem_size);
+ smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, q6_smem_size,
+ SMEM_MODEM, 0);
+ }
if (smem_addr) {
phys_addr_t iova = smem_virt_to_phys(smem_addr);
phys_addr_t pa = iova;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 9974b87..32e9891 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4336,6 +4336,11 @@
return 0;
}
+static bool ipa3_pm_is_used(void)
+{
+ return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
+}
+
int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
struct ipa_api_controller *api_ctrl)
{
@@ -4523,6 +4528,7 @@
api_ctrl->ipa_tz_unlock_reg = ipa3_tz_unlock_reg;
api_ctrl->ipa_get_smmu_params = ipa3_get_smmu_params;
api_ctrl->ipa_is_vlan_mode = ipa3_is_vlan_mode;
+ api_ctrl->ipa_pm_is_used = ipa3_pm_is_used;
return 0;
}
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 819fbf0..6adb44c 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -321,8 +321,11 @@
POWER_SUPPLY_ATTR(sdp_current_max),
POWER_SUPPLY_ATTR(connector_type),
POWER_SUPPLY_ATTR(parallel_batfet_mode),
+ POWER_SUPPLY_ATTR(parallel_fcc_max),
POWER_SUPPLY_ATTR(min_icl),
POWER_SUPPLY_ATTR(moisture_detected),
+ POWER_SUPPLY_ATTR(batt_full_current),
+ POWER_SUPPLY_ATTR(recharge_soc),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 3f8c727..223af14 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.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
@@ -73,6 +73,7 @@
int charge_type;
int total_settled_ua;
int pl_settled_ua;
+ int pl_fcc_max;
struct class qcom_batt_class;
struct wakeup_source *pl_ws;
struct notifier_block nb;
@@ -418,6 +419,7 @@
effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
slave_limited_ua = min(effective_total_ua, bcl_ua);
*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
+ *slave_ua = min(*slave_ua, chip->pl_fcc_max);
/*
* In stacked BATFET configuration charger's current goes
@@ -935,6 +937,12 @@
&pval);
chip->pl_min_icl_ua = pval.intval;
+ chip->pl_fcc_max = INT_MAX;
+ rc = power_supply_get_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, &pval);
+ if (!rc)
+ chip->pl_fcc_max = pval.intval;
+
vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
return true;
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index d1031ba..b07efdf 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -28,7 +28,67 @@
#include "smb5-reg.h"
#include "smb5-lib.h"
-static struct smb_params smb5_params = {
+static struct smb_params smb5_pmi632_params = {
+ .fcc = {
+ .name = "fast charge current",
+ .reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 50000,
+ },
+ .fv = {
+ .name = "float voltage",
+ .reg = CHGR_FLOAT_VOLTAGE_CFG_REG,
+ .min_u = 3600000,
+ .max_u = 4800000,
+ .step_u = 10000,
+ },
+ .usb_icl = {
+ .name = "usb input current limit",
+ .reg = USBIN_CURRENT_LIMIT_CFG_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 50000,
+ },
+ .icl_stat = {
+ .name = "input current limit status",
+ .reg = AICL_ICL_STATUS_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 50000,
+ },
+ .otg_cl = {
+ .name = "usb otg current limit",
+ .reg = DCDC_OTG_CURRENT_LIMIT_CFG_REG,
+ .min_u = 500000,
+ .max_u = 1000000,
+ .step_u = 250000,
+ },
+ .jeita_cc_comp_hot = {
+ .name = "jeita fcc reduction",
+ .reg = JEITA_CCCOMP_CFG_HOT_REG,
+ .min_u = 0,
+ .max_u = 1575000,
+ .step_u = 25000,
+ },
+ .jeita_cc_comp_cold = {
+ .name = "jeita fcc reduction",
+ .reg = JEITA_CCCOMP_CFG_COLD_REG,
+ .min_u = 0,
+ .max_u = 1575000,
+ .step_u = 25000,
+ },
+ .freq_switcher = {
+ .name = "switching frequency",
+ .reg = DCDC_FSW_SEL_REG,
+ .min_u = 600,
+ .max_u = 1200,
+ .step_u = 400,
+ .set_proc = smblib_set_chg_freq,
+ },
+};
+
+static struct smb_params smb5_pmi855_params = {
.fcc = {
.name = "fast charge current",
.reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
@@ -119,6 +179,64 @@
weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
);
+#define PMI632_MAX_ICL_UA 3000000
+static int smb5_chg_config_init(struct smb5 *chip)
+{
+ struct smb_charger *chg = &chip->chg;
+ struct pmic_revid_data *pmic_rev_id;
+ struct device_node *revid_dev_node;
+ int rc = 0;
+
+ revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property\n");
+ return -EINVAL;
+ }
+
+ pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR_OR_NULL(pmic_rev_id)) {
+ /*
+ * the revid peripheral must be registered, any failure
+ * here only indicates that the rev-id module has not
+ * probed yet.
+ */
+ rc = -EPROBE_DEFER;
+ goto out;
+ }
+
+ switch (pmic_rev_id->pmic_subtype) {
+ case PM855B_SUBTYPE:
+ chip->chg.smb_version = PM855B_SUBTYPE;
+ chg->param = smb5_pmi855_params;
+ chg->name = "pm855b_charger";
+ break;
+ case PMI632_SUBTYPE:
+ chip->chg.smb_version = PMI632_SUBTYPE;
+ chg->param = smb5_pmi632_params;
+ chg->use_extcon = true;
+ chg->name = "pmi632_charger";
+ chg->hw_max_icl_ua =
+ (chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
+ : PMI632_MAX_ICL_UA;
+ chg->chg_freq.freq_5V = 600;
+ chg->chg_freq.freq_6V_8V = 800;
+ chg->chg_freq.freq_9V = 1050;
+ chg->chg_freq.freq_removal = 1050;
+ chg->chg_freq.freq_below_otg_threshold = 800;
+ chg->chg_freq.freq_above_otg_threshold = 800;
+ break;
+ default:
+ pr_err("PMIC subtype %d not supported\n",
+ pmic_rev_id->pmic_subtype);
+ rc = -EINVAL;
+ }
+
+out:
+ of_node_put(revid_dev_node);
+ return rc;
+}
+
#define MICRO_1P5A 1500000
#define MICRO_P1A 100000
#define OTG_DEFAULT_DEGLITCH_TIME_MS 50
@@ -213,8 +331,6 @@
chip->dt.auto_recharge_soc = of_property_read_bool(node,
"qcom,auto-recharge-soc");
- chg->micro_usb_mode = of_property_read_bool(node, "qcom,micro-usb");
-
chg->dcp_icl_ua = chip->dt.usb_icl_ua;
chg->suspend_input_on_debug_batt = of_property_read_bool(node,
@@ -253,6 +369,8 @@
POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONNECTOR_TYPE,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
};
static int smb5_usb_get_prop(struct power_supply *psy,
@@ -272,12 +390,13 @@
if (!val->intval)
break;
- if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
- chg->micro_usb_mode) &&
- chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+ if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+ (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+ && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
val->intval = 0;
else
val->intval = 1;
+
if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
val->intval = 0;
break;
@@ -297,19 +416,19 @@
val->intval = chg->real_charger_type;
break;
case POWER_SUPPLY_PROP_TYPEC_MODE:
- if (chg->micro_usb_mode)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
val->intval = POWER_SUPPLY_TYPEC_NONE;
else
val->intval = chg->typec_mode;
break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
- if (chg->micro_usb_mode)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
else
rc = smblib_get_prop_typec_power_role(chg, val);
break;
case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION:
- if (chg->micro_usb_mode)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
val->intval = 0;
else
rc = smblib_get_prop_typec_cc_orientation(chg, val);
@@ -354,6 +473,9 @@
val->intval = get_client_vote(chg->usb_icl_votable,
USB_PSY_VOTER);
break;
+ case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
+ val->intval = chg->connector_type;
+ break;
default:
pr_err("get prop %d is not supported in usb\n", psp);
rc = -EINVAL;
@@ -496,9 +618,9 @@
if (!val->intval)
break;
- if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
- chg->micro_usb_mode) &&
- chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+ if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+ (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+ && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
val->intval = 1;
else
val->intval = 0;
@@ -1093,7 +1215,7 @@
struct regulator_config cfg = {};
int rc = 0;
- if (chg->micro_usb_mode)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
return 0;
chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
@@ -1139,7 +1261,6 @@
}
rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
- MICRO_USB_STATE_CHANGE_INT_EN_BIT |
TYPEC_WATER_DETECTION_INT_EN_BIT);
if (rc < 0) {
dev_err(chg->dev,
@@ -1172,14 +1293,23 @@
return rc;
}
+ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
+ MICRO_USB_STATE_CHANGE_INT_EN_BIT,
+ MICRO_USB_STATE_CHANGE_INT_EN_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't configure Type-C interrupts rc=%d\n", rc);
+ return rc;
+ }
+
return rc;
}
static int smb5_init_hw(struct smb5 *chip)
{
struct smb_charger *chg = &chip->chg;
- int rc;
- u8 val;
+ int rc, type = 0;
+ u8 val = 0;
if (chip->dt.no_battery)
chg->fake_capacity = 50;
@@ -1194,8 +1324,50 @@
smblib_get_charge_param(chg, &chg->param.usb_icl,
&chg->default_icl_ua);
- if (chip->dt.usb_icl_ua < 0)
- chip->dt.usb_icl_ua = chg->default_icl_ua;
+
+ /* Use SW based VBUS control, disable HW autonomous mode */
+ /* TODO: auth can be enabled through vote based on APSD flow */
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
+ HVDCP_AUTH_ALG_EN_CFG_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
+ return rc;
+ }
+
+ /*
+ * PMI632 can have the connector type defined by a dedicated register
+ * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
+ */
+ if (chg->smb_version == PMI632_SUBTYPE) {
+ rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
+ return rc;
+ }
+ type = !!(val & MICRO_USB_MODE_ONLY_BIT);
+ }
+
+ /*
+ * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
+ * check the connector type using TYPEC_U_USB_CFG_REG.
+ */
+ if (!type) {
+ rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ type = !!(val & EN_MICRO_USB_MODE_BIT);
+ }
+
+ chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
+ : POWER_SUPPLY_CONNECTOR_TYPEC;
+ pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
+
+ smblib_rerun_apsd_if_required(chg);
/* vote 0mA on usb_icl for non battery platforms */
vote(chg->usb_icl_votable,
@@ -1207,15 +1379,21 @@
vote(chg->fv_votable, HW_LIMIT_VOTER,
chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
vote(chg->fcc_votable,
- BATT_PROFILE_VOTER, true, chg->batt_profile_fcc_ua);
+ BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
+ chg->batt_profile_fcc_ua);
vote(chg->fv_votable,
- BATT_PROFILE_VOTER, true, chg->batt_profile_fv_uv);
+ BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
+ chg->batt_profile_fv_uv);
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
true, 0);
vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
true, 0);
vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
- chg->micro_usb_mode, 0);
+ chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);
+
+ /* Some h/w limit maximum supported ICL */
+ vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
+ chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
/*
* AICL configuration:
@@ -1235,7 +1413,7 @@
return rc;
}
- if (chg->micro_usb_mode)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
rc = smb5_configure_micro_usb(chg);
else
rc = smb5_configure_typec(chg);
@@ -1384,8 +1562,8 @@
pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
rc = smblib_set_prop_typec_power_role(chg, &pval);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure power role for DRP rc=%d\n", rc);
+ dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
+ rc);
return rc;
}
@@ -1405,6 +1583,7 @@
if (chg->bms_psy)
smblib_suspend_on_debug_battery(chg);
+
usb_plugin_irq_handler(0, &irq_data);
typec_state_change_irq_handler(0, &irq_data);
usb_source_change_irq_handler(0, &irq_data);
@@ -1412,6 +1591,7 @@
icl_change_irq_handler(0, &irq_data);
batt_temp_changed_irq_handler(0, &irq_data);
wdog_bark_irq_handler(0, &irq_data);
+ typec_or_rid_detection_change_irq_handler(0, &irq_data);
return 0;
}
@@ -1586,7 +1766,7 @@
/* TYPEC IRQs */
[TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
.name = "typec-or-rid-detect-change",
- .handler = default_irq_handler,
+ .handler = typec_or_rid_detection_change_irq_handler,
},
[TYPEC_VPD_DETECT_IRQ] = {
.name = "typec-vpd-detect",
@@ -1880,13 +2060,12 @@
chg = &chip->chg;
chg->dev = &pdev->dev;
- chg->param = smb5_params;
chg->debug_mask = &__debug_mask;
chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
chg->mode = PARALLEL_MASTER;
chg->irq_info = smb5_irqs;
chg->die_health = -EINVAL;
- chg->name = "pm855b_charger";
+ chg->otg_present = false;
chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
if (!chg->regmap) {
@@ -1897,13 +2076,20 @@
rc = smb5_parse_dt(chip);
if (rc < 0) {
pr_err("Couldn't parse device tree rc=%d\n", rc);
- goto cleanup;
+ return rc;
+ }
+
+ rc = smb5_chg_config_init(chip);
+ if (rc < 0) {
+ if (rc != -EPROBE_DEFER)
+ pr_err("Couldn't setup chg_config rc=%d\n", rc);
+ return rc;
}
rc = smblib_init(chg);
if (rc < 0) {
pr_err("Smblib_init failed rc=%d\n", rc);
- goto cleanup;
+ return rc;
}
/* set driver data before resources request it */
@@ -1945,10 +2131,12 @@
goto cleanup;
}
- rc = smb5_init_dc_psy(chip);
- if (rc < 0) {
- pr_err("Couldn't initialize dc psy rc=%d\n", rc);
- goto cleanup;
+ if (chg->smb_version == PM855B_SUBTYPE) {
+ rc = smb5_init_dc_psy(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize dc psy rc=%d\n", rc);
+ goto cleanup;
+ }
}
rc = smb5_init_usb_psy(chip);
@@ -1991,7 +2179,7 @@
rc = smb5_post_init(chip);
if (rc < 0) {
pr_err("Failed in post init rc=%d\n", rc);
- goto cleanup;
+ goto free_irq;
}
smb5_create_debugfs(chip);
@@ -1999,7 +2187,7 @@
rc = smb5_show_charger_status(chip);
if (rc < 0) {
pr_err("Failed in getting charger status rc=%d\n", rc);
- goto cleanup;
+ goto free_irq;
}
device_init_wakeup(chg->dev, true);
@@ -2008,8 +2196,9 @@
return rc;
-cleanup:
+free_irq:
smb5_free_interrupts(chg);
+cleanup:
smblib_deinit(chg);
platform_set_drvdata(pdev, NULL);
@@ -2036,7 +2225,7 @@
smb5_disable_interrupts(chg);
/* configure power role for UFP */
- if (!chg->micro_usb_mode)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index ebaaf5c..ffbced6 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -31,6 +31,7 @@
/* SMB1355 registers, different than mentioned in smb-reg.h */
+#define REVID_BASE 0x0100
#define CHGR_BASE 0x1000
#define ANA2_BASE 0x1100
#define BATIF_BASE 0x1200
@@ -38,6 +39,8 @@
#define ANA1_BASE 0x1400
#define MISC_BASE 0x1600
+#define REVID_MFG_ID_SPARE_REG (REVID_BASE + 0xFF)
+
#define BATTERY_STATUS_2_REG (CHGR_BASE + 0x0B)
#define DISABLE_CHARGING_BIT BIT(3)
@@ -222,6 +225,8 @@
char *name;
struct regmap *regmap;
+ int max_fcc;
+
struct smb_dt_props dt;
struct smb_params param;
struct smb_iio iio;
@@ -483,6 +488,7 @@
POWER_SUPPLY_PROP_PARALLEL_MODE,
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+ POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_MIN_ICL,
POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -624,6 +630,9 @@
case POWER_SUPPLY_PROP_MIN_ICL:
val->intval = MIN_PARALLEL_ICL_UA;
break;
+ case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX:
+ val->intval = chip->max_fcc;
+ break;
default:
pr_err_ratelimited("parallel psy get prop %d not supported\n",
prop);
@@ -798,6 +807,37 @@
* HARDWARE INITIALIZATION *
***************************/
+#define MFG_ID_SMB1354 0x01
+#define MFG_ID_SMB1355 0xFF
+#define SMB1354_MAX_PARALLEL_FCC_UA 2500000
+static int smb1355_detect_version(struct smb1355 *chip)
+{
+ int rc;
+ u8 val;
+
+ rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val);
+ if (rc < 0) {
+ pr_err("Unable to read REVID rc=%d\n", rc);
+ return rc;
+ }
+
+ switch (val) {
+ case MFG_ID_SMB1354:
+ chip->name = "smb1354";
+ chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA;
+ break;
+ case MFG_ID_SMB1355:
+ chip->name = "smb1355";
+ chip->max_fcc = INT_MAX;
+ break;
+ default:
+ pr_err("Invalid value of REVID val=%d", val);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
static int smb1355_tskin_sensor_config(struct smb1355 *chip)
{
int rc;
@@ -1196,7 +1236,6 @@
chip->dev = &pdev->dev;
chip->param = v1_params;
chip->c_health = -EINVAL;
- chip->name = "smb1355";
mutex_init(&chip->write_lock);
INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work);
chip->disabled = true;
@@ -1214,6 +1253,12 @@
return -ENODEV;
}
+ rc = smb1355_detect_version(chip);
+ if (rc < 0) {
+ pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc);
+ goto cleanup;
+ }
+
platform_set_drvdata(pdev, chip);
rc = smb1355_parse_dt(chip);
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index ff7da6c..dbadd95 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -107,19 +107,6 @@
return 0;
}
-int smblib_icl_override(struct smb_charger *chg, bool override)
-{
- int rc;
-
- rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
- ICL_OVERRIDE_AFTER_APSD_BIT,
- override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
-
- return rc;
-}
-
int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
{
int rc = 0;
@@ -137,6 +124,39 @@
return rc;
}
+static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
+{
+ union extcon_property_value val;
+ union power_supply_propval prop_val;
+
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) {
+ smblib_get_prop_typec_cc_orientation(chg, &prop_val);
+ val.intval = ((prop_val.intval == 2) ? 1 : 0);
+ extcon_set_property(chg->extcon, id,
+ EXTCON_PROP_USB_TYPEC_POLARITY, val);
+ }
+
+ val.intval = true;
+ extcon_set_property(chg->extcon, id,
+ EXTCON_PROP_USB_SS, val);
+}
+
+static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
+{
+ if (enable)
+ smblib_notify_extcon_props(chg, EXTCON_USB);
+
+ extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
+}
+
+static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
+{
+ if (enable)
+ smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
+
+ extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
+}
+
/********************
* REGISTER GETTERS *
********************/
@@ -281,6 +301,48 @@
/********************
* REGISTER SETTERS *
********************/
+static const struct buck_boost_freq chg_freq_list[] = {
+ [0] = {
+ .freq_khz = 2400,
+ .val = 7,
+ },
+ [1] = {
+ .freq_khz = 2100,
+ .val = 8,
+ },
+ [2] = {
+ .freq_khz = 1600,
+ .val = 11,
+ },
+ [3] = {
+ .freq_khz = 1200,
+ .val = 15,
+ },
+};
+
+int smblib_set_chg_freq(struct smb_chg_param *param,
+ int val_u, u8 *val_raw)
+{
+ u8 i;
+
+ if (val_u > param->max_u || val_u < param->min_u)
+ return -EINVAL;
+
+ /* Charger FSW is the configured freqency / 2 */
+ val_u *= 2;
+ for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
+ if (chg_freq_list[i].freq_khz == val_u)
+ break;
+ }
+ if (i == ARRAY_SIZE(chg_freq_list)) {
+ pr_err("Invalid frequency %d Hz\n", val_u / 2);
+ return -EINVAL;
+ }
+
+ *val_raw = chg_freq_list[i].val;
+
+ return 0;
+}
int smblib_set_opt_switcher_freq(struct smb_charger *chg, int fsw_khz)
{
@@ -316,11 +378,15 @@
if (rc < 0)
return -EINVAL;
} else {
- if (val_u > param->max_u || val_u < param->min_u) {
- smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
+ if (val_u > param->max_u || val_u < param->min_u)
+ smblib_dbg(chg, PR_MISC,
+ "%s: %d is out of range [%d, %d]\n",
param->name, val_u, param->min_u, param->max_u);
- return -EINVAL;
- }
+
+ if (val_u > param->max_u)
+ val_u = param->max_u;
+ if (val_u < param->min_u)
+ val_u = param->min_u;
val_raw = (val_u - param->min_u) / param->step_u;
}
@@ -771,69 +837,46 @@
int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
{
int rc = 0;
- bool override;
+ bool hc_mode = false;
/* suspend and return if 25mA or less is requested */
if (icl_ua <= USBIN_25MA)
return smblib_set_usb_suspend(chg, true);
if (icl_ua == INT_MAX)
- goto override_suspend_config;
+ goto set_mode;
/* configure current */
- if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+ if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
+ || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
rc = set_sdp_current(chg, icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
- goto enable_icl_changed_interrupt;
+ goto out;
}
} else {
set_sdp_current(chg, 100000);
rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
- goto enable_icl_changed_interrupt;
+ goto out;
}
+ hc_mode = true;
}
-override_suspend_config:
- /* determine if override needs to be enforced */
- override = true;
- if (icl_ua == INT_MAX) {
- /* remove override if no voters - hw defaults is desired */
- override = false;
- } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
- if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
- /* For std cable with type = SDP never override */
- override = false;
- else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
- && icl_ua == 1500000)
- /*
- * For std cable with type = CDP override only if
- * current is not 1500mA
- */
- override = false;
- }
-
- /* enforce override */
+set_mode:
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
-
- rc = smblib_icl_override(chg, override);
- if (rc < 0) {
- smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
- goto enable_icl_changed_interrupt;
- }
+ USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0);
/* unsuspend after configuring current and override */
rc = smblib_set_usb_suspend(chg, false);
if (rc < 0) {
smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
- goto enable_icl_changed_interrupt;
+ goto out;
}
-enable_icl_changed_interrupt:
+out:
return rc;
}
@@ -844,7 +887,7 @@
bool override;
if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
- || chg->micro_usb_mode)
+ || chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
&& (chg->usb_psy->desc->type == POWER_SUPPLY_TYPE_USB)) {
rc = get_sdp_current(chg, icl_ua);
if (rc < 0) {
@@ -881,6 +924,9 @@
{
struct smb_charger *chg = data;
+ if (chg->smb_version == PMI632_SUBTYPE)
+ return 0;
+
/* resume input if suspend is invalid */
if (suspend < 0)
suspend = 0;
@@ -1523,6 +1569,18 @@
return rc;
}
+static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
+{
+ int rc;
+
+ rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+ rc);
+
+ return rc;
+}
+
int smblib_dp_dm(struct smb_charger *chg, int val)
{
int target_icl_ua, rc = 0;
@@ -1573,6 +1631,21 @@
smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
target_icl_ua, chg->usb_icl_delta_ua);
break;
+ case POWER_SUPPLY_DP_DM_FORCE_5V:
+ rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
+ if (rc < 0)
+ pr_err("Failed to force 5V\n");
+ break;
+ case POWER_SUPPLY_DP_DM_FORCE_9V:
+ rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
+ if (rc < 0)
+ pr_err("Failed to force 9V\n");
+ break;
+ case POWER_SUPPLY_DP_DM_FORCE_12V:
+ rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
+ if (rc < 0)
+ pr_err("Failed to force 12V\n");
+ break;
case POWER_SUPPLY_DP_DM_ICL_UP:
default:
break;
@@ -1699,8 +1772,13 @@
{
switch (chg->real_charger_type) {
case POWER_SUPPLY_TYPE_USB_HVDCP:
+ case POWER_SUPPLY_TYPE_USB_HVDCP_3:
case POWER_SUPPLY_TYPE_USB_PD:
- val->intval = MICRO_12V;
+ if (chg->smb_version == PMI632_SUBTYPE)
+ val->intval = MICRO_9V;
+ else
+ val->intval = MICRO_12V;
+ break;
default:
val->intval = MICRO_5V;
break;
@@ -2053,7 +2131,7 @@
}
int smblib_set_prop_boost_current(struct smb_charger *chg,
- const union power_supply_propval *val)
+ const union power_supply_propval *val)
{
int rc = 0;
@@ -2076,6 +2154,9 @@
int rc = 0;
u8 power_role;
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+ return 0;
+
switch (val->intval) {
case POWER_SUPPLY_TYPEC_PR_NONE:
power_role = TYPEC_DISABLE_CMD_BIT;
@@ -2513,7 +2594,7 @@
} else {
chg->typec_present = 0;
smblib_update_usb_type(chg);
- extcon_set_state_sync(chg->extcon, EXTCON_USB, false);
+ smblib_notify_device_mode(chg, false);
smblib_uusb_removal(chg);
}
}
@@ -2601,7 +2682,7 @@
smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
}
- if (chg->micro_usb_mode)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
smblib_micro_usb_plugin(chg, vbus_rising);
power_supply_changed(chg->usb_psy);
@@ -2763,37 +2844,6 @@
rising ? "rising" : "falling");
}
-static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
-{
- union extcon_property_value val;
- union power_supply_propval prop_val;
-
- smblib_get_prop_typec_cc_orientation(chg, &prop_val);
- val.intval = ((prop_val.intval == 2) ? 1 : 0);
- extcon_set_property(chg->extcon, id,
- EXTCON_PROP_USB_TYPEC_POLARITY, val);
-
- val.intval = true;
- extcon_set_property(chg->extcon, id,
- EXTCON_PROP_USB_SS, val);
-}
-
-static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
-{
- if (enable)
- smblib_notify_extcon_props(chg, EXTCON_USB);
-
- extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
-}
-
-static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
-{
- if (enable)
- smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
-
- extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
-}
-
static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
{
const struct apsd_result *apsd_result;
@@ -2806,13 +2856,11 @@
switch (apsd_result->bit) {
case SDP_CHARGER_BIT:
case CDP_CHARGER_BIT:
- if (chg->micro_usb_mode)
- extcon_set_state_sync(chg->extcon, EXTCON_USB,
- true);
/* if not DCP then no hvdcp timeout happens. Enable pd here */
vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
false, 0);
- if (chg->use_extcon)
+ if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+ || chg->use_extcon)
smblib_notify_device_mode(chg, true);
break;
case OCP_CHARGER_BIT:
@@ -2845,8 +2893,9 @@
}
smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
- if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
- && !chg->uusb_apsd_rerun_done) {
+ if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+ && (stat & APSD_DTC_STATUS_DONE_BIT)
+ && !chg->uusb_apsd_rerun_done) {
/*
* Force re-run APSD to handle slow insertion related
* charger-mis-detection.
@@ -3146,12 +3195,12 @@
power_supply_changed(chg->usb_psy);
}
-irqreturn_t typec_state_change_irq_handler(int irq, void *data)
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- if (chg->micro_usb_mode) {
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
cancel_delayed_work_sync(&chg->uusb_otg_work);
vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
@@ -3160,7 +3209,16 @@
return IRQ_HANDLED;
}
- if (chg->pr_swap_in_progress) {
+ return IRQ_HANDLED;
+}
+
+irqreturn_t typec_state_change_irq_handler(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+
+ if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+ || chg->pr_swap_in_progress) {
smblib_dbg(chg, PR_INTERRUPT,
"Ignoring since pr_swap_in_progress\n");
return IRQ_HANDLED;
@@ -3335,10 +3393,20 @@
smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
goto out;
}
+ otg = !!(stat & U_USB_GROUND_NOVBUS_BIT);
+ if (chg->otg_present != otg)
+ smblib_notify_usb_host(chg, otg);
+ chg->otg_present = otg;
+ if (!otg)
+ chg->boost_current_ua = 0;
- otg = !!(stat & (U_USB_GROUND_NOVBUS_BIT | U_USB_GROUND_BIT));
- extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, otg);
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
+ rc = smblib_set_charge_param(chg, &chg->param.freq_switcher,
+ otg ? chg->chg_freq.freq_below_otg_threshold
+ : chg->chg_freq.freq_removal);
+ if (rc < 0)
+ dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
+
+ smblib_dbg(chg, PR_REGISTER, "TYPE_C_U_USB_STATUS = 0x%02x OTG=%d\n",
stat, otg);
power_supply_changed(chg->usb_psy);
@@ -3559,13 +3627,6 @@
return rc;
}
- rc = smblib_register_notifier(chg);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't register notifier rc=%d\n", rc);
- return rc;
- }
-
chg->bms_psy = power_supply_get_by_name("bms");
chg->pl.psy = power_supply_get_by_name("parallel");
if (chg->pl.psy) {
@@ -3576,6 +3637,12 @@
return rc;
}
}
+ rc = smblib_register_notifier(chg);
+ if (rc < 0) {
+ smblib_err(chg,
+ "Couldn't register notifier rc=%d\n", rc);
+ return rc;
+ }
break;
case PARALLEL_SLAVE:
break;
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index 8633ba0..fa7381c 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -196,6 +196,11 @@
u8 *val_raw);
};
+struct buck_boost_freq {
+ int freq_khz;
+ u8 val;
+};
+
struct smb_chg_freq {
unsigned int freq_5V;
unsigned int freq_6V_8V;
@@ -311,7 +316,7 @@
bool sw_jeita_enabled;
bool is_hdc;
bool chg_done;
- bool micro_usb_mode;
+ int connector_type;
bool otg_en;
bool suspend_input_on_debug_batt;
int otg_attempts;
@@ -329,6 +334,7 @@
u8 float_cfg;
bool use_extcon;
bool otg_present;
+ int hw_max_icl_ua;
/* workaround flag */
u32 wa_flags;
@@ -369,6 +375,8 @@
int val_u, u8 *val_raw);
int smblib_set_chg_freq(struct smb_chg_param *param,
int val_u, u8 *val_raw);
+int smblib_set_prop_boost_current(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_vbus_regulator_enable(struct regulator_dev *rdev);
int smblib_vbus_regulator_disable(struct regulator_dev *rdev);
int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev);
@@ -390,6 +398,7 @@
irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);
irqreturn_t wdog_bark_irq_handler(int irq, void *data);
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data);
int smblib_get_prop_input_suspend(struct smb_charger *chg,
union power_supply_propval *val);
@@ -470,8 +479,6 @@
const union power_supply_propval *val);
int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
const union power_supply_propval *val);
-int smblib_set_prop_boost_current(struct smb_charger *chg,
- const union power_supply_propval *val);
int smblib_set_prop_typec_power_role(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_pd_active(struct smb_charger *chg,
@@ -484,7 +491,6 @@
int smblib_rerun_apsd_if_required(struct smb_charger *chg);
int smblib_get_prop_fcc_delta(struct smb_charger *chg,
union power_supply_propval *val);
-int smblib_icl_override(struct smb_charger *chg, bool override);
int smblib_dp_dm(struct smb_charger *chg, int val);
int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable);
int smblib_rerun_aicl(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index 1534f7c..9a418c8 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -178,6 +178,8 @@
#define APSD_RERUN_BIT BIT(0)
#define CMD_HVDCP_2_REG (USBIN_BASE + 0x43)
+#define FORCE_12V_BIT BIT(5)
+#define FORCE_9V_BIT BIT(4)
#define FORCE_5V_BIT BIT(3)
#define SINGLE_DECREMENT_BIT BIT(1)
#define SINGLE_INCREMENT_BIT BIT(0)
@@ -196,6 +198,7 @@
};
#define USBIN_OPTIONS_1_CFG_REG (USBIN_BASE + 0x62)
+#define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6)
#define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5)
#define BC1P2_SRC_DETECT_BIT BIT(3)
@@ -299,6 +302,8 @@
#define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70)
#define EN_MICRO_USB_MODE_BIT BIT(0)
+#define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x70)
+#define MICRO_USB_MODE_ONLY_BIT BIT(0)
/********************************
* MISC Peripheral Registers *
********************************/
diff --git a/drivers/regulator/msm_gfx_ldo.c b/drivers/regulator/msm_gfx_ldo.c
index 2800607..115a9b7 100644
--- a/drivers/regulator/msm_gfx_ldo.c
+++ b/drivers/regulator/msm_gfx_ldo.c
@@ -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
@@ -773,12 +773,34 @@
return ldo_vreg->vreg_enabled;
}
+/**
+ * msm_gfx_ldo_list_corner_voltage() - return the ldo voltage mapped to
+ * the specified voltage corner
+ * @rdev: Regulator device pointer for the msm_gfx_ldo
+ * @corner: Voltage corner
+ *
+ * Return: voltage value in microvolts or -EINVAL if the corner is out of range
+ */
+static int msm_gfx_ldo_list_corner_voltage(struct regulator_dev *rdev,
+ int corner)
+{
+ struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
+
+ corner -= MIN_CORNER_OFFSET;
+
+ if (corner >= 0 && corner < ldo_vreg->num_corners)
+ return ldo_vreg->open_loop_volt[corner];
+ else
+ return -EINVAL;
+}
+
static struct regulator_ops msm_gfx_ldo_corner_ops = {
- .enable = msm_gfx_ldo_corner_enable,
- .disable = msm_gfx_ldo_disable,
- .is_enabled = msm_gfx_ldo_is_enabled,
- .set_voltage = msm_gfx_ldo_set_corner,
- .get_voltage = msm_gfx_ldo_get_corner,
+ .enable = msm_gfx_ldo_corner_enable,
+ .disable = msm_gfx_ldo_disable,
+ .is_enabled = msm_gfx_ldo_is_enabled,
+ .set_voltage = msm_gfx_ldo_set_corner,
+ .get_voltage = msm_gfx_ldo_get_corner,
+ .list_corner_voltage = msm_gfx_ldo_list_corner_voltage,
};
static int msm_gfx_ldo_get_bypass(struct regulator_dev *rdev,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index c3b2ca8..770f056 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -250,6 +250,17 @@
deadlocks. It does not run during the bootup process, so it will
not catch any early lockups.
+config QCOM_WDOG_IPI_ENABLE
+ bool "Qcom WDT pet optimization"
+ depends on QCOM_WATCHDOG_V2
+ default n
+ help
+ When this option is enabled, watchdog sends IPI to cores in low power
+ mode also. For power optimizations, by default watchdog don't ping
+ cores in low power mode at pettime.
+
+ To track CPUs health on LPM, or on debug builds enable it.
+
config QPNP_PBS
tristate "PBS trigger support for QPNP PMIC"
depends on SPMI
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0255761..c882403 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -65,9 +65,9 @@
obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) += memshare/
+obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
-obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 9becb10..da122fc 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -216,7 +216,6 @@
bool tx_blocked_signal_sent;
struct kthread_work kwork;
struct kthread_worker kworker;
- struct work_struct wakeup_work;
struct task_struct *task;
struct tasklet_struct tasklet;
struct srcu_struct use_ref;
@@ -854,6 +853,39 @@
}
/**
+ * tx_wakeup_worker() - worker function to wakeup tx blocked thread
+ * @work: kwork associated with the edge to process commands on.
+ */
+static void tx_wakeup_worker(struct edge_info *einfo)
+{
+ struct glink_transport_if xprt_if = einfo->xprt_if;
+ bool trigger_wakeup = false;
+ bool trigger_resume = false;
+ unsigned long flags;
+
+ if (einfo->in_ssr)
+ return;
+
+ spin_lock_irqsave(&einfo->write_lock, flags);
+ if (fifo_write_avail(einfo)) {
+ if (einfo->tx_blocked_signal_sent)
+ einfo->tx_blocked_signal_sent = false;
+ if (einfo->tx_resume_needed) {
+ einfo->tx_resume_needed = false;
+ trigger_resume = true;
+ }
+ }
+ if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
+ trigger_wakeup = true;
+ }
+ spin_unlock_irqrestore(&einfo->write_lock, flags);
+ if (trigger_wakeup)
+ wake_up_all(&einfo->tx_blocked_queue);
+ if (trigger_resume)
+ xprt_if.glink_core_if_ptr->tx_resume(&xprt_if);
+}
+
+/**
* __rx_worker() - process received commands on a specific edge
* @einfo: Edge to process commands on.
* @atomic_ctx: Indicates if the caller is in atomic context and requires any
@@ -903,7 +935,7 @@
if ((atomic_ctx) && ((einfo->tx_resume_needed) ||
(waitqueue_active(&einfo->tx_blocked_queue)))) /* tx waiting ?*/
- schedule_work(&einfo->wakeup_work);
+ tx_wakeup_worker(einfo);
/*
* Access to the fifo needs to be synchronized, however only the calls
@@ -1211,39 +1243,6 @@
}
/**
- * tx_wakeup_worker() - worker function to wakeup tx blocked thread
- * @work: kwork associated with the edge to process commands on.
- */
-static void tx_wakeup_worker(struct work_struct *work)
-{
- struct edge_info *einfo;
- bool trigger_wakeup = false;
- unsigned long flags;
- int rcu_id;
-
- einfo = container_of(work, struct edge_info, wakeup_work);
- rcu_id = srcu_read_lock(&einfo->use_ref);
- if (einfo->in_ssr) {
- srcu_read_unlock(&einfo->use_ref, rcu_id);
- return;
- }
- if (einfo->tx_resume_needed && fifo_write_avail(einfo)) {
- einfo->tx_resume_needed = false;
- einfo->xprt_if.glink_core_if_ptr->tx_resume(
- &einfo->xprt_if);
- }
- spin_lock_irqsave(&einfo->write_lock, flags);
- if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
- einfo->tx_blocked_signal_sent = false;
- trigger_wakeup = true;
- }
- spin_unlock_irqrestore(&einfo->write_lock, flags);
- if (trigger_wakeup)
- wake_up_all(&einfo->tx_blocked_queue);
- srcu_read_unlock(&einfo->use_ref, rcu_id);
-}
-
-/**
* rx_worker() - worker function to process received commands
* @work: kwork associated with the edge to process commands on.
*/
@@ -2425,7 +2424,6 @@
init_waitqueue_head(&einfo->tx_blocked_queue);
kthread_init_work(&einfo->kwork, rx_worker);
kthread_init_worker(&einfo->kworker);
- INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
einfo->read_from_fifo = read_from_fifo;
einfo->write_to_fifo = write_to_fifo;
@@ -2541,7 +2539,6 @@
reg_xprt_fail:
smem_alloc_fail:
kthread_flush_worker(&einfo->kworker);
- flush_work(&einfo->wakeup_work);
kthread_stop(einfo->task);
einfo->task = NULL;
tasklet_kill(&einfo->tasklet);
@@ -2629,7 +2626,6 @@
init_waitqueue_head(&einfo->tx_blocked_queue);
kthread_init_work(&einfo->kwork, rx_worker);
kthread_init_worker(&einfo->kworker);
- INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
einfo->intentless = true;
einfo->read_from_fifo = memcpy32_fromio;
@@ -2790,7 +2786,6 @@
reg_xprt_fail:
toc_init_fail:
kthread_flush_worker(&einfo->kworker);
- flush_work(&einfo->wakeup_work);
kthread_stop(einfo->task);
einfo->task = NULL;
tasklet_kill(&einfo->tasklet);
@@ -2922,7 +2917,6 @@
init_waitqueue_head(&einfo->tx_blocked_queue);
kthread_init_work(&einfo->kwork, rx_worker);
kthread_init_worker(&einfo->kworker);
- INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
einfo->read_from_fifo = read_from_fifo;
einfo->write_to_fifo = write_to_fifo;
@@ -3043,7 +3037,6 @@
reg_xprt_fail:
smem_alloc_fail:
kthread_flush_worker(&einfo->kworker);
- flush_work(&einfo->wakeup_work);
kthread_stop(einfo->task);
einfo->task = NULL;
tasklet_kill(&einfo->tasklet);
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index cef3c77..c93e0e1 100644
--- a/drivers/soc/qcom/ipc_router_glink_xprt.c
+++ b/drivers/soc/qcom/ipc_router_glink_xprt.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,6 +31,7 @@
module_param_named(debug_mask, ipc_router_glink_xprt_debug_mask,
int, 0664);
+#define IPCRTR_INTENT_REQ_TIMEOUT_MS 5000
#if defined(DEBUG)
#define D(x...) do { \
if (ipc_router_glink_xprt_debug_mask) \
@@ -43,6 +44,7 @@
#define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
#define IPC_RTR_XPRT_NAME_LEN (2 * GLINK_NAME_SIZE)
#define PIL_SUBSYSTEM_NAME_LEN 32
+#define IPC_RTR_WS_NAME_LEN ((2 * GLINK_NAME_SIZE) + 4)
#define MAX_NUM_LO_INTENTS 5
#define MAX_NUM_MD_INTENTS 3
@@ -59,6 +61,7 @@
* @transport: Physical Transport Name as identified by Glink.
* @pil_edge: Edge name understood by PIL.
* @ipc_rtr_xprt_name: XPRT Name to be registered with IPC Router.
+ * @notify_rx_ws_name: Name of wakesource used in notify rx path.
* @xprt: IPC Router XPRT structure to contain XPRT specific info.
* @ch_hndl: Opaque Channel handle returned by GLink.
* @xprt_wq: Workqueue to queue read & other XPRT related works.
@@ -79,9 +82,11 @@
char transport[GLINK_NAME_SIZE];
char pil_edge[PIL_SUBSYSTEM_NAME_LEN];
char ipc_rtr_xprt_name[IPC_RTR_XPRT_NAME_LEN];
+ char notify_rx_ws_name[IPC_RTR_WS_NAME_LEN];
struct msm_ipc_router_xprt xprt;
void *ch_hndl;
struct workqueue_struct *xprt_wq;
+ struct wakeup_source notify_rxv_ws;
struct rw_semaphore ss_reset_rwlock;
int ss_reset;
void *pil;
@@ -379,6 +384,7 @@
glink_rx_done(glink_xprtp->ch_hndl, rx_work->iovec, reuse_intent);
kfree(rx_work);
up_read(&glink_xprtp->ss_reset_rwlock);
+ __pm_relax(&glink_xprtp->notify_rxv_ws);
}
static void glink_xprt_open_event(struct work_struct *work)
@@ -493,6 +499,8 @@
rx_work->iovec_size = size;
rx_work->vbuf_provider = vbuf_provider;
rx_work->pbuf_provider = pbuf_provider;
+ if (!glink_xprtp->dynamic_wakeup_source)
+ __pm_stay_awake(&glink_xprtp->notify_rxv_ws);
INIT_WORK(&rx_work->work, glink_xprt_read_data);
queue_work(glink_xprtp->xprt_wq, &rx_work->work);
}
@@ -602,6 +610,7 @@
open_cfg.notify_state = glink_xprt_notify_state;
open_cfg.notify_rx_intent_req = glink_xprt_notify_rx_intent_req;
open_cfg.priv = glink_xprtp;
+ open_cfg.rx_intent_req_timeout_ms = IPCRTR_INTENT_REQ_TIMEOUT_MS;
glink_xprtp->pil = msm_ipc_load_subsystem(glink_xprtp);
glink_xprtp->ch_hndl = glink_open(&open_cfg);
@@ -760,7 +769,10 @@
kfree(glink_xprtp);
return -EFAULT;
}
-
+ scnprintf(glink_xprtp->notify_rx_ws_name, IPC_RTR_WS_NAME_LEN,
+ "%s_%s_rx", glink_xprtp->ch_name, glink_xprtp->edge);
+ wakeup_source_init(&glink_xprtp->notify_rxv_ws,
+ glink_xprtp->notify_rx_ws_name);
mutex_lock(&glink_xprt_list_lock_lha1);
list_add(&glink_xprtp->list, &glink_xprt_list);
mutex_unlock(&glink_xprt_list_lock_lha1);
diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c
index 4a41eee..a4d59f4 100644
--- a/drivers/soc/qcom/lpm-stats.c
+++ b/drivers/soc/qcom/lpm-stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -697,8 +697,10 @@
centry = &stats->child;
list_for_each_entry_reverse(pos, centry, sibling) {
- if (!list_empty(&pos->child))
+ if (!list_empty(&pos->child)) {
cleanup_stats(pos);
+ continue;
+ }
list_del_init(&pos->child);
diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c
index 2c379a0..bc665fd 100644
--- a/drivers/soc/qcom/rpmh_master_stat.c
+++ b/drivers/soc/qcom/rpmh_master_stat.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
@@ -13,21 +13,25 @@
#define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME
-#include <linux/debugfs.h>
-#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/uaccess.h>
#include <soc/qcom/smem.h>
+#include "rpmh_master_stat.h"
+
+#define UNIT_DIST 0x14
+#define REG_VALID 0x0
+#define REG_DATA_LO 0x4
+#define REG_DATA_HI 0x8
+
+#define GET_ADDR(REG, UNIT_NO) (REG + (UNIT_DIST * UNIT_NO))
enum master_smem_id {
MPSS = 605,
@@ -48,6 +52,14 @@
PID_DISPLAY = PID_APSS,
};
+enum profile_data {
+ POWER_DOWN_START,
+ POWER_UP_END,
+ POWER_DOWN_END,
+ POWER_UP_START,
+ NUM_UNIT,
+};
+
struct msm_rpmh_master_data {
char *master_name;
enum master_smem_id smem_id;
@@ -66,16 +78,24 @@
struct msm_rpmh_master_stats {
uint32_t version_id;
uint32_t counts;
- uint64_t last_entered_at;
- uint64_t last_exited_at;
+ uint64_t last_entered;
+ uint64_t last_exited;
uint64_t accumulated_duration;
};
+struct msm_rpmh_profile_unit {
+ uint64_t value;
+ uint64_t valid;
+};
+
struct rpmh_master_stats_prv_data {
struct kobj_attribute ka;
struct kobject *kobj;
};
+static struct msm_rpmh_master_stats apss_master_stats;
+static void __iomem *rpmh_unit_base;
+
static DEFINE_MUTEX(rpmh_stats_mutex);
static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length,
@@ -88,7 +108,7 @@
"\tSleep Last Exited At:0x%llx\n"
"\tSleep Accumulated Duration:0x%llx\n\n",
name, record->version_id, record->counts,
- record->last_entered_at, record->last_exited_at,
+ record->last_entered, record->last_exited,
record->accumulated_duration);
}
@@ -100,13 +120,16 @@
unsigned int size = 0;
struct msm_rpmh_master_stats *record = NULL;
- /*
- * Read SMEM data written by masters
- */
-
mutex_lock(&rpmh_stats_mutex);
- for (i = 0, length = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
+ /* First Read APSS master stats */
+
+ length = msm_rpmh_master_stats_print_data(buf, PAGE_SIZE,
+ &apss_master_stats, "APSS");
+
+ /* Read SMEM data written by other masters */
+
+ for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
record = (struct msm_rpmh_master_stats *) smem_get_entry(
rpmh_masters[i].smem_id, &size,
rpmh_masters[i].pid, 0);
@@ -122,30 +145,66 @@
return length;
}
+static inline void msm_rpmh_apss_master_stats_update(
+ struct msm_rpmh_profile_unit *profile_unit)
+{
+ apss_master_stats.counts++;
+ apss_master_stats.last_entered = profile_unit[POWER_DOWN_END].value;
+ apss_master_stats.last_exited = profile_unit[POWER_UP_START].value;
+ apss_master_stats.accumulated_duration +=
+ (apss_master_stats.last_exited
+ - apss_master_stats.last_entered);
+}
+
+void msm_rpmh_master_stats_update(void)
+{
+ int i;
+ struct msm_rpmh_profile_unit profile_unit[NUM_UNIT];
+
+ if (!rpmh_unit_base)
+ return;
+
+ for (i = POWER_DOWN_END; i < NUM_UNIT; i++) {
+ profile_unit[i].valid = readl_relaxed(rpmh_unit_base +
+ GET_ADDR(REG_VALID, i));
+
+ /*
+ * Do not update APSS stats if valid bit is not set.
+ * It means APSS did not execute cx-off sequence.
+ * This can be due to fall through at some point.
+ */
+
+ if (!(profile_unit[i].valid & BIT(REG_VALID)))
+ return;
+
+ profile_unit[i].value = readl_relaxed(rpmh_unit_base +
+ GET_ADDR(REG_DATA_LO, i));
+ profile_unit[i].value |= ((uint64_t)
+ readl_relaxed(rpmh_unit_base +
+ GET_ADDR(REG_DATA_HI, i)) << 32);
+ }
+ msm_rpmh_apss_master_stats_update(profile_unit);
+}
+EXPORT_SYMBOL(msm_rpmh_master_stats_update);
+
static int msm_rpmh_master_stats_probe(struct platform_device *pdev)
{
struct rpmh_master_stats_prv_data *prvdata = NULL;
struct kobject *rpmh_master_stats_kobj = NULL;
- int ret = 0;
+ int ret = -ENOMEM;
if (!pdev)
return -EINVAL;
- prvdata = kzalloc(sizeof(struct rpmh_master_stats_prv_data),
- GFP_KERNEL);
- if (!prvdata) {
- ret = -ENOMEM;
- goto fail;
- }
+ prvdata = devm_kzalloc(&pdev->dev, sizeof(*prvdata), GFP_KERNEL);
+ if (!prvdata)
+ return ret;
rpmh_master_stats_kobj = kobject_create_and_add(
"rpmh_stats",
power_kobj);
- if (!rpmh_master_stats_kobj) {
- ret = -ENOMEM;
- kfree(prvdata);
- goto fail;
- }
+ if (!rpmh_master_stats_kobj)
+ return ret;
prvdata->kobj = rpmh_master_stats_kobj;
@@ -158,14 +217,24 @@
ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr);
if (ret) {
pr_err("sysfs_create_file failed\n");
- kobject_put(prvdata->kobj);
- kfree(prvdata);
- goto fail;
+ goto fail_sysfs;
}
- platform_set_drvdata(pdev, prvdata);
+ rpmh_unit_base = of_iomap(pdev->dev.of_node, 0);
+ if (!rpmh_unit_base) {
+ pr_err("Failed to get rpmh_unit_base\n");
+ ret = -ENOMEM;
+ goto fail_iomap;
+ }
-fail:
+ apss_master_stats.version_id = 0x1;
+ platform_set_drvdata(pdev, prvdata);
+ return ret;
+
+fail_iomap:
+ sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
+fail_sysfs:
+ kobject_put(prvdata->kobj);
return ret;
}
@@ -181,14 +250,14 @@
sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
kobject_put(prvdata->kobj);
- kfree(prvdata);
platform_set_drvdata(pdev, NULL);
+ iounmap(rpmh_unit_base);
return 0;
}
static const struct of_device_id rpmh_master_table[] = {
- {.compatible = "qcom,rpmh-master-stats"},
+ {.compatible = "qcom,rpmh-master-stats-v1"},
{},
};
@@ -197,24 +266,11 @@
.remove = msm_rpmh_master_stats_remove,
.driver = {
.name = "msm_rpmh_master_stats",
- .owner = THIS_MODULE,
.of_match_table = rpmh_master_table,
},
};
-static int __init msm_rpmh_master_stats_init(void)
-{
- return platform_driver_register(&msm_rpmh_master_stats_driver);
-}
-
-static void __exit msm_rpmh_master_stats_exit(void)
-{
- platform_driver_unregister(&msm_rpmh_master_stats_driver);
-}
-
-module_init(msm_rpmh_master_stats_init);
-module_exit(msm_rpmh_master_stats_exit);
-
+module_platform_driver(msm_rpmh_master_stats_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MSM RPMH Master Statistics driver");
MODULE_ALIAS("platform:msm_rpmh_master_stat_log");
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/drivers/soc/qcom/rpmh_master_stat.h
similarity index 61%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to drivers/soc/qcom/rpmh_master_stat.h
index 194bfeb..c3fe7dc 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/drivers/soc/qcom/rpmh_master_stat.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -9,16 +9,15 @@
* 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/;
+#if defined(CONFIG_QTI_RPMH_API) && defined(CONFIG_QTI_RPM_STATS_LOG)
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+void msm_rpmh_master_stats_update(void);
-/ {
- model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
- compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
- qcom,board-id = <8 4>;
+#else
-};
+static inline void msm_rpmh_master_stats_update(void) {}
+
+#endif
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 685b384..0e83971 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -595,6 +595,10 @@
[294] = {MSM_CPU_8937, "MSM8937"},
[295] = {MSM_CPU_8937, "APQ8937"},
+ /* SDM429 and SDM439 ID*/
+ [353] = {MSM_CPU_SDM439, "SDM439"},
+ [354] = {MSM_CPU_SDM429, "SDM429"},
+
/* Uninitialized IDs are not known to run Linux.
* MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
@@ -1535,6 +1539,14 @@
dummy_socinfo.id = 349;
strlcpy(dummy_socinfo.build_id, "sdm632 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sdm439()) {
+ dummy_socinfo.id = 353;
+ strlcpy(dummy_socinfo.build_id, "sdm439 - ",
+ sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sdm429()) {
+ dummy_socinfo.id = 354;
+ strlcpy(dummy_socinfo.build_id, "sdm429 - ",
+ sizeof(dummy_socinfo.build_id));
}
strlcat(dummy_socinfo.build_id, "Dummy socinfo",
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index 480a33c..30b73db 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -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
@@ -19,6 +19,7 @@
#include <soc/qcom/system_pm.h>
#include <clocksource/arm_arch_timer.h>
+#include "rpmh_master_stat.h"
#define PDC_TIME_VALID_SHIFT 31
#define PDC_TIME_UPPER_MASK 0xFFFFFF
@@ -76,6 +77,7 @@
*/
void system_sleep_exit(void)
{
+ msm_rpmh_master_stats_update();
}
EXPORT_SYMBOL(system_sleep_exit);
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index 6d58d6b..8040d6d 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -112,12 +112,22 @@
module_param(WDT_HZ, long, 0);
/*
+ * Watchdog ipi optimization:
+ * Does not ping cores in low power mode at pet time to save power.
+ * This feature is enabled by default.
+ *
* On the kernel command line specify
- * watchdog_v2.ipi_opt_en=1 to enable the watchdog ipi ping
- * optimization. By default it is turned off
+ * watchdog_v2.ipi_en=1 to disable this optimization.
+ * Or, can be turned off, by enabling CONFIG_QCOM_WDOG_IPI_ENABLE.
*/
-static int ipi_opt_en;
-module_param(ipi_opt_en, int, 0);
+#ifdef CONFIG_QCOM_WDOG_IPI_ENABLE
+#define IPI_CORES_IN_LPM 1
+#else
+#define IPI_CORES_IN_LPM 0
+#endif
+
+static int ipi_en = IPI_CORES_IN_LPM;
+module_param(ipi_en, int, 0444);
static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
{
@@ -463,7 +473,7 @@
struct msm_watchdog_data *wdog_dd =
(struct msm_watchdog_data *)platform_get_drvdata(pdev);
- if (ipi_opt_en)
+ if (!ipi_en)
cpu_pm_unregister_notifier(&wdog_cpu_pm_nb);
mutex_lock(&wdog_dd->disable_lock);
@@ -709,7 +719,7 @@
if (wdog_dd->irq_ppi)
enable_percpu_irq(wdog_dd->bark_irq, 0);
- if (ipi_opt_en)
+ if (!ipi_en)
cpu_pm_register_notifier(&wdog_cpu_pm_nb);
dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
}
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 83b46d4..a1602e4 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -510,17 +510,36 @@
if (test_task_flag(tsk, TIF_MM_RELEASED))
continue;
- if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
- if (test_task_lmk_waiting(tsk)) {
- rcu_read_unlock();
- mutex_unlock(&scan_mutex);
- return 0;
- }
- }
+ if (oom_reaper) {
+ p = find_lock_task_mm(tsk);
+ if (!p)
+ continue;
- p = find_lock_task_mm(tsk);
- if (!p)
- continue;
+ if (test_bit(MMF_OOM_VICTIM, &p->mm->flags)) {
+ if (test_bit(MMF_OOM_SKIP, &p->mm->flags)) {
+ task_unlock(p);
+ continue;
+ } else if (time_before_eq(jiffies,
+ lowmem_deathpending_timeout)) {
+ task_unlock(p);
+ rcu_read_unlock();
+ mutex_unlock(&scan_mutex);
+ return 0;
+ }
+ }
+ } else {
+ if (time_before_eq(jiffies,
+ lowmem_deathpending_timeout))
+ if (test_task_lmk_waiting(tsk)) {
+ rcu_read_unlock();
+ mutex_unlock(&scan_mutex);
+ return 0;
+ }
+
+ p = find_lock_task_mm(tsk);
+ if (!p)
+ continue;
+ }
oom_score_adj = p->signal->oom_score_adj;
if (oom_score_adj < min_score_adj) {
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 27bf54b..1259654 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -58,4 +58,4 @@
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
obj-$(CONFIG_THERMAL_QPNP_ADC_TM) += qpnp-adc-tm.o
-obj-$(CONFIG_THERMAL_TSENS) += msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o
+obj-$(CONFIG_THERMAL_TSENS) += msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o tsens1xxx.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 9e96f8a..2c4a63a 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -237,11 +237,17 @@
case PM_POST_RESTORE:
case PM_POST_SUSPEND:
mutex_lock(&cooling_list_lock);
- mutex_lock(&core_isolate_lock);
list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+ mutex_lock(&core_isolate_lock);
if (cpufreq_dev->cpufreq_state ==
cpufreq_dev->max_level) {
cpu = cpumask_any(&cpufreq_dev->allowed_cpus);
+ /*
+ * Unlock this lock before calling
+ * schedule_isolate. as this could lead to
+ * deadlock with hotplug path.
+ */
+ mutex_unlock(&core_isolate_lock);
if (cpu_online(cpu) &&
!cpumask_test_and_set_cpu(cpu,
&cpus_isolated_by_thermal)) {
@@ -249,9 +255,10 @@
cpumask_clear_cpu(cpu,
&cpus_isolated_by_thermal);
}
+ continue;
}
+ mutex_unlock(&core_isolate_lock);
}
- mutex_unlock(&core_isolate_lock);
mutex_unlock(&cooling_list_lock);
atomic_set(&in_suspend, 0);
@@ -727,6 +734,7 @@
mutex_lock(&core_isolate_lock);
prev_state = cpufreq_device->cpufreq_state;
cpufreq_device->cpufreq_state = state;
+ mutex_unlock(&core_isolate_lock);
/* If state is the last, isolate the CPU */
if (state == cpufreq_device->max_level) {
if (cpu_online(cpu) &&
@@ -736,18 +744,11 @@
cpumask_clear_cpu(cpu,
&cpus_isolated_by_thermal);
}
- mutex_unlock(&core_isolate_lock);
return ret;
} else if ((prev_state == cpufreq_device->max_level)
&& (state < cpufreq_device->max_level)) {
if (cpumask_test_and_clear_cpu(cpu, &cpus_pending_online)) {
cpu_dev = get_cpu_device(cpu);
- mutex_unlock(&core_isolate_lock);
- /*
- * Unlock before calling the device_online.
- * Else, this will lead to deadlock, since the hp
- * online callback will be blocked on this mutex.
- */
ret = device_online(cpu_dev);
if (ret)
pr_err("CPU:%d online error:%d\n", cpu, ret);
@@ -757,7 +758,6 @@
sched_unisolate_cpu(cpu);
}
}
- mutex_unlock(&core_isolate_lock);
update_frequency:
clip_freq = cpufreq_device->freq_table[state];
cpufreq_device->clipped_freq = clip_freq;
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index fe0a7c7..c137d3d 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.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
@@ -49,6 +49,11 @@
return tmdev->ops->hw_init(tmdev);
}
+static int tsens_calib(struct tsens_device *tmdev)
+{
+ return tmdev->ops->calibrate(tmdev);
+}
+
static int tsens_register_interrupts(struct tsens_device *tmdev)
{
if (tmdev->ops->interrupts_reg)
@@ -82,6 +87,9 @@
{ .compatible = "qcom,tsens24xx",
.data = &data_tsens24xx,
},
+ { .compatible = "qcom,msm8937-tsens",
+ .data = &data_tsens14xx,
+ },
{}
};
MODULE_DEVICE_TABLE(of, tsens_table);
@@ -97,6 +105,7 @@
struct device_node *of_node = pdev->dev.of_node;
const struct of_device_id *id;
const struct tsens_data *data;
+ int rc = 0;
struct resource *res_tsens_mem;
if (!of_match_node(tsens_table, of_node)) {
@@ -150,7 +159,27 @@
return PTR_ERR(tmdev->tsens_tm_addr);
}
- return 0;
+ /* TSENS eeprom register region */
+ res_tsens_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "tsens_eeprom_physical");
+ if (!res_tsens_mem) {
+ pr_debug("Could not get tsens physical address resource\n");
+ } else {
+ tmdev->tsens_calib_addr = devm_ioremap_resource(&pdev->dev,
+ res_tsens_mem);
+ if (IS_ERR(tmdev->tsens_calib_addr)) {
+ dev_err(&pdev->dev, "Failed to IO map TSENS EEPROM registers.\n");
+ rc = PTR_ERR(tmdev->tsens_calib_addr);
+ } else {
+ rc = tsens_calib(tmdev);
+ if (rc) {
+ pr_err("Error initializing TSENS controller\n");
+ return rc;
+ }
+ }
+ }
+
+ return rc;
}
static int tsens_thermal_zone_register(struct tsens_device *tmdev)
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index ae4741d..885b15c 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.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
@@ -23,10 +23,15 @@
#define DEBUG_SIZE 10
#define TSENS_MAX_SENSORS 16
+#define TSENS_1x_MAX_SENSORS 11
#define TSENS_CONTROLLER_ID(n) (n)
#define TSENS_CTRL_ADDR(n) (n)
#define TSENS_TM_SN_STATUS(n) ((n) + 0xa0)
+#define ONE_PT_CALIB 0x1
+#define ONE_PT_CALIB2 0x2
+#define TWO_PT_CALIB 0x3
+
enum tsens_dbg_type {
TSENS_DBG_POLL,
TSENS_DBG_LOG_TEMP_READS,
@@ -70,6 +75,8 @@
int high_temp;
int low_temp;
int crit_temp;
+ int high_adc_code;
+ int low_adc_code;
};
struct tsens_sensor {
@@ -79,6 +86,8 @@
u32 id;
const char *sensor_name;
struct tsens_context thr_state;
+ int offset;
+ int slope;
};
/**
@@ -93,6 +102,7 @@
int (*interrupts_reg)(struct tsens_device *);
int (*dbg)(struct tsens_device *, u32, u32, int *);
int (*sensor_en)(struct tsens_device *, u32);
+ int (*calibrate)(struct tsens_device *);
};
struct tsens_irqs {
@@ -116,14 +126,15 @@
bool wd_bark;
u32 wd_bark_mask;
bool mtc;
+ bool valid_status_check;
};
struct tsens_mtc_sysfs {
- uint32_t zone_log;
+ u32 zone_log;
int zone_mtc;
int th1;
int th2;
- uint32_t zone_hist;
+ u32 zone_hist;
};
struct tsens_device {
@@ -134,6 +145,7 @@
struct regmap_field *status_field;
void __iomem *tsens_srot_addr;
void __iomem *tsens_tm_addr;
+ void __iomem *tsens_calib_addr;
const struct tsens_ops *ops;
struct tsens_dbg_context tsens_dbg;
spinlock_t tsens_crit_lock;
@@ -144,6 +156,7 @@
};
extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+extern const struct tsens_data data_tsens14xx;
extern struct list_head tsens_device_list;
#endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
new file mode 100644
index 0000000..e2fad32
--- /dev/null
+++ b/drivers/thermal/tsens1xxx.c
@@ -0,0 +1,654 @@
+/* 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
+ * 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/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include "tsens.h"
+#include "thermal_core.h"
+
+#define TSENS_DRIVER_NAME "msm-tsens"
+
+#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n) (n)
+#define TSENS_INTERRUPT_EN BIT(0)
+
+#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n) ((n) + 0x04)
+#define TSENS_UPPER_STATUS_CLR BIT(21)
+#define TSENS_LOWER_STATUS_CLR BIT(20)
+#define TSENS_UPPER_THRESHOLD_MASK 0xffc00
+#define TSENS_LOWER_THRESHOLD_MASK 0x3ff
+#define TSENS_UPPER_THRESHOLD_SHIFT 10
+
+#define TSENS_S0_STATUS_ADDR(n) ((n) + 0x30)
+#define TSENS_SN_ADDR_OFFSET 0x4
+#define TSENS_SN_STATUS_TEMP_MASK 0x3ff
+#define TSENS_SN_STATUS_LOWER_STATUS BIT(11)
+#define TSENS_SN_STATUS_UPPER_STATUS BIT(12)
+#define TSENS_STATUS_ADDR_OFFSET 2
+
+#define TSENS_TRDY_MASK BIT(0)
+
+#define TSENS_SN_STATUS_ADDR(n) ((n) + 0x44)
+#define TSENS_SN_STATUS_VALID BIT(14)
+#define TSENS_SN_STATUS_VALID_MASK 0x4000
+#define TSENS_TRDY_ADDR(n) ((n) + 0x84)
+
+#define TSENS_CTRL_ADDR(n) (n)
+#define TSENS_EN BIT(0)
+#define TSENS_CTRL_SENSOR_EN_MASK(n) ((n >> 3) & 0x7ff)
+#define TSENS_TRDY_RDY_MIN_TIME 2000
+#define TSENS_TRDY_RDY_MAX_TIME 2100
+#define TSENS_THRESHOLD_MAX_CODE 0x3ff
+#define TSENS_THRESHOLD_MIN_CODE 0x0
+
+/* eeprom layout data for 8937 */
+#define BASE0_MASK 0x000000ff
+#define BASE1_MASK 0xff000000
+#define BASE1_SHIFT 24
+
+#define S0_P1_MASK 0x000001f8
+#define S1_P1_MASK 0x001f8000
+#define S2_P1_MASK_0_4 0xf8000000
+#define S2_P1_MASK_5 0x00000001
+#define S3_P1_MASK 0x00001f80
+#define S4_P1_MASK 0x01f80000
+#define S5_P1_MASK 0x00003f00
+#define S6_P1_MASK 0x03f00000
+#define S7_P1_MASK 0x0000003f
+#define S8_P1_MASK 0x0003f000
+#define S9_P1_MASK 0x0000003f
+#define S10_P1_MASK 0x0003f000
+
+#define S0_P2_MASK 0x00007e00
+#define S1_P2_MASK 0x07e00000
+#define S2_P2_MASK 0x0000007e
+#define S3_P2_MASK 0x0007e000
+#define S4_P2_MASK 0x7e000000
+#define S5_P2_MASK 0x000fc000
+#define S6_P2_MASK 0xfc000000
+#define S7_P2_MASK 0x00000fc0
+#define S8_P2_MASK 0x00fc0000
+#define S9_P2_MASK 0x00000fc0
+#define S10_P2_MASK 0x00fc0000
+
+#define S0_P1_SHIFT 3
+#define S1_P1_SHIFT 15
+#define S2_P1_SHIFT_0_4 27
+#define S2_P1_SHIFT_5 5
+#define S3_P1_SHIFT 7
+#define S4_P1_SHIFT 19
+#define S5_P1_SHIFT 8
+#define S6_P1_SHIFT 20
+#define S8_P1_SHIFT 12
+#define S10_P1_SHIFT 12
+
+#define S0_P2_SHIFT 9
+#define S1_P2_SHIFT 21
+#define S2_P2_SHIFT 1
+#define S3_P2_SHIFT 13
+#define S4_P2_SHIFT 25
+#define S5_P2_SHIFT 14
+#define S6_P2_SHIFT 26
+#define S7_P2_SHIFT 6
+#define S8_P2_SHIFT 18
+#define S9_P2_SHIFT 6
+#define S10_P2_SHIFT 18
+
+#define CAL_SEL_MASK 0x00000007
+
+#define CAL_DEGC_PT1 30
+#define CAL_DEGC_PT2 120
+#define SLOPE_FACTOR 1000
+#define SLOPE_DEFAULT 3200
+
+/*
+ * Use this function on devices where slope and offset calculations
+ * depend on calibration data read from qfprom. On others the slope
+ * and offset values are derived from tz->tzp->slope and tz->tzp->offset
+ * resp.
+ */
+static void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
+ u32 *p2, u32 mode)
+{
+ int i;
+ int num, den;
+
+ for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+ pr_debug(
+ "sensor%d - data_point1:%#x data_point2:%#x\n",
+ i, p1[i], p2[i]);
+
+ tmdev->sensor[i].slope = SLOPE_DEFAULT;
+ if (mode == TWO_PT_CALIB) {
+ /*
+ * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+ * temp_120_degc - temp_30_degc (x2 - x1)
+ */
+ num = p2[i] - p1[i];
+ num *= SLOPE_FACTOR;
+ den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
+ tmdev->sensor[i].slope = num / den;
+ }
+
+ tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
+ (CAL_DEGC_PT1 *
+ tmdev->sensor[i].slope);
+ pr_debug("offset:%d\n", tmdev->sensor[i].offset);
+ }
+}
+
+static int code_to_degc(u32 adc_code, const struct tsens_sensor *sensor)
+{
+ int degc, num, den;
+
+ num = (adc_code * SLOPE_FACTOR) - sensor->offset;
+ den = sensor->slope;
+
+ if (num > 0)
+ degc = num + (den / 2);
+ else if (num < 0)
+ degc = num - (den / 2);
+ else
+ degc = num;
+
+ degc /= den;
+
+ return degc;
+}
+
+static int degc_to_code(int degc, const struct tsens_sensor *sensor)
+{
+ int code = ((degc * sensor->slope)
+ + sensor->offset)/SLOPE_FACTOR;
+
+ if (code > TSENS_THRESHOLD_MAX_CODE)
+ code = TSENS_THRESHOLD_MAX_CODE;
+ else if (code < TSENS_THRESHOLD_MIN_CODE)
+ code = TSENS_THRESHOLD_MIN_CODE;
+ pr_debug("raw_code:0x%x, degc:%d\n",
+ code, degc);
+ return code;
+}
+
+static int calibrate_8937(struct tsens_device *tmdev)
+{
+ int base0 = 0, base1 = 0, i;
+ u32 p1[TSENS_1x_MAX_SENSORS], p2[TSENS_1x_MAX_SENSORS];
+ int mode = 0, tmp = 0;
+ u32 qfprom_cdata[5] = {0, 0, 0, 0, 0};
+
+ qfprom_cdata[0] = readl_relaxed(tmdev->tsens_calib_addr + 0x1D8);
+ qfprom_cdata[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x1DC);
+ qfprom_cdata[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x210);
+ qfprom_cdata[3] = readl_relaxed(tmdev->tsens_calib_addr + 0x214);
+ qfprom_cdata[4] = readl_relaxed(tmdev->tsens_calib_addr + 0x230);
+
+ mode = (qfprom_cdata[2] & CAL_SEL_MASK);
+ pr_debug("calibration mode is %d\n", mode);
+
+ switch (mode) {
+ case TWO_PT_CALIB:
+ base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
+ p2[0] = (qfprom_cdata[2] & S0_P2_MASK) >> S0_P2_SHIFT;
+ p2[1] = (qfprom_cdata[2] & S1_P2_MASK) >> S1_P2_SHIFT;
+ p2[2] = (qfprom_cdata[3] & S2_P2_MASK) >> S2_P2_SHIFT;
+ p2[3] = (qfprom_cdata[3] & S3_P2_MASK) >> S3_P2_SHIFT;
+ p2[4] = (qfprom_cdata[3] & S4_P2_MASK) >> S4_P2_SHIFT;
+ p2[5] = (qfprom_cdata[0] & S5_P2_MASK) >> S5_P2_SHIFT;
+ p2[6] = (qfprom_cdata[0] & S6_P2_MASK) >> S6_P2_SHIFT;
+ p2[7] = (qfprom_cdata[1] & S7_P2_MASK) >> S7_P2_SHIFT;
+ p2[8] = (qfprom_cdata[1] & S8_P2_MASK) >> S8_P2_SHIFT;
+ p2[9] = (qfprom_cdata[4] & S9_P2_MASK) >> S9_P2_SHIFT;
+ p2[10] = (qfprom_cdata[4] & S10_P2_MASK) >> S10_P2_SHIFT;
+
+ for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+ p2[i] = ((base1 + p2[i]) << 2);
+ /* Fall through */
+ case ONE_PT_CALIB2:
+ base0 = (qfprom_cdata[0] & BASE0_MASK);
+ p1[0] = (qfprom_cdata[2] & S0_P1_MASK) >> S0_P1_SHIFT;
+ p1[1] = (qfprom_cdata[2] & S1_P1_MASK) >> S1_P1_SHIFT;
+ p1[2] = (qfprom_cdata[2] & S2_P1_MASK_0_4) >> S2_P1_SHIFT_0_4;
+ tmp = (qfprom_cdata[3] & S2_P1_MASK_5) << S2_P1_SHIFT_5;
+ p1[2] |= tmp;
+ p1[3] = (qfprom_cdata[3] & S3_P1_MASK) >> S3_P1_SHIFT;
+ p1[4] = (qfprom_cdata[3] & S4_P1_MASK) >> S4_P1_SHIFT;
+ p1[5] = (qfprom_cdata[0] & S5_P1_MASK) >> S5_P1_SHIFT;
+ p1[6] = (qfprom_cdata[0] & S6_P1_MASK) >> S6_P1_SHIFT;
+ p1[7] = (qfprom_cdata[1] & S7_P1_MASK);
+ p1[8] = (qfprom_cdata[1] & S8_P1_MASK) >> S8_P1_SHIFT;
+ p1[9] = (qfprom_cdata[4] & S9_P1_MASK);
+ p1[10] = (qfprom_cdata[4] & S10_P1_MASK) >> S10_P1_SHIFT;
+
+ for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+ p1[i] = (((base0) + p1[i]) << 2);
+ break;
+ default:
+ for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+ p1[i] = 500;
+ p2[i] = 780;
+ }
+ break;
+ }
+
+ compute_intercept_slope(tmdev, p1, p2, mode);
+
+ return 0;
+}
+
+static int tsens1xxx_get_temp(struct tsens_sensor *sensor, int *temp)
+{
+ struct tsens_device *tmdev = NULL;
+ unsigned int code;
+ void __iomem *sensor_addr;
+ void __iomem *trdy_addr;
+ int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+ bool last_temp_valid = false, last_temp2_valid = false;
+ bool last_temp3_valid = false;
+
+ if (!sensor)
+ return -EINVAL;
+
+ tmdev = sensor->tmdev;
+
+ trdy_addr = TSENS_TRDY_ADDR(tmdev->tsens_tm_addr);
+ sensor_addr = TSENS_SN_STATUS_ADDR(tmdev->tsens_tm_addr);
+
+ code = readl_relaxed(sensor_addr +
+ (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+ last_temp = code & TSENS_SN_STATUS_TEMP_MASK;
+
+ if (tmdev->ctrl_data->valid_status_check) {
+ if (code & TSENS_SN_STATUS_VALID)
+ last_temp_valid = true;
+ else {
+ code = readl_relaxed(sensor_addr +
+ (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+ last_temp2 = code & TSENS_SN_STATUS_TEMP_MASK;
+ if (code & TSENS_SN_STATUS_VALID) {
+ last_temp = last_temp2;
+ last_temp2_valid = true;
+ } else {
+ code = readl_relaxed(sensor_addr +
+ (sensor->hw_id <<
+ TSENS_STATUS_ADDR_OFFSET));
+ last_temp3 = code & TSENS_SN_STATUS_TEMP_MASK;
+ if (code & TSENS_SN_STATUS_VALID) {
+ last_temp = last_temp3;
+ last_temp3_valid = true;
+ }
+ }
+ }
+ }
+
+ if ((tmdev->ctrl_data->valid_status_check) &&
+ (!last_temp_valid && !last_temp2_valid && !last_temp3_valid)) {
+ if (last_temp == last_temp2)
+ last_temp = last_temp2;
+ else if (last_temp2 == last_temp3)
+ last_temp = last_temp3;
+ }
+
+ *temp = code_to_degc(last_temp, sensor);
+
+ return 0;
+}
+
+static int tsens_tz_activate_trip_type(struct tsens_sensor *tm_sensor,
+ int trip, enum thermal_device_mode mode)
+{
+ struct tsens_device *tmdev = NULL;
+ unsigned int reg_cntl, code, hi_code, lo_code, mask;
+
+ /* clear the interrupt and unmask */
+ if (!tm_sensor || trip < 0)
+ return -EINVAL;
+
+ tmdev = tm_sensor->tmdev;
+ if (!tmdev)
+ return -EINVAL;
+
+ lo_code = TSENS_THRESHOLD_MIN_CODE;
+ hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+ reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id *
+ TSENS_SN_ADDR_OFFSET)));
+
+ switch (trip) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ tmdev->sensor[tm_sensor->hw_id].thr_state.high_th_state = mode;
+
+ code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+ >> TSENS_UPPER_THRESHOLD_SHIFT;
+ mask = TSENS_UPPER_STATUS_CLR;
+
+ if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+ lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ tmdev->sensor[tm_sensor->hw_id].thr_state.low_th_state = mode;
+
+ code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+ mask = TSENS_LOWER_STATUS_CLR;
+
+ if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+ hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+ >> TSENS_UPPER_THRESHOLD_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mode == THERMAL_DEVICE_DISABLED)
+ writel_relaxed(reg_cntl | mask,
+ (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+ else
+ writel_relaxed(reg_cntl & ~mask,
+ (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+ /* Enable the thresholds */
+ mb();
+
+ return 0;
+}
+
+static int tsens1xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
+ int low_temp, int high_temp)
+{
+ unsigned int reg_cntl;
+ unsigned long flags;
+ struct tsens_device *tmdev = NULL;
+ int high_code, low_code, rc = 0;
+
+ if (!tm_sensor)
+ return -EINVAL;
+
+ tmdev = tm_sensor->tmdev;
+ if (!tmdev)
+ return -EINVAL;
+
+ spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+
+ if (high_temp != INT_MAX) {
+ high_code = degc_to_code(high_temp, tm_sensor);
+ tmdev->sensor[tm_sensor->hw_id].thr_state.high_adc_code =
+ high_code;
+ tmdev->sensor[tm_sensor->hw_id].thr_state.high_temp =
+ high_temp;
+
+ reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id *
+ TSENS_SN_ADDR_OFFSET));
+
+ high_code <<= TSENS_UPPER_THRESHOLD_SHIFT;
+ reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
+ writel_relaxed(reg_cntl | high_code,
+ (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id *
+ TSENS_SN_ADDR_OFFSET)));
+ }
+
+ if (low_temp != INT_MIN) {
+ low_code = degc_to_code(low_temp, tm_sensor);
+ tmdev->sensor[tm_sensor->hw_id].thr_state.low_adc_code =
+ low_code;
+ tmdev->sensor[tm_sensor->hw_id].thr_state.low_temp =
+ low_temp;
+
+ reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id *
+ TSENS_SN_ADDR_OFFSET));
+
+ reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
+ writel_relaxed(reg_cntl | low_code,
+ (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id *
+ TSENS_SN_ADDR_OFFSET)));
+ }
+ /* Set trip temperature thresholds */
+ mb();
+
+ if (high_temp != INT_MAX) {
+ rc = tsens_tz_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_HI,
+ THERMAL_DEVICE_ENABLED);
+ if (rc) {
+ pr_err("trip high enable error :%d\n", rc);
+ goto fail;
+ }
+ } else {
+ rc = tsens_tz_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_HI,
+ THERMAL_DEVICE_DISABLED);
+ if (rc) {
+ pr_err("trip high disable error :%d\n", rc);
+ goto fail;
+ }
+ }
+
+ if (low_temp != INT_MIN) {
+ rc = tsens_tz_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_DEVICE_ENABLED);
+ if (rc) {
+ pr_err("trip low enable activation error :%d\n", rc);
+ goto fail;
+ }
+ } else {
+ rc = tsens_tz_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_DEVICE_DISABLED);
+ if (rc) {
+ pr_err("trip low disable error :%d\n", rc);
+ goto fail;
+ }
+ }
+
+fail:
+ spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+ return rc;
+}
+
+static irqreturn_t tsens_irq_thread(int irq, void *data)
+{
+ struct tsens_device *tm = data;
+ unsigned int i, status, threshold, temp, th_temp;
+ unsigned long flags;
+ void __iomem *sensor_status_addr;
+ void __iomem *sensor_status_ctrl_addr;
+ u32 rc = 0, addr_offset;
+
+ sensor_status_addr = TSENS_SN_STATUS_ADDR(tm->tsens_tm_addr);
+ sensor_status_ctrl_addr =
+ TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tm->tsens_tm_addr);
+
+ for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+ bool upper_thr = false, lower_thr = false;
+
+ if (IS_ERR(tm->sensor[i].tzd))
+ continue;
+
+ rc = tsens1xxx_get_temp(&tm->sensor[i], &temp);
+ if (rc) {
+ pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
+ continue;
+ }
+
+ spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
+
+ addr_offset = tm->sensor[i].hw_id *
+ TSENS_SN_ADDR_OFFSET;
+ status = readl_relaxed(sensor_status_addr + addr_offset);
+ threshold = readl_relaxed(sensor_status_ctrl_addr +
+ addr_offset);
+
+ if (status & TSENS_SN_STATUS_UPPER_STATUS) {
+ writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
+ TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+ tm->tsens_tm_addr + addr_offset));
+ th_temp = code_to_degc((threshold &
+ TSENS_UPPER_THRESHOLD_MASK) >>
+ TSENS_UPPER_THRESHOLD_SHIFT,
+ tm->sensor);
+ if (th_temp > temp) {
+ pr_debug("Re-arm high threshold\n");
+ rc = tsens_tz_activate_trip_type(
+ &tm->sensor[i],
+ THERMAL_TRIP_CONFIGURABLE_HI,
+ THERMAL_DEVICE_ENABLED);
+ if (rc)
+ pr_err("high rearm failed");
+ } else {
+ upper_thr = true;
+ tm->sensor[i].thr_state.high_th_state =
+ THERMAL_DEVICE_DISABLED;
+ }
+ }
+
+ if (status & TSENS_SN_STATUS_LOWER_STATUS) {
+ writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
+ TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+ tm->tsens_tm_addr + addr_offset));
+ th_temp = code_to_degc((threshold &
+ TSENS_LOWER_THRESHOLD_MASK),
+ tm->sensor);
+ if (th_temp < temp) {
+ pr_debug("Re-arm Low threshold\n");
+ rc = tsens_tz_activate_trip_type(
+ &tm->sensor[i],
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_DEVICE_ENABLED);
+ if (rc)
+ pr_err("low rearm failed");
+ } else {
+ lower_thr = true;
+ tm->sensor[i].thr_state.low_th_state =
+ THERMAL_DEVICE_DISABLED;
+ }
+ }
+ spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
+
+ if (upper_thr || lower_thr) {
+ pr_debug("sensor:%d trigger temp (%d degC)\n",
+ tm->sensor[i].hw_id,
+ code_to_degc((status &
+ TSENS_SN_STATUS_TEMP_MASK),
+ tm->sensor));
+ of_thermal_handle_trip(tm->sensor[i].tzd);
+ }
+ }
+
+ /* Disable monitoring sensor trip threshold for triggered sensor */
+ mb();
+
+ return IRQ_HANDLED;
+}
+
+static int tsens1xxx_hw_sensor_en(struct tsens_device *tmdev,
+ u32 sensor_id)
+{
+ void __iomem *srot_addr;
+ unsigned int srot_val, sensor_en;
+
+ srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+ srot_val = readl_relaxed(srot_addr);
+ srot_val = TSENS_CTRL_SENSOR_EN_MASK(srot_val);
+
+ sensor_en = ((1 << sensor_id) & srot_val);
+
+ return sensor_en;
+}
+
+static int tsens1xxx_hw_init(struct tsens_device *tmdev)
+{
+ void __iomem *srot_addr;
+ unsigned int srot_val;
+
+ srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+ srot_val = readl_relaxed(srot_addr);
+ if (!(srot_val & TSENS_EN)) {
+ pr_err("TSENS device is not enabled\n");
+ return -ENODEV;
+ }
+
+ writel_relaxed(TSENS_INTERRUPT_EN,
+ TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_tm_addr));
+
+ spin_lock_init(&tmdev->tsens_upp_low_lock);
+
+ return 0;
+}
+
+static const struct tsens_irqs tsens1xxx_irqs[] = {
+ { "tsens-upper-lower", tsens_irq_thread},
+};
+
+static int tsens1xxx_register_interrupts(struct tsens_device *tmdev)
+{
+ struct platform_device *pdev;
+ int i, rc;
+
+ if (!tmdev)
+ return -EINVAL;
+
+ pdev = tmdev->pdev;
+
+ for (i = 0; i < ARRAY_SIZE(tsens1xxx_irqs); i++) {
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, tsens1xxx_irqs[i].name);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq %s\n",
+ tsens1xxx_irqs[i].name);
+ return irq;
+ }
+
+ rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ tsens1xxx_irqs[i].handler,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ tsens1xxx_irqs[i].name, tmdev);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to get irq %s\n",
+ tsens1xxx_irqs[i].name);
+ return rc;
+ }
+ enable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static const struct tsens_ops ops_tsens1xxx = {
+ .hw_init = tsens1xxx_hw_init,
+ .get_temp = tsens1xxx_get_temp,
+ .set_trips = tsens1xxx_set_trip_temp,
+ .interrupts_reg = tsens1xxx_register_interrupts,
+ .sensor_en = tsens1xxx_hw_sensor_en,
+ .calibrate = calibrate_8937,
+};
+
+const struct tsens_data data_tsens14xx = {
+ .ops = &ops_tsens1xxx,
+ .valid_status_check = true,
+ .mtc = true,
+};
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index 50c847f..af60a4b 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.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
@@ -59,9 +59,11 @@
#define TSENS_TM_SCALE_DECI_MILLIDEG 100
#define TSENS_DEBUG_WDOG_TRIGGER_COUNT 5
#define TSENS_TM_WATCHDOG_LOG(n) ((n) + 0x13c)
-
#define TSENS_EN BIT(0)
#define TSENS_CTRL_SENSOR_EN_MASK(n) ((n >> 3) & 0xffff)
+#define TSENS_TM_TRDY(n) ((n) + 0xe4)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE BIT(3)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT 3
static void msm_tsens_convert_temp(int last_temp, int *temp)
{
@@ -79,7 +81,7 @@
{
struct tsens_device *tmdev = NULL;
unsigned int code;
- void __iomem *sensor_addr;
+ void __iomem *sensor_addr, *trdy;
int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
if (!sensor)
@@ -87,6 +89,14 @@
tmdev = sensor->tmdev;
sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr);
+ trdy = TSENS_TM_TRDY(tmdev->tsens_tm_addr);
+
+ code = readl_relaxed_no_log(trdy);
+ if (!((code & TSENS_TM_TRDY_FIRST_ROUND_COMPLETE) >>
+ TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT)) {
+ pr_err("TSENS device first round not complete0x%x\n", code);
+ return -ENODATA;
+ }
code = readl_relaxed_no_log(sensor_addr +
(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index a9c073b..d4c243c 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,6 +11,7 @@
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h>
#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
#include "ci13xxx_udc.c"
@@ -24,9 +25,13 @@
int wake_gpio;
int wake_irq;
bool wake_irq_state;
+ struct pinctrl *ci13xxx_pinctrl;
+ struct timer_list irq_enable_timer;
+ bool irq_disabled;
};
static struct ci13xxx_udc_context _udc_ctxt;
+#define IRQ_ENABLE_DELAY (jiffies + msecs_to_jiffies(1000))
static irqreturn_t msm_udc_irq(int irq, void *data)
{
@@ -36,6 +41,7 @@
static void ci13xxx_msm_suspend(void)
{
struct device *dev = _udc->gadget.dev.parent;
+
dev_dbg(dev, "ci13xxx_msm_suspend\n");
if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) {
@@ -48,6 +54,7 @@
static void ci13xxx_msm_resume(void)
{
struct device *dev = _udc->gadget.dev.parent;
+
dev_dbg(dev, "ci13xxx_msm_resume\n");
if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
@@ -62,11 +69,27 @@
struct ci13xxx *udc = _udc;
struct usb_phy *phy = udc->transceiver;
- if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP))
+ if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+ u32 temp;
+
usb_phy_io_write(phy,
ULPI_MISC_A_VBUSVLDEXT |
ULPI_MISC_A_VBUSVLDEXTSEL,
ULPI_CLR(ULPI_MISC_A));
+
+ /* Notify LINK of VBUS LOW */
+ temp = readl_relaxed(USB_USBCMD);
+ temp &= ~USBCMD_SESS_VLD_CTRL;
+ writel_relaxed(temp, USB_USBCMD);
+
+ /*
+ * Add memory barrier as it is must to complete
+ * above USB PHY and Link register writes before
+ * moving ahead with USB peripheral mode enumeration,
+ * otherwise USB peripheral mode may not work.
+ */
+ mb();
+ }
}
/* Link power management will reduce power consumption by
@@ -102,9 +125,9 @@
ULPI_MISC_A_VBUSVLDEXTSEL,
ULPI_SET(ULPI_MISC_A));
- temp = readl_relaxed(USB_GENCONFIG2);
- temp |= GENCFG2_SESS_VLD_CTRL_EN;
- writel_relaxed(temp, USB_GENCONFIG2);
+ temp = readl_relaxed(USB_GENCONFIG_2);
+ temp |= GENCONFIG_2_SESS_VLD_CTRL_EN;
+ writel_relaxed(temp, USB_GENCONFIG_2);
temp = readl_relaxed(USB_USBCMD);
temp |= USBCMD_SESS_VLD_CTRL;
@@ -125,10 +148,17 @@
struct ci13xxx *udc = _udc;
struct usb_phy *phy = udc->transceiver;
struct device *dev = udc->gadget.dev.parent;
+ int temp;
writel_relaxed(0, USB_AHBBURST);
writel_relaxed(0x08, USB_AHBMODE);
+ /* workaround for rx buffer collision issue */
+ temp = readl_relaxed(USB_GENCONFIG);
+ temp &= ~GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE;
+ temp &= ~GENCONFIG_ULPI_SERIAL_EN;
+ writel_relaxed(temp, USB_GENCONFIG);
+
if (udc->gadget.l1_supported)
ci13xxx_msm_set_l1(udc);
@@ -149,7 +179,24 @@
}
}
-static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
+static void ci13xxx_msm_mark_err_event(void)
+{
+ struct ci13xxx *udc = _udc;
+ struct msm_otg *otg;
+
+ if (udc == NULL)
+ return;
+
+ if (udc->transceiver == NULL)
+ return;
+
+ otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+ /* This will trigger hardware reset before next connection */
+ otg->err_event_seen = true;
+}
+
+static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned int event)
{
struct device *dev = udc->gadget.dev.parent;
@@ -175,13 +222,36 @@
dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
ci13xxx_msm_resume();
break;
-
+ case CI13XXX_CONTROLLER_ERROR_EVENT:
+ dev_info(dev, "CI13XXX_CONTROLLER_ERROR_EVENT received\n");
+ ci13xxx_msm_mark_err_event();
+ break;
+ case CI13XXX_CONTROLLER_UDC_STARTED_EVENT:
+ dev_info(dev,
+ "CI13XXX_CONTROLLER_UDC_STARTED_EVENT received\n");
+ break;
default:
dev_dbg(dev, "unknown ci13xxx_udc event\n");
break;
}
}
+static bool ci13xxx_msm_in_lpm(struct ci13xxx *udc)
+{
+ struct msm_otg *otg;
+
+ if (udc == NULL)
+ return false;
+
+ if (udc->transceiver == NULL)
+ return false;
+
+ otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+ return (atomic_read(&otg->in_lpm) != 0);
+}
+
+
static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
{
struct ci13xxx *udc = _udc;
@@ -200,10 +270,10 @@
CI13XXX_REQUIRE_TRANSCEIVER |
CI13XXX_PULLUP_ON_VBUS |
CI13XXX_ZERO_ITC |
- CI13XXX_DISABLE_STREAMING |
- CI13XXX_IS_OTG,
+ CI13XXX_DISABLE_STREAMING,
.nz_itc = 0,
.notify_event = ci13xxx_msm_notify_event,
+ .in_lpm = ci13xxx_msm_in_lpm,
};
static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
@@ -211,10 +281,20 @@
{
int wake_irq;
int ret;
+ struct pinctrl_state *set_state;
dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");
_udc_ctxt.wake_gpio = res->start;
+ if (_udc_ctxt.ci13xxx_pinctrl) {
+ set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+ "ci13xxx_active");
+ if (IS_ERR(set_state)) {
+ pr_err("cannot get ci13xxx pinctrl active state\n");
+ return PTR_ERR(set_state);
+ }
+ pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl, set_state);
+ }
gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
gpio_direction_input(_udc_ctxt.wake_gpio);
wake_irq = gpio_to_irq(_udc_ctxt.wake_gpio);
@@ -238,20 +318,42 @@
gpio_free:
gpio_free(_udc_ctxt.wake_gpio);
+ if (_udc_ctxt.ci13xxx_pinctrl) {
+ set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+ "ci13xxx_sleep");
+ if (IS_ERR(set_state))
+ pr_err("cannot get ci13xxx pinctrl sleep state\n");
+ else
+ pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+ set_state);
+ }
_udc_ctxt.wake_gpio = 0;
return ret;
}
static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
{
+ struct pinctrl_state *set_state;
+
dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");
if (_udc_ctxt.wake_gpio) {
gpio_free(_udc_ctxt.wake_gpio);
+ if (_udc_ctxt.ci13xxx_pinctrl) {
+ set_state =
+ pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+ "ci13xxx_sleep");
+ if (IS_ERR(set_state))
+ pr_err("cannot get ci13xxx pinctrl sleep state\n");
+ else
+ pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+ set_state);
+ }
_udc_ctxt.wake_gpio = 0;
}
}
+static void enable_usb_irq_timer_func(unsigned long data);
static int ci13xxx_msm_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -271,6 +373,15 @@
1 << (pdata->log2_itc-1);
is_l1_supported = pdata->l1_supported;
+ /* Set ahb2ahb bypass flag if it is requested. */
+ if (pdata->enable_ahb2ahb_bypass)
+ ci13xxx_msm_udc_driver.flags |=
+ CI13XXX_ENABLE_AHB2AHB_BYPASS;
+
+ /* Clear disable streaming flag if is requested. */
+ if (pdata->enable_streaming)
+ ci13xxx_msm_udc_driver.flags &=
+ ~CI13XXX_DISABLE_STREAMING;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -301,6 +412,17 @@
}
res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
+ /* Get pinctrl if target uses pinctrl */
+ _udc_ctxt.ci13xxx_pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(_udc_ctxt.ci13xxx_pinctrl)) {
+ if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) {
+ dev_err(&pdev->dev, "Error encountered while getting pinctrl");
+ ret = PTR_ERR(_udc_ctxt.ci13xxx_pinctrl);
+ goto udc_remove;
+ }
+ dev_dbg(&pdev->dev, "Target does not use pinctrl\n");
+ _udc_ctxt.ci13xxx_pinctrl = NULL;
+ }
if (res) {
ret = ci13xxx_msm_install_wake_gpio(pdev, res);
if (ret < 0) {
@@ -316,7 +438,11 @@
goto gpio_uninstall;
}
+ setup_timer(&_udc_ctxt.irq_enable_timer, enable_usb_irq_timer_func,
+ (unsigned long)NULL);
+
pm_runtime_no_callbacks(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
@@ -341,6 +467,18 @@
return 0;
}
+void ci13xxx_msm_shutdown(struct platform_device *pdev)
+{
+ ci13xxx_pullup(&_udc->gadget, 0);
+}
+
+void msm_hw_soft_reset(void)
+{
+ struct ci13xxx *udc = _udc;
+
+ hw_device_reset(udc);
+}
+
void msm_hw_bam_disable(bool bam_disable)
{
u32 val;
@@ -354,12 +492,52 @@
writel_relaxed(val, USB_GENCONFIG);
}
+void msm_usb_irq_disable(bool disable)
+{
+ struct ci13xxx *udc = _udc;
+ unsigned long flags;
+
+ spin_lock_irqsave(udc->lock, flags);
+
+ if (_udc_ctxt.irq_disabled == disable) {
+ pr_debug("Interrupt state already disable = %d\n", disable);
+ if (disable)
+ mod_timer(&_udc_ctxt.irq_enable_timer,
+ IRQ_ENABLE_DELAY);
+ spin_unlock_irqrestore(udc->lock, flags);
+ return;
+ }
+
+ if (disable) {
+ disable_irq_nosync(_udc_ctxt.irq);
+ /* start timer here */
+ pr_debug("%s: Disabling interrupts\n", __func__);
+ mod_timer(&_udc_ctxt.irq_enable_timer, IRQ_ENABLE_DELAY);
+ _udc_ctxt.irq_disabled = true;
+
+ } else {
+ pr_debug("%s: Enabling interrupts\n", __func__);
+ del_timer(&_udc_ctxt.irq_enable_timer);
+ enable_irq(_udc_ctxt.irq);
+ _udc_ctxt.irq_disabled = false;
+ }
+
+ spin_unlock_irqrestore(udc->lock, flags);
+}
+
+static void enable_usb_irq_timer_func(unsigned long data)
+{
+ pr_debug("enabling interrupt from timer\n");
+ msm_usb_irq_disable(false);
+}
+
static struct platform_driver ci13xxx_msm_driver = {
.probe = ci13xxx_msm_probe,
.driver = {
.name = "msm_hsusb",
},
.remove = ci13xxx_msm_remove,
+ .shutdown = ci13xxx_msm_shutdown,
};
MODULE_ALIAS("platform:msm_hsusb");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b8389e2..28aaa1f 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -58,6 +58,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -66,22 +67,17 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/msm_hsusb.h>
-#include <linux/tracepoint.h>
-#include <mach/usb_trace.h>
-#include "ci13xxx_udc.h"
-/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
-static unsigned int streaming;
-module_param(streaming, uint, S_IRUGO | S_IWUSR);
+#include "ci13xxx_udc.h"
/******************************************************************************
* DEFINE
*****************************************************************************/
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define USB_MAX_TIMEOUT 25 /* 25msec timeout */
#define EP_PRIME_CHECK_DELAY (jiffies + msecs_to_jiffies(1000))
#define MAX_PRIME_CHECK_RETRY 3 /*Wait for 3sec for EP prime failure */
+#define EXTRA_ALLOCATION_SIZE 256
/* ctrl register bank access */
static DEFINE_SPINLOCK(udc_lock);
@@ -140,27 +136,12 @@
return n ? n-1 : 32;
}
-struct ci13xxx_ebi_err_entry {
- u32 *usb_req_buf;
- u32 usb_req_length;
- u32 ep_info;
- struct ci13xxx_ebi_err_entry *next;
-};
-
-struct ci13xxx_ebi_err_data {
- u32 ebi_err_addr;
- u32 apkt0;
- u32 apkt1;
- struct ci13xxx_ebi_err_entry *ebi_err_entry;
-};
-static struct ci13xxx_ebi_err_data *ebi_err_data;
-
/******************************************************************************
* HW block
*****************************************************************************/
/* register bank descriptor */
static struct {
- unsigned lpm; /* is LPM? */
+ unsigned int lpm; /* is LPM? */
void __iomem *abs; /* bus map offset */
void __iomem *cap; /* bus map offset + CAP offset + CAP data */
size_t size; /* bank size */
@@ -195,7 +176,7 @@
#define REMOTE_WAKEUP_DELAY msecs_to_jiffies(200)
/* maximum number of enpoints: valid only after hw_device_reset() */
-static unsigned hw_ep_max;
+static unsigned int hw_ep_max;
static void dbg_usb_op_fail(u8 addr, const char *name,
const struct ci13xxx_ep *mep);
/**
@@ -394,17 +375,26 @@
struct ci13xxx *udc = _udc;
if (dma) {
- if (streaming || !(udc->udc_driver->flags &
- CI13XXX_DISABLE_STREAMING))
+ if (!(udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)) {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
- else
+ pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+
+ } else {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
+ pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+ }
hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_CONNECT_EVENT);
+
+ /* Set BIT(31) to enable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+ pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
/* interrupt, error, port change, reset, sleep/suspend */
hw_cwrite(CAP_USBINTR, ~0,
@@ -413,6 +403,12 @@
} else {
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
hw_cwrite(CAP_USBINTR, ~0, 0);
+ /* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+ pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
}
return 0;
}
@@ -469,6 +465,10 @@
dir ? "IN" : "OUT");
debug_ept_flush_info(num, dir);
_udc->skip_flush = true;
+ /* Notify to trigger h/w reset recovery later */
+ if (_udc->udc_driver->notify_event)
+ _udc->udc_driver->notify_event(_udc,
+ CI13XXX_CONTROLLER_ERROR_EVENT);
return 0;
}
}
@@ -716,7 +716,7 @@
*/
static size_t hw_register_read(u32 *buf, size_t size)
{
- unsigned i;
+ unsigned int i;
if (size > hw_bank.size)
size = hw_bank.size;
@@ -827,9 +827,6 @@
/* ESS flushes only at end?!? */
hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */
- /* clear setup token semaphores */
- hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */
-
/* clear complete status */
hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */
@@ -841,8 +838,10 @@
/* reset all endpoints ? */
- /* reset internal status and wait for further instructions
- no need to verify the port reset status (ESS does it) */
+ /*
+ * reset internal status and wait for further instructions
+ * no need to verify the port reset status (ESS does it)
+ */
return 0;
}
@@ -862,7 +861,7 @@
struct usb_gadget *gadget = &udc->gadget;
int n = 0;
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
@@ -890,7 +889,7 @@
return n;
}
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
+static DEVICE_ATTR(device, 0400, show_device, NULL);
/**
* show_driver: prints information about attached gadget (if any)
@@ -904,7 +903,7 @@
struct usb_gadget_driver *driver = udc->driver;
int n = 0;
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
@@ -921,7 +920,7 @@
return n;
}
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
+static DEVICE_ATTR(driver, 0400, show_driver, NULL);
/* Maximum event message length */
#define DBG_DATA_MSG 64UL
@@ -931,10 +930,10 @@
/* Event buffer descriptor */
static struct {
- char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
- unsigned idx; /* index */
- unsigned tty; /* print to console? */
- rwlock_t lck; /* lock */
+ char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
+ unsigned int idx; /* index */
+ unsigned int tty; /* print to console? */
+ rwlock_t lck; /* lock */
} dbg_data = {
.idx = 0,
.tty = 0,
@@ -945,7 +944,7 @@
* dbg_dec: decrements debug event index
* @idx: buffer index
*/
-static void dbg_dec(unsigned *idx)
+static void dbg_dec(unsigned int *idx)
{
*idx = (*idx - 1) & (DBG_DATA_MAX-1);
}
@@ -954,16 +953,16 @@
* dbg_inc: increments debug event index
* @idx: buffer index
*/
-static void dbg_inc(unsigned *idx)
+static void dbg_inc(unsigned int *idx)
{
*idx = (*idx + 1) & (DBG_DATA_MAX-1);
}
static unsigned int ep_addr_txdbg_mask;
-module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
+module_param(ep_addr_txdbg_mask, uint, 0644);
static unsigned int ep_addr_rxdbg_mask;
-module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
+module_param(ep_addr_rxdbg_mask, uint, 0644);
static int allow_dbg_print(u8 addr)
{
@@ -985,6 +984,20 @@
return 0;
}
+#define TIME_BUF_LEN 20
+/*get_timestamp - returns time of day in us */
+static char *get_timestamp(char *tbuf)
+{
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000)/1000;
+ scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
+ nanosec_rem);
+ return tbuf;
+}
+
/**
* dbg_print: prints the common part of the event
* @addr: endpoint address
@@ -994,30 +1007,25 @@
*/
static void dbg_print(u8 addr, const char *name, int status, const char *extra)
{
- struct timeval tval;
- unsigned int stamp;
unsigned long flags;
+ char tbuf[TIME_BUF_LEN];
if (!allow_dbg_print(addr))
return;
write_lock_irqsave(&dbg_data.lck, flags);
- do_gettimeofday(&tval);
- stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
- stamp = stamp * 1000000 + tval.tv_usec;
-
scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
- "%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
+ "%s\t? %02X %-7.7s %4i ?\t%s\n",
+ get_timestamp(tbuf), addr, name, status, extra);
dbg_inc(&dbg_data.idx);
write_unlock_irqrestore(&dbg_data.lck, flags);
if (dbg_data.tty != 0)
- pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
+ pr_notice("%s\t? %02X %-7.7s %4i ?\t%s\n",
+ get_timestamp(tbuf), addr, name, status, extra);
}
/**
@@ -1110,8 +1118,8 @@
list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
scnprintf(msg, sizeof(msg),
- "%08X:%08X:%08X\n",
- req->dma, req->ptr->next,
+ "%pKa:%08X:%08X\n",
+ &req->dma, req->ptr->next,
req->ptr->token);
dbg_print(addr, "REQ", 0, msg);
scnprintf(msg, sizeof(msg), "%08X:%d\n",
@@ -1131,9 +1139,9 @@
char *buf)
{
unsigned long flags;
- unsigned i, j, n = 0;
+ unsigned int i, j, n = 0;
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
@@ -1166,15 +1174,15 @@
static ssize_t store_events(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- unsigned tty;
+ unsigned int tty;
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
goto done;
}
- if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+ if (kstrtouint(buf, 10, &tty) || tty > 1) {
dev_err(dev, "<1|0>: enable|disable console log\n");
goto done;
}
@@ -1185,7 +1193,7 @@
done:
return count;
}
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+static DEVICE_ATTR(events, 0600, show_events, store_events);
/**
* show_inters: interrupt status, enable status and historic
@@ -1198,9 +1206,9 @@
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
u32 intr;
- unsigned i, j, n = 0;
+ unsigned int i, j, n = 0;
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
@@ -1271,9 +1279,9 @@
{
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
- unsigned en, bit;
+ unsigned int en, bit;
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
goto done;
@@ -1299,7 +1307,7 @@
done:
return count;
}
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
+static DEVICE_ATTR(inters, 0600, show_inters, store_inters);
/**
* show_port_test: reads port test mode
@@ -1311,9 +1319,9 @@
{
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
- unsigned mode;
+ unsigned int mode;
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
@@ -1337,15 +1345,15 @@
{
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
- unsigned mode;
+ unsigned int mode;
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
goto done;
}
- if (sscanf(buf, "%u", &mode) != 1) {
+ if (kstrtouint(buf, 10, &mode)) {
dev_err(dev, "<mode>: set port test mode");
goto done;
}
@@ -1358,8 +1366,7 @@
done:
return count;
}
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
- show_port_test, store_port_test);
+static DEVICE_ATTR(port_test, 0600, show_port_test, store_port_test);
/**
* show_qheads: DMA contents of all queue heads
@@ -1371,9 +1378,9 @@
{
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
- unsigned i, j, n = 0;
+ unsigned int i, j, n = 0;
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
@@ -1383,6 +1390,7 @@
for (i = 0; i < hw_ep_max/2; i++) {
struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
+
n += scnprintf(buf + n, PAGE_SIZE - n,
"EP=%02i: RX=%08X TX=%08X\n",
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
@@ -1397,7 +1405,7 @@
return n;
}
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+static DEVICE_ATTR(qheads, 0400, show_qheads, NULL);
/**
* show_registers: dumps all registers
@@ -1411,19 +1419,17 @@
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
u32 *dump;
- unsigned i, k, n = 0;
+ unsigned int i, k, n = 0;
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
}
dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
- if (!dump) {
- dev_err(dev, "%s: out of memory\n", __func__);
+ if (!dump)
return 0;
- }
spin_lock_irqsave(udc->lock, flags);
k = hw_register_read(dump, DUMP_ENTRIES);
@@ -1432,7 +1438,7 @@
for (i = 0; i < k; i++) {
n += scnprintf(buf + n, PAGE_SIZE - n,
"reg[0x%04X] = 0x%08X\n",
- i * (unsigned)sizeof(u32), dump[i]);
+ i * (unsigned int)sizeof(u32), dump[i]);
}
kfree(dump);
@@ -1451,7 +1457,7 @@
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long addr, data, flags;
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
goto done;
@@ -1470,8 +1476,7 @@
done:
return count;
}
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
- show_registers, store_registers);
+static DEVICE_ATTR(registers, 0600, show_registers, store_registers);
/**
* show_requests: DMA contents of all requests currently queued (all endpts)
@@ -1485,9 +1490,9 @@
unsigned long flags;
struct list_head *ptr = NULL;
struct ci13xxx_req *req = NULL;
- unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+ unsigned int i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
- dbg_trace("[%s] %p\n", __func__, buf);
+ dbg_trace("[%s] %pK\n", __func__, buf);
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
@@ -1513,7 +1518,7 @@
return n;
}
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+static DEVICE_ATTR(requests, 0400, show_requests, NULL);
/* EP# and Direction */
static ssize_t prime_ept(struct device *dev,
@@ -1541,6 +1546,7 @@
mEp->qh.ptr->td.next = mReq->dma;
mEp->qh.ptr->td.token &= ~TD_STATUS;
+ /* Makes sure that above write goes through */
wmb();
hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
@@ -1555,7 +1561,7 @@
return count;
}
-static DEVICE_ATTR(prime, S_IWUSR, NULL, prime_ept);
+static DEVICE_ATTR(prime, 0200, NULL, prime_ept);
/* EP# and Direction */
static ssize_t print_dtds(struct device *dev,
@@ -1580,15 +1586,14 @@
mEp = &udc->ci13xxx_ep[ep_num];
n = hw_ep_bit(mEp->num, mEp->dir);
- pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s"
- "dTD_update_fail_count: %lu "
- "mEp->dTD_update_fail_count: %lu"
- "mEp->prime_fail_count: %lu\n", __func__,
+ pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s dTD_update_fail_count: %lu mEp->dTD_update_fail_count: %lu mEp->dTD_active_re_q_count: %lu mEp->prime_fail_count: %lu\n",
+ __func__,
hw_cread(CAP_ENDPTPRIME, ~0),
hw_cread(CAP_ENDPTSTAT, ~0),
mEp->num, mEp->dir ? "IN" : "OUT",
udc->dTD_update_fail_count,
mEp->dTD_update_fail_count,
+ mEp->dTD_active_re_q_count,
mEp->prime_fail_count);
pr_info("QH: cap:%08x cur:%08x next:%08x token:%08x\n",
@@ -1598,15 +1603,15 @@
list_for_each(ptr, &mEp->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
- pr_info("\treq:%08x next:%08x token:%08x page0:%08x status:%d\n",
- req->dma, req->ptr->next, req->ptr->token,
+ pr_info("\treq:%pKa next:%08x token:%08x page0:%08x status:%d\n",
+ &req->dma, req->ptr->next, req->ptr->token,
req->ptr->page[0], req->req.status);
}
done:
return count;
}
-static DEVICE_ATTR(dtds, S_IWUSR, NULL, print_dtds);
+static DEVICE_ATTR(dtds, 0200, NULL, print_dtds);
static int ci13xxx_wakeup(struct usb_gadget *_gadget)
{
@@ -1617,13 +1622,15 @@
trace();
spin_lock_irqsave(udc->lock, flags);
- if (!udc->remote_wakeup) {
+ if (!udc->gadget.remote_wakeup) {
ret = -EOPNOTSUPP;
dbg_trace("remote wakeup feature is not enabled\n");
goto out;
}
spin_unlock_irqrestore(udc->lock, flags);
+ pm_runtime_get_sync(&_gadget->dev);
+
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT);
@@ -1634,9 +1641,13 @@
if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
ret = -EINVAL;
dbg_trace("port is not suspended\n");
+ pm_runtime_put(&_gadget->dev);
goto out;
}
hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
+
+ pm_runtime_mark_last_busy(&_gadget->dev);
+ pm_runtime_put_autosuspend(&_gadget->dev);
out:
spin_unlock_irqrestore(udc->lock, flags);
return ret;
@@ -1653,7 +1664,7 @@
* if wakeup conditions are still met.
*/
spin_lock_irqsave(udc->lock, flags);
- do_wake = udc->suspended && udc->remote_wakeup;
+ do_wake = udc->suspended && udc->gadget.remote_wakeup;
spin_unlock_irqrestore(udc->lock, flags);
if (do_wake)
@@ -1669,7 +1680,7 @@
return count;
}
-static DEVICE_ATTR(wakeup, S_IWUSR, 0, usb_remote_wakeup);
+static DEVICE_ATTR(wakeup, 0200, 0, usb_remote_wakeup);
/**
* dbg_create_files: initializes the attribute interface
@@ -1677,7 +1688,7 @@
*
* This function returns an error code
*/
-__maybe_unused static int dbg_create_files(struct device *dev)
+static int __maybe_unused dbg_create_files(struct device *dev)
{
int retval = 0;
@@ -1749,7 +1760,7 @@
*
* This function returns an error code
*/
-__maybe_unused static int dbg_remove_files(struct device *dev)
+static int __maybe_unused dbg_remove_files(struct device *dev)
{
if (dev == NULL)
return -EINVAL;
@@ -1765,72 +1776,6 @@
return 0;
}
-static void dump_usb_info(void *ignore, unsigned int ebi_addr,
- unsigned int ebi_apacket0, unsigned int ebi_apacket1)
-{
- struct ci13xxx *udc = _udc;
- unsigned long flags;
- struct list_head *ptr = NULL;
- struct ci13xxx_req *req = NULL;
- struct ci13xxx_ep *mEp;
- unsigned i;
- struct ci13xxx_ebi_err_entry *temp_dump;
- static int count;
- u32 epdir = 0;
-
- if (count)
- return;
- count++;
-
- pr_info("%s: USB EBI error detected\n", __func__);
-
- ebi_err_data = kmalloc(sizeof(struct ci13xxx_ebi_err_data),
- GFP_ATOMIC);
- if (!ebi_err_data) {
- pr_err("%s: memory alloc failed for ebi_err_data\n", __func__);
- return;
- }
-
- ebi_err_data->ebi_err_entry = kmalloc(
- sizeof(struct ci13xxx_ebi_err_entry),
- GFP_ATOMIC);
- if (!ebi_err_data->ebi_err_entry) {
- kfree(ebi_err_data);
- pr_err("%s: memory alloc failed for ebi_err_entry\n", __func__);
- return;
- }
-
- ebi_err_data->ebi_err_addr = ebi_addr;
- ebi_err_data->apkt0 = ebi_apacket0;
- ebi_err_data->apkt1 = ebi_apacket1;
-
- temp_dump = ebi_err_data->ebi_err_entry;
- pr_info("\n DUMPING USB Requests Information\n");
- spin_lock_irqsave(udc->lock, flags);
- for (i = 0; i < hw_ep_max; i++) {
- list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) {
- mEp = &udc->ci13xxx_ep[i];
- req = list_entry(ptr, struct ci13xxx_req, queue);
-
- temp_dump->usb_req_buf = req->req.buf;
- temp_dump->usb_req_length = req->req.length;
- epdir = mEp->dir;
- temp_dump->ep_info = mEp->num | (epdir << 15);
-
- temp_dump->next = kmalloc(
- sizeof(struct ci13xxx_ebi_err_entry),
- GFP_ATOMIC);
- if (!temp_dump->next) {
- pr_err("%s: memory alloc failed\n", __func__);
- spin_unlock_irqrestore(udc->lock, flags);
- return;
- }
- temp_dump = temp_dump->next;
- }
- }
- spin_unlock_irqrestore(udc->lock, flags);
-}
-
/******************************************************************************
* UTIL block
*****************************************************************************/
@@ -1869,6 +1814,7 @@
req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
+ /* clean speculative fetches on req->ptr->token */
mb();
if (!(TD_STATUS_ACTIVE & req->ptr->token))
goto out;
@@ -1882,8 +1828,8 @@
mep->qh.ptr->td.next, mep->qh.ptr->td.token);
list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
- pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
- req->dma, req->ptr->next,
+ pr_info("\treq:%pKa:%08xtkn:%08xpage0:%08xsts:%d\n",
+ &req->dma, req->ptr->next,
req->ptr->token, req->ptr->page[0],
req->req.status);
}
@@ -1911,23 +1857,22 @@
*/
static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
- unsigned i;
+ unsigned int i;
int ret = 0;
- unsigned length = mReq->req.length;
+ unsigned int length = mReq->req.length;
struct ci13xxx *udc = _udc;
- trace("%p, %p", mEp, mReq);
+ trace("%pK, %pK", mEp, mReq);
/* don't queue twice */
if (mReq->req.status == -EALREADY)
return -EALREADY;
mReq->req.status = -EALREADY;
- if (length && mReq->req.dma == DMA_ADDR_INVALID) {
- mReq->req.dma = \
- dma_map_single(mEp->device, mReq->req.buf,
- length, mEp->dir ? DMA_TO_DEVICE :
- DMA_FROM_DEVICE);
+ if (length && mReq->req.dma == DMA_ERROR_CODE) {
+ mReq->req.dma = dma_map_single(mEp->device, mReq->req.buf,
+ length, mEp->dir ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
if (mReq->req.dma == 0)
return -ENOMEM;
@@ -1942,7 +1887,7 @@
dma_unmap_single(mEp->device, mReq->req.dma,
length, mEp->dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
+ mReq->req.dma = DMA_ERROR_CODE;
mReq->map = 0;
}
return -ENOMEM;
@@ -1953,6 +1898,7 @@
if (!mReq->req.no_interrupt)
mReq->zptr->token |= TD_IOC;
}
+
/*
* TD configuration
* TODO - handle requests which spawns into several TDs
@@ -1970,7 +1916,7 @@
}
/* MSM Specific: updating the request as required for
- * SPS mode. Enable MSM DMA engine acording
+ * SPS mode. Enable MSM DMA engine according
* to the UDC private data in the request.
*/
if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
@@ -1990,16 +1936,22 @@
for (i = 1; i < 5; i++)
mReq->ptr->page[i] = (mReq->req.dma + i * CI13XXX_PAGE_SIZE) &
~TD_RESERVED_MASK;
+ /* Makes sure that above write goes through */
wmb();
/* Remote Wakeup */
if (udc->suspended) {
- if (!udc->remote_wakeup) {
+ if (!udc->gadget.remote_wakeup) {
mReq->req.status = -EAGAIN;
- dev_dbg(mEp->device, "%s: queue failed (suspend) ept #%d\n",
- __func__, mEp->num);
+
+ dev_dbg(mEp->device, "%s: queue failed (suspend).",
+ __func__);
+ dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+ __func__, mEp->num);
+
return -EAGAIN;
}
+
usb_phy_set_suspend(udc->transceiver, 0);
schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
}
@@ -2016,6 +1968,7 @@
mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
else
mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+ /* Makes sure that above write goes through */
wmb();
if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto done;
@@ -2039,19 +1992,37 @@
goto done;
}
- /* QH configuration */
+ /* Hardware may leave few TDs unprocessed, check and reprime with 1st */
if (!list_empty(&mEp->qh.queue)) {
- struct ci13xxx_req *mReq = \
- list_entry(mEp->qh.queue.next,
- struct ci13xxx_req, queue);
+ struct ci13xxx_req *mReq_active, *mReq_next;
+ u32 i = 0;
- if (TD_STATUS_ACTIVE & mReq->ptr->token) {
- mEp->qh.ptr->td.next = mReq->dma;
- mEp->qh.ptr->td.token &= ~TD_STATUS;
- goto prime;
+ /* Nothing to be done if hardware already finished this TD */
+ if ((TD_STATUS_ACTIVE & mReq->ptr->token) == 0)
+ goto done;
+
+ /* Iterate forward to find first TD with ACTIVE bit set */
+ mReq_active = mReq;
+ list_for_each_entry(mReq_next, &mEp->qh.queue, queue) {
+ i++;
+ mEp->dTD_active_re_q_count++;
+ if (TD_STATUS_ACTIVE & mReq_next->ptr->token) {
+ mReq_active = mReq_next;
+ dbg_event(_usb_addr(mEp), "ReQUE",
+ mReq_next->ptr->token);
+ pr_debug("!!ReQ(%u-%u-%x)-%u!!\n", mEp->num,
+ mEp->dir, mReq_next->ptr->token, i);
+ break;
+ }
}
+
+ /* QH configuration */
+ mEp->qh.ptr->td.next = mReq_active->dma;
+ mEp->qh.ptr->td.token &= ~TD_STATUS;
+ goto prime;
}
+ /* QH configuration */
mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
@@ -2063,8 +2034,10 @@
i = (mEp->dir == TX) ?
((i >> MSM_TX_PIPE_ID_OFS) & MSM_PIPE_ID_MASK) :
(i & MSM_PIPE_ID_MASK);
- /* If requested pipe id is different from current,
- then write it */
+ /*
+ * If requested pipe id is different from current,
+ * then write it
+ */
if (i != (mReq->req.udc_priv & MSM_PIPE_ID_MASK)) {
if (mEp->dir == TX)
hw_cwrite(
@@ -2090,12 +2063,14 @@
mEp->qh.ptr->cap |= QH_ZLT;
prime:
+ /* Makes sure that above write goes through */
wmb(); /* synchronize before ep prime */
ret = hw_ep_prime(mEp->num, mEp->dir,
mEp->type == USB_ENDPOINT_XFER_CONTROL);
if (!ret)
mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+
done:
return ret;
}
@@ -2109,7 +2084,7 @@
*/
static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
- trace("%p, %p", mEp, mReq);
+ trace("%pK, %pK", mEp, mReq);
if (mReq->req.status != -EALREADY)
return -EINVAL;
@@ -2147,7 +2122,7 @@
if (mReq->map) {
dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
+ mReq->req.dma = DMA_ERROR_CODE;
mReq->map = 0;
}
@@ -2168,6 +2143,65 @@
}
/**
+ * purge_rw_queue: Purge requests pending at the remote-wakeup
+ * queue and send them to the HW.
+ *
+ * Go over all of the endpoints and push any pending requests to
+ * the HW queue.
+ */
+static void purge_rw_queue(struct ci13xxx *udc)
+{
+ int i;
+ struct ci13xxx_ep *mEp = NULL;
+ struct ci13xxx_req *mReq = NULL;
+
+ /*
+ * Go over all of the endpoints and push any pending requests to
+ * the HW queue.
+ */
+ for (i = 0; i < hw_ep_max; i++) {
+ mEp = &udc->ci13xxx_ep[i];
+
+ while (!list_empty(&udc->ci13xxx_ep[i].rw_queue)) {
+ int retval;
+
+ /* pop oldest request */
+ mReq = list_entry(udc->ci13xxx_ep[i].rw_queue.next,
+ struct ci13xxx_req, queue);
+
+ list_del_init(&mReq->queue);
+
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval != 0) {
+ dbg_event(_usb_addr(mEp), "QUEUE", retval);
+ mReq->req.status = retval;
+ if (mReq->req.complete != NULL) {
+ if (mEp->type ==
+ USB_ENDPOINT_XFER_CONTROL)
+ mReq->req.complete(
+ &(_udc->ep0in.ep),
+ &mReq->req);
+ else
+ mReq->req.complete(
+ &mEp->ep,
+ &mReq->req);
+ }
+ retval = 0;
+ }
+
+ if (!retval)
+ list_add_tail(&mReq->queue, &mEp->qh.queue);
+ else if (mEp->multi_req)
+ mEp->multi_req = false;
+
+ }
+ }
+
+ udc->rw_pending = false;
+}
+
+/**
* restore_original_req: Restore original req's attributes
* @mReq: Request
*
@@ -2187,6 +2221,67 @@
}
/**
+ * release_ep_request: Free and endpoint request and release
+ * resources
+ * @mReq: request
+ * @mEp: endpoint
+ *
+ */
+static void release_ep_request(struct ci13xxx_ep *mEp,
+ struct ci13xxx_req *mReq)
+{
+ struct ci13xxx_ep *mEpTemp = mEp;
+
+ unsigned int val;
+
+ /* MSM Specific: Clear end point specific register */
+ if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+ if (mReq->req.udc_priv & MSM_SPS_MODE) {
+ val = hw_cread(CAP_ENDPTPIPEID +
+ mEp->num * sizeof(u32),
+ ~0);
+
+ if (val != MSM_EP_PIPE_ID_RESET_VAL)
+ hw_cwrite(
+ CAP_ENDPTPIPEID +
+ mEp->num * sizeof(u32),
+ ~0, MSM_EP_PIPE_ID_RESET_VAL);
+ }
+ }
+ mReq->req.status = -ESHUTDOWN;
+
+ if (mReq->map) {
+ dma_unmap_single(mEp->device, mReq->req.dma,
+ mReq->req.length,
+ mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mReq->req.dma = DMA_ERROR_CODE;
+ mReq->map = 0;
+ }
+
+ if (mReq->zptr) {
+ dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+ mReq->zptr = NULL;
+ mReq->zdma = 0;
+ }
+
+ if (mEp->multi_req) {
+ restore_original_req(mReq);
+ mEp->multi_req = false;
+ }
+
+ if (mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+ mReq->req.length)
+ mEpTemp = &_udc->ep0in;
+ mReq->req.complete(&mEpTemp->ep, &mReq->req);
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mReq->req.complete = NULL;
+ spin_lock(mEp->lock);
+ }
+}
+
+/**
* _ep_nuke: dequeues all endpoint requests
* @mEp: endpoint
*
@@ -2197,10 +2292,7 @@
__releases(mEp->lock)
__acquires(mEp->lock)
{
- struct ci13xxx_ep *mEpTemp = mEp;
- unsigned val;
-
- trace("%p", mEp);
+ trace("%pK", mEp);
if (mEp == NULL)
return -EINVAL;
@@ -2211,53 +2303,34 @@
hw_ep_flush(mEp->num, mEp->dir);
while (!list_empty(&mEp->qh.queue)) {
-
/* pop oldest request */
- struct ci13xxx_req *mReq = \
+ struct ci13xxx_req *mReq =
list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
list_del_init(&mReq->queue);
- /* MSM Specific: Clear end point specific register */
- if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
- if (mReq->req.udc_priv & MSM_SPS_MODE) {
- val = hw_cread(CAP_ENDPTPIPEID +
- mEp->num * sizeof(u32),
- ~0);
-
- if (val != MSM_EP_PIPE_ID_RESET_VAL)
- hw_cwrite(
- CAP_ENDPTPIPEID +
- mEp->num * sizeof(u32),
- ~0, MSM_EP_PIPE_ID_RESET_VAL);
- }
- }
- mReq->req.status = -ESHUTDOWN;
-
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma,
- mReq->req.length,
- mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
-
- if (mEp->multi_req) {
- restore_original_req(mReq);
- mEp->multi_req = false;
- }
-
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
- mReq->req.length)
- mEpTemp = &_udc->ep0in;
- mReq->req.complete(&mEpTemp->ep, &mReq->req);
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mReq->req.complete = NULL;
- spin_lock(mEp->lock);
- }
+ release_ep_request(mEp, mReq);
}
+
+ /* Clear the requests pending at the remote-wakeup queue */
+ while (!list_empty(&mEp->rw_queue)) {
+
+ /* pop oldest request */
+ struct ci13xxx_req *mReq =
+ list_entry(mEp->rw_queue.next,
+ struct ci13xxx_req, queue);
+
+ list_del_init(&mReq->queue);
+
+ release_ep_request(mEp, mReq);
+ }
+
+ if (mEp->last_zptr) {
+ dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+ mEp->last_zptr = NULL;
+ mEp->last_zdma = 0;
+ }
+
return 0;
}
@@ -2272,23 +2345,18 @@
struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
unsigned long flags;
- trace("%p", gadget);
+ trace("%pK", gadget);
if (gadget == NULL)
return -EINVAL;
spin_lock_irqsave(udc->lock, flags);
udc->gadget.speed = USB_SPEED_UNKNOWN;
- udc->remote_wakeup = 0;
+ udc->gadget.remote_wakeup = 0;
udc->suspended = 0;
udc->configured = 0;
spin_unlock_irqrestore(udc->lock, flags);
- gadget->b_hnp_enable = 0;
- gadget->a_hnp_support = 0;
- gadget->host_request = 0;
- gadget->otg_srp_reqd = 0;
-
udc->driver->disconnect(gadget);
spin_lock_irqsave(udc->lock, flags);
@@ -2296,12 +2364,6 @@
_ep_nuke(&udc->ep0in);
spin_unlock_irqrestore(udc->lock, flags);
- if (udc->ep0in.last_zptr) {
- dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
- udc->ep0in.last_zdma);
- udc->ep0in.last_zptr = NULL;
- }
-
return 0;
}
@@ -2320,7 +2382,7 @@
{
int retval;
- trace("%p", udc);
+ trace("%pK", udc);
if (udc == NULL) {
err("EINVAL");
@@ -2349,6 +2411,9 @@
if (retval)
goto done;
+ if (udc->rw_pending)
+ purge_rw_queue(udc);
+
_udc->skip_flush = false;
retval = hw_usb_reset();
if (retval)
@@ -2377,9 +2442,13 @@
CI13XXX_CONTROLLER_RESUME_EVENT);
if (udc->transceiver)
usb_phy_set_suspend(udc->transceiver, 0);
+ udc->suspended = 0;
udc->driver->resume(&udc->gadget);
spin_lock(udc->lock);
- udc->suspended = 0;
+
+ if (udc->rw_pending)
+ purge_rw_queue(udc);
+
}
}
@@ -2415,7 +2484,7 @@
*/
static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
{
- trace("%p, %p", ep, req);
+ trace("%pK, %pK", ep, req);
if (ep == NULL || req == NULL) {
err("EINVAL");
@@ -2442,7 +2511,7 @@
struct usb_request *req = udc->status;
int dir, num, retval;
- trace("%p, %p", mEp, setup);
+ trace("%pK, %pK", mEp, setup);
if (mEp == NULL || setup == NULL)
return -EINVAL;
@@ -2452,18 +2521,11 @@
req->buf = udc->status_buf;
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- if (setup->wIndex == OTG_STATUS_SELECTOR) {
- *((u8 *)req->buf) = _udc->gadget.host_request <<
- HOST_REQUEST_FLAG;
- req->length = 1;
- } else {
- /* Assume that device is bus powered for now. */
- *((u16 *)req->buf) = _udc->remote_wakeup << 1;
- }
- /* TODO: D1 - Remote Wakeup; D0 - Self Powered */
+ /* Assume that device is bus powered for now. */
+ *((u16 *)req->buf) = _udc->gadget.remote_wakeup << 1;
retval = 0;
- } else if ((setup->bRequestType & USB_RECIP_MASK) \
- == USB_RECIP_ENDPOINT) {
+ } else if ((setup->bRequestType & USB_RECIP_MASK) ==
+ USB_RECIP_ENDPOINT) {
dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
TX : RX;
num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
@@ -2491,7 +2553,7 @@
struct ci13xxx *udc = req->context;
unsigned long flags;
- trace("%p, %p", ep, req);
+ trace("%pK, %pK", ep, req);
spin_lock_irqsave(udc->lock, flags);
if (udc->test_mode)
@@ -2512,7 +2574,7 @@
int retval;
struct ci13xxx_ep *mEp;
- trace("%p", udc);
+ trace("%pK", udc);
mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
udc->status->context = udc;
@@ -2539,11 +2601,11 @@
{
struct ci13xxx_req *mReq, *mReqTemp;
struct ci13xxx_ep *mEpTemp = mEp;
- int uninitialized_var(retval);
+ int retval = 0;
int req_dequeue = 1;
struct ci13xxx *udc = _udc;
- trace("%p", mEp);
+ trace("%pK", mEp);
if (list_empty(&mEp->qh.queue))
return 0;
@@ -2574,7 +2636,7 @@
req_dequeue = 0;
if (mEp->multi_req) { /* Large request in progress */
- unsigned remain_len;
+ unsigned int remain_len;
mReq->multi.actual += mReq->req.actual;
remain_len = mReq->multi.len - mReq->multi.actual;
@@ -2585,8 +2647,9 @@
} else {
mReq->req.buf = mReq->multi.buf +
mReq->multi.actual;
- mReq->req.length = min_t(unsigned, remain_len,
- (4 * CI13XXX_PAGE_SIZE));
+ mReq->req.length = min_t(unsigned int,
+ remain_len,
+ 4 * CI13XXX_PAGE_SIZE);
mReq->req.status = -EINPROGRESS;
mReq->req.actual = 0;
@@ -2638,10 +2701,10 @@
__releases(udc->lock)
__acquires(udc->lock)
{
- unsigned i;
+ unsigned int i;
u8 tmode = 0;
- trace("%p", udc);
+ trace("%pK", udc);
if (udc == NULL) {
err("EINVAL");
@@ -2728,7 +2791,7 @@
USB_DEVICE_REMOTE_WAKEUP) {
if (req.wLength != 0)
break;
- udc->remote_wakeup = 0;
+ udc->gadget.remote_wakeup = 0;
err = isr_setup_status_phase(udc);
} else {
goto delegate;
@@ -2739,7 +2802,8 @@
type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
type != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto delegate;
- if (le16_to_cpu(req.wValue) != 0)
+ if (le16_to_cpu(req.wLength) != 2 ||
+ le16_to_cpu(req.wValue) != 0)
break;
err = isr_get_status_response(udc, &req);
break;
@@ -2780,19 +2844,9 @@
break;
switch (le16_to_cpu(req.wValue)) {
case USB_DEVICE_REMOTE_WAKEUP:
- udc->remote_wakeup = 1;
+ udc->gadget.remote_wakeup = 1;
err = isr_setup_status_phase(udc);
break;
- case USB_DEVICE_B_HNP_ENABLE:
- udc->gadget.b_hnp_enable = 1;
- err = isr_setup_status_phase(udc);
- break;
- case USB_DEVICE_A_HNP_SUPPORT:
- udc->gadget.a_hnp_support = 1;
- err = isr_setup_status_phase(udc);
- break;
- case USB_DEVICE_A_ALT_HNP_SUPPORT:
- break;
case USB_DEVICE_TEST_MODE:
tmode = le16_to_cpu(req.wIndex) >> 8;
switch (tmode) {
@@ -2805,21 +2859,11 @@
err = isr_setup_status_phase(
udc);
break;
- case TEST_OTG_SRP_REQD:
- udc->gadget.otg_srp_reqd = 1;
- err = isr_setup_status_phase(
- udc);
- break;
- case TEST_OTG_HNP_REQD:
- udc->gadget.host_request = 1;
- err = isr_setup_status_phase(
- udc);
- break;
default:
break;
}
default:
- break;
+ goto delegate;
}
} else {
goto delegate;
@@ -2861,9 +2905,9 @@
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
int retval = 0;
unsigned long flags;
- unsigned mult = 0;
+ unsigned int mult = 0;
- trace("ep = %p, desc = %p", ep, desc);
+ trace("ep = %pK, desc = %pK", ep, desc);
if (ep == NULL || desc == NULL)
return -EINVAL;
@@ -2926,7 +2970,7 @@
int direction, retval = 0;
unsigned long flags;
- trace("%p", ep);
+ trace("%pK", ep);
if (ep == NULL)
return -EINVAL;
@@ -2949,12 +2993,6 @@
} while (mEp->dir != direction);
- if (mEp->last_zptr) {
- dma_pool_free(mEp->td_pool, mEp->last_zptr,
- mEp->last_zdma);
- mEp->last_zptr = NULL;
- }
-
mEp->desc = NULL;
mEp->ep.desc = NULL;
mEp->ep.maxpacket = USHRT_MAX;
@@ -2973,7 +3011,7 @@
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
struct ci13xxx_req *mReq = NULL;
- trace("%p, %i", ep, gfp_flags);
+ trace("%pK, %i", ep, gfp_flags);
if (ep == NULL) {
err("EINVAL");
@@ -2983,7 +3021,7 @@
mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
if (mReq != NULL) {
INIT_LIST_HEAD(&mReq->queue);
- mReq->req.dma = DMA_ADDR_INVALID;
+ mReq->req.dma = DMA_ERROR_CODE;
mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
&mReq->dma);
@@ -3009,7 +3047,7 @@
struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
unsigned long flags;
- trace("%p, %p", ep, req);
+ trace("%pK, %pK", ep, req);
if (ep == NULL || req == NULL) {
err("EINVAL");
@@ -3044,10 +3082,13 @@
unsigned long flags;
struct ci13xxx *udc = _udc;
- trace("%p, %p, %X", ep, req, gfp_flags);
+ trace("%pK, %pK, %X", ep, req, gfp_flags);
+
+ if (ep == NULL)
+ return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
- if (ep == NULL || req == NULL || mEp->desc == NULL) {
+ if (req == NULL || mEp->desc == NULL) {
retval = -EINVAL;
goto done;
}
@@ -3059,8 +3100,7 @@
if (!udc->configured && mEp->type !=
USB_ENDPOINT_XFER_CONTROL) {
- trace("usb is not configured"
- "ept #%d, ept name#%s\n",
+ trace("usb is not configured ept #%d, ept name#%s\n",
mEp->num, mEp->ep.name);
retval = -ESHUTDOWN;
goto done;
@@ -3077,6 +3117,12 @@
}
}
+ if (ep->endless && udc->gadget.speed == USB_SPEED_FULL) {
+ err("Queueing endless req is not supported for FS");
+ retval = -EINVAL;
+ goto done;
+ }
+
/* first nuke then test link, e.g. previous status has not sent */
if (!list_empty(&mReq->queue)) {
retval = -EBUSY;
@@ -3113,6 +3159,36 @@
mReq->req.status = -EINPROGRESS;
mReq->req.actual = 0;
+ if (udc->rw_pending) {
+ list_add_tail(&mReq->queue, &mEp->rw_queue);
+ retval = 0;
+ goto done;
+ }
+
+ if (udc->suspended) {
+ /* Remote Wakeup */
+ if (!udc->gadget.remote_wakeup) {
+
+ dev_dbg(mEp->device, "%s: queue failed (suspend).",
+ __func__);
+ dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+ __func__, mEp->num);
+ mEp->multi_req = false;
+
+ retval = -EAGAIN;
+ goto done;
+ }
+
+ list_add_tail(&mReq->queue, &mEp->rw_queue);
+
+ udc->rw_pending = true;
+ schedule_delayed_work(&udc->rw_work,
+ REMOTE_WAKEUP_DELAY);
+
+ retval = 0;
+ goto done;
+ }
+
retval = _hardware_enqueue(mEp, mReq);
if (retval == -EALREADY) {
@@ -3139,16 +3215,27 @@
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
struct ci13xxx_ep *mEpTemp = mEp;
struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx *udc = _udc;
unsigned long flags;
- trace("%p, %p", ep, req);
+ trace("%pK, %pK", ep, req);
+
+ if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+ dev_err(udc->transceiver->dev,
+ "%s: Unable to dequeue while in LPM\n",
+ __func__);
+ return -EAGAIN;
+ }
+
+ if (ep == NULL)
+ return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
/*
* Only ep0 IN is exposed to composite. When a req is dequeued
* on ep0, check both ep0 IN and ep0 OUT queues.
*/
- if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
+ if (req == NULL || mReq->req.status != -EALREADY ||
mEp->desc == NULL || list_empty(&mReq->queue) ||
(list_empty(&mEp->qh.queue) && ((mEp->type !=
USB_ENDPOINT_XFER_CONTROL) ||
@@ -3159,7 +3246,7 @@
dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
- if ((mEp->type == USB_ENDPOINT_XFER_CONTROL)) {
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
hw_ep_flush(_udc->ep0out.num, RX);
hw_ep_flush(_udc->ep0in.num, TX);
} else {
@@ -3171,10 +3258,23 @@
if (mReq->map) {
dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
+ mReq->req.dma = DMA_ERROR_CODE;
mReq->map = 0;
}
req->status = -ECONNRESET;
+
+ if (mEp->last_zptr) {
+ dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+ mEp->last_zptr = NULL;
+ mEp->last_zdma = 0;
+ }
+
+ if (mReq->zptr) {
+ dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+ mReq->zptr = NULL;
+ mReq->zdma = 0;
+ }
+
if (mEp->multi_req) {
restore_original_req(mReq);
mEp->multi_req = false;
@@ -3209,14 +3309,21 @@
static int ep_set_halt(struct usb_ep *ep, int value)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx *udc = _udc;
int direction, retval = 0;
unsigned long flags;
- trace("%p, %i", ep, value);
+ trace("%pK, %i", ep, value);
if (ep == NULL || mEp->desc == NULL)
return -EINVAL;
+ if (udc->suspended) {
+ dev_err(udc->transceiver->dev,
+ "%s: Unable to halt EP while suspended\n", __func__);
+ return -EINVAL;
+ }
+
spin_lock_irqsave(mEp->lock, flags);
#ifndef STALL_IN
@@ -3257,7 +3364,7 @@
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
unsigned long flags;
- trace("%p", ep);
+ trace("%pK", ep);
if (ep == NULL || mEp->desc == NULL)
return -EINVAL;
@@ -3279,16 +3386,24 @@
*/
static void ep_fifo_flush(struct usb_ep *ep)
{
+ struct ci13xxx *udc = _udc;
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
unsigned long flags;
- trace("%p", ep);
+ trace("%pK", ep);
if (ep == NULL) {
err("%02X: -EINVAL", _usb_addr(mEp));
return;
}
+ if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+ dev_err(udc->transceiver->dev,
+ "%s: Unable to fifo_flush while in LPM\n",
+ __func__);
+ return;
+ }
+
spin_lock_irqsave(mEp->lock, flags);
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
@@ -3337,28 +3452,51 @@
gadget_ready = 1;
spin_unlock_irqrestore(udc->lock, flags);
- if (gadget_ready) {
- if (is_active) {
- pm_runtime_get_sync(&_gadget->dev);
- hw_device_reset(udc);
- if (udc->softconnect)
- hw_device_state(udc->ep0out.qh.dma);
- } else {
- hw_device_state(0);
- _gadget_stop_activity(&udc->gadget);
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_DISCONNECT_EVENT);
- pm_runtime_put_sync(&_gadget->dev);
+ if (!gadget_ready)
+ return 0;
+
+ if (is_active) {
+ hw_device_reset(udc);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_CONNECT_EVENT);
+ /* Enable BAM (if needed) before starting controller */
+ if (udc->softconnect) {
+ dbg_event(0xFF, "BAM EN2",
+ _gadget->bam2bam_func_enabled);
+ msm_usb_bam_enable(CI_CTRL,
+ _gadget->bam2bam_func_enabled);
+ hw_device_state(udc->ep0out.qh.dma);
}
+ } else {
+ hw_device_state(0);
+ _gadget_stop_activity(&udc->gadget);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_DISCONNECT_EVENT);
}
return 0;
}
-static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+#define VBUS_DRAW_BUF_LEN 10
+#define MAX_OVERRIDE_VBUS_ALLOWED 900 /* 900 mA */
+static char vbus_draw_mA[VBUS_DRAW_BUF_LEN];
+module_param_string(vbus_draw_mA, vbus_draw_mA, VBUS_DRAW_BUF_LEN, 0644);
+
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned int mA)
{
struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+ unsigned int override_mA = 0;
+
+ /* override param to draw more current if battery draining faster */
+ if ((mA == CONFIG_USB_GADGET_VBUS_DRAW) &&
+ (vbus_draw_mA[0] != '\0')) {
+ if ((!kstrtoint(vbus_draw_mA, 10, &override_mA)) &&
+ (override_mA <= MAX_OVERRIDE_VBUS_ALLOWED)) {
+ mA = override_mA;
+ }
+ }
if (udc->transceiver)
return usb_phy_set_power(udc->transceiver, mA);
@@ -3379,17 +3517,41 @@
}
spin_unlock_irqrestore(udc->lock, flags);
- if (is_active)
+ pm_runtime_get_sync(&_gadget->dev);
+
+ /* Enable BAM (if needed) before starting controller */
+ if (is_active) {
+ dbg_event(0xFF, "BAM EN1", _gadget->bam2bam_func_enabled);
+ msm_usb_bam_enable(CI_CTRL, _gadget->bam2bam_func_enabled);
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ if (!udc->vbus_active) {
+ spin_unlock_irqrestore(udc->lock, flags);
+ pm_runtime_put_sync(&_gadget->dev);
+ return 0;
+ }
+ if (is_active) {
+ spin_unlock(udc->lock);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_CONNECT_EVENT);
+ spin_lock(udc->lock);
hw_device_state(udc->ep0out.qh.dma);
- else
+ } else {
hw_device_state(0);
+ }
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ pm_runtime_mark_last_busy(&_gadget->dev);
+ pm_runtime_put_autosuspend(&_gadget->dev);
return 0;
}
-static int ci13xxx_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int ci13xxx_stop(struct usb_gadget_driver *driver);
+static int ci13xxx_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int ci13xxx_stop(struct usb_gadget *gadget);
/**
* Device operations part of the API to the USB controller hardware,
@@ -3401,31 +3563,27 @@
.wakeup = ci13xxx_wakeup,
.vbus_draw = ci13xxx_vbus_draw,
.pullup = ci13xxx_pullup,
- .start = ci13xxx_start,
- .stop = ci13xxx_stop,
+ .udc_start = ci13xxx_start,
+ .udc_stop = ci13xxx_stop,
};
/**
* ci13xxx_start: register a gadget driver
+ * @gadget: our gadget
* @driver: the driver being registered
- * @bind: the driver's bind callback
*
- * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
* Interrupts are enabled here.
*/
-static int ci13xxx_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int ci13xxx_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
struct ci13xxx *udc = _udc;
unsigned long flags;
- int i, j;
int retval = -ENOMEM;
- bool put = false;
- trace("%p", driver);
+ trace("%pK", driver);
if (driver == NULL ||
- bind == NULL ||
driver->setup == NULL ||
driver->disconnect == NULL)
return -EINVAL;
@@ -3434,82 +3592,37 @@
else if (udc->driver != NULL)
return -EBUSY;
- /* alloc resources */
- udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
- sizeof(struct ci13xxx_qh),
- 64, CI13XXX_PAGE_SIZE);
- if (udc->qh_pool == NULL)
- return -ENOMEM;
-
- udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
- sizeof(struct ci13xxx_td),
- 64, CI13XXX_PAGE_SIZE);
- if (udc->td_pool == NULL) {
- dma_pool_destroy(udc->qh_pool);
- udc->qh_pool = NULL;
- return -ENOMEM;
- }
-
spin_lock_irqsave(udc->lock, flags);
info("hw_ep_max = %d", hw_ep_max);
udc->gadget.dev.driver = NULL;
- retval = 0;
- for (i = 0; i < hw_ep_max/2; i++) {
- for (j = RX; j <= TX; j++) {
- int k = i + j * hw_ep_max/2;
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
-
- scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
- (j == TX) ? "in" : "out");
-
- mEp->lock = udc->lock;
- mEp->device = &udc->gadget.dev;
- mEp->td_pool = udc->td_pool;
-
- mEp->ep.name = mEp->name;
- mEp->ep.ops = &usb_ep_ops;
- mEp->ep.maxpacket =
- k ? USHRT_MAX : CTRL_PAYLOAD_MAX;
-
- INIT_LIST_HEAD(&mEp->qh.queue);
- spin_unlock_irqrestore(udc->lock, flags);
- mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
- &mEp->qh.dma);
- spin_lock_irqsave(udc->lock, flags);
- if (mEp->qh.ptr == NULL)
- retval = -ENOMEM;
- else
- memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
-
- /* skip ep0 out and in endpoints */
- if (i == 0)
- continue;
-
- list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
- }
- }
- if (retval)
- goto done;
spin_unlock_irqrestore(udc->lock, flags);
+
+ pm_runtime_get_sync(&udc->gadget.dev);
+
udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
retval = usb_ep_enable(&udc->ep0out.ep);
if (retval)
- return retval;
+ goto pm_put;
udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
retval = usb_ep_enable(&udc->ep0in.ep);
if (retval)
- return retval;
+ goto pm_put;
udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_KERNEL);
- if (!udc->status)
- return -ENOMEM;
- udc->status_buf = kzalloc(2, GFP_KERNEL); /* for GET_STATUS */
+ if (!udc->status) {
+ retval = -ENOMEM;
+ goto pm_put;
+ }
+
+ udc->status_buf = kzalloc(2 + udc->gadget.extra_buf_alloc,
+ GFP_KERNEL); /* for GET_STATUS */
if (!udc->status_buf) {
usb_ep_free_request(&udc->ep0in.ep, udc->status);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto pm_put;
}
spin_lock_irqsave(udc->lock, flags);
@@ -3517,17 +3630,6 @@
/* bind gadget */
driver->driver.bus = NULL;
udc->gadget.dev.driver = &driver->driver;
- udc->softconnect = 1;
-
- spin_unlock_irqrestore(udc->lock, flags);
- pm_runtime_get_sync(&udc->gadget.dev);
- retval = bind(&udc->gadget); /* MAY SLEEP */
- spin_lock_irqsave(udc->lock, flags);
-
- if (retval) {
- udc->gadget.dev.driver = NULL;
- goto done;
- }
udc->driver = driver;
if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
@@ -3535,26 +3637,23 @@
if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
hw_device_reset(udc);
} else {
- put = true;
goto done;
}
}
- if (!udc->softconnect) {
- put = true;
+ if (!udc->softconnect)
goto done;
- }
retval = hw_device_state(udc->ep0out.qh.dma);
- done:
+done:
spin_unlock_irqrestore(udc->lock, flags);
- if (retval || put)
- pm_runtime_put_sync(&udc->gadget.dev);
if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
+ udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_UDC_STARTED_EVENT);
+pm_put:
+ pm_runtime_put(&udc->gadget.dev);
return retval;
}
@@ -3564,19 +3663,10 @@
*
* Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
*/
-static int ci13xxx_stop(struct usb_gadget_driver *driver)
+static int ci13xxx_stop(struct usb_gadget *gadget)
{
struct ci13xxx *udc = _udc;
- unsigned long i, flags;
-
- trace("%p", driver);
-
- if (driver == NULL ||
- driver->unbind == NULL ||
- driver->setup == NULL ||
- driver->disconnect == NULL ||
- driver != udc->driver)
- return -EINVAL;
+ unsigned long flags;
spin_lock_irqsave(udc->lock, flags);
@@ -3586,44 +3676,13 @@
spin_unlock_irqrestore(udc->lock, flags);
_gadget_stop_activity(&udc->gadget);
spin_lock_irqsave(udc->lock, flags);
- pm_runtime_put(&udc->gadget.dev);
}
- /* unbind gadget */
spin_unlock_irqrestore(udc->lock, flags);
- driver->unbind(&udc->gadget); /* MAY SLEEP */
- spin_lock_irqsave(udc->lock, flags);
usb_ep_free_request(&udc->ep0in.ep, udc->status);
kfree(udc->status_buf);
- udc->gadget.dev.driver = NULL;
-
- /* free resources */
- for (i = 0; i < hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
-
- if (!list_empty(&mEp->ep.ep_list))
- list_del_init(&mEp->ep.ep_list);
-
- if (mEp->qh.ptr != NULL)
- dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
- }
-
- udc->gadget.ep0 = NULL;
- udc->driver = NULL;
-
- spin_unlock_irqrestore(udc->lock, flags);
-
- if (udc->td_pool != NULL) {
- dma_pool_destroy(udc->td_pool);
- udc->td_pool = NULL;
- }
- if (udc->qh_pool != NULL) {
- dma_pool_destroy(udc->qh_pool);
- udc->qh_pool = NULL;
- }
-
return 0;
}
@@ -3651,6 +3710,11 @@
spin_lock(udc->lock);
+ if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+ spin_unlock(udc->lock);
+ return IRQ_NONE;
+ }
+
if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
USBMODE_CM_DEVICE) {
@@ -3667,6 +3731,9 @@
/* order defines priority - do NOT change it */
if (USBi_URI & intr) {
isr_statistics.uri++;
+ if (!hw_cread(CAP_PORTSC, PORTSC_PR))
+ pr_info("%s: USB reset interrupt is delayed\n",
+ __func__);
isr_reset_handler(udc);
}
if (USBi_PCI & intr) {
@@ -3693,18 +3760,15 @@
return retval;
}
-/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
+static void destroy_eps(struct ci13xxx *ci)
{
- trace("%p", dev);
+ int i;
- if (dev == NULL)
- err("EINVAL");
+ for (i = 0; i < hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
+
+ dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+ }
}
/**
@@ -3722,9 +3786,9 @@
{
struct ci13xxx *udc;
struct ci13xxx_platform_data *pdata;
- int retval = 0, i;
+ int retval = 0, i, j;
- trace("%p, %p, %p", dev, regs, driver->name);
+ trace("%pK, %pK, %pK", dev, regs, driver->name);
if (dev == NULL || regs == NULL || driver == NULL ||
driver->name == NULL)
@@ -3741,100 +3805,146 @@
udc->gadget.ops = &usb_gadget_ops;
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.max_speed = USB_SPEED_HIGH;
- if (udc->udc_driver->flags & CI13XXX_IS_OTG)
- udc->gadget.is_otg = 1;
- else
- udc->gadget.is_otg = 0;
+ udc->gadget.is_otg = 0;
udc->gadget.name = driver->name;
- INIT_LIST_HEAD(&udc->gadget.ep_list);
- udc->gadget.ep0 = NULL;
+ /* alloc resources */
+ udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
+ sizeof(struct ci13xxx_qh),
+ 64, CI13XXX_PAGE_SIZE);
+ if (udc->qh_pool == NULL) {
+ retval = -ENOMEM;
+ goto free_udc;
+ }
- pdata = dev->platform_data;
- if (pdata)
- udc->gadget.usb_core_id = pdata->usb_core_id;
-
- dev_set_name(&udc->gadget.dev, "gadget");
- udc->gadget.dev.dma_mask = dev->dma_mask;
- udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
- udc->gadget.dev.parent = dev;
- udc->gadget.dev.release = udc_release;
-
- if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
- udc->transceiver = usb_get_transceiver();
- if (udc->transceiver == NULL) {
- retval = -ENODEV;
- goto free_udc;
- }
+ udc->td_pool = dma_pool_create("ci13xxx_td", dev,
+ sizeof(struct ci13xxx_td),
+ 64, CI13XXX_PAGE_SIZE);
+ if (udc->td_pool == NULL) {
+ retval = -ENOMEM;
+ goto free_qh_pool;
}
INIT_DELAYED_WORK(&udc->rw_work, usb_do_remote_wakeup);
retval = hw_device_init(regs);
if (retval < 0)
- goto put_transceiver;
+ goto free_qh_pool;
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
for (i = 0; i < hw_ep_max; i++) {
struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
INIT_LIST_HEAD(&mEp->ep.ep_list);
+ INIT_LIST_HEAD(&mEp->rw_queue);
setup_timer(&mEp->prime_timer, ep_prime_timer_func,
(unsigned long) mEp);
}
+ for (i = 0; i < hw_ep_max/2; i++) {
+ for (j = RX; j <= TX; j++) {
+ int k = i + j * hw_ep_max/2;
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
+
+ scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+ (j == TX) ? "in" : "out");
+
+ mEp->lock = udc->lock;
+ mEp->device = &udc->gadget.dev;
+ mEp->td_pool = udc->td_pool;
+
+ mEp->ep.name = mEp->name;
+ mEp->ep.ops = &usb_ep_ops;
+ usb_ep_set_maxpacket_limit(&mEp->ep,
+ k ? USHRT_MAX : CTRL_PAYLOAD_MAX);
+
+ INIT_LIST_HEAD(&mEp->qh.queue);
+ mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+ &mEp->qh.dma);
+ if (mEp->qh.ptr == NULL)
+ retval = -ENOMEM;
+ else
+ memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+ /* skip ep0 out and in endpoints */
+ if (i == 0)
+ continue;
+
+ list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+ }
+ }
+
+ if (retval)
+ goto free_dma_pools;
+
+ udc->gadget.ep0 = &udc->ep0in.ep;
+
+ pdata = dev->platform_data;
+ if (pdata) {
+ if (pdata->enable_axi_prefetch)
+ udc->gadget.extra_buf_alloc = EXTRA_ALLOCATION_SIZE;
+ }
+
+ if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+ udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (udc->transceiver == NULL) {
+ retval = -ENODEV;
+ goto destroy_eps;
+ }
+ }
+
if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
retval = hw_device_reset(udc);
if (retval)
goto put_transceiver;
}
- retval = device_register(&udc->gadget.dev);
- if (retval) {
- put_device(&udc->gadget.dev);
- goto put_transceiver;
- }
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- retval = dbg_create_files(&udc->gadget.dev);
-#endif
- if (retval)
- goto unreg_device;
-
if (udc->transceiver) {
retval = otg_set_peripheral(udc->transceiver->otg,
&udc->gadget);
if (retval)
- goto remove_dbg;
+ goto put_transceiver;
}
retval = usb_add_gadget_udc(dev, &udc->gadget);
if (retval)
goto remove_trans;
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ retval = dbg_create_files(&udc->gadget.dev);
+ if (retval) {
+ pr_err("Registering sysfs files for debug failed!!!!\n");
+ goto del_udc;
+ }
+#endif
+
pm_runtime_no_callbacks(&udc->gadget.dev);
+ pm_runtime_set_active(&udc->gadget.dev);
pm_runtime_enable(&udc->gadget.dev);
- if (register_trace_usb_daytona_invalid_access(dump_usb_info, NULL))
- pr_err("Registering trace failed\n");
+ /* Use delayed LPM especially for composition-switch in LPM (suspend) */
+ pm_runtime_set_autosuspend_delay(&udc->gadget.dev, 2000);
+ pm_runtime_use_autosuspend(&udc->gadget.dev);
_udc = udc;
return retval;
+del_udc:
+ usb_del_gadget_udc(&udc->gadget);
remove_trans:
- if (udc->transceiver) {
+ if (udc->transceiver)
otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
- usb_put_transceiver(udc->transceiver);
- }
err("error = %i", retval);
-remove_dbg:
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- dbg_remove_files(&udc->gadget.dev);
-#endif
-unreg_device:
- device_unregister(&udc->gadget.dev);
put_transceiver:
if (udc->transceiver)
- usb_put_transceiver(udc->transceiver);
+ usb_put_phy(udc->transceiver);
+destroy_eps:
+ destroy_eps(udc);
+free_dma_pools:
+ dma_pool_destroy(udc->td_pool);
+free_qh_pool:
+ dma_pool_destroy(udc->qh_pool);
free_udc:
kfree(udc);
_udc = NULL;
@@ -3849,27 +3959,24 @@
static void udc_remove(void)
{
struct ci13xxx *udc = _udc;
- int retval;
if (udc == NULL) {
err("EINVAL");
return;
}
- retval = unregister_trace_usb_daytona_invalid_access(dump_usb_info,
- NULL);
- if (retval)
- pr_err("Unregistering trace failed\n");
usb_del_gadget_udc(&udc->gadget);
if (udc->transceiver) {
otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
- usb_put_transceiver(udc->transceiver);
+ usb_put_phy(udc->transceiver);
}
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
dbg_remove_files(&udc->gadget.dev);
#endif
- device_unregister(&udc->gadget.dev);
+ destroy_eps(udc);
+ dma_pool_destroy(udc->td_pool);
+ dma_pool_destroy(udc->qh_pool);
kfree(udc);
_udc = NULL;
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f90ea86..8c93080 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -57,7 +57,7 @@
#define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0)
-} __attribute__ ((packed, aligned(4)));
+} __packed __aligned(4);
/* DMA layout of queue heads */
struct ci13xxx_qh {
@@ -75,19 +75,19 @@
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
-} __attribute__ ((packed, aligned(4)));
+} __packed __aligned(4);
/* cache of larger request's original attributes */
struct ci13xxx_multi_req {
- unsigned len;
- unsigned actual;
+ unsigned int len;
+ unsigned int actual;
void *buf;
};
/* Extension of usb_request */
struct ci13xxx_req {
struct usb_request req;
- unsigned map;
+ unsigned int map;
struct list_head queue;
struct ci13xxx_td *ptr;
dma_addr_t dma;
@@ -109,6 +109,7 @@
struct ci13xxx_qh *ptr;
dma_addr_t dma;
} qh;
+ struct list_head rw_queue;
int wedge;
/* global resources */
@@ -117,7 +118,8 @@
struct dma_pool *td_pool;
struct ci13xxx_td *last_zptr;
dma_addr_t last_zdma;
- unsigned long dTD_update_fail_count;
+ unsigned long dTD_update_fail_count;
+ unsigned long dTD_active_re_q_count;
unsigned long prime_fail_count;
int prime_timer_count;
struct timer_list prime_timer;
@@ -135,7 +137,7 @@
#define CI13XXX_PULLUP_ON_VBUS BIT(2)
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_ZERO_ITC BIT(4)
-#define CI13XXX_IS_OTG BIT(5)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS BIT(6)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
@@ -144,8 +146,10 @@
#define CI13XXX_CONTROLLER_RESUME_EVENT 4
#define CI13XXX_CONTROLLER_DISCONNECT_EVENT 5
#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT 6
+#define CI13XXX_CONTROLLER_ERROR_EVENT 7
- void (*notify_event) (struct ci13xxx *udc, unsigned event);
+ void (*notify_event)(struct ci13xxx *udc, unsigned int event);
+ bool (*in_lpm)(struct ci13xxx *udc);
};
/* CI13XXX UDC descriptor & global resources */
@@ -163,12 +167,10 @@
u32 ep0_dir; /* ep0 direction */
#define ep0out ci13xxx_ep[0]
#define ep0in ci13xxx_ep[hw_ep_max / 2]
- u8 remote_wakeup; /* Is remote wakeup feature
- enabled by the host? */
u8 suspended; /* suspended by the host */
u8 configured; /* is device configured */
u8 test_mode; /* the selected test mode */
-
+ bool rw_pending; /* Remote wakeup pending flag */
struct delayed_work rw_work; /* remote wakeup delayed work */
struct usb_gadget_driver *driver; /* 3rd party gadget driver */
struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
@@ -176,9 +178,11 @@
int softconnect; /* is pull-up enable allowed */
unsigned long dTD_update_fail_count;
struct usb_phy *transceiver; /* Transceiver struct */
- bool skip_flush; /* skip flushing remaining EP
- upon flush timeout for the
- first EP. */
+ bool skip_flush; /*
+ * skip flushing remaining EP
+ * upon flush timeout for the
+ * first EP.
+ */
};
/******************************************************************************
@@ -197,6 +201,9 @@
/* TESTMODE */
#define TESTMODE_FORCE BIT(0)
+/* AHB_MODE */
+#define AHB2AHB_BYPASS BIT(31)
+
/* USBCMD */
#define USBCMD_RS BIT(0)
#define USBCMD_RST BIT(1)
@@ -217,6 +224,7 @@
/* PORTSC */
#define PORTSC_FPR BIT(6)
#define PORTSC_SUSP BIT(7)
+#define PORTSC_PR BIT(8)
#define PORTSC_HSP BIT(9)
#define PORTSC_PTC (0x0FUL << 16)
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 4bdfadf..41aa62d 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1655,11 +1655,10 @@
buf = (rndis_init_msg_type *)req->buf;
if (buf->MessageType == RNDIS_MSG_INIT) {
- gsi->d_port.in_aggr_size = min_t(u32, gsi->d_port.in_aggr_size,
- gsi->params->dl_max_xfer_size);
- log_event_dbg("RNDIS host dl_aggr_size:%d in_aggr_size:%d\n",
- gsi->params->dl_max_xfer_size,
- gsi->d_port.in_aggr_size);
+ /* honor host dl aggr size */
+ gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size;
+ log_event_dbg("RNDIS host dl_aggr_size:%d\n",
+ gsi->params->dl_max_xfer_size);
}
}
@@ -2565,7 +2564,7 @@
info.out_epname = "gsi-epout";
info.in_req_buf_len = GSI_IN_BUFF_SIZE;
gsi->d_port.in_aggr_size = GSI_IN_RNDIS_AGGR_SIZE;
- info.in_req_num_buf = GSI_NUM_IN_BUFFERS;
+ info.in_req_num_buf = GSI_NUM_IN_RNDIS_BUFFERS;
gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE;
info.out_req_buf_len = GSI_OUT_AGGR_SIZE;
info.out_req_num_buf = GSI_NUM_OUT_BUFFERS;
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 58a7706..71bea5e 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -34,13 +34,13 @@
#define GSI_MAX_CTRL_PKT_SIZE 4096
#define GSI_CTRL_DTR (1 << 0)
-
+#define GSI_NUM_IN_RNDIS_BUFFERS 50
#define GSI_NUM_IN_BUFFERS 15
#define GSI_IN_BUFF_SIZE 2048
#define GSI_NUM_OUT_BUFFERS 14
#define GSI_OUT_AGGR_SIZE 24576
-#define GSI_IN_RNDIS_AGGR_SIZE 9216
+#define GSI_IN_RNDIS_AGGR_SIZE 16384
#define GSI_IN_MBIM_AGGR_SIZE 16384
#define GSI_IN_RMNET_AGGR_SIZE 16384
#define GSI_ECM_AGGR_SIZE 2048
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 54220a5..d50510f 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -21,6 +21,8 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/if_arp.h>
+#include <linux/msm_rmnet.h>
#include "u_ether.h"
@@ -89,6 +91,8 @@
struct work_struct rx_work;
unsigned long todo;
+ unsigned long flags;
+ unsigned short rx_needed_headroom;
#define WORK_RX_MEMORY 0
bool zlp;
@@ -161,6 +165,25 @@
return 0;
}
+static int ueth_change_mtu_ip(struct net_device *net, int new_mtu)
+{
+ struct eth_dev *dev = netdev_priv(net);
+ unsigned long flags;
+ int status = 0;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (new_mtu <= 0)
+ status = -EINVAL;
+ else
+ net->mtu = new_mtu;
+
+ DBG(dev, "[%s] MTU change: old=%d new=%d\n", net->name,
+ net->mtu, new_mtu);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return status;
+}
+
static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
{
struct eth_dev *dev = netdev_priv(net);
@@ -900,15 +923,176 @@
return 18;
}
+static int ether_ioctl(struct net_device *, struct ifreq *, int);
+
static const struct net_device_ops eth_netdev_ops = {
.ndo_open = eth_open,
.ndo_stop = eth_stop,
.ndo_start_xmit = eth_start_xmit,
+ .ndo_do_ioctl = ether_ioctl,
.ndo_change_mtu = ueth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
+static const struct net_device_ops eth_netdev_ops_ip = {
+ .ndo_open = eth_open,
+ .ndo_stop = eth_stop,
+ .ndo_start_xmit = eth_start_xmit,
+ .ndo_do_ioctl = ether_ioctl,
+ .ndo_change_mtu = ueth_change_mtu_ip,
+ .ndo_set_mac_address = NULL,
+ .ndo_validate_addr = NULL,
+};
+
+static int rmnet_ioctl_extended(struct net_device *dev, struct ifreq *ifr)
+{
+ struct rmnet_ioctl_extended_s ext_cmd;
+ struct eth_dev *eth_dev = netdev_priv(dev);
+ int rc = 0;
+
+ rc = copy_from_user(&ext_cmd, ifr->ifr_ifru.ifru_data,
+ sizeof(struct rmnet_ioctl_extended_s));
+
+ if (rc) {
+ DBG(eth_dev, "%s(): copy_from_user() failed\n", __func__);
+ return rc;
+ }
+
+ switch (ext_cmd.extended_ioctl) {
+ case RMNET_IOCTL_GET_SUPPORTED_FEATURES:
+ ext_cmd.u.data = 0;
+ break;
+
+ case RMNET_IOCTL_SET_MRU:
+ if (netif_running(dev))
+ return -EBUSY;
+
+ /* 16K max */
+ if ((size_t)ext_cmd.u.data > 0x4000)
+ return -EINVAL;
+
+ if (eth_dev->port_usb) {
+ eth_dev->port_usb->is_fixed = true;
+ eth_dev->port_usb->fixed_out_len =
+ (size_t) ext_cmd.u.data;
+ DBG(eth_dev, "[%s] rmnet_ioctl(): SET MRU to %u\n",
+ dev->name, eth_dev->port_usb->fixed_out_len);
+ } else {
+ pr_err("[%s]: %s: SET MRU failed. Cable disconnected\n",
+ dev->name, __func__);
+ return -ENODEV;
+ }
+ break;
+
+ case RMNET_IOCTL_GET_MRU:
+ if (eth_dev->port_usb) {
+ ext_cmd.u.data = eth_dev->port_usb->is_fixed ?
+ eth_dev->port_usb->fixed_out_len :
+ dev->mtu;
+ } else {
+ pr_err("[%s]: %s: GET MRU failed. Cable disconnected\n",
+ dev->name, __func__);
+ return -ENODEV;
+ }
+ break;
+
+ case RMNET_IOCTL_GET_DRIVER_NAME:
+ strlcpy(ext_cmd.u.if_name, dev->name,
+ sizeof(ext_cmd.u.if_name));
+ break;
+
+ default:
+ break;
+ }
+
+ rc = copy_to_user(ifr->ifr_ifru.ifru_data, &ext_cmd,
+ sizeof(struct rmnet_ioctl_extended_s));
+
+ if (rc)
+ DBG(eth_dev, "%s(): copy_to_user() failed\n", __func__);
+ return rc;
+}
+
+static int ether_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct eth_dev *eth_dev = netdev_priv(dev);
+ void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data;
+ int prev_mtu = dev->mtu;
+ u32 state, old_opmode;
+ int rc = -EFAULT;
+
+ old_opmode = eth_dev->flags;
+ /* Process IOCTL command */
+ switch (cmd) {
+ case RMNET_IOCTL_SET_LLP_ETHERNET: /*Set Ethernet protocol*/
+ /* Perform Ethernet config only if in IP mode currently*/
+ if (test_bit(RMNET_MODE_LLP_IP, ð_dev->flags)) {
+ ether_setup(dev);
+ dev->mtu = prev_mtu;
+ dev->netdev_ops = ð_netdev_ops;
+ clear_bit(RMNET_MODE_LLP_IP, ð_dev->flags);
+ set_bit(RMNET_MODE_LLP_ETH, ð_dev->flags);
+ DBG(eth_dev, "[%s] ioctl(): set Ethernet proto mode\n",
+ dev->name);
+ }
+ if (test_bit(RMNET_MODE_LLP_ETH, ð_dev->flags))
+ rc = 0;
+ break;
+
+ case RMNET_IOCTL_SET_LLP_IP: /* Set RAWIP protocol*/
+ /* Perform IP config only if in Ethernet mode currently*/
+ if (test_bit(RMNET_MODE_LLP_ETH, ð_dev->flags)) {
+ /* Undo config done in ether_setup() */
+ dev->header_ops = NULL; /* No header */
+ dev->type = ARPHRD_RAWIP;
+ dev->hard_header_len = 0;
+ dev->mtu = prev_mtu;
+ dev->addr_len = 0;
+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+ dev->netdev_ops = ð_netdev_ops_ip;
+ clear_bit(RMNET_MODE_LLP_ETH, ð_dev->flags);
+ set_bit(RMNET_MODE_LLP_IP, ð_dev->flags);
+ DBG(eth_dev, "[%s] ioctl(): set IP protocol mode\n",
+ dev->name);
+ }
+ if (test_bit(RMNET_MODE_LLP_IP, ð_dev->flags))
+ rc = 0;
+ break;
+
+ case RMNET_IOCTL_GET_LLP: /* Get link protocol state */
+ state = eth_dev->flags & (RMNET_MODE_LLP_ETH
+ | RMNET_MODE_LLP_IP);
+ if (copy_to_user(addr, &state, sizeof(state)))
+ break;
+ rc = 0;
+ break;
+
+ case RMNET_IOCTL_SET_RX_HEADROOM: /* Set RX headroom */
+ if (copy_from_user(ð_dev->rx_needed_headroom, addr,
+ sizeof(eth_dev->rx_needed_headroom)))
+ break;
+ DBG(eth_dev, "[%s] ioctl(): set RX HEADROOM: %x\n",
+ dev->name, eth_dev->rx_needed_headroom);
+ rc = 0;
+ break;
+
+ case RMNET_IOCTL_EXTENDED:
+ rc = rmnet_ioctl_extended(dev, ifr);
+ break;
+
+ default:
+ pr_err("[%s] error: ioctl called for unsupported cmd[%d]",
+ dev->name, cmd);
+ rc = -EINVAL;
+ }
+
+ DBG(eth_dev, "[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08lx\n",
+ dev->name, __func__, cmd, old_opmode, eth_dev->flags);
+
+ return rc;
+}
+
static struct device_type gadget_type = {
.name = "gadget",
};
@@ -968,6 +1152,9 @@
net->ethtool_ops = &ops;
+ /* set operation mode to eth by default */
+ set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev);
SET_NETDEV_DEVTYPE(net, &gadget_type);
@@ -1025,6 +1212,10 @@
net->netdev_ops = ð_netdev_ops;
net->ethtool_ops = &ops;
+
+ /* set operation mode to eth by default */
+ set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
SET_NETDEV_DEVTYPE(net, &gadget_type);
return net;
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index f472b2b..42028cc 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -391,7 +391,6 @@
config USB_CI13XXX_MSM
tristate "MIPS USB CI13xxx for MSM"
- depends on ARCH_MSM
select USB_MSM_OTG
help
MSM SoC has chipidea USB controller. This driver uses
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 19f3f18..95105d1 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -71,6 +71,8 @@
#define SQ_CTRL1_CHIRP_DISABLE 0x20
#define SQ_CTRL2_CHIRP_DISABLE 0x80
+#define DEBUG_CTRL1_OVERRIDE_VAL 0x09
+
/* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
#define BANDGAP_BYPASS BIT(0)
@@ -84,6 +86,7 @@
BIAS_CTRL_2,
SQ_CTRL1,
SQ_CTRL2,
+ DEBUG_CTRL1,
USB2_PHY_REG_MAX,
};
@@ -553,6 +556,11 @@
writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
+ /* if soc revision is mentioned override DEBUG_CTRL1 value */
+ if (qphy->soc_min_rev)
+ writel_relaxed(DEBUG_CTRL1_OVERRIDE_VAL,
+ qphy->base + qphy->phy_reg[DEBUG_CTRL1]);
+
/* ensure above writes are completed before re-enabling PHY */
wmb();
@@ -1228,7 +1236,7 @@
* qusb_phy_disable_chirp is not required if soc version is
* mentioned and is not base version.
*/
- if (qphy->soc_min_rev == 0)
+ if (!qphy->soc_min_rev)
qphy->phy.disable_chirp = qusb_phy_disable_chirp;
qphy->phy.start_port_reset = qusb_phy_enable_ext_pulldown;
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index fd84889..3482c93 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -422,6 +422,28 @@
static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
{
+ struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+
+ if (phy->suspended && suspend) {
+ dev_dbg(uphy->dev, "%s: USB PHY is already suspended\n",
+ __func__);
+ return 0;
+ }
+
+ if (suspend) { /* Bus suspend */
+ if (phy->cable_connected ||
+ (phy->phy.flags & PHY_HOST_MODE)) {
+ msm_hsphy_enable_clocks(phy, false);
+ } else {/* Cable disconnect */
+ msm_hsphy_enable_clocks(phy, false);
+ msm_hsphy_enable_power(phy, false);
+ }
+ phy->suspended = true;
+ } else { /* Bus resume and cable connect */
+ msm_hsphy_enable_clocks(phy, true);
+ phy->suspended = false;
+ }
+
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c
index b7c8d43..089d32d 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.c
+++ b/drivers/video/fbdev/msm/mdp3_dma.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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.
diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h
index 6c8e7fe..24caedb9 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.h
+++ b/drivers/video/fbdev/msm/mdp3_dma.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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.
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index d84cf5e..1cbaa44 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -79,10 +79,10 @@
if (level == 0) {
if (ctrl->pwm_enabled) {
- ret = pwm_config_us(ctrl->pwm_bl, level,
- ctrl->pwm_period);
+ ret = pwm_config(ctrl->pwm_bl, 0,
+ ctrl->pwm_period * NSEC_PER_USEC);
if (ret)
- pr_err("%s: pwm_config_us() failed err=%d.\n",
+ pr_err("%s: pwm_config() failed err=%d.\n",
__func__, ret);
pwm_disable(ctrl->pwm_bl);
}
diff --git a/drivers/video/fbdev/msm/mdss_edp_aux.c b/drivers/video/fbdev/msm/mdss_edp_aux.c
index 8ba715d..268daaa 100644
--- a/drivers/video/fbdev/msm/mdss_edp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_edp_aux.c
@@ -607,7 +607,6 @@
/*
* EDID structure can be found in VESA standard here:
- * http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf
*
* following table contains default edid
* static char edid_raw_data[128] = {
diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
index 02ddced..44817c3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+/* 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
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index fffaad4..0b3b223 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -32,23 +32,20 @@
ci->data->under_android = pi->data->under_android;
ci->data->under_cache = pi->data->under_cache;
ci->data->under_obb = pi->data->under_obb;
- set_top(ci, pi->top_data);
}
/* helper function for derived state */
void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
- uid_t uid, bool under_android,
- struct sdcardfs_inode_data *top)
+ uid_t uid)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
info->data->perm = perm;
info->data->userid = userid;
info->data->d_uid = uid;
- info->data->under_android = under_android;
+ info->data->under_android = false;
info->data->under_cache = false;
info->data->under_obb = false;
- set_top(info, top);
}
/* While renaming, there is a point where we want the path from dentry,
@@ -58,8 +55,8 @@
const struct qstr *name)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry));
- struct sdcardfs_inode_data *parent_data =
- SDCARDFS_I(d_inode(parent))->data;
+ struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent));
+ struct sdcardfs_inode_data *parent_data = parent_info->data;
appid_t appid;
unsigned long user_num;
int err;
@@ -80,13 +77,15 @@
inherit_derived_state(d_inode(parent), d_inode(dentry));
/* Files don't get special labels */
- if (!S_ISDIR(d_inode(dentry)->i_mode))
+ if (!S_ISDIR(d_inode(dentry)->i_mode)) {
+ set_top(info, parent_info);
return;
+ }
/* Derive custom permissions based on parent and current node */
switch (parent_data->perm) {
case PERM_INHERIT:
case PERM_ANDROID_PACKAGE_CACHE:
- /* Already inherited above */
+ set_top(info, parent_info);
break;
case PERM_PRE_ROOT:
/* Legacy internal layout places users at top level */
@@ -96,7 +95,6 @@
info->data->userid = 0;
else
info->data->userid = user_num;
- set_top(info, info->data);
break;
case PERM_ROOT:
/* Assume masked off by default. */
@@ -104,24 +102,24 @@
/* App-specific directories inside; let anyone traverse */
info->data->perm = PERM_ANDROID;
info->data->under_android = true;
- set_top(info, info->data);
+ } else {
+ set_top(info, parent_info);
}
break;
case PERM_ANDROID:
if (qstr_case_eq(name, &q_data)) {
/* App-specific directories inside; let anyone traverse */
info->data->perm = PERM_ANDROID_DATA;
- set_top(info, info->data);
} else if (qstr_case_eq(name, &q_obb)) {
/* App-specific directories inside; let anyone traverse */
info->data->perm = PERM_ANDROID_OBB;
info->data->under_obb = true;
- set_top(info, info->data);
/* Single OBB directory is always shared */
} else if (qstr_case_eq(name, &q_media)) {
/* App-specific directories inside; let anyone traverse */
info->data->perm = PERM_ANDROID_MEDIA;
- set_top(info, info->data);
+ } else {
+ set_top(info, parent_info);
}
break;
case PERM_ANDROID_OBB:
@@ -132,13 +130,13 @@
if (appid != 0 && !is_excluded(name->name, parent_data->userid))
info->data->d_uid =
multiuser_get_uid(parent_data->userid, appid);
- set_top(info, info->data);
break;
case PERM_ANDROID_PACKAGE:
if (qstr_case_eq(name, &q_cache)) {
info->data->perm = PERM_ANDROID_PACKAGE_CACHE;
info->data->under_cache = true;
}
+ set_top(info, parent_info);
break;
}
}
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 8ed0ea1..137d876 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -821,8 +821,8 @@
return err;
}
-static int sdcardfs_fillattr(struct vfsmount *mnt,
- struct inode *inode, struct kstat *stat)
+static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode,
+ struct kstat *lower_stat, struct kstat *stat)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
struct sdcardfs_inode_data *top = top_data_get(info);
@@ -837,12 +837,12 @@
stat->uid = make_kuid(&init_user_ns, top->d_uid);
stat->gid = make_kgid(&init_user_ns, get_gid(mnt, top));
stat->rdev = inode->i_rdev;
- stat->size = i_size_read(inode);
- stat->atime = inode->i_atime;
- stat->mtime = inode->i_mtime;
- stat->ctime = inode->i_ctime;
- stat->blksize = (1 << inode->i_blkbits);
- stat->blocks = inode->i_blocks;
+ stat->size = lower_stat->size;
+ stat->atime = lower_stat->atime;
+ stat->mtime = lower_stat->mtime;
+ stat->ctime = lower_stat->ctime;
+ stat->blksize = lower_stat->blksize;
+ stat->blocks = lower_stat->blocks;
data_put(top);
return 0;
}
@@ -868,8 +868,7 @@
goto out;
sdcardfs_copy_and_fix_attrs(d_inode(dentry),
d_inode(lower_path.dentry));
- err = sdcardfs_fillattr(mnt, d_inode(dentry), stat);
- stat->blocks = lower_stat.blocks;
+ err = sdcardfs_fillattr(mnt, d_inode(dentry), &lower_stat, stat);
out:
sdcardfs_put_lower_path(dentry, &lower_path);
return err;
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 0a2b516..37d4864 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -334,13 +334,11 @@
mutex_lock(&sdcardfs_super_list_lock);
if (sb_info->options.multiuser) {
setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT,
- sb_info->options.fs_user_id, AID_ROOT,
- false, SDCARDFS_I(d_inode(sb->s_root))->data);
+ sb_info->options.fs_user_id, AID_ROOT);
snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
} else {
setup_derived_state(d_inode(sb->s_root), PERM_ROOT,
- sb_info->options.fs_user_id, AID_ROOT,
- false, SDCARDFS_I(d_inode(sb->s_root))->data);
+ sb_info->options.fs_user_id, AID_ROOT);
snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
}
fixup_tmp_permissions(d_inode(sb->s_root));
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index d1d8bab..eda8e7a 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -201,6 +201,7 @@
struct sdcardfs_inode_data *data;
/* top folder for ownership */
+ spinlock_t top_lock;
struct sdcardfs_inode_data *top_data;
struct inode vfs_inode;
@@ -379,7 +380,12 @@
static inline struct sdcardfs_inode_data *top_data_get(
struct sdcardfs_inode_info *info)
{
- return data_get(info->top_data);
+ struct sdcardfs_inode_data *top_data;
+
+ spin_lock(&info->top_lock);
+ top_data = data_get(info->top_data);
+ spin_unlock(&info->top_lock);
+ return top_data;
}
extern void data_release(struct kref *ref);
@@ -401,15 +407,20 @@
}
static inline void set_top(struct sdcardfs_inode_info *info,
- struct sdcardfs_inode_data *top)
+ struct sdcardfs_inode_info *top_owner)
{
- struct sdcardfs_inode_data *old_top = info->top_data;
+ struct sdcardfs_inode_data *old_top;
+ struct sdcardfs_inode_data *new_top = NULL;
- if (top)
- data_get(top);
- info->top_data = top;
+ if (top_owner)
+ new_top = top_data_get(top_owner);
+
+ spin_lock(&info->top_lock);
+ old_top = info->top_data;
+ info->top_data = new_top;
if (old_top)
data_put(old_top);
+ spin_unlock(&info->top_lock);
}
static inline int get_gid(struct vfsmount *mnt,
@@ -513,8 +524,7 @@
};
extern void setup_derived_state(struct inode *inode, perm_t perm,
- userid_t userid, uid_t uid, bool under_android,
- struct sdcardfs_inode_data *top);
+ userid_t userid, uid_t uid);
extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name);
extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit);
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index b89947d..72d89b9 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -215,6 +215,9 @@
i->data = d;
kref_init(&d->refcount);
+ i->top_data = d;
+ spin_lock_init(&i->top_lock);
+ kref_get(&d->refcount);
i->vfs_inode.i_version = 1;
return &i->vfs_inode;
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 530a1d6..07b2e96 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -59,6 +59,23 @@
void (*detach)(struct drm_bridge *bridge);
/**
+ * @connector_init:
+ *
+ * This callback is used to init the connector from bridge side. In some
+ * cases connector and bridge are created in different modules, and the
+ * connector ops might need extra info from bridge. This callback offers
+ * the opportunity to overwrite connector's behavior in external bridge.
+ *
+ * The connector_init callback is optional.
+ *
+ * RETURNS:
+ *
+ * Zero on success, error code on failure.
+ */
+ int (*connector_init)(struct drm_bridge *bridge,
+ struct drm_connector *connector);
+
+ /**
* @mode_fixup:
*
* This callback is used to validate and adjust a mode. The paramater
@@ -214,5 +231,7 @@
struct drm_display_mode *adjusted_mode);
void drm_bridge_pre_enable(struct drm_bridge *bridge);
void drm_bridge_enable(struct drm_bridge *bridge);
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+ struct drm_connector *connector);
#endif
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index b28c4a3..9a5114d 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -560,6 +560,7 @@
* @tile_v_loc: vertical location of this tile
* @tile_h_size: horizontal size of this tile.
* @tile_v_size: vertical size of this tile.
+ * @private: connector private data.
*
* Each connector may be connected to one or more CRTCs, or may be clonable by
* another connector if they can share a CRTC. Each connector also has a specific
@@ -726,6 +727,8 @@
uint8_t num_h_tile, num_v_tile;
uint8_t tile_h_loc, tile_v_loc;
uint16_t tile_h_size, tile_v_size;
+
+ void *private;
};
#define obj_to_connector(x) container_of(x, struct drm_connector, base)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 0dbddb3..3c2024d 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -140,6 +140,10 @@
#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
/* transmit data in low power */
#define MIPI_DSI_MODE_LPM BIT(11)
+/* disable BLLP area */
+#define MIPI_DSI_MODE_VIDEO_BLLP BIT(12)
+/* disable EOF BLLP area */
+#define MIPI_DSI_MODE_VIDEO_EOF_BLLP BIT(13)
enum mipi_dsi_pixel_format {
MIPI_DSI_FMT_RGB888,
diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h
index afaa08a20..d5a5457 100644
--- a/include/linux/msm_hdmi.h
+++ b/include/linux/msm_hdmi.h
@@ -1,10 +1,6 @@
/* include/linux/msm_hdmi.h
*
-<<<<<<< HEAD
* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
-=======
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
->>>>>>> dfa46f9... fbdev: msm: fix compilation error
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 164abe2..61c557a 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -272,8 +272,11 @@
POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
POWER_SUPPLY_PROP_CONNECTOR_TYPE,
POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+ POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
POWER_SUPPLY_PROP_MIN_ICL,
POWER_SUPPLY_PROP_MOISTURE_DETECTED,
+ POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
+ POWER_SUPPLY_PROP_RECHARGE_SOC,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 62c770d..290e2b2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1777,7 +1777,7 @@
u32 init_load_pct;
u64 last_wake_ts;
u64 last_switch_out_ts;
- u64 last_cpu_selected_ts;
+ u64 last_enqueued_ts;
struct related_thread_group *grp;
struct list_head grp_list;
u64 cpu_cycles;
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 12bd032..3e97574 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -34,6 +34,7 @@
extern unsigned int sysctl_sched_boost;
extern unsigned int sysctl_sched_group_upmigrate_pct;
extern unsigned int sysctl_sched_group_downmigrate_pct;
+extern unsigned int sysctl_sched_walt_rotate_big_tasks;
extern int
walt_proc_update_handler(struct ctl_table *table, int write,
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 3fda92f..6acd229 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -478,6 +478,9 @@
* @deactivated: True if gadget is deactivated - in deactivated state it cannot
* be connected.
* @connected: True if gadget is connected.
+ * @bam2bam_func_enabled; Indicates function using bam2bam is enabled or not.
+ * @extra_buf_alloc: Extra allocation size for AXI prefetch so that out of
+ * boundary access is protected.
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@@ -531,6 +534,9 @@
unsigned deactivated:1;
unsigned connected:1;
bool remote_wakeup;
+ bool bam2bam_func_enabled;
+ u32 extra_buf_alloc;
+ bool l1_supported;
};
#define work_to_gadget(w) (container_of((w), struct usb_gadget, work))
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index daa245d..2f90ddc 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -21,6 +21,7 @@
#define USB_AHBBURST (MSM_USB_BASE + 0x0090)
#define USB_AHBMODE (MSM_USB_BASE + 0x0098)
+#define USB_GENCONFIG (MSM_USB_BASE + 0x009C)
#define USB_GENCONFIG_2 (MSM_USB_BASE + 0x00a0)
#define ULPI_TX_PKT_EN_CLR_FIX BIT(19)
@@ -47,6 +48,14 @@
#define AHB2AHB_BYPASS BIT(31)
#define AHB2AHB_BYPASS_BIT_MASK BIT(31)
#define AHB2AHB_BYPASS_CLEAR (0 << 31)
+#define USB_L1_EP_CTRL (MSM_USB_BASE + 0x0250)
+#define USB_L1_CONFIG (MSM_USB_BASE + 0x0254)
+
+#define L1_CONFIG_LPM_EN BIT(4)
+#define L1_CONFIG_REMOTE_WAKEUP BIT(5)
+#define L1_CONFIG_GATE_SYS_CLK BIT(7)
+#define L1_CONFIG_PHY_LPM BIT(10)
+#define L1_CONFIG_PLL BIT(11)
#define PORTSC_PHCD (1 << 23) /* phy suspend mode */
#define PORTSC_PTS_MASK (3 << 30)
@@ -64,6 +73,10 @@
#define ULPI_DATA(n) ((n) & 255)
#define ULPI_DATA_READ(n) (((n) >> 8) & 255)
+#define GENCONFIG_BAM_DISABLE (1 << 13)
+#define GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE (1 << 4)
+#define GENCONFIG_ULPI_SERIAL_EN (1 << 5)
+
/* synopsys 28nm phy registers */
#define ULPI_PWR_CLK_MNG_REG 0x88
#define OTG_COMP_DISABLE BIT(0)
diff --git a/include/net/cnss.h b/include/net/cnss.h
new file mode 100644
index 0000000..368d01e
--- /dev/null
+++ b/include/net/cnss.h
@@ -0,0 +1,266 @@
+/* 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
+ * 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_CNSS_H_
+#define _NET_CNSS_H_
+
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_CNSS
+#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
+#define CNSS_MAX_FILE_NAME 20
+#define PINCTRL_SLEEP 0
+#define PINCTRL_ACTIVE 1
+
+enum cnss_bus_width_type {
+ CNSS_BUS_WIDTH_NONE,
+ CNSS_BUS_WIDTH_LOW,
+ CNSS_BUS_WIDTH_MEDIUM,
+ CNSS_BUS_WIDTH_HIGH
+};
+
+enum cnss_cc_src {
+ CNSS_SOURCE_CORE,
+ CNSS_SOURCE_11D,
+ CNSS_SOURCE_USER
+};
+
+/* FW image files */
+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_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);
+ 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;
+};
+
+/*
+ * codeseg_total_bytes: Total bytes across all the codesegment blocks
+ * num_codesegs: No of Pages used
+ * codeseg_size: Size of each segment. Should be power of 2 and multiple of 4K
+ * codeseg_size_log2: log2(codeseg_size)
+ * codeseg_busaddr: Physical address of the DMAble memory;4K aligned
+ */
+
+#define CODESWAP_MAX_CODESEGS 16
+struct codeswap_codeseg_info {
+ u32 codeseg_total_bytes;
+ u32 num_codesegs;
+ u32 codeseg_size;
+ u32 codeseg_size_log2;
+ void *codeseg_busaddr[CODESWAP_MAX_CODESEGS];
+};
+
+struct image_desc_info {
+ dma_addr_t fw_addr;
+ u32 fw_size;
+ dma_addr_t bdata_addr;
+ u32 bdata_size;
+};
+
+/* platform capabilities */
+enum cnss_platform_cap_flag {
+ CNSS_HAS_EXTERNAL_SWREG = 0x01,
+ CNSS_HAS_UART_ACCESS = 0x02,
+};
+
+struct cnss_platform_cap {
+ u32 cap_flag;
+};
+
+/* WLAN driver status */
+enum cnss_driver_status {
+ CNSS_UNINITIALIZED,
+ CNSS_INITIALIZED,
+ CNSS_LOAD_UNLOAD
+};
+
+enum cnss_runtime_request {
+ CNSS_PM_RUNTIME_GET,
+ CNSS_PM_RUNTIME_PUT,
+ CNSS_PM_RUNTIME_MARK_LAST_BUSY,
+ CNSS_PM_RUNTIME_RESUME,
+ CNSS_PM_RUNTIME_PUT_NOIDLE,
+ CNSS_PM_REQUEST_RESUME,
+ CNSS_PM_RUNTIME_PUT_AUTO,
+ CNSS_PM_GET_NORESUME,
+};
+
+extern int cnss_get_fw_image(struct image_desc_info *image_desc_info);
+extern void cnss_runtime_init(struct device *dev, int auto_delay);
+extern void cnss_runtime_exit(struct device *dev);
+extern void cnss_wlan_pci_link_down(void);
+extern int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable);
+extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
+extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
+extern int cnss_get_fw_files(struct cnss_fw_files *pfw_files);
+extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+ u32 target_type, u32 target_version);
+extern void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+ u32 size, u32 tufello_dual_fw);
+
+extern int cnss_request_bus_bandwidth(int bandwidth);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+extern int cnss_get_sha_hash(const u8 *data, u32 data_len,
+ u8 *hash_idx, u8 *out);
+extern void *cnss_get_fw_ptr(void);
+#endif
+
+extern int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg);
+extern int cnss_get_bmi_setup(void);
+
+#ifdef CONFIG_PCI_MSM
+extern int cnss_wlan_pm_control(bool vote);
+#endif
+extern void cnss_lock_pm_sem(void);
+extern void cnss_release_pm_sem(void);
+
+extern void cnss_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_request_pm_qos(u32 qos_val);
+extern void cnss_remove_pm_qos(void);
+
+extern void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_pci_request_pm_qos(u32 qos_val);
+extern void cnss_pci_remove_pm_qos(void);
+
+extern void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_sdio_request_pm_qos(u32 qos_val);
+extern void cnss_sdio_remove_pm_qos(void);
+
+extern int cnss_get_platform_cap(struct cnss_platform_cap *cap);
+extern void cnss_set_driver_status(enum cnss_driver_status driver_status);
+
+#ifndef CONFIG_WCNSS_MEM_PRE_ALLOC
+static inline int wcnss_pre_alloc_reset(void) { return 0; }
+#endif
+
+extern int msm_pcie_enumerate(u32 rc_idx);
+extern int cnss_auto_suspend(void);
+extern int cnss_auto_resume(void);
+extern int cnss_prevent_auto_suspend(const char *caller_func);
+extern int cnss_allow_auto_suspend(const char *caller_func);
+extern int cnss_is_auto_suspend_allowed(const char *caller_func);
+
+extern int cnss_pm_runtime_request(struct device *dev, enum
+ cnss_runtime_request request);
+extern void cnss_set_cc_source(enum cnss_cc_src cc_source);
+extern enum cnss_cc_src cnss_get_cc_source(void);
+#endif
+
+extern void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name);
+extern void cnss_pm_wake_lock(struct wakeup_source *ws);
+
+extern void cnss_device_crashed(void);
+extern void cnss_device_self_recovery(void);
+extern void *cnss_get_virt_ramdump_mem(unsigned long *size);
+
+extern void cnss_schedule_recovery_work(void);
+extern int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len);
+extern u8 *cnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len);
+
+enum {
+ CNSS_RESET_SOC = 0,
+ CNSS_RESET_SUBSYS_COUPLED,
+ CNSS_RESET_LEVEL_MAX
+};
+extern int cnss_get_restart_level(void);
+
+struct cnss_sdio_wlan_driver {
+ const char *name;
+ const struct sdio_device_id *id_table;
+ int (*probe)(struct sdio_func *, const struct sdio_device_id *);
+ void (*remove)(struct sdio_func *);
+ int (*reinit)(struct sdio_func *, const struct sdio_device_id *);
+ void (*shutdown)(struct sdio_func *);
+ void (*crash_shutdown)(struct sdio_func *);
+ int (*suspend)(struct device *);
+ int (*resume)(struct device *);
+};
+
+extern int cnss_sdio_wlan_register_driver(
+ struct cnss_sdio_wlan_driver *driver);
+extern void cnss_sdio_wlan_unregister_driver(
+ struct cnss_sdio_wlan_driver *driver);
+
+typedef void (*oob_irq_handler_t)(void *dev_para);
+extern int cnss_wlan_query_oob_status(void);
+extern int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler,
+ void *pm_oob);
+extern int cnss_wlan_unregister_oob_irq_handler(void *pm_oob);
+
+
+extern void cnss_dump_stack(struct task_struct *task);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern void cnss_init_work(struct work_struct *work, work_func_t func);
+extern void cnss_flush_delayed_work(void *dwork);
+extern void cnss_flush_work(void *work);
+extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec);
+extern void cnss_pm_wake_lock_release(struct wakeup_source *ws);
+extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws);
+extern void cnss_get_monotonic_boottime(struct timespec *ts);
+extern void cnss_get_boottime(struct timespec *ts);
+extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t
+ func);
+extern int cnss_vendor_cmd_reply(struct sk_buff *skb);
+extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu);
+extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count);
+extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
+ u16 buf_len);
+extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len);
+extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len);
+extern int cnss_common_request_bus_bandwidth(struct device *dev, int
+ bandwidth);
+extern void cnss_common_device_crashed(struct device *dev);
+extern void cnss_common_device_self_recovery(struct device *dev);
+extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long
+ *size);
+extern void cnss_common_schedule_recovery_work(struct device *dev);
+extern int cnss_common_set_wlan_mac_address(struct device *dev, const u8 *in,
+ uint32_t len);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_power_up(struct device *dev);
+extern int cnss_power_down(struct device *dev);
+extern int cnss_sdio_configure_spdt(bool state);
+
+extern int cnss_common_register_tsf_captured_handler(struct device *dev,
+ irq_handler_t handler,
+ void *ctx);
+extern int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+ void *ctx);
+#endif /* _NET_CNSS_H_ */
diff --git a/include/net/cnss_logger.h b/include/net/cnss_logger.h
new file mode 100644
index 0000000..f06ec9b
--- /dev/null
+++ b/include/net/cnss_logger.h
@@ -0,0 +1,59 @@
+/* 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.
+ */
+#ifndef _NET_CNSS_LOGGER_H_
+#define _NET_CNSS_LOGGER_H_
+
+struct sk_buff;
+struct wiphy;
+
+#ifdef CONFIG_CNSS_LOGGER
+int cnss_logger_event_register(int radio, int event,
+ int (*cb)(struct sk_buff *skb));
+int cnss_logger_event_unregister(int radio, int event,
+ int (*cb)(struct sk_buff *skb));
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name);
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy);
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag);
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag);
+#else
+static inline int cnss_logger_event_register(int radio, int event,
+ int (*cb)(struct sk_buff *skb))
+{
+ return 0;
+}
+static inline int cnss_logger_event_unregister(int radio, int event,
+ int (*cb)(struct sk_buff *skb))
+{
+ return 0;
+}
+static inline int cnss_logger_device_register(struct wiphy *wiphy,
+ const char *name)
+{
+ return 0;
+}
+static inline int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+ return 0;
+}
+static inline int cnss_logger_nl_ucast(struct sk_buff *skb, int portid,
+ int flag)
+{
+ return 0;
+}
+static inline int cnss_logger_nl_bcast(struct sk_buff *skb, int portid,
+ int flag)
+{
+ return 0;
+}
+#endif /* CONFIG_CNSS_LOGGER */
+#endif /* _NET_CNSS_H_ */
+
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index cbfe7e4..a872c9a 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -114,6 +114,10 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm450")
#define early_machine_is_sdm632() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm632")
+#define early_machine_is_sdm439() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm439")
+#define early_machine_is_sdm429() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm429")
#else
#define of_board_is_sim() 0
#define of_board_is_rumi() 0
@@ -160,6 +164,8 @@
#define early_machine_is_msm8937() 0
#define early_machine_is_sdm450() 0
#define early_machine_is_sdm632() 0
+#define early_machine_is_sdm439() 0
+#define early_machine_is_sdm429() 0
#endif
#define PLATFORM_SUBTYPE_MDM 1
@@ -228,7 +234,9 @@
MSM_CPU_SDM450,
MSM_CPU_SDM632,
MSM_CPU_SDA632,
- MSM_CPU_8937
+ MSM_CPU_8937,
+ MSM_CPU_SDM439,
+ MSM_CPU_SDM429,
};
struct msm_soc_info {
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 0125cde..63f2baf 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -596,8 +596,8 @@
TRACE_EVENT(sched_load_to_gov,
- TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy),
- TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy),
+ TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy, int big_task_rotation),
+ TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy, big_task_rotation),
TP_STRUCT__entry(
__field( int, cpu )
@@ -612,6 +612,7 @@
__field( u64, grp_nt_ps )
__field( u64, pl )
__field( u64, load )
+ __field( int, big_task_rotation )
),
TP_fast_assign(
@@ -627,13 +628,15 @@
__entry->grp_nt_ps = rq->grp_time.nt_prev_runnable_sum;
__entry->pl = rq->walt_stats.pred_demands_sum;
__entry->load = load;
+ __entry->big_task_rotation = big_task_rotation;
),
- TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu",
+ TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu big_task_rotation=%d",
__entry->cpu, __entry->policy, __entry->ed_task_pid,
__entry->aggr_grp_load, __entry->freq_aggr_thresh,
__entry->tt_load, __entry->rq_ps, __entry->grp_rq_ps,
- __entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load)
+ __entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load,
+ __entry->big_task_rotation)
);
#endif
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 7b02ae6..31b45b7 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -775,6 +775,7 @@
if (!(flags & ENQUEUE_RESTORE))
sched_info_queued(rq, p);
p->sched_class->enqueue_task(rq, p, flags);
+ walt_update_last_enqueue(p);
trace_sched_enq_deq_task(p, 1, cpumask_bits(&p->cpus_allowed)[0]);
}
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index cc5a97c..c0a8a2a 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.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
@@ -482,6 +482,7 @@
sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg,
&max_nr, &big_max_nr);
+ walt_rotation_checkpoint(big_avg);
spin_lock_irqsave(&state_lock, flags);
for_each_cluster(cluster, index) {
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 1ff2e5e..55c3957 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -11430,6 +11430,141 @@
return rc;
}
+#ifdef CONFIG_SCHED_WALT
+struct walt_rotate_work {
+ struct work_struct w;
+ struct task_struct *src_task;
+ struct task_struct *dst_task;
+ int src_cpu;
+ int dst_cpu;
+};
+
+static DEFINE_PER_CPU(struct walt_rotate_work, walt_rotate_works);
+
+static void walt_rotate_work_func(struct work_struct *work)
+{
+ struct walt_rotate_work *wr = container_of(work,
+ struct walt_rotate_work, w);
+
+ migrate_swap(wr->src_task, wr->dst_task);
+
+ put_task_struct(wr->src_task);
+ put_task_struct(wr->dst_task);
+
+ clear_reserved(wr->src_cpu);
+ clear_reserved(wr->dst_cpu);
+}
+
+void walt_rotate_work_init(void)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ struct walt_rotate_work *wr = &per_cpu(walt_rotate_works, i);
+
+ INIT_WORK(&wr->w, walt_rotate_work_func);
+ }
+}
+
+#define WALT_ROTATION_THRESHOLD_NS 16000000
+static void walt_check_for_rotation(struct rq *src_rq)
+{
+ u64 wc, wait, max_wait = 0, run, max_run = 0;
+ int deserved_cpu = nr_cpu_ids, dst_cpu = nr_cpu_ids;
+ int i, src_cpu = cpu_of(src_rq);
+ struct rq *dst_rq;
+ struct walt_rotate_work *wr = NULL;
+
+ if (!walt_rotation_enabled)
+ return;
+
+ if (got_boost_kick())
+ return;
+
+ if (is_max_capacity_cpu(src_cpu))
+ return;
+
+ wc = ktime_get_ns();
+ for_each_possible_cpu(i) {
+ struct rq *rq = cpu_rq(i);
+
+ if (is_max_capacity_cpu(i))
+ break;
+
+ if (is_reserved(i))
+ continue;
+
+ if (!rq->misfit_task || rq->curr->sched_class !=
+ &fair_sched_class)
+ continue;
+
+ wait = wc - rq->curr->last_enqueued_ts;
+ if (wait > max_wait) {
+ max_wait = wait;
+ deserved_cpu = i;
+ }
+ }
+
+ if (deserved_cpu != src_cpu)
+ return;
+
+ for_each_possible_cpu(i) {
+ struct rq *rq = cpu_rq(i);
+
+ if (!is_max_capacity_cpu(i))
+ continue;
+
+ if (is_reserved(i))
+ continue;
+
+ if (rq->curr->sched_class != &fair_sched_class)
+ continue;
+
+ if (rq->nr_running > 1)
+ continue;
+
+ run = wc - rq->curr->last_enqueued_ts;
+
+ if (run < WALT_ROTATION_THRESHOLD_NS)
+ continue;
+
+ if (run > max_run) {
+ max_run = run;
+ dst_cpu = i;
+ }
+ }
+
+ if (dst_cpu == nr_cpu_ids)
+ return;
+
+ dst_rq = cpu_rq(dst_cpu);
+
+ double_rq_lock(src_rq, dst_rq);
+ if (dst_rq->curr->sched_class == &fair_sched_class) {
+ get_task_struct(src_rq->curr);
+ get_task_struct(dst_rq->curr);
+
+ mark_reserved(src_cpu);
+ mark_reserved(dst_cpu);
+ wr = &per_cpu(walt_rotate_works, src_cpu);
+
+ wr->src_task = src_rq->curr;
+ wr->dst_task = dst_rq->curr;
+
+ wr->src_cpu = src_cpu;
+ wr->dst_cpu = dst_cpu;
+ }
+ double_rq_unlock(src_rq, dst_rq);
+
+ if (wr)
+ queue_work_on(src_cpu, system_highpri_wq, &wr->w);
+}
+#else
+static inline void walt_check_for_rotation(struct rq *rq)
+{
+}
+#endif
+
static DEFINE_RAW_SPINLOCK(migration_lock);
void check_for_migration(struct rq *rq, struct task_struct *p)
{
@@ -11459,6 +11594,8 @@
&rq->active_balance_work);
return;
}
+ } else {
+ walt_check_for_rotation(rq);
}
raw_spin_unlock(&migration_lock);
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 5508248..e0aa30d 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -943,8 +943,8 @@
};
extern void sched_setnuma(struct task_struct *p, int node);
extern int migrate_task_to(struct task_struct *p, int cpu);
-extern int migrate_swap(struct task_struct *, struct task_struct *);
#endif /* CONFIG_NUMA_BALANCING */
+extern int migrate_swap(struct task_struct *cur, struct task_struct *p);
#ifdef CONFIG_SMP
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index b7da03f..23fd885 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -88,6 +88,9 @@
__read_mostly unsigned int sysctl_sched_cpu_high_irqload = (10 * NSEC_PER_MSEC);
+unsigned int sysctl_sched_walt_rotate_big_tasks;
+unsigned int walt_rotation_enabled;
+
/*
* sched_window_stats_policy and sched_ravg_hist_size have a 'sysctl' copy
* associated with them. This is required for atomic update of those variables
@@ -316,7 +319,8 @@
struct task_struct *p;
int loop_max = 10;
- if (sched_boost_policy() == SCHED_BOOST_NONE || !rq->cfs.h_nr_running)
+ if ((!walt_rotation_enabled && sched_boost_policy() ==
+ SCHED_BOOST_NONE) || !rq->cfs.h_nr_running)
return 0;
rq->ed_task = NULL;
@@ -487,7 +491,7 @@
done:
trace_sched_load_to_gov(rq, aggr_grp_load, tt_load, freq_aggr_thresh,
- load, reporting_policy);
+ load, reporting_policy, walt_rotation_enabled);
return load;
}
@@ -2019,7 +2023,7 @@
wallclock = ktime_get_ns();
p->ravg.mark_start = p->last_wake_ts = wallclock;
- p->last_cpu_selected_ts = wallclock;
+ p->last_enqueued_ts = wallclock;
p->last_switch_out_ts = 0;
update_task_cpu_cycles(p, cpu_of(rq));
}
@@ -3143,6 +3147,19 @@
core_ctl_check(this_rq()->window_start);
}
+void walt_rotation_checkpoint(int nr_big)
+{
+ if (!hmp_capable())
+ return;
+
+ if (!sysctl_sched_walt_rotate_big_tasks || sched_boost() != NO_BOOST) {
+ walt_rotation_enabled = 0;
+ return;
+ }
+
+ walt_rotation_enabled = nr_big >= num_possible_cpus();
+}
+
int walt_proc_update_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
@@ -3178,6 +3195,8 @@
cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask);
init_irq_work(&walt_migration_irq_work, walt_irq_work);
init_irq_work(&walt_cpufreq_irq_work, walt_irq_work);
+ walt_rotate_work_init();
+
rq->walt_stats.cumulative_runnable_avg = 0;
rq->window_start = 0;
rq->cum_window_start = 0;
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index c8780cf..da53ea4 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -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
@@ -291,9 +291,20 @@
return sysctl_sched_is_big_little ? prev_cpu : min_power_cpu;
}
+static inline void walt_update_last_enqueue(struct task_struct *p)
+{
+ p->last_enqueued_ts = ktime_get_ns();
+}
+extern void walt_rotate_work_init(void);
+extern void walt_rotation_checkpoint(int nr_big);
+extern unsigned int walt_rotation_enabled;
+
#else /* CONFIG_SCHED_WALT */
static inline void walt_sched_init(struct rq *rq) { }
+static inline void walt_rotate_work_init(void) { }
+static inline void walt_rotation_checkpoint(int nr_big) { }
+static inline void walt_update_last_enqueue(struct task_struct *p) { }
static inline void update_task_ravg(struct task_struct *p, struct rq *rq,
int event, u64 wallclock, u64 irqtime) { }
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index a01c821..b057784 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -325,6 +325,15 @@
.extra1 = &zero,
.extra2 = &three,
},
+ {
+ .procname = "sched_walt_rotate_big_tasks",
+ .data = &sysctl_sched_walt_rotate_big_tasks,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
#endif
{
.procname = "sched_upmigrate",
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 4a60459..d3ea11f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3288,6 +3288,46 @@
return NULL;
}
+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+ struct zone *zone;
+ struct zoneref *z;
+
+ /* Let costly order requests check for compaction progress */
+ if (order > PAGE_ALLOC_COSTLY_ORDER)
+ return false;
+
+ /*
+ * For (0 < order < PAGE_ALLOC_COSTLY_ORDER) allow the shrinkers
+ * to run and free up memory. Do not let these allocations fail
+ * if shrinkers can free up memory. This is similar to
+ * should_compact_retry implementation for !CONFIG_COMPACTION.
+ */
+ for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
+ ac->high_zoneidx, ac->nodemask) {
+ unsigned long available;
+
+ available = zone_reclaimable_pages(zone);
+ available +=
+ zone_page_state_snapshot(zone, NR_FREE_PAGES);
+
+ if (__zone_watermark_ok(zone, 0, min_wmark_pages(zone),
+ ac_classzone_idx(ac), alloc_flags, available))
+ return true;
+ }
+
+ return false;
+}
+#else
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+ return false;
+}
+#endif
+
static inline bool
should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
enum compact_result compact_result,
@@ -3300,6 +3340,9 @@
if (!order)
return false;
+ if (should_compact_lmk_retry(ac, order, alloc_flags))
+ return true;
+
if (compaction_made_progress(compact_result))
(*compaction_retries)++;
@@ -3537,7 +3580,8 @@
* their order will become available due to high fragmentation so
* always increment the no progress counter for them
*/
- if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
+ if ((did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) ||
+ IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
*no_progress_loops = 0;
else
(*no_progress_loops)++;
@@ -3815,7 +3859,8 @@
* implementation of the compaction depends on the sufficient amount
* of free memory (see __compaction_suitable)
*/
- if (did_some_progress > 0 &&
+ if ((did_some_progress > 0 ||
+ IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER)) &&
should_compact_retry(ac, order, alloc_flags,
compact_result, &compact_priority,
&compaction_retries))
diff --git a/mm/vmscan.c b/mm/vmscan.c
index bb18b47..2740973 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -212,7 +212,8 @@
nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) +
zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE);
- if (get_nr_swap_pages() > 0)
+ if (get_nr_swap_pages() > 0
+ || IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) +
zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f7e685f..558d566 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -393,14 +393,11 @@
struct net_device *loopback_dev =
dev_net(dev)->loopback_dev;
- if (dev != loopback_dev) {
- if (idev && idev->dev == dev) {
- struct inet6_dev *loopback_idev =
- in6_dev_get(loopback_dev);
- if (loopback_idev) {
- rt->rt6i_idev = loopback_idev;
- in6_dev_put(idev);
- }
+ if (idev && idev->dev != loopback_dev) {
+ struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
+ if (loopback_idev) {
+ rt->rt6i_idev = loopback_idev;
+ in6_dev_put(idev);
}
}
}
diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch
index ac5f1267..aab8585 100644
--- a/scripts/const_structs.checkpatch
+++ b/scripts/const_structs.checkpatch
@@ -9,7 +9,6 @@
dev_pm_ops
dma_map_ops
driver_info
-drm_connector_funcs
drm_encoder_funcs
drm_encoder_helper_funcs
ethtool_ops
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index e2cebf15..1c5b36d 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -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
@@ -173,6 +173,9 @@
USB_QMI_PCM_FORMAT_U32_BE,
};
+static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
+ size_t iova_size, size_t mapped_iova_size);
+
static enum usb_audio_device_speed_enum_v01
get_speed_info(enum usb_device_speed udev_speed)
{
@@ -279,11 +282,14 @@
}
static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
- size_t size)
+ size_t size, struct sg_table *sgt)
{
- unsigned long va = 0;
+ unsigned long va_sg, va = 0;
bool map = true;
- int ret;
+ int i, ret;
+ size_t sg_len, total_len = 0;
+ struct scatterlist *sg;
+ phys_addr_t pa_sg;
switch (mtype) {
case MEM_EVENT_RING:
@@ -306,18 +312,48 @@
pr_err("%s: unknown mem type %d\n", __func__, mtype);
}
- if (!va)
- map = false;
-
- if (!map)
+ if (!va || !map)
goto done;
- pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa,
- va, mtype);
+ if (!sgt)
+ goto skip_sgt_map;
+
+ va_sg = va;
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ sg_len = PAGE_ALIGN(sg->offset + sg->length);
+ pa_sg = page_to_phys(sg_page(sg));
+ ret = iommu_map(uaudio_qdev->domain, va_sg, pa_sg, sg_len,
+ IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
+ if (ret) {
+ pr_err("%s:mapping failed ret%d\n", __func__, ret);
+ pr_err("memtype:%d, pa:%pK iova:%lu sg_len:%zu\n",
+ mtype, &pa_sg, va_sg, sg_len);
+ uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+ va = 0;
+ goto done;
+ }
+ pr_debug("%s:memtype %d:map pa:%pK to iova:%lu len:%zu\n",
+ __func__, mtype, &pa_sg, va_sg, sg_len);
+ va_sg += sg_len;
+ total_len += sg_len;
+ }
+
+ if (size != total_len) {
+ pr_err("%s: iova size %zu != mapped iova size %zu\n", __func__,
+ size, total_len);
+ uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+ va = 0;
+ }
+ return va;
+
+skip_sgt_map:
+ pr_debug("%s:memtype:%d map pa:%pK to iova %lu size:%zu\n", __func__,
+ mtype, &pa, va, size);
+
ret = iommu_map(uaudio_qdev->domain, va, pa, size,
IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
if (ret)
- pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n",
+ pr_err("%s:failed to map pa:%pK iova:%lu memtype:%d ret:%d\n",
__func__, &pa, va, mtype, ret);
done:
return va;
@@ -361,12 +397,12 @@
}
static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
- size_t size)
+ size_t iova_size, size_t mapped_iova_size)
{
size_t umap_size;
bool unmap = true;
- if (!va || !size)
+ if (!va || !iova_size)
return;
switch (mtype) {
@@ -378,11 +414,11 @@
break;
case MEM_XFER_RING:
- uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list,
+ uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_ring_list,
&uaudio_qdev->xfer_ring_iova_size);
break;
case MEM_XFER_BUF:
- uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list,
+ uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_buf_list,
&uaudio_qdev->xfer_buf_iova_size);
break;
default:
@@ -390,15 +426,16 @@
unmap = false;
}
- if (!unmap)
+ if (!unmap || !mapped_iova_size)
return;
- pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype);
+ pr_debug("%s:memtype %d: unmap iova %lu size %zu\n", __func__, mtype,
+ va, mapped_iova_size);
- umap_size = iommu_unmap(uaudio_qdev->domain, va, size);
- if (umap_size != size)
- pr_err("%s: unmapped size %zu for iova %lu\n", __func__,
- umap_size, va);
+ umap_size = iommu_unmap(uaudio_qdev->domain, va, mapped_iova_size);
+ if (umap_size != mapped_iova_size)
+ pr_err("%s:unmapped size %zu for iova %lu of mapped size %zu\n",
+ __func__, umap_size, va, mapped_iova_size);
}
static int prepare_qmi_response(struct snd_usb_substream *subs,
@@ -418,12 +455,11 @@
void *hdr_ptr;
u8 *xfer_buf;
unsigned int data_ep_pipe = 0, sync_ep_pipe = 0;
- u32 len, mult, remainder, xfer_buf_len, sg_len, i, total_len = 0;
- unsigned long va, va_sg, tr_data_va = 0, tr_sync_va = 0;
+ u32 len, mult, remainder, xfer_buf_len;
+ unsigned long va, tr_data_va = 0, tr_sync_va = 0;
phys_addr_t xhci_pa, xfer_buf_pa, tr_data_pa = 0, tr_sync_pa = 0;
dma_addr_t dma;
struct sg_table sgt;
- struct scatterlist *sg;
iface = usb_ifnum_to_if(subs->dev, subs->interface);
if (!iface) {
@@ -593,7 +629,7 @@
goto err;
}
- va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE);
+ va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE, NULL);
if (!va)
goto err;
@@ -610,7 +646,7 @@
resp->speed_info_valid = 1;
/* data transfer ring */
- va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE);
+ va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE, NULL);
if (!va)
goto unmap_er;
@@ -624,7 +660,7 @@
goto skip_sync;
xhci_pa = resp->xhci_mem_info.tr_sync.pa;
- va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE);
+ va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE, NULL);
if (!va)
goto unmap_data;
@@ -655,20 +691,9 @@
dma_get_sgtable(subs->dev->bus->sysdev, &sgt, xfer_buf, xfer_buf_pa,
len);
-
- va = 0;
- for_each_sg(sgt.sgl, sg, sgt.nents, i) {
- sg_len = PAGE_ALIGN(sg->offset + sg->length);
- va_sg = uaudio_iommu_map(MEM_XFER_BUF,
- page_to_phys(sg_page(sg)), sg_len);
- if (!va_sg)
- goto unmap_xfer_buf;
-
- if (!va)
- va = va_sg;
-
- total_len += sg_len;
- }
+ va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len, &sgt);
+ if (!va)
+ goto unmap_sync;
resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa;
resp->xhci_mem_info.xfer_buff.size = len;
@@ -690,7 +715,7 @@
uadev[card_num].num_intf, GFP_KERNEL);
if (!uadev[card_num].info) {
ret = -ENOMEM;
- goto unmap_xfer_buf;
+ goto unmap_sync;
}
uadev[card_num].udev = subs->dev;
atomic_set(&uadev[card_num].in_use, 1);
@@ -722,16 +747,13 @@
return 0;
-unmap_xfer_buf:
- if (va)
- uaudio_iommu_unmap(MEM_XFER_BUF, va, total_len);
unmap_sync:
usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa);
- uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE);
+ uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE, PAGE_SIZE);
unmap_data:
- uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE);
+ uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE, PAGE_SIZE);
unmap_er:
- uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+ uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE, PAGE_SIZE);
err:
return ret;
}
@@ -760,17 +782,17 @@
}
uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va,
- info->data_xfer_ring_size);
+ info->data_xfer_ring_size, info->data_xfer_ring_size);
info->data_xfer_ring_va = 0;
info->data_xfer_ring_size = 0;
uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va,
- info->sync_xfer_ring_size);
+ info->sync_xfer_ring_size, info->sync_xfer_ring_size);
info->sync_xfer_ring_va = 0;
info->sync_xfer_ring_size = 0;
uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va,
- info->xfer_buf_size);
+ info->xfer_buf_size, info->xfer_buf_size);
info->xfer_buf_va = 0;
usb_free_coherent(udev, info->xfer_buf_size,
@@ -805,7 +827,8 @@
/* all audio devices are disconnected */
if (!uaudio_qdev->card_slot) {
- uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+ uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+ PAGE_SIZE);
usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
pr_debug("%s: all audio devices disconnected\n", __func__);
}
@@ -881,7 +904,8 @@
/* all audio devices are disconnected */
if (!uaudio_qdev->card_slot) {
usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
- uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+ uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+ PAGE_SIZE);
pr_debug("%s: all audio devices disconnected\n", __func__);
}