Merge "msm: secure_buffer: Add SPSS_HLOS_SHARED vmid"
diff --git a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
index ce2d8bd..1114308 100644
--- a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
@@ -2,12 +2,15 @@
Required properties:
-compatible : Should be one of
- To communicate with modem
+ To communicate with adsp
qcom,smp2pgpio_client_rdbg_2_in (inbound)
qcom,smp2pgpio_client_rdbg_2_out (outbound)
To communicate with modem
qcom,smp2pgpio_client_rdbg_1_in (inbound)
qcom,smp2pgpio_client_rdbg_1_out (outbound)
+ To communicate with cdsp
+ qcom,smp2pgpio_client_rdbg_5_in (inbound)
+ qcom,smp2pgpio_client_rdbg_5_out (outbound)
-gpios : the relevant gpio pins of the entry.
Example:
diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt
index c801e848..700a8f7 100644
--- a/Documentation/devicetree/bindings/cnss/icnss.txt
+++ b/Documentation/devicetree/bindings/cnss/icnss.txt
@@ -28,6 +28,7 @@
- qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
- qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs.
- qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
+ - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory
Example:
@@ -54,6 +55,7 @@
<0 140 0 /* CE10 */ >,
<0 141 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x200000>;
+ qcom,wlan-msa-fixed-region = <&wlan_msa_mem>;
qcom,smmu-s1-bypass;
vdd-0.8-cx-mx-supply = <&pm8998_l5>;
qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 375eaf2..196f6f7 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -91,6 +91,11 @@
a four level page table configuration. Set to use a three
level page table instead.
+- qcom,no-asid-retention:
+ Some hardware may lose internal state for asid after
+ retention. No cache invalidation operations involving asid
+ may be used.
+
- clocks : List of clocks to be used during SMMU register access. See
Documentation/devicetree/bindings/clock/clock-bindings.txt
for information about the format. For each clock specified
diff --git a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
index 937ccb9..58bac0b 100644
--- a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
@@ -120,6 +120,8 @@
minimum allowable length configuration value.
- qcom,sde-ubwc-swizzle: A u32 property to specify the default UBWC
swizzle configuration value.
+- qcom,rot-reg-bus: Property to provide Bus scaling for register
+ access for rotator blocks.
Subnode properties:
- compatible: Compatible name used in smmu v2.
@@ -189,6 +191,16 @@
cache-slice-names = "rotator";
cache-slices = <&llcc 4>;
+ rot_reg: qcom,rot-reg-bus {
+ qcom,msm-bus,name = "mdss_rot_reg";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <1 590 0 0>,
+ <1 590 0 76800>;
+ };
+
smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
compatible = "qcom,smmu_sde_rot_unsec";
iommus = <&mdp_smmu 0xe00>;
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index a9480be..6109fad 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -152,6 +152,7 @@
and reset lines used by this controller.
- reset-names: reset signal name strings sorted in the same order as the resets
property.
+ - qcom,qusb-phy-reg-offset: Provides important phy register offsets in an order defined in phy driver.
Optional properties:
- reg-names: Additional registers corresponding with the following:
@@ -174,7 +175,6 @@
- qcom,hold-reset: Indicates that hold QUSB PHY into reset state.
- qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided.
- qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0
- - qcom,phy-auto-resume-offset: Provides phy auto-resume register offset.
Example:
qusb_phy: qusb@f9b39000 {
@@ -185,6 +185,13 @@
vdda18-supply = <&pm8994_l6>;
vdda33-supply = <&pm8994_l24>;
qcom,vdd-voltage-level = <1 5 7>;
+ qcom,qusb-phy-reg-offset =
+ <0x240 /* QUSB2PHY_PORT_TUNE1 */
+ 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */
+ 0x210 /* QUSB2PHY_PWR_CTRL1 */
+ 0x230 /* QUSB2PHY_INTR_CTRL */
+ 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */
+ 0x254>; /* QUSB2PHY_TEST1 */
qcom,efuse-bit-pos = <21>;
qcom,efuse-num-bits = <3>;
diff --git a/Documentation/misc-devices/qcom_invoke_driver.txt b/Documentation/misc-devices/qcom_invoke_driver.txt
new file mode 100644
index 0000000..38c976a
--- /dev/null
+++ b/Documentation/misc-devices/qcom_invoke_driver.txt
@@ -0,0 +1,54 @@
+Introduction:
+=============
+Invoke driver is a misc driver which helps communication between non secure
+and secure world. Invoke driver communicates with secure side using SCM
+driver. To use invoke driver, open must be called on invoke device i.e.
+/dev/invoke. Invoke driver exposes only one IOCTL invoke which passes
+userspace request to TZ.
+
+SW Architecture
+===============
+Following is SW stack for Invoke driver.
+
++++++++++++++++++++++++++++++++++++++++++
++ Applications +
++++++++++++++++++++++++++++++++++++++++++
++ System Layer +
++++++++++++++++++++++++++++++++++++++++++
++ Kernel +
++ +++++++++++++++++++ +
++ + Invoke driver + +
++ +++++++++++++++++++ +
++ + SCM Driver + +
++++++++++++++++++++++++++++++++++++++++++
+ ||
+ ||
+ \/
++++++++++++++++++++++++++++++++++++++++++
++ Trust Zone +
++ +++++++++++ +++++++++++ +
++ + TZ App1 + + TZ App2 + +
++++++++++++++++++++++++++++++++++++++++++
+
+
+Interfaces
+==========
+Invoke driver exposes INVOKE_IOCTL_INVOKE_REQ IOCTL for userspace to
+communicate with driver. More details of IOCTL are avilable in
+corresponding header file.
+
+
+Driver Parameters
+=================
+This driver is built and statically linked into the kernel; therefore,
+there are no module parameters supported by this driver.
+
+There are no kernel command line parameters supported by this driver.
+
+Power Management
+================
+TBD
+
+Dependencies
+============
+Invoke driver depends on SCM driver to communicate with TZ.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d04e168..e06ecbb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -230,6 +230,9 @@
config ARCH_MTD_XIP
bool
+config ARCH_WANT_KMAP_ATOMIC_FLUSH
+ bool
+
config VECTORS_BASE
hex
default 0xffff0000 if MMU || CPU_HIGH_VECTOR
@@ -567,6 +570,7 @@
select SPARSE_IRQ
select USE_OF
select PINCTRL
+ select ARCH_WANT_KMAP_ATOMIC_FLUSH
help
Support for Qualcomm MSM/QSD based systems. This runs on the
apps processor of the MSM/QSD and depends on a shared memory
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index d02f818..5d73327 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
@@ -147,3 +148,58 @@ void *kmap_atomic_pfn(unsigned long pfn)
return (void *)vaddr;
}
+
+#ifdef CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH
+static void kmap_remove_unused_cpu(int cpu)
+{
+ int start_idx, idx, type;
+
+ pagefault_disable();
+ type = kmap_atomic_idx();
+ start_idx = type + 1 + KM_TYPE_NR * cpu;
+
+ for (idx = start_idx; idx < KM_TYPE_NR + KM_TYPE_NR * cpu; idx++) {
+ unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ pte_t ptep;
+
+ ptep = get_top_pte(vaddr);
+ if (ptep)
+ set_top_pte(vaddr, __pte(0));
+ }
+ pagefault_enable();
+}
+
+static void kmap_remove_unused(void *unused)
+{
+ kmap_remove_unused_cpu(smp_processor_id());
+}
+
+void kmap_atomic_flush_unused(void)
+{
+ on_each_cpu(kmap_remove_unused, NULL, 1);
+}
+
+static int hotplug_kmap_atomic_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ switch (action & (~CPU_TASKS_FROZEN)) {
+ case CPU_DYING:
+ kmap_remove_unused_cpu((int)hcpu);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block hotplug_kmap_atomic_notifier = {
+ .notifier_call = hotplug_kmap_atomic_callback,
+};
+
+static int __init init_kmap_atomic(void)
+{
+ return register_hotcpu_notifier(&hotplug_kmap_atomic_notifier);
+}
+early_initcall(init_kmap_atomic);
+#endif
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 84867ba..842c38a 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -108,6 +108,7 @@
select POWER_SUPPLY
select SPARSE_IRQ
select SYSCTL_EXCEPTION_TRACE
+ select THREAD_INFO_IN_TASK
help
ARM 64-bit (AArch64) Linux support.
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 9b20651..20288fe 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -2,16 +2,27 @@
dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb
-
ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
dtbo-$(CONFIG_ARCH_SDM845) += \
sdm845-cdp-overlay.dtbo \
sdm845-mtp-overlay.dtbo \
- sdm845-qrd-overlay.dtbo
+ sdm845-qrd-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-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-mtp-overlay.dtbo-base := sdm845.dtb
sdm845-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-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
else
dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
sdm845-rumi.dtb \
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 1a2ca5b..02fedbe 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -65,6 +65,7 @@
#iommu-cells = <2>;
qcom,skip-init;
qcom,use-3-lvl-tables;
+ qcom,no-asid-retention;
#global-interrupts = <1>;
#size-cells = <1>;
#address-cells = <1>;
@@ -339,10 +340,10 @@
apps_iommu_coherent_test_device {
compatible = "iommu-debug-test";
/*
- * This SID belongs to QUP1-DMA. We can't use a fake SID for
+ * This SID belongs to TSIF. We can't use a fake SID for
* the apps_smmu device.
*/
- iommus = <&apps_smmu 0x3 0>;
+ iommus = <&apps_smmu 0x20 0>;
dma-coherent;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..0006937
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-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 4K Display Panel CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,msm-id = <321 0x0>;
+ 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-4k-panel-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
index 94d74e2..faf09c4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-cdp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..2675b96
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-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 4K Display Panel MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,msm-id = <321 0x0>;
+ 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-4k-panel-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
index fca87e1..2ae9345 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-mtp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..39c9d37
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
@@ -0,0 +1,32 @@
+/* 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 4K Display Panel QRD";
+ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+ qcom,msm-id = <321 0x0>;
+ qcom,board-id = <11 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
index 6171c7b..5951f6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-qrd.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 3ce5611..5fbb1db 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -572,6 +572,18 @@
qcom,prio = <2>;
};
+ mas_xm_pcie_0: mas-xm-pcie-0 {
+ cell-id = <MSM_BUS_MASTER_PCIE>;
+ label = "mas-xm-pcie-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,connections = <&slv_qns_pcie_a1noc_snoc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ };
+
mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg {
cell-id = <MSM_BUS_MASTER_A2NOC_CFG>;
label = "mas-qhm-a2noc-cfg";
@@ -648,18 +660,6 @@
qcom,prio = <2>;
};
- mas_xm_pcie_0: mas-xm-pcie-0 {
- cell-id = <MSM_BUS_MASTER_PCIE>;
- label = "mas-xm-pcie-0";
- qcom,buswidth = <8>;
- qcom,agg-ports = <1>;
- qcom,qport = <5>;
- qcom,connections = <&slv_qns_pcie_snoc>;
- qcom,bus-dev = <&fab_aggre1_noc>;
- qcom,ap-owned;
- qcom,prio = <2>;
- };
-
mas_xm_qdss_etr: mas-xm-qdss-etr {
cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
label = "mas-xm-qdss-etr";
@@ -715,6 +715,7 @@
qcom,agg-ports = <1>;
qcom,connections = <&slv_qns_camnoc_uncomp>;
qcom,bus-dev = <&fab_camnoc_virt>;
+ qcom,bcms = <&bcm_mm1>;
};
mas_qxm_camnoc_hf1_uncomp: mas-qxm-camnoc-hf1-uncomp {
@@ -724,6 +725,7 @@
qcom,agg-ports = <1>;
qcom,connections = <&slv_qns_camnoc_uncomp>;
qcom,bus-dev = <&fab_camnoc_virt>;
+ qcom,bcms = <&bcm_mm1>;
};
mas_qxm_camnoc_sf_uncomp: mas-qxm-camnoc-sf-uncomp {
@@ -733,6 +735,7 @@
qcom,agg-ports = <1>;
qcom,connections = <&slv_qns_camnoc_uncomp>;
qcom,bus-dev = <&fab_camnoc_virt>;
+ qcom,bcms = <&bcm_mm1>;
};
mas_qhm_spdm: mas-qhm-spdm {
@@ -1222,6 +1225,19 @@
qcom,prio = <2>;
};
+ mas_xm_gic: mas-xm-gic {
+ cell-id = <MSM_BUS_MASTER_GIC>;
+ label = "mas-xm-gic";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <0>;
+ qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn12>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
+ };
+
mas_alc: mas-alc {
cell-id = <MSM_BUS_MASTER_ALC>;
label = "mas-alc";
@@ -1315,6 +1331,15 @@
qcom,bcms = <&bcm_sn9>;
};
+ slv_qns_pcie_a1noc_snoc:slv-qns-pcie-a1noc-snoc {
+ cell-id = <MSM_BUS_SLAVE_ANOC_PCIE_A1NOC_SNOC>;
+ label = "slv-qns-pcie-a1noc-snoc";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,connections = <&mas_qnm_pcie_anoc>;
+ };
+
slv_qns_a2noc_snoc:slv-qns-a2noc-snoc {
cell-id = <MSM_BUS_A2NOC_SNOC_SLV>;
label = "slv-qns-a2noc-snoc";
@@ -1348,7 +1373,6 @@
qcom,buswidth = <32>;
qcom,agg-ports = <1>;
qcom,bus-dev = <&fab_camnoc_virt>;
- qcom,bcms = <&bcm_mm1>;
};
slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
index 4747c99..efc78e0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
@@ -15,9 +15,11 @@
#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"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp.dts
index 22e3aea..0a6aa5e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-cdp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
index 52c0f05..45941a1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
@@ -15,9 +15,11 @@
#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"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
index f7af60c..e74b342 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-mtp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
index 5729d76..6cead9d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
@@ -15,9 +15,11 @@
#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"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd.dts
index 228b924..6cb7815 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-qrd.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 3153e66..41c1876 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -369,6 +369,17 @@
cache-slice-names = "rotator";
cache-slices = <&llcc 4>;
+ /* reg bus scale settings */
+ rot_reg: qcom,rot-reg-bus {
+ qcom,msm-bus,name = "mdss_rot_reg";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <1 590 0 0>,
+ <1 590 0 76800>;
+ };
+
smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
compatible = "qcom,smmu_sde_rot_unsec";
iommus = <&apps_smmu 0x1090 0x0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index 53cb27e..ac16d03 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -113,13 +113,24 @@
/* Primary USB port related QUSB2 PHY */
qusb_phy0: qusb@88e2000 {
compatible = "qcom,qusb2phy-v2";
- reg = <0x088e2000 0x400>;
- reg-names = "qusb_phy_base";
+ reg = <0x088e2000 0x400>,
+ <0x007801e8 0x4>;
+ reg-names = "qusb_phy_base", "efuse_addr";
+ qcom,efuse-bit-pos = <25>;
+ qcom,efuse-num-bits = <3>;
vdd-supply = <&pm8998_l1>;
vdda18-supply = <&pm8998_l12>;
vdda33-supply = <&pm8998_l24>;
qcom,vdd-voltage-level = <0 880000 880000>;
+ qcom,qusb-phy-reg-offset =
+ <0x240 /* QUSB2PHY_PORT_TUNE1 */
+ 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */
+ 0x210 /* QUSB2PHY_PWR_CTRL1 */
+ 0x230 /* QUSB2PHY_INTR_CTRL */
+ 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */
+ 0x254>; /* QUSB2PHY_TEST1 */
+
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
<0x23 0x210 /* PWR_CTRL1 */
@@ -133,7 +144,7 @@
0x21 0x214 /* PWR_CTRL2 */
0x00 0x220 /* IMP_CTRL1 */
0x58 0x224 /* IMP_CTRL2 */
- 0x32 0x240 /* TUNE1 */
+ 0x30 0x240 /* TUNE1 */
0x29 0x244 /* TUNE2 */
0xca 0x248 /* TUNE3 */
0x04 0x24c /* TUNE4 */
@@ -141,8 +152,6 @@
0x00 0x23c /* CHG_CTRL2 */
0x22 0x210>; /* PWR_CTRL1 */
- qcom,phy-auto-resume-offset = <0x254>;
-
phy_type= "utmi";
clocks = <&clock_rpmh RPMH_CXO_CLK>,
<&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
@@ -385,6 +394,14 @@
vdda18-supply = <&pm8998_l12>;
vdda33-supply = <&pm8998_l24>;
qcom,vdd-voltage-level = <0 880000 880000>;
+ qcom,qusb-phy-reg-offset =
+ <0x240 /* QUSB2PHY_PORT_TUNE1 */
+ 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */
+ 0x210 /* QUSB2PHY_PWR_CTRL1 */
+ 0x230 /* QUSB2PHY_INTR_CTRL */
+ 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */
+ 0x254>; /* QUSB2PHY_TEST1 */
+
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
<0x23 0x210 /* PWR_CTRL1 */
@@ -398,7 +415,7 @@
0x21 0x214 /* PWR_CTRL2 */
0x00 0x220 /* IMP_CTRL1 */
0x58 0x224 /* IMP_CTRL2 */
- 0x32 0x240 /* TUNE1 */
+ 0x20 0x240 /* TUNE1 */
0x29 0x244 /* TUNE2 */
0xca 0x248 /* TUNE3 */
0x04 0x24c /* TUNE4 */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts
new file mode 100644
index 0000000..3cd7678
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts
@@ -0,0 +1,31 @@
+/* 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 CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <1 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts
index 8ab0593..66ee4c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-cdp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts
new file mode 100644
index 0000000..e049357
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts
@@ -0,0 +1,31 @@
+/* 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 MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts
index 57c3e71..cea38e6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-mtp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts
new file mode 100644
index 0000000..a5a32ab
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts
@@ -0,0 +1,31 @@
+/* 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 QRD";
+ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <11 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
index 8a9a544..9a87617 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-qrd.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.dts
new file mode 100644
index 0000000..d36d0fd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dts
@@ -0,0 +1,21 @@
+/* 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 "sdm845-v2.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 v2 SoC";
+ compatible = "qcom,sdm845";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 78036eb..1944014 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -476,6 +476,10 @@
method = "smc";
};
+ chosen {
+ bootargs = "rcupdate.rcu_expedited=1";
+ };
+
soc: soc { };
vendor: vendor {
@@ -641,7 +645,6 @@
#include "sdm845-sde-pll.dtsi"
#include "msm-rdbg.dtsi"
#include "sdm845-sde.dtsi"
-#include "sdm845-sde-display.dtsi"
#include "sdm845-qupv3.dtsi"
&soc {
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 14243fb..b8f115b 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -86,7 +86,6 @@
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_BOOST=y
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
-CONFIG_CPU_FREQ_MSM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 9f98841..992a30b 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -264,9 +264,15 @@
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WIL6210=m
# CONFIG_WIL6210_TRACING is not set
@@ -514,6 +520,7 @@
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_CDSP_LOADER=y
CONFIG_MSM_AVTIMER=y
+CONFIG_QCOM_SMCINVOKE=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_MSM_QBT1000=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index cd4cbb1..d7f2629 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -271,9 +271,15 @@
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WIL6210=m
CONFIG_WCNSS_MEM_PRE_ALLOC=y
@@ -532,6 +538,7 @@
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_CDSP_LOADER=y
CONFIG_MSM_AVTIMER=y
+CONFIG_QCOM_SMCINVOKE=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_MSM_QBT1000=y
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 44e1d7f..28196b1 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -1,7 +1,6 @@
generic-y += bugs.h
generic-y += clkdev.h
generic-y += cputime.h
-generic-y += current.h
generic-y += delay.h
generic-y += div64.h
generic-y += dma.h
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index a4ae545..ef5970e 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -241,14 +241,25 @@ lr .req x30 // link register
.endm
/*
+ * @dst: Result of per_cpu(sym, smp_processor_id())
* @sym: The name of the per-cpu variable
- * @reg: Result of per_cpu(sym, smp_processor_id())
* @tmp: scratch register
*/
- .macro this_cpu_ptr, sym, reg, tmp
- adr_l \reg, \sym
+ .macro adr_this_cpu, dst, sym, tmp
+ adr_l \dst, \sym
mrs \tmp, tpidr_el1
- add \reg, \reg, \tmp
+ add \dst, \dst, \tmp
+ .endm
+
+ /*
+ * @dst: Result of READ_ONCE(per_cpu(sym, smp_processor_id()))
+ * @sym: The name of the per-cpu variable
+ * @tmp: scratch register
+ */
+ .macro ldr_this_cpu dst, sym, tmp
+ adr_l \dst, \sym
+ mrs \tmp, tpidr_el1
+ ldr \dst, [\dst, \tmp]
.endm
/*
diff --git a/arch/arm64/include/asm/current.h b/arch/arm64/include/asm/current.h
new file mode 100644
index 0000000..86c4041
--- /dev/null
+++ b/arch/arm64/include/asm/current.h
@@ -0,0 +1,30 @@
+#ifndef __ASM_CURRENT_H
+#define __ASM_CURRENT_H
+
+#include <linux/compiler.h>
+
+#include <asm/sysreg.h>
+
+#ifndef __ASSEMBLY__
+
+struct task_struct;
+
+/*
+ * We don't use read_sysreg() as we want the compiler to cache the value where
+ * possible.
+ */
+static __always_inline struct task_struct *get_current(void)
+{
+ unsigned long sp_el0;
+
+ asm ("mrs %0, sp_el0" : "=r" (sp_el0));
+
+ return (struct task_struct *)sp_el0;
+}
+
+#define current get_current()
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_CURRENT_H */
+
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 0226447..d050d72 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -29,11 +29,22 @@
#ifndef __ASSEMBLY__
+#include <asm/percpu.h>
+
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/thread_info.h>
-#define raw_smp_processor_id() (current_thread_info()->cpu)
+DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
+
+/*
+ * We don't use this_cpu_read(cpu_number) as that has implicit writes to
+ * preempt_count, and associated (compiler) barriers, that we'd like to avoid
+ * the expense of. If we're preemptible, the value can be stale at use anyway.
+ * And we can't use this_cpu_ptr() either, as that winds up recursing back
+ * here under CONFIG_DEBUG_PREEMPT=y.
+ */
+#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
struct seq_file;
@@ -73,6 +84,7 @@ asmlinkage void secondary_start_kernel(void);
*/
struct secondary_data {
void *stack;
+ struct task_struct *task;
long status;
};
diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h
index b8a313f..de5600f 100644
--- a/arch/arm64/include/asm/suspend.h
+++ b/arch/arm64/include/asm/suspend.h
@@ -1,7 +1,7 @@
#ifndef __ASM_SUSPEND_H
#define __ASM_SUSPEND_H
-#define NR_CTX_REGS 10
+#define NR_CTX_REGS 12
#define NR_CALLEE_SAVED_REGS 12
/*
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index f3a0169..ebd18b7 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -43,50 +43,24 @@ typedef unsigned long mm_segment_t;
/*
* low level task data that entry.S needs immediate access to.
- * __switch_to() assumes cpu_context follows immediately after cpu_domain.
*/
struct thread_info {
unsigned long flags; /* low level flags */
mm_segment_t addr_limit; /* address limit */
- struct task_struct *task; /* main task structure */
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
u64 ttbr0; /* saved TTBR0_EL1 */
#endif
int preempt_count; /* 0 => preemptable, <0 => bug */
- int cpu; /* cpu */
};
#define INIT_THREAD_INFO(tsk) \
{ \
- .task = &tsk, \
- .flags = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
}
-#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
-/*
- * how to get the thread information struct from C
- */
-static inline struct thread_info *current_thread_info(void) __attribute_const__;
-
-/*
- * struct thread_info can be accessed directly via sp_el0.
- *
- * We don't use read_sysreg() as we want the compiler to cache the value where
- * possible.
- */
-static inline struct thread_info *current_thread_info(void)
-{
- unsigned long sp_el0;
-
- asm ("mrs %0, sp_el0" : "=r" (sp_el0));
-
- return (struct thread_info *)sp_el0;
-}
-
#define thread_saved_pc(tsk) \
((unsigned long)(tsk->thread.cpu_context.pc))
#define thread_saved_sp(tsk) \
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index fd1c4f6..b3bb7ef 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -36,12 +36,13 @@ int main(void)
{
DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
BLANK();
- DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
- DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
- DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
+ DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags));
+ DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count));
+ DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit));
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
- DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0));
+ DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0));
#endif
+ DEFINE(TSK_STACK, offsetof(struct task_struct, stack));
BLANK();
DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context));
BLANK();
@@ -124,6 +125,7 @@ int main(void)
DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime));
BLANK();
DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack));
+ DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task));
BLANK();
#ifdef CONFIG_KVM_ARM_HOST
DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt));
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index c44a933..718c4c8 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -93,9 +93,8 @@
.if \el == 0
mrs x21, sp_el0
- mov tsk, sp
- and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear,
- ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug
+ ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear,
+ ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug
disable_step_tsk x19, x20 // exceptions when scheduling.
mov x29, xzr // fp pointed to user-space
@@ -103,10 +102,10 @@
add x21, sp, #S_FRAME_SIZE
get_thread_info tsk
/* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
- ldr x20, [tsk, #TI_ADDR_LIMIT]
+ ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]
str x20, [sp, #S_ORIG_ADDR_LIMIT]
mov x20, #TASK_SIZE_64
- str x20, [tsk, #TI_ADDR_LIMIT]
+ str x20, [tsk, #TSK_TI_ADDR_LIMIT]
/* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */
.endif /* \el == 0 */
mrs x22, elr_el1
@@ -168,7 +167,7 @@
.if \el != 0
/* Restore the task's original addr_limit. */
ldr x20, [sp, #S_ORIG_ADDR_LIMIT]
- str x20, [tsk, #TI_ADDR_LIMIT]
+ str x20, [tsk, #TSK_TI_ADDR_LIMIT]
/* No need to restore UAO, it will be restored from SPSR_EL1 */
.endif
@@ -252,15 +251,16 @@
mov x19, sp // preserve the original sp
/*
- * Compare sp with the current thread_info, if the top
- * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and
- * should switch to the irq stack.
+ * Compare sp with the base of the task stack.
+ * If the top ~(THREAD_SIZE - 1) bits match, we are on a task stack,
+ * and should switch to the irq stack.
*/
- and x25, x19, #~(THREAD_SIZE - 1)
- cmp x25, tsk
- b.ne 9998f
+ ldr x25, [tsk, TSK_STACK]
+ eor x25, x25, x19
+ and x25, x25, #~(THREAD_SIZE - 1)
+ cbnz x25, 9998f
- this_cpu_ptr irq_stack, x25, x26
+ adr_this_cpu x25, irq_stack, x26
mov x26, #IRQ_STACK_START_SP
add x26, x25, x26
@@ -488,9 +488,9 @@
irq_handler
#ifdef CONFIG_PREEMPT
- ldr w24, [tsk, #TI_PREEMPT] // get preempt count
+ ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count
cbnz w24, 1f // preempt count != 0
- ldr x0, [tsk, #TI_FLAGS] // get flags
+ ldr x0, [tsk, #TSK_TI_FLAGS] // get flags
tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling?
bl el1_preempt
1:
@@ -505,7 +505,7 @@
el1_preempt:
mov x24, lr
1: bl preempt_schedule_irq // irq en/disable is done inside
- ldr x0, [tsk, #TI_FLAGS] // get new tasks TI_FLAGS
+ ldr x0, [tsk, #TSK_TI_FLAGS] // get new tasks TI_FLAGS
tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling?
ret x24
#endif
@@ -735,8 +735,7 @@
ldp x29, x9, [x8], #16
ldr lr, [x8]
mov sp, x9
- and x9, x9, #~(THREAD_SIZE - 1)
- msr sp_el0, x9
+ msr sp_el0, x1
ret
ENDPROC(cpu_switch_to)
@@ -747,7 +746,7 @@
ret_fast_syscall:
disable_irq // disable interrupts
str x0, [sp, #S_X0] // returned x0
- ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing
+ ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing
and x2, x1, #_TIF_SYSCALL_WORK
cbnz x2, ret_fast_syscall_trace
and x2, x1, #_TIF_WORK_MASK
@@ -767,14 +766,14 @@
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on // enabled while in userspace
#endif
- ldr x1, [tsk, #TI_FLAGS] // re-check for single-step
+ ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for single-step
b finish_ret_to_user
/*
* "slow" syscall return path.
*/
ret_to_user:
disable_irq // disable interrupts
- ldr x1, [tsk, #TI_FLAGS]
+ ldr x1, [tsk, #TSK_TI_FLAGS]
and x2, x1, #_TIF_WORK_MASK
cbnz x2, work_pending
finish_ret_to_user:
@@ -807,7 +806,7 @@
enable_dbg_and_irq
ct_user_exit 1
- ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks
+ ldr x16, [tsk, #TSK_TI_FLAGS] // check for syscall hooks
tst x16, #_TIF_SYSCALL_WORK
b.ne __sys_trace
cmp scno, sc_nr // check upper syscall limit
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index c7d26bb..7ee6d74 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -428,7 +428,8 @@
__primary_switched:
adrp x4, init_thread_union
add sp, x4, #THREAD_SIZE
- msr sp_el0, x4 // Save thread_info
+ adr_l x5, init_task
+ msr sp_el0, x5 // Save thread_info
adr_l x8, vectors // load VBAR_EL1 with virtual
msr vbar_el1, x8 // vector table address
@@ -699,10 +700,10 @@
isb
adr_l x0, secondary_data
- ldr x0, [x0, #CPU_BOOT_STACK] // get secondary_data.stack
- mov sp, x0
- and x0, x0, #~(THREAD_SIZE - 1)
- msr sp_el0, x0 // save thread_info
+ ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack
+ mov sp, x1
+ ldr x2, [x0, #CPU_BOOT_TASK]
+ msr sp_el0, x2
mov x29, #0
b secondary_start_kernel
ENDPROC(__secondary_switched)
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index fc1a286..5fe594e 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -45,6 +45,7 @@
#include <linux/personality.h>
#include <linux/notifier.h>
#include <trace/events/power.h>
+#include <linux/percpu.h>
#include <asm/alternative.h>
#include <asm/compat.h>
@@ -390,6 +391,20 @@ void uao_thread_switch(struct task_struct *next)
}
/*
+ * We store our current task in sp_el0, which is clobbered by userspace. Keep a
+ * shadow copy so that we can restore this upon entry from userspace.
+ *
+ * This is *only* for exception entry from EL0, and is not valid until we
+ * __switch_to() a user task.
+ */
+DEFINE_PER_CPU(struct task_struct *, __entry_task);
+
+static void entry_task_switch(struct task_struct *next)
+{
+ __this_cpu_write(__entry_task, next);
+}
+
+/*
* Thread switching.
*/
struct task_struct *__switch_to(struct task_struct *prev,
@@ -401,6 +416,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
tls_thread_switch(next);
hw_breakpoint_thread_switch(next);
contextidr_thread_switch(next);
+ entry_task_switch(next);
uao_thread_switch(next);
/*
@@ -418,27 +434,35 @@ struct task_struct *__switch_to(struct task_struct *prev,
unsigned long get_wchan(struct task_struct *p)
{
struct stackframe frame;
- unsigned long stack_page;
+ unsigned long stack_page, ret = 0;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
+ stack_page = (unsigned long)try_get_task_stack(p);
+ if (!stack_page)
+ return 0;
+
frame.fp = thread_saved_fp(p);
frame.sp = thread_saved_sp(p);
frame.pc = thread_saved_pc(p);
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
frame.graph = p->curr_ret_stack;
#endif
- stack_page = (unsigned long)task_stack_page(p);
do {
if (frame.sp < stack_page ||
frame.sp >= stack_page + THREAD_SIZE ||
unwind_frame(p, &frame))
- return 0;
- if (!in_sched_functions(frame.pc))
- return frame.pc;
+ goto out;
+ if (!in_sched_functions(frame.pc)) {
+ ret = frame.pc;
+ goto out;
+ }
} while (count ++ < 16);
- return 0;
+
+out:
+ put_task_stack(p);
+ return ret;
}
unsigned long arch_align_stack(unsigned long sp)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 49f3ae0..ae02756 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -312,7 +312,7 @@ void __init setup_arch(char **cmdline_p)
* faults in case uaccess_enable() is inadvertently called by the init
* thread.
*/
- init_thread_info.ttbr0 = virt_to_phys(empty_zero_page);
+ init_task.thread_info.ttbr0 = virt_to_phys(empty_zero_page);
#endif
#ifdef CONFIG_VT
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index 1bec41b..df67652 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -125,9 +125,6 @@
/* load sp from context */
ldr x2, [x0, #CPU_CTX_SP]
mov sp, x2
- /* save thread_info */
- and x2, x2, #~(THREAD_SIZE - 1)
- msr sp_el0, x2
/*
* cpu_do_resume expects x0 to contain context address pointer
*/
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index df95830..2437f15 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -58,6 +58,9 @@
#define CREATE_TRACE_POINTS
#include <trace/events/ipi.h>
+DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number);
+EXPORT_PER_CPU_SYMBOL(cpu_number);
+
/*
* as from 2.5, kernels no longer have an init_tasks structure
* so we need some other way of telling a new secondary core
@@ -147,6 +150,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
* We need to tell the secondary core where to find its stack and the
* page tables.
*/
+ secondary_data.task = idle;
secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
update_cpu_boot_status(CPU_MMU_OFF);
__flush_dcache_area(&secondary_data, sizeof(secondary_data));
@@ -171,6 +175,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
}
+ secondary_data.task = NULL;
secondary_data.stack = NULL;
status = READ_ONCE(secondary_data.status);
if (ret && status) {
@@ -209,7 +214,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
asmlinkage void secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
- unsigned int cpu = smp_processor_id();
+ unsigned int cpu;
+
+ cpu = task_cpu(current);
+ set_my_cpu_offset(per_cpu_offset(cpu));
/*
* All kernel threads share the same mm context; grab a
@@ -218,8 +226,6 @@ asmlinkage void secondary_start_kernel(void)
atomic_inc(&mm->mm_count);
current->active_mm = mm;
- set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
-
pr_debug("CPU%u: Booted secondary processor\n", cpu);
/*
@@ -733,6 +739,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
*/
for_each_possible_cpu(cpu) {
+ per_cpu(cpu_number, cpu) = cpu;
+
if (cpu == smp_processor_id())
continue;
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index 2e940b1..900c1ec 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -181,6 +181,9 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
struct stack_trace_data data;
struct stackframe frame;
+ if (!try_get_task_stack(tsk))
+ return;
+
data.trace = trace;
data.skip = trace->skip;
@@ -202,6 +205,8 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
walk_stackframe(tsk, &frame, save_trace, &data);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
+
+ put_task_stack(tsk);
}
EXPORT_SYMBOL(save_stack_trace_tsk);
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index bb0cd78..1e3be90 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -47,12 +47,6 @@ void notrace __cpu_suspend_exit(void)
cpu_uninstall_idmap();
/*
- * Restore per-cpu offset before any kernel
- * subsystem relying on it has a chance to run.
- */
- set_my_cpu_offset(per_cpu_offset(cpu));
-
- /*
* PSTATE was not saved over suspend/resume, re-enable any detected
* features that might not have been set correctly.
*/
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index cd6c4d9..e576c1d 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -148,6 +148,9 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
if (!tsk)
tsk = current;
+ if (!try_get_task_stack(tsk))
+ return;
+
/*
* Switching between stacks is valid when tracing current and in
* non-preemptible context.
@@ -213,6 +216,8 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
stack + sizeof(struct pt_regs));
}
}
+
+ put_task_stack(tsk);
}
void show_stack(struct task_struct *tsk, unsigned long *sp)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 0a34644..d0ffade 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -40,7 +40,6 @@
#include <asm/system_misc.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
-#include <asm/kryo3xx-arm64-edac.h>
#include <soc/qcom/scm.h>
struct fault_info {
@@ -521,7 +520,6 @@ static int do_alignment_fault(unsigned long addr, unsigned int esr,
*/
static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
{
- kryo3xx_poll_cache_errors(NULL);
return 1;
}
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 61330c9..8d21250 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -116,11 +116,14 @@
mrs x8, mdscr_el1
mrs x9, oslsr_el1
mrs x10, sctlr_el1
+ mrs x11, tpidr_el1
+ mrs x12, sp_el0
stp x2, x3, [x0]
stp x4, xzr, [x0, #16]
stp x5, x6, [x0, #32]
stp x7, x8, [x0, #48]
stp x9, x10, [x0, #64]
+ stp x11, x12, [x0, #80]
ret
ENDPROC(cpu_do_suspend)
@@ -136,6 +139,7 @@
ldp x6, x8, [x0, #32]
ldp x9, x10, [x0, #48]
ldp x11, x12, [x0, #64]
+ ldp x13, x14, [x0, #80]
msr tpidr_el0, x2
msr tpidrro_el0, x3
msr contextidr_el1, x4
@@ -158,6 +162,8 @@
msr mdscr_el1, x10
msr sctlr_el1, x12
+ msr tpidr_el1, x13
+ msr sp_el0, x14
/*
* Restore oslsr_el1 by writing oslar_el1
*/
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 50da8a7..13fac71 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1749,6 +1749,8 @@ static void fastrpc_channel_close(struct kref *kref)
cid = ctx - &gcinfo[0];
fastrpc_glink_close(ctx->chan, cid);
ctx->chan = 0;
+ glink_unregister_link_state_cb(ctx->link.link_notify_handle);
+ ctx->link.link_notify_handle = NULL;
mutex_unlock(&me->smd_mutex);
pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
MAJOR(me->dev_no), cid);
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 89fba64..a0a9ab6 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -264,8 +264,10 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
struct list_head *temp;
struct diag_cmd_reg_t *item = NULL;
+ mutex_lock(&driver->cmd_reg_mutex);
if (diag_dbgfs_table_index == driver->cmd_reg_count) {
diag_dbgfs_table_index = 0;
+ mutex_unlock(&driver->cmd_reg_mutex);
return 0;
}
@@ -274,6 +276,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
buf = kcalloc(buf_size, sizeof(char), GFP_KERNEL);
if (ZERO_OR_NULL_PTR(buf)) {
pr_err("diag: %s, Error allocating memory\n", __func__);
+ mutex_unlock(&driver->cmd_reg_mutex);
return -ENOMEM;
}
buf_size = ksize(buf);
@@ -318,6 +321,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
break;
}
diag_dbgfs_table_index = i;
+ mutex_unlock(&driver->cmd_reg_mutex);
*ppos = 0;
ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c
index 92d9399..8612112 100644
--- a/drivers/char/rdbg.c
+++ b/drivers/char/rdbg.c
@@ -22,7 +22,7 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
-#define SMP2P_NUM_PROCS 8
+#define SMP2P_NUM_PROCS 16
#define MAX_RETRIES 20
#define SM_VERSION 1
@@ -146,9 +146,17 @@ static struct processor_specific_info proc_info[SMP2P_NUM_PROCS] = {
{"rdbg_adsp", SMEM_LC_DEBUGGER, 16*1024}, /*ADSP*/
{0}, /*SMP2P_RESERVED_PROC_1*/
{"rdbg_wcnss", 0, 0}, /*WCNSS*/
- {0}, /*SMP2P_RESERVED_PROC_2*/
- {0}, /*SMP2P_POWER_PROC*/
- {0} /*SMP2P_REMOTE_MOCK_PROC*/
+ {"rdbg_cdsp", SMEM_LC_DEBUGGER, 16*1024}, /*CDSP*/
+ {NULL}, /*SMP2P_POWER_PROC*/
+ {NULL}, /*SMP2P_TZ_PROC*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL} /*SMP2P_REMOTE_MOCK_PROC*/
};
static int smq_blockmap_get(struct smq_block_map *block_map,
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 7536aa9b..827ee8f 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -571,22 +571,21 @@ static int cpu_power_select(struct cpuidle_device *dev,
int best_level = -1;
uint32_t latency_us = pm_qos_request_for_cpu(PM_QOS_CPU_DMA_LATENCY,
dev->cpu);
- uint32_t sleep_us =
- (uint32_t)(ktime_to_us(tick_nohz_get_sleep_length()));
+ s64 sleep_us = ktime_to_us(tick_nohz_get_sleep_length());
uint32_t modified_time_us = 0;
uint32_t next_event_us = 0;
int i, idx_restrict;
uint32_t lvl_latency_us = 0;
uint64_t predicted = 0;
uint32_t htime = 0, idx_restrict_time = 0;
- uint32_t next_wakeup_us = sleep_us;
+ uint32_t next_wakeup_us = (uint32_t)sleep_us;
uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu);
uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu);
if (!cpu)
return -EINVAL;
- if (sleep_disabled)
+ if (sleep_disabled || sleep_us < 0)
return 0;
idx_restrict = cpu->nlevels + 1;
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 70581e2..67c6b2d 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -131,13 +131,14 @@ static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
return -ETIMEDOUT;
}
- pr_debug("aux status %s\n",
- dp_aux_get_error(aux->aux_error_num));
-
- if (aux->aux_error_num == DP_AUX_ERR_NONE)
+ if (aux->aux_error_num == DP_AUX_ERR_NONE) {
ret = len;
- else
+ } else {
+ pr_err_ratelimited("aux err: %s\n",
+ dp_aux_get_error(aux->aux_error_num));
+
ret = -EINVAL;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 9361b52..5825ba8 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -471,6 +471,8 @@ static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u32 cfg)
dp_catalog_get_priv(ctrl);
base = catalog->io->ctrl_io.base;
+ pr_debug("DP_CONFIGURATION_CTRL=0x%x\n", cfg);
+
dp_write(base + DP_CONFIGURATION_CTRL, cfg);
dp_write(base + DP_MAINLINK_LEVELS, 0xa08);
dp_write(base + MMSS_DP_ASYNC_FIFO_CONFIG, 0x1);
@@ -507,10 +509,7 @@ static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl,
dp_catalog_get_priv(ctrl);
base = catalog->io->ctrl_io.base;
- mainlink_ctrl = dp_read(base + DP_MAINLINK_CTRL);
-
if (enable) {
- mainlink_ctrl |= BIT(0);
dp_write(base + DP_MAINLINK_CTRL, 0x02000000);
wmb(); /* make sure mainlink is turned off before reset */
dp_write(base + DP_MAINLINK_CTRL, 0x02000002);
@@ -520,8 +519,9 @@ static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl,
dp_write(base + DP_MAINLINK_CTRL, 0x02000001);
wmb(); /* make sure mainlink turned on */
} else {
+ mainlink_ctrl = dp_read(base + DP_MAINLINK_CTRL);
mainlink_ctrl &= ~BIT(0);
- dp_write(base + DP_MAINLINK_CTRL, 0x0);
+ dp_write(base + DP_MAINLINK_CTRL, mainlink_ctrl);
}
}
@@ -543,14 +543,16 @@ static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl,
misc_val |= (tb << 5);
misc_val |= BIT(0); /* Configure clock to synchronous mode */
- pr_debug("isc settings = 0x%x\n", misc_val);
+ pr_debug("misc settings = 0x%x\n", misc_val);
dp_write(base + DP_MISC1_MISC0, misc_val);
}
-static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl)
+static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl,
+ u32 rate)
{
u32 pixel_m, pixel_n;
u32 mvid, nvid;
+ u32 const link_rate = 540000;
struct dp_catalog_private *catalog;
void __iomem *base_cc, *base_ctrl;
@@ -570,6 +572,11 @@ static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl)
mvid = (pixel_m & 0xFFFF) * 5;
nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
+ pr_debug("rate = %d\n", rate);
+
+ if (link_rate == rate)
+ nvid *= 2;
+
pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
dp_write(base_ctrl + DP_SOFTWARE_MVID, mvid);
dp_write(base_ctrl + DP_SOFTWARE_NVID, nvid);
@@ -593,7 +600,7 @@ static void dp_catalog_ctrl_set_pattern(struct dp_catalog_ctrl *ctrl,
bit = 1;
bit <<= (pattern - 1);
- pr_debug("bit=%d train=%d\n", bit, pattern);
+ pr_debug("hw: bit=%d train=%d\n", bit, pattern);
dp_write(base + DP_STATE_CTRL, bit);
bit = 8;
@@ -792,7 +799,7 @@ static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
base0 = catalog->io->ln_tx0_io.base;
base1 = catalog->io->ln_tx1_io.base;
- pr_debug("v=%d p=%d\n", v_level, p_level);
+ pr_debug("hw: v=%d p=%d\n", v_level, p_level);
value0 = vm_voltage_swing[v_level][p_level];
value1 = vm_pre_emphasis[v_level][p_level];
@@ -814,8 +821,11 @@ static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
dp_write(base0 + TXn_TX_EMP_POST1_LVL, value1);
dp_write(base1 + TXn_TX_EMP_POST1_LVL, value1);
- pr_debug("host PHY settings: value0=0x%x value1=0x%x",
- value0, value1);
+ pr_debug("hw: vx_value=0x%x px_value=0x%x\n",
+ value0, value1);
+ } else {
+ pr_err("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
+ v_level, value0, p_level, value1);
}
}
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index ce88569..c9916c72 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -58,7 +58,7 @@ struct dp_catalog_ctrl {
void (*lane_mapping)(struct dp_catalog_ctrl *ctrl);
void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable);
void (*config_misc)(struct dp_catalog_ctrl *ctrl, u32 cc, u32 tb);
- void (*config_msa)(struct dp_catalog_ctrl *ctrl);
+ void (*config_msa)(struct dp_catalog_ctrl *ctrl, u32 rate);
void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern);
void (*reset)(struct dp_catalog_ctrl *ctrl);
bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 706398db2..b78f0df 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -67,6 +67,7 @@ struct dp_ctrl_private {
bool psm_enabled;
bool orientation;
+ atomic_t aborted;
u32 pixel_rate;
u32 vic;
@@ -92,6 +93,20 @@ static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl)
complete(&ctrl->video_comp);
}
+static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl)
+{
+ struct dp_ctrl_private *ctrl;
+
+ if (!dp_ctrl) {
+ pr_err("Invalid input data\n");
+ return;
+ }
+
+ ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+ atomic_set(&ctrl->aborted, 1);
+}
+
static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
{
ctrl->catalog->state_ctrl(ctrl->catalog, state);
@@ -109,8 +124,6 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
- drm_dp_link_power_down(ctrl->aux->drm_aux, &ctrl->panel->dp_link);
-
reinit_completion(&ctrl->idle_comp);
dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
@@ -135,6 +148,10 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
tbd = ctrl->link->get_test_bits_depth(ctrl->link,
ctrl->panel->pinfo.bpp);
+
+ if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN)
+ tbd = DP_TEST_BIT_DEPTH_8;
+
config |= tbd << 8;
/* Num of Lanes */
@@ -170,9 +187,6 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
ctrl->panel->pinfo.bpp);
cc = ctrl->link->get_colorimetry_config(ctrl->link);
ctrl->catalog->config_misc(ctrl->catalog, cc, tb);
-
- ctrl->catalog->config_msa(ctrl->catalog);
-
ctrl->panel->timing_cfg(ctrl->panel);
}
@@ -226,7 +240,7 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
{
u32 const multiplier = 1000000;
u64 pclk, lclk;
- u8 bpp, ln_cnt, link_rate;
+ u8 bpp, ln_cnt;
int run_idx = 0;
u32 lwidth, h_blank;
u32 fifo_empty = 0;
@@ -289,7 +303,6 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
u64 brute_force_threshold = 10;
u64 diff_abs;
- link_rate = ctrl->link->link_rate;
ln_cnt = ctrl->link->lane_count;
bpp = pinfo->bpp;
@@ -309,7 +322,7 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
even_distribution = 0;
min_hblank = 0;
- lclk = drm_dp_bw_code_to_link_rate(link_rate) * DP_KHZ_TO_HZ;
+ lclk = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code) * DP_KHZ_TO_HZ;
pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
pclk, lwidth, h_blank);
@@ -734,14 +747,12 @@ static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl,
max_level_reached |= BIT(5);
}
- pr_debug("max_level_reached = 0x%x\n", max_level_reached);
-
pre_emphasis_level <<= 3;
for (i = 0; i < 4; i++)
buf[i] = voltage_level | pre_emphasis_level | max_level_reached;
- pr_debug("p|v=0x%x\n", voltage_level | pre_emphasis_level);
+ pr_debug("sink: p|v=0x%x\n", voltage_level | pre_emphasis_level);
return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
}
@@ -749,8 +760,6 @@ static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
{
struct dp_link *link = ctrl->link;
- pr_debug("v=%d p=%d\n", link->v_level, link->p_level);
-
ctrl->catalog->update_vx_px(ctrl->catalog,
link->v_level, link->p_level);
@@ -762,15 +771,38 @@ static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
{
u8 buf[4];
- pr_debug("pattern=%x\n", pattern);
+ pr_debug("sink: pattern=%x\n", pattern);
buf[0] = pattern;
drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1);
}
+static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
+ u8 *link_status)
+{
+ int ret = 0, len;
+ u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS;
+ u32 link_status_read_max_retries = 100;
+
+ while (--link_status_read_max_retries) {
+ len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
+ link_status);
+ if (len != DP_LINK_STATUS_SIZE) {
+ pr_err("DP link status read failed, err: %d\n", len);
+ ret = len;
+ break;
+ }
+
+ if (!(link_status[offset] & DP_LINK_STATUS_UPDATED))
+ break;
+ }
+
+ return ret;
+}
+
static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
{
- int tries, old_v_level, ret = 0, len = 0;
+ int tries, old_v_level, ret = 0;
u8 link_status[DP_LINK_STATUS_SIZE];
int const maximum_retries = 5;
@@ -780,7 +812,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
- DP_RECOVERED_CLOCK_OUT_EN); /* train_1 */
+ DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
dp_ctrl_update_vx_px(ctrl);
tries = 0;
@@ -788,36 +820,35 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
while (1) {
drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
- len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
- link_status);
- if (len < DP_LINK_STATUS_SIZE) {
- pr_err("[%s]: DP link status read failed\n", __func__);
- ret = -1;
+ ret = dp_ctrl_read_link_status(ctrl, link_status);
+ if (ret)
break;
- }
if (drm_dp_clock_recovery_ok(link_status,
ctrl->link->lane_count)) {
- ret = 0;
break;
}
if (ctrl->link->v_level == DP_LINK_VOLTAGE_MAX) {
- ret = -1;
- break; /* quit */
+ pr_err_ratelimited("max v_level reached\n");
+ ret = -EAGAIN;
+ break;
}
if (old_v_level == ctrl->link->v_level) {
tries++;
if (tries >= maximum_retries) {
- ret = -1;
- break; /* quit */
+ pr_err("max tries reached\n");
+ ret = -EAGAIN;
+ break;
}
} else {
tries = 0;
old_v_level = ctrl->link->v_level;
}
+ pr_debug("clock recovery not done, adjusting vx px\n");
+
ctrl->link->adjust_levels(ctrl->link, link_status);
dp_ctrl_update_vx_px(ctrl);
}
@@ -828,27 +859,41 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
{
int ret = 0;
+ u32 min_req_link_rate_khz;
+ u32 new_proposed_link_bw_code;
+ u32 new_proposed_link_rate_khz;
if (!ctrl)
return -EINVAL;
- switch (ctrl->link->link_rate) {
+ min_req_link_rate_khz = ctrl->panel->get_min_req_link_rate(ctrl->panel);
+
+ switch (ctrl->link->bw_code) {
case DP_LINK_RATE_810:
- ctrl->link->link_rate = DP_LINK_BW_5_4;
+ new_proposed_link_bw_code = DP_LINK_BW_5_4;
break;
case DP_LINK_BW_5_4:
- ctrl->link->link_rate = DP_LINK_BW_2_7;
+ new_proposed_link_bw_code = DP_LINK_BW_2_7;
break;
case DP_LINK_BW_2_7:
- ctrl->link->link_rate = DP_LINK_BW_1_62;
- break;
case DP_LINK_BW_1_62:
default:
- ret = -EINVAL;
+ new_proposed_link_bw_code = DP_LINK_BW_1_62;
break;
};
- pr_debug("new rate=%d\n", ctrl->link->link_rate);
+ new_proposed_link_rate_khz = drm_dp_bw_code_to_link_rate(
+ new_proposed_link_bw_code);
+
+ pr_debug("new proposed link rate=%d khz\n", new_proposed_link_rate_khz);
+ pr_debug("min required link rate=%d khz\n", min_req_link_rate_khz);
+
+ if (new_proposed_link_rate_khz >= min_req_link_rate_khz)
+ ctrl->link->bw_code = new_proposed_link_bw_code;
+ else
+ pr_debug("can't go below min required link rate\n");
+
+ pr_debug("new bw code=0x%x\n", ctrl->link->bw_code);
return ret;
}
@@ -861,11 +906,15 @@ static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
{
- int tries = 0, ret = 0, len = 0;
+ int tries = 0, ret = 0;
char pattern;
int const maximum_retries = 5;
u8 link_status[DP_LINK_STATUS_SIZE];
+ dp_ctrl_state_ctrl(ctrl, 0);
+ /* Make sure to clear the current pattern before starting a new one */
+ wmb();
+
if (drm_dp_tps3_supported(ctrl->panel->dpcd))
pattern = DP_TRAINING_PATTERN_3;
else
@@ -878,21 +927,15 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
do {
drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
- len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
- link_status);
- if (len < DP_LINK_STATUS_SIZE) {
- pr_err("[%s]: DP link status read failed\n", __func__);
- ret = -1;
+ ret = dp_ctrl_read_link_status(ctrl, link_status);
+ if (ret)
break;
- }
- if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count)) {
- ret = 0;
+ if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count))
break;
- }
if (tries > maximum_retries) {
- ret = -1;
+ ret = -EAGAIN;
break;
}
tries++;
@@ -907,61 +950,45 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
{
int ret = 0;
- struct drm_dp_link dp_link;
+ u8 encoding = 0x1;
+ struct drm_dp_link link_info = {0};
ctrl->link->p_level = 0;
ctrl->link->v_level = 0;
dp_ctrl_config_ctrl(ctrl);
- dp_ctrl_state_ctrl(ctrl, 0);
- dp_link.num_lanes = ctrl->link->lane_count;
- dp_link.rate = ctrl->link->link_rate;
- dp_link.capabilities = ctrl->panel->dp_link.capabilities;
- drm_dp_link_configure(ctrl->aux->drm_aux, &dp_link);
+ link_info.num_lanes = ctrl->link->lane_count;
+ link_info.rate = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code);
+ link_info.capabilities = ctrl->panel->link_info.capabilities;
+
+ drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
+ drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
+ &encoding, 1);
ret = dp_ctrl_link_train_1(ctrl);
- if (ret < 0) {
- if (!dp_ctrl_link_rate_down_shift(ctrl)) {
- pr_debug("retry with lower rate\n");
-
- dp_ctrl_clear_training_pattern(ctrl);
- return -EAGAIN;
- }
-
- pr_err("Training 1 failed\n");
- ret = -EINVAL;
- goto clear;
+ if (ret) {
+ pr_err("link training #1 failed\n");
+ goto end;
}
- pr_debug("Training 1 completed successfully\n");
-
- dp_ctrl_state_ctrl(ctrl, 0);
-
- /* Make sure to clear the current pattern before starting a new one */
- wmb();
+ /* print success info as this is a result of user initiated action */
+ pr_info("link training #1 successful\n");
ret = dp_ctrl_link_training_2(ctrl);
- if (ret < 0) {
- if (!dp_ctrl_link_rate_down_shift(ctrl)) {
- pr_debug("retry with lower rate\n");
-
- dp_ctrl_clear_training_pattern(ctrl);
- return -EAGAIN;
- }
-
- pr_err("Training 2 failed\n");
- ret = -EINVAL;
- goto clear;
+ if (ret) {
+ pr_err("link training #2 failed\n");
+ goto end;
}
- pr_debug("Training 2 completed successfully\n");
+ /* print success info as this is a result of user initiated action */
+ pr_debug("link training #2 successful\n");
+end:
dp_ctrl_state_ctrl(ctrl, 0);
/* Make sure to clear the current pattern before starting a new one */
wmb();
-clear:
dp_ctrl_clear_training_pattern(ctrl);
return ret;
}
@@ -973,7 +1000,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)
ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
- drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->dp_link);
+ drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info);
if (ctrl->link->phy_pattern_requested(ctrl->link))
goto end;
@@ -1018,6 +1045,8 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
cfg++;
}
+ pr_debug("setting rate=%d on clk=%s\n", rate, name);
+
if (num)
cfg->rate = rate;
else
@@ -1031,7 +1060,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
ctrl->power->set_pixel_clk_parent(ctrl->power);
dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
- drm_dp_bw_code_to_link_rate(ctrl->link->link_rate));
+ drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate);
@@ -1128,6 +1157,9 @@ static int dp_ctrl_on_irq(struct dp_ctrl_private *ctrl, bool lt_needed)
dp_ctrl_configure_source_params(ctrl);
+ ctrl->catalog->config_msa(ctrl->catalog,
+ drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
+
reinit_completion(&ctrl->idle_comp);
if (ctrl->psm_enabled) {
@@ -1148,16 +1180,20 @@ static int dp_ctrl_on_irq(struct dp_ctrl_private *ctrl, bool lt_needed)
static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)
{
int ret = 0;
+ u32 rate = ctrl->panel->link_info.rate;
+ u32 link_train_max_retries = 100;
+
+ atomic_set(&ctrl->aborted, 0);
ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
ctrl->catalog->hpd_config(ctrl->catalog, true);
- ctrl->link->link_rate = ctrl->panel->get_link_rate(ctrl->panel);
- ctrl->link->lane_count = ctrl->panel->dp_link.num_lanes;
+ ctrl->link->bw_code = drm_dp_link_rate_to_bw_code(rate);
+ ctrl->link->lane_count = ctrl->panel->link_info.num_lanes;
ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
- pr_debug("link_rate=%d, lane_count=%d, pixel_rate=%d\n",
- ctrl->link->link_rate, ctrl->link->lane_count,
+ pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n",
+ ctrl->link->bw_code, ctrl->link->lane_count,
ctrl->pixel_rate);
ctrl->catalog->phy_lane_cfg(ctrl->catalog,
@@ -1174,8 +1210,25 @@ static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)
if (ctrl->psm_enabled)
ret = ctrl->link->send_psm_request(ctrl->link, false);
- while (-EAGAIN == dp_ctrl_setup_main_link(ctrl, true))
- pr_debug("MAIN LINK TRAINING RETRY\n");
+ while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
+ ctrl->catalog->config_msa(ctrl->catalog,
+ drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
+
+ ret = dp_ctrl_setup_main_link(ctrl, true);
+ if (!ret)
+ break;
+
+ /* try with lower link rate */
+ dp_ctrl_link_rate_down_shift(ctrl);
+
+ ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
+
+ dp_ctrl_disable_mainlink_clocks(ctrl);
+ /* hw recommended delay before re-enabling clocks */
+ msleep(20);
+
+ dp_ctrl_enable_mainlink_clocks(ctrl);
+ }
pr_debug("End-\n");
@@ -1292,6 +1345,7 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
dp_ctrl->on = dp_ctrl_on;
dp_ctrl->off = dp_ctrl_off;
dp_ctrl->push_idle = dp_ctrl_push_idle;
+ dp_ctrl->abort = dp_ctrl_abort;
dp_ctrl->isr = dp_ctrl_isr;
return dp_ctrl;
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 474e0ad..2ecfa0d 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -28,6 +28,7 @@ struct dp_ctrl {
int (*on)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
void (*off)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
void (*push_idle)(struct dp_ctrl *dp_ctrl);
+ void (*abort)(struct dp_ctrl *dp_ctrl);
void (*isr)(struct dp_ctrl *dp_ctrl);
};
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 5a33fdb..b45cf4d 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -12,7 +12,7 @@
*
*/
-#define pr_fmt(fmt) "[drm-dp]: %s: " fmt, __func__
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
#include <linux/module.h>
#include <linux/slab.h>
@@ -45,7 +45,7 @@ struct dp_display_private {
struct platform_device *pdev;
struct dentry *root;
- struct mutex lock;
+ struct completion notification_comp;
struct dp_usbpd *usbpd;
struct dp_parser *parser;
@@ -171,7 +171,7 @@ static int dp_display_bind(struct device *dev, struct device *master,
pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
dev, pdev, master);
rc = -EINVAL;
- goto error;
+ goto end;
}
drm = dev_get_drvdata(master);
@@ -180,14 +180,12 @@ static int dp_display_bind(struct device *dev, struct device *master,
pr_err("invalid param(s), drm %pK, dp %pK\n",
drm, dp);
rc = -EINVAL;
- goto error;
+ goto end;
}
dp->dp_display.drm_dev = drm;
priv = drm->dev_private;
- mutex_lock(&dp->lock);
-
rc = dp_display_debugfs_init(dp);
if (rc) {
pr_err("[%s]Debugfs init failed, rc=%d\n", dp->name, rc);
@@ -218,8 +216,6 @@ static int dp_display_bind(struct device *dev, struct device *master,
goto end;
}
end:
- mutex_unlock(&dp->lock);
-error:
return rc;
}
@@ -240,17 +236,10 @@ static void dp_display_unbind(struct device *dev, struct device *master,
return;
}
- mutex_lock(&dp->lock);
-
(void)dp->power->power_client_deinit(dp->power);
-
- (void) dp->panel->sde_edid_deregister(dp->panel);
-
- (void) dp->aux->drm_aux_deregister(dp->aux);
-
+ (void)dp->panel->sde_edid_deregister(dp->panel);
+ (void)dp->aux->drm_aux_deregister(dp->aux);
(void)dp_display_debugfs_deinit(dp);
-
- mutex_unlock(&dp->lock);
}
static const struct component_ops dp_display_comp_ops = {
@@ -276,8 +265,13 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
dp->parser->max_pclk_khz);
dp->dp_display.is_connected = true;
+
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+ reinit_completion(&dp->notification_comp);
+ if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
+ pr_warn("timeout\n");
+
return rc;
}
@@ -316,8 +310,15 @@ static void dp_display_host_deinit(struct dp_display_private *dp)
static void dp_display_process_hpd_low(struct dp_display_private *dp)
{
+ /* cancel any pending request */
+ dp->ctrl->abort(dp->ctrl);
+
dp->dp_display.is_connected = false;
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+
+ reinit_completion(&dp->notification_comp);
+ if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
+ pr_warn("timeout\n");
}
static int dp_display_usbpd_configure_cb(struct device *dev)
@@ -338,11 +339,10 @@ static int dp_display_usbpd_configure_cb(struct device *dev)
goto end;
}
- mutex_lock(&dp->lock);
dp_display_host_init(dp);
+
if (dp->usbpd->hpd_high)
dp_display_process_hpd_high(dp);
- mutex_unlock(&dp->lock);
end:
return rc;
}
@@ -365,11 +365,16 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
goto end;
}
- mutex_lock(&dp->lock);
+ /* cancel any pending request */
+ dp->ctrl->abort(dp->ctrl);
dp->dp_display.is_connected = false;
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+ reinit_completion(&dp->notification_comp);
+ if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
+ pr_warn("timeout\n");
+
/*
* If a cable/dongle is connected to the TX device but
* no sink device is connected, we call host
@@ -381,8 +386,6 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
*/
if (!dp->power_on && dp->core_initialized)
dp_display_host_deinit(dp);
-
- mutex_unlock(&dp->lock);
end:
return rc;
}
@@ -403,8 +406,6 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
return -ENODEV;
}
- mutex_lock(&dp->lock);
-
if (dp->usbpd->hpd_irq) {
dp->hpd_irq_on = true;
rc = dp->link->process_request(dp->link);
@@ -423,7 +424,6 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
dp_display_process_hpd_high(dp);
}
end:
- mutex_unlock(&dp->lock);
return rc;
}
@@ -543,18 +543,29 @@ static int dp_display_enable(struct dp_display *dp_display)
dp = container_of(dp_display, struct dp_display_private, dp_display);
- mutex_lock(&dp->lock);
rc = dp->ctrl->on(dp->ctrl, dp->hpd_irq_on);
if (!rc)
dp->power_on = true;
- mutex_unlock(&dp->lock);
error:
return rc;
}
-static int dp_display_post_enable(struct dp_display *dp)
+static int dp_display_post_enable(struct dp_display *dp_display)
{
- return 0;
+ int rc = 0;
+ struct dp_display_private *dp;
+
+ if (!dp_display) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ complete_all(&dp->notification_comp);
+end:
+ return rc;
}
static int dp_display_pre_disable(struct dp_display *dp_display)
@@ -570,9 +581,7 @@ static int dp_display_pre_disable(struct dp_display *dp_display)
dp = container_of(dp_display, struct dp_display_private, dp_display);
- mutex_lock(&dp->lock);
dp->ctrl->push_idle(dp->ctrl);
- mutex_unlock(&dp->lock);
error:
return rc;
}
@@ -590,11 +599,12 @@ static int dp_display_disable(struct dp_display *dp_display)
dp = container_of(dp_display, struct dp_display_private, dp_display);
- mutex_lock(&dp->lock);
dp->ctrl->off(dp->ctrl, dp->hpd_irq_on);
dp_display_host_deinit(dp);
+
dp->power_on = false;
- mutex_unlock(&dp->lock);
+
+ complete_all(&dp->notification_comp);
error:
return rc;
}
@@ -668,7 +678,8 @@ static int dp_display_probe(struct platform_device *pdev)
if (!dp)
return -ENOMEM;
- mutex_init(&dp->lock);
+ init_completion(&dp->notification_comp);
+
dp->pdev = pdev;
dp->name = "drm_dp";
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 741acfca..2beac0d 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -47,13 +47,6 @@ enum test_video_pattern {
DP_TEST_VIDEO_PATTERN_COLOR_SQUARE = 0x03,
};
-enum test_bit_depth {
- DP_TEST_BIT_DEPTH_6 = 0x00,
- DP_TEST_BIT_DEPTH_8 = 0x01,
- DP_TEST_BIT_DEPTH_10 = 0x02,
- DP_TEST_BIT_DEPTH_UNKNOWN = 0xFFFFFFFF,
-};
-
enum dp_link_response {
TEST_ACK = 0x1,
TEST_NACK = 0x2,
@@ -765,12 +758,12 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link)
*
* Returns true if the requested link rate is supported.
*/
-static bool dp_link_is_link_rate_valid(u32 link_rate)
+static bool dp_link_is_link_rate_valid(u32 bw_code)
{
- return ((link_rate == DP_LINK_BW_1_62) ||
- (link_rate == DP_LINK_BW_2_7) ||
- (link_rate == DP_LINK_BW_5_4) ||
- (link_rate == DP_LINK_RATE_810));
+ return ((bw_code == DP_LINK_BW_1_62) ||
+ (bw_code == DP_LINK_BW_2_7) ||
+ (bw_code == DP_LINK_BW_5_4) ||
+ (bw_code == DP_LINK_RATE_810));
}
/**
@@ -1101,7 +1094,7 @@ static int dp_link_process_link_training_request(struct dp_link_private *link)
link->request.test_lane_count);
link->dp_link.lane_count = link->request.test_lane_count;
- link->dp_link.link_rate = link->request.test_link_rate;
+ link->dp_link.bw_code = link->request.test_link_rate;
return 0;
}
@@ -1216,7 +1209,7 @@ static int dp_link_process_phy_test_pattern_request(
pr_debug("start\n");
link->dp_link.lane_count = link->request.test_lane_count;
- link->dp_link.link_rate = link->request.test_link_rate;
+ link->dp_link.bw_code = link->request.test_link_rate;
dp_link_parse_vx_px(link);
@@ -1517,7 +1510,7 @@ static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
dp_link->p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1;
}
- pr_debug("v_level=%d, p_level=%d\n",
+ pr_debug("adjusted: v_level=%d, p_level=%d\n",
dp_link->v_level, dp_link->p_level);
return 0;
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 26249d6..8ea43da 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -46,11 +46,18 @@ enum status_update {
DS_PORT_STATUS_CHANGED = 0x200,
};
+enum test_bit_depth {
+ DP_TEST_BIT_DEPTH_6 = 0x00,
+ DP_TEST_BIT_DEPTH_8 = 0x01,
+ DP_TEST_BIT_DEPTH_10 = 0x02,
+ DP_TEST_BIT_DEPTH_UNKNOWN = 0xFFFFFFFF,
+};
+
struct dp_link {
u32 test_requested;
u32 lane_count;
- u32 link_rate;
+ u32 bw_code;
u32 v_level;
u32 p_level;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 4496e9a..5f25b2d 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -16,6 +16,8 @@
#include "dp_panel.h"
+#define DP_PANEL_DEFAULT_BPP 24
+
enum {
DP_LINK_RATE_MULTIPLIER = 27000000,
};
@@ -25,14 +27,16 @@ struct dp_panel_private {
struct dp_panel dp_panel;
struct dp_aux *aux;
struct dp_catalog_panel *catalog;
+ bool lane_switch_supported;
};
static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
{
int rlen, rc = 0;
struct dp_panel_private *panel;
- struct drm_dp_link *dp_link;
+ struct drm_dp_link *link_info;
u8 major = 0, minor = 0;
+ unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING;
if (!dp_panel) {
pr_err("invalid input\n");
@@ -41,7 +45,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
}
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
- dp_link = &dp_panel->dp_link;
+ link_info = &dp_panel->link_info;
rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV,
dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
@@ -51,22 +55,26 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
goto end;
}
- dp_link->revision = dp_panel->dpcd[DP_DPCD_REV];
+ link_info->revision = dp_panel->dpcd[DP_DPCD_REV];
- major = (dp_link->revision >> 4) & 0x0f;
- minor = dp_link->revision & 0x0f;
+ major = (link_info->revision >> 4) & 0x0f;
+ minor = link_info->revision & 0x0f;
pr_debug("version: %d.%d\n", major, minor);
- dp_link->rate =
+ link_info->rate =
drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]);
- pr_debug("link_rate=%d\n", dp_link->rate);
+ pr_debug("link_rate=%d\n", link_info->rate);
- dp_link->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
+ if (panel->lane_switch_supported)
+ link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
DP_MAX_LANE_COUNT_MASK;
- pr_debug("lane_count=%d\n", dp_link->num_lanes);
+ else
+ link_info->num_lanes = 2;
+
+ pr_debug("lane_count=%d\n", link_info->num_lanes);
if (dp_panel->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)
- dp_link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
+ link_info->capabilities |= caps;
end:
return rc;
@@ -74,26 +82,26 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
static u32 dp_panel_get_max_pclk(struct dp_panel *dp_panel)
{
- struct dp_panel_private *panel;
- struct drm_dp_link *dp_link;
- u32 bpc, bpp, max_data_rate_khz, max_pclk_rate_khz;
+ struct drm_dp_link *link_info;
const u8 num_components = 3;
+ u32 bpc, bpp, max_data_rate_khz, max_pclk_rate_khz;
if (!dp_panel) {
pr_err("invalid input\n");
return 0;
}
- panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
- dp_link = &dp_panel->dp_link;
+ link_info = &dp_panel->link_info;
bpc = sde_get_sink_bpc(dp_panel->edid_ctrl);
bpp = bpc * num_components;
+ if (!bpp)
+ bpp = DP_PANEL_DEFAULT_BPP;
- max_data_rate_khz = (dp_link->num_lanes * dp_link->rate * 8);
+ max_data_rate_khz = (link_info->num_lanes * link_info->rate * 8);
max_pclk_rate_khz = max_data_rate_khz / bpp;
- pr_debug("bpp=%d, max_lane_cnt=%d\n", bpp, dp_link->num_lanes);
+ pr_debug("bpp=%d, max_lane_cnt=%d\n", bpp, link_info->num_lanes);
pr_debug("max_data_rate=%dKHz, max_pclk_rate=%dKHz\n",
max_data_rate_khz, max_pclk_rate_khz);
@@ -196,7 +204,7 @@ static void dp_panel_edid_deregister(struct dp_panel *dp_panel)
static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
{
int rc = 0;
- struct dp_panel_private *panel;
+ struct dp_panel_info *pinfo;
if (!dp_panel) {
pr_err("invalid input\n");
@@ -204,18 +212,38 @@ static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
goto end;
}
- panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+ pinfo = &dp_panel->pinfo;
+
+ /*
+ * print resolution info as this is a result
+ * of user initiated action of cable connection
+ */
+ pr_info("SET NEW RESOLUTION:\n");
+ pr_info("%dx%d@%dfps\n", pinfo->h_active,
+ pinfo->v_active, pinfo->refresh_rate);
+ pr_info("h_porches(back|front|width) = (%d|%d|%d)\n",
+ pinfo->h_back_porch,
+ pinfo->h_front_porch,
+ pinfo->h_sync_width);
+ pr_info("v_porches(back|front|width) = (%d|%d|%d)\n",
+ pinfo->v_back_porch,
+ pinfo->v_front_porch,
+ pinfo->v_sync_width);
+ pr_info("pixel clock (KHz)=(%d)\n", pinfo->pixel_clk_khz);
+ pr_info("bpp = %d\n", pinfo->bpp);
+ pr_info("active low (h|v)=(%d|%d)\n", pinfo->h_active_low,
+ pinfo->v_active_low);
+
+ pinfo->bpp = max_t(u32, 18, min_t(u32, pinfo->bpp, 30));
+ pr_info("updated bpp = %d\n", pinfo->bpp);
end:
return rc;
}
-static u32 dp_panel_get_link_rate(struct dp_panel *dp_panel)
+static u32 dp_panel_get_min_req_link_rate(struct dp_panel *dp_panel)
{
const u32 encoding_factx10 = 8;
- const u32 ln_to_link_ratio = 10;
- u32 min_link_rate, reminder = 0;
- u32 calc_link_rate = 0, lane_cnt, max_rate = 0;
- struct dp_panel_private *panel;
+ u32 min_link_rate_khz = 0, lane_cnt;
struct dp_panel_info *pinfo;
if (!dp_panel) {
@@ -223,54 +251,19 @@ static u32 dp_panel_get_link_rate(struct dp_panel *dp_panel)
goto end;
}
- panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
-
- lane_cnt = dp_panel->dp_link.num_lanes;
- max_rate = drm_dp_link_rate_to_bw_code(dp_panel->dp_link.rate);
+ lane_cnt = dp_panel->link_info.num_lanes;
pinfo = &dp_panel->pinfo;
- /*
- * The max pixel clock supported is 675Mhz. The
- * current calculations below will make sure
- * the min_link_rate is within 32 bit limits.
- * Any changes in the section of code should
- * consider this limitation.
- */
- min_link_rate = (u32)div_u64(pinfo->pixel_clk_khz * 1000,
- (lane_cnt * encoding_factx10));
- min_link_rate /= ln_to_link_ratio;
- min_link_rate = (min_link_rate * pinfo->bpp);
- min_link_rate = (u32)div_u64_rem(min_link_rate * 10,
- DP_LINK_RATE_MULTIPLIER, &reminder);
+ /* num_lanes * lane_count * 8 >= pclk * bpp * 10 */
+ min_link_rate_khz = pinfo->pixel_clk_khz /
+ (lane_cnt * encoding_factx10);
+ min_link_rate_khz *= pinfo->bpp;
- /*
- * To avoid any fractional values,
- * increment the min_link_rate
- */
- if (reminder)
- min_link_rate += 1;
- pr_debug("min_link_rate = %d\n", min_link_rate);
-
- if (min_link_rate <= DP_LINK_BW_1_62)
- calc_link_rate = DP_LINK_BW_1_62;
- else if (min_link_rate <= DP_LINK_BW_2_7)
- calc_link_rate = DP_LINK_BW_2_7;
- else if (min_link_rate <= DP_LINK_BW_5_4)
- calc_link_rate = DP_LINK_BW_5_4;
- else if (min_link_rate <= DP_LINK_RATE_810)
- calc_link_rate = DP_LINK_RATE_810;
- else {
- /* Cap the link rate to the max supported rate */
- pr_debug("link_rate = %d is unsupported\n", min_link_rate);
- calc_link_rate = DP_LINK_RATE_810;
- }
-
- if (calc_link_rate > max_rate)
- calc_link_rate = max_rate;
-
- pr_debug("calc_link_rate = 0x%x\n", calc_link_rate);
+ pr_debug("min lclk req=%d khz for pclk=%d khz, lanes=%d, bpp=%d\n",
+ min_link_rate_khz, pinfo->pixel_clk_khz, lane_cnt,
+ pinfo->bpp);
end:
- return calc_link_rate;
+ return min_link_rate_khz;
}
struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
@@ -303,7 +296,7 @@ struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
dp_panel->init_info = dp_panel_init_panel_info;
dp_panel->timing_cfg = dp_panel_timing_cfg;
dp_panel->read_dpcd = dp_panel_read_dpcd;
- dp_panel->get_link_rate = dp_panel_get_link_rate;
+ dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate;
dp_panel->get_max_pclk = dp_panel_get_max_pclk;
return dp_panel;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index b63c51f..6cca0f1 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -40,7 +40,7 @@ struct dp_panel_info {
struct dp_panel {
/* dpcd raw data */
u8 dpcd[DP_RECEIVER_CAP_SIZE];
- struct drm_dp_link dp_link;
+ struct drm_dp_link link_info;
struct sde_edid_ctrl *edid_ctrl;
struct dp_panel_info pinfo;
@@ -53,7 +53,7 @@ struct dp_panel {
int (*init_info)(struct dp_panel *dp_panel);
int (*timing_cfg)(struct dp_panel *dp_panel);
int (*read_dpcd)(struct dp_panel *dp_panel);
- u32 (*get_link_rate)(struct dp_panel *dp_panel);
+ u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel);
u32 (*get_max_pclk)(struct dp_panel *dp_panel);
};
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 6ef8266..c6ed918 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -345,12 +345,8 @@ static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd,
pd->vdo = *vdos;
dp_usbpd_get_status(pd);
- if (pd->dp_cb && pd->dp_cb->attention) {
- pd->dp_cb->attention(pd->dev);
-
- if (!pd->dp_usbpd.alt_mode_cfg_done)
- dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE);
- }
+ if (!pd->dp_usbpd.alt_mode_cfg_done)
+ dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE);
break;
case DP_USBPD_VDM_STATUS:
pd->vdo = *vdos;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 810d0d6..11f1c4f 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -58,13 +58,14 @@
#define MSM_VERSION_PATCHLEVEL 0
#define TEARDOWN_DEADLOCK_RETRY_MAX 5
+#define HPD_STRING_SIZE 30
static void msm_drm_helper_hotplug_event(struct drm_device *dev)
{
struct drm_connector *connector;
- char *event_string;
+ char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE];
char const *connector_name;
- char *envp[2];
+ char *envp[3];
if (!dev) {
DRM_ERROR("hotplug_event failed, invalid input\n");
@@ -74,12 +75,6 @@ static void msm_drm_helper_hotplug_event(struct drm_device *dev)
if (!dev->mode_config.poll_enabled)
return;
- event_string = kzalloc(SZ_4K, GFP_KERNEL);
- if (!event_string) {
- DRM_ERROR("failed to allocate event string\n");
- return;
- }
-
mutex_lock(&dev->mode_config.mutex);
drm_for_each_connector(connector, dev) {
/* Only handle HPD capable connectors. */
@@ -93,17 +88,20 @@ static void msm_drm_helper_hotplug_event(struct drm_device *dev)
else
connector_name = "unknown";
- snprintf(event_string, SZ_4K, "name=%s status=%s\n",
- connector_name,
+ snprintf(name, HPD_STRING_SIZE, "name=%s", connector_name);
+
+ snprintf(status, HPD_STRING_SIZE, "status=%s",
drm_get_connector_status_name(connector->status));
- DRM_DEBUG("generating hotplug event [%s]\n", event_string);
- envp[0] = event_string;
- envp[1] = NULL;
+
+ DRM_DEBUG("generating hotplug event [%s]: [%s]\n",
+ name, status);
+ envp[0] = name;
+ envp[1] = status;
+ envp[2] = NULL;
kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
envp);
}
mutex_unlock(&dev->mode_config.mutex);
- kfree(event_string);
}
static void msm_fb_output_poll_changed(struct drm_device *dev)
@@ -126,21 +124,10 @@ static void msm_fb_output_poll_changed(struct drm_device *dev)
int msm_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
- struct msm_drm_private *priv;
-
- if (!dev)
- return -EINVAL;
-
if (msm_is_suspend_blocked(dev)) {
DRM_DEBUG("rejecting commit during suspend\n");
return -EBUSY;
}
-
- priv = dev->dev_private;
- if (priv && priv->kms && priv->kms->funcs &&
- priv->kms->funcs->atomic_check)
- return priv->kms->funcs->atomic_check(priv->kms, state);
-
return drm_atomic_helper_check(dev, state);
}
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index eb10d6b..35e6b71 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -75,9 +75,6 @@ struct msm_kms_funcs {
const struct msm_format *msm_fmt,
const struct drm_mode_fb_cmd2 *cmd,
struct drm_gem_object **bos);
- /* perform complete atomic check of given atomic state */
- int (*atomic_check)(struct msm_kms *kms,
- struct drm_atomic_state *state);
/* misc: */
long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 71dfc12..7243fe2 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -225,8 +225,17 @@ int sde_core_perf_crtc_check(struct drm_crtc *crtc,
struct sde_crtc_state *tmp_cstate =
to_sde_crtc_state(tmp_crtc->state);
- bw_sum_of_intfs +=
- tmp_cstate->new_perf.bw_ctl[i];
+ SDE_DEBUG("crtc:%d bw:%llu ctrl:%d\n",
+ tmp_crtc->base.id,
+ tmp_cstate->new_perf.bw_ctl[i],
+ tmp_cstate->bw_control);
+ /*
+ * For bw check only use the bw if the
+ * atomic property has been already set
+ */
+ if (tmp_cstate->bw_control)
+ bw_sum_of_intfs +=
+ tmp_cstate->new_perf.bw_ctl[i];
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 368181f..63979dd 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -2021,6 +2021,16 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
if (unlikely(!sde_crtc->num_mixers))
return;
+ /*
+ * For planes without commit update, drm framework will not add
+ * those planes to current state since hardware update is not
+ * required. However, if those planes were power collapsed since
+ * last commit cycle, driver has to restore the hardware state
+ * of those planes explicitly here prior to plane flush.
+ */
+ drm_atomic_crtc_for_each_plane(plane, crtc)
+ sde_plane_restore(plane);
+
/* wait for acquire fences before anything else is done */
_sde_crtc_wait_for_fences(crtc);
@@ -2339,8 +2349,6 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc)
_sde_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp);
- cstate->idle_pc = sde_crtc->idle_pc;
-
return &cstate->base;
}
@@ -2441,24 +2449,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
sde_encoder_virt_restore(encoder);
}
- } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) {
- /*
- * Serialize h/w idle state update with crtc atomic check.
- * Grab the modeset lock to ensure that there is no on-going
- * atomic check, then increment the idle_pc counter. The next
- * atomic check will detect a new idle_pc since the counter
- * has advanced between the old_state and new_state, and
- * therefore properly reprogram all relevant drm objects'
- * hardware.
- */
- drm_modeset_lock_crtc(crtc, NULL);
-
- sde_crtc->idle_pc++;
-
- SDE_DEBUG("crtc%d idle_pc:%d\n", crtc->base.id,
- sde_crtc->idle_pc);
- SDE_EVT32(DRMID(crtc), sde_crtc->idle_pc);
-
} else if (event_type == SDE_POWER_EVENT_POST_DISABLE) {
struct drm_plane *plane;
@@ -2469,7 +2459,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
drm_atomic_crtc_for_each_plane(plane, crtc)
sde_plane_set_revalidate(plane, true);
- drm_modeset_unlock_crtc(crtc);
sde_cp_crtc_suspend(crtc);
}
@@ -2599,8 +2588,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
sde_crtc->power_event = sde_power_handle_register_event(
&priv->phandle,
- SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE |
- SDE_POWER_EVENT_PRE_DISABLE,
+ SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE,
sde_crtc_handle_power_event, crtc, sde_crtc->name);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index f021477..0d72ff1 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -125,7 +125,6 @@ struct sde_crtc_event {
* @vblank_cb_time : ktime at vblank count reset
* @vblank_refcount : reference count for vblank enable request
* @suspend : whether or not a suspend operation is in progress
- * @idle_pc : count of current idle power collapse request
* @feature_list : list of color processing features supported on a crtc
* @active_list : list of color processing features are active
* @dirty_list : list of color processing features are dirty
@@ -174,7 +173,6 @@ struct sde_crtc {
ktime_t vblank_cb_time;
atomic_t vblank_refcount;
bool suspend;
- u32 idle_pc;
struct list_head feature_list;
struct list_head active_list;
@@ -280,7 +278,6 @@ struct sde_crtc_respool {
* @sbuf_cfg: stream buffer configuration
* @sbuf_prefill_line: number of line for inline rotator prefetch
* @sbuf_flush_mask: flush mask for inline rotator
- * @idle_pc: count of idle power collapse request when state is duplicated
*/
struct sde_crtc_state {
struct drm_crtc_state base;
@@ -310,8 +307,6 @@ struct sde_crtc_state {
u32 sbuf_prefill_line;
u32 sbuf_flush_mask;
- u32 idle_pc;
-
struct sde_crtc_respool rp;
};
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 6ee1aae..6e85e93 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -161,7 +161,7 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
unsigned long lock_flags;
int new_cnt;
- if (!phys_enc)
+ if (!phys_enc || !phys_enc->hw_pp)
return;
/* notify all synchronous clients first, then asynchronous clients */
@@ -207,7 +207,7 @@ static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx)
{
struct sde_encoder_phys *phys_enc = arg;
- if (!phys_enc)
+ if (!phys_enc || !phys_enc->hw_pp)
return;
SDE_EVT32_IRQ(DRMID(phys_enc->parent),
@@ -607,7 +607,7 @@ static void sde_encoder_phys_cmd_tearcheck_config(
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
struct sde_hw_tear_check tc_cfg = { 0 };
- struct drm_display_mode *mode = &phys_enc->cached_mode;
+ struct drm_display_mode *mode;
bool tc_enable = true;
u32 vsync_hz;
struct msm_drm_private *priv;
@@ -617,6 +617,7 @@ static void sde_encoder_phys_cmd_tearcheck_config(
SDE_ERROR("invalid encoder\n");
return;
}
+ mode = &phys_enc->cached_mode;
SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
@@ -627,7 +628,12 @@ static void sde_encoder_phys_cmd_tearcheck_config(
}
sde_kms = phys_enc->sde_kms;
+ if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) {
+ SDE_ERROR("invalid device\n");
+ return;
+ }
priv = sde_kms->dev->dev_private;
+
/*
* TE default: dsi byte clock calculated base on 70 fps;
* around 14 ms to complete a kickoff cycle if te disabled;
@@ -638,8 +644,10 @@ static void sde_encoder_phys_cmd_tearcheck_config(
* frequency divided by the no. of rows (lines) in the LCDpanel.
*/
vsync_hz = sde_power_clk_get_rate(&priv->phandle, "vsync_clk");
- if (!vsync_hz) {
- SDE_DEBUG_CMDENC(cmd_enc, "invalid vsync clock rate\n");
+ if (!vsync_hz || !mode->vtotal || !mode->vrefresh) {
+ SDE_DEBUG_CMDENC(cmd_enc,
+ "invalid params - vsync_hz %u vtot %u vrefresh %u\n",
+ vsync_hz, mode->vtotal, mode->vrefresh);
return;
}
@@ -687,8 +695,8 @@ static void _sde_encoder_phys_cmd_pingpong_config(
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- if (!phys_enc || !phys_enc->hw_ctl ||
- !phys_enc->hw_ctl->ops.setup_intf_cfg) {
+ if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp
+ || !phys_enc->hw_ctl->ops.setup_intf_cfg) {
SDE_ERROR("invalid arg(s), enc %d\n", phys_enc != 0);
return;
}
@@ -717,7 +725,7 @@ static void sde_encoder_phys_cmd_enable_helper(
struct sde_hw_ctl *ctl;
u32 flush_mask = 0;
- if (!phys_enc || !phys_enc->hw_ctl) {
+ if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) {
SDE_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0);
return;
}
@@ -747,10 +755,11 @@ static void sde_encoder_phys_cmd_enable(struct sde_encoder_phys *phys_enc)
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid phys encoder\n");
return;
}
+
SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
if (phys_enc->enable_state == SDE_ENC_ENABLED) {
@@ -803,7 +812,7 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
to_sde_encoder_phys_cmd(phys_enc);
int ret;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return;
}
@@ -857,6 +866,12 @@ static void sde_encoder_phys_cmd_get_hw_resources(
SDE_ERROR("invalid encoder\n");
return;
}
+
+ if ((phys_enc->intf_idx - INTF_0) >= INTF_MAX) {
+ SDE_ERROR("invalid intf idx:%d\n", phys_enc->intf_idx);
+ return;
+ }
+
SDE_DEBUG_CMDENC(cmd_enc, "\n");
hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_CMD;
}
@@ -869,7 +884,7 @@ static void sde_encoder_phys_cmd_prepare_for_kickoff(
to_sde_encoder_phys_cmd(phys_enc);
int ret;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return;
}
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 afd61ae..c1fba2f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -49,6 +49,23 @@ static void drm_mode_to_intf_timing_params(
struct intf_timing_params *timing)
{
memset(timing, 0, sizeof(*timing));
+
+ if ((mode->htotal < mode->hsync_end)
+ || (mode->hsync_start < mode->hdisplay)
+ || (mode->vtotal < mode->vsync_end)
+ || (mode->vsync_start < mode->vdisplay)
+ || (mode->hsync_end < mode->hsync_start)
+ || (mode->vsync_end < mode->vsync_start)) {
+ SDE_ERROR(
+ "invalid params - hstart:%d,hend:%d,htot:%d,hdisplay:%d\n",
+ mode->hsync_start, mode->hsync_end,
+ mode->htotal, mode->hdisplay);
+ SDE_ERROR("vstart:%d,vend:%d,vtot:%d,vdisplay:%d\n",
+ mode->vsync_start, mode->vsync_end,
+ mode->vtotal, mode->vdisplay);
+ return;
+ }
+
/*
* https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
* Active Region Front Porch Sync Back Porch
@@ -139,6 +156,15 @@ static u32 programmable_fetch_get_num_lines(
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,
@@ -442,15 +468,18 @@ static void sde_encoder_phys_vid_mode_set(
struct sde_encoder_phys_vid *vid_enc;
if (!phys_enc || !phys_enc->sde_kms) {
- SDE_ERROR("invalid encoder\n");
+ SDE_ERROR("invalid encoder/kms\n");
return;
}
rm = &phys_enc->sde_kms->rm;
vid_enc = to_sde_encoder_phys_vid(phys_enc);
- phys_enc->cached_mode = *adj_mode;
- SDE_DEBUG_VIDENC(vid_enc, "caching mode:\n");
- drm_mode_debug_printmodeline(adj_mode);
+
+ if (adj_mode) {
+ phys_enc->cached_mode = *adj_mode;
+ drm_mode_debug_printmodeline(adj_mode);
+ SDE_DEBUG_VIDENC(vid_enc, "caching mode:\n");
+ }
instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0;
@@ -620,13 +649,18 @@ static void sde_encoder_phys_vid_get_hw_resources(
static int sde_encoder_phys_vid_wait_for_vblank(
struct sde_encoder_phys *phys_enc, bool notify)
{
- struct sde_encoder_wait_info wait_info = {
- .wq = &phys_enc->pending_kickoff_wq,
- .atomic_cnt = &phys_enc->pending_kickoff_cnt,
- .timeout_ms = KICKOFF_TIMEOUT_MS,
- };
+ struct sde_encoder_wait_info wait_info;
int ret;
+ if (!phys_enc) {
+ pr_err("invalid encoder\n");
+ return -EINVAL;
+ }
+
+ wait_info.wq = &phys_enc->pending_kickoff_wq;
+ wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
+ wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
+
if (!sde_encoder_phys_vid_is_master(phys_enc)) {
/* signal done for slave video encoder, unless it is pp-split */
if (!_sde_encoder_phys_is_ppsplit(phys_enc) &&
@@ -654,11 +688,7 @@ static int sde_encoder_phys_vid_wait_for_vblank(
static int sde_encoder_phys_vid_wait_for_commit_done(
struct sde_encoder_phys *phys_enc)
{
- int ret;
-
- ret = sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
-
- return ret;
+ return sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
}
static void sde_encoder_phys_vid_prepare_for_kickoff(
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 7b620bf..b9fbd62 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -1376,48 +1376,6 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file)
sde_crtc_cancel_pending_flip(priv->crtcs[i], file);
}
-static int sde_kms_atomic_check(struct msm_kms *kms,
- struct drm_atomic_state *state)
-{
- struct sde_kms *sde_kms = to_sde_kms(kms);
- struct drm_device *dev = sde_kms->dev;
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- int rc, i;
-
- if (!kms || !state)
- return -EINVAL;
-
- /*
- * Add planes (and other affected DRM objects, if any) to new state
- * if idle power collapse occurred since previous commit.
- * Since atomic state is a delta from the last, if the user-space
- * did not request any changes on a plane/connector, that object
- * will not be included in the new atomic state. Idle power collapse
- * is driver-autonomous, so the driver needs to ensure that all
- * hardware is reprogrammed as the power comes back on by forcing
- * the drm objects attached to the CRTC into the new atomic state.
- */
- for_each_crtc_in_state(state, crtc, crtc_state, i) {
- struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state);
- struct sde_crtc_state *old_cstate =
- to_sde_crtc_state(crtc->state);
-
- if (cstate->idle_pc != old_cstate->idle_pc) {
- SDE_DEBUG("crtc%d idle_pc:%d/%d\n",
- crtc->base.id, cstate->idle_pc,
- old_cstate->idle_pc);
- SDE_EVT32(DRMID(crtc), cstate->idle_pc,
- old_cstate->idle_pc);
- rc = drm_atomic_add_affected_planes(state, crtc);
- if (rc)
- return rc;
- }
- }
-
- return drm_atomic_helper_check(dev, state);
-}
-
static struct msm_gem_address_space*
_sde_kms_get_address_space(struct msm_kms *kms,
unsigned int domain)
@@ -1458,7 +1416,6 @@ static const struct msm_kms_funcs kms_funcs = {
.enable_vblank = sde_kms_enable_vblank,
.disable_vblank = sde_kms_disable_vblank,
.check_modified_format = sde_format_check_modified_format,
- .atomic_check = sde_kms_atomic_check,
.get_format = sde_get_msm_format,
.round_pixclk = sde_kms_round_pixclk,
.destroy = sde_kms_destroy,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index b185359..8077756 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -3574,6 +3574,29 @@ static void sde_plane_atomic_update(struct drm_plane *plane,
}
}
+void sde_plane_restore(struct drm_plane *plane)
+{
+ struct sde_plane *psde;
+
+ if (!plane || !plane->state) {
+ SDE_ERROR("invalid plane\n");
+ return;
+ }
+
+ psde = to_sde_plane(plane);
+
+ /*
+ * Revalidate is only true here if idle PC occurred and
+ * there is no plane state update in current commit cycle.
+ */
+ if (!psde->revalidate)
+ return;
+
+ SDE_DEBUG_PLANE(psde, "\n");
+
+ /* last plane state is same as current state */
+ sde_plane_atomic_update(plane, plane->state);
+}
/* helper to install properties which are common to planes and crtcs */
static void _sde_plane_install_properties(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 3a36ea0..be0ea67 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -217,6 +217,12 @@ void sde_plane_get_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl,
bool sde_plane_is_sbuf_mode(struct drm_plane *plane, u32 *prefill);
/**
+ * sde_plane_restore - restore hw state if previously power collapsed
+ * @plane: Pointer to drm plane structure
+ */
+void sde_plane_restore(struct drm_plane *plane);
+
+/**
* sde_plane_flush - final plane operations before commit flush
* @plane: Pointer to drm plane structure
*/
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 13c36e6..742da91 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -55,7 +55,7 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = {
{ adreno_is_a530, a530_vbif },
{ adreno_is_a512, a540_vbif },
{ adreno_is_a510, a530_vbif },
- { adreno_is_a508, a540_vbif },
+ { adreno_is_a508, a530_vbif },
{ adreno_is_a505, a530_vbif },
{ adreno_is_a506, a530_vbif },
};
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index ed0129f..1f97888 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -205,13 +205,16 @@ static const unsigned int a6xx_vbif_ver_20xxxxxx_registers[] = {
0x3410, 0x3410, 0x3800, 0x3801,
};
-static const unsigned int a6xx_gmu_registers[] = {
+static const unsigned int a6xx_gmu_gx_registers[] = {
/* GMU GX */
0x1A800, 0x1A800, 0x1A810, 0x1A813, 0x1A816, 0x1A816, 0x1A818, 0x1A81B,
0x1A81E, 0x1A81E, 0x1A820, 0x1A823, 0x1A826, 0x1A826, 0x1A828, 0x1A82B,
0x1A82E, 0x1A82E, 0x1A830, 0x1A833, 0x1A836, 0x1A836, 0x1A838, 0x1A83B,
0x1A83E, 0x1A83E, 0x1A840, 0x1A843, 0x1A846, 0x1A846, 0x1A880, 0x1A884,
0x1A900, 0x1A92B, 0x1A940, 0x1A940,
+};
+
+static const unsigned int a6xx_gmu_registers[] = {
/* GMU TCM */
0x1B400, 0x1C3FF, 0x1C400, 0x1D3FF,
/* GMU CX */
@@ -1321,11 +1324,19 @@ static void a6xx_snapshot_debugbus(struct kgsl_device *device,
static void a6xx_snapshot_gmu(struct kgsl_device *device,
struct kgsl_snapshot *snapshot)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+
if (!kgsl_gmu_isenabled(device))
return;
adreno_snapshot_registers(device, snapshot, a6xx_gmu_registers,
ARRAY_SIZE(a6xx_gmu_registers) / 2);
+
+ if (gpudev->gx_is_on(adreno_dev))
+ adreno_snapshot_registers(device, snapshot,
+ a6xx_gmu_gx_registers,
+ ARRAY_SIZE(a6xx_gmu_gx_registers) / 2);
}
/* a6xx_snapshot_sqe() - Dump SQE data in snapshot */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 4e67efb..129e99c 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2225,21 +2225,23 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device,
if (fd != 0)
dmabuf = dma_buf_get(fd - 1);
}
- up_read(¤t->mm->mmap_sem);
- if (IS_ERR_OR_NULL(dmabuf))
+ if (IS_ERR_OR_NULL(dmabuf)) {
+ up_read(¤t->mm->mmap_sem);
return dmabuf ? PTR_ERR(dmabuf) : -ENODEV;
+ }
ret = kgsl_setup_dma_buf(device, pagetable, entry, dmabuf);
if (ret) {
dma_buf_put(dmabuf);
+ up_read(¤t->mm->mmap_sem);
return ret;
}
/* Setup the user addr/cache mode for cache operations */
entry->memdesc.useraddr = hostptr;
_setup_cache_mode(entry, vma);
-
+ up_read(¤t->mm->mmap_sem);
return 0;
}
#else
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index c9f1483..dff46d2 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -436,6 +436,7 @@ int gmu_dcvs_set(struct gmu_device *gmu,
struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu);
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int perf_idx = INVALID_DCVS_IDX, bw_idx = INVALID_DCVS_IDX;
if (gpu_pwrlevel < gmu->num_gpupwrlevels)
@@ -448,6 +449,10 @@ int gmu_dcvs_set(struct gmu_device *gmu,
(bw_idx == INVALID_DCVS_IDX))
return -EINVAL;
+ if (bw_idx == INVALID_DCVS_IDX)
+ /* Use default BW, algorithm changes on V2 */
+ bw_idx = pwr->pwrlevels[gpu_pwrlevel].bus_freq;
+
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
return gpudev->rpmh_gpu_pwrctrl(adreno_dev,
GMU_DCVS_NOHFI, perf_idx, bw_idx);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 051ab8e..6aa2e36 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -123,32 +123,40 @@ static inline void qcom_geni_i2c_conf(void __iomem *base, int dfs, int div)
static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
{
- u32 m_stat = readl_relaxed(gi2c->base + SE_GENI_M_IRQ_STATUS);
- u32 rx_st = readl_relaxed(gi2c->base + SE_GENI_RX_FIFO_STATUS);
- u32 tx_st = readl_relaxed(gi2c->base + SE_GENI_TX_FIFO_STATUS);
u32 m_cmd = readl_relaxed(gi2c->base + SE_GENI_M_CMD0);
+ u32 m_stat = readl_relaxed(gi2c->base + SE_GENI_M_IRQ_STATUS);
u32 geni_s = readl_relaxed(gi2c->base + SE_GENI_STATUS);
u32 geni_ios = readl_relaxed(gi2c->base + SE_GENI_IOS);
+ u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN);
+ u32 rx_st, tx_st;
+
+ if (gi2c->cur)
+ GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+ "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len,
+ gi2c->cur->addr, gi2c->cur->flags);
if (err == I2C_NACK || err == GENI_ABORT_DONE) {
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n",
- gi2c_log[err].msg);
- GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
- "m_stat:0x%x, tx_stat:0x%x, rx_stat:0x%x, ",
- m_stat, tx_st, rx_st);
- GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
- "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
- m_cmd, geni_s, geni_ios);
+ gi2c_log[err].msg);
+ goto err_ret;
} else {
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n",
gi2c_log[err].msg);
- GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
- "m_stat:0x%x, tx_stat:0x%x, rx_stat:0x%x, ",
- m_stat, tx_st, rx_st);
- GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+ }
+ if (dma) {
+ rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT);
+ tx_st = readl_relaxed(gi2c->base + SE_DMA_TX_IRQ_STAT);
+ } else {
+ rx_st = readl_relaxed(gi2c->base + SE_GENI_RX_FIFO_STATUS);
+ tx_st = readl_relaxed(gi2c->base + SE_GENI_TX_FIFO_STATUS);
+ }
+ GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+ "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n",
+ dma, tx_st, rx_st, m_stat);
+ GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
"m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
m_cmd, geni_s, geni_ios);
- }
+err_ret:
gi2c->err = gi2c_log[err].err;
}
@@ -185,7 +193,6 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
if (!dma)
writel_relaxed(0, (gi2c->base +
SE_GENI_TX_WATERMARK_REG));
- gi2c->err = -EIO;
goto irqret;
}
@@ -310,11 +317,12 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
ret = geni_se_rx_dma_prep(gi2c->wrapper_dev,
gi2c->base, msgs[i].buf,
msgs[i].len, &rx_dma);
- if (ret)
+ if (ret) {
mode = FIFO_MODE;
+ ret = geni_se_select_mode(gi2c->base,
+ mode);
+ }
}
- if (mode == FIFO_MODE)
- geni_se_select_mode(gi2c->base, mode);
} else {
dev_dbg(gi2c->dev,
"WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n",
@@ -327,15 +335,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
ret = geni_se_tx_dma_prep(gi2c->wrapper_dev,
gi2c->base, msgs[i].buf,
msgs[i].len, &tx_dma);
- if (ret)
+ if (ret) {
mode = FIFO_MODE;
+ ret = geni_se_select_mode(gi2c->base,
+ mode);
+ }
}
- if (mode == FIFO_MODE) {
- geni_se_select_mode(gi2c->base, mode);
- /* Get FIFO IRQ */
+ if (mode == FIFO_MODE) /* Get FIFO IRQ */
geni_write_reg(1, gi2c->base,
SE_GENI_TX_WATERMARK_REG);
- }
}
/* Ensure FIFO write go through before waiting for Done evet */
mb();
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 1d5c514..9a4d11f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -238,6 +238,7 @@ enum arm_smmu_s2cr_privcfg {
#define ARM_SMMU_CB_FSYNR0 0x68
#define ARM_SMMU_CB_S1_TLBIVA 0x600
#define ARM_SMMU_CB_S1_TLBIASID 0x610
+#define ARM_SMMU_CB_S1_TLBIALL 0x618
#define ARM_SMMU_CB_S1_TLBIVAL 0x620
#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630
#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638
@@ -415,6 +416,7 @@ struct arm_smmu_device {
#define ARM_SMMU_OPT_SKIP_INIT (1 << 2)
#define ARM_SMMU_OPT_DYNAMIC (1 << 3)
#define ARM_SMMU_OPT_3LVL_TABLES (1 << 4)
+#define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5)
u32 options;
enum arm_smmu_arch_version version;
enum arm_smmu_implementation model;
@@ -534,6 +536,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
{ ARM_SMMU_OPT_SKIP_INIT, "qcom,skip-init" },
{ ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
+ { ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" },
{ 0, NULL},
};
@@ -991,12 +994,17 @@ static void arm_smmu_tlb_inv_context(void *cookie)
struct arm_smmu_device *smmu = smmu_domain->smmu;
bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
void __iomem *base;
+ bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
- if (stage1) {
+ if (stage1 && !use_tlbiall) {
base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg),
base + ARM_SMMU_CB_S1_TLBIASID);
arm_smmu_tlb_sync_cb(smmu, cfg->cbndx);
+ } else if (stage1 && use_tlbiall) {
+ base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
+ arm_smmu_tlb_sync_cb(smmu, cfg->cbndx);
} else {
base = ARM_SMMU_GR0(smmu);
writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg),
@@ -1013,8 +1021,9 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
struct arm_smmu_device *smmu = smmu_domain->smmu;
bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
void __iomem *reg;
+ bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
- if (stage1) {
+ if (stage1 && !use_tlbiall) {
reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
@@ -1033,6 +1042,10 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
iova += granule >> 12;
} while (size -= granule);
}
+ } else if (stage1 && use_tlbiall) {
+ reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ reg += ARM_SMMU_CB_S1_TLBIALL;
+ writel_relaxed(0, reg);
} else if (smmu->version == ARM_SMMU_V2) {
reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L :
diff --git a/drivers/irqchip/qcom/pdc-sdm670.c b/drivers/irqchip/qcom/pdc-sdm670.c
index 046a595..7bd6333 100644
--- a/drivers/irqchip/qcom/pdc-sdm670.c
+++ b/drivers/irqchip/qcom/pdc-sdm670.c
@@ -126,7 +126,7 @@ static struct pdc_pin sdm670_data[] = {
{122, 669}, /* core_bi_px_gpio_41 */
{123, 670}, /* core_bi_px_gpio_89 */
{124, 671}, /* core_bi_px_gpio_31 */
- {125, 672}, /* core_bi_px_gpio_49 */
+ {125, 95}, /* core_bi_px_gpio_49 */
{-1}
};
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index d2cb1e8..3989bc6 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -330,6 +330,16 @@ bool mbox_controller_is_idle(struct mbox_chan *chan)
}
EXPORT_SYMBOL(mbox_controller_is_idle);
+
+void mbox_chan_debug(struct mbox_chan *chan)
+{
+ if (!chan || !chan->cl || !chan->mbox->debug)
+ return;
+
+ return chan->mbox->debug(chan);
+}
+EXPORT_SYMBOL(mbox_chan_debug);
+
/**
* mbox_request_channel - Request a mailbox channel.
* @cl: Identity of the client requesting the channel.
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index be91a65..15d0805 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -241,11 +241,11 @@ static void print_response(struct tcs_drv *drv, int m)
return;
msg = resp->msg;
- pr_debug("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
+ pr_warn("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
resp->idx, resp->m, resp->in_use);
- pr_debug("Msg: state=%d\n", msg->state);
+ pr_warn("Msg: state=%d\n", msg->state);
for (i = 0; i < msg->num_payload; i++)
- pr_debug("addr=0x%x data=0x%x complete=0x%x\n",
+ pr_warn("addr=0x%x data=0x%x complete=0x%x\n",
msg->payload[i].addr,
msg->payload[i].data,
msg->payload[i].complete);
@@ -804,14 +804,14 @@ static void print_tcs_regs(struct tcs_drv *drv, int m)
if (!enable)
return;
- pr_debug("TCS-%d contents:\n", m);
+ pr_warn("TCS-%d contents:\n", m);
for (n = 0; n < tcs->ncpt; n++) {
if (!(enable & BIT(n)))
continue;
addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n);
data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n);
msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n);
- pr_debug("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
+ pr_warn("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
n, addr, data, msgid);
}
}
@@ -824,7 +824,7 @@ static void dump_tcs_stats(struct tcs_drv *drv)
for (i = 0; i < drv->num_tcs; i++) {
if (!atomic_read(&drv->tcs_in_use[i]))
continue;
- pr_debug("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
+ pr_warn("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
curr, i,
atomic_read(&drv->tcs_send_count[i]),
drv->tcs_last_sent_ts[i],
@@ -835,6 +835,13 @@ static void dump_tcs_stats(struct tcs_drv *drv)
}
}
+static void chan_debug(struct mbox_chan *chan)
+{
+ struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
+
+ dump_tcs_stats(drv);
+}
+
/**
* chan_tcs_write: Validate the incoming message and write to the
* appropriate TCS block.
@@ -910,7 +917,6 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data)
/* If we were just busy waiting for TCS, dump the state and return */
if (ret == -EBUSY) {
pr_info_ratelimited("TCS Busy, retrying RPMH message send\n");
- dump_tcs_stats(drv);
ret = -EAGAIN;
}
@@ -1162,6 +1168,7 @@ static int tcs_drv_probe(struct platform_device *pdev)
drv->mbox.txdone_irq = true;
drv->mbox.of_xlate = of_tcs_mbox_xlate;
drv->mbox.is_idle = tcs_drv_is_idle;
+ drv->mbox.debug = chan_debug;
drv->num_tcs = st;
drv->pdev = pdev;
INIT_LIST_HEAD(&drv->response_pending);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index a195c15..df2642c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -2583,6 +2583,7 @@ static int sde_rotator_parse_dt_bus(struct sde_rot_mgr *mgr,
{
int ret = 0, i;
int usecases;
+ struct device_node *node;
mgr->data_bus.bus_scale_pdata = msm_bus_cl_get_pdata(dev);
if (IS_ERR_OR_NULL(mgr->data_bus.bus_scale_pdata)) {
@@ -2594,12 +2595,27 @@ static int sde_rotator_parse_dt_bus(struct sde_rot_mgr *mgr,
}
}
- mgr->reg_bus.bus_scale_pdata = &rot_reg_bus_scale_table;
- usecases = mgr->reg_bus.bus_scale_pdata->num_usecases;
- for (i = 0; i < usecases; i++) {
- rot_reg_bus_usecases[i].num_paths = 1;
- rot_reg_bus_usecases[i].vectors =
- &rot_reg_bus_vectors[i];
+ node = of_get_child_by_name(dev->dev.of_node, "qcom,rot-reg-bus");
+ if (node) {
+ mgr->reg_bus.bus_scale_pdata
+ = msm_bus_pdata_from_node(dev, node);
+ if (IS_ERR_OR_NULL(mgr->reg_bus.bus_scale_pdata)) {
+ SDEROT_ERR("reg bus pdata parsing failed\n");
+ ret = PTR_ERR(mgr->reg_bus.bus_scale_pdata);
+ if (!mgr->reg_bus.bus_scale_pdata)
+ ret = -EINVAL;
+ mgr->reg_bus.bus_scale_pdata = NULL;
+ }
+ } else {
+ SDEROT_DBG(
+ "no DT entries, configuring default reg bus table\n");
+ mgr->reg_bus.bus_scale_pdata = &rot_reg_bus_scale_table;
+ usecases = mgr->reg_bus.bus_scale_pdata->num_usecases;
+ for (i = 0; i < usecases; i++) {
+ rot_reg_bus_usecases[i].num_paths = 1;
+ rot_reg_bus_usecases[i].vectors =
+ &rot_reg_bus_vectors[i];
+ }
}
return ret;
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index 9f8b341..a7b1852 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -846,10 +846,6 @@ static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
if (!dev || !freq)
return -EINVAL;
- /* Start with highest frequecy and decide correct one later*/
-
- ab_kbps = INT_MAX;
-
gov = container_of(dev->governor,
struct governor, devfreq_gov);
dev->profile->get_dev_status(dev->dev.parent, &stats);
@@ -860,11 +856,11 @@ static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
for (c = 0; c < vidc_data->data_count; ++c) {
if (vidc_data->data->power_mode == VIDC_POWER_TURBO) {
+ ab_kbps = INT_MAX;
goto exit;
}
}
- ab_kbps = 0;
for (c = 0; c < vidc_data->data_count; ++c)
ab_kbps += __calculate(&vidc_data->data[c], gov->mode);
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 1991a34..32e79f2 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1360,11 +1360,15 @@ int create_pkt_cmd_session_set_property(
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
- if (hfi)
- hfi->conceal_color =
+ if (hfi) {
+ hfi->conceal_color_8bit =
((struct hfi_conceal_color *) pdata)->
- conceal_color;
- pkt->size += sizeof(u32) * 2;
+ conceal_color_8bit;
+ hfi->conceal_color_10bit =
+ ((struct hfi_conceal_color *) pdata)->
+ conceal_color_10bit;
+ }
+ pkt->size += sizeof(u32) + sizeof(struct hfi_conceal_color);
break;
}
case HAL_PARAM_VPE_ROTATION:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index c2a93a96..e5d1576 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -337,26 +337,26 @@ static int hfi_process_session_error(u32 device_id,
cmd_done.device_id = device_id;
cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
cmd_done.status = hfi_map_err_status(pkt->event_data1);
+ info->response.cmd = cmd_done;
dprintk(VIDC_INFO, "Received: SESSION_ERROR with event id : %#x %#x\n",
pkt->event_data1, pkt->event_data2);
switch (pkt->event_data1) {
+ /* Ignore below errors */
case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
- case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
- case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
- cmd_done.status = VIDC_ERR_NONE;
dprintk(VIDC_INFO, "Non Fatal: HFI_EVENT_SESSION_ERROR\n");
info->response_type = HAL_RESPONSE_UNUSED;
- info->response.cmd = cmd_done;
- return 0;
+ break;
default:
+ /* All other errors are not expected and treated as sys error */
dprintk(VIDC_ERR,
- "HFI_EVENT_SESSION_ERROR: data1 %#x, data2 %#x\n",
- pkt->event_data1, pkt->event_data2);
- info->response_type = HAL_SESSION_ERROR;
- info->response.cmd = cmd_done;
- return 0;
+ "%s: data1 %#x, data2 %#x, treat as sys error\n",
+ __func__, pkt->event_data1, pkt->event_data2);
+ info->response_type = HAL_SYS_ERROR;
+ break;
}
+
+ return 0;
}
static int hfi_process_event_notify(u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index acca9f4..e1da47d 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -24,7 +24,8 @@
#define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS MIN_NUM_CAPTURE_BUFFERS
#define MIN_NUM_DEC_OUTPUT_BUFFERS 4
#define MIN_NUM_DEC_CAPTURE_BUFFERS 4
-#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
+// Y=16(0-9bits), Cb(10-19bits)=Cr(20-29bits)=128, black by default
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010
#define MB_SIZE_IN_PIXEL (16 * 16)
#define OPERATING_FRAME_RATE_STEP (1 << 16)
@@ -264,11 +265,20 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
- .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
- .name = "Picture concealed color",
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT,
+ .name = "Picture concealed color 8bit",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0x0,
- .maximum = 0xffffff,
+ .maximum = 0xff3fcff,
+ .default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT,
+ .name = "Picture concealed color 10bit",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0x0,
+ .maximum = 0x3fffffff,
.default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
.step = 1,
},
@@ -804,6 +814,10 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
}
bufreq->buffer_count_min =
MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
+ bufreq->buffer_count_min_host =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
+ bufreq->buffer_count_actual =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
@@ -819,6 +833,10 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
bufreq->buffer_count_min =
MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS;
+ bufreq->buffer_count_min_host =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
+ bufreq->buffer_count_actual =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
bufreq = get_buff_req_buffer(inst,
HAL_BUFFER_OUTPUT2);
@@ -831,6 +849,11 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
bufreq->buffer_count_min =
MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS;
+ bufreq->buffer_count_min_host =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
+ bufreq->buffer_count_actual =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
+
} else {
bufreq = get_buff_req_buffer(inst,
@@ -843,6 +866,10 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
}
bufreq->buffer_count_min =
MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS;
+ bufreq->buffer_count_min_host =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
+ bufreq->buffer_count_actual =
+ MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
}
@@ -974,11 +1001,6 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
break;
}
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
- property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
- property_val = ctrl->val;
- pdata = &property_val;
- break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
property_id =
@@ -1067,22 +1089,27 @@ int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
int rc = 0, i = 0, fourcc = 0;
struct v4l2_ext_control *ext_control;
struct v4l2_control control;
+ struct hal_conceal_color conceal_color = {0};
+ struct hfi_device *hdev;
- if (!inst || !inst->core || !ctrl) {
+ if (!inst || !inst->core || !inst->core->device || !ctrl) {
dprintk(VIDC_ERR,
"%s invalid parameters\n", __func__);
return -EINVAL;
}
+ hdev = inst->core->device;
+
+ v4l2_try_ext_ctrls(&inst->ctrl_handler, ctrl);
+
ext_control = ctrl->controls;
- control.id =
- V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
for (i = 0; i < ctrl->count; i++) {
switch (ext_control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
control.value = ext_control[i].value;
-
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
rc = msm_comm_s_ctrl(inst, &control);
if (rc)
dprintk(VIDC_ERR,
@@ -1090,6 +1117,8 @@ int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
__func__, rc);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT:
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
switch (ext_control[i].value) {
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE:
if (!msm_comm_g_ctrl_for_id(inst, control.id)) {
@@ -1135,6 +1164,36 @@ int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
break;
}
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT:
+ conceal_color.conceal_color_8bit = ext_control[i].value;
+ i++;
+ switch (ext_control[i].id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT:
+ conceal_color.conceal_color_10bit =
+ ext_control[i].value;
+ dprintk(VIDC_DBG,
+ "conceal color: 8bit=0x%x 10bit=0x%x",
+ conceal_color.conceal_color_8bit,
+ conceal_color.conceal_color_10bit);
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session,
+ HAL_PARAM_VDEC_CONCEAL_COLOR,
+ &conceal_color);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s Failed setting conceal color",
+ __func__);
+ }
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "%s Could not find CONCEAL_COLOR_10BIT ext_control",
+ __func__);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ break;
default:
dprintk(VIDC_ERR
, "%s Unsupported set control %d",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 21ad17a..98a59a5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -918,6 +918,10 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
}
fail_start:
+ if (rc) {
+ dprintk(VIDC_ERR, "%s: kill session %pK\n", __func__, inst);
+ msm_comm_kill_session(inst);
+ }
return rc;
}
@@ -1601,13 +1605,25 @@ void *msm_vidc_open(int core_id, int session_type)
}
EXPORT_SYMBOL(msm_vidc_open);
-static void cleanup_instance(struct msm_vidc_inst *inst)
+static void msm_vidc_cleanup_instance(struct msm_vidc_inst *inst)
{
+ struct msm_vidc_buffer *temp, *dummy;
+
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return;
}
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry_safe(temp, dummy, &inst->registeredbufs.list,
+ list) {
+ print_vidc_buffer(VIDC_ERR, "undequeud buf", inst, temp);
+ msm_comm_unmap_vidc_buffer(inst, temp);
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+
msm_comm_free_freq_table(inst);
if (msm_comm_release_scratch_buffers(inst, false))
@@ -1661,18 +1677,18 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst)
msm_comm_ctrl_deinit(inst);
- DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
- DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
- DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq);
- DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
- DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
-
v4l2_fh_del(&inst->event_handler);
v4l2_fh_exit(&inst->event_handler);
for (i = 0; i < MAX_PORT_NUM; i++)
vb2_queue_release(&inst->bufq[i].vb2_bufq);
+ DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq);
+ DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
+
mutex_destroy(&inst->sync_lock);
mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
@@ -1695,7 +1711,6 @@ static void close_helper(struct kref *kref)
int msm_vidc_close(void *instance)
{
struct msm_vidc_inst *inst = instance;
- struct msm_vidc_buffer *temp, *dummy;
int rc = 0;
if (!inst || !inst->core) {
@@ -1707,30 +1722,20 @@ int msm_vidc_close(void *instance)
* Make sure that HW stop working on these buffers that
* we are going to free.
*/
- if (inst->state != MSM_VIDC_CORE_INVALID &&
- inst->core->state != VIDC_CORE_INVALID)
- rc = msm_comm_try_state(inst,
- MSM_VIDC_RELEASE_RESOURCES_DONE);
-
- mutex_lock(&inst->registeredbufs.lock);
- list_for_each_entry_safe(temp, dummy, &inst->registeredbufs.list,
- list) {
- print_vidc_buffer(VIDC_ERR, "undequeud buf", inst, temp);
- msm_comm_unmap_vidc_buffer(inst, temp);
- list_del(&temp->list);
- kfree(temp);
- }
- mutex_unlock(&inst->registeredbufs.lock);
-
- cleanup_instance(inst);
- if (inst->state != MSM_VIDC_CORE_INVALID &&
- inst->core->state != VIDC_CORE_INVALID)
- rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
- else
- rc = msm_comm_force_cleanup(inst);
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
if (rc)
dprintk(VIDC_ERR,
- "Failed to move video instance to uninit state\n");
+ "Failed to move inst %pK to rel resource done state\n",
+ inst);
+
+ msm_vidc_cleanup_instance(inst);
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst %pK to uninit state\n", inst);
+ rc = msm_comm_force_cleanup(inst);
+ }
msm_comm_session_clean(inst);
msm_smem_delete_client(inst->mem_client);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 61c4d7b..efc2b51 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1175,11 +1175,6 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
if (!rc) {
dprintk(VIDC_ERR, "Wait interrupted or timed out: %d\n",
SESSION_MSG_INDEX(cmd));
- call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
- dprintk(VIDC_ERR,
- "sess resp timeout can potentially crash the system\n");
- msm_comm_print_debug_info(inst);
- msm_vidc_handle_hw_error(inst->core);
msm_comm_kill_session(inst);
rc = -EIO;
} else {
@@ -1951,7 +1946,6 @@ static void handle_session_error(enum hal_command_response cmd, void *data)
hdev = inst->core->device;
dprintk(VIDC_WARN, "Session error received for session %pK\n", inst);
- change_inst_state(inst, MSM_VIDC_CORE_INVALID);
if (response->status == VIDC_ERR_MAX_CLIENTS) {
dprintk(VIDC_WARN, "Too many clients, rejecting %pK", inst);
@@ -1989,7 +1983,6 @@ static void msm_comm_clean_notify_client(struct msm_vidc_core *core)
dprintk(VIDC_WARN, "%s: Core %pK\n", __func__, core);
mutex_lock(&core->lock);
- core->state = VIDC_CORE_INVALID;
list_for_each_entry(inst, &core->instances, list) {
mutex_lock(&inst->lock);
@@ -2026,52 +2019,37 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
}
mutex_lock(&core->lock);
- if (core->state == VIDC_CORE_INVALID ||
- core->state == VIDC_CORE_UNINIT) {
+ if (core->state == VIDC_CORE_UNINIT) {
dprintk(VIDC_ERR,
- "%s: Core already moved to state %d\n",
- __func__, core->state);
+ "%s: Core %pK already moved to state %d\n",
+ __func__, core, core->state);
mutex_unlock(&core->lock);
return;
}
- mutex_unlock(&core->lock);
- dprintk(VIDC_WARN, "SYS_ERROR %d received for core %pK\n", cmd, core);
- msm_comm_clean_notify_client(core);
-
- hdev = core->device;
- mutex_lock(&core->lock);
- if (core->state == VIDC_CORE_INVALID) {
- dprintk(VIDC_DBG, "Calling core_release\n");
- rc = call_hfi_op(hdev, core_release,
- hdev->hfi_device_data);
- if (rc) {
- dprintk(VIDC_ERR, "core_release failed\n");
- mutex_unlock(&core->lock);
- return;
- }
- core->state = VIDC_CORE_UNINIT;
- }
- mutex_unlock(&core->lock);
-
- msm_vidc_print_running_insts(core);
+ dprintk(VIDC_WARN, "SYS_ERROR received for core %pK\n", core);
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
+ list_for_each_entry(inst, &core->instances, list) {
+ dprintk(VIDC_WARN,
+ "%s: Send sys error for inst %pK\n", __func__, inst);
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+ 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) {
+ dprintk(VIDC_ERR, "core_release failed\n");
+ mutex_unlock(&core->lock);
+ return;
+ }
+ core->state = VIDC_CORE_UNINIT;
+ mutex_unlock(&core->lock);
+
dprintk(VIDC_ERR,
"SYS_ERROR can potentially crash the system\n");
- /*
- * For SYS_ERROR, there will not be any inst pointer.
- * Just grab one of the inst from instances list and
- * use it.
- */
-
- mutex_lock(&core->lock);
- inst = list_first_entry_or_null(&core->instances,
- struct msm_vidc_inst, list);
- mutex_unlock(&core->lock);
-
- msm_comm_print_debug_info(inst);
-
msm_vidc_handle_hw_error(core);
}
@@ -2084,19 +2062,22 @@ void msm_comm_session_clean(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "%s invalid params\n", __func__);
return;
}
+ if (!inst->session) {
+ dprintk(VIDC_DBG, "%s: inst %pK session already cleaned\n",
+ __func__, inst);
+ return;
+ }
hdev = inst->core->device;
mutex_lock(&inst->lock);
- if (hdev && inst->session) {
- dprintk(VIDC_DBG, "cleaning up instance: %pK\n", inst);
- rc = call_hfi_op(hdev, session_clean,
- (void *)inst->session);
- if (rc) {
- dprintk(VIDC_ERR,
- "Session clean failed :%pK\n", inst);
- }
- inst->session = NULL;
+ dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst);
+ rc = call_hfi_op(hdev, session_clean,
+ (void *)inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session clean failed :%pK\n", inst);
}
+ inst->session = NULL;
mutex_unlock(&inst->lock);
}
@@ -2586,31 +2567,26 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst)
hdev = inst->core->device;
abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE);
+ dprintk(VIDC_WARN, "%s: inst %pK\n", __func__, inst);
rc = call_hfi_op(hdev, session_abort, (void *)inst->session);
if (rc) {
dprintk(VIDC_ERR,
"%s session_abort failed rc: %d\n", __func__, rc);
- return rc;
+ goto exit;
}
rc = wait_for_completion_timeout(
&inst->completions[abort_completion],
msecs_to_jiffies(
inst->core->resources.msm_vidc_hw_rsp_timeout));
if (!rc) {
- dprintk(VIDC_ERR,
- "%s: Wait interrupted or timed out [%pK]: %d\n",
- __func__, inst, abort_completion);
- call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
- dprintk(VIDC_ERR,
- "ABORT timeout can potentially crash the system\n");
- msm_comm_print_debug_info(inst);
-
- msm_vidc_handle_hw_error(inst->core);
+ dprintk(VIDC_ERR, "%s: inst %pK abort timed out\n",
+ __func__, inst);
+ msm_comm_generate_sys_error(inst);
rc = -EBUSY;
} else {
rc = 0;
}
- msm_comm_session_clean(inst);
+exit:
return rc;
}
@@ -2765,7 +2741,7 @@ static int msm_comm_init_core(struct msm_vidc_inst *inst)
"%s: capabilities memory is expected to be freed\n",
__func__);
}
-
+ dprintk(VIDC_DBG, "%s: core %pK\n", __func__, core);
rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data);
if (rc) {
dprintk(VIDC_ERR, "Failed to init core, id = %d\n",
@@ -2825,13 +2801,12 @@ static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
* e.g. thumbnail generation.
*/
schedule_delayed_work(&core->fw_unload_work,
- msecs_to_jiffies(core->state == VIDC_CORE_INVALID ?
- 0 :
- core->resources.msm_vidc_firmware_unload_delay));
+ msecs_to_jiffies(core->state == VIDC_CORE_INIT_DONE ?
+ core->resources.msm_vidc_firmware_unload_delay : 0));
dprintk(VIDC_DBG, "firmware unload delayed by %u ms\n",
- core->state == VIDC_CORE_INVALID ?
- 0 : core->resources.msm_vidc_firmware_unload_delay);
+ core->state == VIDC_CORE_INIT_DONE ?
+ core->resources.msm_vidc_firmware_unload_delay : 0);
}
core_already_uninited:
@@ -2875,6 +2850,7 @@ static int msm_comm_session_init(int flipped_state,
msm_comm_init_clocks_and_bus_data(inst);
+ dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst);
rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data,
inst, get_hal_domain(inst->session_type),
get_hal_codec(fourcc),
@@ -2940,19 +2916,17 @@ static int msm_vidc_load_resources(int flipped_state,
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
-
- core = inst->core;
- if (core->state == VIDC_CORE_INVALID) {
- dprintk(VIDC_ERR,
- "Core is in bad state can't do load res\n");
- return -EINVAL;
- }
-
if (inst->state == MSM_VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
- "Instance is in invalid state can't do load res\n");
+ "%s: inst %pK is in invalid state\n", __func__, inst);
return -EINVAL;
}
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+ dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
+ inst, inst->state);
+ goto exit;
+ }
+ core = inst->core;
num_mbs_per_sec =
msm_comm_get_load(core, MSM_VIDC_DECODER, quirks) +
@@ -2965,18 +2939,12 @@ static int msm_vidc_load_resources(int flipped_state,
dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
num_mbs_per_sec, max_load_adj);
msm_vidc_print_running_insts(core);
- inst->state = MSM_VIDC_CORE_INVALID;
msm_comm_kill_session(inst);
return -EBUSY;
}
hdev = core->device;
- if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
- dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
- inst, inst->state);
- goto exit;
- }
-
+ dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst);
rc = call_hfi_op(hdev, session_load_res, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -2997,21 +2965,19 @@ static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
- if (inst->state == MSM_VIDC_CORE_INVALID ||
- inst->core->state == VIDC_CORE_INVALID) {
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
- "Core is in bad state can't do start\n");
+ "%s: inst %pK is in invalid\n", __func__, inst);
return -EINVAL;
}
-
- hdev = inst->core->device;
-
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
dprintk(VIDC_INFO,
"inst: %pK is already in state: %d\n",
inst, inst->state);
goto exit;
}
+ hdev = inst->core->device;
+ dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst);
rc = call_hfi_op(hdev, session_start, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -3032,18 +2998,23 @@ static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
- hdev = inst->core->device;
-
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "%s: inst %pK is in invalid state\n", __func__, inst);
+ return -EINVAL;
+ }
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
dprintk(VIDC_INFO,
"inst: %pK is already in state: %d\n",
inst, inst->state);
goto exit;
}
- dprintk(VIDC_DBG, "Send Stop to hal\n");
+ hdev = inst->core->device;
+ dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst);
rc = call_hfi_op(hdev, session_stop, (void *) inst->session);
if (rc) {
- dprintk(VIDC_ERR, "Failed to send stop\n");
+ dprintk(VIDC_ERR, "%s: inst %pK session_stop failed\n",
+ __func__, inst);
goto exit;
}
change_inst_state(inst, MSM_VIDC_STOP);
@@ -3060,16 +3031,19 @@ static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
- hdev = inst->core->device;
-
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "%s: inst %pK is in invalid state\n", __func__, inst);
+ return -EINVAL;
+ }
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
dprintk(VIDC_INFO,
"inst: %pK is already in state: %d\n",
inst, inst->state);
goto exit;
}
- dprintk(VIDC_DBG,
- "Send release res to hal\n");
+ hdev = inst->core->device;
+ dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst);
rc = call_hfi_op(hdev, session_release_res, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -3091,15 +3065,14 @@ static int msm_comm_session_close(int flipped_state,
dprintk(VIDC_ERR, "%s invalid params\n", __func__);
return -EINVAL;
}
- hdev = inst->core->device;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
dprintk(VIDC_INFO,
"inst: %pK is already in state: %d\n",
inst, inst->state);
goto exit;
}
- dprintk(VIDC_DBG,
- "Send session close to hal\n");
+ hdev = inst->core->device;
+ dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst);
rc = call_hfi_op(hdev, session_end, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -3132,7 +3105,7 @@ int msm_comm_suspend(int core_id)
}
mutex_lock(&core->lock);
- if (core->state == VIDC_CORE_INVALID) {
+ if (core->state != VIDC_CORE_INIT_DONE) {
dprintk(VIDC_ERR,
"%s - fw is not in proper state, skip suspend\n",
__func__);
@@ -3490,30 +3463,23 @@ int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
{
int rc = 0;
int flipped_state;
- struct msm_vidc_core *core;
if (!inst) {
- dprintk(VIDC_ERR,
- "Invalid instance pointer = %pK\n", inst);
+ dprintk(VIDC_ERR, "%s: invalid params %pK", __func__, inst);
return -EINVAL;
}
dprintk(VIDC_DBG,
"Trying to move inst: %pK from: %#x to %#x\n",
inst, inst->state, state);
- core = inst->core;
- if (!core) {
- dprintk(VIDC_ERR,
- "Invalid core pointer = %pK\n", inst);
+
+ mutex_lock(&inst->sync_lock);
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR, "%s: inst %pK is in invalid\n",
+ __func__, inst);
+ mutex_unlock(&inst->sync_lock);
return -EINVAL;
}
- mutex_lock(&inst->sync_lock);
- if (inst->state == MSM_VIDC_CORE_INVALID ||
- core->state == VIDC_CORE_INVALID) {
- dprintk(VIDC_ERR,
- "Core is in bad state can't change the state\n");
- rc = -EINVAL;
- goto exit;
- }
+
flipped_state = get_flipped_state(inst->state, state);
dprintk(VIDC_DBG,
"flipped_state = %#x\n", flipped_state);
@@ -3593,15 +3559,17 @@ int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
rc = -EINVAL;
break;
}
-exit:
mutex_unlock(&inst->sync_lock);
- if (rc)
+
+ if (rc) {
dprintk(VIDC_ERR,
"Failed to move from state: %d to %d\n",
inst->state, state);
- else
+ msm_comm_kill_session(inst);
+ } else {
trace_msm_vidc_common_state_change((void *)inst,
inst->state, state);
+ }
return rc;
}
@@ -3631,14 +3599,6 @@ int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd)
switch (which_cmd) {
case V4L2_QCOM_CMD_FLUSH:
- if (core->state != VIDC_CORE_INVALID &&
- inst->state == MSM_VIDC_CORE_INVALID) {
- rc = msm_comm_kill_session(inst);
- if (rc)
- dprintk(VIDC_ERR,
- "Fail to clean session: %d\n",
- rc);
- }
rc = msm_comm_flush(inst, flags);
if (rc) {
dprintk(VIDC_ERR,
@@ -4252,13 +4212,6 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
"%s: Wait interrupted or timed out [%pK]: %d\n",
__func__, inst,
SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO));
- inst->state = MSM_VIDC_CORE_INVALID;
- call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
- dprintk(VIDC_ERR,
- "SESS_PROP timeout can potentially crash the system\n");
- msm_comm_print_debug_info(inst);
-
- msm_vidc_handle_hw_error(inst->core);
msm_comm_kill_session(inst);
rc = -ETIMEDOUT;
goto exit;
@@ -4333,9 +4286,7 @@ int msm_comm_release_output_buffers(struct msm_vidc_inst *inst,
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = handle->device_addr;
if (inst->buffer_mode_set[CAPTURE_PORT] ==
- HAL_BUFFER_MODE_STATIC &&
- inst->state != MSM_VIDC_CORE_INVALID &&
- core->state != VIDC_CORE_INVALID) {
+ HAL_BUFFER_MODE_STATIC) {
buffer_info.response_required = false;
rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
@@ -4441,26 +4392,23 @@ int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
buffer_info.buffer_type = buf->buffer_type;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = handle->device_addr;
- if (inst->state != MSM_VIDC_CORE_INVALID &&
- core->state != VIDC_CORE_INVALID) {
- buffer_info.response_required = true;
- rc = call_hfi_op(hdev, session_release_buffers,
+ buffer_info.response_required = true;
+ rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
- if (rc) {
- dprintk(VIDC_WARN,
- "Rel scrtch buf fail:%x, %d\n",
- buffer_info.align_device_addr,
- buffer_info.buffer_size);
- }
+ if (!rc) {
mutex_unlock(&inst->scratchbufs.lock);
rc = wait_for_sess_signal_receipt(inst,
HAL_SESSION_RELEASE_BUFFER_DONE);
- if (rc) {
- change_inst_state(inst,
- MSM_VIDC_CORE_INVALID);
- msm_comm_kill_session(inst);
- }
+ if (rc)
+ dprintk(VIDC_WARN,
+ "%s: wait for signal failed, rc %d\n",
+ __func__, rc);
mutex_lock(&inst->scratchbufs.lock);
+ } else {
+ dprintk(VIDC_WARN,
+ "Rel scrtch buf fail:%x, %d\n",
+ buffer_info.align_device_addr,
+ buffer_info.buffer_size);
}
/*If scratch buffers can be reused, do not free the buffers*/
@@ -4532,25 +4480,23 @@ int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
buffer_info.buffer_type = buf->buffer_type;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = handle->device_addr;
- if (inst->state != MSM_VIDC_CORE_INVALID &&
- core->state != VIDC_CORE_INVALID) {
- buffer_info.response_required = true;
- rc = call_hfi_op(hdev, session_release_buffers,
+ buffer_info.response_required = true;
+ rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
- if (rc) {
- dprintk(VIDC_WARN,
- "Rel prst buf fail:%x, %d\n",
- buffer_info.align_device_addr,
- buffer_info.buffer_size);
- }
+ if (!rc) {
mutex_unlock(&inst->persistbufs.lock);
rc = wait_for_sess_signal_receipt(inst,
HAL_SESSION_RELEASE_BUFFER_DONE);
- if (rc) {
- change_inst_state(inst, MSM_VIDC_CORE_INVALID);
- msm_comm_kill_session(inst);
- }
+ if (rc)
+ dprintk(VIDC_WARN,
+ "%s: wait for signal failed, rc %d\n",
+ __func__, rc);
mutex_lock(&inst->persistbufs.lock);
+ } else {
+ dprintk(VIDC_WARN,
+ "Rel prst buf fail:%x, %d\n",
+ buffer_info.align_device_addr,
+ buffer_info.buffer_size);
}
list_del(&buf->list);
msm_comm_smem_free(inst, handle);
@@ -4994,6 +4940,7 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
{
u32 x_min, x_max, y_min, y_max;
u32 input_height, input_width, output_height, output_width;
+ u32 rotation;
input_height = inst->prop.height[OUTPUT_PORT];
input_width = inst->prop.width[OUTPUT_PORT];
@@ -5029,6 +4976,20 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
return 0;
}
+ rotation = msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+
+ if ((output_width != output_height) &&
+ (rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 ||
+ rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)) {
+
+ output_width = inst->prop.height[CAPTURE_PORT];
+ output_height = inst->prop.width[CAPTURE_PORT];
+ dprintk(VIDC_DBG,
+ "Rotation=%u Swapped Output W=%u H=%u to check scaling",
+ rotation, output_width, output_height);
+ }
+
x_min = (1<<16)/inst->capability.scale_x.min;
y_min = (1<<16)/inst->capability.scale_y.min;
x_max = inst->capability.scale_x.max >> 16;
@@ -5083,7 +5044,6 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
core = inst->core;
rc = msm_vidc_load_supported(inst);
if (rc) {
- change_inst_state(inst, MSM_VIDC_CORE_INVALID);
dprintk(VIDC_WARN,
"%s: Hardware is overloaded\n", __func__);
return rc;
@@ -5110,7 +5070,7 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
if (!rc && inst->prop.width[CAPTURE_PORT] >
capability->width.max) {
dprintk(VIDC_ERR,
- "Unsupported width = %u supported max width = %u",
+ "Unsupported width = %u supported max width = %u\n",
inst->prop.width[CAPTURE_PORT],
capability->width.max);
rc = -ENOTSUPP;
@@ -5132,7 +5092,6 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
}
}
if (rc) {
- change_inst_state(inst, MSM_VIDC_CORE_INVALID);
dprintk(VIDC_ERR,
"%s: Resolution unsupported\n", __func__);
}
@@ -5144,12 +5103,11 @@ static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
enum hal_command_response cmd = HAL_SESSION_ERROR;
struct msm_vidc_cb_cmd_done response = {0};
- dprintk(VIDC_WARN, "msm_comm_generate_session_error\n");
if (!inst || !inst->core) {
dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
return;
}
-
+ dprintk(VIDC_WARN, "%s: inst %pK\n", __func__, inst);
response.session_id = inst;
response.status = VIDC_ERR_FAIL;
handle_session_error(cmd, (void *)&response);
@@ -5165,6 +5123,7 @@ static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
return;
}
+ dprintk(VIDC_WARN, "%s: inst %pK\n", __func__, inst);
core = inst->core;
response.device_id = (u32) core->id;
handle_sys_error(cmd, (void *) &response);
@@ -5179,10 +5138,13 @@ int msm_comm_kill_session(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
return -EINVAL;
} else if (!inst->session) {
- /* There's no hfi session to kill */
+ dprintk(VIDC_ERR, "%s: no session to kill for inst %pK\n",
+ __func__, inst);
return 0;
}
+ dprintk(VIDC_WARN, "%s: inst %pK, state %d\n", __func__,
+ inst, inst->state);
/*
* We're internally forcibly killing the session, if fw is aware of
* the session send session_abort to firmware to clean up and release
@@ -5191,20 +5153,18 @@ int msm_comm_kill_session(struct msm_vidc_inst *inst)
if ((inst->state >= MSM_VIDC_OPEN_DONE &&
inst->state < MSM_VIDC_CLOSE_DONE) ||
inst->state == MSM_VIDC_CORE_INVALID) {
- if (msm_comm_session_abort(inst)) {
- msm_comm_generate_sys_error(inst);
- return 0;
+ rc = msm_comm_session_abort(inst);
+ if (rc) {
+ dprintk(VIDC_WARN, "%s: inst %pK abort failed\n",
+ __func__, inst);
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
}
- change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
- msm_comm_generate_session_error(inst);
- } else {
- dprintk(VIDC_WARN,
- "Inactive session %pK, triggering an internal session error\n",
- inst);
- msm_comm_generate_session_error(inst);
-
}
+ change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+ msm_comm_session_clean(inst);
+
+ dprintk(VIDC_WARN, "%s: inst %pK handled\n", __func__, inst);
return rc;
}
@@ -5624,8 +5584,7 @@ int msm_comm_session_continue(void *instance)
hdev = inst->core->device;
mutex_lock(&inst->lock);
if (inst->state >= MSM_VIDC_RELEASE_RESOURCES_DONE ||
- inst->state < MSM_VIDC_START_DONE ||
- inst->core->state == VIDC_CORE_INVALID) {
+ inst->state < MSM_VIDC_START_DONE) {
dprintk(VIDC_DBG,
"Inst %pK : Not in valid state to call %s\n",
inst, __func__);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 677ee89..49e6c3ec 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -83,7 +83,6 @@ enum vidc_core_state {
VIDC_CORE_UNINIT = 0,
VIDC_CORE_INIT,
VIDC_CORE_INIT_DONE,
- VIDC_CORE_INVALID
};
/*
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index dad4b60..b430d14 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -90,6 +90,8 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet);
static int __initialize_packetization(struct venus_hfi_device *device);
static struct hal_session *__get_session(struct venus_hfi_device *device,
u32 session_id);
+static bool __is_session_valid(struct venus_hfi_device *device,
+ struct hal_session *session, const char *func);
static int __set_clocks(struct venus_hfi_device *device, u32 freq);
static int __iface_cmdq_write(struct venus_hfi_device *device,
void *pkt);
@@ -1668,11 +1670,9 @@ static int __sys_set_power_control(struct venus_hfi_device *device,
static int venus_hfi_core_init(void *device)
{
+ int rc = 0;
struct hfi_cmd_sys_init_packet pkt;
struct hfi_cmd_sys_get_property_packet version_pkt;
- int rc = 0;
- struct list_head *ptr, *next;
- struct hal_session *session = NULL;
struct venus_hfi_device *dev;
if (!device) {
@@ -1681,8 +1681,16 @@ static int venus_hfi_core_init(void *device)
}
dev = device;
+
+ dprintk(VIDC_DBG, "Core initializing\n");
+
mutex_lock(&dev->lock);
+ dev->bus_vote.data =
+ kzalloc(sizeof(struct vidc_bus_vote_data), GFP_KERNEL);
+ dev->bus_vote.data_count = 1;
+ dev->bus_vote.data->power_mode = VIDC_POWER_TURBO;
+
rc = __load_fw(dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to load Venus FW\n");
@@ -1691,20 +1699,6 @@ static int venus_hfi_core_init(void *device)
__set_state(dev, VENUS_STATE_INIT);
- list_for_each_safe(ptr, next, &dev->sess_head) {
- /*
- * This means that session list is not empty. Kick stale
- * sessions out of our valid instance list, but keep the
- * list_head inited so that list_del (in the future, called
- * by session_clean()) will be valid. When client doesn't close
- * them, then it is a genuine leak which driver can't fix.
- */
- session = list_entry(ptr, struct hal_session, list);
- list_del_init(&session->list);
- }
-
- INIT_LIST_HEAD(&dev->sess_head);
-
if (!dev->hal_client) {
dev->hal_client = msm_smem_new_client(
SMEM_ION, dev->res, MSM_VIDC_UNKNOWN);
@@ -1766,21 +1760,23 @@ static int venus_hfi_core_init(void *device)
pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY,
dev->res->pm_qos_latency_us);
}
-
+ dprintk(VIDC_DBG, "Core inited successfully\n");
mutex_unlock(&dev->lock);
return rc;
err_core_init:
__set_state(dev, VENUS_STATE_DEINIT);
__unload_fw(dev);
err_load_fw:
+ dprintk(VIDC_ERR, "Core init failed\n");
mutex_unlock(&dev->lock);
return rc;
}
static int venus_hfi_core_release(void *dev)
{
- struct venus_hfi_device *device = dev;
int rc = 0;
+ struct venus_hfi_device *device = dev;
+ struct hal_session *session, *next;
if (!device) {
dprintk(VIDC_ERR, "invalid device\n");
@@ -1788,7 +1784,7 @@ static int venus_hfi_core_release(void *dev)
}
mutex_lock(&device->lock);
-
+ dprintk(VIDC_DBG, "Core releasing\n");
if (device->res->pm_qos_latency_us &&
pm_qos_request_active(&device->qos))
pm_qos_remove_request(&device->qos);
@@ -1797,6 +1793,11 @@ static int venus_hfi_core_release(void *dev)
__set_state(device, VENUS_STATE_DEINIT);
__unload_fw(device);
+ /* unlink all sessions from device */
+ list_for_each_entry_safe(session, next, &device->sess_head, list)
+ list_del(&session->list);
+
+ dprintk(VIDC_DBG, "Core released successfully\n");
mutex_unlock(&device->lock);
return rc;
@@ -1937,6 +1938,10 @@ static int venus_hfi_session_set_property(void *sess,
mutex_lock(&device->lock);
dprintk(VIDC_INFO, "in set_prop,with prop id: %#x\n", ptype);
+ if (!__is_session_valid(device, session, __func__)) {
+ rc = -EINVAL;
+ goto err_set_prop;
+ }
rc = call_hfi_pkt_op(device, session_set_property,
pkt, session, ptype, pdata);
@@ -1979,6 +1984,10 @@ static int venus_hfi_session_get_property(void *sess,
mutex_lock(&device->lock);
dprintk(VIDC_INFO, "%s: property id: %d\n", __func__, ptype);
+ if (!__is_session_valid(device, session, __func__)) {
+ rc = -EINVAL;
+ goto err_create_pkt;
+ }
rc = call_hfi_pkt_op(device, session_get_property,
&pkt, session, ptype);
@@ -2010,8 +2019,25 @@ static void __set_default_sys_properties(struct venus_hfi_device *device)
static void __session_clean(struct hal_session *session)
{
+ struct hal_session *temp, *next;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_WARN, "%s: invalid params\n", __func__);
+ return;
+ }
+ device = session->device;
dprintk(VIDC_DBG, "deleted the session: %pK\n", session);
- list_del(&session->list);
+ /*
+ * session might have been removed from the device list in
+ * core_release, so check and remove if it is in the list
+ */
+ list_for_each_entry_safe(temp, next, &device->sess_head, list) {
+ if (session == temp) {
+ list_del(&session->list);
+ break;
+ }
+ }
/* Poison the session handle with zeros */
*session = (struct hal_session){ {0} };
kfree(session);
@@ -2105,6 +2131,9 @@ static int __send_session_cmd(struct hal_session *session, int pkt_type)
int rc = 0;
struct venus_hfi_device *device = session->device;
+ if (!__is_session_valid(device, session, __func__))
+ return -EINVAL;
+
rc = call_hfi_pkt_op(device, session_cmd,
&pkt, pkt_type, session);
if (rc == -EPERM)
@@ -2190,6 +2219,10 @@ static int venus_hfi_session_set_buffers(void *sess,
device = session->device;
mutex_lock(&device->lock);
+ if (!__is_session_valid(device, session, __func__)) {
+ rc = -EINVAL;
+ goto err_create_pkt;
+ }
if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
/*
* Hardware doesn't care about input buffers being
@@ -2234,6 +2267,10 @@ static int venus_hfi_session_release_buffers(void *sess,
device = session->device;
mutex_lock(&device->lock);
+ if (!__is_session_valid(device, session, __func__)) {
+ rc = -EINVAL;
+ goto err_create_pkt;
+ }
if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
rc = 0;
goto err_create_pkt;
@@ -2368,6 +2405,9 @@ static int __session_etb(struct hal_session *session,
int rc = 0;
struct venus_hfi_device *device = session->device;
+ if (!__is_session_valid(device, session, __func__))
+ return -EINVAL;
+
if (session->is_decoder) {
struct hfi_cmd_session_empty_buffer_compressed_packet pkt;
@@ -2437,6 +2477,9 @@ static int __session_ftb(struct hal_session *session,
struct venus_hfi_device *device = session->device;
struct hfi_cmd_session_fill_buffer_packet pkt;
+ if (!__is_session_valid(device, session, __func__))
+ return -EINVAL;
+
rc = call_hfi_pkt_op(device, session_ftb,
&pkt, session, output_frame);
if (rc) {
@@ -2490,6 +2533,12 @@ static int venus_hfi_session_process_batch(void *sess,
device = session->device;
mutex_lock(&device->lock);
+
+ if (!__is_session_valid(device, session, __func__)) {
+ rc = -EINVAL;
+ goto err_etbs_and_ftbs;
+ }
+
for (c = 0; c < num_ftbs; ++c) {
rc = __session_ftb(session, &ftbs[c], true);
if (rc) {
@@ -2537,6 +2586,10 @@ static int venus_hfi_session_get_buf_req(void *sess)
device = session->device;
mutex_lock(&device->lock);
+ if (!__is_session_valid(device, session, __func__)) {
+ rc = -EINVAL;
+ goto err_create_pkt;
+ }
rc = call_hfi_pkt_op(device, session_get_buf_req,
&pkt, session);
if (rc) {
@@ -2567,6 +2620,10 @@ static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode)
device = session->device;
mutex_lock(&device->lock);
+ if (!__is_session_valid(device, session, __func__)) {
+ rc = -EINVAL;
+ goto err_create_pkt;
+ }
rc = call_hfi_pkt_op(device, session_flush,
&pkt, session, flush_mode);
if (rc) {
@@ -2844,6 +2901,24 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet)
kfree(packet);
}
+static bool __is_session_valid(struct venus_hfi_device *device,
+ struct hal_session *session, const char *func)
+{
+ struct hal_session *temp = NULL;
+
+ if (!device || !session)
+ goto invalid;
+
+ list_for_each_entry(temp, &device->sess_head, list)
+ if (session == temp)
+ return true;
+
+invalid:
+ dprintk(VIDC_WARN, "%s: device %pK, invalid session %pK\n",
+ func, device, session);
+ return false;
+}
+
static struct hal_session *__get_session(struct venus_hfi_device *device,
u32 session_id)
{
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 79ce858..fbd3b02 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -996,6 +996,11 @@ struct buffer_requirements {
struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
};
+struct hal_conceal_color {
+ u32 conceal_color_8bit;
+ u32 conceal_color_10bit;
+};
+
union hal_get_property {
struct hal_frame_rate frame_rate;
struct hal_uncompressed_format_select format_select;
@@ -1045,6 +1050,7 @@ union hal_get_property {
struct hal_buffer_alloc_mode buffer_alloc_mode;
struct buffer_requirements buf_req;
enum hal_h264_entropy h264_entropy;
+ struct hal_conceal_color conceal_color;
};
/* HAL Response */
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index d5624ce..a522918 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -478,7 +478,8 @@ struct hfi_vpe_rotation_type {
};
struct hfi_conceal_color {
- u32 conceal_color;
+ u32 conceal_color_8bit;
+ u32 conceal_color_10bit;
};
struct hfi_intra_period {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 093f28a..3e9448b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -479,12 +479,17 @@ static int mmc_devfreq_set_target(struct device *dev,
struct mmc_devfeq_clk_scaling *clk_scaling;
int err = 0;
int abort;
+ unsigned long pflags = current->flags;
+
+ /* Ensure scaling would happen even in memory pressure conditions */
+ current->flags |= PF_MEMALLOC;
if (!(host && freq)) {
pr_err("%s: unexpected host/freq parameter\n", __func__);
err = -EINVAL;
goto out;
}
+
clk_scaling = &host->clk_scaling;
if (!clk_scaling->enable)
@@ -548,6 +553,7 @@ static int mmc_devfreq_set_target(struct device *dev,
rel_host:
mmc_release_host(host);
out:
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
return err;
}
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c
index a528e16..e55260d 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.c
+++ b/drivers/platform/msm/seemp_core/seemp_logk.c
@@ -13,6 +13,11 @@
#define pr_fmt(fmt) "seemp: %s: " fmt, __func__
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/seemp_instrumentation.h>
+#include <soc/qcom/scm.h>
+
#include "seemp_logk.h"
#include "seemp_ringbuf.h"
@@ -24,6 +29,8 @@
#define FOUR_MB 4
#define YEAR_BASE 1900
+#define EL2_SCM_ID 0x02001902
+
static struct seemp_logk_dev *slogk_dev;
static unsigned int ring_sz = FOUR_MB;
@@ -49,11 +56,15 @@ static rwlock_t filter_lock;
static struct seemp_source_mask *pmask;
static unsigned int num_sources;
+static void *el2_shared_mem;
+static struct task_struct *rtic_thread;
+
static long seemp_logk_reserve_rdblks(
struct seemp_logk_dev *sdev, unsigned long arg);
static long seemp_logk_set_mask(unsigned long arg);
static long seemp_logk_set_mapping(unsigned long arg);
static long seemp_logk_check_filter(unsigned long arg);
+static int seemp_logk_rtic_thread(void *data);
void* (*seemp_logk_kernel_begin)(char **buf);
@@ -569,6 +580,15 @@ static int seemp_logk_mmap(struct file *filp,
}
}
+ if (!rtic_thread && el2_shared_mem) {
+ rtic_thread = kthread_run(seemp_logk_rtic_thread,
+ NULL, "seemp_logk_rtic_thread");
+ if (IS_ERR(rtic_thread)) {
+ pr_err("rtic_thread creation failed");
+ rtic_thread = NULL;
+ }
+ }
+
return 0;
}
@@ -580,10 +600,59 @@ static const struct file_operations seemp_logk_fops = {
.mmap = seemp_logk_mmap,
};
+static int seemp_logk_rtic_thread(void *data)
+{
+ struct el2_report_header_t *header;
+ __u64 last_sequence_number = 0;
+ int last_pos = -1;
+ int i;
+ int num_entries = (PAGE_SIZE - sizeof(struct el2_report_header_t))
+ / sizeof(struct el2_report_data_t);
+ header = (struct el2_report_header_t *) el2_shared_mem;
+
+ while (!kthread_should_stop()) {
+ for (i = 1; i < num_entries + 1; i++) {
+ struct el2_report_data_t *report;
+ int cur_pos = last_pos + i;
+
+ if (cur_pos >= num_entries)
+ cur_pos -= num_entries;
+
+ report = el2_shared_mem +
+ sizeof(struct el2_report_header_t) +
+ cur_pos * sizeof(struct el2_report_data_t);
+
+ /* determine legitimacy of report */
+ if (report->report_valid &&
+ report->sequence_number <=
+ header->num_incidents &&
+ (last_sequence_number == 0
+ || report->sequence_number >
+ last_sequence_number)) {
+ seemp_logk_rtic(report->report_type,
+ report->report.incident.actor,
+ report->report.incident.asset_id,
+ report->report.incident.asset_category,
+ report->report.incident.response);
+ last_sequence_number = report->sequence_number;
+ } else {
+ last_pos = cur_pos - 1;
+ break;
+ }
+ }
+
+ /* periodically check el2 report every second */
+ ssleep(1);
+ }
+
+ return 0;
+}
+
__init int seemp_logk_init(void)
{
int ret;
int devno = 0;
+ struct scm_desc desc = {0};
num_sources = 0;
kmalloc_flag = 0;
@@ -650,6 +719,21 @@ __init int seemp_logk_init(void)
init_waitqueue_head(&slogk_dev->readers_wq);
init_waitqueue_head(&slogk_dev->writers_wq);
rwlock_init(&filter_lock);
+
+ el2_shared_mem = (void *) __get_free_page(GFP_KERNEL);
+ if (el2_shared_mem) {
+ desc.arginfo = SCM_ARGS(2, SCM_RW, SCM_VAL);
+ desc.args[0] = (uint64_t) virt_to_phys(el2_shared_mem);
+ desc.args[1] = PAGE_SIZE;
+ ret = scm_call2(EL2_SCM_ID, &desc);
+ if (ret || desc.ret[0] || desc.ret[1]) {
+ pr_err("SCM call failed with ret val = %d %d %d",
+ ret, (int)desc.ret[0], (int)desc.ret[1]);
+ free_page((unsigned long) el2_shared_mem);
+ el2_shared_mem = NULL;
+ }
+ }
+
return 0;
class_destroy_fail:
class_destroy(cl);
@@ -666,6 +750,11 @@ __exit void seemp_logk_cleanup(void)
{
dev_t devno = MKDEV(slogk_dev->major, slogk_dev->minor);
+ if (rtic_thread) {
+ kthread_stop(rtic_thread);
+ rtic_thread = NULL;
+ }
+
seemp_logk_detach();
cdev_del(&slogk_dev->cdev);
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.h b/drivers/platform/msm/seemp_core/seemp_logk.h
index 1a41d4c..871de0e 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.h
+++ b/drivers/platform/msm/seemp_core/seemp_logk.h
@@ -158,4 +158,45 @@ struct seemp_source_mask {
__u32 hash;
bool isOn;
};
+
+/* report region header */
+struct el2_report_header_t {
+ __u64 report_version; /* Version of the EL2 report */
+ __u64 mp_catalog_version;
+ /* Version of MP catalogue used for kernel protection */
+ __u8 protection_enabled; /* Kernel Assets protected by EL2 */
+ __u8 pad1;
+ __u8 pad2;
+ __u8 pad3;
+ __u32 pad4;
+ __u64 num_incidents; /* Number of Incidents Observed by EL2 */
+};
+
+/* individual report contents */
+union el2_report {
+ struct {
+ __u8 asset_id[0x20]; /* Asset Identifier */
+ __u64 actor;
+ /* Actor that caused the Incident. */
+ __u8 asset_category; /* Asset Category */
+ __u8 response; /* Response From EL2 */
+ __u16 pad1;
+ __u32 pad2;
+ } incident;
+ struct {
+ __u64 reserved; /* TBD */
+ } info;
+};
+
+/* individual report */
+struct el2_report_data_t {
+ __u8 report_valid;
+ /* Flag to indicate whether report instance is valid */
+ __u8 report_type; /* Report Type */
+ __u8 pad1;
+ __u8 pad2;
+ __u64 sequence_number; /* Sequence number of the report */
+ union el2_report report; /* Report Contents */
+};
+
#endif
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 4c67c80..ae44f01 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -3688,6 +3688,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
+ vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
/* reset hvdcp voters */
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
@@ -3849,6 +3850,12 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
smblib_handle_typec_removal(chg);
}
+ /* suspend usb if sink */
+ if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
+ vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
+ else
+ vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
+
smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
smblib_typec_mode_name[chg->typec_mode]);
}
@@ -3896,6 +3903,12 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
return IRQ_HANDLED;
}
+ if (chg->pr_swap_in_progress) {
+ smblib_dbg(chg, PR_INTERRUPT,
+ "Ignoring since pr_swap_in_progress\n");
+ return IRQ_HANDLED;
+ }
+
mutex_lock(&chg->lock);
smblib_usb_typec_change(chg);
mutex_unlock(&chg->lock);
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index a2168f0..5c7819e 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -65,6 +65,7 @@ enum print_reason {
#define OTG_DELAY_VOTER "OTG_DELAY_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
+#define OTG_VOTER "OTG_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 7ad650e..d75f157 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2408,6 +2408,14 @@ static void regulator_disable_work(struct work_struct *work)
count = rdev->deferred_disables;
rdev->deferred_disables = 0;
+ /*
+ * Workqueue functions queue the new work instance while the previous
+ * work instance is being processed. Cancel the queued work instance
+ * as the work instance under processing does the job of the queued
+ * work instance.
+ */
+ cancel_delayed_work(&rdev->disable_work);
+
for (i = 0; i < count; i++) {
ret = _regulator_disable(rdev);
if (ret != 0)
@@ -2451,10 +2459,10 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
mutex_lock(&rdev->mutex);
rdev->deferred_disables++;
+ mod_delayed_work(system_power_efficient_wq, &rdev->disable_work,
+ msecs_to_jiffies(ms));
mutex_unlock(&rdev->mutex);
- queue_delayed_work(system_power_efficient_wq, &rdev->disable_work,
- msecs_to_jiffies(ms));
return 0;
}
EXPORT_SYMBOL_GPL(regulator_disable_deferred);
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index d8c5ea8..01779f9 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -182,6 +182,9 @@ static int msm_slim_iommu_attach(struct msm_slim_ctrl *ctrl_dev)
if (!ctrl_dev->iommu_desc.cb_dev)
return 0;
+ if (!IS_ERR_OR_NULL(ctrl_dev->iommu_desc.iommu_map))
+ return 0;
+
dev = ctrl_dev->iommu_desc.cb_dev;
iommu_map = arm_iommu_create_mapping(&platform_bus_type,
va_start, va_size);
@@ -1299,6 +1302,13 @@ void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
if (dev->pipes[i].connected)
msm_slim_disconn_pipe_port(dev, i);
}
+
+ if (!IS_ERR_OR_NULL(dev->iommu_desc.iommu_map)) {
+ arm_iommu_detach_device(dev->iommu_desc.cb_dev);
+ arm_iommu_release_mapping(dev->iommu_desc.iommu_map);
+ dev->iommu_desc.iommu_map = NULL;
+ }
+
if (dereg) {
for (i = 0; i < dev->port_nums; i++) {
if (dev->pipes[i].connected)
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index e6c2aa3..1f7286b 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -632,6 +632,14 @@
between MSM and WCD DSP over glink transport protocol. This driver
provides read and write interface via char device.
+config QCOM_SMCINVOKE
+ bool "Secure QSEE Support"
+ help
+ Enable SMCInvoke driver which supports capability based secure
+ communication between QTI Secure Execution Environment (QSEE)
+ and high level operating system. It exposes APIs for both
+ userspace and kernel clients.
+
config MSM_EVENT_TIMER
bool "Event timer"
help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 64fb7a0..7820f8b 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -77,3 +77,4 @@
obj-$(CONFIG_APSS_CORE_EA) += msm-core.o debug_core.o
obj-$(CONFIG_QCOM_DCC_V2) += dcc_v2.o
obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o
+obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 28f89bf..72a1498 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "icnss: " fmt
#include <asm/dma-iommu.h>
+#include <linux/of_address.h>
#include <linux/clk.h>
#include <linux/iommu.h>
#include <linux/export.h>
@@ -357,6 +358,7 @@ struct icnss_stats {
uint32_t vbatt_req;
uint32_t vbatt_resp;
uint32_t vbatt_req_err;
+ u32 rejuvenate_ind;
uint32_t rejuvenate_ack_req;
uint32_t rejuvenate_ack_resp;
uint32_t rejuvenate_ack_err;
@@ -434,6 +436,10 @@ static struct icnss_priv {
bool is_wlan_mac_set;
struct icnss_wlan_mac_addr wlan_mac_addr;
bool bypass_s1_smmu;
+ u8 cause_for_rejuvenation;
+ u8 requesting_sub_system;
+ u16 line_number;
+ char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
} *penv;
#ifdef CONFIG_ICNSS_DEBUG
@@ -1669,6 +1675,60 @@ static int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv,
return ret;
}
+static int icnss_decode_rejuvenate_ind(void *msg, unsigned int msg_len)
+{
+ struct msg_desc ind_desc;
+ struct wlfw_rejuvenate_ind_msg_v01 ind_msg;
+ int ret = 0;
+
+ if (!penv || !penv->wlfw_clnt) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ memset(&ind_msg, 0, sizeof(ind_msg));
+
+ ind_desc.msg_id = QMI_WLFW_REJUVENATE_IND_V01;
+ ind_desc.max_msg_len = WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN;
+ ind_desc.ei_array = wlfw_rejuvenate_ind_msg_v01_ei;
+
+ ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+ if (ret < 0) {
+ icnss_pr_err("Failed to decode rejuvenate ind message: ret %d, msg_len %u\n",
+ ret, msg_len);
+ goto out;
+ }
+
+ if (ind_msg.cause_for_rejuvenation_valid)
+ penv->cause_for_rejuvenation = ind_msg.cause_for_rejuvenation;
+ else
+ penv->cause_for_rejuvenation = 0;
+ if (ind_msg.requesting_sub_system_valid)
+ penv->requesting_sub_system = ind_msg.requesting_sub_system;
+ else
+ penv->requesting_sub_system = 0;
+ if (ind_msg.line_number_valid)
+ penv->line_number = ind_msg.line_number;
+ else
+ penv->line_number = 0;
+ if (ind_msg.function_name_valid)
+ memcpy(penv->function_name, ind_msg.function_name,
+ QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1);
+ else
+ memset(penv->function_name, 0,
+ QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1);
+
+ icnss_pr_info("Cause for rejuvenation: 0x%x, requesting sub-system: 0x%x, line number: %u, function name: %s\n",
+ penv->cause_for_rejuvenation,
+ penv->requesting_sub_system,
+ penv->line_number,
+ penv->function_name);
+
+ penv->stats.rejuvenate_ind++;
+out:
+ return ret;
+}
+
static int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv)
{
int ret;
@@ -1862,6 +1922,7 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
msg_id, penv->state);
icnss_ignore_qmi_timeout(true);
+ icnss_decode_rejuvenate_ind(msg, msg_len);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
if (event_data == NULL)
return;
@@ -3742,6 +3803,26 @@ static int icnss_stats_show_capability(struct seq_file *s,
return 0;
}
+static int icnss_stats_show_rejuvenate_info(struct seq_file *s,
+ struct icnss_priv *priv)
+{
+ if (priv->stats.rejuvenate_ind) {
+ seq_puts(s, "\n<---------------- Rejuvenate Info ----------------->\n");
+ seq_printf(s, "Number of Rejuvenations: %u\n",
+ priv->stats.rejuvenate_ind);
+ seq_printf(s, "Cause for Rejuvenation: 0x%x\n",
+ priv->cause_for_rejuvenation);
+ seq_printf(s, "Requesting Sub-System: 0x%x\n",
+ priv->requesting_sub_system);
+ seq_printf(s, "Line Number: %u\n",
+ priv->line_number);
+ seq_printf(s, "Function Name: %s\n",
+ priv->function_name);
+ }
+
+ return 0;
+}
+
static int icnss_stats_show_events(struct seq_file *s, struct icnss_priv *priv)
{
int i;
@@ -3807,6 +3888,7 @@ static int icnss_stats_show(struct seq_file *s, void *data)
ICNSS_STATS_DUMP(s, priv, vbatt_req);
ICNSS_STATS_DUMP(s, priv, vbatt_resp);
ICNSS_STATS_DUMP(s, priv, vbatt_req_err);
+ ICNSS_STATS_DUMP(s, priv, rejuvenate_ind);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
@@ -3828,6 +3910,8 @@ static int icnss_stats_show(struct seq_file *s, void *data)
icnss_stats_show_capability(s, priv);
+ icnss_stats_show_rejuvenate_info(s, priv);
+
icnss_stats_show_events(s, priv);
icnss_stats_show_state(s, priv);
@@ -4160,6 +4244,9 @@ static int icnss_probe(struct platform_device *pdev)
int i;
struct device *dev = &pdev->dev;
struct icnss_priv *priv;
+ const __be32 *addrp;
+ u64 prop_size = 0;
+ struct device_node *np;
if (penv) {
icnss_pr_err("Driver is already initialized\n");
@@ -4231,24 +4318,53 @@ static int icnss_probe(struct platform_device *pdev)
}
}
- ret = of_property_read_u32(dev->of_node, "qcom,wlan-msa-memory",
- &priv->msa_mem_size);
+ np = of_parse_phandle(dev->of_node,
+ "qcom,wlan-msa-fixed-region", 0);
+ if (np) {
+ addrp = of_get_address(np, 0, &prop_size, NULL);
+ if (!addrp) {
+ icnss_pr_err("Failed to get assigned-addresses or property\n");
+ ret = -EINVAL;
+ goto out;
+ }
- if (ret || priv->msa_mem_size == 0) {
- icnss_pr_err("Fail to get MSA Memory Size: %u, ret: %d\n",
- priv->msa_mem_size, ret);
- goto out;
+ priv->msa_pa = of_translate_address(np, addrp);
+ if (priv->msa_pa == OF_BAD_ADDR) {
+ icnss_pr_err("Failed to translate MSA PA from device-tree\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ priv->msa_va = memremap(priv->msa_pa,
+ (unsigned long)prop_size, MEMREMAP_WT);
+ if (!priv->msa_va) {
+ icnss_pr_err("MSA PA ioremap failed: phy addr: %pa\n",
+ &priv->msa_pa);
+ ret = -EINVAL;
+ goto out;
+ }
+ priv->msa_mem_size = prop_size;
+ } else {
+ ret = of_property_read_u32(dev->of_node, "qcom,wlan-msa-memory",
+ &priv->msa_mem_size);
+ if (ret || priv->msa_mem_size == 0) {
+ icnss_pr_err("Fail to get MSA Memory Size: %u ret: %d\n",
+ priv->msa_mem_size, ret);
+ goto out;
+ }
+
+ priv->msa_va = dmam_alloc_coherent(&pdev->dev,
+ priv->msa_mem_size, &priv->msa_pa, GFP_KERNEL);
+
+ if (!priv->msa_va) {
+ icnss_pr_err("DMA alloc failed for MSA\n");
+ ret = -ENOMEM;
+ goto out;
+ }
}
- priv->msa_va = dmam_alloc_coherent(&pdev->dev, priv->msa_mem_size,
- &priv->msa_pa, GFP_KERNEL);
- if (!priv->msa_va) {
- icnss_pr_err("DMA alloc failed for MSA\n");
- ret = -ENOMEM;
- goto out;
- }
- icnss_pr_dbg("MSA pa: %pa, MSA va: 0x%p\n", &priv->msa_pa,
- priv->msa_va);
+ icnss_pr_dbg("MSA pa: %pa, MSA va: 0x%p MSA Memory Size: 0x%x\n",
+ &priv->msa_pa, (void *)priv->msa_va, priv->msa_mem_size);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"smmu_iova_base");
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 36c0154..ed78af7 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -746,18 +746,16 @@ static void msm_bus_fab_init_noc_ops(struct msm_bus_node_device_type *bus_dev)
static int msm_bus_disable_node_qos_clk(struct msm_bus_node_device_type *node)
{
- struct msm_bus_node_device_type *bus_node = NULL;
int i;
int ret = 0;
- if (!node || (!to_msm_bus_node(node->node_info->bus_device))) {
+ if (!node) {
ret = -ENXIO;
goto exit_disable_node_qos_clk;
}
- bus_node = to_msm_bus_node(node->node_info->bus_device);
- for (i = 0; i < bus_node->num_node_qos_clks; i++)
- ret = disable_nodeclk(&bus_node->node_qos_clks[i]);
+ for (i = 0; i < node->num_node_qos_clks; i++)
+ ret = disable_nodeclk(&node->node_qos_clks[i]);
exit_disable_node_qos_clk:
return ret;
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 9a98063..17e0a4c 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -32,6 +32,7 @@
#define RPMH_MAX_MBOXES 2
#define RPMH_MAX_FAST_RES 32
#define RPMH_MAX_REQ_IN_BATCH 10
+#define RPMH_TIMEOUT msecs_to_jiffies(10000)
#define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name) \
struct rpmh_msg name = { \
@@ -166,6 +167,41 @@ static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
complete(compl);
}
+/**
+ * wait_for_tx_done: Wait forever until the response is received.
+ *
+ * @rc: The RPMH client
+ * @compl: The completion object
+ * @addr: An addr that we sent in that request
+ * @data: The data for the address in that request
+ *
+ */
+static inline void wait_for_tx_done(struct rpmh_client *rc,
+ struct completion *compl, u32 addr, u32 data)
+{
+ int ret;
+ int count = 4;
+
+ do {
+ ret = wait_for_completion_timeout(compl, RPMH_TIMEOUT);
+ if (ret) {
+ if (count != 4)
+ dev_notice(rc->dev,
+ "RPMH response received addr=0x%x data=0x%x\n",
+ addr, data);
+ return;
+ }
+ if (!count) {
+ mbox_chan_debug(rc->chan);
+ } else {
+ dev_err(rc->dev,
+ "RPMH response timeout (%d) addr=0x%x,data=0x%x\n",
+ count, addr, data);
+ count--;
+ }
+ } while (true);
+}
+
static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr)
{
struct rpmh_req *p, *req = NULL;
@@ -365,7 +401,7 @@ int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state,
if (ret < 0)
return ret;
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, addr, data);
return rpm_msg.err;
}
@@ -469,7 +505,7 @@ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state,
if (ret)
return ret;
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, cmd[0].addr, cmd[0].data);
return rpm_msg.err;
}
@@ -500,6 +536,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
int count = 0;
int ret, i, j, k;
bool complete_set;
+ u32 addr, data;
if (IS_ERR_OR_NULL(rc) || !cmd || !n)
return -EINVAL;
@@ -537,6 +574,8 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
}
}
+ addr = cmd[0].addr;
+ data = cmd[0].data;
/* Create async request batches */
for (i = 0; i < count; i++) {
rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]);
@@ -566,7 +605,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
/* For those unsent requests, spoof tx_done */
for (j = i; j < count; j++)
rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, ret);
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, addr, data);
} else {
/* Send Sleep requests to the controller, expect no response */
for (i = 0; i < count; i++) {
@@ -719,7 +758,7 @@ int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp)
return ret;
/* Wait until the response is received from RPMH */
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, addr, 0);
/* Read the data back from the tcs_mbox_msg structrure */
*resp = rpm_msg.cmd[0].data;
diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c
new file mode 100644
index 0000000..3f31fb1
--- /dev/null
+++ b/drivers/soc/qcom/smcinvoke.c
@@ -0,0 +1,575 @@
+/*
+ * SMC Invoke driver
+ *
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/anon_inodes.h>
+#include <linux/smcinvoke.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+
+#include <soc/qcom/scm.h>
+#include <asm/cacheflush.h>
+#include <soc/qcom/qseecomi.h>
+
+#include "smcinvoke_object.h"
+#include "../../misc/qseecom_kernel.h"
+
+#define SMCINVOKE_DEV "smcinvoke"
+#define SMCINVOKE_TZ_PARAM_ID 0x224
+#define SMCINVOKE_TZ_CMD 0x32000600
+#define SMCINVOKE_TZ_ROOT_OBJ 1
+#define SMCINVOKE_TZ_MIN_BUF_SIZE 4096
+#define SMCINVOKE_ARGS_ALIGN_SIZE (sizeof(uint64_t))
+#define SMCINVOKE_TZ_OBJ_NULL 0
+
+#define FOR_ARGS(ndxvar, counts, section) \
+ for (ndxvar = object_counts_index_##section(counts); \
+ ndxvar < (object_counts_index_##section(counts) \
+ + object_counts_num_##section(counts)); \
+ ++ndxvar)
+
+static long smcinvoke_ioctl(struct file *, unsigned int, unsigned long);
+static int smcinvoke_open(struct inode *, struct file *);
+static int smcinvoke_release(struct inode *, struct file *);
+
+static const struct file_operations smcinvoke_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = smcinvoke_ioctl,
+ .compat_ioctl = smcinvoke_ioctl,
+ .open = smcinvoke_open,
+ .release = smcinvoke_release,
+};
+
+struct smcinvoke_buf_hdr {
+ uint32_t offset;
+ uint32_t size;
+};
+
+union smcinvoke_tz_args {
+ struct smcinvoke_buf_hdr b;
+ uint32_t tzhandle;
+};
+struct smcinvoke_msg_hdr {
+ uint32_t tzhandle;
+ uint32_t op;
+ uint32_t counts;
+};
+
+struct smcinvoke_tzobj_context {
+ uint32_t tzhandle;
+};
+
+static dev_t smcinvoke_device_no;
+struct cdev smcinvoke_cdev;
+struct class *driver_class;
+struct device *class_dev;
+
+/*
+ * size_add saturates at SIZE_MAX. If integer overflow is detected,
+ * this function would return SIZE_MAX otherwise normal a+b is returned.
+ */
+static inline size_t size_add(size_t a, size_t b)
+{
+ return (b > (SIZE_MAX - a)) ? SIZE_MAX : a + b;
+}
+
+/*
+ * pad_size is used along with size_align to define a buffer overflow
+ * protected version of ALIGN
+ */
+static inline size_t pad_size(size_t a, size_t b)
+{
+ return (~a + 1) % b;
+}
+
+/*
+ * size_align saturates at SIZE_MAX. If integer overflow is detected, this
+ * function would return SIZE_MAX otherwise next aligned size is returned.
+ */
+static inline size_t size_align(size_t a, size_t b)
+{
+ return size_add(a, pad_size(a, b));
+}
+
+/*
+ * This function retrieves file pointer corresponding to FD provided. It stores
+ * retrived file pointer until IOCTL call is concluded. Once call is completed,
+ * all stored file pointers are released. file pointers are stored to prevent
+ * other threads from releasing that FD while IOCTL is in progress.
+ */
+static int get_tzhandle_from_fd(int64_t fd, struct file **filp,
+ uint32_t *tzhandle)
+{
+ int ret = -EBADF;
+ struct file *tmp_filp = NULL;
+ struct smcinvoke_tzobj_context *tzobj = NULL;
+
+ if (fd == SMCINVOKE_USERSPACE_OBJ_NULL) {
+ *tzhandle = SMCINVOKE_TZ_OBJ_NULL;
+ ret = 0;
+ goto out;
+ } else if (fd < SMCINVOKE_USERSPACE_OBJ_NULL) {
+ goto out;
+ }
+
+ tmp_filp = fget(fd);
+ if (!tmp_filp)
+ goto out;
+
+ /* Verify if filp is smcinvoke device's file pointer */
+ if (!tmp_filp->f_op || !tmp_filp->private_data ||
+ (tmp_filp->f_op != &smcinvoke_fops)) {
+ fput(tmp_filp);
+ goto out;
+ }
+
+ tzobj = tmp_filp->private_data;
+ *tzhandle = tzobj->tzhandle;
+ *filp = tmp_filp;
+ ret = 0;
+out:
+ return ret;
+}
+
+static int get_fd_from_tzhandle(uint32_t tzhandle, int64_t *fd)
+{
+ int unused_fd = -1, ret = -1;
+ struct file *f = NULL;
+ struct smcinvoke_tzobj_context *cxt = NULL;
+
+ if (tzhandle == SMCINVOKE_TZ_OBJ_NULL) {
+ *fd = SMCINVOKE_USERSPACE_OBJ_NULL;
+ ret = 0;
+ goto out;
+ }
+
+ cxt = kzalloc(sizeof(*cxt), GFP_KERNEL);
+ if (!cxt) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ unused_fd = get_unused_fd_flags(O_RDWR);
+ if (unused_fd < 0)
+ goto out;
+
+ f = anon_inode_getfile(SMCINVOKE_DEV, &smcinvoke_fops, cxt, O_RDWR);
+ if (IS_ERR(f))
+ goto out;
+
+ *fd = unused_fd;
+ fd_install(*fd, f);
+ ((struct smcinvoke_tzobj_context *)
+ (f->private_data))->tzhandle = tzhandle;
+ return 0;
+out:
+ if (unused_fd >= 0)
+ put_unused_fd(unused_fd);
+ kfree(cxt);
+
+ return ret;
+}
+
+static int prepare_send_scm_msg(const uint8_t *in_buf, size_t in_buf_len,
+ const uint8_t *out_buf, size_t out_buf_len,
+ int32_t *smcinvoke_result)
+{
+ int ret = 0;
+ struct scm_desc desc = {0};
+ size_t inbuf_flush_size = (1UL << get_order(in_buf_len)) * PAGE_SIZE;
+ size_t outbuf_flush_size = (1UL << get_order(out_buf_len)) * PAGE_SIZE;
+
+ desc.arginfo = SMCINVOKE_TZ_PARAM_ID;
+ desc.args[0] = (uint64_t)virt_to_phys(in_buf);
+ desc.args[1] = inbuf_flush_size;
+ desc.args[2] = (uint64_t)virt_to_phys(out_buf);
+ desc.args[3] = outbuf_flush_size;
+
+ dmac_flush_range(in_buf, in_buf + inbuf_flush_size);
+ dmac_flush_range(out_buf, out_buf + outbuf_flush_size);
+
+ ret = scm_call2(SMCINVOKE_TZ_CMD, &desc);
+
+ /* process listener request */
+ if (!ret && (desc.ret[0] == QSEOS_RESULT_INCOMPLETE ||
+ desc.ret[0] == QSEOS_RESULT_BLOCKED_ON_LISTENER))
+ ret = qseecom_process_listener_from_smcinvoke(&desc);
+
+ *smcinvoke_result = (int32_t)desc.ret[1];
+ if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0])
+ pr_err("SCM call failed with ret val = %d %d %d %d\n",
+ ret, (int)desc.ret[0],
+ (int)desc.ret[1], (int)desc.ret[2]);
+
+ dmac_inv_range(in_buf, in_buf + inbuf_flush_size);
+ dmac_inv_range(out_buf, out_buf + outbuf_flush_size);
+ return ret;
+}
+
+static int marshal_out(void *buf, uint32_t buf_size,
+ struct smcinvoke_cmd_req *req,
+ union smcinvoke_arg *args_buf)
+{
+ int ret = -EINVAL, i = 0;
+ union smcinvoke_tz_args *tz_args = NULL;
+ size_t offset = sizeof(struct smcinvoke_msg_hdr) +
+ object_counts_total(req->counts) *
+ sizeof(union smcinvoke_tz_args);
+
+ if (offset > buf_size)
+ goto out;
+
+ tz_args = (union smcinvoke_tz_args *)
+ (buf + sizeof(struct smcinvoke_msg_hdr));
+
+ tz_args += object_counts_num_BI(req->counts);
+
+ FOR_ARGS(i, req->counts, BO) {
+ args_buf[i].b.size = tz_args->b.size;
+ if ((buf_size - tz_args->b.offset < tz_args->b.size) ||
+ tz_args->b.offset > buf_size) {
+ pr_err("%s: buffer overflow detected\n", __func__);
+ goto out;
+ }
+ if (copy_to_user((void __user *)(uintptr_t)(args_buf[i].b.addr),
+ (uint8_t *)(buf) + tz_args->b.offset,
+ tz_args->b.size)) {
+ pr_err("Error %d copying ctxt to user\n", ret);
+ goto out;
+ }
+ tz_args++;
+ }
+ tz_args += object_counts_num_OI(req->counts);
+
+ FOR_ARGS(i, req->counts, OO) {
+ /*
+ * create a new FD and assign to output object's
+ * context
+ */
+ ret = get_fd_from_tzhandle(tz_args->tzhandle,
+ &(args_buf[i].o.fd));
+ if (ret)
+ goto out;
+ tz_args++;
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ * SMC expects arguments in following format
+ * ---------------------------------------------------------------------------
+ * | cxt | op | counts | ptr|size |ptr|size...|ORef|ORef|...| rest of payload |
+ * ---------------------------------------------------------------------------
+ * cxt: target, op: operation, counts: total arguments
+ * offset: offset is from beginning of buffer i.e. cxt
+ * size: size is 8 bytes aligned value
+ */
+static size_t compute_in_msg_size(const struct smcinvoke_cmd_req *req,
+ const union smcinvoke_arg *args_buf)
+{
+ uint32_t i = 0;
+
+ size_t total_size = sizeof(struct smcinvoke_msg_hdr) +
+ object_counts_total(req->counts) *
+ sizeof(union smcinvoke_tz_args);
+
+ /* Computed total_size should be 8 bytes aligned from start of buf */
+ total_size = ALIGN(total_size, SMCINVOKE_ARGS_ALIGN_SIZE);
+
+ /* each buffer has to be 8 bytes aligned */
+ while (i < object_counts_num_buffers(req->counts))
+ total_size = size_add(total_size,
+ size_align(args_buf[i++].b.size, SMCINVOKE_ARGS_ALIGN_SIZE));
+
+ /* Since we're using get_free_pages, no need for explicit PAGE align */
+ return total_size;
+}
+
+static int marshal_in(const struct smcinvoke_cmd_req *req,
+ const union smcinvoke_arg *args_buf, uint32_t tzhandle,
+ uint8_t *buf, size_t buf_size, struct file **arr_filp)
+{
+ int ret = -EINVAL, i = 0;
+ union smcinvoke_tz_args *tz_args = NULL;
+ struct smcinvoke_msg_hdr msg_hdr = {tzhandle, req->op, req->counts};
+ uint32_t offset = sizeof(struct smcinvoke_msg_hdr) +
+ sizeof(union smcinvoke_tz_args) *
+ object_counts_total(req->counts);
+
+ if (buf_size < offset)
+ goto out;
+
+ *(struct smcinvoke_msg_hdr *)buf = msg_hdr;
+ tz_args = (union smcinvoke_tz_args *)
+ (buf + sizeof(struct smcinvoke_msg_hdr));
+
+ FOR_ARGS(i, req->counts, BI) {
+ offset = size_align(offset, SMCINVOKE_ARGS_ALIGN_SIZE);
+ if ((offset > buf_size) ||
+ (args_buf[i].b.size > (buf_size - offset)))
+ goto out;
+
+ tz_args->b.offset = offset;
+ tz_args->b.size = args_buf[i].b.size;
+ tz_args++;
+
+ if (copy_from_user(buf+offset,
+ (void __user *)(uintptr_t)(args_buf[i].b.addr),
+ args_buf[i].b.size))
+ goto out;
+
+ offset += args_buf[i].b.size;
+ }
+ FOR_ARGS(i, req->counts, BO) {
+ offset = size_align(offset, SMCINVOKE_ARGS_ALIGN_SIZE);
+ if ((offset > buf_size) ||
+ (args_buf[i].b.size > (buf_size - offset)))
+ goto out;
+
+ tz_args->b.offset = offset;
+ tz_args->b.size = args_buf[i].b.size;
+ tz_args++;
+
+ offset += args_buf[i].b.size;
+ }
+ FOR_ARGS(i, req->counts, OI) {
+ if (get_tzhandle_from_fd(args_buf[i].o.fd,
+ &arr_filp[i], &(tz_args->tzhandle)))
+ goto out;
+ tz_args++;
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+long smcinvoke_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = -1, i = 0, nr_args = 0;
+ struct smcinvoke_cmd_req req = {0};
+ void *in_msg = NULL;
+ size_t inmsg_size = 0;
+ void *out_msg = NULL;
+ union smcinvoke_arg *args_buf = NULL;
+ struct file *filp_to_release[object_counts_max_OO] = {NULL};
+ struct smcinvoke_tzobj_context *tzobj = filp->private_data;
+
+ switch (cmd) {
+ case SMCINVOKE_IOCTL_INVOKE_REQ:
+ if (_IOC_SIZE(cmd) != sizeof(req)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = copy_from_user(&req, (void __user *)arg, sizeof(req));
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ nr_args = object_counts_num_buffers(req.counts) +
+ object_counts_num_objects(req.counts);
+
+ if (req.argsize != sizeof(union smcinvoke_arg)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (nr_args) {
+
+ args_buf = kzalloc(nr_args * req.argsize, GFP_KERNEL);
+ if (!args_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = copy_from_user(args_buf,
+ (void __user *)(uintptr_t)(req.args),
+ nr_args * req.argsize);
+
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ inmsg_size = compute_in_msg_size(&req, args_buf);
+ in_msg = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(inmsg_size));
+ if (!in_msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ out_msg = (void *)__get_free_page(GFP_KERNEL);
+ if (!out_msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = marshal_in(&req, args_buf, tzobj->tzhandle, in_msg,
+ inmsg_size, filp_to_release);
+ if (ret)
+ goto out;
+
+ ret = prepare_send_scm_msg(in_msg, inmsg_size, out_msg,
+ SMCINVOKE_TZ_MIN_BUF_SIZE, &req.result);
+ if (ret)
+ goto out;
+
+ /*
+ * if invoke op results in an err, no need to marshal_out and
+ * copy args buf to user space
+ */
+ if (!req.result) {
+ ret = marshal_out(in_msg, inmsg_size, &req, args_buf);
+
+ ret |= copy_to_user(
+ (void __user *)(uintptr_t)(req.args),
+ args_buf, nr_args * req.argsize);
+ }
+ ret |= copy_to_user((void __user *)arg, &req, sizeof(req));
+ if (ret)
+ goto out;
+
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+out:
+ free_page((long)out_msg);
+ free_pages((long)in_msg, get_order(inmsg_size));
+ kfree(args_buf);
+ for (i = 0; i < object_counts_max_OO; i++) {
+ if (filp_to_release[i])
+ fput(filp_to_release[i]);
+ }
+
+ return ret;
+}
+
+static int smcinvoke_open(struct inode *nodp, struct file *filp)
+{
+ struct smcinvoke_tzobj_context *tzcxt = NULL;
+
+ tzcxt = kzalloc(sizeof(*tzcxt), GFP_KERNEL);
+ if (!tzcxt)
+ return -ENOMEM;
+
+ tzcxt->tzhandle = SMCINVOKE_TZ_ROOT_OBJ;
+ filp->private_data = tzcxt;
+
+ return 0;
+}
+
+static int smcinvoke_release(struct inode *nodp, struct file *filp)
+{
+ int ret = 0, smcinvoke_result = 0;
+ uint8_t *in_buf = NULL;
+ uint8_t *out_buf = NULL;
+ struct smcinvoke_msg_hdr hdr = {0};
+ struct smcinvoke_tzobj_context *tzobj = filp->private_data;
+ uint32_t tzhandle = tzobj->tzhandle;
+
+ /* Root object is special in sense it is indestructible */
+ if (!tzhandle || tzhandle == SMCINVOKE_TZ_ROOT_OBJ)
+ goto out;
+
+ in_buf = (uint8_t *)__get_free_page(GFP_KERNEL);
+ out_buf = (uint8_t *)__get_free_page(GFP_KERNEL);
+ if (!in_buf || !out_buf)
+ goto out;
+
+ hdr.tzhandle = tzhandle;
+ hdr.op = object_op_RELEASE;
+ hdr.counts = 0;
+ *(struct smcinvoke_msg_hdr *)in_buf = hdr;
+
+ ret = prepare_send_scm_msg(in_buf, SMCINVOKE_TZ_MIN_BUF_SIZE,
+ out_buf, SMCINVOKE_TZ_MIN_BUF_SIZE, &smcinvoke_result);
+out:
+ kfree(filp->private_data);
+ free_page((long)in_buf);
+ free_page((long)out_buf);
+
+ return ret;
+}
+
+static int __init smcinvoke_init(void)
+{
+ unsigned int baseminor = 0;
+ unsigned int count = 1;
+ int rc = 0;
+
+ rc = alloc_chrdev_region(&smcinvoke_device_no, baseminor, count,
+ SMCINVOKE_DEV);
+ if (rc < 0) {
+ pr_err("chrdev_region failed %d for %s\n", rc, SMCINVOKE_DEV);
+ return rc;
+ }
+ driver_class = class_create(THIS_MODULE, SMCINVOKE_DEV);
+ if (IS_ERR(driver_class)) {
+ rc = -ENOMEM;
+ pr_err("class_create failed %d\n", rc);
+ goto exit_unreg_chrdev_region;
+ }
+ class_dev = device_create(driver_class, NULL, smcinvoke_device_no,
+ NULL, SMCINVOKE_DEV);
+ if (!class_dev) {
+ pr_err("class_device_create failed %d\n", rc);
+ rc = -ENOMEM;
+ goto exit_destroy_class;
+ }
+
+ cdev_init(&smcinvoke_cdev, &smcinvoke_fops);
+ smcinvoke_cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&smcinvoke_cdev, MKDEV(MAJOR(smcinvoke_device_no), 0),
+ count);
+ if (rc < 0) {
+ pr_err("cdev_add failed %d for %s\n", rc, SMCINVOKE_DEV);
+ goto exit_destroy_device;
+ }
+ return 0;
+
+exit_destroy_device:
+ device_destroy(driver_class, smcinvoke_device_no);
+exit_destroy_class:
+ class_destroy(driver_class);
+exit_unreg_chrdev_region:
+ unregister_chrdev_region(smcinvoke_device_no, count);
+
+ return rc;
+}
+
+static void __exit smcinvoke_exit(void)
+{
+ int count = 1;
+
+ cdev_del(&smcinvoke_cdev);
+ device_destroy(driver_class, smcinvoke_device_no);
+ class_destroy(driver_class);
+ unregister_chrdev_region(smcinvoke_device_no, count);
+}
+device_initcall(smcinvoke_init);
+module_exit(smcinvoke_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SMC Invoke driver");
diff --git a/drivers/soc/qcom/smcinvoke_object.h b/drivers/soc/qcom/smcinvoke_object.h
new file mode 100644
index 0000000..670b425
--- /dev/null
+++ b/drivers/soc/qcom/smcinvoke_object.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __SMCINVOKE_OBJECT_H
+#define __SMCINVOKE_OBJECT_H
+
+#include <linux/types.h>
+
+#define object_op_METHOD_MASK ((uint32_t)0x0000FFFFu)
+#define object_op_RELEASE (object_op_METHOD_MASK - 0)
+#define object_op_RETAIN (object_op_METHOD_MASK - 1)
+
+#define object_counts_max_BI 0xF
+#define object_counts_max_BO 0xF
+#define object_counts_max_OI 0xF
+#define object_counts_max_OO 0xF
+
+/* unpack counts */
+
+#define object_counts_num_BI(k) ((size_t) (((k) >> 0) & object_counts_max_BI))
+#define object_counts_num_BO(k) ((size_t) (((k) >> 4) & object_counts_max_BO))
+#define object_counts_num_OI(k) ((size_t) (((k) >> 8) & object_counts_max_OI))
+#define object_counts_num_OO(k) ((size_t) (((k) >> 12) & object_counts_max_OO))
+#define object_counts_num_buffers(k) \
+ (object_counts_num_BI(k) + object_counts_num_BO(k))
+
+#define object_counts_num_objects(k) \
+ (object_counts_num_OI(k) + object_counts_num_OO(k))
+
+/* Indices into args[] */
+
+#define object_counts_index_BI(k) 0
+#define object_counts_index_BO(k) \
+ (object_counts_index_BI(k) + object_counts_num_BI(k))
+#define object_counts_index_OI(k) \
+ (object_counts_index_BO(k) + object_counts_num_BO(k))
+#define object_counts_index_OO(k) \
+ (object_counts_index_OI(k) + object_counts_num_OI(k))
+#define object_counts_total(k) \
+ (object_counts_index_OO(k) + object_counts_num_OO(k))
+
+
+#endif /* __SMCINVOKE_OBJECT_H */
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 9ea4a9f..4082a7d 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -3,7 +3,7 @@
* drivers/staging/android/ion/ion.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -76,7 +76,7 @@ struct ion_device {
* @dev: backpointer to ion device
* @handles: an rb tree of all the handles in this client
* @idr: an idr space for allocating handle ids
- * @lock: lock protecting the tree of handles
+ * @lock: lock protecting the tree of handles and idr
* @name: used for debugging
* @display_name: used for debugging (unique version of @name)
* @display_serial: used for debugging (to make display_name unique)
@@ -91,7 +91,6 @@ struct ion_client {
struct ion_device *dev;
struct rb_root handles;
struct idr idr;
- /* Protects idr */
struct mutex lock;
char *name;
char *display_name;
@@ -671,8 +670,8 @@ int ion_phys(struct ion_client *client, struct ion_handle *handle,
mutex_unlock(&client->lock);
return -ENODEV;
}
- mutex_unlock(&client->lock);
ret = buffer->heap->ops->phys(buffer->heap, buffer, addr, len);
+ mutex_unlock(&client->lock);
return ret;
}
EXPORT_SYMBOL(ion_phys);
@@ -777,33 +776,7 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
}
EXPORT_SYMBOL(ion_unmap_kernel);
-static struct mutex debugfs_mutex;
static struct rb_root *ion_root_client;
-static int is_client_alive(struct ion_client *client)
-{
- struct rb_node *node;
- struct ion_client *tmp;
- struct ion_device *dev;
-
- node = ion_root_client->rb_node;
- dev = container_of(ion_root_client, struct ion_device, clients);
-
- down_read(&dev->lock);
- while (node) {
- tmp = rb_entry(node, struct ion_client, node);
- if (client < tmp) {
- node = node->rb_left;
- } else if (client > tmp) {
- node = node->rb_right;
- } else {
- up_read(&dev->lock);
- return 1;
- }
- }
-
- up_read(&dev->lock);
- return 0;
-}
static int ion_debug_client_show(struct seq_file *s, void *unused)
{
@@ -814,14 +787,6 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
"heap_name", "size_in_bytes", "handle refcount",
"buffer");
- mutex_lock(&debugfs_mutex);
- if (!is_client_alive(client)) {
- seq_printf(s, "ion_client 0x%p dead, can't dump its buffers\n",
- client);
- mutex_unlock(&debugfs_mutex);
- return 0;
- }
-
mutex_lock(&client->lock);
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
@@ -836,7 +801,6 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
seq_puts(s, "\n");
}
mutex_unlock(&client->lock);
- mutex_unlock(&debugfs_mutex);
return 0;
}
@@ -967,27 +931,27 @@ void ion_client_destroy(struct ion_client *client)
struct rb_node *n;
pr_debug("%s: %d\n", __func__, __LINE__);
- mutex_lock(&debugfs_mutex);
+ down_write(&dev->lock);
+ rb_erase(&client->node, &dev->clients);
+ up_write(&dev->lock);
+
+ /* After this completes, there are no more references to client */
+ debugfs_remove_recursive(client->debug_root);
+
+ mutex_lock(&client->lock);
while ((n = rb_first(&client->handles))) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
node);
ion_handle_destroy(&handle->ref);
}
+ mutex_unlock(&client->lock);
idr_destroy(&client->idr);
-
- down_write(&dev->lock);
if (client->task)
put_task_struct(client->task);
- rb_erase(&client->node, &dev->clients);
- debugfs_remove_recursive(client->debug_root);
-
- up_write(&dev->lock);
-
kfree(client->display_name);
kfree(client->name);
kfree(client);
- mutex_unlock(&debugfs_mutex);
}
EXPORT_SYMBOL(ion_client_destroy);
@@ -1794,7 +1758,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size");
seq_puts(s, "----------------------------------------------------\n");
- mutex_lock(&debugfs_mutex);
+ down_read(&dev->lock);
for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
struct ion_client *client = rb_entry(n, struct ion_client,
node);
@@ -1813,7 +1777,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
client->pid, size);
}
}
- mutex_unlock(&debugfs_mutex);
+ up_read(&dev->lock);
seq_puts(s, "----------------------------------------------------\n");
seq_puts(s, "orphaned allocations (info is from last known client):\n");
@@ -2048,7 +2012,6 @@ struct ion_device *ion_device_create(long (*custom_ioctl)
plist_head_init(&idev->heaps);
idev->clients = RB_ROOT;
ion_root_client = &idev->clients;
- mutex_init(&debugfs_mutex);
return idev;
}
EXPORT_SYMBOL(ion_device_create);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 68d9feb..95ef027 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -897,6 +897,60 @@ passive_show(struct device *dev, struct device_attribute *attr,
}
static ssize_t
+polling_delay_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", tz->polling_delay);
+}
+
+static ssize_t
+polling_delay_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int delay;
+
+ if (kstrtoint(buf, 10, &delay))
+ return -EINVAL;
+
+ mutex_lock(&tz->lock);
+ tz->polling_delay = delay;
+ mutex_unlock(&tz->lock);
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+ return count;
+}
+
+static ssize_t
+passive_delay_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", tz->passive_delay);
+}
+
+static ssize_t
+passive_delay_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int delay;
+
+ if (kstrtoint(buf, 10, &delay))
+ return -EINVAL;
+
+ mutex_lock(&tz->lock);
+ tz->passive_delay = delay;
+ mutex_unlock(&tz->lock);
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+ return count;
+}
+
+static ssize_t
policy_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -1167,6 +1221,10 @@ static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
static DEVICE_ATTR(available_policies, S_IRUGO, available_policies_show, NULL);
+static DEVICE_ATTR(passive_delay, 0644, passive_delay_show,
+ passive_delay_store);
+static DEVICE_ATTR(polling_delay, 0644, polling_delay_show,
+ polling_delay_store);
/* sys I/F for cooling device */
#define to_cooling_device(_dev) \
@@ -1324,6 +1382,54 @@ thermal_cooling_device_trip_point_show(struct device *dev,
return sprintf(buf, "%d\n", instance->trip);
}
+static ssize_t
+thermal_cooling_device_upper_limit_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ struct thermal_instance *instance;
+ int ret, upper_limit;
+
+ instance =
+ container_of(attr, struct thermal_instance, upper_attr);
+
+ ret = kstrtoint(buf, 0, &upper_limit);
+ if (ret)
+ return ret;
+ if (upper_limit < instance->lower)
+ return -EINVAL;
+
+ instance->upper = upper_limit;
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+ return count;
+}
+
+static ssize_t
+thermal_cooling_device_lower_limit_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ struct thermal_instance *instance;
+ int ret, lower_limit;
+
+ instance =
+ container_of(attr, struct thermal_instance, lower_attr);
+
+ ret = kstrtoint(buf, 0, &lower_limit);
+ if (ret)
+ return ret;
+ if (lower_limit > instance->upper)
+ return -EINVAL;
+
+ instance->lower = lower_limit;
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+ return count;
+}
+
static struct attribute *cooling_device_attrs[] = {
&dev_attr_cdev_type.attr,
&dev_attr_max_state.attr,
@@ -1484,8 +1590,9 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
"cdev%d_upper_limit", dev->id);
sysfs_attr_init(&dev->upper_attr.attr);
dev->upper_attr.attr.name = dev->upper_attr_name;
- dev->upper_attr.attr.mode = 0444;
+ dev->upper_attr.attr.mode = 0644;
dev->upper_attr.show = thermal_cooling_device_upper_limit_show;
+ dev->upper_attr.store = thermal_cooling_device_upper_limit_store;
result = device_create_file(&tz->device, &dev->upper_attr);
if (result)
goto remove_trip_file;
@@ -1494,8 +1601,9 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
"cdev%d_lower_limit", dev->id);
sysfs_attr_init(&dev->lower_attr.attr);
dev->lower_attr.attr.name = dev->lower_attr_name;
- dev->lower_attr.attr.mode = 0444;
+ dev->lower_attr.attr.mode = 0644;
dev->lower_attr.show = thermal_cooling_device_lower_limit_show;
+ dev->lower_attr.store = thermal_cooling_device_lower_limit_store;
result = device_create_file(&tz->device, &dev->lower_attr);
if (result)
goto remove_upper_file;
@@ -2084,6 +2192,13 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
if (result)
goto unregister;
}
+ result = device_create_file(&tz->device, &dev_attr_passive_delay);
+ if (result)
+ goto unregister;
+
+ result = device_create_file(&tz->device, &dev_attr_polling_delay);
+ if (result)
+ goto unregister;
if (IS_ENABLED(CONFIG_THERMAL_EMULATION)) {
result = device_create_file(&tz->device, &dev_attr_emul_temp);
@@ -2207,6 +2322,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
device_remove_file(&tz->device, &dev_attr_mode);
device_remove_file(&tz->device, &dev_attr_policy);
device_remove_file(&tz->device, &dev_attr_available_policies);
+ device_remove_file(&tz->device, &dev_attr_passive_delay);
+ device_remove_file(&tz->device, &dev_attr_polling_delay);
remove_trip_attrs(tz);
thermal_set_governor(tz, NULL);
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 94ba2c3e..d1cde1b 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -1069,6 +1069,14 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
SE_GENI_TX_PACKING_CFG0);
geni_write_reg_nolog(cfg1, uport->membase,
SE_GENI_TX_PACKING_CFG1);
+ msm_port->handle_rx = handle_rx_hs;
+ msm_port->rx_fifo = devm_kzalloc(uport->dev,
+ sizeof(msm_port->rx_fifo_depth * sizeof(u32)),
+ GFP_KERNEL);
+ if (!msm_port->rx_fifo) {
+ ret = -ENOMEM;
+ goto exit_portsetup;
+ }
} else {
/*
* Make an unconditional cancel on the main sequencer to reset
@@ -1166,12 +1174,12 @@ static int msm_geni_serial_startup(struct uart_port *uport)
goto exit_startup;
}
+ get_tx_fifo_size(msm_port);
if (!msm_port->port_setup) {
if (msm_geni_serial_port_setup(uport))
goto exit_startup;
}
- get_tx_fifo_size(msm_port);
msm_geni_serial_start_rx(uport);
/*
* Ensure that all the port configuration writes complete
@@ -1790,10 +1798,6 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
dev_port->rx_fifo = devm_kzalloc(uport->dev, sizeof(u32),
GFP_KERNEL);
} else {
- dev_port->handle_rx = handle_rx_hs;
- dev_port->rx_fifo = devm_kzalloc(uport->dev,
- sizeof(dev_port->rx_fifo_depth * sizeof(u32)),
- GFP_KERNEL);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
diff --git a/drivers/usb/dwc3/dbm.c b/drivers/usb/dwc3/dbm.c
index 285cd5a..3860a1a 100644
--- a/drivers/usb/dwc3/dbm.c
+++ b/drivers/usb/dwc3/dbm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -129,7 +129,7 @@ static inline void msm_dbm_write_ep_reg_field(struct dbm *dbm,
enum dbm_reg reg, int ep,
const u32 mask, u32 val)
{
- u32 shift = find_first_bit((void *)&mask, 32);
+ u32 shift = __ffs(mask);
u32 offset = dbm->reg_table[reg].offset +
(dbm->reg_table[reg].ep_mult * ep);
u32 tmp = ioread32(dbm->base + offset);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a496468..81f3384 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -319,7 +319,7 @@ static inline u32 dwc3_msm_read_reg_field(void __iomem *base,
u32 offset,
const u32 mask)
{
- u32 shift = ffs(mask);
+ u32 shift = __ffs(mask);
u32 val = ioread32(base + offset);
val &= mask; /* clear other bits */
@@ -353,7 +353,7 @@ static inline void dwc3_msm_write_reg(void __iomem *base, u32 offset, u32 val)
static inline void dwc3_msm_write_reg_field(void __iomem *base, u32 offset,
const u32 mask, u32 val)
{
- u32 shift = find_first_bit((void *)&mask, 32);
+ u32 shift = __ffs(mask);
u32 tmp = ioread32(base + offset);
tmp &= ~mask; /* clear written bits */
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 1210188e..675e50e 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -27,29 +27,23 @@
#include <linux/usb/phy.h>
#include <linux/reset.h>
-#define QUSB2PHY_PWR_CTRL1 0x210
+/* QUSB2PHY_PWR_CTRL1 register related bits */
#define PWR_CTRL1_POWR_DOWN BIT(0)
-#define QUSB2PHY_PLL_COMMON_STATUS_ONE 0x1A0
+/* QUSB2PHY_PLL_COMMON_STATUS_ONE register related bits */
#define CORE_READY_STATUS BIT(0)
/* Get TUNE value from efuse bit-mask */
#define TUNE_VAL_MASK(val, pos, mask) ((val >> pos) & mask)
-#define QUSB2PHY_INTR_CTRL 0x22C
+/* QUSB2PHY_INTR_CTRL register related bits */
#define DMSE_INTR_HIGH_SEL BIT(4)
#define DPSE_INTR_HIGH_SEL BIT(3)
#define CHG_DET_INTR_EN BIT(2)
#define DMSE_INTR_EN BIT(1)
#define DPSE_INTR_EN BIT(0)
-#define QUSB2PHY_INTR_STAT 0x230
-#define DMSE_INTERRUPT BIT(1)
-#define DPSE_INTERRUPT BIT(0)
-
-#define QUSB2PHY_PORT_TUNE1 0x23c
-
-#define QUSB2PHY_PLL_CORE_INPUT_OVERRIDE 0x0a8
+/* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE register related bits */
#define CORE_PLL_RATE BIT(0)
#define CORE_PLL_RATE_MUX BIT(1)
#define CORE_PLL_EN BIT(2)
@@ -73,6 +67,16 @@ unsigned int phy_tune1;
module_param(phy_tune1, uint, 0644);
MODULE_PARM_DESC(phy_tune1, "QUSB PHY v2 TUNE1");
+enum qusb_phy_reg {
+ PORT_TUNE1,
+ PLL_COMMON_STATUS_ONE,
+ PWR_CTRL1,
+ INTR_CTRL,
+ PLL_CORE_INPUT_OVERRIDE,
+ TEST1,
+ USB2_PHY_REG_MAX,
+};
+
struct qusb_phy {
struct usb_phy phy;
void __iomem *base;
@@ -92,8 +96,10 @@ struct qusb_phy {
int host_init_seq_len;
int *qusb_phy_host_init_seq;
+ unsigned int *phy_reg;
+ int qusb_phy_reg_offset_cnt;
+
u32 tune_val;
- u32 phy_auto_resume_offset;
int efuse_bit_pos;
int efuse_num_of_bits;
@@ -316,7 +322,7 @@ static void qusb_phy_get_tune1_param(struct qusb_phy *qphy)
qphy->tune_val = TUNE_VAL_MASK(qphy->tune_val,
qphy->efuse_bit_pos, bit_mask);
- reg = readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE1);
+ reg = readb_relaxed(qphy->base + qphy->phy_reg[PORT_TUNE1]);
if (qphy->tune_val) {
reg = reg & 0x0f;
reg |= (qphy->tune_val << 4);
@@ -372,7 +378,7 @@ static void qusb_phy_host_init(struct usb_phy *phy)
/* Require to get phy pll lock successfully */
usleep_range(150, 160);
- reg = readb_relaxed(qphy->base + QUSB2PHY_PLL_COMMON_STATUS_ONE);
+ reg = readb_relaxed(qphy->base + qphy->phy_reg[PLL_COMMON_STATUS_ONE]);
dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg);
if (!(reg & CORE_READY_STATUS)) {
dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg);
@@ -421,9 +427,9 @@ static int qusb_phy_init(struct usb_phy *phy)
}
/* Disable the PHY */
- writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) |
+ writel_relaxed(readl_relaxed(qphy->base + qphy->phy_reg[PWR_CTRL1]) |
PWR_CTRL1_POWR_DOWN,
- qphy->base + QUSB2PHY_PWR_CTRL1);
+ qphy->base + qphy->phy_reg[PWR_CTRL1]);
if (qphy->qusb_phy_init_seq)
qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq,
@@ -435,7 +441,7 @@ static int qusb_phy_init(struct usb_phy *phy)
pr_debug("%s(): Programming TUNE1 parameter as:%x\n", __func__,
qphy->tune_val);
writel_relaxed(qphy->tune_val,
- qphy->base + QUSB2PHY_PORT_TUNE1);
+ qphy->base + qphy->phy_reg[PORT_TUNE1]);
}
/* If phy_tune1 modparam set, override tune1 value */
@@ -443,16 +449,16 @@ static int qusb_phy_init(struct usb_phy *phy)
pr_debug("%s(): (modparam) TUNE1 val:0x%02x\n",
__func__, phy_tune1);
writel_relaxed(phy_tune1,
- qphy->base + QUSB2PHY_PORT_TUNE1);
+ qphy->base + qphy->phy_reg[PORT_TUNE1]);
}
/* ensure above writes are completed before re-enabling PHY */
wmb();
/* Enable the PHY */
- writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) &
+ writel_relaxed(readl_relaxed(qphy->base + qphy->phy_reg[PWR_CTRL1]) &
~PWR_CTRL1_POWR_DOWN,
- qphy->base + QUSB2PHY_PWR_CTRL1);
+ qphy->base + qphy->phy_reg[PWR_CTRL1]);
/* Ensure above write is completed before turning ON ref clk */
wmb();
@@ -460,7 +466,7 @@ static int qusb_phy_init(struct usb_phy *phy)
/* Require to get phy pll lock successfully */
usleep_range(150, 160);
- reg = readb_relaxed(qphy->base + QUSB2PHY_PLL_COMMON_STATUS_ONE);
+ reg = readb_relaxed(qphy->base + qphy->phy_reg[PLL_COMMON_STATUS_ONE]);
dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg);
if (!(reg & CORE_READY_STATUS)) {
dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg);
@@ -478,9 +484,9 @@ static void qusb_phy_shutdown(struct usb_phy *phy)
qusb_phy_enable_clocks(qphy, true);
/* Disable the PHY */
- writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) |
+ writel_relaxed(readl_relaxed(qphy->base + qphy->phy_reg[PWR_CTRL1]) |
PWR_CTRL1_POWR_DOWN,
- qphy->base + QUSB2PHY_PWR_CTRL1);
+ qphy->base + qphy->phy_reg[PWR_CTRL1]);
/* Makes sure that above write goes through */
wmb();
@@ -525,7 +531,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
(qphy->phy.flags & PHY_HOST_MODE)) {
/* Disable all interrupts */
writel_relaxed(0x00,
- qphy->base + QUSB2PHY_INTR_CTRL);
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
linestate = qusb_phy_get_linestate(qphy);
/*
@@ -537,29 +543,27 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
* e.g. if currently D+ high, D- low (HS 'J'/Suspend),
* configure the mask to trigger on D+ low OR D- high
*/
- intr_mask = DMSE_INTERRUPT | DPSE_INTERRUPT;
+ intr_mask = DPSE_INTR_EN | DMSE_INTR_EN;
if (!(linestate & LINESTATE_DP)) /* D+ low */
intr_mask |= DPSE_INTR_HIGH_SEL;
if (!(linestate & LINESTATE_DM)) /* D- low */
intr_mask |= DMSE_INTR_HIGH_SEL;
writel_relaxed(intr_mask,
- qphy->base + QUSB2PHY_INTR_CTRL);
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
/* hold core PLL into reset */
writel_relaxed(CORE_PLL_EN_FROM_RESET |
CORE_RESET | CORE_RESET_MUX,
- qphy->base + QUSB2PHY_PLL_CORE_INPUT_OVERRIDE);
+ qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
- if (qphy->phy_auto_resume_offset) {
- /* enable phy auto-resume */
- writel_relaxed(0x91,
- qphy->base + qphy->phy_auto_resume_offset);
- /* flush the previous write before next write */
- wmb();
- writel_relaxed(0x90,
- qphy->base + qphy->phy_auto_resume_offset);
- }
+ /* enable phy auto-resume */
+ writel_relaxed(0x91, qphy->base + qphy->phy_reg[TEST1]);
+ /* flush the previous write before next write */
+ wmb();
+ writel_relaxed(0x90, qphy->base + qphy->phy_reg[TEST1]);
+
dev_dbg(phy->dev, "%s: intr_mask = %x\n",
__func__, intr_mask);
@@ -569,7 +573,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
} else { /* Cable disconnect case */
/* Disable all interrupts */
writel_relaxed(0x00,
- qphy->base + QUSB2PHY_INTR_CTRL);
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
qusb_phy_reset(qphy);
qusb_phy_enable_clocks(qphy, false);
qusb_phy_enable_power(qphy, false, true);
@@ -582,11 +586,11 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
qusb_phy_enable_clocks(qphy, true);
/* Clear all interrupts on resume */
writel_relaxed(0x00,
- qphy->base + QUSB2PHY_INTR_CTRL);
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
/* bring core PLL out of reset */
- writel_relaxed(CORE_PLL_EN_FROM_RESET,
- qphy->base + QUSB2PHY_PLL_CORE_INPUT_OVERRIDE);
+ writel_relaxed(CORE_PLL_EN_FROM_RESET, qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
/* Makes sure that above write goes through */
wmb();
@@ -870,6 +874,31 @@ static int qusb_phy_probe(struct platform_device *pdev)
}
size = 0;
+ of_get_property(dev->of_node, "qcom,qusb-phy-reg-offset", &size);
+ if (size) {
+ qphy->phy_reg = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (qphy->phy_reg) {
+ qphy->qusb_phy_reg_offset_cnt =
+ size / sizeof(*qphy->phy_reg);
+ if (qphy->qusb_phy_reg_offset_cnt > USB2_PHY_REG_MAX) {
+ dev_err(dev, "invalid reg offset count\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(dev->of_node,
+ "qcom,qusb-phy-reg-offset",
+ qphy->phy_reg,
+ qphy->qusb_phy_reg_offset_cnt);
+ } else {
+ dev_err(dev, "err mem alloc for qusb_phy_reg_offset\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(dev, "err provide qcom,qmp-phy-reg-offset\n");
+ return -EINVAL;
+ }
+
+ size = 0;
of_get_property(dev->of_node, "qcom,qusb-phy-init-seq", &size);
if (size) {
qphy->qusb_phy_init_seq = devm_kzalloc(dev,
@@ -917,12 +946,6 @@ static int qusb_phy_probe(struct platform_device *pdev)
return ret;
}
- ret = of_property_read_u32(dev->of_node, "qcom,phy-auto-resume-offset",
- &qphy->phy_auto_resume_offset);
- if (ret)
- dev_dbg(dev, "error reading qcom,phy-auto-resume-offset %d\n",
- ret);
-
qphy->vdd = devm_regulator_get(dev, "vdd");
if (IS_ERR(qphy->vdd)) {
dev_err(dev, "unable to get vdd supply\n");
diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h
index 8bd30d4..bc87beb 100644
--- a/include/dt-bindings/msm/msm-bus-ids.h
+++ b/include/dt-bindings/msm/msm-bus-ids.h
@@ -250,7 +250,8 @@
#define MSM_BUS_MASTER_CAMNOC_HF0_UNCOMP 146
#define MSM_BUS_MASTER_CAMNOC_HF1_UNCOMP 147
#define MSM_BUS_MASTER_CAMNOC_SF_UNCOMP 148
-#define MSM_BUS_MASTER_MASTER_LAST 149
+#define MSM_BUS_MASTER_GIC 149
+#define MSM_BUS_MASTER_MASTER_LAST 150
#define MSM_BUS_MASTER_LLCC_DISPLAY 20000
#define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001
@@ -330,7 +331,8 @@
#define MSM_BUS_A2NOC_SNOC_SLV 10065
#define MSM_BUS_SNOC_INT_2 10066
#define MSM_BUS_A0NOC_QDSS_INT 10067
-#define MSM_BUS_INT_LAST 10068
+#define MSM_BUS_SLAVE_ANOC_PCIE_A1NOC_SNOC 10068
+#define MSM_BUS_INT_LAST 10069
#define MSM_BUS_INT_TEST_ID 20000
#define MSM_BUS_INT_TEST_LAST 20050
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
index 78f01ea..86a2dc6 100644
--- a/include/linux/mailbox_client.h
+++ b/include/linux/mailbox_client.h
@@ -49,5 +49,6 @@ 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 */
bool mbox_controller_is_idle(struct mbox_chan *chan); /* atomic */
+void mbox_chan_debug(struct mbox_chan *chan);
#endif /* __MAILBOX_CLIENT_H */
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 30a4ed2..7827c68 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -49,6 +49,8 @@ struct mbox_chan;
* Used only if txdone_poll:=true && txdone_irq:=false
* @peek_data: Atomic check for any received data. Return true if controller
* has some data to push to the client. False otherwise.
+ * @debug: Allow chan to be debugged when the client detects a channel is
+ * locked up.
*/
struct mbox_chan_ops {
int (*send_data)(struct mbox_chan *chan, void *data);
@@ -90,6 +92,7 @@ struct mbox_controller {
struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
const struct of_phandle_args *sp);
bool (*is_idle)(struct mbox_controller *mbox);
+ void (*debug)(struct mbox_chan *chan);
/* Internal to API */
struct hrtimer poll_hrt;
struct list_head node;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 864c7d7..ff65b44 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1499,6 +1499,7 @@ struct ravg {
*/
u64 mark_start;
u32 sum, demand;
+ u32 coloc_demand;
u32 sum_history[RAVG_HIST_SIZE_MAX];
u32 *curr_window_cpu, *prev_window_cpu;
u32 curr_window, prev_window;
diff --git a/include/linux/seemp_instrumentation.h b/include/linux/seemp_instrumentation.h
index 21bc436..ff09bd2 100644
--- a/include/linux/seemp_instrumentation.h
+++ b/include/linux/seemp_instrumentation.h
@@ -15,6 +15,8 @@
#ifdef CONFIG_SEEMP_CORE
#include <linux/kernel.h>
+#include <linux/seemp_api.h>
+#include <linux/socket.h>
#define MAX_BUF_SIZE 188
@@ -66,11 +68,33 @@ static inline void seemp_logk_sendto(int fd, void __user *buff, size_t len,
seemp_logk_kernel_end(blck);
}
+
+static inline void seemp_logk_rtic(__u8 type, __u64 actor, __u8 asset_id[0x20],
+ __u8 asset_category, __u8 response)
+{
+ char *buf = NULL;
+ void *blck = NULL;
+
+ blck = seemp_setup_buf(&buf);
+ if (!blck)
+ return;
+
+ SEEMP_LOGK_RECORD(SEEMP_API_kernel__rtic,
+ "app_pid=%llu,rtic_type=%u,asset_id=%s,asset_category=%u,response=%u",
+ actor, type, asset_id, asset_category, response);
+
+ seemp_logk_kernel_end(blck);
+}
#else
static inline void seemp_logk_sendto(int fd, void __user *buff,
size_t len, unsigned int flags, struct sockaddr __user *addr,
int addr_len)
{
}
+
+static inline void seemp_logk_rtic(__u8 type, __u64 actor, __u8 asset_id[0x20],
+ __u8 asset_category, __u8 response)
+{
+}
#endif
#endif
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index bf8f149..e94a82b 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -236,6 +236,7 @@ TRACE_EVENT(sched_update_history,
__field( int, samples )
__field(enum task_event, evt )
__field(unsigned int, demand )
+ __field(unsigned int, coloc_demand )
__field(unsigned int, pred_demand )
__array( u32, hist, RAVG_HIST_SIZE_MAX)
__field(unsigned int, nr_big_tasks )
@@ -249,6 +250,7 @@ TRACE_EVENT(sched_update_history,
__entry->samples = samples;
__entry->evt = evt;
__entry->demand = p->ravg.demand;
+ __entry->coloc_demand = p->ravg.coloc_demand;
__entry->pred_demand = p->ravg.pred_demand;
memcpy(__entry->hist, p->ravg.sum_history,
RAVG_HIST_SIZE_MAX * sizeof(u32));
@@ -256,12 +258,12 @@ TRACE_EVENT(sched_update_history,
__entry->cpu = rq->cpu;
),
- TP_printk("%d (%s): runtime %u samples %d event %s demand %u pred_demand %u"
+ TP_printk("%d (%s): runtime %u samples %d event %s demand %u coloc_demand %u pred_demand %u"
" (hist: %u %u %u %u %u) cpu %d nr_big %u",
__entry->pid, __entry->comm,
__entry->runtime, __entry->samples,
task_event_names[__entry->evt],
- __entry->demand, __entry->pred_demand,
+ __entry->demand, __entry->coloc_demand, __entry->pred_demand,
__entry->hist[0], __entry->hist[1],
__entry->hist[2], __entry->hist[3],
__entry->hist[4], __entry->cpu, __entry->nr_big_tasks)
@@ -317,6 +319,7 @@ TRACE_EVENT(sched_update_task_ravg,
__field( u64, irqtime )
__field(enum task_event, evt )
__field(unsigned int, demand )
+ __field(unsigned int, coloc_demand )
__field(unsigned int, sum )
__field( int, cpu )
__field(unsigned int, pred_demand )
@@ -350,6 +353,7 @@ TRACE_EVENT(sched_update_task_ravg,
__entry->mark_start = p->ravg.mark_start;
__entry->delta_m = (wallclock - p->ravg.mark_start);
__entry->demand = p->ravg.demand;
+ __entry->coloc_demand = p->ravg.coloc_demand;
__entry->sum = p->ravg.sum;
__entry->irqtime = irqtime;
__entry->pred_demand = p->ravg.pred_demand;
@@ -370,12 +374,12 @@ TRACE_EVENT(sched_update_task_ravg,
__entry->prev_top = rq->prev_top;
),
- TP_printk("wc %llu ws %llu delta %llu event %s cpu %d cur_freq %u cur_pid %d task %d (%s) ms %llu delta %llu demand %u sum %u irqtime %llu pred_demand %u rq_cs %llu rq_ps %llu cur_window %u (%s) prev_window %u (%s) nt_cs %llu nt_ps %llu active_wins %u grp_cs %lld grp_ps %lld, grp_nt_cs %llu, grp_nt_ps: %llu curr_top %u prev_top %u",
+ TP_printk("wc %llu ws %llu delta %llu event %s cpu %d cur_freq %u cur_pid %d task %d (%s) ms %llu delta %llu demand %u coloc_demand: %u sum %u irqtime %llu pred_demand %u rq_cs %llu rq_ps %llu cur_window %u (%s) prev_window %u (%s) nt_cs %llu nt_ps %llu active_wins %u grp_cs %lld grp_ps %lld, grp_nt_cs %llu, grp_nt_ps: %llu curr_top %u prev_top %u",
__entry->wallclock, __entry->win_start, __entry->delta,
task_event_names[__entry->evt], __entry->cpu,
__entry->cur_freq, __entry->cur_pid,
__entry->pid, __entry->comm, __entry->mark_start,
- __entry->delta_m, __entry->demand,
+ __entry->delta_m, __entry->demand, __entry->coloc_demand,
__entry->sum, __entry->irqtime, __entry->pred_demand,
__entry->rq_cs, __entry->rq_ps, __entry->curr_window,
__window_print(p, __get_dynamic_array(curr_sum), nr_cpu_ids),
diff --git a/include/uapi/linux/seemp_api.h b/include/uapi/linux/seemp_api.h
index 4dfc257..a42ad4b 100644
--- a/include/uapi/linux/seemp_api.h
+++ b/include/uapi/linux/seemp_api.h
@@ -1,6 +1,8 @@
#ifndef _SEEMP_API_H_
#define _SEEMP_API_H_
+#define SEEMP_API_kernel__rtic 100000
+
#define SEEMP_API_kernel__oom_adjust_write 0
#define SEEMP_API_kernel__sendto 1
#define SEEMP_API_kernel__recvfrom 2
diff --git a/include/uapi/linux/seemp_param_id.h b/include/uapi/linux/seemp_param_id.h
index c72c579..d8b9f78 100644
--- a/include/uapi/linux/seemp_param_id.h
+++ b/include/uapi/linux/seemp_param_id.h
@@ -15,7 +15,11 @@
#define PARAM_ID_SENSOR 8
#define PARAM_ID_WINDOW_TYPE 9
#define PARAM_ID_WINDOW_FLAG 10
-#define NUM_PARAM_IDS 11
+#define PARAM_ID_RTIC_TYPE 11
+#define PARAM_ID_RTIC_ASSET_ID 12
+#define PARAM_ID_RTIC_ASSET_CATEGORY 13
+#define PARAM_ID_RTIC_RESPONSE 14
+#define NUM_PARAM_IDS 15
static inline int param_id_index(const char *param, const char *end)
{
@@ -44,6 +48,14 @@ static inline int param_id_index(const char *param, const char *end)
id = 9;
else if ((len == 11) && !memcmp(param, "window_flag", 11))
id = 10;
+ else if ((len == 9) && !memcmp(param, "rtic_type", 9))
+ id = 11;
+ else if ((len == 8) && !memcmp(param, "asset_id", 8))
+ id = 12;
+ else if ((len == 14) && !memcmp(param, "asset_category", 14))
+ id = 13;
+ else if ((len == 8) && !memcmp(param, "response", 8))
+ id = 14;
return id;
}
@@ -86,6 +98,18 @@ static inline const char *get_param_id_name(int id)
case 10:
name = "window_flag";
break;
+ case 11:
+ name = "rtic_type";
+ break;
+ case 12:
+ name = "asset_id";
+ break;
+ case 13:
+ name = "asset_category";
+ break;
+ case 14:
+ name = "response";
+ break;
}
return name;
}
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index e5c4ddf..731b2f0 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1074,6 +1074,11 @@ enum v4l2_mpeg_vidc_video_venc_iframesize_type {
V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 109)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 110)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 3577ec6a..7e3dfa6 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -409,12 +409,25 @@ static int notify_online(unsigned int cpu)
cpu_notify(CPU_ONLINE, cpu);
return 0;
}
+static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st);
static int bringup_wait_for_ap(unsigned int cpu)
{
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */
wait_for_completion(&st->done);
+ BUG_ON(!cpu_online(cpu));
+
+ /* Unpark the stopper thread and the hotplug thread of the target cpu */
+ stop_machine_unpark(cpu);
+ kthread_unpark(st->thread);
+
+ /* Should we go further up ? */
+ if (st->target > CPUHP_AP_ONLINE_IDLE) {
+ __cpuhp_kick_ap_work(st);
+ wait_for_completion(&st->done);
+ }
return st->result;
}
@@ -437,9 +450,7 @@ static int bringup_cpu(unsigned int cpu)
cpu_notify(CPU_UP_CANCELED, cpu);
return ret;
}
- ret = bringup_wait_for_ap(cpu);
- BUG_ON(!cpu_online(cpu));
- return ret;
+ return bringup_wait_for_ap(cpu);
}
/*
@@ -979,31 +990,20 @@ void notify_cpu_starting(unsigned int cpu)
}
/*
- * Called from the idle task. We need to set active here, so we can kick off
- * the stopper thread and unpark the smpboot threads. If the target state is
- * beyond CPUHP_AP_ONLINE_IDLE we kick cpuhp thread and let it bring up the
- * cpu further.
+ * Called from the idle task. Wake up the controlling task which brings the
+ * stopper and the hotplug thread of the upcoming CPU up and then delegates
+ * the rest of the online bringup to the hotplug thread.
*/
void cpuhp_online_idle(enum cpuhp_state state)
{
struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
- unsigned int cpu = smp_processor_id();
/* Happens for the boot cpu */
if (state != CPUHP_AP_ONLINE_IDLE)
return;
st->state = CPUHP_AP_ONLINE_IDLE;
-
- /* Unpark the stopper thread and the hotplug thread of this cpu */
- stop_machine_unpark(cpu);
- kthread_unpark(st->thread);
-
- /* Should we go further up ? */
- if (st->target > CPUHP_AP_ONLINE_IDLE)
- __cpuhp_kick_ap_work(st);
- else
- complete(&st->done);
+ complete(&st->done);
}
/* Requires cpu_add_remove_lock to be held */
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 80bf7ba..b65854c 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -160,11 +160,9 @@ static void __kthread_parkme(struct kthread *self)
{
__set_current_state(TASK_PARKED);
while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
- preempt_disable();
if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
complete(&self->parked);
- schedule_preempt_disabled();
- preempt_enable();
+ schedule();
__set_current_state(TASK_PARKED);
}
clear_bit(KTHREAD_IS_PARKED, &self->flags);
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index b6a639b..dce76d1 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -404,12 +404,13 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time,
static void sugov_work(struct kthread_work *work)
{
struct sugov_policy *sg_policy = container_of(work, struct sugov_policy, work);
+ unsigned long flags;
mutex_lock(&sg_policy->work_lock);
- raw_spin_lock(&sg_policy->update_lock);
+ raw_spin_lock_irqsave(&sg_policy->update_lock, flags);
sugov_track_cycles(sg_policy, sg_policy->policy->cur,
sched_ktime_clock());
- raw_spin_unlock(&sg_policy->update_lock);
+ raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags);
__cpufreq_driver_target(sg_policy->policy, sg_policy->next_freq,
CPUFREQ_RELATION_L);
mutex_unlock(&sg_policy->work_lock);
@@ -488,18 +489,19 @@ static ssize_t hispeed_freq_store(struct gov_attr_set *attr_set,
unsigned int val;
struct sugov_policy *sg_policy;
unsigned long hs_util;
+ unsigned long flags;
if (kstrtouint(buf, 10, &val))
return -EINVAL;
tunables->hispeed_freq = val;
list_for_each_entry(sg_policy, &attr_set->policy_list, tunables_hook) {
- raw_spin_lock(&sg_policy->update_lock);
+ raw_spin_lock_irqsave(&sg_policy->update_lock, flags);
hs_util = freq_to_util(sg_policy,
sg_policy->tunables->hispeed_freq);
hs_util = mult_frac(hs_util, TARGET_LOAD, 100);
sg_policy->hispeed_util = hs_util;
- raw_spin_unlock(&sg_policy->update_lock);
+ raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags);
}
return count;
@@ -784,13 +786,14 @@ static void sugov_stop(struct cpufreq_policy *policy)
static void sugov_limits(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
+ unsigned long flags;
if (!policy->fast_switch_enabled) {
mutex_lock(&sg_policy->work_lock);
- raw_spin_lock(&sg_policy->update_lock);
+ raw_spin_lock_irqsave(&sg_policy->update_lock, flags);
sugov_track_cycles(sg_policy, sg_policy->policy->cur,
sched_ktime_clock());
- raw_spin_unlock(&sg_policy->update_lock);
+ raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags);
cpufreq_policy_apply_limits(policy);
mutex_unlock(&sg_policy->work_lock);
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d06ac7d..1c5bb37 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5407,10 +5407,13 @@ static inline int task_util(struct task_struct *p)
}
static inline bool
-bias_to_waker_cpu(struct task_struct *p, int cpu)
+bias_to_waker_cpu(struct task_struct *p, int cpu, struct cpumask *rtg_target)
{
+ int rtg_target_cpu = rtg_target ? cpumask_first(rtg_target) : cpu;
+
return cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) &&
cpu_active(cpu) && !cpu_isolated(cpu) &&
+ capacity_orig_of(cpu) >= capacity_orig_of(rtg_target_cpu) &&
task_fits_max(p, cpu);
}
@@ -6730,6 +6733,7 @@ static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync)
bool need_idle;
enum sched_boost_policy placement_boost = task_sched_boost(p) ?
sched_boost_policy() : SCHED_BOOST_NONE;
+ struct related_thread_group *grp;
sd = rcu_dereference(per_cpu(sd_ea, task_cpu(p)));
@@ -6745,22 +6749,17 @@ static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync)
need_idle = wake_to_idle(p);
- if (sync && bias_to_waker_cpu(p, cpu)) {
+ grp = task_related_thread_group(p);
+ if (grp && grp->preferred_cluster)
+ rtg_target = &grp->preferred_cluster->cpus;
+
+ if (sync && bias_to_waker_cpu(p, cpu, rtg_target)) {
trace_sched_task_util_bias_to_waker(p, task_cpu(p),
task_util(p), cpu, cpu, 0, need_idle);
return cpu;
}
if (sysctl_sched_is_big_little) {
- struct related_thread_group *grp;
-
- rcu_read_lock();
- grp = task_related_thread_group(p);
- rcu_read_unlock();
-
- if (grp && grp->preferred_cluster)
- rtg_target = &grp->preferred_cluster->cpus;
-
task_util_boosted = boosted_task_util(p);
/*
@@ -7080,8 +7079,12 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
return select_best_cpu(p, prev_cpu, 0, sync);
#endif
- if (energy_aware())
- return energy_aware_wake_cpu(p, prev_cpu, sync);
+ if (energy_aware()) {
+ rcu_read_lock();
+ new_cpu = energy_aware_wake_cpu(p, prev_cpu, sync);
+ rcu_read_unlock();
+ return new_cpu;
+ }
if (sd_flag & SD_BALANCE_WAKE) {
record_wakee(p);
@@ -12296,7 +12299,9 @@ void check_for_migration(struct rq *rq, struct task_struct *p)
rq->curr->nr_cpus_allowed == 1)
return;
+ rcu_read_lock();
new_cpu = energy_aware_wake_cpu(p, cpu, 0);
+ rcu_read_unlock();
if (capacity_orig_of(new_cpu) > capacity_orig_of(cpu)) {
active_balance = kick_active_balance(rq, p, new_cpu);
if (active_balance) {
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index ae45283..69bbce2 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -1704,6 +1704,7 @@ static void update_history(struct rq *rq, struct task_struct *p,
pred_demand);
p->ravg.demand = demand;
+ p->ravg.coloc_demand = div64_u64(sum, sched_ravg_hist_size);
p->ravg.pred_demand = pred_demand;
if (__task_in_cum_window_demand(rq, p))
@@ -1982,6 +1983,7 @@ void init_new_task_load(struct task_struct *p, bool idle_task)
(u64)sched_ravg_window, 100);
p->ravg.demand = init_load_windows;
+ p->ravg.coloc_demand = init_load_windows;
p->ravg.pred_demand = 0;
for (i = 0; i < RAVG_HIST_SIZE_MAX; ++i)
p->ravg.sum_history[i] = init_load_windows;
@@ -2505,7 +2507,7 @@ static void _set_preferred_cluster(struct related_thread_group *grp)
(sched_ravg_window * sched_ravg_hist_size))
continue;
- combined_demand += p->ravg.demand;
+ combined_demand += p->ravg.coloc_demand;
}
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
index 04a1b97..14e3d85 100644
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -76,6 +76,7 @@ struct idletimer_tg {
bool send_nl_msg;
bool active;
uid_t uid;
+ bool suspend_time_valid;
};
static LIST_HEAD(idletimer_tg_list);
@@ -245,8 +246,13 @@ static int idletimer_resume(struct notifier_block *notifier,
switch (pm_event) {
case PM_SUSPEND_PREPARE:
get_monotonic_boottime(&timer->last_suspend_time);
+ timer->suspend_time_valid = true;
break;
case PM_POST_SUSPEND:
+ if (!timer->suspend_time_valid)
+ break;
+ timer->suspend_time_valid = false;
+
spin_lock_bh(×tamp_lock);
if (!timer->active) {
spin_unlock_bh(×tamp_lock);
@@ -281,7 +287,7 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
{
int ret;
- info->timer = kmalloc(sizeof(*info->timer), GFP_KERNEL);
+ info->timer = kzalloc(sizeof(*info->timer), GFP_KERNEL);
if (!info->timer) {
ret = -ENOMEM;
goto out;
diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h
index afd93b2..93a1ad3 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-routing.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h
@@ -117,6 +117,70 @@ const struct snd_soc_dapm_route tavil_slim_audio_map[] = {
const struct snd_soc_dapm_route tavil_audio_map[] = {
+ /* WDMA3 */
+ {"WDMA3 PORT0 MUX", "DEC0", "ADC MUX0"},
+ {"WDMA3 PORT0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"},
+ {"WDMA3 PORT1 MUX", "DEC1", "ADC MUX1"},
+ {"WDMA3 PORT1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"},
+ {"WDMA3 PORT2 MUX", "DEC2", "ADC MUX2"},
+ {"WDMA3 PORT2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"},
+ {"WDMA3 PORT3 MUX", "DEC3", "ADC MUX3"},
+ {"WDMA3 PORT3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"},
+ {"WDMA3 PORT4 MUX", "DEC4", "ADC MUX4"},
+ {"WDMA3 PORT4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"},
+ {"WDMA3 PORT5 MUX", "DEC5", "ADC MUX5"},
+ {"WDMA3 PORT5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"},
+ {"WDMA3 PORT6 MUX", "DEC6", "ADC MUX6"},
+ {"WDMA3 PORT6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"},
+
+ {"WDMA3 CH0 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+ {"WDMA3 CH0 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+ {"WDMA3 CH0 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+ {"WDMA3 CH0 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+ {"WDMA3 CH0 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+ {"WDMA3 CH0 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+ {"WDMA3 CH0 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+ {"WDMA3 CH0 MUX", "PORT_7", "ADC MUX7"},
+ {"WDMA3 CH0 MUX", "PORT_8", "ADC MUX8"},
+
+ {"WDMA3 CH1 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+ {"WDMA3 CH1 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+ {"WDMA3 CH1 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+ {"WDMA3 CH1 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+ {"WDMA3 CH1 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+ {"WDMA3 CH1 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+ {"WDMA3 CH1 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+ {"WDMA3 CH1 MUX", "PORT_7", "ADC MUX7"},
+ {"WDMA3 CH1 MUX", "PORT_8", "ADC MUX8"},
+
+ {"WDMA3 CH2 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+ {"WDMA3 CH2 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+ {"WDMA3 CH2 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+ {"WDMA3 CH2 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+ {"WDMA3 CH2 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+ {"WDMA3 CH2 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+ {"WDMA3 CH2 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+ {"WDMA3 CH2 MUX", "PORT_7", "ADC MUX7"},
+ {"WDMA3 CH2 MUX", "PORT_8", "ADC MUX8"},
+
+ {"WDMA3 CH3 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+ {"WDMA3 CH3 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+ {"WDMA3 CH3 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+ {"WDMA3 CH3 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+ {"WDMA3 CH3 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+ {"WDMA3 CH3 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+ {"WDMA3 CH3 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+ {"WDMA3 CH3 MUX", "PORT_7", "ADC MUX7"},
+ {"WDMA3 CH3 MUX", "PORT_8", "ADC MUX8"},
+
+ {"WDMA3_CH_MIXER", NULL, "WDMA3 CH0 MUX"},
+ {"WDMA3_CH_MIXER", NULL, "WDMA3 CH1 MUX"},
+ {"WDMA3_CH_MIXER", NULL, "WDMA3 CH2 MUX"},
+ {"WDMA3_CH_MIXER", NULL, "WDMA3 CH3 MUX"},
+
+ {"WDMA3_ON_OFF", "Switch", "WDMA3_CH_MIXER"},
+ {"WDMA3_OUT", NULL, "WDMA3_ON_OFF"},
+
/* MAD */
{"MAD_SEL MUX", "SPE", "MAD_CPE_INPUT"},
{"MAD_SEL MUX", "MSM", "MADINPUT"},
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index ca16ed8..3079cca 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -180,6 +180,8 @@ enum {
ANC_MIC_AMIC2,
ANC_MIC_AMIC3,
ANC_MIC_AMIC4,
+ CLK_INTERNAL,
+ CLK_MODE,
};
enum {
@@ -1071,6 +1073,40 @@ static int tavil_codec_enable_anc(struct snd_soc_dapm_widget *w,
return ret;
}
+static int tavil_get_clkmode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+
+ if (test_bit(CLK_MODE, &tavil_p->status_mask))
+ ucontrol->value.enumerated.item[0] = 1;
+ else
+ ucontrol->value.enumerated.item[0] = 0;
+
+ dev_dbg(codec->dev, "%s: is_low_power_clock: %s\n", __func__,
+ test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false");
+
+ return 0;
+}
+
+static int tavil_put_clkmode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+
+ if (ucontrol->value.enumerated.item[0])
+ set_bit(CLK_MODE, &tavil_p->status_mask);
+ else
+ clear_bit(CLK_MODE, &tavil_p->status_mask);
+
+ dev_dbg(codec->dev, "%s: is_low_power_clock: %s\n", __func__,
+ test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false");
+
+ return 0;
+}
+
static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2809,6 +2845,35 @@ static int tavil_get_asrc_mode(struct tavil_priv *tavil, int asrc,
return asrc_mode;
}
+static int tavil_codec_wdma3_ctl(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Fix to 16KHz */
+ snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+ 0xF0, 0x10);
+ /* Select mclk_1 */
+ snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+ 0x02, 0x00);
+ /* Enable DMA */
+ snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+ 0x01, 0x01);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ /* Disable DMA */
+ snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+ 0x01, 0x00);
+ break;
+
+ };
+
+ return 0;
+}
+
static int tavil_codec_enable_asrc(struct snd_soc_codec *codec,
int asrc_in, int event)
{
@@ -5547,6 +5612,9 @@ static const char *const tavil_anc_func_text[] = {"OFF", "ON"};
static const struct soc_enum tavil_anc_func_enum =
SOC_ENUM_SINGLE_EXT(2, tavil_anc_func_text);
+static const char *const tavil_clkmode_text[] = {"EXTERNAL", "INTERNAL"};
+static SOC_ENUM_SINGLE_EXT_DECL(tavil_clkmode_enum, tavil_clkmode_text);
+
/* Cutoff frequency for high pass filter */
static const char * const cf_text[] = {
"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ"
@@ -5726,6 +5794,9 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = {
SOC_ENUM_EXT("ANC Function", tavil_anc_func_enum, tavil_get_anc_func,
tavil_put_anc_func),
+ SOC_ENUM_EXT("CLK MODE", tavil_clkmode_enum, tavil_get_clkmode,
+ tavil_put_clkmode),
+
SOC_ENUM("TX0 HPF cut off", cf_dec0_enum),
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
@@ -6165,6 +6236,39 @@ static const char * const native_mux_text[] = {
"OFF", "ON",
};
+static const char *const wdma3_port0_text[] = {
+ "RX_MIX_TX0", "DEC0"
+};
+
+static const char *const wdma3_port1_text[] = {
+ "RX_MIX_TX1", "DEC1"
+};
+
+static const char *const wdma3_port2_text[] = {
+ "RX_MIX_TX2", "DEC2"
+};
+
+static const char *const wdma3_port3_text[] = {
+ "RX_MIX_TX3", "DEC3"
+};
+
+static const char *const wdma3_port4_text[] = {
+ "RX_MIX_TX4", "DEC4"
+};
+
+static const char *const wdma3_port5_text[] = {
+ "RX_MIX_TX5", "DEC5"
+};
+
+static const char *const wdma3_port6_text[] = {
+ "RX_MIX_TX6", "DEC6"
+};
+
+static const char *const wdma3_ch_text[] = {
+ "PORT_0", "PORT_1", "PORT_2", "PORT_3", "PORT_4",
+ "PORT_5", "PORT_6", "PORT_7", "PORT_8",
+};
+
static const struct snd_kcontrol_new aif4_vi_mixer[] = {
SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, WCD934X_TX14, 1, 0,
tavil_vi_feed_mixer_get, tavil_vi_feed_mixer_put),
@@ -6570,6 +6674,20 @@ WCD_DAPM_ENUM(int8_2_native, SND_SOC_NOPM, 0, native_mux_text);
WCD_DAPM_ENUM(anc0_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 0, anc0_fb_mux_text);
WCD_DAPM_ENUM(anc1_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 3, anc1_fb_mux_text);
+
+WCD_DAPM_ENUM(wdma3_port0, WCD934X_DMA_WDMA3_PRT_CFG, 0, wdma3_port0_text);
+WCD_DAPM_ENUM(wdma3_port1, WCD934X_DMA_WDMA3_PRT_CFG, 1, wdma3_port1_text);
+WCD_DAPM_ENUM(wdma3_port2, WCD934X_DMA_WDMA3_PRT_CFG, 2, wdma3_port2_text);
+WCD_DAPM_ENUM(wdma3_port3, WCD934X_DMA_WDMA3_PRT_CFG, 3, wdma3_port3_text);
+WCD_DAPM_ENUM(wdma3_port4, WCD934X_DMA_WDMA3_PRT_CFG, 4, wdma3_port4_text);
+WCD_DAPM_ENUM(wdma3_port5, WCD934X_DMA_WDMA3_PRT_CFG, 5, wdma3_port5_text);
+WCD_DAPM_ENUM(wdma3_port6, WCD934X_DMA_WDMA3_PRT_CFG, 6, wdma3_port6_text);
+
+WCD_DAPM_ENUM(wdma3_ch0, WCD934X_DMA_CH_0_1_CFG_WDMA_3, 0, wdma3_ch_text);
+WCD_DAPM_ENUM(wdma3_ch1, WCD934X_DMA_CH_0_1_CFG_WDMA_3, 4, wdma3_ch_text);
+WCD_DAPM_ENUM(wdma3_ch2, WCD934X_DMA_CH_2_3_CFG_WDMA_3, 0, wdma3_ch_text);
+WCD_DAPM_ENUM(wdma3_ch3, WCD934X_DMA_CH_2_3_CFG_WDMA_3, 4, wdma3_ch_text);
+
static const struct snd_kcontrol_new anc_ear_switch =
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
@@ -6637,6 +6755,9 @@ static const struct snd_kcontrol_new rx_int4_asrc_switch[] = {
SOC_DAPM_SINGLE("LO2 Switch", SND_SOC_NOPM, 0, 1, 0),
};
+static const struct snd_kcontrol_new wdma3_onoff_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
static int tavil_dsd_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -7319,6 +7440,28 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
SND_SOC_DAPM_MUX_E("ASRC3 MUX", SND_SOC_NOPM, ASRC3, 0,
&asrc3_mux, tavil_codec_enable_asrc_resampler,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* WDMA3 widgets */
+ WCD_DAPM_MUX("WDMA3 PORT0 MUX", 0, wdma3_port0),
+ WCD_DAPM_MUX("WDMA3 PORT1 MUX", 1, wdma3_port1),
+ WCD_DAPM_MUX("WDMA3 PORT2 MUX", 2, wdma3_port2),
+ WCD_DAPM_MUX("WDMA3 PORT3 MUX", 3, wdma3_port3),
+ WCD_DAPM_MUX("WDMA3 PORT4 MUX", 4, wdma3_port4),
+ WCD_DAPM_MUX("WDMA3 PORT5 MUX", 5, wdma3_port5),
+ WCD_DAPM_MUX("WDMA3 PORT6 MUX", 6, wdma3_port6),
+
+ WCD_DAPM_MUX("WDMA3 CH0 MUX", 0, wdma3_ch0),
+ WCD_DAPM_MUX("WDMA3 CH1 MUX", 4, wdma3_ch1),
+ WCD_DAPM_MUX("WDMA3 CH2 MUX", 0, wdma3_ch2),
+ WCD_DAPM_MUX("WDMA3 CH3 MUX", 4, wdma3_ch3),
+
+ SND_SOC_DAPM_MIXER("WDMA3_CH_MIXER", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SWITCH_E("WDMA3_ON_OFF", SND_SOC_NOPM, 0, 0,
+ &wdma3_onoff_switch, tavil_codec_wdma3_ctl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_OUTPUT("WDMA3_OUT"),
};
static int tavil_get_channel_map(struct snd_soc_dai *dai,
@@ -8316,6 +8459,50 @@ static int tavil_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
return ret;
}
+/*
+ * tavil_cdc_mclk_tx_enable: Enable/Disable codec's clock for TX path
+ * @codec: Handle to codec
+ * @enable: Indicates whether clock should be enabled or disabled
+ */
+int tavil_cdc_mclk_tx_enable(struct snd_soc_codec *codec, bool enable)
+{
+ struct tavil_priv *tavil_p;
+ int ret = 0;
+ bool clk_mode;
+ bool clk_internal;
+
+ if (!codec)
+ return -EINVAL;
+
+ tavil_p = snd_soc_codec_get_drvdata(codec);
+ clk_mode = test_bit(CLK_MODE, &tavil_p->status_mask);
+ clk_internal = test_bit(CLK_INTERNAL, &tavil_p->status_mask);
+
+ dev_dbg(codec->dev, "%s: clkmode: %d, enable: %d, clk_internal: %d\n",
+ __func__, clk_mode, enable, clk_internal);
+
+ if (clk_mode || clk_internal) {
+ if (enable) {
+ wcd_resmgr_enable_master_bias(tavil_p->resmgr);
+ tavil_dig_core_power_collapse(tavil_p, POWER_RESUME);
+ tavil_vote_svs(tavil_p, true);
+ ret = tavil_codec_internal_rco_ctrl(codec, enable);
+ set_bit(CLK_INTERNAL, &tavil_p->status_mask);
+ } else {
+ clear_bit(CLK_INTERNAL, &tavil_p->status_mask);
+ tavil_codec_internal_rco_ctrl(codec, enable);
+ tavil_vote_svs(tavil_p, false);
+ tavil_dig_core_power_collapse(tavil_p, POWER_COLLAPSE);
+ wcd_resmgr_disable_master_bias(tavil_p->resmgr);
+ }
+ } else {
+ ret = __tavil_cdc_mclk_enable(tavil_p, enable);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(tavil_cdc_mclk_tx_enable);
+
static const struct wcd_resmgr_cb tavil_resmgr_cb = {
.cdc_rco_ctrl = __tavil_codec_internal_rco_ctrl,
};
diff --git a/sound/soc/codecs/wcd934x/wcd934x.h b/sound/soc/codecs/wcd934x/wcd934x.h
index c3bf50a..27c21f1 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.h
+++ b/sound/soc/codecs/wcd934x/wcd934x.h
@@ -137,6 +137,7 @@ struct tavil_reg_mask_val {
extern void *tavil_get_afe_config(struct snd_soc_codec *codec,
enum afe_config_type config_type);
extern int tavil_cdc_mclk_enable(struct snd_soc_codec *codec, bool enable);
+extern int tavil_cdc_mclk_tx_enable(struct snd_soc_codec *codec, bool enable);
extern int tavil_set_spkr_mode(struct snd_soc_codec *codec, int mode);
extern int tavil_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset);
extern struct wcd_dsp_cntl *tavil_get_wcd_dsp_cntl(struct device *dev);
diff --git a/sound/soc/msm/qdsp6v2/audio_calibration.c b/sound/soc/msm/qdsp6v2/audio_calibration.c
index 808a0e4..d709b09 100644
--- a/sound/soc/msm/qdsp6v2/audio_calibration.c
+++ b/sound/soc/msm/qdsp6v2/audio_calibration.c
@@ -460,6 +460,12 @@ static long audio_cal_shared_ioctl(struct file *file, unsigned int cmd,
data->cal_type.cal_hdr.buffer_number);
ret = -EINVAL;
goto done;
+ } else if ((data->hdr.cal_type_size + sizeof(data->hdr)) > size) {
+ pr_err("%s: cal type hdr size %zd + cal type size %d is greater than user buffer size %d\n",
+ __func__, sizeof(data->hdr), data->hdr.cal_type_size,
+ size);
+ ret = -EFAULT;
+ goto done;
}
@@ -497,13 +503,7 @@ static long audio_cal_shared_ioctl(struct file *file, unsigned int cmd,
goto unlock;
if (data == NULL)
goto unlock;
- if ((sizeof(data->hdr) + data->hdr.cal_type_size) > size) {
- pr_err("%s: header size %zd plus cal type size %d are greater than data buffer size %d\n",
- __func__, sizeof(data->hdr),
- data->hdr.cal_type_size, size);
- ret = -EFAULT;
- goto unlock;
- } else if (copy_to_user((void *)arg, data,
+ if (copy_to_user(arg, data,
sizeof(data->hdr) + data->hdr.cal_type_size)) {
pr_err("%s: Could not copy cal type to user\n",
__func__);
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index d3c4e05..9248766 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -538,10 +538,10 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = {
};
static struct snd_soc_dapm_route wcd_audio_paths[] = {
- {"MIC BIAS1", NULL, "MCLK"},
- {"MIC BIAS2", NULL, "MCLK"},
- {"MIC BIAS3", NULL, "MCLK"},
- {"MIC BIAS4", NULL, "MCLK"},
+ {"MIC BIAS1", NULL, "MCLK TX"},
+ {"MIC BIAS2", NULL, "MCLK TX"},
+ {"MIC BIAS3", NULL, "MCLK TX"},
+ {"MIC BIAS4", NULL, "MCLK TX"},
};
static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
@@ -2784,6 +2784,38 @@ static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
return ret;
}
+static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ if (!strcmp(dev_name(codec->dev), "tavil_codec")) {
+ ret = tavil_cdc_mclk_tx_enable(codec, enable);
+ } else {
+ dev_err(codec->dev, "%s: unknown codec to enable TX ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int msm_mclk_tx_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 0, true);
+ }
+ return 0;
+}
+
static int msm_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -2840,7 +2872,7 @@ static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("MCLK TX", SND_SOC_NOPM, 0, 0,
- NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ msm_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),