Merge "smp: Wake up all idle CPUs when suspending to idle"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index b3f3431..0d955ed 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -139,6 +139,7 @@
the command DB driver.
qcom,drv-id: The DRV id associated with the RSC, used to differentiate
between RSCS owned by different execution environments.
+qcom,defer-init-qos: Flag to force defer initial QoS configuration at probe time.
Example:
diff --git a/Documentation/devicetree/bindings/clock/qcom,camcc.txt b/Documentation/devicetree/bindings/clock/qcom,camcc.txt
index 313e50f..daf8a539 100644
--- a/Documentation/devicetree/bindings/clock/qcom,camcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,camcc.txt
@@ -2,7 +2,8 @@
----------------------------------------------------
Required properties :
-- compatible : shall contain "qcom,cam_cc-sdm845" or "qcom,cam_cc-sdm845-v2"
+- compatible : shall contain "qcom,cam_cc-sdm845", "qcom,cam_cc-sdm845-v2" or
+ "qcom,cam_cc-sdm670"
- reg : shall contain base register location and length
- reg-names: names of registers listed in the same order as in
the reg property.
diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
index 87af0f6..d169c31 100644
--- a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
@@ -2,7 +2,8 @@
----------------------------------------------------
Required properties :
-- compatible : shall contain "qcom,dispcc-sdm845" or "qcom,dispcc-sdm845-v2".
+- compatible : shall contain "qcom,dispcc-sdm845", "qcom,dispcc-sdm845-v2" or
+ "qcom,dispcc-sdm670".
- reg : shall contain base register location and length.
- reg-names: names of registers listed in the same order as in
the reg property.
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index c280b92..538fb6d 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -18,6 +18,7 @@
"qcom,gcc-mdm9615"
"qcom,gcc-sdm845"
"qcom,gcc-sdm845-v2"
+ "qcom,gcc-sdm670"
"qcom,debugcc-sdm845"
- reg : shall contain base register location and length
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
index 12676b7..aa90bc4 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -7,6 +7,8 @@
"qcom,gpucc-sdm845-v2",
"qcom,gfxcc-sdm845",
"qcom,gfxcc-sdm845-v2"
+ "qcom,gpucc-sdm670",
+ "qcom,gfxcc-sdm670"
- reg : shall contain base register offset and size.
- #clock-cells : shall contain 1.
diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt
index c81a454..9ad7263 100644
--- a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt
@@ -2,7 +2,8 @@
-------------------------------------------------------
Required properties :
-- compatible : must be "qcom,rpmh-clk-sdm845"
+- compatible : shall contain "qcom,rpmh-clk-sdm845" or "qcom,rpmh-clk-sdm670"
+
- #clock-cells : must contain 1
- mboxes : list of RPMh mailbox phandle and channel identifier tuples.
- mbox-names : list of names to identify the RPMh mailboxes used.
diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.txt b/Documentation/devicetree/bindings/clock/qcom,videocc.txt
index 6bd0f0b..9b53c65 100644
--- a/Documentation/devicetree/bindings/clock/qcom,videocc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,videocc.txt
@@ -2,8 +2,8 @@
----------------------------------------------------
Required properties :
-- compatible : shall contain "qcom,video_cc-sdm845" or
- "qcom,video_cc-sdm845-v2".
+- compatible : shall contain "qcom,video_cc-sdm845", "qcom,video_cc-sdm845-v2"
+ or "qcom,video_cc-sdm670".
- reg : shall contain base register location and length.
- reg-names: names of registers listed in the same order as in
the reg property.
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index 92ef23c..fd2729f 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -43,6 +43,13 @@
Definition: Boolean flag which indicates that the charger should not draw
current from any of its input sources (USB, DC).
+- qcom,use-extcon
+ Usage: optional
+ Value type: <empty>
+ Definition: Boolean flag which specify that smb138x will act as main charger
+ to do extcon USB calls. If not defined, other charger driver can
+ act as main charger to do extcon USB calls.
+
- qcom,fcc-max-ua
Usage: optional
Value type: <u32>
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 041b304..954738a 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -8,21 +8,27 @@
sdm845-mtp-overlay.dtbo \
sdm845-qrd-overlay.dtbo \
sdm845-qvr-overlay.dtbo \
- sdm845-v2-cdp-overlay.dtbo \
- sdm845-v2-mtp-overlay.dtbo \
- sdm845-v2-qrd-overlay.dtbo \
sdm845-4k-panel-mtp-overlay.dtbo \
sdm845-4k-panel-cdp-overlay.dtbo \
sdm845-4k-panel-qrd-overlay.dtbo \
+ sdm845-v2-cdp-overlay.dtbo \
+ sdm845-v2-mtp-overlay.dtbo \
+ sdm845-v2-qrd-overlay.dtbo \
+ sdm845-v2-4k-panel-mtp-overlay.dtbo \
+ sdm845-v2-4k-panel-cdp-overlay.dtbo \
+ sdm845-v2-4k-panel-qrd-overlay.dtbo \
sda845-cdp-overlay.dtbo \
sda845-mtp-overlay.dtbo \
sda845-qrd-overlay.dtbo \
- sda845-v2-cdp-overlay.dtbo \
- sda845-v2-mtp-overlay.dtbo \
- sda845-v2-qrd-overlay.dtbo \
sda845-4k-panel-mtp-overlay.dtbo \
sda845-4k-panel-cdp-overlay.dtbo \
sda845-4k-panel-qrd-overlay.dtbo \
+ sda845-v2-cdp-overlay.dtbo \
+ sda845-v2-mtp-overlay.dtbo \
+ sda845-v2-qrd-overlay.dtbo \
+ sda845-v2-4k-panel-mtp-overlay.dtbo \
+ sda845-v2-4k-panel-cdp-overlay.dtbo \
+ sda845-v2-4k-panel-qrd-overlay.dtbo \
sdm845-interposer-sdm670-cdp-overlay.dtbo \
sdm845-interposer-sdm670-mtp-overlay.dtbo
@@ -30,21 +36,28 @@
sdm845-mtp-overlay.dtbo-base := sdm845.dtb
sdm845-qrd-overlay.dtbo-base := sdm845.dtb
sdm845-qvr-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-qvr-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-mtp-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-qrd-overlay.dtbo-base := sdm845.dtb
+sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-mtp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-cdp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-qrd-overlay.dtbo-base := sdm845-v2.dtb
sda845-cdp-overlay.dtbo-base := sda845.dtb
sda845-mtp-overlay.dtbo-base := sda845.dtb
sda845-qrd-overlay.dtbo-base := sda845.dtb
-sda845-v2-cdp-overlay.dtbo-base := sda845-v2.dtb
-sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
-sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
sda845-4k-panel-mtp-overlay.dtbo-base := sda845.dtb
sda845-4k-panel-cdp-overlay.dtbo-base := sda845.dtb
sda845-4k-panel-qrd-overlay.dtbo-base := sda845.dtb
+sda845-v2-cdp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-qrd-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
sdm845-interposer-sdm670-cdp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
sdm845-interposer-sdm670-mtp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
else
@@ -69,15 +82,21 @@
dtbo-$(CONFIG_ARCH_SDM670) += \
sdm670-cdp-overlay.dtbo \
sdm670-mtp-overlay.dtbo \
- sdm670-rumi-overlay.dtbo
+ sdm670-rumi-overlay.dtbo \
+ sdm670-pm660a-cdp-overlay.dtbo \
+ sdm670-pm660a-mtp-overlay.dtbo
sdm670-cdp-overlay.dtbo-base := sdm670.dtb
sdm670-mtp-overlay.dtbo-base := sdm670.dtb
sdm670-rumi-overlay.dtbo-base := sdm670.dtb
+sdm670-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
else
dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
sdm670-mtp.dtb \
- sdm670-cdp.dtb
+ sdm670-cdp.dtb \
+ sdm670-pm660a-mtp.dtb \
+ sdm670-pm660a-cdp.dtb
endif
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 8075b9e..48d68a7 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -14,7 +14,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
&spmi_bus {
- qcom,pm660@0 {
+ pm660_0: qcom,pm660@0 {
compatible ="qcom,spmi-pmic";
reg = <0x0 SPMI_USID>;
#address-cells = <2>;
@@ -245,149 +245,10 @@
};
};
- pm660_charger: qcom,qpnp-smb2 {
- compatible = "qcom,qpnp-smb2";
- #address-cells = <1>;
- #size-cells = <1>;
-
- 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>;
-
- /* Enable after the qusb_phy0 device node is added */
- /* dpdm-supply = <&qusb_phy0>; */
-
- qcom,thermal-mitigation
- = <3000000 2500000 2000000 1500000
- 1000000 500000>;
-
- 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";
- };
- };
-
pm660_pdphy: qcom,usb-pdphy@1700 {
compatible = "qcom,qpnp-pdphy";
reg = <0x1700 0x100>;
vdd-pdphy-supply = <&pm660l_l7>;
- vbus-supply = <&smb2_vbus>;
- vconn-supply = <&smb2_vconn>;
interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
<0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
<0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
@@ -497,73 +358,6 @@
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 = <96 96>;
- qcom,fg-esr-timer-asleep = <256 256>;
- qcom,fg-esr-timer-charging = <0 96>;
- qcom,cycle-counter-en;
- 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";
- };
- };
-
bcl@4200 {
compatible = "qcom,msm-bcl-lmh";
reg = <0x4200 0xff>,
@@ -579,32 +373,11 @@
};
};
- qcom,pm660@1 {
+ pm660_1: qcom,pm660@1 {
compatible ="qcom,spmi-pmic";
reg = <0x1 SPMI_USID>;
#address-cells = <2>;
#size-cells = <0>;
-
- 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/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
index 11101ffe..771154a 100644
--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -185,35 +185,6 @@
};
};
- pm660l_wled: qcom,leds@d800 {
- compatible = "qcom,qpnp-wled";
- reg = <0xd800 0x100>,
- <0xd900 0x100>;
- reg-names = "qpnp-wled-ctrl-base",
- "qpnp-wled-sink-base";
- interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
- interrupt-names = "ovp-irq";
- linux,name = "wled";
- linux,default-trigger = "bkl-trigger";
- qcom,fdbk-output = "auto";
- qcom,vref-uv = <127500>;
- qcom,switch-freq-khz = <800>;
- qcom,ovp-mv = <29600>;
- qcom,ilim-ma = <970>;
- qcom,boost-duty-ns = <26>;
- qcom,mod-freq-khz = <9600>;
- qcom,dim-mode = "hybrid";
- qcom,hyb-thres = <625>;
- qcom,sync-dly-us = <800>;
- qcom,fs-curr-ua = <25000>;
- qcom,cons-sync-write-delay-us = <1000>;
- qcom,led-strings-list = [00 01 02];
- qcom,loop-auto-gm-en;
- qcom,pmic-revid = <&pm660l_revid>;
- qcom,auto-calibration-enable;
- status = "ok";
- };
-
flash_led: qcom,leds@d300 {
compatible = "qcom,qpnp-flash-led-v2";
reg = <0xd300 0x100>;
@@ -322,89 +293,5 @@
qcom,default-led-trigger = "switch1_trigger";
};
};
-
- pm660l_lcdb: qpnp-lcdb@ec00 {
- compatible = "qcom,qpnp-lcdb-regulator";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xec00 0x100>;
- interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
- interrupt-names = "sc-irq";
-
- qcom,pmic-revid = <&pm660l_revid>;
-
- lcdb_ldo_vreg: ldo {
- label = "ldo";
- regulator-name = "lcdb_ldo";
- regulator-min-microvolt = <4000000>;
- regulator-max-microvolt = <6000000>;
- };
-
- lcdb_ncp_vreg: ncp {
- label = "ncp";
- regulator-name = "lcdb_ncp";
- regulator-min-microvolt = <4000000>;
- regulator-max-microvolt = <6000000>;
- };
- };
-
- pm660a_oledb: qpnp-oledb@e000 {
- compatible = "qcom,qpnp-oledb-regulator";
- #address-cells = <1>;
- #size-cells = <1>;
- qcom,pmic-revid = <&pm660l_revid>;
- reg = <0xe000 0x100>;
- qcom,pbs-client = <&pm660l_pbs>;
-
- label = "oledb";
- regulator-name = "regulator-oledb";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <8100000>;
-
- qcom,swire-control;
- qcom,ext-pin-control;
- status = "disabled";
- };
-
- pm660a_labibb: qpnp-labibb-regulator {
- compatible = "qcom,qpnp-labibb-regulator";
- #address-cells = <1>;
- #size-cells = <1>;
- qcom,pmic-revid = <&pm660l_revid>;
- qcom,swire-control;
- status = "disabled";
-
- ibb_regulator: qcom,ibb@dc00 {
- reg = <0xdc00 0x100>;
- reg-names = "ibb_reg";
- regulator-name = "ibb_reg";
-
- regulator-min-microvolt = <4000000>;
- regulator-max-microvolt = <6300000>;
-
- qcom,qpnp-ibb-min-voltage = <1400000>;
- qcom,qpnp-ibb-step-size = <100000>;
- qcom,qpnp-ibb-slew-rate = <2000000>;
- qcom,qpnp-ibb-init-voltage = <4000000>;
- qcom,qpnp-ibb-init-amoled-voltage = <4000000>;
- };
-
- lab_regulator: qcom,lab@de00 {
- reg = <0xde00 0x100>;
- reg-names = "lab";
- regulator-name = "lab_reg";
-
- regulator-min-microvolt = <4600000>;
- regulator-max-microvolt = <6100000>;
-
- qcom,qpnp-lab-min-voltage = <4600000>;
- qcom,qpnp-lab-step-size = <100000>;
- qcom,qpnp-lab-slew-rate = <5000>;
- qcom,qpnp-lab-init-voltage = <4600000>;
- qcom,qpnp-lab-init-amoled-voltage = <4600000>;
-
- qcom,notify-lab-vreg-ok-sts;
- };
- };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..9b7449e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel CDP";
+ compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <1 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..bb310d3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel MTP";
+ compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <8 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb &sde_dp>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..ab61f2e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts
@@ -0,0 +1,64 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/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-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel QRD";
+ compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <11 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
index f0c820f..9feb5b4 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
@@ -22,9 +22,12 @@
#include "sdm670-cdp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. SDM670 CDP";
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP";
compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
qcom,msm-id = <336 0x0>;
qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
index 7e5947b..27882dd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
@@ -17,7 +17,10 @@
#include "sdm670-cdp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. SDM670 CDP";
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP";
compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index 0cf48a3..4f40678 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#include "sdm670-pmic-overlay.dtsi"
+
&qupv3_se9_2uart {
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
new file mode 100644
index 0000000..d13aa15
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -0,0 +1,310 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+
+ pil_gpu: qcom,kgsl-hyp {
+ compatible = "qcom,pil-tz-generic";
+ qcom,pas-id = <13>;
+ qcom,firmware-name = "a615_zap";
+ };
+
+ msm_bus: qcom,kgsl-busmon{
+ label = "kgsl-busmon";
+ compatible = "qcom,kgsl-busmon";
+ };
+
+ gpubw: qcom,gpubw {
+ compatible = "qcom,devbw";
+ governor = "bw_vbif";
+ qcom,src-dst-ports = <26 512>;
+ qcom,bw-tbl =
+ < 0 /* off */ >,
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 3147 /* 825 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ msm_gpu: qcom,kgsl-3d0@5000000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ status = "ok";
+ reg = <0x5000000 0x40000>;
+ reg-names = "kgsl_3d0_reg_memory";
+ interrupts = <0 300 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x06010500>;
+
+ qcom,initial-pwrlevel = <3>;
+
+ qcom,gpu-quirk-hfi-use-reg;
+
+ /* <HZ/12> */
+ qcom,idle-timeout = <80>;
+ qcom,no-nap;
+
+ qcom,highest-bank-bit = <14>;
+
+ qcom,min-access-length = <64>;
+
+ qcom,ubwc-mode = <2>;
+
+ /* size in bytes */
+ qcom,snapshot-size = <1048576>;
+
+ /* base addr, size */
+ qcom,gpu-qdss-stm = <0x161c0000 0x40000>;
+
+ clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
+ <&clock_gpucc GPU_CC_CXO_CLK>,
+ <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+ <&clock_gpucc GPU_CC_CX_GMU_CLK>,
+ <&clock_gpucc GPU_CC_AHB_CLK>;
+
+ clock-names = "core_clk", "rbbmtimer_clk", "mem_clk",
+ "mem_iface_clk", "gmu_clk", "ahb_clk";
+
+ /* Bus Scale Settings */
+ qcom,gpubw-dev = <&gpubw>;
+ qcom,bus-control;
+ qcom,msm-bus,name = "grp3d";
+ qcom,bus-width = <32>;
+ qcom,msm-bus,num-cases = <12>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>,
+ <26 512 0 400000>, /* 1 bus=100 */
+ <26 512 0 800000>, /* 2 bus=200 */
+ <26 512 0 1200000>, /* 3 bus=300 */
+ <26 512 0 1804000>, /* 4 bus=451 */
+ <26 512 0 2188000>, /* 5 bus=547 */
+ <26 512 0 2724000>, /* 6 bus=681 */
+ <26 512 0 3300000>, /* 7 bus=825 */
+ <26 512 0 4068000>, /* 8 bus=1017 */
+ <26 512 0 5412000>, /* 9 bus=1353 */
+ <26 512 0 6220000>, /* 10 bus=1555 */
+ <26 512 0 7216000>; /* 11 bus=1804 */
+
+ /* GDSC regulator names */
+ regulator-names = "vddcx", "vdd";
+ /* GDSC oxili regulators */
+ vddcx-supply = <&gpu_cx_gdsc>;
+ vdd-supply = <&gpu_gx_gdsc>;
+
+ /* GPU related llc slices */
+ cache-slice-names = "gpu", "gpuhtw";
+ cache-slices = <&llcc 12>, <&llcc 11>;
+
+ /* CPU latency parameter */
+ qcom,pm-qos-active-latency = <660>;
+ qcom,pm-qos-wakeup-latency = <460>;
+
+ /* Enable context aware freq. scaling */
+ qcom,enable-ca-jump;
+ /* Context aware jump busy penalty in us */
+ qcom,ca-busy-penalty = <12000>;
+ /* Context aware jump target power level */
+ qcom,ca-target-pwrlevel = <1>;
+
+ /* GPU Mempools */
+ qcom,gpu-mempools {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-mempools";
+
+ /* 4K Page Pool configuration */
+ qcom,gpu-mempool@0 {
+ reg = <0>;
+ qcom,mempool-page-size = <4096>;
+ qcom,mempool-allocate;
+ };
+ /* 8K Page Pool configuration */
+ qcom,gpu-mempool@1 {
+ reg = <1>;
+ qcom,mempool-page-size = <8192>;
+ qcom,mempool-allocate;
+ };
+ /* 64K Page Pool configuration */
+ qcom,gpu-mempool@2 {
+ reg = <2>;
+ qcom,mempool-page-size = <65536>;
+ qcom,mempool-reserved = <256>;
+ };
+ /* 1M Page Pool configuration */
+ qcom,gpu-mempool@3 {
+ reg = <3>;
+ qcom,mempool-page-size = <1048576>;
+ qcom,mempool-reserved = <32>;
+ };
+ };
+
+ /* Power levels */
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ /* SVS_L1 */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <430000000>;
+ qcom,bus-freq = <11>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <11>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <355000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <10>;
+ };
+
+ /* LOW SVS */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <267000000>;
+ qcom,bus-freq = <6>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <8>;
+ };
+
+ /* MIN SVS */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <180000000>;
+ qcom,bus-freq = <4>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <0>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
+ };
+
+ };
+
+ kgsl_msm_iommu: qcom,kgsl-iommu {
+ compatible = "qcom,kgsl-smmu-v2";
+
+ reg = <0x05040000 0x10000>;
+ qcom,protect = <0x40000 0x10000>;
+ qcom,micro-mmu-control = <0x6000>;
+
+ clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+ <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+ clock-names = "iface_clk", "mem_clk", "mem_iface_clk";
+
+ qcom,secure_align_mask = <0xfff>;
+ qcom,retention;
+ qcom,hyp_secure_alloc;
+
+ gfx3d_user: gfx3d_user {
+ compatible = "qcom,smmu-kgsl-cb";
+ label = "gfx3d_user";
+ iommus = <&kgsl_smmu 0>;
+ qcom,gpu-offset = <0x48000>;
+ };
+
+ gfx3d_secure: gfx3d_secure {
+ compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 2>;
+ };
+ };
+
+ gmu: qcom,gmu {
+ label = "kgsl-gmu";
+ compatible = "qcom,gpu-gmu";
+
+ reg =
+ <0x506a000 0x31000>,
+ <0xb200000 0x300000>,
+ <0xc200000 0x10000>;
+ reg-names =
+ "kgsl_gmu_reg",
+ "kgsl_gmu_pdc_reg",
+ "kgsl_gmu_cpr_reg";
+
+ interrupts = <0 304 0>, <0 305 0>;
+ interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq";
+
+ qcom,msm-bus,name = "cnoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 10036 0 0>, /* CNOC off */
+ <26 10036 0 100>; /* CNOC on */
+
+ regulator-names = "vddcx", "vdd";
+ vddcx-supply = <&gpu_cx_gdsc>;
+ vdd-supply = <&gpu_gx_gdsc>;
+
+
+ clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>,
+ <&clock_gpucc GPU_CC_CXO_CLK>,
+ <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+ <&clock_gpucc GPU_CC_AHB_CLK>;
+
+ clock-names = "gmu_clk", "cxo_clk", "axi_clk",
+ "memnoc_clk", "ahb_clk";
+
+ qcom,gmu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gmu-pwrlevels";
+
+ qcom,gmu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gmu-freq = <200000000>;
+ };
+
+ qcom,gmu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gmu-freq = <0>;
+ };
+ };
+
+ gmu_user: gmu_user {
+ compatible = "qcom,smmu-gmu-user-cb";
+ iommus = <&kgsl_smmu 4>;
+ };
+
+ gmu_kernel: gmu_kernel {
+ compatible = "qcom,smmu-gmu-kernel-cb";
+ iommus = <&kgsl_smmu 5>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
index c8537bc..65c16c1 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
@@ -22,8 +22,11 @@
#include "sdm670-mtp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. SDM670 MTP";
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP";
compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
qcom,msm-id = <336 0x0>;
qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
index 1de40b7..38a9fae 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
@@ -17,7 +17,10 @@
#include "sdm670-mtp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. SDM670 MTP";
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP";
compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index 0cf48a3..4f40678 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#include "sdm670-pmic-overlay.dtsi"
+
&qupv3_se9_2uart {
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..b3d2357
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts
new file mode 100644
index 0000000..5cf3513
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..ff3270d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts
new file mode 100644
index 0000000..febd5d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
new file mode 100644
index 0000000..cd8bfba
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -0,0 +1,367 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&pm660_0{
+ pm660_charger: qcom,qpnp-smb2 {
+ compatible = "qcom,qpnp-smb2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ 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>;
+
+ /* Enable after the qusb_phy0 device node is added */
+ /* dpdm-supply = <&qusb_phy0>; */
+
+ qcom,thermal-mitigation
+ = <3000000 2500000 2000000 1500000
+ 1000000 500000>;
+
+ 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_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 = <96 96>;
+ qcom,fg-esr-timer-asleep = <256 256>;
+ qcom,fg-esr-timer-charging = <0 96>;
+ qcom,cycle-counter-en;
+ 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>;
+ };
+};
+
+&pm660l_3 {
+ pm660l_wled: qcom,leds@d800 {
+ compatible = "qcom,qpnp-wled";
+ reg = <0xd800 0x100>,
+ <0xd900 0x100>;
+ reg-names = "qpnp-wled-ctrl-base",
+ "qpnp-wled-sink-base";
+ interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "ovp-irq";
+ linux,name = "wled";
+ linux,default-trigger = "bkl-trigger";
+ qcom,fdbk-output = "auto";
+ qcom,vref-uv = <127500>;
+ qcom,switch-freq-khz = <800>;
+ qcom,ovp-mv = <29600>;
+ qcom,ilim-ma = <970>;
+ qcom,boost-duty-ns = <26>;
+ qcom,mod-freq-khz = <9600>;
+ qcom,dim-mode = "hybrid";
+ qcom,hyb-thres = <625>;
+ qcom,sync-dly-us = <800>;
+ qcom,fs-curr-ua = <25000>;
+ qcom,cons-sync-write-delay-us = <1000>;
+ qcom,led-strings-list = [00 01 02];
+ qcom,loop-auto-gm-en;
+ qcom,pmic-revid = <&pm660l_revid>;
+ qcom,auto-calibration-enable;
+ status = "ok";
+ };
+
+ pm660l_lcdb: qpnp-lcdb@ec00 {
+ compatible = "qcom,qpnp-lcdb-regulator";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xec00 0x100>;
+ interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "sc-irq";
+
+ qcom,pmic-revid = <&pm660l_revid>;
+
+ lcdb_ldo_vreg: ldo {
+ label = "ldo";
+ regulator-name = "lcdb_ldo";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+
+ lcdb_ncp_vreg: ncp {
+ label = "ncp";
+ regulator-name = "lcdb_ncp";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+ };
+
+ pm660a_oledb: qpnp-oledb@e000 {
+ compatible = "qcom,qpnp-oledb-regulator";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,pmic-revid = <&pm660l_revid>;
+ reg = <0xe000 0x100>;
+ qcom,pbs-client = <&pm660l_pbs>;
+
+ label = "oledb";
+ regulator-name = "regulator-oledb";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <8100000>;
+
+ qcom,swire-control;
+ qcom,ext-pin-control;
+ status = "disabled";
+ };
+
+ pm660a_labibb: qpnp-labibb-regulator {
+ compatible = "qcom,qpnp-labibb-regulator";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,pmic-revid = <&pm660l_revid>;
+ qcom,swire-control;
+ status = "disabled";
+
+ ibb_regulator: qcom,ibb@dc00 {
+ reg = <0xdc00 0x100>;
+ reg-names = "ibb_reg";
+ regulator-name = "ibb_reg";
+
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6300000>;
+
+ qcom,qpnp-ibb-min-voltage = <1400000>;
+ qcom,qpnp-ibb-step-size = <100000>;
+ qcom,qpnp-ibb-slew-rate = <2000000>;
+ qcom,qpnp-ibb-init-voltage = <4000000>;
+ qcom,qpnp-ibb-init-amoled-voltage = <4000000>;
+ };
+
+ lab_regulator: qcom,lab@de00 {
+ reg = <0xde00 0x100>;
+ reg-names = "lab";
+ regulator-name = "lab_reg";
+
+ regulator-min-microvolt = <4600000>;
+ regulator-max-microvolt = <6100000>;
+
+ qcom,qpnp-lab-min-voltage = <4600000>;
+ qcom,qpnp-lab-step-size = <100000>;
+ qcom,qpnp-lab-slew-rate = <5000>;
+ qcom,qpnp-lab-init-voltage = <4600000>;
+ qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+
+ qcom,notify-lab-vreg-ok-sts;
+ };
+ };
+};
+
+&pm660_pdphy {
+ vbus-supply = <&smb2_vbus>;
+ vconn-supply = <&smb2_vconn>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 0a8c49f..1f76288 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -628,13 +628,3 @@
};
};
};
-
-&pm660_charger {
- smb2_vbus: qcom,smb2-vbus {
- regulator-name = "smb2-vbus";
- };
-
- smb2_vconn: qcom,smb2-vconn {
- regulator-name = "smb2-vconn";
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts
index a770b3c..4a24d87 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/plugin/;
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "sdm670-rumi.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
index cc97e3e..ca9d8c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#include "sdm670-pmic-overlay.dtsi"
+
&soc {
/* Delete all regulators */
/delete-node/ rpmh-regulator-smpa4;
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index aeaa3ff..692d75f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -72,6 +72,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9000>;
};
+ L1_TLB_0: l1-tlb {
+ qcom,dump-size = <0x3000>;
+ };
};
CPU1: cpu@100 {
@@ -97,6 +100,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9000>;
};
+ L1_TLB_100: l1-tlb {
+ qcom,dump-size = <0x3000>;
+ };
};
CPU2: cpu@200 {
@@ -122,6 +128,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9000>;
};
+ L1_TLB_200: l1-tlb {
+ qcom,dump-size = <0x3000>;
+ };
};
CPU3: cpu@300 {
@@ -147,6 +156,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9000>;
};
+ L1_TLB_300: l1-tlb {
+ qcom,dump-size = <0x3000>;
+ };
};
CPU4: cpu@400 {
@@ -172,6 +184,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9000>;
};
+ L1_TLB_400: l1-tlb {
+ qcom,dump-size = <0x3000>;
+ };
};
CPU5: cpu@500 {
@@ -197,6 +212,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9000>;
};
+ L1_TLB_500: l1-tlb {
+ qcom,dump-size = <0x3000>;
+ };
};
CPU6: cpu@600 {
@@ -222,6 +240,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
};
+ L1_TLB_600: l1-tlb {
+ qcom,dump-size = <0x3c000>;
+ };
};
CPU7: cpu@700 {
@@ -247,6 +268,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
};
+ L1_TLB_700: l1-tlb {
+ qcom,dump-size = <0x3c000>;
+ };
};
cpu-map {
@@ -984,6 +1008,16 @@
compatible = "qcom,msm-imem-kaslr_offset";
reg = <0x6d0 12>;
};
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 0x20>;
+ };
+
+ diag_dload@c8 {
+ compatible = "qcom,msm-imem-diag-dload";
+ reg = <0xc8 0xc8>;
+ };
};
gpi_dma0: qcom,gpi-dma@0x800000 {
@@ -1024,31 +1058,31 @@
qcom,dump-node = <&L1_I_0>;
qcom,dump-id = <0x60>;
};
- qcom,l1_i_cache1 {
+ qcom,l1_i_cache100 {
qcom,dump-node = <&L1_I_100>;
qcom,dump-id = <0x61>;
};
- qcom,l1_i_cache2 {
+ qcom,l1_i_cache200 {
qcom,dump-node = <&L1_I_200>;
qcom,dump-id = <0x62>;
};
- qcom,l1_i_cache3 {
+ qcom,l1_i_cache300 {
qcom,dump-node = <&L1_I_300>;
qcom,dump-id = <0x63>;
};
- qcom,l1_i_cache100 {
+ qcom,l1_i_cache400 {
qcom,dump-node = <&L1_I_400>;
qcom,dump-id = <0x64>;
};
- qcom,l1_i_cache101 {
+ qcom,l1_i_cache500 {
qcom,dump-node = <&L1_I_500>;
qcom,dump-id = <0x65>;
};
- qcom,l1_i_cache102 {
+ qcom,l1_i_cache600 {
qcom,dump-node = <&L1_I_600>;
qcom,dump-id = <0x66>;
};
- qcom,l1_i_cache103 {
+ qcom,l1_i_cache700 {
qcom,dump-node = <&L1_I_700>;
qcom,dump-id = <0x67>;
};
@@ -1056,31 +1090,31 @@
qcom,dump-node = <&L1_D_0>;
qcom,dump-id = <0x80>;
};
- qcom,l1_d_cache1 {
+ qcom,l1_d_cache100 {
qcom,dump-node = <&L1_D_100>;
qcom,dump-id = <0x81>;
};
- qcom,l1_d_cache2 {
+ qcom,l1_d_cache200 {
qcom,dump-node = <&L1_D_200>;
qcom,dump-id = <0x82>;
};
- qcom,l1_d_cache3 {
+ qcom,l1_d_cache300 {
qcom,dump-node = <&L1_D_300>;
qcom,dump-id = <0x83>;
};
- qcom,l1_d_cache100 {
+ qcom,l1_d_cache400 {
qcom,dump-node = <&L1_D_400>;
qcom,dump-id = <0x84>;
};
- qcom,l1_d_cache101 {
+ qcom,l1_d_cache500 {
qcom,dump-node = <&L1_D_500>;
qcom,dump-id = <0x85>;
};
- qcom,l1_d_cache102 {
+ qcom,l1_d_cache600 {
qcom,dump-node = <&L1_D_600>;
qcom,dump-id = <0x86>;
};
- qcom,l1_d_cache103 {
+ qcom,l1_d_cache700 {
qcom,dump-node = <&L1_D_700>;
qcom,dump-id = <0x87>;
};
@@ -1092,6 +1126,38 @@
qcom,dump-node = <&LLCC_2>;
qcom,dump-id = <0x141>;
};
+ qcom,l1_tlb_dump0 {
+ qcom,dump-node = <&L1_TLB_0>;
+ qcom,dump-id = <0x20>;
+ };
+ qcom,l1_tlb_dump100 {
+ qcom,dump-node = <&L1_TLB_100>;
+ qcom,dump-id = <0x21>;
+ };
+ qcom,l1_tlb_dump200 {
+ qcom,dump-node = <&L1_TLB_200>;
+ qcom,dump-id = <0x22>;
+ };
+ qcom,l1_tlb_dump300 {
+ qcom,dump-node = <&L1_TLB_300>;
+ qcom,dump-id = <0x23>;
+ };
+ qcom,l1_tlb_dump400 {
+ qcom,dump-node = <&L1_TLB_400>;
+ qcom,dump-id = <0x24>;
+ };
+ qcom,l1_tlb_dump500 {
+ qcom,dump-node = <&L1_TLB_500>;
+ qcom,dump-id = <0x25>;
+ };
+ qcom,l1_tlb_dump600 {
+ qcom,dump-node = <&L1_TLB_600>;
+ qcom,dump-id = <0x26>;
+ };
+ qcom,l1_tlb_dump700 {
+ qcom,dump-node = <&L1_TLB_700>;
+ qcom,dump-id = <0x27>;
+ };
};
kryo3xx-erp {
@@ -2047,3 +2113,4 @@
#include "sdm670-regulator.dtsi"
#include "sdm670-audio.dtsi"
#include "sdm670-usb.dtsi"
+#include "sdm670-gpu.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 5fbb1db..646dbad 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -645,7 +645,10 @@
qcom,qport = <2>;
qcom,connections = <&slv_qns_a2noc_snoc>;
qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,ap-owned;
qcom,prio = <2>;
+ qcom,defer-init-qos;
+ qcom,node-qos-bcms = <7035 0 1>;
};
mas_xm_pcie3_1: mas-xm-pcie3-1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index c1fcb62..3cfcddb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -1430,6 +1430,15 @@
<&tpda_spss_out_funnel_spss>;
};
};
+
+ port@2 {
+ reg = <1>;
+ funnel_spss_in_spss_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&spss_etm0_out_funnel_spss>;
+ };
+ };
};
};
@@ -1931,6 +1940,20 @@
};
};
+ spss_etm0 {
+ compatible = "qcom,coresight-dummy";
+
+ coresight-name = "coresight-spss-etm0";
+
+ qcom,dummy-source;
+ port {
+ spss_etm0_out_funnel_spss: endpoint {
+ remote-endpoint =
+ <&funnel_spss_in_spss_etm0>;
+ };
+ };
+ };
+
funnel_apss_merg: funnel@7810000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index b34751b..c02a0a6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -75,6 +75,8 @@
qcom,tsens-name = "tsens_tz_sensor12";
#cooling-cells = <2>;
+ qcom,pm-qos-active-latency = <460>;
+
clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
<&clock_gpucc GPU_CC_CXO_CLK>,
<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index 299f01b..e36a759e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -389,6 +389,7 @@
#include "pm660.dtsi"
#include "pm660l.dtsi"
#include "sdm670-regulator.dtsi"
+#include "sdm670-pmic-overlay.dtsi"
&soc {
/delete-node/ thermal-zones;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..5b3e964
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <1 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..0d6c5e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <8 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb &sde_dp>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..764c145
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts
@@ -0,0 +1,64 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/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-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel QRD";
+ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <11 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 98ab8d4..11d6d8b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -843,6 +843,25 @@
qcom,count-unit = <0x10000>;
};
+&cpubw {
+ qcom,bw-tbl =
+ < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */
+ < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */
+ < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */
+ < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */
+ < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */
+ < MHZ_TO_MBPS(806, 16) >, /* 12298 MB/s */
+ < MHZ_TO_MBPS(933, 16) >; /* 14236 MB/s */
+};
+
+&devfreq_cpufreq {
+ mincpubw-cpufreq {
+ cpu-to-dev-map-4 =
+ < 1881600 MHZ_TO_MBPS(200, 4) >,
+ < 2400000 MHZ_TO_MBPS(681, 4) >;
+ };
+};
+
&clock_gcc {
compatible = "qcom,gcc-sdm845-v2", "syscon";
};
@@ -890,10 +909,10 @@
&energy_costs {
CPU_COST_0: core-cost0 {
busy-cost-data = <
- 300000 11
+ 300000 12
403200 17
480000 21
- 576000 26
+ 576000 27
652800 31
748800 37
825600 42
@@ -901,13 +920,13 @@
979200 52
1056000 57
1132800 62
- 1228800 69
+ 1228800 70
1324800 78
1420800 89
1516800 103
1612800 122
- 1689600 140
- 1766400 159
+ 1689600 141
+ 1766400 160
>;
idle-cost-data = <
22 18 14 12
@@ -915,37 +934,37 @@
};
CPU_COST_1: core-cost1 {
busy-cost-data = <
- 300000 130
- 403200 480
- 480000 730
- 576000 1030
- 652800 1260
- 748800 1530
- 825600 1740
- 902400 1930
- 979200 2110
- 1056000 2290
- 1132800 2460
- 1209600 2630
- 1286400 2800
- 1363200 2980
- 1459200 3240
- 1536000 3490
- 1612800 3780
- 1689600 4120
- 1766400 4530
- 1843200 5020
- 1920000 5590
- 1996800 6230
+ 300000 189
+ 403200 523
+ 480000 763
+ 576000 1052
+ 652800 1273
+ 748800 1536
+ 825600 1736
+ 902400 1926
+ 979200 2108
+ 1056000 2284
+ 1132800 2456
+ 1209600 2628
+ 1286400 2804
+ 1363200 2992
+ 1459200 3255
+ 1536000 3499
+ 1612800 3786
+ 1689600 4128
+ 1766400 4535
+ 1843200 5019
+ 1920000 5583
+ 1996800 6226
2092800 7120
- 2169600 7870
- 2246400 8620
- 2323200 9330
+ 2169600 7876
+ 2246400 8628
+ 2323200 9344
2400000 10030
- 2476800 10830
- 2553600 12080
- 2630400 14580
- 2707200 19960
+ 2476800 10806
+ 2553600 12045
+ 2649600 15686
+ 2745600 25586
>;
idle-cost-data = <
100 80 60 40
@@ -1007,8 +1026,8 @@
2400000 135
2476800 140
2553600 145
- 2630400 150
- 2707200 155
+ 2649600 150
+ 2745600 155
>;
idle-cost-data = <
4 3 2 1
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 0b02e20..fc130cb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -547,6 +547,7 @@
wlan_fw_region: wlan_fw_region@8cb00000 {
compatible = "shared-dma-pool";
+ no-map;
reg = <0 0x8cb00000 0 0x100000>;
};
@@ -827,12 +828,12 @@
<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_LLCC>;
qcom,active-only;
qcom,bw-tbl =
- < 2288 /* 150 MHz */ >,
- < 4577 /* 300 MHz */ >,
- < 6500 /* 426 MHz */ >,
- < 8132 /* 533 MHz */ >,
- < 9155 /* 600 MHz */ >,
- < 10681 /* 700 MHz */ >;
+ < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */
+ < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */
+ < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */
+ < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */
+ < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */
+ < MHZ_TO_MBPS(700, 16) >; /* 10681 MB/s */
};
bwmon: qcom,cpu-bwmon {
@@ -852,16 +853,16 @@
<MSM_BUS_MASTER_LLCC MSM_BUS_SLAVE_EBI_CH0>;
qcom,active-only;
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
llcc_bwmon: qcom,llcc-bwmon {
@@ -882,16 +883,16 @@
qcom,src-dst-ports = <1 512>;
qcom,active-only;
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
memlat_cpu4: qcom,memlat-cpu4 {
@@ -901,16 +902,16 @@
qcom,active-only;
status = "ok";
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive {
@@ -929,11 +930,11 @@
qcom,target-dev = <&memlat_cpu0>;
qcom,cachemiss-ev = <0x2A>;
qcom,core-dev-table =
- < 300000 762 >,
- < 748800 1720 >,
- < 1132800 2086 >,
- < 1440000 2929 >,
- < 1593600 3879 >;
+ < 300000 MHZ_TO_MBPS( 200, 4) >,
+ < 748800 MHZ_TO_MBPS( 451, 4) >,
+ < 1132800 MHZ_TO_MBPS( 547, 4) >,
+ < 1440000 MHZ_TO_MBPS( 768, 4) >,
+ < 1593600 MHZ_TO_MBPS(1017, 4) >;
};
devfreq_memlat_4: qcom,cpu4-memlat-mon {
@@ -942,14 +943,14 @@
qcom,target-dev = <&memlat_cpu4>;
qcom,cachemiss-ev = <0x2A>;
qcom,core-dev-table =
- < 300000 762 >,
- < 499200 1720 >,
- < 806400 2086 >,
- < 1036800 2929 >,
- < 1190400 3879 >,
- < 1574400 4943 >,
- < 1728000 5931 >,
- < 1958400 6881 >;
+ < 300000 MHZ_TO_MBPS( 200, 4) >,
+ < 499200 MHZ_TO_MBPS( 451, 4) >,
+ < 806400 MHZ_TO_MBPS( 547, 4) >,
+ < 1036800 MHZ_TO_MBPS( 768, 4) >,
+ < 1190400 MHZ_TO_MBPS(1017, 4) >,
+ < 1574400 MHZ_TO_MBPS(1296, 4) >,
+ < 1728000 MHZ_TO_MBPS(1555, 4) >,
+ < 1958400 MHZ_TO_MBPS(1804, 4) >;
};
l3_cpu0: qcom,l3-cpu0 {
@@ -1007,26 +1008,26 @@
qcom,src-dst-ports = <1 512>;
qcom,active-only;
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
- devfreq-cpufreq {
+ devfreq_cpufreq: devfreq-cpufreq {
mincpubw-cpufreq {
target-dev = <&mincpubw>;
cpu-to-dev-map-0 =
- < 1708800 762 >;
+ < 1708800 MHZ_TO_MBPS(200, 4) >;
cpu-to-dev-map-4 =
- < 1881600 762 >,
- < 2208000 2597 >;
+ < 1881600 MHZ_TO_MBPS(200, 4) >,
+ < 2208000 MHZ_TO_MBPS(681, 4) >;
};
};
@@ -3008,6 +3009,7 @@
<0 424 0 /* CE10 */ >,
<0 425 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x100000>;
+ qcom,wlan-msa-fixed-region = <&wlan_fw_region>;
vdd-0.8-cx-mx-supply = <&pm8998_l5>;
vdd-1.8-xo-supply = <&pm8998_l7>;
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 59e795b..07e7ee9 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -422,6 +422,7 @@
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index bdc27ea..cda924c 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -410,6 +410,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_RING_BUFFER=y
+CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_CLKGATE=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
@@ -417,6 +418,7 @@
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 4b347e6..f202f7e 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -610,6 +610,7 @@
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_PANIC_ON_SCHED_BUG=y
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 88edacd..9f1a1bb 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3252,6 +3252,7 @@
err_dead_proc_or_thread:
return_error = BR_DEAD_REPLY;
return_error_line = __LINE__;
+ binder_dequeue_work(proc, tcomplete);
err_translate_failed:
err_bad_object_type:
err_bad_offset:
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 55687b8..e17ad53 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -208,6 +208,59 @@
#endif
+static ssize_t show_sched_load_boost(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t rc;
+ unsigned int boost;
+ struct cpu *cpu = container_of(dev, struct cpu, dev);
+ int cpuid = cpu->dev.id;
+
+ boost = per_cpu(sched_load_boost, cpuid);
+ rc = snprintf(buf, PAGE_SIZE-2, "%d\n", boost);
+
+ return rc;
+}
+
+static ssize_t __ref store_sched_load_boost(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int boost;
+ struct cpu *cpu = container_of(dev, struct cpu, dev);
+ int cpuid = cpu->dev.id;
+
+ err = kstrtoint(strstrip((char *)buf), 0, &boost);
+ if (err)
+ return err;
+
+ /*
+ * -100 is low enough to cancel out CPU's load and make it near zro.
+ * 1000 is close to the maximum value that cpu_util_freq_{walt,pelt}
+ * can take without overflow.
+ */
+ if (boost < -100 || boost > 1000)
+ return -EINVAL;
+
+ per_cpu(sched_load_boost, cpuid) = boost;
+
+ return count;
+}
+
+static DEVICE_ATTR(sched_load_boost, 0644,
+ show_sched_load_boost,
+ store_sched_load_boost);
+
+static struct attribute *sched_cpu_attrs[] = {
+ &dev_attr_sched_load_boost.attr,
+ NULL
+};
+
+static struct attribute_group sched_cpu_attr_group = {
+ .attrs = sched_cpu_attrs,
+};
+
static const struct attribute_group *common_cpu_attr_groups[] = {
#ifdef CONFIG_KEXEC
&crash_note_cpu_attr_group,
@@ -215,6 +268,7 @@
#ifdef CONFIG_HOTPLUG_CPU
&cpu_isolated_attr_group,
#endif
+ &sched_cpu_attr_group,
NULL
};
@@ -225,6 +279,7 @@
#ifdef CONFIG_HOTPLUG_CPU
&cpu_isolated_attr_group,
#endif
+ &sched_cpu_attr_group,
NULL
};
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index 1984d4a..3819959 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -1959,6 +1959,7 @@
static const struct of_device_id cam_cc_sdm845_match_table[] = {
{ .compatible = "qcom,cam_cc-sdm845" },
{ .compatible = "qcom,cam_cc-sdm845-v2" },
+ { .compatible = "qcom,cam_cc-sdm670" },
{ }
};
MODULE_DEVICE_TABLE(of, cam_cc_sdm845_match_table);
@@ -1986,6 +1987,11 @@
cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 80000000;
}
+static void cam_cc_sdm845_fixup_sdm670(void)
+{
+ cam_cc_sdm845_fixup_sdm845v2();
+}
+
static int cam_cc_sdm845_fixup(struct platform_device *pdev)
{
const char *compat = NULL;
@@ -1997,6 +2003,8 @@
if (!strcmp(compat, "qcom,cam_cc-sdm845-v2"))
cam_cc_sdm845_fixup_sdm845v2();
+ else if (!strcmp(compat, "qcom,cam_cc-sdm670"))
+ cam_cc_sdm845_fixup_sdm670();
return 0;
}
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c
index e1cda90..2109132 100644
--- a/drivers/clk/qcom/clk-rpmh.c
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -317,10 +317,32 @@
static const struct of_device_id clk_rpmh_match_table[] = {
{ .compatible = "qcom,rpmh-clk-sdm845", .data = &clk_rpmh_sdm845},
+ { .compatible = "qcom,rpmh-clk-sdm670", .data = &clk_rpmh_sdm845},
{ }
};
MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);
+static void clk_rpmh_sdm670_fixup_sdm670(void)
+{
+ sdm845_rpmh_clocks[RPMH_RF_CLK3] = NULL;
+ sdm845_rpmh_clocks[RPMH_RF_CLK3_A] = NULL;
+}
+
+static int clk_rpmh_sdm670_fixup(struct platform_device *pdev)
+{
+ const char *compat = NULL;
+ int compatlen = 0;
+
+ compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+ if (!compat || (compatlen <= 0))
+ return -EINVAL;
+
+ if (!strcmp(compat, "qcom,rpmh-clk-sdm670"))
+ clk_rpmh_sdm670_fixup_sdm670();
+
+ return 0;
+}
+
static int clk_rpmh_probe(struct platform_device *pdev)
{
struct clk **clks;
@@ -388,6 +410,10 @@
goto err2;
}
+ ret = clk_rpmh_sdm670_fixup(pdev);
+ if (ret)
+ return ret;
+
hw_clks = desc->clks;
num_clks = desc->num_clks;
@@ -404,6 +430,11 @@
data->clk_num = num_clks;
for (i = 0; i < num_clks; i++) {
+ if (!hw_clks[i]) {
+ clks[i] = ERR_PTR(-ENOENT);
+ continue;
+ }
+
rpmh_clk = to_clk_rpmh(hw_clks[i]);
rpmh_clk->res_addr = cmd_db_get_addr(rpmh_clk->res_name);
if (!rpmh_clk->res_addr) {
diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c
index cb0cadd..ef1da5c 100644
--- a/drivers/clk/qcom/debugcc-sdm845.c
+++ b/drivers/clk/qcom/debugcc-sdm845.c
@@ -235,6 +235,9 @@
"gcc_video_ahb_clk",
"gcc_video_axi_clk",
"gcc_video_xo_clk",
+ "gcc_sdcc1_ahb_clk",
+ "gcc_sdcc1_apps_clk",
+ "gcc_sdcc1_ice_core_clk",
"gpu_cc_acd_cxo_clk",
"gpu_cc_ahb_clk",
"gpu_cc_crc_ahb_clk",
@@ -685,6 +688,12 @@
0x3F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_video_xo_clk", 0x42, 4, GCC,
0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sdcc1_ahb_clk", 0x15C, 4, GCC,
+ 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sdcc1_apps_clk", 0x15B, 4, GCC,
+ 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sdcc1_ice_core_clk", 0x15D, 4, GCC,
+ 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gpu_cc_acd_cxo_clk", 0x144, 4, GPU_CC,
0x1F, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
{ "gpu_cc_ahb_clk", 0x144, 4, GPU_CC,
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index 53bfe77..d57bf5f 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -1014,6 +1014,7 @@
static const struct of_device_id disp_cc_sdm845_match_table[] = {
{ .compatible = "qcom,dispcc-sdm845" },
{ .compatible = "qcom,dispcc-sdm845-v2" },
+ { .compatible = "qcom,dispcc-sdm670" },
{ }
};
MODULE_DEVICE_TABLE(of, disp_cc_sdm845_match_table);
@@ -1064,6 +1065,11 @@
430000000;
}
+static void disp_cc_sdm845_fixup_sdm670(struct regmap *regmap)
+{
+ disp_cc_sdm845_fixup_sdm845v2(regmap);
+}
+
static int disp_cc_sdm845_fixup(struct platform_device *pdev,
struct regmap *regmap)
{
@@ -1076,6 +1082,8 @@
if (!strcmp(compat, "qcom,dispcc-sdm845-v2"))
disp_cc_sdm845_fixup_sdm845v2(regmap);
+ else if (!strcmp(compat, "qcom,dispcc-sdm670"))
+ disp_cc_sdm845_fixup_sdm670(regmap);
return 0;
}
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 17b2403..a363235 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -198,6 +198,22 @@
"core_bi_pll_test_se",
};
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL6_OUT_MAIN, 2 },
+ { P_GPLL0_OUT_EVEN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_11[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll6",
+ "gpll0_out_even",
+ "core_bi_pll_test_se",
+};
+
static struct clk_dummy measure_only_snoc_clk = {
.rrate = 1000,
.hw.init = &(struct clk_init_data){
@@ -301,6 +317,28 @@
},
};
+static struct clk_alpha_pll gpll6 = {
+ .offset = 0x13000,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .type = FABIA_PLL,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(6),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll6",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_fabia_fixed_pll_ops,
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
+ },
+ },
+};
+
static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
{ }
@@ -330,6 +368,12 @@
{ }
};
+static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src_sdm670[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = {
.cmd_rcgr = 0x4815c,
.mnd_width = 0,
@@ -862,6 +906,67 @@
},
};
+static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = {
+ F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x26010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ VDD_CX_FMAX_MAP3(
+ MIN, 75000000,
+ LOW, 150000000,
+ NOMINAL, 300000000),
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+ F(144000, P_BI_TCXO, 16, 3, 25),
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(20000000, P_GPLL0_OUT_EVEN, 5, 1, 3),
+ F(25000000, P_GPLL0_OUT_EVEN, 6, 1, 2),
+ F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x26028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk_src",
+ .parent_names = gcc_parent_names_11,
+ .num_parents = 5,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ VDD_CX_FMAX_MAP4(
+ MIN, 19200000,
+ LOWER, 50000000,
+ LOW, 100000000,
+ NOMINAL, 384000000),
+ },
+};
+
static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
F(400000, P_BI_TCXO, 12, 1, 4),
F(9600000, P_BI_TCXO, 2, 0, 0),
@@ -904,17 +1009,28 @@
{ }
};
+static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src_sdm670[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(9600000, P_BI_TCXO, 2, 0, 0),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(33333333, P_GPLL0_OUT_EVEN, 9, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
.cmd_rcgr = 0x1600c,
.mnd_width = 8,
.hid_width = 5,
- .parent_map = gcc_parent_map_3,
+ .parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_sdcc4_apps_clk_src,
.enable_safe_config = true,
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc4_apps_clk_src",
- .parent_names = gcc_parent_names_3,
- .num_parents = 3,
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
VDD_CX_FMAX_MAP4(
@@ -2700,6 +2816,55 @@
},
};
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x2600c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_names = (const char *[]){
+ "gcc_sdcc1_ice_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x26008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x26008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x26004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x26004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_names = (const char *[]){
+ "gcc_sdcc1_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_sdcc2_ahb_clk = {
.halt_reg = 0x14008,
.halt_check = BRANCH_HALT,
@@ -3824,6 +3989,12 @@
[GPLL0] = &gpll0.clkr,
[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
[GPLL4] = &gpll4.clkr,
+ [GCC_SDCC1_AHB_CLK] = NULL,
+ [GCC_SDCC1_APPS_CLK] = NULL,
+ [GCC_SDCC1_ICE_CORE_CLK] = NULL,
+ [GCC_SDCC1_APPS_CLK_SRC] = NULL,
+ [GCC_SDCC1_ICE_CORE_CLK_SRC] = NULL,
+ [GPLL6] = NULL,
};
static const struct qcom_reset_map gcc_sdm845_resets[] = {
@@ -3853,6 +4024,7 @@
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
[GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
[GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
+ [GCC_SDCC1_BCR] = { 0x26000 },
};
/* List of RCG clocks and corresponding flags requested for DFS Mode */
@@ -3899,6 +4071,7 @@
static const struct of_device_id gcc_sdm845_match_table[] = {
{ .compatible = "qcom,gcc-sdm845" },
{ .compatible = "qcom,gcc-sdm845-v2" },
+ { .compatible = "qcom,gcc-sdm670" },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
@@ -4009,6 +4182,86 @@
ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2;
}
+static void gcc_sdm845_fixup_sdm670(void)
+{
+ gcc_sdm845_fixup_sdm845v2();
+
+ gcc_sdm845_clocks[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr;
+ gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr;
+ gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK] =
+ &gcc_sdcc1_ice_core_clk.clkr;
+ gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK_SRC] =
+ &gcc_sdcc1_apps_clk_src.clkr;
+ gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK_SRC] =
+ &gcc_sdcc1_ice_core_clk_src.clkr;
+ gcc_sdm845_clocks[GPLL6] = &gpll6.clkr;
+ gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_AGGRE_USB3_SEC_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_AGGRE_NOC_PCIE_TBU_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_CFG_NOC_USB3_SEC_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_CFG_AHB_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_CLKREF_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_MSTR_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_PIPE_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_SLV_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_0_SLV_Q2A_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_CFG_AHB_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_CLKREF_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_MSTR_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_PIPE_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_SLV_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_1_SLV_Q2A_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_PHY_AUX_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_AHB_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_AXI_HW_CTL_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_CLKREF_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_0_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_1_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_TX_SYMBOL_0_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_UFS_PHY_RX_SYMBOL_1_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_USB30_SEC_SLEEP_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_USB3_SEC_CLKREF_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK_SRC] = NULL;
+ gcc_sdm845_clocks[GCC_USB3_SEC_PHY_COM_AUX_CLK] = NULL;
+ gcc_sdm845_clocks[GCC_USB3_SEC_PHY_PIPE_CLK] = NULL;
+
+ gcc_cpuss_rbcpr_clk_src.freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src_sdm670;
+ gcc_cpuss_rbcpr_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+ 50000000;
+ gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+ 50000000;
+ gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+ 100000000;
+ gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+ 201500000;
+ gcc_sdcc4_apps_clk_src.freq_tbl = ftbl_gcc_sdcc4_apps_clk_src_sdm670;
+ gcc_sdcc4_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+ 33333333;
+}
+
static int gcc_sdm845_fixup(struct platform_device *pdev)
{
const char *compat = NULL;
@@ -4020,6 +4273,8 @@
if (!strcmp(compat, "qcom,gcc-sdm845-v2"))
gcc_sdm845_fixup_sdm845v2();
+ else if (!strcmp(compat, "qcom,gcc-sdm670"))
+ gcc_sdm845_fixup_sdm670();
return 0;
}
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index cf4a8a5..db0dad1 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -224,6 +224,12 @@
{ }
};
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm670[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gpu_cc_gmu_clk_src = {
.cmd_rcgr = 0x1120,
.mnd_width = 0,
@@ -279,6 +285,18 @@
{ }
};
+static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670[] = {
+ F(180000000, P_CRC_DIV, 1, 0, 0),
+ F(267000000, P_CRC_DIV, 1, 0, 0),
+ F(355000000, P_CRC_DIV, 1, 0, 0),
+ F(430000000, P_CRC_DIV, 1, 0, 0),
+ F(565000000, P_CRC_DIV, 1, 0, 0),
+ F(650000000, P_CRC_DIV, 1, 0, 0),
+ F(750000000, P_CRC_DIV, 1, 0, 0),
+ F(780000000, P_CRC_DIV, 1, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = {
.cmd_rcgr = 0x101c,
.mnd_width = 0,
@@ -585,6 +603,7 @@
static const struct of_device_id gpu_cc_sdm845_match_table[] = {
{ .compatible = "qcom,gpucc-sdm845" },
{ .compatible = "qcom,gpucc-sdm845-v2" },
+ { .compatible = "qcom,gpucc-sdm670" },
{ }
};
MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
@@ -592,6 +611,7 @@
static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = {
{ .compatible = "qcom,gfxcc-sdm845" },
{ .compatible = "qcom,gfxcc-sdm845-v2" },
+ { .compatible = "qcom,gfxcc-sdm670" },
{},
};
MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table);
@@ -605,6 +625,15 @@
gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 500000000;
}
+static void gpu_cc_sdm845_fixup_sdm670(struct regmap *regmap)
+{
+ gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr;
+ clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
+ gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm670;
+ gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 0;
+}
+
static void gpu_cc_gfx_sdm845_fixup_sdm845v2(void)
{
gpu_cc_gx_gfx3d_clk_src.freq_tbl =
@@ -624,6 +653,28 @@
710000000;
}
+static void gpu_cc_gfx_sdm845_fixup_sdm670(void)
+{
+ gpu_cc_gx_gfx3d_clk_src.freq_tbl =
+ ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] =
+ 180000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] =
+ 267000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] =
+ 355000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] =
+ 430000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] =
+ 565000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] =
+ 650000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] =
+ 750000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] =
+ 780000000;
+}
+
static int gpu_cc_gfx_sdm845_fixup(struct platform_device *pdev)
{
const char *compat = NULL;
@@ -635,6 +686,8 @@
if (!strcmp(compat, "qcom,gfxcc-sdm845-v2"))
gpu_cc_gfx_sdm845_fixup_sdm845v2();
+ else if (!strcmp(compat, "qcom,gfxcc-sdm670"))
+ gpu_cc_gfx_sdm845_fixup_sdm670();
return 0;
}
@@ -651,6 +704,8 @@
if (!strcmp(compat, "qcom,gpucc-sdm845-v2"))
gpu_cc_sdm845_fixup_sdm845v2(regmap);
+ else if (!strcmp(compat, "qcom,gpucc-sdm670"))
+ gpu_cc_sdm845_fixup_sdm670(regmap);
return 0;
}
diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index ba4e591..3311e9f 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -328,6 +328,7 @@
static const struct of_device_id video_cc_sdm845_match_table[] = {
{ .compatible = "qcom,video_cc-sdm845" },
{ .compatible = "qcom,video_cc-sdm845-v2" },
+ { .compatible = "qcom,video_cc-sdm670" },
{ }
};
MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table);
@@ -340,6 +341,12 @@
404000000;
}
+static void video_cc_sdm845_fixup_sdm670(void)
+{
+ video_cc_sdm845_fixup_sdm845v2();
+
+}
+
static int video_cc_sdm845_fixup(struct platform_device *pdev)
{
const char *compat = NULL;
@@ -351,6 +358,8 @@
if (!strcmp(compat, "qcom,video_cc-sdm845-v2"))
video_cc_sdm845_fixup_sdm845v2();
+ else if (!strcmp(compat, "qcom,video_cc-sdm670"))
+ video_cc_sdm845_fixup_sdm670();
return 0;
}
diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c
index e1afa60..81d98d1 100644
--- a/drivers/devfreq/governor_memlat.c
+++ b/drivers/devfreq/governor_memlat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -244,7 +244,11 @@
hw->core_stats[i].mem_count,
hw->core_stats[i].freq, ratio);
- if (ratio && ratio <= node->ratio_ceil
+ if (!hw->core_stats[i].inst_count
+ || !hw->core_stats[i].freq)
+ continue;
+
+ if (ratio <= node->ratio_ceil
&& hw->core_stats[i].freq > max_freq) {
lat_dev = i;
max_freq = hw->core_stats[i].freq;
diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index 4b89cbf..038e89c 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -397,21 +397,6 @@
if (rc)
goto out_mem;
- if (interrupt_mode) {
- drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
- if (!drv->ecc_irq) {
- rc = -ENODEV;
- goto out_dev;
- }
-
- rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
- IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
- if (rc) {
- dev_err(dev, "failed to request ecc irq\n");
- goto out_dev;
- }
- }
-
drv->llcc_banks = devm_kzalloc(&pdev->dev,
sizeof(u32) * drv->num_banks, GFP_KERNEL);
@@ -437,6 +422,21 @@
platform_set_drvdata(pdev, edev_ctl);
+ if (interrupt_mode) {
+ drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
+ if (!drv->ecc_irq) {
+ rc = -ENODEV;
+ goto out_dev;
+ }
+
+ rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
+ IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
+ if (rc) {
+ dev_err(dev, "failed to request ecc irq\n");
+ goto out_dev;
+ }
+ }
+
return 0;
out_dev:
diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
index 061acee..016e1b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
+++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
@@ -27,6 +27,7 @@
#define DP_INTR_STATUS3 (0x00000028)
#define dp_read(offset) readl_relaxed((offset))
#define dp_write(offset, data) writel_relaxed((data), (offset))
+#define DP_HDCP_RXCAPS_LENGTH 3
enum dp_hdcp2p2_sink_status {
SINK_DISCONNECTED,
@@ -893,21 +894,22 @@
static bool dp_hdcp2p2_supported(struct dp_hdcp2p2_ctrl *ctrl)
{
u32 const rxcaps_dpcd_offset = 0x6921d;
- ssize_t const bytes_to_read = 1;
ssize_t bytes_read = 0;
- u8 buf = 0;
+ u8 buf[DP_HDCP_RXCAPS_LENGTH];
bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
- rxcaps_dpcd_offset, &buf, bytes_to_read);
- if (bytes_read != bytes_to_read) {
+ rxcaps_dpcd_offset, &buf, DP_HDCP_RXCAPS_LENGTH);
+ if (bytes_read != DP_HDCP_RXCAPS_LENGTH) {
pr_err("RxCaps read failed\n");
goto error;
}
- pr_debug("rxcaps 0x%x\n", buf);
+ pr_debug("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1);
+ pr_debug("VERSION=%d\n", buf[0]);
- if (buf & BIT(1))
+ if ((buf[2] & BIT(1)) && (buf[0] == 0x2))
return true;
+
error:
return false;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index df43267..bd7a66e 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -178,7 +178,10 @@
u32 config = 0;
const u32 ufp_d_config = 0x2, dp_ver = 0x1;
- pin_cfg = pd->cap.dlink_pin_config;
+ if (pd->cap.receptacle_state)
+ pin_cfg = pd->cap.ulink_pin_config;
+ else
+ pin_cfg = pd->cap.dlink_pin_config;
for (pin = DP_USBPD_PIN_A; pin < DP_USBPD_PIN_MAX; pin++) {
if (pin_cfg & BIT(pin)) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 3fec296..cd21413 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -354,8 +354,6 @@
reg_ctrl |= (reg << offset);
reg_ctrl2 &= ~(0xFFFF << offset);
reg_ctrl2 |= (dsc.bytes_in_slice << offset);
- DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
- DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
pr_debug("ctrl %d reg_ctrl 0x%x reg_ctrl2 0x%x\n", ctrl->index,
reg_ctrl, reg_ctrl2);
@@ -373,6 +371,9 @@
stream_ctrl |= (vc_id & 0x3) << 8;
stream_ctrl |= 0x39; /* packet data type */
+ DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
+ DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
+
DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, stream_ctrl);
DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, stream_ctrl);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 4e76aa5..aa81d55 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -95,10 +95,28 @@
pr_debug("bl_scale = %u, bl_scale_ad = %u, bl_lvl = %u\n",
bl_scale, bl_scale_ad, (u32)bl_temp);
+
+ rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_ON);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
+ dsi_display->name, rc);
+ goto error;
+ }
+
rc = dsi_panel_set_backlight(panel, (u32)bl_temp);
if (rc)
pr_err("unable to set backlight\n");
+ rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_OFF);
+ if (rc) {
+ pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
+ dsi_display->name, rc);
+ goto error;
+ }
+
+error:
return rc;
}
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 0c1bcf6..e0617ee 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -476,6 +476,10 @@
struct drm_crtc *crtc = NULL;
struct drm_crtc_state *crtc_state = NULL;
int ret = -EINVAL, i = 0, j = 0;
+ bool nonblock;
+
+ /* cache since work will kfree commit in non-blocking case */
+ nonblock = commit->nonblock;
for_each_crtc_in_state(state, crtc, crtc_state, i) {
for (j = 0; j < priv->num_crtcs; j++) {
@@ -515,10 +519,13 @@
*/
DRM_ERROR("failed to dispatch commit to any CRTC\n");
complete_commit(commit);
- } else if (!commit->nonblock) {
+ } else if (!nonblock) {
kthread_flush_work(&commit->commit_work);
- kfree(commit);
}
+
+ /* free nonblocking commits in this context, after processing */
+ if (!nonblock)
+ kfree(commit);
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 9409066..faef4ce 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -1445,7 +1445,6 @@
goto exit;
}
- INIT_LIST_HEAD(&ad_irq->list);
ad_irq->arg = crtc;
ad_irq->func = sde_cp_ad_interrupt_cb;
ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq);
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 9d70525..69ee2be 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -12,6 +12,7 @@
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
#include "msm_drv.h"
+#include "sde_dbg.h"
#include "sde_kms.h"
#include "sde_connector.h"
@@ -107,7 +108,6 @@
static int sde_backlight_setup(struct sde_connector *c_conn,
struct drm_device *dev)
{
- struct backlight_device *bl_device;
struct backlight_properties props;
struct dsi_display *display;
struct dsi_backlight_config *bl_config;
@@ -131,11 +131,12 @@
props.brightness = bl_config->brightness_max_level;
snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
display_count);
- bl_device = backlight_device_register(bl_node_name, dev->dev,
+ c_conn->bl_device = backlight_device_register(bl_node_name, dev->dev,
c_conn, &sde_backlight_device_ops, &props);
- if (IS_ERR_OR_NULL(bl_device)) {
+ if (IS_ERR_OR_NULL(c_conn->bl_device)) {
SDE_ERROR("Failed to register backlight: %ld\n",
- PTR_ERR(bl_device));
+ PTR_ERR(c_conn->bl_device));
+ c_conn->bl_device = NULL;
return -ENODEV;
}
display_count++;
@@ -502,6 +503,8 @@
drm_property_unreference_blob(c_conn->blob_dither);
msm_property_destroy(&c_conn->property_info);
+ if (c_conn->bl_device)
+ backlight_device_unregister(c_conn->bl_device);
drm_connector_unregister(connector);
mutex_destroy(&c_conn->lock);
sde_fence_deinit(&c_conn->retire_fence);
@@ -1197,6 +1200,8 @@
return ERR_PTR(-ENOMEM);
}
+ memset(&display_info, 0, sizeof(display_info));
+
rc = drm_connector_init(dev,
&c_conn->base,
&sde_connector_ops,
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index b44bfae..ceeafc2 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -247,6 +247,7 @@
* @fb_kmap: true if kernel mapping of framebuffer is requested
* @event_table: Array of registered events
* @event_lock: Lock object for event_table
+ * @bl_device: backlight device node
*/
struct sde_connector {
struct drm_connector base;
@@ -277,6 +278,8 @@
bool fb_kmap;
struct sde_connector_evt event_table[SDE_CONN_EVENT_COUNT];
spinlock_t event_lock;
+
+ struct backlight_device *bl_device;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index cac7893..387f08d 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -3046,6 +3046,9 @@
struct drm_encoder *encoder;
struct sde_crtc_mixer *m;
u32 i, misr_status;
+ unsigned long flags;
+ struct sde_crtc_irq_info *node = NULL;
+ int ret = 0;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -3066,6 +3069,18 @@
sde_encoder_virt_restore(encoder);
}
+
+ spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+ list_for_each_entry(node, &sde_crtc->user_event_list, list) {
+ ret = 0;
+ if (node->func)
+ ret = node->func(crtc, true, &node->irq);
+ if (ret)
+ SDE_ERROR("%s failed to enable event %x\n",
+ sde_crtc->name, node->event);
+ }
+ spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
+
sde_cp_crtc_post_ipc(crtc);
for (i = 0; i < sde_crtc->num_mixers; ++i) {
@@ -3089,6 +3104,19 @@
sde_crtc->misr_data[i] = misr_status ? misr_status :
sde_crtc->misr_data[i];
}
+
+ spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+ node = NULL;
+ list_for_each_entry(node, &sde_crtc->user_event_list, list) {
+ ret = 0;
+ if (node->func)
+ ret = node->func(crtc, false, &node->irq);
+ if (ret)
+ SDE_ERROR("%s failed to disable event %x\n",
+ sde_crtc->name, node->event);
+ }
+ spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
+
sde_cp_crtc_pre_ipc(crtc);
break;
case SDE_POWER_EVENT_POST_DISABLE:
@@ -4705,6 +4733,7 @@
if (crtc_drm->enabled) {
sde_power_resource_enable(&priv->phandle, kms->core_client,
true);
+ INIT_LIST_HEAD(&node->irq.list);
ret = node->func(crtc_drm, true, &node->irq);
sde_power_resource_enable(&priv->phandle, kms->core_client,
false);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 8a46d66..3e1ed7b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1237,6 +1237,102 @@
}
}
+static int _sde_encoder_dsc_disable(struct sde_encoder_virt *sde_enc)
+{
+ enum sde_rm_topology_name topology;
+ struct drm_connector *drm_conn;
+ int i, ret = 0;
+ struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
+ struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC] = {NULL};
+ int pp_count = 0;
+ int dsc_count = 0;
+
+ if (!sde_enc || !sde_enc->phys_encs[0] ||
+ !sde_enc->phys_encs[0]->connector) {
+ SDE_ERROR("invalid params %d %d\n",
+ !sde_enc, sde_enc ? !sde_enc->phys_encs[0] : -1);
+ return -EINVAL;
+ }
+
+ drm_conn = sde_enc->phys_encs[0]->connector;
+
+ topology = sde_connector_get_topology_name(drm_conn);
+ if (topology == SDE_RM_TOPOLOGY_NONE) {
+ SDE_ERROR_ENC(sde_enc, "topology not set yet\n");
+ return -EINVAL;
+ }
+
+ switch (topology) {
+ case SDE_RM_TOPOLOGY_SINGLEPIPE:
+ case SDE_RM_TOPOLOGY_SINGLEPIPE_DSC:
+ /* single PP */
+ hw_pp[0] = sde_enc->hw_pp[0];
+ hw_dsc[0] = sde_enc->hw_dsc[0];
+ pp_count = 1;
+ dsc_count = 1;
+ break;
+ case SDE_RM_TOPOLOGY_DUALPIPE_DSC:
+ case SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC:
+ case SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE:
+ /* dual dsc */
+ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+ hw_dsc[i] = sde_enc->hw_dsc[i];
+ if (hw_dsc[i])
+ dsc_count++;
+ }
+ /* fall through */
+ case SDE_RM_TOPOLOGY_DUALPIPE:
+ case SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE:
+ /* dual pp */
+ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+ hw_pp[i] = sde_enc->hw_pp[i];
+ if (hw_pp[i])
+ pp_count++;
+ }
+ break;
+ default:
+ SDE_ERROR_ENC(sde_enc, "Unexpected topology:%d\n", topology);
+ return -EINVAL;
+ };
+
+ SDE_EVT32(DRMID(&sde_enc->base), topology, pp_count, dsc_count);
+
+ if (pp_count > MAX_CHANNELS_PER_ENC ||
+ dsc_count > MAX_CHANNELS_PER_ENC) {
+ SDE_ERROR_ENC(sde_enc, "Wrong count pp:%d dsc:%d top:%d\n",
+ pp_count, dsc_count, topology);
+ return -EINVAL;
+ }
+
+ /* Disable DSC for all the pp's present in this topology */
+ for (i = 0; i < pp_count; i++) {
+
+ if (!hw_pp[i]) {
+ SDE_ERROR_ENC(sde_enc, "null pp:%d top:%d cnt:%d\n",
+ i, topology, pp_count);
+ return -EINVAL;
+ }
+
+ if (hw_pp[i]->ops.disable_dsc)
+ hw_pp[i]->ops.disable_dsc(hw_pp[i]);
+ }
+
+ /* Disable DSC HW */
+ for (i = 0; i < dsc_count; i++) {
+
+ if (!hw_dsc[i]) {
+ SDE_ERROR_ENC(sde_enc, "null dsc:%d top:%d cnt:%d\n",
+ i, topology, dsc_count);
+ return -EINVAL;
+ }
+
+ if (hw_dsc[i]->ops.dsc_disable)
+ hw_dsc[i]->ops.dsc_disable(hw_dsc[i]);
+ }
+
+ return ret;
+}
+
static int _sde_encoder_update_rsc_client(
struct drm_encoder *drm_enc,
struct sde_encoder_rsc_config *config, bool enable)
@@ -1876,6 +1972,12 @@
ret);
return;
}
+
+ /*
+ * Disable dsc before switch the mode and after pre_modeset,
+ * to guarantee that previous kickoff finished.
+ */
+ _sde_encoder_dsc_disable(sde_enc);
}
/* Reserve dynamic resources now. Indicating non-AtomicTest phase */
@@ -2107,6 +2209,13 @@
phys->ops.disable(phys);
}
+ /*
+ * disable dsc after the transfer is complete (for command mode)
+ * and after physical encoder is disabled, to make sure timing
+ * engine is already disabled (for video mode).
+ */
+ _sde_encoder_dsc_disable(sde_enc);
+
/* after phys waits for frame-done, should be no more frames pending */
if (atomic_xchg(&sde_enc->frame_done_timeout, 0)) {
SDE_ERROR("enc%d timeout pending\n", drm_enc->base.id);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 61e761d..b80ed1f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -157,15 +157,6 @@
u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines;
u32 actual_vfp_lines = 0;
- if (worst_case_needed_lines < start_of_frame_lines) {
- needed_vfp_lines = 0;
- SDE_ERROR("invalid params - needed_lines:%d, frame_lines:%d\n",
- worst_case_needed_lines, start_of_frame_lines);
- } else {
- needed_vfp_lines = worst_case_needed_lines
- - start_of_frame_lines;
- }
-
/* Fetch must be outside active lines, otherwise undefined. */
if (start_of_frame_lines >= worst_case_needed_lines) {
SDE_DEBUG_VIDENC(vid_enc,
@@ -464,10 +455,26 @@
return false;
}
+static bool _sde_encoder_phys_is_dual_ctl(struct sde_encoder_phys *phys_enc)
+{
+ enum sde_rm_topology_name topology;
+
+ if (!phys_enc)
+ return false;
+
+ topology = sde_connector_get_topology_name(phys_enc->connector);
+ if ((topology == SDE_RM_TOPOLOGY_DUALPIPE_DSC) ||
+ (topology == SDE_RM_TOPOLOGY_DUALPIPE))
+ return true;
+
+ return false;
+}
+
static bool sde_encoder_phys_vid_needs_single_flush(
struct sde_encoder_phys *phys_enc)
{
- return phys_enc && _sde_encoder_phys_is_ppsplit(phys_enc);
+ return phys_enc && (_sde_encoder_phys_is_ppsplit(phys_enc) ||
+ _sde_encoder_phys_is_dual_ctl(phys_enc));
}
static void _sde_encoder_phys_vid_setup_irq_hw_idx(
@@ -614,10 +621,11 @@
sde_encoder_phys_vid_setup_timing_engine(phys_enc);
/*
- * For pp-split, skip setting the flush bit for the slave intf, since
- * both intfs use same ctl and HW will only flush the master.
+ * For single flush cases (dual-ctl or pp-split), skip setting the
+ * flush bit for the slave intf, since both intfs use same ctl
+ * and HW will only flush the master.
*/
- if (_sde_encoder_phys_is_ppsplit(phys_enc) &&
+ if (sde_encoder_phys_vid_needs_single_flush(phys_enc) &&
!sde_encoder_phys_vid_is_master(phys_enc))
goto skip_flush;
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index ad390af..5732aae6 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -136,31 +136,12 @@
static void sde_fence_release(struct fence *fence)
{
- struct sde_fence *f = to_sde_fence(fence);
- struct sde_fence *fc, *next;
- struct sde_fence_context *ctx;
- bool release_kref = false;
+ struct sde_fence *f;
- if (!fence || !f->ctx)
- return;
-
- ctx = f->ctx;
-
- spin_lock(&ctx->list_lock);
- list_for_each_entry_safe(fc, next, &ctx->fence_list_head, fence_list) {
- /* fence release called before signal */
- if (f == fc) {
- list_del_init(&fc->fence_list);
- release_kref = true;
- break;
- }
+ if (fence) {
+ f = to_sde_fence(fence);
+ kfree(f);
}
- spin_unlock(&ctx->list_lock);
-
- /* keep kput outside spin_lock because it may release ctx */
- if (release_kref)
- kref_put(&ctx->kref, sde_fence_destroy);
- kfree(f);
}
static void sde_fence_value_str(struct fence *fence, char *str, int size)
@@ -324,6 +305,7 @@
spin_unlock_irqrestore(&ctx->lock, flags);
if (is_signaled) {
+ fence_put(&fc->base);
kref_put(&ctx->kref, sde_fence_destroy);
} else {
spin_lock(&ctx->list_lock);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 0e1ab51..ccc4443 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -2944,33 +2944,25 @@
rc = sde_hardware_format_caps(sde_cfg, hw_rev);
- switch (hw_rev) {
- case SDE_HW_VER_170:
- case SDE_HW_VER_171:
- case SDE_HW_VER_172:
+ if (IS_MSM8996_TARGET(hw_rev)) {
/* update msm8996 target here */
sde_cfg->perf.min_prefill_lines = 21;
- break;
- case SDE_HW_VER_300:
- case SDE_HW_VER_301:
+ } else if (IS_MSM8998_TARGET(hw_rev)) {
/* update msm8998 target here */
sde_cfg->has_wb_ubwc = true;
sde_cfg->perf.min_prefill_lines = 25;
sde_cfg->vbif_qos_nlvl = 4;
sde_cfg->ts_prefill_rev = 1;
- sde_cfg->perf.min_prefill_lines = 25;
- break;
- case SDE_HW_VER_400:
+ } else if (IS_SDM845_TARGET(hw_rev)) {
/* update sdm845 target here */
sde_cfg->has_wb_ubwc = true;
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
- sde_cfg->perf.min_prefill_lines = 24;
- break;
- default:
+ } else {
+ SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
sde_cfg->perf.min_prefill_lines = 0xffff;
- break;
+ rc = -ENODEV;
}
return rc;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index fa10a88..48c3db7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -45,7 +45,10 @@
#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */
#define SDE_HW_VER_301 SDE_HW_VER(3, 0, 1) /* 8998 v1.1 */
#define SDE_HW_VER_400 SDE_HW_VER(4, 0, 0) /* sdm845 v1.0 */
+#define SDE_HW_VER_401 SDE_HW_VER(4, 0, 1) /* sdm845 v2.0 */
+#define IS_MSM8996_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_170)
+#define IS_MSM8998_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_300)
#define IS_SDM845_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400)
#define SDE_HW_BLK_NAME_LEN 16
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 6b1f33d..621a172 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -39,7 +39,7 @@
#define CTL_FLUSH_MASK_ROT BIT(27)
#define CTL_FLUSH_MASK_CTL BIT(17)
-#define SDE_REG_RESET_TIMEOUT_COUNT 20
+#define SDE_REG_RESET_TIMEOUT_US 2000
static struct sde_ctl_cfg *_ctl_offset(enum sde_ctl ctl,
struct sde_mdss_cfg *m,
@@ -298,14 +298,13 @@
return 0;
}
-static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 count)
+static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 timeout_us)
{
struct sde_hw_blk_reg_map *c = &ctx->hw;
+ ktime_t timeout;
u32 status;
- /* protect to do at least one iteration */
- if (!count)
- count = 1;
+ timeout = ktime_add_us(ktime_get(), timeout_us);
/*
* it takes around 30us to have mdp finish resetting its ctl path
@@ -313,10 +312,10 @@
*/
do {
status = SDE_REG_READ(c, CTL_SW_RESET);
- status &= 0x01;
+ status &= 0x1;
if (status)
usleep_range(20, 50);
- } while (status && --count > 0);
+ } while (status && ktime_compare_safe(ktime_get(), timeout) < 0);
return status;
}
@@ -327,7 +326,7 @@
pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx);
SDE_REG_WRITE(c, CTL_SW_RESET, 0x1);
- if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT))
+ if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_US))
return -EINVAL;
return 0;
@@ -344,7 +343,7 @@
return 0;
pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx);
- if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT)) {
+ if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_US)) {
pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index ff796f7..d65e8d0 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -165,11 +165,16 @@
static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
{
struct sde_hw_blk_reg_map *c;
+ u32 data;
if (!pp)
return;
c = &pp->hw;
+ data = SDE_REG_READ(c, PP_DCE_DATA_OUT_SWAP);
+ data &= ~BIT(18); /* disable endian flip */
+ SDE_REG_WRITE(c, PP_DCE_DATA_OUT_SWAP, data);
+
SDE_REG_WRITE(c, PP_DSC_MODE, 0);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 40dad76..a121b2e 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1469,6 +1469,12 @@
if (psde->pipe_hw->ops.setup_pe)
psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
&pstate->pixel_ext);
+
+ if (psde->pipe_hw->ops.setup_scaler &&
+ pstate->multirect_index != SDE_SSPP_RECT_1)
+ psde->pipe_hw->ops.setup_scaler(psde->pipe_hw,
+ &psde->pipe_cfg, &pstate->pixel_ext,
+ &pstate->scaler3_cfg);
}
return 0;
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 7e58c2f..768dfbd 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -3067,9 +3067,7 @@
memset(&dbg->dbgbus_sde, 0, sizeof(dbg->dbgbus_sde));
memset(&dbg->dbgbus_vbif_rt, 0, sizeof(dbg->dbgbus_vbif_rt));
- switch (hwversion) {
- case SDE_HW_VER_300:
- case SDE_HW_VER_301:
+ if (IS_MSM8998_TARGET(hwversion)) {
dbg->dbgbus_sde.entries = dbg_bus_sde_8998;
dbg->dbgbus_sde.cmn.entries_size = ARRAY_SIZE(dbg_bus_sde_8998);
dbg->dbgbus_sde.cmn.flags = DBGBUS_FLAGS_DSPP;
@@ -3077,9 +3075,7 @@
dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
dbg->dbgbus_vbif_rt.cmn.entries_size =
ARRAY_SIZE(vbif_dbg_bus_msm8998);
- break;
-
- case SDE_HW_VER_400:
+ } else if (IS_SDM845_TARGET(hwversion)) {
dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845;
dbg->dbgbus_sde.cmn.entries_size =
ARRAY_SIZE(dbg_bus_sde_sdm845);
@@ -3089,10 +3085,8 @@
dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
dbg->dbgbus_vbif_rt.cmn.entries_size =
ARRAY_SIZE(vbif_dbg_bus_msm8998);
- break;
- default:
- pr_err("unsupported chipset id %u\n", hwversion);
- break;
+ } else {
+ pr_err("unsupported chipset id %X\n", hwversion);
}
}
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 12824b0..b9df4ec 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1943,9 +1943,7 @@
/* If SPTP_RAC is on, turn off SPTP_RAC HS */
a6xx_sptprac_disable(adreno_dev);
- /* Disconnect GPU from BUS. Clear and reconnected after reset */
- adreno_vbif_clear_pending_transactions(device);
- /* Unnecessary: a6xx_soft_reset(adreno_dev); */
+ /* Disconnect GPU from BUS is not needed if CX GDSC goes off later */
/* Check no outstanding RPMh voting */
a6xx_complete_rpmh_votes(device);
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 0840aba..f608927 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -837,7 +837,8 @@
snapshot_frozen_objsize = 0;
- setup_fault_process(device, snapshot,
+ if (!IS_ERR(context))
+ setup_fault_process(device, snapshot,
context ? context->proc_priv : NULL);
/* Add GPU specific sections - registers mainly, but other stuff too */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 9968d8c..7dff251 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -3471,7 +3471,7 @@
struct sparse_bind_object *new;
struct rb_node **node, *parent = NULL;
- new = kzalloc(sizeof(*new), GFP_KERNEL);
+ new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL)
return -ENOMEM;
@@ -3505,7 +3505,6 @@
struct sparse_bind_object *obj,
uint64_t v_offset, uint64_t size)
{
- spin_lock(&entry->bind_lock);
if (v_offset == obj->v_off && size >= obj->size) {
/*
* We are all encompassing, remove the entry and free
@@ -3538,7 +3537,6 @@
obj->size = v_offset - obj->v_off;
- spin_unlock(&entry->bind_lock);
ret = _sparse_add_to_bind_tree(entry, v_offset + size,
obj->p_memdesc,
obj->p_off + (v_offset - obj->v_off) + size,
@@ -3548,11 +3546,10 @@
return ret;
}
- spin_unlock(&entry->bind_lock);
-
return 0;
}
+/* entry->bind_lock must be held by the caller */
static struct sparse_bind_object *_find_containing_bind_obj(
struct kgsl_mem_entry *entry,
uint64_t offset, uint64_t size)
@@ -3560,8 +3557,6 @@
struct sparse_bind_object *obj = NULL;
struct rb_node *node = entry->bind_tree.rb_node;
- spin_lock(&entry->bind_lock);
-
while (node != NULL) {
obj = rb_entry(node, struct sparse_bind_object, node);
@@ -3580,33 +3575,16 @@
}
}
- spin_unlock(&entry->bind_lock);
-
return obj;
}
+/* entry->bind_lock must be held by the caller */
static int _sparse_unbind(struct kgsl_mem_entry *entry,
struct sparse_bind_object *bind_obj,
uint64_t offset, uint64_t size)
{
- struct kgsl_memdesc *memdesc = bind_obj->p_memdesc;
- struct kgsl_pagetable *pt = memdesc->pagetable;
int ret;
- if (memdesc->cur_bindings < (size / PAGE_SIZE))
- return -EINVAL;
-
- memdesc->cur_bindings -= size / PAGE_SIZE;
-
- ret = kgsl_mmu_unmap_offset(pt, memdesc,
- entry->memdesc.gpuaddr, offset, size);
- if (ret)
- return ret;
-
- ret = kgsl_mmu_sparse_dummy_map(pt, &entry->memdesc, offset, size);
- if (ret)
- return ret;
-
ret = _sparse_rm_from_bind_tree(entry, bind_obj, offset, size);
if (ret == 0) {
atomic_long_sub(size, &kgsl_driver.stats.mapped);
@@ -3620,6 +3598,8 @@
struct kgsl_mem_entry *virt_entry)
{
struct sparse_bind_object *bind_obj;
+ struct kgsl_memdesc *memdesc;
+ struct kgsl_pagetable *pt;
int ret = 0;
uint64_t size = obj->size;
uint64_t tmp_size = obj->size;
@@ -3627,9 +3607,14 @@
while (size > 0 && ret == 0) {
tmp_size = size;
+
+ spin_lock(&virt_entry->bind_lock);
bind_obj = _find_containing_bind_obj(virt_entry, offset, size);
- if (bind_obj == NULL)
+
+ if (bind_obj == NULL) {
+ spin_unlock(&virt_entry->bind_lock);
return 0;
+ }
if (bind_obj->v_off > offset) {
tmp_size = size - bind_obj->v_off - offset;
@@ -3646,7 +3631,28 @@
tmp_size = bind_obj->size;
}
+ memdesc = bind_obj->p_memdesc;
+ pt = memdesc->pagetable;
+
+ if (memdesc->cur_bindings < (tmp_size / PAGE_SIZE)) {
+ spin_unlock(&virt_entry->bind_lock);
+ return -EINVAL;
+ }
+
+ memdesc->cur_bindings -= tmp_size / PAGE_SIZE;
+
ret = _sparse_unbind(virt_entry, bind_obj, offset, tmp_size);
+ spin_unlock(&virt_entry->bind_lock);
+
+ ret = kgsl_mmu_unmap_offset(pt, memdesc,
+ virt_entry->memdesc.gpuaddr, offset, tmp_size);
+ if (ret)
+ return ret;
+
+ ret = kgsl_mmu_sparse_dummy_map(pt, memdesc, offset, tmp_size);
+ if (ret)
+ return ret;
+
if (ret == 0) {
offset += tmp_size;
size -= tmp_size;
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 2ddb082..f21a179 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -456,11 +456,12 @@
GMU_DCVS_NOHFI, perf_idx, bw_idx);
if (ret) {
- dev_err(&gmu->pdev->dev,
+ dev_err_ratelimited(&gmu->pdev->dev,
"Failed to set GPU perf idx %d, bw idx %d\n",
perf_idx, bw_idx);
- gmu_snapshot(device);
+ adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT);
+ adreno_dispatcher_schedule(device);
}
return ret;
@@ -1341,6 +1342,7 @@
gmu_disable_clks(gmu);
gmu_disable_gdsc(gmu);
+ dev_err(&gmu->pdev->dev, "Suspended GMU\n");
return 0;
}
@@ -1349,7 +1351,7 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = &device->gmu;
- if (!test_and_set_bit(GMU_FAULT, &gmu->flags)) {
+ if (!gmu->fault_count) {
/* Mask so there's no interrupt caused by NMI */
adreno_write_gmureg(adreno_dev,
ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
@@ -1364,7 +1366,7 @@
/* Wait for the NMI to be handled */
wmb();
udelay(100);
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, ERR_PTR(-EINVAL));
adreno_write_gmureg(adreno_dev,
ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
@@ -1372,6 +1374,8 @@
ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
(unsigned int) ~HFI_IRQ_MASK);
}
+
+ gmu->fault_count++;
}
/* To be called to power on both GPU and GMU */
@@ -1389,32 +1393,29 @@
WARN_ON(test_bit(GMU_CLK_ON, &gmu->flags));
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
+ gmu_irq_enable(device);
/* Vote for 300MHz DDR for GMU to init */
ret = msm_bus_scale_client_update_request(gmu->pcl,
pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
- if (ret) {
+ if (ret)
dev_err(&gmu->pdev->dev,
- "Failed to allocate gmu b/w\n");
- goto error_clks;
- }
+ "Failed to allocate gmu b/w: %d\n", ret);
ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START,
GMU_COLD_BOOT, 0);
if (ret)
- goto error_bus;
-
- gmu_irq_enable(device);
+ goto error_gmu;
ret = hfi_start(gmu, GMU_COLD_BOOT);
if (ret)
- goto error_gpu;
+ goto error_gmu;
/* Send default DCVS level */
ret = gmu_dcvs_set(gmu, pwr->default_pwrlevel,
pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
if (ret)
- goto error_gpu;
+ goto error_gmu;
msm_bus_scale_client_update_request(gmu->pcl, 0);
break;
@@ -1423,49 +1424,49 @@
WARN_ON(test_bit(GMU_CLK_ON, &gmu->flags));
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
+ gmu_irq_enable(device);
ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START,
GMU_WARM_BOOT, 0);
if (ret)
- goto error_clks;
-
- gmu_irq_enable(device);
+ goto error_gmu;
ret = hfi_start(gmu, GMU_WARM_BOOT);
if (ret)
- goto error_gpu;
+ goto error_gmu;
ret = gmu_dcvs_set(gmu, gmu->wakeup_pwrlevel,
pwr->pwrlevels[gmu->wakeup_pwrlevel].bus_freq);
if (ret)
- goto error_gpu;
+ goto error_gmu;
gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
break;
case KGSL_STATE_RESET:
- if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv)) {
+ if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv) ||
+ test_bit(GMU_FAULT, &gmu->flags)) {
gmu_suspend(device);
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
+ gmu_irq_enable(device);
ret = gpudev->rpmh_gpu_pwrctrl(
adreno_dev, GMU_FW_START, GMU_RESET, 0);
if (ret)
- goto error_clks;
+ goto error_gmu;
- gmu_irq_enable(device);
ret = hfi_start(gmu, GMU_COLD_BOOT);
if (ret)
- goto error_gpu;
+ goto error_gmu;
/* Send DCVS level prior to reset*/
ret = gmu_dcvs_set(gmu, pwr->active_pwrlevel,
pwr->pwrlevels[pwr->active_pwrlevel]
.bus_freq);
if (ret)
- goto error_gpu;
+ goto error_gmu;
ret = gpudev->oob_set(adreno_dev,
OOB_CPINIT_SET_MASK,
@@ -1485,20 +1486,8 @@
return ret;
-error_gpu:
+error_gmu:
gmu_snapshot(device);
- hfi_stop(gmu);
- gmu_irq_disable(device);
- if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
- gpudev->oob_clear(adreno_dev,
- OOB_BOOT_SLUMBER_CLEAR_MASK);
- gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
-error_bus:
- msm_bus_scale_client_update_request(gmu->pcl, 0);
-error_clks:
- gmu_snapshot(device);
- gmu_disable_clks(gmu);
- gmu_disable_gdsc(gmu);
return ret;
}
@@ -1535,18 +1524,30 @@
if (!idle || (gpudev->wait_for_gmu_idle &&
gpudev->wait_for_gmu_idle(adreno_dev))) {
dev_err(&gmu->pdev->dev, "Stopping GMU before it is idle\n");
+ idle = false;
+ set_bit(GMU_FAULT, &gmu->flags);
+ } else {
+ idle = true;
}
- /* Pending message in all queues are abandoned */
- hfi_stop(gmu);
- clear_bit(GMU_HFI_ON, &gmu->flags);
- gmu_irq_disable(device);
+ if (idle) {
+ /* Pending message in all queues are abandoned */
+ hfi_stop(gmu);
+ clear_bit(GMU_HFI_ON, &gmu->flags);
+ gmu_irq_disable(device);
- gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
- gmu_disable_clks(gmu);
- gmu_disable_gdsc(gmu);
-
- /* TODO: Vote CX, MX retention off */
+ gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
+ gmu_disable_clks(gmu);
+ gmu_disable_gdsc(gmu);
+ } else {
+ /*
+ * The power controller will change state to SLUMBER anyway
+ * Set GMU_FAULT flag to indicate to power contrller
+ * that hang recovery is needed to power on GPU
+ */
+ set_bit(GMU_FAULT, &gmu->flags);
+ gmu_snapshot(device);
+ }
msm_bus_scale_client_update_request(gmu->pcl, 0);
}
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index 63ca028..ff65f66 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -193,6 +193,7 @@
* @pcl: GPU BW scaling client
* @ccl: CNOC BW scaling client
* @idle_level: Minimal GPU idle power level
+ * @fault_count: GMU fault count
*/
struct gmu_device {
unsigned int ver;
@@ -226,6 +227,7 @@
unsigned int pcl;
unsigned int ccl;
unsigned int idle_level;
+ unsigned int fault_count;
};
bool kgsl_gmu_isenabled(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 6e55395..007121c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2629,6 +2629,7 @@
_aware(struct kgsl_device *device)
{
int status = 0;
+ struct gmu_device *gmu = &device->gmu;
switch (device->state) {
case KGSL_STATE_RESET:
@@ -2648,15 +2649,42 @@
kgsl_pwrscale_midframe_timer_cancel(device);
break;
case KGSL_STATE_SLUMBER:
+ /* if GMU already in FAULT */
+ if (kgsl_gmu_isenabled(device) &&
+ test_bit(GMU_FAULT, &gmu->flags)) {
+ status = -EINVAL;
+ break;
+ }
+
status = kgsl_pwrctrl_enable(device);
break;
default:
status = -EINVAL;
}
- if (status)
+
+ if (status) {
+ if (kgsl_gmu_isenabled(device)) {
+ /* GMU hang recovery */
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_RESET);
+ set_bit(GMU_FAULT, &gmu->flags);
+ status = kgsl_pwrctrl_enable(device);
+ if (status) {
+ /*
+ * Cannot recover GMU failure
+ * GPU will not be powered on
+ */
+ WARN_ONCE(1, "Failed to recover GMU\n");
+ }
+
+ clear_bit(GMU_FAULT, &gmu->flags);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
+ return status;
+ }
+
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
- else
+ } else {
kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
+ }
return status;
}
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 7cbda72..e704db7 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -182,7 +182,8 @@
context = kgsl_context_get(device, header->current_context);
/* Get the current PT base */
- header->ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
+ if (!IS_ERR(priv))
+ header->ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
/* And the PID for the task leader */
if (context) {
@@ -633,8 +634,10 @@
snapshot->size += sizeof(*header);
/* Build the Linux specific header */
+ /* Context err is implied a GMU fault, so limit dump */
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
- snapshot, snapshot_os, NULL);
+ snapshot, snapshot_os,
+ IS_ERR(context) ? context : NULL);
/* Get the device specific sections */
if (device->ftbl->snapshot)
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index e23001b..5c88ba7 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -56,13 +56,13 @@
static struct rb_node *
__get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
{
- if ((*limit_pfn != iovad->dma_32bit_pfn) ||
+ if ((*limit_pfn > iovad->dma_32bit_pfn) ||
(iovad->cached32_node == NULL))
return rb_last(&iovad->rbroot);
else {
struct rb_node *prev_node = rb_prev(iovad->cached32_node);
struct iova *curr_iova =
- container_of(iovad->cached32_node, struct iova, node);
+ rb_entry(iovad->cached32_node, struct iova, node);
*limit_pfn = curr_iova->pfn_lo - 1;
return prev_node;
}
@@ -86,11 +86,11 @@
if (!iovad->cached32_node)
return;
curr = iovad->cached32_node;
- cached_iova = container_of(curr, struct iova, node);
+ cached_iova = rb_entry(curr, struct iova, node);
if (free->pfn_lo >= cached_iova->pfn_lo) {
struct rb_node *node = rb_next(&free->node);
- struct iova *iova = container_of(node, struct iova, node);
+ struct iova *iova = rb_entry(node, struct iova, node);
/* only cache if it's below 32bit pfn */
if (node && iova->pfn_lo < iovad->dma_32bit_pfn)
@@ -100,6 +100,34 @@
}
}
+/* Insert the iova into domain rbtree by holding writer lock */
+static void
+iova_insert_rbtree(struct rb_root *root, struct iova *iova,
+ struct rb_node *start)
+{
+ struct rb_node **new, *parent = NULL;
+
+ new = (start) ? &start : &(root->rb_node);
+ /* Figure out where to put new node */
+ while (*new) {
+ struct iova *this = rb_entry(*new, struct iova, node);
+
+ parent = *new;
+
+ if (iova->pfn_lo < this->pfn_lo)
+ new = &((*new)->rb_left);
+ else if (iova->pfn_lo > this->pfn_lo)
+ new = &((*new)->rb_right);
+ else {
+ WARN_ON(1); /* this should not happen */
+ return;
+ }
+ }
+ /* Add new node and rebalance tree. */
+ rb_link_node(&iova->node, parent, new);
+ rb_insert_color(&iova->node, root);
+}
+
/*
* Computes the padding size required, to make the start address
* naturally aligned on the power-of-two order of its size
@@ -125,7 +153,7 @@
curr = __get_cached_rbnode(iovad, &limit_pfn);
prev = curr;
while (curr) {
- struct iova *curr_iova = container_of(curr, struct iova, node);
+ struct iova *curr_iova = rb_entry(curr, struct iova, node);
if (limit_pfn < curr_iova->pfn_lo)
goto move_left;
@@ -138,7 +166,7 @@
break; /* found a free slot */
}
adjust_limit_pfn:
- limit_pfn = curr_iova->pfn_lo - 1;
+ limit_pfn = curr_iova->pfn_lo ? (curr_iova->pfn_lo - 1) : 0;
move_left:
prev = curr;
curr = rb_prev(curr);
@@ -157,36 +185,8 @@
new->pfn_lo = limit_pfn - (size + pad_size) + 1;
new->pfn_hi = new->pfn_lo + size - 1;
- /* Insert the new_iova into domain rbtree by holding writer lock */
- /* Add new node and rebalance tree. */
- {
- struct rb_node **entry, *parent = NULL;
-
- /* If we have 'prev', it's a valid place to start the
- insertion. Otherwise, start from the root. */
- if (prev)
- entry = &prev;
- else
- entry = &iovad->rbroot.rb_node;
-
- /* Figure out where to put new node */
- while (*entry) {
- struct iova *this = container_of(*entry,
- struct iova, node);
- parent = *entry;
-
- if (new->pfn_lo < this->pfn_lo)
- entry = &((*entry)->rb_left);
- else if (new->pfn_lo > this->pfn_lo)
- entry = &((*entry)->rb_right);
- else
- BUG(); /* this should not happen */
- }
-
- /* Add new node and rebalance tree. */
- rb_link_node(&new->node, parent, entry);
- rb_insert_color(&new->node, &iovad->rbroot);
- }
+ /* If we have 'prev', it's a valid place to start the insertion. */
+ iova_insert_rbtree(&iovad->rbroot, new, prev);
__cached_rbnode_insert_update(iovad, saved_pfn, new);
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
@@ -195,28 +195,6 @@
return 0;
}
-static void
-iova_insert_rbtree(struct rb_root *root, struct iova *iova)
-{
- struct rb_node **new = &(root->rb_node), *parent = NULL;
- /* Figure out where to put new node */
- while (*new) {
- struct iova *this = container_of(*new, struct iova, node);
-
- parent = *new;
-
- if (iova->pfn_lo < this->pfn_lo)
- new = &((*new)->rb_left);
- else if (iova->pfn_lo > this->pfn_lo)
- new = &((*new)->rb_right);
- else
- BUG(); /* this should not happen */
- }
- /* Add new node and rebalance tree. */
- rb_link_node(&iova->node, parent, new);
- rb_insert_color(&iova->node, root);
-}
-
static struct kmem_cache *iova_cache;
static unsigned int iova_cache_users;
static DEFINE_MUTEX(iova_cache_mutex);
@@ -311,7 +289,7 @@
assert_spin_locked(&iovad->iova_rbtree_lock);
while (node) {
- struct iova *iova = container_of(node, struct iova, node);
+ struct iova *iova = rb_entry(node, struct iova, node);
/* If pfn falls within iova's range, return iova */
if ((pfn >= iova->pfn_lo) && (pfn <= iova->pfn_hi)) {
@@ -463,7 +441,7 @@
spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
node = rb_first(&iovad->rbroot);
while (node) {
- struct iova *iova = container_of(node, struct iova, node);
+ struct iova *iova = rb_entry(node, struct iova, node);
rb_erase(node, &iovad->rbroot);
free_iova_mem(iova);
@@ -477,7 +455,7 @@
__is_range_overlap(struct rb_node *node,
unsigned long pfn_lo, unsigned long pfn_hi)
{
- struct iova *iova = container_of(node, struct iova, node);
+ struct iova *iova = rb_entry(node, struct iova, node);
if ((pfn_lo <= iova->pfn_hi) && (pfn_hi >= iova->pfn_lo))
return 1;
@@ -506,7 +484,7 @@
iova = alloc_and_init_iova(pfn_lo, pfn_hi);
if (iova)
- iova_insert_rbtree(&iovad->rbroot, iova);
+ iova_insert_rbtree(&iovad->rbroot, iova, NULL);
return iova;
}
@@ -541,7 +519,7 @@
spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) {
if (__is_range_overlap(node, pfn_lo, pfn_hi)) {
- iova = container_of(node, struct iova, node);
+ iova = rb_entry(node, struct iova, node);
__adjust_overlap_range(iova, &pfn_lo, &pfn_hi);
if ((pfn_lo >= iova->pfn_lo) &&
(pfn_hi <= iova->pfn_hi))
@@ -578,7 +556,7 @@
spin_lock_irqsave(&from->iova_rbtree_lock, flags);
for (node = rb_first(&from->rbroot); node; node = rb_next(node)) {
- struct iova *iova = container_of(node, struct iova, node);
+ struct iova *iova = rb_entry(node, struct iova, node);
struct iova *new_iova;
new_iova = reserve_iova(to, iova->pfn_lo, iova->pfn_hi);
@@ -613,11 +591,11 @@
rb_erase(&iova->node, &iovad->rbroot);
if (prev) {
- iova_insert_rbtree(&iovad->rbroot, prev);
+ iova_insert_rbtree(&iovad->rbroot, prev, NULL);
iova->pfn_lo = pfn_lo;
}
if (next) {
- iova_insert_rbtree(&iovad->rbroot, next);
+ iova_insert_rbtree(&iovad->rbroot, next, NULL);
iova->pfn_hi = pfn_hi;
}
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index 568c9f9..5c9c75c 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -123,6 +123,7 @@
#define QPNP_WLED_ILIM_FAULT_BIT BIT(0)
#define QPNP_WLED_OVP_FAULT_BIT BIT(1)
#define QPNP_WLED_SC_FAULT_BIT BIT(2)
+#define QPNP_WLED_OVP_FLT_RT_STS_BIT BIT(1)
/* sink registers */
#define QPNP_WLED_CURR_SINK_REG(b) (b + 0x46)
@@ -1103,14 +1104,6 @@
int rc = 0, i;
u8 reg = 0, sink_config = 0, sink_test = 0, sink_valid = 0, int_sts;
- mutex_lock(&wled->lock);
-
- /* disable OVP IRQ */
- if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
- disable_irq_nosync(wled->ovp_irq);
- wled->ovp_irq_disabled = true;
- }
-
/* read configured sink configuration */
rc = qpnp_wled_read_reg(wled,
QPNP_WLED_CURR_SINK_REG(wled->sink_base), &sink_config);
@@ -1259,7 +1252,8 @@
}
/* restore brightness */
- rc = qpnp_wled_set_level(wled, wled->cdev.brightness);
+ rc = qpnp_wled_set_level(wled, !wled->cdev.brightness ?
+ AUTO_CALIB_BRIGHTNESS : wled->cdev.brightness);
if (rc < 0) {
pr_err("Failed to set brightness after calibration rc=%d\n",
rc);
@@ -1280,11 +1274,6 @@
QPNP_WLED_SOFT_START_DLY_US + 1000);
failed_calib:
- if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
- enable_irq(wled->ovp_irq);
- wled->ovp_irq_disabled = false;
- }
- mutex_unlock(&wled->lock);
return rc;
}
@@ -1320,6 +1309,38 @@
return false;
}
+static int qpnp_wled_auto_calibrate_at_init(struct qpnp_wled *wled)
+{
+ int rc;
+ u8 fault_status = 0, rt_status = 0;
+
+ if (!wled->auto_calib_enabled)
+ return 0;
+
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_INT_RT_STS(wled->ctrl_base), &rt_status);
+ if (rc < 0)
+ pr_err("Failed to read RT status rc=%d\n", rc);
+
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &fault_status);
+ if (rc < 0)
+ pr_err("Failed to read fault status rc=%d\n", rc);
+
+ if ((rt_status & QPNP_WLED_OVP_FLT_RT_STS_BIT) ||
+ (fault_status & QPNP_WLED_OVP_FAULT_BIT)) {
+ mutex_lock(&wled->lock);
+ rc = wled_auto_calibrate(wled);
+ if (rc < 0)
+ pr_err("Failed auto-calibration rc=%d\n", rc);
+ else
+ wled->auto_calib_done = true;
+ mutex_unlock(&wled->lock);
+ }
+
+ return rc;
+}
+
/* ovp irq handler */
static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled)
{
@@ -1348,13 +1369,26 @@
if (fault_sts & QPNP_WLED_OVP_FAULT_BIT) {
if (wled->auto_calib_enabled && !wled->auto_calib_done) {
if (qpnp_wled_auto_cal_required(wled)) {
- rc = wled_auto_calibrate(wled);
- if (rc < 0) {
- pr_err("Failed auto-calibration rc=%d\n",
- rc);
- return IRQ_HANDLED;
+ mutex_lock(&wled->lock);
+ if (wled->ovp_irq > 0 &&
+ !wled->ovp_irq_disabled) {
+ disable_irq_nosync(wled->ovp_irq);
+ wled->ovp_irq_disabled = true;
}
- wled->auto_calib_done = true;
+
+ rc = wled_auto_calibrate(wled);
+ if (rc < 0)
+ pr_err("Failed auto-calibration rc=%d\n",
+ rc);
+ else
+ wled->auto_calib_done = true;
+
+ if (wled->ovp_irq > 0 &&
+ wled->ovp_irq_disabled) {
+ enable_irq(wled->ovp_irq);
+ wled->ovp_irq_disabled = false;
+ }
+ mutex_unlock(&wled->lock);
}
}
}
@@ -1946,6 +1980,10 @@
return rc;
}
+ rc = qpnp_wled_auto_calibrate_at_init(wled);
+ if (rc < 0)
+ pr_err("Failed to auto-calibrate at init rc=%d\n", rc);
+
/* setup ovp and sc irqs */
if (wled->ovp_irq >= 0) {
rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq,
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index ecb77cc..9f340bf 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -296,8 +296,9 @@
EXPORT_SYMBOL_GPL(mbox_send_message);
/**
- * mbox_send_controller_data- For client to submit a message to be
- * sent only to the controller.
+ * mbox_write_controller_data - For client to submit a message to be
+ * written to the controller but not sent to
+ * the remote processor.
* @chan: Mailbox channel assigned to this client.
* @mssg: Client specific message typecasted.
*
@@ -308,7 +309,7 @@
* or transmission over chan (blocking mode).
* Negative value denotes failure.
*/
-int mbox_send_controller_data(struct mbox_chan *chan, void *mssg)
+int mbox_write_controller_data(struct mbox_chan *chan, void *mssg)
{
unsigned long flags;
int err;
@@ -317,12 +318,12 @@
return -EINVAL;
spin_lock_irqsave(&chan->lock, flags);
- err = chan->mbox->ops->send_controller_data(chan, mssg);
+ err = chan->mbox->ops->write_controller_data(chan, mssg);
spin_unlock_irqrestore(&chan->lock, flags);
return err;
}
-EXPORT_SYMBOL(mbox_send_controller_data);
+EXPORT_SYMBOL(mbox_write_controller_data);
bool mbox_controller_is_idle(struct mbox_chan *chan)
{
diff --git a/drivers/mailbox/qcom-rpmh-mailbox.c b/drivers/mailbox/qcom-rpmh-mailbox.c
index a69fe85..7bf8a18 100644
--- a/drivers/mailbox/qcom-rpmh-mailbox.c
+++ b/drivers/mailbox/qcom-rpmh-mailbox.c
@@ -1075,7 +1075,7 @@
static const struct mbox_chan_ops mbox_ops = {
.send_data = chan_tcs_write,
- .send_controller_data = chan_tcs_ctrl_write,
+ .write_controller_data = chan_tcs_ctrl_write,
.startup = chan_init,
.shutdown = chan_shutdown,
};
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 2f2a439..1a9e84d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1081,8 +1081,10 @@
int i;
if (ctx->rot->mode == ROT_REGDMA_ON) {
- SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_EN,
- REGDMA_INT_MASK);
+ if (rot->irq_num >= 0)
+ SDE_ROTREG_WRITE(rot->mdss_base,
+ REGDMA_CSR_REGDMA_INT_EN,
+ REGDMA_INT_MASK);
SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_OP_MODE,
REGDMA_EN);
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 56e7a99..cb03576 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -581,6 +581,13 @@
inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto err_invalid_fmt;
+ }
+
msm_comm_set_color_format(inst,
msm_comm_get_hal_output_buffer(inst),
f->fmt.pix_mp.pixelformat);
@@ -648,6 +655,12 @@
}
inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto err_invalid_fmt;
+ }
frame_sz.buffer_type = HAL_BUFFER_INPUT;
frame_sz.width = inst->prop.width[OUTPUT_PORT];
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index dfb2ad5..0d8cb76 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2385,6 +2385,12 @@
inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
frame_sz.width = inst->prop.width[CAPTURE_PORT];
@@ -2443,6 +2449,12 @@
inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
frame_sz.buffer_type = HAL_BUFFER_INPUT;
frame_sz.width = inst->prop.width[OUTPUT_PORT];
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 6a7588c..5149086 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -883,6 +883,13 @@
goto fail_start;
}
+ rc = msm_vidc_check_scaling_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "This session scaling is not supported %pK\n", inst);
+ goto fail_start;
+ }
+
/* Decide work mode for current session */
rc = msm_vidc_decide_work_mode(inst);
if (rc) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 428bf71..6e29c53 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2161,6 +2161,7 @@
"Got SYS_ERR but unable to identify core\n");
return;
}
+ hdev = core->device;
mutex_lock(&core->lock);
if (core->state == VIDC_CORE_UNINIT) {
@@ -2181,7 +2182,6 @@
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
msm_comm_print_inst_info(inst);
}
- hdev = core->device;
dprintk(VIDC_DBG, "Calling core_release\n");
rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
if (rc) {
@@ -3011,6 +3011,23 @@
return msm_vidc_deinit_core(inst);
}
+static int msm_comm_session_init_done(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc;
+
+ dprintk(VIDC_DBG, "inst %pK: waiting for session init done\n", inst);
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+ HAL_SESSION_INIT_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Session init failed for inst %pK\n", inst);
+ msm_comm_generate_sys_error(inst);
+ return rc;
+ }
+
+ return rc;
+}
+
static int msm_comm_session_init(int flipped_state,
struct msm_vidc_inst *inst)
{
@@ -3693,8 +3710,7 @@
if (rc || state <= get_flipped_state(inst->state, state))
break;
case MSM_VIDC_OPEN_DONE:
- rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
- HAL_SESSION_INIT_DONE);
+ rc = msm_comm_session_init_done(flipped_state, inst);
if (rc || state <= get_flipped_state(inst->state, state))
break;
case MSM_VIDC_LOAD_RESOURCES:
@@ -5472,10 +5488,6 @@
capability->width.max, capability->height.max);
rc = -ENOTSUPP;
}
-
- if (!rc && msm_vidc_check_scaling_supported(inst)) {
- rc = -ENOTSUPP;
- }
}
if (rc) {
dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index c94da61..dde6029 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1047,9 +1047,9 @@
mutex_lock(&device->lock);
- if (device->power_enabled) {
- dprintk(VIDC_DBG, "Venus is busy\n");
- rc = -EBUSY;
+ if (!device->power_enabled) {
+ dprintk(VIDC_WARN, "%s: venus power off\n", __func__);
+ rc = -EINVAL;
goto exit;
}
__flush_debug_queue(device, NULL);
diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c
index baa4f94..ea4bedf 100644
--- a/drivers/nfc/nq-nci.c
+++ b/drivers/nfc/nq-nci.c
@@ -354,6 +354,7 @@
usleep_range(1000, 1100);
}
gpio_set_value(nqx_dev->ese_gpio, 1);
+ usleep_range(1000, 1100);
if (gpio_get_value(nqx_dev->ese_gpio)) {
dev_dbg(&nqx_dev->client->dev, "ese_gpio is enabled\n");
r = 0;
@@ -406,6 +407,7 @@
* there's no need to send the i2c commands
*/
gpio_set_value(nqx_dev->ese_gpio, 0);
+ usleep_range(1000, 1100);
}
if (!gpio_get_value(nqx_dev->ese_gpio)) {
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index f06fb1f..2ecbd22 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -471,6 +471,7 @@
pad = pctldev->desc->pins[pin].drv_data;
+ pad->is_enabled = true;
for (i = 0; i < nconfs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
@@ -619,6 +620,10 @@
return ret;
}
+ val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
+
+ ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
+
return ret;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index bfd0446..70d74f0 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -531,7 +531,7 @@
kfree(buff);
}
-static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type)
+static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache)
{
int retval;
struct ipa_wan_msg *wan_msg;
@@ -559,6 +559,25 @@
return retval;
}
+ if (is_cache) {
+ mutex_lock(&ipa_ctx->ipa_cne_evt_lock);
+
+ /* cache the cne event */
+ memcpy(&ipa_ctx->ipa_cne_evt_req_cache[
+ ipa_ctx->num_ipa_cne_evt_req].wan_msg,
+ wan_msg,
+ sizeof(struct ipa_wan_msg));
+
+ memcpy(&ipa_ctx->ipa_cne_evt_req_cache[
+ ipa_ctx->num_ipa_cne_evt_req].msg_meta,
+ &msg_meta,
+ sizeof(struct ipa_msg_meta));
+
+ ipa_ctx->num_ipa_cne_evt_req++;
+ ipa_ctx->num_ipa_cne_evt_req %= IPA_MAX_NUM_REQ_CACHE;
+ mutex_unlock(&ipa_ctx->ipa_cne_evt_lock);
+ }
+
return 0;
}
@@ -1328,21 +1347,21 @@
}
break;
case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD:
- retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD);
+ retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD, true);
if (retval) {
IPAERR("ipa_send_wan_msg failed: %d\n", retval);
break;
}
break;
case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL:
- retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL);
+ retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL, true);
if (retval) {
IPAERR("ipa_send_wan_msg failed: %d\n", retval);
break;
}
break;
case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED:
- retval = ipa_send_wan_msg(arg, WAN_EMBMS_CONNECT);
+ retval = ipa_send_wan_msg(arg, WAN_EMBMS_CONNECT, false);
if (retval) {
IPAERR("ipa_send_wan_msg failed: %d\n", retval);
break;
@@ -4169,6 +4188,7 @@
mutex_init(&ipa_ctx->lock);
mutex_init(&ipa_ctx->nat_mem.lock);
+ mutex_init(&ipa_ctx->ipa_cne_evt_lock);
idr_init(&ipa_ctx->ipa_idr);
spin_lock_init(&ipa_ctx->idr_lock);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 141bff1..9bfdcdc 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -63,6 +63,9 @@
#define IPA_MAX_STATUS_STAT_NUM 30
+
+#define IPA_MAX_NUM_REQ_CACHE 10
+
#define IPADBG(fmt, args...) \
pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
#define IPAERR(fmt, args...) \
@@ -968,6 +971,11 @@
bool uplink;
};
+struct ipa_cne_evt {
+ struct ipa_wan_msg wan_msg;
+ struct ipa_msg_meta msg_meta;
+};
+
/**
* struct ipa_context - IPA context
* @class: pointer to the struct class
@@ -1164,6 +1172,9 @@
u32 ipa_rx_min_timeout_usec;
u32 ipa_rx_max_timeout_usec;
u32 ipa_polling_iteration;
+ struct ipa_cne_evt ipa_cne_evt_req_cache[IPA_MAX_NUM_REQ_CACHE];
+ int num_ipa_cne_evt_req;
+ struct mutex ipa_cne_evt_lock;
};
/**
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index ede5254..2210ee7 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -540,7 +540,7 @@
kfree(buff);
}
-static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type)
+static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache)
{
int retval;
struct ipa_wan_msg *wan_msg;
@@ -568,6 +568,25 @@
return retval;
}
+ if (is_cache) {
+ mutex_lock(&ipa3_ctx->ipa_cne_evt_lock);
+
+ /* cache the cne event */
+ memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
+ ipa3_ctx->num_ipa_cne_evt_req].wan_msg,
+ wan_msg,
+ sizeof(struct ipa_wan_msg));
+
+ memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
+ ipa3_ctx->num_ipa_cne_evt_req].msg_meta,
+ &msg_meta,
+ sizeof(struct ipa_msg_meta));
+
+ ipa3_ctx->num_ipa_cne_evt_req++;
+ ipa3_ctx->num_ipa_cne_evt_req %= IPA_MAX_NUM_REQ_CACHE;
+ mutex_unlock(&ipa3_ctx->ipa_cne_evt_lock);
+ }
+
return 0;
}
@@ -1524,21 +1543,21 @@
}
break;
case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD:
- retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD);
+ retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD, true);
if (retval) {
IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
break;
}
break;
case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL:
- retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL);
+ retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL, true);
if (retval) {
IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
break;
}
break;
case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED:
- retval = ipa3_send_wan_msg(arg, WAN_EMBMS_CONNECT);
+ retval = ipa3_send_wan_msg(arg, WAN_EMBMS_CONNECT, false);
if (retval) {
IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
break;
@@ -4877,6 +4896,7 @@
mutex_init(&ipa3_ctx->lock);
mutex_init(&ipa3_ctx->nat_mem.lock);
mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
+ mutex_init(&ipa3_ctx->ipa_cne_evt_lock);
idr_init(&ipa3_ctx->ipa_idr);
spin_lock_init(&ipa3_ctx->idr_lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index b891606..4d1baea 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -71,6 +71,8 @@
#define IPA_IPC_LOG_PAGES 50
+#define IPA_MAX_NUM_REQ_CACHE 10
+
#define IPADBG(fmt, args...) \
do { \
pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\
@@ -1088,6 +1090,11 @@
struct ipa_hw_stats_drop drop;
};
+struct ipa_cne_evt {
+ struct ipa_wan_msg wan_msg;
+ struct ipa_msg_meta msg_meta;
+};
+
/**
* struct ipa3_context - IPA context
* @class: pointer to the struct class
@@ -1304,6 +1311,9 @@
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
struct ipa_dma_task_info dma_task_info;
struct ipa_hw_stats hw_stats;
+ struct ipa_cne_evt ipa_cne_evt_req_cache[IPA_MAX_NUM_REQ_CACHE];
+ int num_ipa_cne_evt_req;
+ struct mutex ipa_cne_evt_lock;
};
struct ipa3_plat_drv_res {
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 48e689f..9b5b592 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -3358,6 +3358,10 @@
vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
schedule_delayed_work(&chg->pl_enable_work,
msecs_to_jiffies(PL_DELAY_MS));
+ /* vbus rising when APSD was disabled and PD_ACTIVE = 0 */
+ if (get_effective_result(chg->apsd_disable_votable) &&
+ !chg->pd_active)
+ pr_err("APSD disabled on vbus rising without PD\n");
} else {
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
@@ -3642,6 +3646,37 @@
}
}
+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);
+}
+
#define HVDCP_DET_MS 2500
static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
{
@@ -3664,6 +3699,8 @@
/* if not DCP then no hvdcp timeout happens. Enable pd here */
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
+ if (chg->use_extcon)
+ smblib_notify_device_mode(chg, true);
break;
case OCP_CHARGER_BIT:
case FLOAT_CHARGER_BIT:
@@ -3749,6 +3786,10 @@
*/
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
+ if (chg->use_extcon) {
+ smblib_notify_usb_host(chg, true);
+ chg->otg_present = true;
+ }
}
static void typec_sink_removal(struct smb_charger *chg)
@@ -3899,6 +3940,14 @@
typec_sink_removal(chg);
smblib_update_usb_type(chg);
+
+ if (chg->use_extcon) {
+ if (chg->otg_present)
+ smblib_notify_usb_host(chg, false);
+ else
+ smblib_notify_device_mode(chg, false);
+ }
+ chg->otg_present = false;
}
static void smblib_handle_typec_insertion(struct smb_charger *chg)
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 704a8db..5251b6f 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -144,6 +144,9 @@
EXTCON_NONE,
};
+/* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */
+static const u32 smblib_extcon_exclusive[] = {0x3, 0};
+
struct smb_regulator {
struct regulator_dev *rdev;
struct regulator_desc rdesc;
@@ -331,6 +334,8 @@
int usb_icl_change_irq_enabled;
u32 jeita_status;
u8 float_cfg;
+ bool use_extcon;
+ bool otg_present;
/* workaround flag */
u32 wa_flags;
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 911dd69..e0c92c6 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -170,6 +170,9 @@
chip->dt.suspend_input = of_property_read_bool(node,
"qcom,suspend-input");
+ chg->use_extcon = of_property_read_bool(node,
+ "qcom,use-extcon");
+
rc = of_property_read_u32(node,
"qcom,fcc-max-ua", &chip->dt.fcc_ua);
if (rc < 0)
@@ -1405,55 +1408,95 @@
rc = smb138x_parse_dt(chip);
if (rc < 0) {
pr_err("Couldn't parse device tree rc=%d\n", rc);
- return rc;
+ goto cleanup;
}
rc = smb138x_init_vbus_regulator(chip);
if (rc < 0) {
pr_err("Couldn't initialize vbus regulator rc=%d\n",
rc);
- return rc;
+ goto cleanup;
}
rc = smb138x_init_vconn_regulator(chip);
if (rc < 0) {
pr_err("Couldn't initialize vconn regulator rc=%d\n",
rc);
- return rc;
+ goto cleanup;
+ }
+
+ if (chg->use_extcon) {
+ /* extcon registration */
+ chg->extcon = devm_extcon_dev_allocate(chg->dev,
+ smblib_extcon_cable);
+ if (IS_ERR(chg->extcon)) {
+ rc = PTR_ERR(chg->extcon);
+ dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
+ rc);
+ goto cleanup;
+ }
+
+ chg->extcon->mutually_exclusive = smblib_extcon_exclusive;
+ rc = devm_extcon_dev_register(chg->dev, chg->extcon);
+ if (rc < 0) {
+ dev_err(chg->dev, "failed to register extcon device rc=%d\n",
+ rc);
+ goto cleanup;
+ }
+
+ /* Support reporting polarity and speed via properties */
+ rc = extcon_set_property_capability(chg->extcon,
+ EXTCON_USB, EXTCON_PROP_USB_TYPEC_POLARITY);
+ rc |= extcon_set_property_capability(chg->extcon,
+ EXTCON_USB, EXTCON_PROP_USB_SS);
+ rc |= extcon_set_property_capability(chg->extcon,
+ EXTCON_USB_HOST,
+ EXTCON_PROP_USB_TYPEC_POLARITY);
+ rc |= extcon_set_property_capability(chg->extcon,
+ EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "failed to configure extcon capabilities\n");
+ goto cleanup;
+ }
}
rc = smb138x_init_usb_psy(chip);
if (rc < 0) {
pr_err("Couldn't initialize usb psy rc=%d\n", rc);
- return rc;
+ goto cleanup;
}
rc = smb138x_init_batt_psy(chip);
if (rc < 0) {
pr_err("Couldn't initialize batt psy rc=%d\n", rc);
- return rc;
+ goto cleanup;
}
rc = smb138x_init_hw(chip);
if (rc < 0) {
pr_err("Couldn't initialize hardware rc=%d\n", rc);
- return rc;
+ goto cleanup;
}
rc = smb138x_determine_initial_status(chip);
if (rc < 0) {
pr_err("Couldn't determine initial status rc=%d\n",
rc);
- return rc;
+ goto cleanup;
}
rc = smb138x_request_interrupts(chip);
if (rc < 0) {
pr_err("Couldn't request interrupts rc=%d\n", rc);
- return rc;
+ goto cleanup;
}
return rc;
+
+cleanup:
+ smblib_deinit(chg);
+ return rc;
}
static int smb138x_slave_probe(struct smb138x *chip)
diff --git a/drivers/soc/qcom/gladiator_erp.c b/drivers/soc/qcom/gladiator_erp.c
index 835d4b0..3b70ca4 100644
--- a/drivers/soc/qcom/gladiator_erp.c
+++ b/drivers/soc/qcom/gladiator_erp.c
@@ -163,6 +163,7 @@
DISCONNECT_ERROR,
DIRECTORY_ERROR,
PARITY_ERROR,
+ PHYSICAL_ADDRESS_ERROR,
};
static void clear_gladiator_error(void __iomem *gladiator_virt_base,
@@ -200,12 +201,14 @@
static inline void print_gld_errtype(unsigned int errtype)
{
+ char *errors = "Disconnect, Directory, Parity, Physical address";
+
if (errtype == 0)
pr_alert("Error type: Snoop data transfer\n");
else if (errtype == 1)
pr_alert("Error type: DVM error\n");
else if (errtype == 3)
- pr_alert("Error type: Disconnect, directory, or parity error\n");
+ pr_alert("Error type: %s\n", errors);
else
pr_alert("Error type: Unknown; value:%u\n", errtype);
}
@@ -288,7 +291,7 @@
log_err_type = (err_reg5 & mask_shifts->gld_errlog5_error_type_mask)
>> mask_shifts->gld_errlog5_error_type_shift;
- for (i = 0 ; i <= 6 ; i++) {
+ for (i = 0 ; i <= 7 ; i++) {
value = log_err_type & 0x1;
switch (i) {
case DATA_TRANSFER_ERROR:
@@ -337,7 +340,14 @@
mask_shifts);
decode_index_parity(err_reg5, mask_shifts);
break;
+ case PHYSICAL_ADDRESS_ERROR:
+ if (value == 0)
+ continue;
+ pr_alert("Error type: Physical address error\n");
+ pr_alert("Address is greater than SoC address range\n");
+ break;
}
+
log_err_type = log_err_type >> 1;
}
}
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index ea01076..707d9e7 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -563,9 +563,6 @@
return ret;
list_for_each_entry_safe(node, node_tmp, clist, link) {
- if (unlikely(node->node_info->defer_qos))
- msm_bus_dev_init_qos(&node->dev, NULL);
-
bcm_clist_add(node);
}
@@ -668,6 +665,12 @@
kfree(cmdlist_active);
kfree(n_active);
+
+ list_for_each_entry_safe(node, node_tmp, clist, link) {
+ if (unlikely(node->node_info->defer_qos))
+ msm_bus_dev_init_qos(&node->dev, NULL);
+ }
+
exit_msm_bus_commit_data:
list_for_each_entry_safe(node, node_tmp, clist, link) {
bcm_clist_clean(node);
@@ -962,6 +965,12 @@
MSM_BUS_DBG("Device = %d", node_dev->node_info->id);
+ if (node_dev->node_info->qos_params.defer_init_qos) {
+ node_dev->node_info->qos_params.defer_init_qos = false;
+ node_dev->node_info->defer_qos = true;
+ goto exit_init_qos;
+ }
+
if (node_dev->ap_owned) {
struct msm_bus_node_device_type *bus_node_info;
@@ -1290,6 +1299,8 @@
pdata_node_info->qos_params.reg_mode.write;
node_info->qos_params.urg_fwd_en =
pdata_node_info->qos_params.urg_fwd_en;
+ node_info->qos_params.defer_init_qos =
+ pdata_node_info->qos_params.defer_init_qos;
node_info->agg_params.buswidth = pdata_node_info->agg_params.buswidth;
node_info->agg_params.agg_scheme =
pdata_node_info->agg_params.agg_scheme;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
index 77cbbf1..32b6adf 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
@@ -241,6 +241,8 @@
node_info->qos_params.urg_fwd_en = of_property_read_bool(dev_node,
"qcom,forwarding");
+ node_info->qos_params.defer_init_qos = of_property_read_bool(dev_node,
+ "qcom,defer-init-qos");
}
static int msm_bus_of_parse_clk_array(struct device_node *dev_node,
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
index ad04fef..a9733f1 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
@@ -136,6 +136,7 @@
struct msm_bus_noc_regulator reg;
struct msm_bus_noc_regulator_mode reg_mode;
bool urg_fwd_en;
+ bool defer_init_qos;
};
struct node_util_levels_type {
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index a3cf11d..f5aff4f 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -269,7 +269,7 @@
return ret;
}
-static int pil_mss_assert_resets(struct q6v5_data *drv)
+int pil_mss_assert_resets(struct q6v5_data *drv)
{
int ret = 0;
@@ -280,7 +280,7 @@
return ret;
}
-static int pil_mss_deassert_resets(struct q6v5_data *drv)
+int pil_mss_deassert_resets(struct q6v5_data *drv)
{
int ret = 0;
diff --git a/drivers/soc/qcom/pil-msa.h b/drivers/soc/qcom/pil-msa.h
index 1789ba3..7a6a3cc 100644
--- a/drivers/soc/qcom/pil-msa.h
+++ b/drivers/soc/qcom/pil-msa.h
@@ -46,4 +46,6 @@
int pil_mss_shutdown(struct pil_desc *pil);
int pil_mss_deinit_image(struct pil_desc *pil);
int __pil_mss_deinit_image(struct pil_desc *pil, bool err_path);
+int pil_mss_assert_resets(struct q6v5_data *drv);
+int pil_mss_deassert_resets(struct q6v5_data *drv);
#endif
diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c
index 49dd0be..6a30381 100644
--- a/drivers/soc/qcom/pil-q6v5.c
+++ b/drivers/soc/qcom/pil-q6v5.c
@@ -23,6 +23,7 @@
#include <trace/events/trace_msm_pil_event.h>
#include "peripheral-loader.h"
+#include "pil-msa.h"
#include "pil-q6v5.h"
/* QDSP6SS Register Offsets */
@@ -86,7 +87,7 @@
#define QDSP6SS_BOOT_STATUS (0x408)
#define QDSP6SS_SLEEP (0x3C)
#define SLEEP_CHECK_MAX_LOOPS (200)
-#define BOOT_FSM_TIMEOUT (10)
+#define BOOT_FSM_TIMEOUT (100)
#define QDSP6SS_ACC_OVERRIDE_VAL 0x20
@@ -384,7 +385,7 @@
{
struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
u32 val, count;
- unsigned long timeout;
+ int ret;
val = readl_relaxed(drv->reg_base + QDSP6SS_SLEEP);
val |= 0x1;
@@ -409,15 +410,19 @@
writel_relaxed(1, drv->reg_base + QDSP6SS_BOOT_CMD);
/* Wait for boot FSM to complete */
- timeout = jiffies + usecs_to_jiffies(BOOT_FSM_TIMEOUT);
- while (time_before(jiffies, timeout)) {
- val = readl_relaxed(drv->reg_base + QDSP6SS_BOOT_STATUS);
- if (val & BIT(0))
- return 0;
+ ret = readl_poll_timeout(drv->reg_base + QDSP6SS_BOOT_STATUS, val,
+ val != 0, 10, BOOT_FSM_TIMEOUT);
+
+ if (ret) {
+ dev_err(drv->desc.dev, "Boot FSM failed to complete.\n");
+ /* Reset the modem so that boot FSM is in reset state */
+ pil_mss_assert_resets(drv);
+ /* Wait 6 32kHz sleep cycles for reset */
+ udelay(200);
+ pil_mss_deassert_resets(drv);
}
- dev_err(drv->desc.dev, "Boot FSM failed to complete.\n");
- return -ETIMEDOUT;
+ return ret;
}
static int __pil_q6v55_reset(struct pil_desc *pil)
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index f4c35ab..f7902e1 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -563,7 +563,7 @@
spin_lock_irqsave(&rpm->lock, flags);
for (i = 0; rpm->passthru_cache[i]; i++) {
rpm_msg = rpm->passthru_cache[i];
- ret = mbox_send_controller_data(rc->chan, &rpm_msg->msg);
+ ret = mbox_write_controller_data(rc->chan, &rpm_msg->msg);
if (ret)
goto fail;
}
@@ -762,7 +762,7 @@
rpm_msg.msg.is_control = true;
rpm_msg.msg.is_complete = false;
- return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
+ return mbox_write_controller_data(rc->chan, &rpm_msg.msg);
}
EXPORT_SYMBOL(rpmh_write_control);
@@ -797,7 +797,7 @@
rpm->dirty = true;
spin_unlock_irqrestore(&rpm->lock, flags);
- return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
+ return mbox_write_controller_data(rc->chan, &rpm_msg.msg);
}
EXPORT_SYMBOL(rpmh_invalidate);
@@ -886,7 +886,7 @@
rpm_msg.msg.num_payload = 1;
rpm_msg.msg.is_complete = false;
- return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
+ return mbox_write_controller_data(rc->chan, &rpm_msg.msg);
}
/**
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 6acb731..de3dc69 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -192,16 +192,26 @@
static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,
int bits_per_word)
{
- int pack_words = 0;
+ int pack_words = 1;
bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
u32 word_len = geni_read_reg(mas->base, SE_SPI_WORD_LEN);
+ unsigned long cfg0, cfg1;
+ /*
+ * If bits_per_word isn't a byte aligned value, set the packing to be
+ * 1 SPI word per FIFO word.
+ */
if (!(mas->tx_fifo_width % bits_per_word))
pack_words = mas->tx_fifo_width / bits_per_word;
word_len &= ~WORD_LEN_MSK;
word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK);
se_config_packing(mas->base, bits_per_word, pack_words, msb_first);
geni_write_reg(word_len, mas->base, SE_SPI_WORD_LEN);
+ se_get_packing_config(bits_per_word, pack_words, msb_first,
+ &cfg0, &cfg1);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: cfg0 %lu cfg1 %lu bpw %d pack_words %d\n", __func__,
+ cfg0, cfg1, bits_per_word, pack_words);
}
static int setup_fifo_params(struct spi_device *spi_slv,
@@ -257,6 +267,12 @@
geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV);
geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n",
+ __func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:clk_sel 0x%x cpol %d cpha %d\n", __func__,
+ clk_sel, cpol, cpha);
/* Ensure message level attributes are written before returning */
mb();
setup_fifo_params_exit:
@@ -316,10 +332,7 @@
flags |= GSI_CS_TOGGLE;
word_len = xfer->bits_per_word - MIN_WORD_LEN;
- if (mas->tx_fifo_width % xfer->bits_per_word)
- pack = 0;
- else
- pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
+ pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
if (ret) {
dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret);
@@ -504,19 +517,26 @@
}
}
+ if (!(mas->cur_word_len % MIN_WORD_LEN)) {
+ rx_len = ((xfer->len << 3) / mas->cur_word_len);
+ } else {
+ int bytes_per_word = (mas->cur_word_len / BITS_PER_BYTE) + 1;
+
+ rx_len = (xfer->len / bytes_per_word);
+ }
+
if (xfer->tx_buf && xfer->rx_buf) {
cmd = SPI_FULL_DUPLEX;
tx_nent += 2;
rx_nent++;
- rx_len = ((xfer->len << 3) / mas->cur_word_len);
} else if (xfer->tx_buf) {
cmd = SPI_TX_ONLY;
tx_nent += 2;
+ rx_len = 0;
} else if (xfer->rx_buf) {
cmd = SPI_RX_ONLY;
tx_nent++;
rx_nent++;
- rx_len = ((xfer->len << 3) / mas->cur_word_len);
}
cs |= spi_slv->chip_select;
@@ -844,7 +864,14 @@
spi_tx_cfg &= ~CS_TOGGLE;
if (xfer->cs_change)
spi_tx_cfg |= CS_TOGGLE;
- trans_len = ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
+ if (!(mas->cur_word_len % MIN_WORD_LEN)) {
+ trans_len =
+ ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
+ } else {
+ int bytes_per_word = (mas->cur_word_len / BITS_PER_BYTE) + 1;
+
+ trans_len = (xfer->len / bytes_per_word) & TRANS_LEN_MSK;
+ }
if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
m_param |= FRAGMENTATION;
@@ -860,6 +887,9 @@
}
geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
geni_setup_m_cmd(mas->base, m_cmd, m_param);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x\n",
+ __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd);
if (m_cmd & SPI_TX_ONLY)
geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
/* Ensure all writes are done before the WM interrupt */
@@ -872,6 +902,7 @@
reinit_completion(&mas->xfer_done);
geni_cancel_m_cmd(mas->base);
+ geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
/* Ensure cmd cancel is written */
mb();
timeout = wait_for_completion_timeout(&mas->xfer_done, HZ);
@@ -966,12 +997,25 @@
{
int i = 0;
int tx_fifo_width = (mas->tx_fifo_width >> 3);
- int max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
+ int max_bytes = 0;
const u8 *tx_buf = NULL;
if (!mas->cur_xfer)
return;
+ /*
+ * For non-byte aligned bits-per-word values:
+ * Assumption is that each SPI word will be accomodated in
+ * ceil (bits_per_word / bits_per_byte)
+ * and the next SPI word starts at the next byte.
+ * In such cases, we can fit 1 SPI word per FIFO word so adjust the
+ * max byte that can be sent per IRQ accordingly.
+ */
+ if ((mas->tx_fifo_width % mas->cur_word_len))
+ max_bytes = (mas->tx_fifo_depth - mas->tx_wm) *
+ ((mas->cur_word_len / BITS_PER_BYTE) + 1);
+ else
+ max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
tx_buf = mas->cur_xfer->tx_buf;
tx_buf += (mas->cur_xfer->len - mas->tx_rem_bytes);
max_bytes = min_t(int, mas->tx_rem_bytes, max_bytes);
@@ -979,8 +1023,13 @@
int j;
u32 fifo_word = 0;
u8 *fifo_byte;
- int bytes_to_write = min_t(int, (max_bytes - i), tx_fifo_width);
+ int bytes_per_fifo = tx_fifo_width;
+ int bytes_to_write = 0;
+ if ((mas->tx_fifo_width % mas->cur_word_len))
+ bytes_per_fifo =
+ (mas->cur_word_len / BITS_PER_BYTE) + 1;
+ bytes_to_write = min_t(int, (max_bytes - i), bytes_per_fifo);
fifo_byte = (u8 *)&fifo_word;
for (j = 0; j < bytes_to_write; j++)
fifo_byte[j] = tx_buf[i++];
@@ -1019,15 +1068,24 @@
rx_bytes += rx_last_byte_valid;
}
}
- rx_bytes += rx_wc * fifo_width;
+ if (!(mas->tx_fifo_width % mas->cur_word_len))
+ rx_bytes += rx_wc * fifo_width;
+ else
+ rx_bytes += rx_wc *
+ ((mas->cur_word_len / BITS_PER_BYTE) + 1);
rx_bytes = min_t(int, mas->rx_rem_bytes, rx_bytes);
rx_buf += (mas->cur_xfer->len - mas->rx_rem_bytes);
while (i < rx_bytes) {
u32 fifo_word = 0;
u8 *fifo_byte;
- int read_bytes = min_t(int, (rx_bytes - i), fifo_width);
+ int bytes_per_fifo = fifo_width;
+ int read_bytes = 0;
int j;
+ if ((mas->tx_fifo_width % mas->cur_word_len))
+ bytes_per_fifo =
+ (mas->cur_word_len / BITS_PER_BYTE) + 1;
+ read_bytes = min_t(int, (rx_bytes - i), bytes_per_fifo);
fifo_word = geni_read_reg(mas->base, SE_GENI_RX_FIFOn);
fifo_byte = (u8 *)&fifo_word;
for (j = 0; j < read_bytes; j++)
@@ -1039,8 +1097,14 @@
static irqreturn_t geni_spi_irq(int irq, void *dev)
{
struct spi_geni_master *mas = dev;
- u32 m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);
+ u32 m_irq = 0;
+ if (pm_runtime_status_suspended(dev)) {
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: device is suspended\n", __func__);
+ goto exit_geni_spi_irq;
+ }
+ m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);
if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
geni_spi_handle_rx(mas);
@@ -1050,7 +1114,26 @@
if ((m_irq & M_CMD_DONE_EN) || (m_irq & M_CMD_CANCEL_EN) ||
(m_irq & M_CMD_ABORT_EN)) {
complete(&mas->xfer_done);
+ /*
+ * If this happens, then a CMD_DONE came before all the buffer
+ * bytes were sent out. This is unusual, log this condition and
+ * disable the WM interrupt to prevent the system from stalling
+ * due an interrupt storm.
+ * If this happens when all Rx bytes haven't been received, log
+ * the condition.
+ */
+ if (mas->tx_rem_bytes) {
+ geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:Premature Done.tx_rem%d bpw%d\n",
+ __func__, mas->tx_rem_bytes, mas->cur_word_len);
+ }
+ if (mas->rx_rem_bytes)
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:Premature Done.rx_rem%d bpw%d\n",
+ __func__, mas->rx_rem_bytes, mas->cur_word_len);
}
+exit_geni_spi_irq:
geni_write_reg(m_irq, mas->base, SE_GENI_M_IRQ_CLEAR);
return IRQ_HANDLED;
}
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index f9054cb..67ed0e8 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -98,7 +98,9 @@
#define UART_PARAM (0x1)
/* UART DMA Rx GP_IRQ_BITS */
-#define UART_DMA_RX_ERRS (GENMASK(5, 8))
+#define UART_DMA_RX_PARITY_ERR BIT(5)
+#define UART_DMA_RX_ERRS (GENMASK(5, 6))
+#define UART_DMA_RX_BREAK (GENMASK(7, 8))
#define UART_OVERSAMPLING (32)
#define STALE_TIMEOUT (16)
@@ -141,7 +143,8 @@
int (*handle_rx)(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last);
+ unsigned int rx_last,
+ bool drop_rx);
struct device *wrapper_dev;
struct se_geni_rsc serial_rsc;
dma_addr_t tx_dma;
@@ -167,11 +170,13 @@
static int handle_rx_console(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last);
+ unsigned int rx_last,
+ bool drop_rx);
static int handle_rx_hs(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last);
+ unsigned int rx_last,
+ bool drop_rx);
static unsigned int msm_geni_serial_tx_empty(struct uart_port *port);
static int msm_geni_serial_power_on(struct uart_port *uport);
static void msm_geni_serial_power_off(struct uart_port *uport);
@@ -681,7 +686,8 @@
static int handle_rx_console(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last)
+ unsigned int rx_last,
+ bool drop_rx)
{
int i, c;
unsigned char *rx_char;
@@ -694,6 +700,8 @@
*(msm_port->rx_fifo) =
geni_read_reg_nolog(uport->membase, SE_GENI_RX_FIFOn);
+ if (drop_rx)
+ continue;
rx_char = (unsigned char *)msm_port->rx_fifo;
if (i == (rx_fifo_wc - 1)) {
@@ -710,14 +718,16 @@
tty_insert_flip_char(tport, rx_char[c], flag);
}
}
- tty_flip_buffer_push(tport);
+ if (!drop_rx)
+ tty_flip_buffer_push(tport);
return 0;
}
#else
static int handle_rx_console(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last)
+ unsigned int rx_last,
+ bool drop_rx)
{
return -EPERM;
}
@@ -1001,7 +1011,8 @@
static int handle_rx_hs(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last)
+ unsigned int rx_last,
+ bool drop_rx)
{
unsigned char *rx_char;
struct tty_port *tport;
@@ -1016,6 +1027,8 @@
tport = &uport->state->port;
ioread32_rep((uport->membase + SE_GENI_RX_FIFOn), msm_port->rx_fifo,
rx_fifo_wc);
+ if (drop_rx)
+ return 0;
rx_char = (unsigned char *)msm_port->rx_fifo;
ret = tty_insert_flip_string(tport, rx_char, rx_bytes);
@@ -1031,7 +1044,7 @@
return ret;
}
-static int msm_geni_serial_handle_rx(struct uart_port *uport)
+static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx)
{
int ret = 0;
unsigned int rx_fifo_status;
@@ -1050,7 +1063,7 @@
rx_last = rx_fifo_status & RX_LAST;
if (rx_fifo_wc)
port->handle_rx(uport, rx_fifo_wc, rx_last_byte_valid,
- rx_last);
+ rx_last, drop_rx);
return ret;
}
@@ -1128,13 +1141,13 @@
} else {
msm_port->xmit_size = xmit_size;
}
+exit_handle_tx:
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(uport);
-exit_handle_tx:
return ret;
}
-static int msm_geni_serial_handle_dma_rx(struct uart_port *uport)
+static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
{
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
unsigned int rx_bytes = 0;
@@ -1160,6 +1173,8 @@
__func__, rx_bytes);
goto exit_handle_dma_rx;
}
+ if (drop_rx)
+ goto exit_handle_dma_rx;
tport = &uport->state->port;
ret = tty_insert_flip_string(tport, (unsigned char *)(msm_port->rx_buf),
@@ -1211,6 +1226,7 @@
unsigned long flags;
unsigned int m_irq_en;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ bool drop_rx = false;
spin_lock_irqsave(&uport->lock, flags);
if (uart_console(uport) && uport->suspended)
@@ -1239,21 +1255,29 @@
}
if (!dma) {
- if ((s_irq_status & S_GP_IRQ_0_EN) ||
- (s_irq_status & S_GP_IRQ_1_EN) ||
- (s_irq_status & S_GP_IRQ_2_EN) ||
- (s_irq_status & S_GP_IRQ_3_EN)) {
- IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s.sirq 0x%x.\n", __func__, s_irq_status);
- goto exit_geni_serial_isr;
- }
- if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
- (s_irq_status & S_RX_FIFO_LAST_EN))
- msm_geni_serial_handle_rx(uport);
-
if ((m_irq_status & m_irq_en) &
(M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
msm_geni_serial_handle_tx(uport);
+
+ if ((s_irq_status & S_GP_IRQ_0_EN) ||
+ (s_irq_status & S_GP_IRQ_1_EN)) {
+ if (s_irq_status & S_GP_IRQ_0_EN)
+ uport->icount.parity++;
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.sirq 0x%x parity:%d\n",
+ __func__, s_irq_status, uport->icount.parity);
+ drop_rx = true;
+ } else if ((s_irq_status & S_GP_IRQ_2_EN) ||
+ (s_irq_status & S_GP_IRQ_3_EN)) {
+ uport->icount.brk++;
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.sirq 0x%x break:%d\n",
+ __func__, s_irq_status, uport->icount.brk);
+ }
+
+ if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
+ (s_irq_status & S_RX_FIFO_LAST_EN))
+ msm_geni_serial_handle_rx(uport, drop_rx);
} else {
if (dma_tx_status) {
geni_write_reg_nolog(dma_tx_status, uport->membase,
@@ -1272,13 +1296,22 @@
goto exit_geni_serial_isr;
}
if (dma_rx_status & UART_DMA_RX_ERRS) {
+ if (dma_rx_status & UART_DMA_RX_PARITY_ERR)
+ uport->icount.parity++;
IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s.Rx Errors. 0x%x.\n",
- __func__, dma_rx_status);
- goto exit_geni_serial_isr;
+ "%s.Rx Errors. 0x%x parity:%d\n",
+ __func__, dma_rx_status,
+ uport->icount.parity);
+ drop_rx = true;
+ } else if (dma_rx_status & UART_DMA_RX_BREAK) {
+ uport->icount.brk++;
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.Rx Errors. 0x%x break:%d\n",
+ __func__, dma_rx_status,
+ uport->icount.brk);
}
if (dma_rx_status & RX_DMA_DONE)
- msm_geni_serial_handle_dma_rx(uport);
+ msm_geni_serial_handle_dma_rx(uport, drop_rx);
}
}
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index 339d470..c8696df 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -212,6 +212,7 @@
#define GCC_VS_CTRL_CLK_SRC 194
#define GCC_VSENSOR_CLK_SRC 195
#define GPLL4 196
+#define GPLL6 197
/* GCC reset clocks */
#define GCC_MMSS_BCR 0
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
index 86a2dc6..073391b 100644
--- a/include/linux/mailbox_client.h
+++ b/include/linux/mailbox_client.h
@@ -44,7 +44,7 @@
const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);
int mbox_send_message(struct mbox_chan *chan, void *mssg);
-int mbox_send_controller_data(struct mbox_chan *chan, void *mssg);
+int mbox_write_controller_data(struct mbox_chan *chan, void *mssg);
void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */
bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */
void mbox_free_channel(struct mbox_chan *chan); /* may sleep */
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 7827c68..751b354 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -24,8 +24,8 @@
* transmission of data is reported by the controller via
* mbox_chan_txdone (if it has some TX ACK irq). It must not
* sleep.
- * @send_controller_data:
- * Send data for the controller driver. This could be data to
+ * @write_controller_data:
+ * Write data for the controller driver. This could be data to
* configure the controller or data that may be cached in the
* controller and not transmitted immediately. There is no ACK
* for this request and the request is not buffered in the
@@ -54,7 +54,7 @@
*/
struct mbox_chan_ops {
int (*send_data)(struct mbox_chan *chan, void *data);
- int (*send_controller_data)(struct mbox_chan *chan, void *data);
+ int (*write_controller_data)(struct mbox_chan *chan, void *data);
int (*startup)(struct mbox_chan *chan);
void (*shutdown)(struct mbox_chan *chan);
bool (*last_tx_done)(struct mbox_chan *chan);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ed0099c9..07e1acb 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -158,7 +158,6 @@
NR_UNEVICTABLE, /* " " " " " */
NR_ISOLATED_ANON, /* Temporary isolated pages from anon lru */
NR_ISOLATED_FILE, /* Temporary isolated pages from file lru */
- NR_PAGES_SCANNED, /* pages scanned since last reclaim */
WORKINGSET_REFAULT,
WORKINGSET_ACTIVATE,
WORKINGSET_NODERECLAIM,
@@ -645,6 +644,8 @@
int kswapd_order;
enum zone_type kswapd_classzone_idx;
+ int kswapd_failures; /* Number of 'reclaimed == 0' runs */
+
#ifdef CONFIG_COMPACTION
int kcompactd_max_order;
enum zone_type kcompactd_classzone_idx;
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index 3ca2526..4443a29 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -24,6 +24,9 @@
#define NMI_WATCHDOG_ENABLED (1 << NMI_WATCHDOG_ENABLED_BIT)
#define SOFT_WATCHDOG_ENABLED (1 << SOFT_WATCHDOG_ENABLED_BIT)
+DECLARE_PER_CPU(unsigned long, hrtimer_interrupts);
+DECLARE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+
/**
* touch_nmi_watchdog - restart NMI watchdog timeout.
*
@@ -31,8 +34,11 @@
* may be used to reset the timeout - for code which intentionally
* disables interrupts for a long time. This call is stateless.
*/
-#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR_NMI)
#include <asm/nmi.h>
+#endif
+
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
extern void touch_nmi_watchdog(void);
#else
static inline void touch_nmi_watchdog(void)
@@ -130,6 +136,7 @@
#define sysctl_softlockup_all_cpu_backtrace 0
#define sysctl_hardlockup_all_cpu_backtrace 0
#endif
+
extern bool is_hardlockup(void);
struct ctl_table;
extern int proc_watchdog(struct ctl_table *, int ,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e1345ec..a4ea064 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -3964,4 +3964,6 @@
void cpufreq_remove_update_util_hook(int cpu);
#endif /* CONFIG_CPU_FREQ */
+extern DEFINE_PER_CPU_READ_MOSTLY(int, sched_load_boost);
+
#endif
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 261202f..8dbfdf7 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -95,8 +95,6 @@
[FRA_FWMARK] = { .type = NLA_U32 }, \
[FRA_FWMASK] = { .type = NLA_U32 }, \
[FRA_TABLE] = { .type = NLA_U32 }, \
- [FRA_UID_START] = { .type = NLA_U32 }, \
- [FRA_UID_END] = { .type = NLA_U32 }, \
[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
[FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
[FRA_GOTO] = { .type = NLA_U32 }, \
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index c88fd09..2f8536b 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -269,23 +269,24 @@
__entry->retval)
);
-DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
-
+TRACE_EVENT(mm_vmscan_lru_isolate,
TP_PROTO(int classzone_idx,
int order,
unsigned long nr_requested,
unsigned long nr_scanned,
+ unsigned long nr_skipped,
unsigned long nr_taken,
isolate_mode_t isolate_mode,
int file),
- TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
+ TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_skipped, nr_taken, isolate_mode, file),
TP_STRUCT__entry(
__field(int, classzone_idx)
__field(int, order)
__field(unsigned long, nr_requested)
__field(unsigned long, nr_scanned)
+ __field(unsigned long, nr_skipped)
__field(unsigned long, nr_taken)
__field(isolate_mode_t, isolate_mode)
__field(int, file)
@@ -296,49 +297,23 @@
__entry->order = order;
__entry->nr_requested = nr_requested;
__entry->nr_scanned = nr_scanned;
+ __entry->nr_skipped = nr_skipped;
__entry->nr_taken = nr_taken;
__entry->isolate_mode = isolate_mode;
__entry->file = file;
),
- TP_printk("isolate_mode=%d classzone=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
+ TP_printk("isolate_mode=%d classzone=%d order=%d nr_requested=%lu nr_scanned=%lu nr_skipped=%lu nr_taken=%lu file=%d",
__entry->isolate_mode,
__entry->classzone_idx,
__entry->order,
__entry->nr_requested,
__entry->nr_scanned,
+ __entry->nr_skipped,
__entry->nr_taken,
__entry->file)
);
-DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
-
- TP_PROTO(int classzone_idx,
- int order,
- unsigned long nr_requested,
- unsigned long nr_scanned,
- unsigned long nr_taken,
- isolate_mode_t isolate_mode,
- int file),
-
- TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
-
-);
-
-DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
-
- TP_PROTO(int classzone_idx,
- int order,
- unsigned long nr_requested,
- unsigned long nr_scanned,
- unsigned long nr_taken,
- isolate_mode_t isolate_mode,
- int file),
-
- TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
-
-);
-
TRACE_EVENT(mm_vmscan_writepage,
TP_PROTO(struct page *page),
diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index a66c4ba..bbf02a6 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -54,8 +54,6 @@
FRA_TABLE, /* Extended table id */
FRA_FWMASK, /* mask for netfilter mark */
FRA_OIFNAME,
- FRA_UID_START, /* UID range */
- FRA_UID_END,
FRA_PAD,
FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
FRA_UID_RANGE, /* UID range */
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4573d45..ccfb9bf 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3232,9 +3232,9 @@
static inline
unsigned long sum_capacity_reqs(unsigned long cfs_cap,
- struct sched_capacity_reqs *scr)
+ struct sched_capacity_reqs *scr, int cpu)
{
- unsigned long total = add_capacity_margin(cfs_cap + scr->rt);
+ unsigned long total = add_capacity_margin(cfs_cap + scr->rt, cpu);
return total += scr->dl;
}
@@ -3246,7 +3246,7 @@
struct sched_capacity_reqs *scr;
scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
- if (sum_capacity_reqs(cpu_utilization, scr) < capacity_curr)
+ if (sum_capacity_reqs(cpu_utilization, scr, cpu) < capacity_curr)
return;
/*
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 116ffe4..c2372f8 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -84,6 +84,7 @@
};
static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu);
+static unsigned int stale_ns;
/************************ Governor internals ***********************/
@@ -364,7 +365,7 @@
* idle now (and clear iowait_boost for it).
*/
delta_ns = last_freq_update_time - j_sg_cpu->last_update;
- if (delta_ns > sched_ravg_window) {
+ if (delta_ns > stale_ns) {
j_sg_cpu->iowait_boost = 0;
continue;
}
@@ -716,6 +717,7 @@
policy->governor_data = sg_policy;
sg_policy->tunables = tunables;
+ stale_ns = sched_ravg_window + (sched_ravg_window >> 3);
ret = kobject_init_and_add(&tunables->attr_set.kobj, &sugov_tunables_ktype,
get_governor_parent_kobj(policy), "%s",
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index fde0639..38fa781 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -89,6 +89,7 @@
unsigned int sysctl_sched_sync_hint_enable = 1;
unsigned int sysctl_sched_initial_task_util = 0;
unsigned int sysctl_sched_cstate_aware = 1;
+DEFINE_PER_CPU_READ_MOSTLY(int, sched_load_boost);
#ifdef CONFIG_SCHED_WALT
unsigned int sysctl_sched_use_walt_cpu_util = 1;
@@ -7043,7 +7044,7 @@
cpu_idle_idx = idle_get_state_idx(cpu_rq(i));
if (!need_idle &&
- add_capacity_margin(new_util_cum) <
+ add_capacity_margin(new_util_cum, i) <
capacity_curr_of(i)) {
if (sysctl_sched_cstate_aware) {
if (cpu_idle_idx < min_idle_idx) {
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 6b935e7..1bc4828 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1811,7 +1811,7 @@
cpu_idle_idx =
idle_get_state_idx(cpu_rq(cpu));
- if (add_capacity_margin(new_util_cum) <
+ if (add_capacity_margin(new_util_cum, cpu) <
capacity_curr_of(cpu)) {
if (cpu_idle_idx < best_cpu_idle_idx ||
(best_cpu != task_cpu(task) &&
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 72b79bb..0a1e62f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -29,6 +29,7 @@
#ifdef CONFIG_SCHED_WALT
extern unsigned int sched_ravg_window;
+extern unsigned int walt_cpu_util_freq_divisor;
struct walt_sched_stats {
int nr_big_tasks;
@@ -1805,47 +1806,87 @@
#endif
static inline unsigned long
-cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+cpu_util_freq_pelt(int cpu)
{
struct rq *rq = cpu_rq(cpu);
- u64 util = rq->cfs.avg.util_avg;
+ unsigned long util = rq->cfs.avg.util_avg;
unsigned long capacity = capacity_orig_of(cpu);
-#ifdef CONFIG_SCHED_WALT
- if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
+ util *= (100 + per_cpu(sched_load_boost, cpu));
+ do_div(util, 100);
- util = freq_policy_load(rq);
- util = div64_u64(util,
- sched_ravg_window >> SCHED_CAPACITY_SHIFT);
-
- if (walt_load) {
- u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum +
- rq->grp_time.nt_prev_runnable_sum;
- u64 pl = rq->walt_stats.pred_demands_sum;
-
- nl = div64_u64(nl, sched_ravg_window >>
- SCHED_CAPACITY_SHIFT);
- pl = div64_u64(pl, sched_ravg_window >>
- SCHED_CAPACITY_SHIFT);
-
- walt_load->prev_window_util = util;
- walt_load->nl = nl;
- walt_load->pl = pl;
- rq->old_busy_time = util;
- rq->old_estimated_time = pl;
- walt_load->ws = rq->window_start;
- }
- }
-#endif
return (util >= capacity) ? capacity : util;
}
+
+#ifdef CONFIG_SCHED_WALT
+static inline unsigned long
+cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+ u64 util, util_unboosted;
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long capacity = capacity_orig_of(cpu);
+ int boost;
+
+ if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
+ return cpu_util_freq_pelt(cpu);
+
+ boost = per_cpu(sched_load_boost, cpu);
+ util_unboosted = util = freq_policy_load(rq);
+ util = div64_u64(util * (100 + boost),
+ walt_cpu_util_freq_divisor);
+
+ if (walt_load) {
+ u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum +
+ rq->grp_time.nt_prev_runnable_sum;
+ u64 pl = rq->walt_stats.pred_demands_sum;
+
+ /* do_pl_notif() needs unboosted signals */
+ rq->old_busy_time = div64_u64(util_unboosted,
+ sched_ravg_window >>
+ SCHED_CAPACITY_SHIFT);
+ rq->old_estimated_time = div64_u64(pl, sched_ravg_window >>
+ SCHED_CAPACITY_SHIFT);
+
+ nl = div64_u64(nl * (100 + boost),
+ walt_cpu_util_freq_divisor);
+ pl = div64_u64(pl * (100 + boost),
+ walt_cpu_util_freq_divisor);
+
+ walt_load->prev_window_util = util;
+ walt_load->nl = nl;
+ walt_load->pl = pl;
+ walt_load->ws = rq->window_start;
+ }
+
+ return (util >= capacity) ? capacity : util;
+}
+
+static inline unsigned long
+cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+ return cpu_util_freq_walt(cpu, walt_load);
+}
+
+#else
+
+static inline unsigned long
+cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+ return cpu_util_freq_pelt(cpu);
+}
+
+#endif /* CONFIG_SCHED_WALT */
+
#endif
extern unsigned int capacity_margin_freq;
-static inline unsigned long add_capacity_margin(unsigned long cpu_capacity)
+static inline unsigned long
+add_capacity_margin(unsigned long cpu_capacity, int cpu)
{
- cpu_capacity = cpu_capacity * capacity_margin_freq;
+ cpu_capacity = cpu_capacity * capacity_margin_freq *
+ (100 + per_cpu(sched_load_boost, cpu));
+ cpu_capacity /= 100;
cpu_capacity /= SCHED_CAPACITY_SCALE;
return cpu_capacity;
}
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 60249e4..316c276 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -109,6 +109,12 @@
/* Window size (in ns) */
__read_mostly unsigned int sched_ravg_window = MIN_SCHED_RAVG_WINDOW;
+/*
+ * A after-boot constant divisor for cpu_util_freq_walt() to apply the load
+ * boost.
+ */
+__read_mostly unsigned int walt_cpu_util_freq_divisor;
+
/* Initial task load. Newly created tasks are assigned this load. */
unsigned int __read_mostly sched_init_task_load_windows;
unsigned int __read_mostly sysctl_sched_init_task_load_pct = 15;
@@ -3107,4 +3113,7 @@
clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]);
}
rq->cum_window_demand = 0;
+
+ walt_cpu_util_freq_divisor =
+ (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100;
}
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index e671a32..843fb50 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -201,6 +201,7 @@
bool migration_enabled;
bool nohz_active;
bool is_idle;
+ bool must_forward_clk;
DECLARE_BITMAP(pending_map, WHEEL_SIZE);
struct hlist_head vectors[WHEEL_SIZE];
} ____cacheline_aligned;
@@ -874,13 +875,19 @@
static inline void forward_timer_base(struct timer_base *base)
{
- unsigned long jnow = READ_ONCE(jiffies);
+ unsigned long jnow;
/*
- * We only forward the base when it's idle and we have a delta between
- * base clock and jiffies.
+ * We only forward the base when we are idle or have just come out of
+ * idle (must_forward_clk logic), and have a delta between base clock
+ * and jiffies. In the common case, run_timers will take care of it.
*/
- if (!base->is_idle || (long) (jnow - base->clk) < 2)
+ if (likely(!base->must_forward_clk))
+ return;
+
+ jnow = READ_ONCE(jiffies);
+ base->must_forward_clk = base->is_idle;
+ if ((long)(jnow - base->clk) < 2)
return;
/*
@@ -956,6 +963,11 @@
* same array bucket then just return:
*/
if (timer_pending(timer)) {
+ /*
+ * The downside of this optimization is that it can result in
+ * larger granularity than you would get from adding a new
+ * timer with this expiry.
+ */
if (timer->expires == expires)
return 1;
@@ -966,6 +978,7 @@
* dequeue/enqueue dance.
*/
base = lock_timer_base(timer, &flags);
+ forward_timer_base(base);
clk = base->clk;
idx = calc_wheel_index(expires, clk);
@@ -982,6 +995,7 @@
}
} else {
base = lock_timer_base(timer, &flags);
+ forward_timer_base(base);
}
ret = detach_if_pending(timer, base, false);
@@ -1009,12 +1023,10 @@
spin_lock(&base->lock);
WRITE_ONCE(timer->flags,
(timer->flags & ~TIMER_BASEMASK) | base->cpu);
+ forward_timer_base(base);
}
}
- /* Try to forward a stale timer base clock */
- forward_timer_base(base);
-
timer->expires = expires;
/*
* If 'idx' was calculated above and the base time did not advance
@@ -1130,6 +1142,7 @@
WRITE_ONCE(timer->flags,
(timer->flags & ~TIMER_BASEMASK) | cpu);
}
+ forward_timer_base(base);
debug_activate(timer, timer->expires);
internal_add_timer(base, timer);
@@ -1546,10 +1559,16 @@
if (!is_max_delta)
expires = basem + (nextevt - basej) * TICK_NSEC;
/*
- * If we expect to sleep more than a tick, mark the base idle:
+ * If we expect to sleep more than a tick, mark the base idle.
+ * Also the tick is stopped so any added timer must forward
+ * the base clk itself to keep granularity small. This idle
+ * logic is only maintained for the BASE_STD base, deferrable
+ * timers may still see large granularity skew (by design).
*/
- if ((expires - basem) > TICK_NSEC)
+ if ((expires - basem) > TICK_NSEC) {
+ base->must_forward_clk = true;
base->is_idle = true;
+ }
}
spin_unlock(&base->lock);
@@ -1659,6 +1678,19 @@
{
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
+ /*
+ * must_forward_clk must be cleared before running timers so that any
+ * timer functions that call mod_timer will not try to forward the
+ * base. idle trcking / clock forwarding logic is only used with
+ * BASE_STD timers.
+ *
+ * The deferrable base does not do idle tracking at all, so we do
+ * not forward it. This can result in very large variations in
+ * granularity for deferrable timers, but they can be deferred for
+ * long periods due to idle.
+ */
+ base->must_forward_clk = false;
+
__run_timers(base);
if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active)
__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index cffb5f2..cfbf027 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -81,10 +81,10 @@
static DEFINE_PER_CPU(unsigned int, watchdog_en);
static DEFINE_PER_CPU(bool, softlockup_touch_sync);
static DEFINE_PER_CPU(bool, soft_watchdog_warn);
-static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
static DEFINE_PER_CPU(unsigned long, soft_lockup_hrtimer_cnt);
static DEFINE_PER_CPU(struct task_struct *, softlockup_task_ptr_saved);
-static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
+DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
static unsigned long soft_lockup_nmi_warn;
unsigned int __read_mostly softlockup_panic =
@@ -254,6 +254,10 @@
{
}
+void __weak watchdog_check_hardlockup_other_cpu(void)
+{
+}
+
static int watchdog_enable_all_cpus(void);
static void watchdog_disable_all_cpus(void);
@@ -271,6 +275,9 @@
/* kick the hardlockup detector */
watchdog_interrupt_count();
+ /* test for hardlockups on the next cpu */
+ watchdog_check_hardlockup_other_cpu();
+
/* kick the softlockup detector */
wake_up_process(__this_cpu_read(softlockup_watchdog));
diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c
index 12b8dd6..5b2c127 100644
--- a/kernel/watchdog_hld.c
+++ b/kernel/watchdog_hld.c
@@ -18,7 +18,11 @@
static DEFINE_PER_CPU(bool, hard_watchdog_warn);
static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
+static cpumask_t __read_mostly watchdog_cpus;
+#else
static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
+#endif
/* boot commands */
/*
@@ -26,7 +30,10 @@
*/
unsigned int __read_mostly hardlockup_panic =
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
static unsigned long hardlockup_allcpu_dumped;
+#endif
/*
* We may not want to enable hard lockup detection by default in all cases,
* for example when running the kernel as a guest on a hypervisor. In these
@@ -68,6 +75,108 @@
}
EXPORT_SYMBOL(touch_nmi_watchdog);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
+static unsigned int watchdog_next_cpu(unsigned int cpu)
+{
+ cpumask_t cpus = watchdog_cpus;
+ unsigned int next_cpu;
+
+ next_cpu = cpumask_next(cpu, &cpus);
+ if (next_cpu >= nr_cpu_ids)
+ next_cpu = cpumask_first(&cpus);
+
+ if (next_cpu == cpu)
+ return nr_cpu_ids;
+
+ return next_cpu;
+}
+
+static int is_hardlockup_other_cpu(unsigned int cpu)
+{
+ unsigned long hrint = per_cpu(hrtimer_interrupts, cpu);
+
+ if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
+ return 1;
+
+ per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
+ return 0;
+}
+
+void watchdog_check_hardlockup_other_cpu(void)
+{
+ unsigned int next_cpu;
+
+ /*
+ * Test for hardlockups every 3 samples. The sample period is
+ * watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over
+ * watchdog_thresh (over by 20%).
+ */
+ if (__this_cpu_read(hrtimer_interrupts) % 3 != 0)
+ return;
+
+ /* check for a hardlockup on the next cpu */
+ next_cpu = watchdog_next_cpu(smp_processor_id());
+ if (next_cpu >= nr_cpu_ids)
+ return;
+
+ smp_rmb();
+
+ if (per_cpu(watchdog_nmi_touch, next_cpu) == true) {
+ per_cpu(watchdog_nmi_touch, next_cpu) = false;
+ return;
+ }
+
+ if (is_hardlockup_other_cpu(next_cpu)) {
+ /* only warn once */
+ if (per_cpu(hard_watchdog_warn, next_cpu) == true)
+ return;
+
+ if (hardlockup_panic)
+ panic("Watchdog detected hard LOCKUP on cpu %u",
+ next_cpu);
+ else
+ WARN(1, "Watchdog detected hard LOCKUP on cpu %u",
+ next_cpu);
+
+ per_cpu(hard_watchdog_warn, next_cpu) = true;
+ } else {
+ per_cpu(hard_watchdog_warn, next_cpu) = false;
+ }
+}
+
+int watchdog_nmi_enable(unsigned int cpu)
+{
+ /*
+ * The new cpu will be marked online before the first hrtimer interrupt
+ * runs on it. If another cpu tests for a hardlockup on the new cpu
+ * before it has run its first hrtimer, it will get a false positive.
+ * Touch the watchdog on the new cpu to delay the first check for at
+ * least 3 sampling periods to guarantee one hrtimer has run on the new
+ * cpu.
+ */
+ per_cpu(watchdog_nmi_touch, cpu) = true;
+ smp_wmb();
+ cpumask_set_cpu(cpu, &watchdog_cpus);
+ return 0;
+}
+
+void watchdog_nmi_disable(unsigned int cpu)
+{
+ unsigned int next_cpu = watchdog_next_cpu(cpu);
+
+ /*
+ * Offlining this cpu will cause the cpu before this one to start
+ * checking the one after this one. If this cpu just finished checking
+ * the next cpu and updating hrtimer_interrupts_saved, and then the
+ * previous cpu checks it within one sample period, it will trigger a
+ * false positive. Touch the watchdog on the next cpu to prevent it.
+ */
+ if (next_cpu < nr_cpu_ids)
+ per_cpu(watchdog_nmi_touch, next_cpu) = true;
+ smp_wmb();
+ cpumask_clear_cpu(cpu, &watchdog_cpus);
+}
+#else
static struct perf_event_attr wd_hw_attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
@@ -228,3 +337,4 @@
cpu0_err = 0;
}
}
+#endif
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2f9f7aa..411b383 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -779,11 +779,20 @@
The frequency of hrtimer and NMI events and the soft and hard lockup
thresholds can be controlled through the sysctl watchdog_thresh.
-config HARDLOCKUP_DETECTOR
+config HARDLOCKUP_DETECTOR_NMI
def_bool y
depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG
depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
+config HARDLOCKUP_DETECTOR_OTHER_CPU
+ def_bool y
+ depends on LOCKUP_DETECTOR && SMP
+ depends on !HARDLOCKUP_DETECTOR_NMI && !HAVE_NMI_WATCHDOG
+
+config HARDLOCKUP_DETECTOR
+ def_bool y
+ depends on HARDLOCKUP_DETECTOR_NMI || HARDLOCKUP_DETECTOR_OTHER_CPU
+
config BOOTPARAM_HARDLOCKUP_PANIC
bool "Panic (Reboot) On Hard Lockups"
depends on HARDLOCKUP_DETECTOR
diff --git a/mm/internal.h b/mm/internal.h
index 537ac99..df6319f 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -74,11 +74,16 @@
extern unsigned long highest_memmap_pfn;
/*
+ * Maximum number of reclaim retries without progress before the OOM
+ * killer is consider the only way forward.
+ */
+#define MAX_RECLAIM_RETRIES 16
+
+/*
* in mm/vmscan.c:
*/
extern int isolate_lru_page(struct page *page);
extern void putback_lru_page(struct page *page);
-extern bool pgdat_reclaimable(struct pglist_data *pgdat);
/*
* in mm/rmap.c:
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index ede13734..6eb61a4 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1201,7 +1201,11 @@
arch_refresh_nodedata(nid, pgdat);
} else {
- /* Reset the nr_zones, order and classzone_idx before reuse */
+ /*
+ * Reset the nr_zones, order and classzone_idx before reuse.
+ * Note that kswapd will init kswapd_classzone_idx properly
+ * when it starts in the near future.
+ */
pgdat->nr_zones = 0;
pgdat->kswapd_order = 0;
pgdat->kswapd_classzone_idx = 0;
diff --git a/mm/migrate.c b/mm/migrate.c
index f0b786d..4213d27 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1738,9 +1738,6 @@
{
int z;
- if (!pgdat_reclaimable(pgdat))
- return false;
-
for (z = pgdat->nr_zones - 1; z >= 0; z--) {
struct zone *zone = pgdat->node_zones + z;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 44085b2..3eb5f68 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1099,14 +1099,10 @@
{
int migratetype = 0;
int batch_free = 0;
- unsigned long nr_scanned;
bool isolated_pageblocks;
spin_lock(&zone->lock);
isolated_pageblocks = has_isolate_pageblock(zone);
- nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
- if (nr_scanned)
- __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
while (count) {
struct page *page;
@@ -1159,12 +1155,7 @@
unsigned int order,
int migratetype)
{
- unsigned long nr_scanned;
spin_lock(&zone->lock);
- nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
- if (nr_scanned)
- __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
-
if (unlikely(has_isolate_pageblock(zone) ||
is_migrate_isolate(migratetype))) {
migratetype = get_pfnblock_migratetype(page, pfn);
@@ -3501,19 +3492,12 @@
}
/*
- * Maximum number of reclaim retries without any progress before OOM killer
- * is consider as the only way to move forward.
- */
-#define MAX_RECLAIM_RETRIES 16
-
-/*
* Checks whether it makes sense to retry the reclaim to make a forward progress
* for the given allocation request.
- * The reclaim feedback represented by did_some_progress (any progress during
- * the last reclaim round) and no_progress_loops (number of reclaim rounds without
- * any progress in a row) is considered as well as the reclaimable pages on the
- * applicable zone list (with a backoff mechanism which is a function of
- * no_progress_loops).
+ *
+ * We give up when we either have tried MAX_RECLAIM_RETRIES in a row
+ * without success, or when we couldn't even meet the watermark if we
+ * reclaimed all remaining pages on the LRU lists.
*
* Returns true if a retry is viable or false to enter the oom path.
*/
@@ -3556,13 +3540,11 @@
unsigned long reclaimable;
available = reclaimable = zone_reclaimable_pages(zone);
- available -= DIV_ROUND_UP((*no_progress_loops) * available,
- MAX_RECLAIM_RETRIES);
available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
/*
- * Would the allocation succeed if we reclaimed the whole
- * available?
+ * Would the allocation succeed if we reclaimed all
+ * reclaimable pages?
*/
if (__zone_watermark_ok(zone, order, min_wmark_pages(zone),
ac_classzone_idx(ac), alloc_flags, available)) {
@@ -4442,7 +4424,6 @@
#endif
" writeback_tmp:%lukB"
" unstable:%lukB"
- " pages_scanned:%lu"
" all_unreclaimable? %s"
"\n",
pgdat->node_id,
@@ -4465,8 +4446,8 @@
#endif
K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
- node_page_state(pgdat, NR_PAGES_SCANNED),
- !pgdat_reclaimable(pgdat) ? "yes" : "no");
+ pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES ?
+ "yes" : "no");
}
for_each_populated_zone(zone) {
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 7b5848cf..bb18b47 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -235,12 +235,6 @@
return nr;
}
-bool pgdat_reclaimable(struct pglist_data *pgdat)
-{
- return node_page_state_snapshot(pgdat, NR_PAGES_SCANNED) <
- pgdat_reclaimable_pages(pgdat) * 6;
-}
-
/**
* lruvec_lru_size - Returns the number of pages on the given LRU list.
* @lruvec: lru vector
@@ -1495,7 +1489,7 @@
*
* Appropriate locks must be held before calling this function.
*
- * @nr_to_scan: The number of pages to look through on the list.
+ * @nr_to_scan: The number of eligible pages to look through on the list.
* @lruvec: The LRU vector to pull pages from.
* @dst: The temp list to put pages on to.
* @nr_scanned: The number of pages that were scanned.
@@ -1514,11 +1508,14 @@
unsigned long nr_taken = 0;
unsigned long nr_zone_taken[MAX_NR_ZONES] = { 0 };
unsigned long nr_skipped[MAX_NR_ZONES] = { 0, };
- unsigned long scan, nr_pages;
+ unsigned long skipped = 0;
+ unsigned long scan, total_scan, nr_pages;
LIST_HEAD(pages_skipped);
- for (scan = 0; scan < nr_to_scan && nr_taken < nr_to_scan &&
- !list_empty(src);) {
+ scan = 0;
+ for (total_scan = 0;
+ scan < nr_to_scan && nr_taken < nr_to_scan && !list_empty(src);
+ total_scan++) {
struct page *page;
page = lru_to_page(src);
@@ -1533,11 +1530,12 @@
}
/*
- * Account for scanned and skipped separetly to avoid the pgdat
- * being prematurely marked unreclaimable by pgdat_reclaimable.
+ * Do not count skipped pages because that makes the function
+ * return with no isolated pages if the LRU mostly contains
+ * ineligible pages. This causes the VM to not reclaim any
+ * pages, triggering a premature OOM.
*/
scan++;
-
switch (__isolate_lru_page(page, mode)) {
case 0:
nr_pages = hpage_nr_pages(page);
@@ -1565,28 +1563,20 @@
*/
if (!list_empty(&pages_skipped)) {
int zid;
- unsigned long total_skipped = 0;
+ list_splice(&pages_skipped, src);
for (zid = 0; zid < MAX_NR_ZONES; zid++) {
if (!nr_skipped[zid])
continue;
__count_zid_vm_events(PGSCAN_SKIP, zid, nr_skipped[zid]);
- total_skipped += nr_skipped[zid];
+ skipped += nr_skipped[zid];
}
-
- /*
- * Account skipped pages as a partial scan as the pgdat may be
- * close to unreclaimable. If the LRU list is empty, account
- * skipped pages as a full scan.
- */
- scan += list_empty(src) ? total_skipped : total_skipped >> 2;
-
- list_splice(&pages_skipped, src);
}
- *nr_scanned = scan;
- trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan,
- nr_taken, mode, is_file_lru(lru));
+ *nr_scanned = total_scan;
+ trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan,
+ total_scan, skipped, nr_taken, mode,
+ is_file_lru(lru));
update_lru_sizes(lruvec, lru, nr_zone_taken);
return nr_taken;
}
@@ -1849,7 +1839,6 @@
reclaim_stat->recent_scanned[file] += nr_taken;
if (global_reclaim(sc)) {
- __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
if (current_is_kswapd())
__count_vm_events(PGSCAN_KSWAPD, nr_scanned);
else
@@ -2038,8 +2027,6 @@
__mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
reclaim_stat->recent_scanned[file] += nr_taken;
- if (global_reclaim(sc))
- __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
__count_vm_events(PGREFILL, nr_scanned);
spin_unlock_irq(&pgdat->lru_lock);
@@ -2199,30 +2186,8 @@
unsigned long anon_prio, file_prio;
enum scan_balance scan_balance;
unsigned long anon, file;
- bool force_scan = false;
unsigned long ap, fp;
enum lru_list lru;
- bool some_scanned;
- int pass;
-
- /*
- * If the zone or memcg is small, nr[l] can be 0. This
- * results in no scanning on this priority and a potential
- * priority drop. Global direct reclaim can go to the next
- * zone and tends to have no problems. Global kswapd is for
- * zone balancing and it needs to scan a minimum amount. When
- * reclaiming for a memcg, a priority drop can cause high
- * latencies, so it's better to scan a minimum amount there as
- * well.
- */
- if (current_is_kswapd()) {
- if (!pgdat_reclaimable(pgdat))
- force_scan = true;
- if (!mem_cgroup_online(memcg))
- force_scan = true;
- }
- if (!global_reclaim(sc))
- force_scan = true;
/* If we have no swap space, do not bother scanning anon pages. */
if (!sc->may_swap || mem_cgroup_get_nr_swap_pages(memcg) <= 0) {
@@ -2354,55 +2319,48 @@
fraction[1] = fp;
denominator = ap + fp + 1;
out:
- some_scanned = false;
- /* Only use force_scan on second pass. */
- for (pass = 0; !some_scanned && pass < 2; pass++) {
- *lru_pages = 0;
- for_each_evictable_lru(lru) {
- int file = is_file_lru(lru);
- unsigned long size;
- unsigned long scan;
+ *lru_pages = 0;
+ for_each_evictable_lru(lru) {
+ int file = is_file_lru(lru);
+ unsigned long size;
+ unsigned long scan;
- size = lruvec_lru_size(lruvec, lru, sc->reclaim_idx);
- scan = size >> sc->priority;
+ size = lruvec_lru_size(lruvec, lru, sc->reclaim_idx);
+ scan = size >> sc->priority;
+ /*
+ * If the cgroup's already been deleted, make sure to
+ * scrape out the remaining cache.
+ */
+ if (!scan && !mem_cgroup_online(memcg))
+ scan = min(size, SWAP_CLUSTER_MAX);
- if (!scan && pass && force_scan)
- scan = min(size, SWAP_CLUSTER_MAX);
-
- switch (scan_balance) {
- case SCAN_EQUAL:
- /* Scan lists relative to size */
- break;
- case SCAN_FRACT:
- /*
- * Scan types proportional to swappiness and
- * their relative recent reclaim efficiency.
- */
- scan = div64_u64(scan * fraction[file],
- denominator);
- break;
- case SCAN_FILE:
- case SCAN_ANON:
- /* Scan one type exclusively */
- if ((scan_balance == SCAN_FILE) != file) {
- size = 0;
- scan = 0;
- }
- break;
- default:
- /* Look ma, no brain */
- BUG();
- }
-
- *lru_pages += size;
- nr[lru] = scan;
-
+ switch (scan_balance) {
+ case SCAN_EQUAL:
+ /* Scan lists relative to size */
+ break;
+ case SCAN_FRACT:
/*
- * Skip the second pass and don't force_scan,
- * if we found something to scan.
+ * Scan types proportional to swappiness and
+ * their relative recent reclaim efficiency.
*/
- some_scanned |= !!scan;
+ scan = div64_u64(scan * fraction[file],
+ denominator);
+ break;
+ case SCAN_FILE:
+ case SCAN_ANON:
+ /* Scan one type exclusively */
+ if ((scan_balance == SCAN_FILE) != file) {
+ size = 0;
+ scan = 0;
+ }
+ break;
+ default:
+ /* Look ma, no brain */
+ BUG();
}
+
+ *lru_pages += size;
+ nr[lru] = scan;
}
}
@@ -2704,6 +2662,15 @@
} while (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
sc->nr_scanned - nr_scanned, sc));
+ /*
+ * Kswapd gives up on balancing particular nodes after too
+ * many failures to reclaim anything from them and goes to
+ * sleep. On reclaim progress, reset the failure counter. A
+ * successful direct reclaim run will revive a dormant kswapd.
+ */
+ if (reclaimable)
+ pgdat->kswapd_failures = 0;
+
return reclaimable;
}
@@ -2778,10 +2745,6 @@
GFP_KERNEL | __GFP_HARDWALL))
continue;
- if (sc->priority != DEF_PRIORITY &&
- !pgdat_reclaimable(zone->zone_pgdat))
- continue; /* Let kswapd poll it */
-
/*
* If we already have plenty of memory free for
* compaction in this zone, don't free any more.
@@ -2918,7 +2881,7 @@
return 0;
}
-static bool pfmemalloc_watermark_ok(pg_data_t *pgdat)
+static bool allow_direct_reclaim(pg_data_t *pgdat)
{
struct zone *zone;
unsigned long pfmemalloc_reserve = 0;
@@ -2926,10 +2889,15 @@
int i;
bool wmark_ok;
+ if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
+ return true;
+
for (i = 0; i <= ZONE_NORMAL; i++) {
zone = &pgdat->node_zones[i];
- if (!managed_zone(zone) ||
- pgdat_reclaimable_pages(pgdat) == 0)
+ if (!managed_zone(zone))
+ continue;
+
+ if (!zone_reclaimable_pages(zone))
continue;
pfmemalloc_reserve += min_wmark_pages(zone);
@@ -3006,7 +2974,7 @@
/* Throttle based on the first usable node */
pgdat = zone->zone_pgdat;
- if (pfmemalloc_watermark_ok(pgdat))
+ if (allow_direct_reclaim(pgdat))
goto out;
break;
}
@@ -3028,14 +2996,14 @@
*/
if (!(gfp_mask & __GFP_FS)) {
wait_event_interruptible_timeout(pgdat->pfmemalloc_wait,
- pfmemalloc_watermark_ok(pgdat), HZ);
+ allow_direct_reclaim(pgdat), HZ);
goto check_pending;
}
/* Throttle until kswapd wakes the process */
wait_event_killable(zone->zone_pgdat->pfmemalloc_wait,
- pfmemalloc_watermark_ok(pgdat));
+ allow_direct_reclaim(pgdat));
check_pending:
if (fatal_signal_pending(current))
@@ -3185,21 +3153,44 @@
} while (memcg);
}
-static bool zone_balanced(struct zone *zone, int order, int classzone_idx)
+/*
+ * Returns true if there is an eligible zone balanced for the request order
+ * and classzone_idx
+ */
+static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
{
- unsigned long mark = high_wmark_pages(zone);
+ int i;
+ unsigned long mark = -1;
+ struct zone *zone;
- if (!zone_watermark_ok_safe(zone, order, mark, classzone_idx))
- return false;
+ for (i = 0; i <= classzone_idx; i++) {
+ zone = pgdat->node_zones + i;
+
+ if (!managed_zone(zone))
+ continue;
+
+ mark = high_wmark_pages(zone);
+ if (zone_watermark_ok_safe(zone, order, mark, classzone_idx))
+ return true;
+ }
/*
- * If any eligible zone is balanced then the node is not considered
- * to be congested or dirty
+ * If a node has no populated zone within classzone_idx, it does not
+ * need balancing by definition. This can happen if a zone-restricted
+ * allocation tries to wake a remote kswapd.
*/
- clear_bit(PGDAT_CONGESTED, &zone->zone_pgdat->flags);
- clear_bit(PGDAT_DIRTY, &zone->zone_pgdat->flags);
+ if (mark == -1)
+ return true;
- return true;
+ return false;
+}
+
+/* Clear pgdat state for congested, dirty or under writeback. */
+static void clear_pgdat_congested(pg_data_t *pgdat)
+{
+ clear_bit(PGDAT_CONGESTED, &pgdat->flags);
+ clear_bit(PGDAT_DIRTY, &pgdat->flags);
+ clear_bit(PGDAT_WRITEBACK, &pgdat->flags);
}
/*
@@ -3210,11 +3201,9 @@
*/
static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, int classzone_idx)
{
- int i;
-
/*
* The throttled processes are normally woken up in balance_pgdat() as
- * soon as pfmemalloc_watermark_ok() is true. But there is a potential
+ * soon as allow_direct_reclaim() is true. But there is a potential
* race between when kswapd checks the watermarks and a process gets
* throttled. There is also a potential race if processes get
* throttled, kswapd wakes, a large process exits thereby balancing the
@@ -3228,17 +3217,16 @@
if (waitqueue_active(&pgdat->pfmemalloc_wait))
wake_up_all(&pgdat->pfmemalloc_wait);
- for (i = 0; i <= classzone_idx; i++) {
- struct zone *zone = pgdat->node_zones + i;
+ /* Hopeless node, leave it to direct reclaim */
+ if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
+ return true;
- if (!managed_zone(zone))
- continue;
-
- if (!zone_balanced(zone, order, classzone_idx))
- return false;
+ if (pgdat_balanced(pgdat, order, classzone_idx)) {
+ clear_pgdat_congested(pgdat);
+ return true;
}
- return true;
+ return false;
}
/*
@@ -3314,9 +3302,9 @@
count_vm_event(PAGEOUTRUN);
do {
+ unsigned long nr_reclaimed = sc.nr_reclaimed;
bool raise_priority = true;
- sc.nr_reclaimed = 0;
sc.reclaim_idx = classzone_idx;
/*
@@ -3341,23 +3329,12 @@
}
/*
- * Only reclaim if there are no eligible zones. Check from
- * high to low zone as allocations prefer higher zones.
- * Scanning from low to high zone would allow congestion to be
- * cleared during a very small window when a small low
- * zone was balanced even under extreme pressure when the
- * overall node may be congested. Note that sc.reclaim_idx
- * is not used as buffer_heads_over_limit may have adjusted
- * it.
+ * Only reclaim if there are no eligible zones. Note that
+ * sc.reclaim_idx is not used as buffer_heads_over_limit may
+ * have adjusted it.
*/
- for (i = classzone_idx; i >= 0; i--) {
- zone = pgdat->node_zones + i;
- if (!managed_zone(zone))
- continue;
-
- if (zone_balanced(zone, sc.order, classzone_idx))
- goto out;
- }
+ if (pgdat_balanced(pgdat, sc.order, classzone_idx))
+ goto out;
/*
* Do some background aging of the anon list, to give
@@ -3371,7 +3348,7 @@
* If we're getting trouble reclaiming, start doing writepage
* even in laptop mode.
*/
- if (sc.priority < DEF_PRIORITY - 2 || !pgdat_reclaimable(pgdat))
+ if (sc.priority < DEF_PRIORITY - 2)
sc.may_writepage = 1;
/* Call soft limit reclaim before calling shrink_node. */
@@ -3395,7 +3372,7 @@
* able to safely make forward progress. Wake them
*/
if (waitqueue_active(&pgdat->pfmemalloc_wait) &&
- pfmemalloc_watermark_ok(pgdat))
+ allow_direct_reclaim(pgdat))
wake_up_all(&pgdat->pfmemalloc_wait);
/* Check if kswapd should be suspending */
@@ -3406,10 +3383,14 @@
* Raise priority if scanning rate is too low or there was no
* progress in reclaiming pages
*/
- if (raise_priority || !sc.nr_reclaimed)
+ nr_reclaimed = sc.nr_reclaimed - nr_reclaimed;
+ if (raise_priority || !nr_reclaimed)
sc.priority--;
} while (sc.priority >= 1);
+ if (!sc.nr_reclaimed)
+ pgdat->kswapd_failures++;
+
out:
/*
* Return the order kswapd stopped reclaiming at as
@@ -3420,6 +3401,22 @@
return sc.order;
}
+/*
+ * pgdat->kswapd_classzone_idx is the highest zone index that a recent
+ * allocation request woke kswapd for. When kswapd has not woken recently,
+ * the value is MAX_NR_ZONES which is not a valid index. This compares a
+ * given classzone and returns it or the highest classzone index kswapd
+ * was recently woke for.
+ */
+static enum zone_type kswapd_classzone_idx(pg_data_t *pgdat,
+ enum zone_type classzone_idx)
+{
+ if (pgdat->kswapd_classzone_idx == MAX_NR_ZONES)
+ return classzone_idx;
+
+ return max(pgdat->kswapd_classzone_idx, classzone_idx);
+}
+
static void kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order,
unsigned int classzone_idx)
{
@@ -3431,7 +3428,13 @@
prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
- /* Try to sleep for a short interval */
+ /*
+ * Try to sleep for a short interval. Note that kcompactd will only be
+ * woken if it is possible to sleep for a short interval. This is
+ * deliberate on the assumption that if reclaim cannot keep an
+ * eligible zone balanced that it's also unlikely that compaction will
+ * succeed.
+ */
if (prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) {
/*
* Compaction records what page blocks it recently failed to
@@ -3455,7 +3458,7 @@
* the previous request that slept prematurely.
*/
if (remaining) {
- pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx);
+ pgdat->kswapd_classzone_idx = kswapd_classzone_idx(pgdat, classzone_idx);
pgdat->kswapd_order = max(pgdat->kswapd_order, reclaim_order);
}
@@ -3509,7 +3512,8 @@
*/
static int kswapd(void *p)
{
- unsigned int alloc_order, reclaim_order, classzone_idx;
+ unsigned int alloc_order, reclaim_order;
+ unsigned int classzone_idx = MAX_NR_ZONES - 1;
pg_data_t *pgdat = (pg_data_t*)p;
struct task_struct *tsk = current;
@@ -3539,20 +3543,23 @@
tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
set_freezable();
- pgdat->kswapd_order = alloc_order = reclaim_order = 0;
- pgdat->kswapd_classzone_idx = classzone_idx = 0;
+ pgdat->kswapd_order = 0;
+ pgdat->kswapd_classzone_idx = MAX_NR_ZONES;
for ( ; ; ) {
bool ret;
+ alloc_order = reclaim_order = pgdat->kswapd_order;
+ classzone_idx = kswapd_classzone_idx(pgdat, classzone_idx);
+
kswapd_try_sleep:
kswapd_try_to_sleep(pgdat, alloc_order, reclaim_order,
classzone_idx);
/* Read the new order and classzone_idx */
alloc_order = reclaim_order = pgdat->kswapd_order;
- classzone_idx = pgdat->kswapd_classzone_idx;
+ classzone_idx = kswapd_classzone_idx(pgdat, 0);
pgdat->kswapd_order = 0;
- pgdat->kswapd_classzone_idx = 0;
+ pgdat->kswapd_classzone_idx = MAX_NR_ZONES;
ret = try_to_freeze();
if (kthread_should_stop())
@@ -3578,9 +3585,6 @@
reclaim_order = balance_pgdat(pgdat, alloc_order, classzone_idx);
if (reclaim_order < alloc_order)
goto kswapd_try_sleep;
-
- alloc_order = reclaim_order = pgdat->kswapd_order;
- classzone_idx = pgdat->kswapd_classzone_idx;
}
tsk->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD);
@@ -3596,7 +3600,6 @@
void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
{
pg_data_t *pgdat;
- int z;
if (!managed_zone(zone))
return;
@@ -3604,22 +3607,20 @@
if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL))
return;
pgdat = zone->zone_pgdat;
- pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx);
+ pgdat->kswapd_classzone_idx = kswapd_classzone_idx(pgdat,
+ classzone_idx);
pgdat->kswapd_order = max(pgdat->kswapd_order, order);
if (!waitqueue_active(&pgdat->kswapd_wait))
return;
- /* Only wake kswapd if all zones are unbalanced */
- for (z = 0; z <= classzone_idx; z++) {
- zone = pgdat->node_zones + z;
- if (!managed_zone(zone))
- continue;
+ /* Hopeless node, leave it to direct reclaim */
+ if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
+ return;
- if (zone_balanced(zone, order, classzone_idx))
- return;
- }
+ if (pgdat_balanced(pgdat, order, classzone_idx))
+ return;
- trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, zone_idx(zone), order);
+ trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, classzone_idx, order);
wake_up_interruptible(&pgdat->kswapd_wait);
}
@@ -3879,9 +3880,6 @@
sum_zone_node_page_state(pgdat->node_id, NR_SLAB_RECLAIMABLE) <= pgdat->min_slab_pages)
return NODE_RECLAIM_FULL;
- if (!pgdat_reclaimable(pgdat))
- return NODE_RECLAIM_FULL;
-
/*
* Do not scan if the allocation should not be delayed.
*/
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 513c37a..2ab7973 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -954,7 +954,6 @@
"nr_unevictable",
"nr_isolated_anon",
"nr_isolated_file",
- "nr_pages_scanned",
"workingset_refault",
"workingset_activate",
"workingset_nodereclaim",
@@ -1379,7 +1378,6 @@
"\n min %lu"
"\n low %lu"
"\n high %lu"
- "\n node_scanned %lu"
"\n spanned %lu"
"\n present %lu"
"\n managed %lu",
@@ -1387,7 +1385,6 @@
min_wmark_pages(zone),
low_wmark_pages(zone),
high_wmark_pages(zone),
- node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED),
zone->spanned_pages,
zone->present_pages,
zone->managed_pages);
@@ -1426,7 +1423,7 @@
"\n node_unreclaimable: %u"
"\n start_pfn: %lu"
"\n node_inactive_ratio: %u",
- !pgdat_reclaimable(zone->zone_pgdat),
+ pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
zone->zone_start_pfn,
zone->zone_pgdat->inactive_ratio);
seq_putc(m, '\n');
@@ -1588,22 +1585,9 @@
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
val = atomic_long_read(&vm_zone_stat[i]);
if (val < 0) {
- switch (i) {
- case NR_PAGES_SCANNED:
- /*
- * This is often seen to go negative in
- * recent kernels, but not to go permanently
- * negative. Whilst it would be nicer not to
- * have exceptions, rooting them out would be
- * another task, of rather low priority.
- */
- break;
- default:
- pr_warn("%s: %s %ld\n",
- __func__, vmstat_text[i], val);
- err = -EINVAL;
- break;
- }
+ pr_warn("%s: %s %ld\n",
+ __func__, vmstat_text[i], val);
+ err = -EINVAL;
}
}
if (err)
diff --git a/net/core/dst.c b/net/core/dst.c
index 39cc119..b5de366 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -349,8 +349,15 @@
new = ((unsigned long) &dst_default_metrics) | DST_METRICS_READ_ONLY;
prev = cmpxchg(&dst->_metrics, old, new);
- if (prev == old)
- kfree(__DST_METRICS_PTR(old));
+ if (prev == old) {
+ struct dst_metrics *old_p = (struct dst_metrics *)
+ __DST_METRICS_PTR(old);
+
+ if (prev & DST_METRICS_REFCOUNTED) {
+ if (atomic_dec_and_test(&old_p->refcnt))
+ kfree(old_p);
+ }
+ }
}
EXPORT_SYMBOL(__dst_destroy_metrics_generic);