Merge "ARM: dts: msm: add 4k panel support for SDM845" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index fe53218..592fcef 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -141,6 +141,20 @@
* qcom,msr-fix-req: boolean, indicating if MSRs need to be programmed
after enabling the subunit.
+* Optional properties for CTI:
+
+ * qcom,cti-gpio-trigin: cti trigger input driven by gpio.
+
+ * qcom,cti-gpio-trigout: cti trigger output sent to gpio.
+
+ * pinctrl-names: names corresponding to the numbered pinctrl. The
+ allowed names are subset of the following: cti-trigin-pinctrl,
+ cti-trigout-pctrl.
+
+ * pinctrl-<n>: list of pinctrl phandles for the different pinctrl
+ states. Refer to
+ "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt"
+
* Required property for Remote ETMs:
* qcom,inst-id: must be present. QMI instance id for remote ETMs.
diff --git a/Documentation/devicetree/bindings/arm/msm/cmd-db.txt b/Documentation/devicetree/bindings/arm/msm/cmd-db.txt
index b989d8a..e704d70 100644
--- a/Documentation/devicetree/bindings/arm/msm/cmd-db.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cmd-db.txt
@@ -24,10 +24,12 @@
Value type: <prop-encoded-array>
Definition: First element is the base address of shared memory
Second element is the size of the shared memory region
+ Points to the dictionary address that houses the command DB
+ start address and the size of the command DB region
Example:
qcom,cmd-db@861e0000 {
compatible = "qcom,cmd-db";
- reg = <0x861e0000 0x4000>;
+ reg = <0xc3f000c 0x8>;
}
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index bc226a7..a3ef34c 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -128,6 +128,8 @@
feature is available or not.
- qcom,sde-has-dim-layer: Boolean property to indicate if mixer has dim layer
feature is available or not.
+- qcom,sde-has-idle-pc: Boolean property to indicate if target has idle
+ power collapse feature available or not.
- qcom,sde-has-mixer-gc: Boolean property to indicate if mixer has gamma correction
feature available or not.
- qcom,sde-has-cdp: Boolean property to indicate if cdp feature is
@@ -420,6 +422,7 @@
qcom,sde-csc-type = "csc-10bit";
qcom,sde-highest-bank-bit = <15>;
qcom,sde-has-mixer-gc;
+ qcom,sde-has-idle-pc;
qcom,sde-sspp-max-rects = <1 1 1 1
1 1 1 1
1 1
diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
index 3e7fcb7..75d6e91 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
@@ -35,7 +35,7 @@
- qcom,mdss-dsi-panel-destination: A string that specifies the destination display for the panel.
"display_1" = DISPLAY_1
"display_2" = DISPLAY_2
-- qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY
+- qcom,mdss-dsi-panel-phy-timings: An array of length 12 that specifies the PHY
timing settings for the panel.
- qcom,mdss-dsi-panel-timings-8996: An array of length 40 char that specifies the 8996 PHY lane
timing settings for the panel.
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
new file mode 100644
index 0000000..2ed913c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
@@ -0,0 +1,130 @@
+* Qualcomm Technologies, Inc. MSM Camera SMMU
+
+The MSM camera SMMU device provides SMMU context bank definitions
+for all HW blocks that need to map IOVA to physical memory. These
+definitions consist of various properties that define how the
+IOVA address space is laid out for each HW block in the camera
+subsystem.
+
+=======================
+Required Node Structure
+=======================
+The camera SMMU device must be described in three levels of device nodes. The
+first level describes the overall SMMU device. Within it, second level nodes
+describe individual context banks that map different stream ids. There can
+also be second level nodes describing firmware device nodes. Each HW block
+such as IFE, ICP maps into these second level device nodes. All context bank
+specific properties that define how the IOVA is laid out is contained within
+third level device nodes within the second level device nodes.
+
+During the kernel initialization all the devices are probed recursively and
+a device pointer is created for each context bank keeping track of the IOVA
+mapping information.
+
+Duplicate regions of the same type are not allowed within the same
+context bank. All context banks must contain an IO region at the very least.
+
+==================================
+First Level Node - CAM SMMU device
+==================================
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,msm-cam-smmu".
+
+===================================================================
+Second Level Node - CAM SMMU context bank device or firmware device
+===================================================================
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,msm-cam-smmu-cb" or "qcom,msm-cam-smmu-fw-dev".
+
+- memory-region
+ Usage: optional
+ Value type: <phandle>
+ Definition: Should specify the phandle of the memory region for firmware.
+ allocation
+
+- iommus
+ Usage: required
+ Value type: <phandle>
+ Definition: Should specify the phandle of the iommu sid.
+
+- label
+ Usage: required
+ Value type: <string>
+ Definition: Should specify a string label to identify the context bank.
+
+=============================================
+Third Level Node - CAM SMMU memory map device
+=============================================
+- iova-region-name
+ Usage: required
+ Value type: <string>
+ Definition: Should specify a string label to identify the IOVA region.
+
+- iova-region-start
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify start IOVA for region.
+
+- iova-region-len
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify length for IOVA region.
+
+- iova-region-id
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify the numerical identifier for IOVA region.
+ Allowed values are: 0x00 to 0x03
+ - Firmware region: 0x00
+ - Shared region: 0x01
+ - Scratch region: 0x02
+ - IO region: 0x03
+
+Example:
+ qcom,cam_smmu@0 {
+ compatible = "qcom,msm-cam-smmu";
+
+ msm_cam_smmu_icp {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1078>,
+ <&apps_smmu 0x1020>,
+ <&apps_smmu 0x1028>,
+ <&apps_smmu 0x1040>,
+ <&apps_smmu 0x1048>,
+ <&apps_smmu 0x1030>,
+ <&apps_smmu 0x1050>;
+ label = "icp";
+ icp_iova_mem_map: iova-mem-map {
+ iova-mem-region-firmware {
+ /* Firmware region is 5MB */
+ iova-region-name = "firmware";
+ iova-region-start = <0x0>;
+ iova-region-len = <0x500000>;
+ iova-region-id = <0x0>;
+ status = "ok";
+ };
+
+ iova-mem-region-shared {
+ /* Shared region is 100MB long */
+ iova-region-name = "shared";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0x6400000>;
+ iova-region-id = <0x1>;
+ status = "ok";
+ };
+
+ iova-mem-region-io {
+ /* IO region is approximately 3.5 GB */
+ iova-region-name = "io";
+ iova-region-start = <0xd800000>;
+ iova-region-len = <0xd2800000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index ea828da..bc844de 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -16,6 +16,10 @@
If "halt_base" is in same 4K pages this register then
this will be defined else "halt_q6", "halt_modem",
"halt_nc" is required.
+ "pdc_sync" is the power domain register introduced in
+ sdm845 for power domain of subsystems.
+ If alternative reset is required, "alt_reset" maps to
+ mss_alt_ares.
- interrupts: The modem watchdog interrupt
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- vdd_cx-voltage: Voltage corner/level(max) for cx rail.
diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
index 5bf560e..846bd22 100644
--- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
@@ -216,6 +216,15 @@
as the corresponding addresses are specified in
the qcom,cpr-panic-reg-addr-list property.
+- qcom,cpr-reset-step-quot-loop-en
+ Usage: optional; only meaningful for CPR4 and CPRh controllers
+ Value type: <empty>
+ Definition: Boolean value which indicates that the CPR controller should
+ be configured to reset step_quot on each loop_en = 0
+ transition. This configuration allows the CPR controller to
+ first use the default step_quot and then later switch to the
+ run-time calibrated step_quot.
+
- qcom,saw-avs-ctrl
Usage: required if "saw" registers are specified by reg and
reg-names properties
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
index bb20644..fc8ec87 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
@@ -12,10 +12,17 @@
- interrupts: PMIC temperature alarm interrupt
- label: A string used as a descriptive name for this thermal device.
This name should be 19 characters or less.
+- #thermal-sensor-cells: Must be 0. Please refer to
+ <devicetree/bindings/thermal/thermal.txt> for more
+ details.
Required structure:
- A qcom,qpnp-temp-alarm node must be a child of an SPMI node that has specified
the spmi-slave-container property
+- A top level device tree node named "thermal-zones" must exist. It must
+ contain a subnode with a property named "thermal-sensors" which is assigned
+ a phandle to the qpnp-temp-alarm device node. See
+ <devicetree/bindings/thermal/thermal.txt> for more details.
Optional properties:
- qcom,channel-num: VADC channel number associated PMIC DIE_TEMP thermistor.
@@ -38,11 +45,6 @@
1 = 50 Hz
2 = 25 Hz
3 = 12.5 Hz
-- qcom,allow-override: Boolean which controls the ability of software to
- override shutdowns. If present, then software is
- allowed to override automatic PMIC hardware stage 2 and
- stage 3 over temperature shutdowns. Otherwise, software
- is not allowed to override automatic shutdown.
- qcom,default-temp: Specifies the default temperature in millicelcius to use
if no ADC channel is present to read the real time
temperature.
@@ -64,7 +66,7 @@
#address-cells = <1>;
#size-cells = <1>;
- qcom,temp-alarm@2400 {
+ pm8941_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
interrupts = <0x0 0x24 0x0>;
@@ -72,6 +74,36 @@
qcom,channel-num = <8>;
qcom,threshold-set = <0>;
qcom,temp_alarm-vadc = <&pm8941_vadc>;
+ #thermal-sensor-cells = <0>;
+ };
+ };
+};
+
+Below is an example thermal zone definition for the temperature alarm
+peripheral.
+thermal-zones {
+ pm8941_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&pm8941_tz>;
+
+ trips {
+ pm8941-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8941-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8941-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
};
};
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
index 967e71f..78a26c2 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
@@ -26,4 +26,5 @@
&blsp1_uart2 {
pinctrl-names = "default";
pinctrl-0 = <&uart2_console_active>;
+ status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 0afa5a8..0078617 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -153,5 +153,8 @@
reg = <0x831000 0x200>;
interrupts = <0 26 0>;
status = "disabled";
+ clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>,
+ <&clock_gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
};
};
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index c32324f..ff2cc3e 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -11,7 +11,8 @@
sdm845-v2-cdp.dtb \
sdm845-qrd.dtb \
sdm845-4k-panel-mtp.dtb \
- sdm845-4k-panel-cdp.dtb
+ sdm845-4k-panel-cdp.dtb \
+ sdm845-4k-panel-qrd.dtb
dtb-$(CONFIG_ARCH_SDM830) += sdm830-sim.dtb \
sdm830-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 f1501fa..16d2474 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -61,7 +61,7 @@
reg = <0x15000000 0x80000>,
<0x150c2000 0x20>;
reg-names = "base", "tcu-base";
- #iommu-cells = <1>;
+ #iommu-cells = <2>;
qcom,skip-init;
#global-interrupts = <1>;
#size-cells = <1>;
@@ -339,6 +339,6 @@
* This SID belongs to PCIE. We can't use a fake SID for
* the apps_smmu device.
*/
- iommus = <&apps_smmu 0x1c03>;
+ iommus = <&apps_smmu 0x1c03 0>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
index 4036ce5..655f447 100644
--- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -362,7 +362,7 @@
compatible = "qcom,msm-audio-ion";
qcom,smmu-version = <2>;
qcom,smmu-enabled;
- iommus = <&apps_smmu 0x1821>;
+ iommus = <&apps_smmu 0x1821 0x0>;
};
qcom,msm-adsp-loader {
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index 15db8da..b119305 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -62,11 +62,12 @@
};
};
- qcom,temp-alarm@2400 {
+ pm8998_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
label = "pm8998_tz";
+ #thermal-sensor-cells = <0>;
};
pm8998_gpios: pinctrl@c000 {
@@ -197,3 +198,30 @@
#size-cells = <0>;
};
};
+
+&thermal_zones {
+ pm8998_temp_alarm: pm8998_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&pm8998_tz>;
+
+ trips {
+ pm8998_trip0: pm8998-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8998_trip1: pm8998-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8998_trip2: pm8998-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 923804f..b53f7ac 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -31,11 +31,12 @@
reg = <0x800 0x100>;
};
- qcom,temp-alarm@2400 {
+ pmi8998_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
label = "pmi8998_tz";
+ #thermal-sensor-cells = <0>;
};
pmi8998_gpios: pinctrl@c000 {
@@ -796,4 +797,28 @@
};
};
};
+
+ pmi8998_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmi8998_tz>;
+
+ trips {
+ pmi8998_trip0: pmi8998-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pmi8998_trip1: pmi8998-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pmi8998_trip2: pmi8998-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
new file mode 100644
index 0000000..6171c7b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
@@ -0,0 +1,23 @@
+/* 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.dtsi"
+#include "sdm845-qrd.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel QRD";
+ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+ qcom,board-id = <11 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
index 9d59a16..69dfe46 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
@@ -17,7 +17,7 @@
#include <dt-bindings/clock/qcom,audio-ext-clk.h>
&msm_audio_ion {
- iommus = <&apps_smmu 0x1821>;
+ iommus = <&apps_smmu 0x1821 0x0>;
qcom,smmu-sid-mask = /bits/ 64 <0xf>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
index c0189a4..922e990 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
@@ -118,10 +118,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_rear_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk0_active
@@ -157,10 +159,12 @@
cam_vdig-supply = <&camera_ldo>;
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
- qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
- qcom,cam-vreg-op-mode = <105000 0 80000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+ qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk2_active
@@ -193,10 +197,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk1_active
@@ -240,10 +246,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_rear_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk0_active
@@ -280,10 +288,12 @@
cam_vdig-supply = <&camera_ldo>;
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
- qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
- qcom,cam-vreg-op-mode = <105000 0 80000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+ qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk2_active
@@ -322,10 +332,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk1_active
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
index c0189a4..922e990 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -118,10 +118,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_rear_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk0_active
@@ -157,10 +159,12 @@
cam_vdig-supply = <&camera_ldo>;
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
- qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
- qcom,cam-vreg-op-mode = <105000 0 80000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+ qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk2_active
@@ -193,10 +197,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk1_active
@@ -240,10 +246,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_rear_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk0_active
@@ -280,10 +288,12 @@
cam_vdig-supply = <&camera_ldo>;
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
- qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
- qcom,cam-vreg-op-mode = <105000 0 80000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+ qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk2_active
@@ -322,10 +332,12 @@
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
cam_vdig-supply = <&camera_ldo>;
- qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
- qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
- qcom,cam-vreg-op-mode = <0 80000 105000>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+ qcom,cam-vreg-op-mode = <0 80000 105000 0>;
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk1_active
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index cd9c8a8..3b9c26f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -71,7 +71,7 @@
<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
<&clock_camcc CAM_CC_CSIPHY1_CLK>,
<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>,
- <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>,
+ <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>,
<&clock_camcc CAM_CC_IFE_1_CSID_CLK>,
<&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>;
clock-names = "camnoc_axi_clk",
@@ -225,4 +225,108 @@
status = "ok";
};
};
+
+ qcom,cam_smmu {
+ compatible = "qcom,msm-cam-smmu";
+ status = "ok";
+
+ msm_cam_smmu_ife {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x808>,
+ <&apps_smmu 0x810>,
+ <&apps_smmu 0x818>,
+ <&apps_smmu 0xc08>,
+ <&apps_smmu 0xc10>,
+ <&apps_smmu 0xc18>;
+ label = "ife";
+ ife_iova_mem_map: iova-mem-map {
+ /* IO region is approximately 3.4 GB */
+ iova-mem-region-io {
+ iova-region-name = "io";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0xd8c00000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+
+ msm_cam_icp_fw {
+ compatible = "qcom,msm-cam-smmu-fw-dev";
+ label="icp";
+ memory-region = <&pil_camera_mem>;
+ };
+
+ msm_cam_smmu_icp {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1078>,
+ <&apps_smmu 0x1020>,
+ <&apps_smmu 0x1028>,
+ <&apps_smmu 0x1040>,
+ <&apps_smmu 0x1048>,
+ <&apps_smmu 0x1030>,
+ <&apps_smmu 0x1050>;
+ label = "icp";
+ icp_iova_mem_map: iova-mem-map {
+ iova-mem-region-firmware {
+ /* Firmware region is 5MB */
+ iova-region-name = "firmware";
+ iova-region-start = <0x0>;
+ iova-region-len = <0x500000>;
+ iova-region-id = <0x0>;
+ status = "ok";
+ };
+
+ iova-mem-region-shared {
+ /* Shared region is 100MB long */
+ iova-region-name = "shared";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0x6400000>;
+ iova-region-id = <0x1>;
+ status = "ok";
+ };
+
+ iova-mem-region-io {
+ /* IO region is approximately 3.3 GB */
+ iova-region-name = "io";
+ iova-region-start = <0xd800000>;
+ iova-region-len = <0xd2800000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+
+ msm_cam_smmu_cpas_cdm {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1000>;
+ label = "cpas-cdm0";
+ cpas_cdm_iova_mem_map: iova-mem-map {
+ iova-mem-region-io {
+ /* IO region is approximately 3.4 GB */
+ iova-region-name = "io";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0xd8c00000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+
+ msm_cam_smmu_secure {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1001>;
+ label = "cam-secure";
+ cam_secure_iova_mem_map: iova-mem-map {
+ /* Secure IO region is approximately 3.4 GB */
+ iova-mem-region-io {
+ iova-region-name = "io";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0xd8c00000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 68824d7..6f40fae 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -93,6 +93,10 @@
};
};
+&mdss_mdp {
+ #cooling-cells = <2>;
+};
+
&ufsphy_mem {
compatible = "qcom,ufs-phy-qmp-v3";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index 434de76..91946d7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -380,6 +380,32 @@
};
+ hwevent: hwevent@0x014066f0 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0x14066f0 0x4>,
+ <0x14166f0 0x4>,
+ <0x1406038 0x4>,
+ <0x1416038 0x4>;
+ reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl",
+ "ddr-ch23-ctrl";
+
+ coresight-name = "coresight-hwevent";
+
+ clocks = <&clock_gcc RPMH_QDSS_CLK>,
+ <&clock_gcc RPMH_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ csr: csr@6001000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0x6001000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-name = "coresight-csr";
+
+ qcom,blk-size = <1>;
+ };
+
funnel_in0: funnel@0x6041000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
@@ -504,6 +530,7 @@
<2 32>,
<3 32>,
<5 32>,
+ <6 32>,
<10 32>,
<11 32>,
<13 32>;
@@ -563,6 +590,15 @@
};
port@5 {
+ reg = <6>;
+ tpda_in_funnel_turing: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_turing_out_tpda>;
+ };
+ };
+
+ port@6 {
reg = <7>;
tpda_in_tpdm_vsense: endpoint {
slave-mode;
@@ -571,7 +607,7 @@
};
};
- port@6 {
+ port@7 {
reg = <10>;
tpda_in_tpdm_qm: endpoint {
slave-mode;
@@ -580,7 +616,7 @@
};
};
- port@7 {
+ port@8 {
reg = <11>;
tpda_in_tpdm_north: endpoint {
slave-mode;
@@ -589,7 +625,7 @@
};
};
- port@8 {
+ port@9 {
reg = <13>;
tpda_in_tpdm_pimem: endpoint {
slave-mode;
@@ -1013,6 +1049,68 @@
};
};
+ funnel_turing: funnel@6861000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6861000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-turing";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_turing_out_tpda: endpoint {
+ remote-endpoint =
+ <&tpda_in_funnel_turing>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_turing_in_tpdm_turing: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_turing_out_funnel_turing>;
+ };
+ };
+
+ port@2 {
+ reg = <1>;
+ funnel_turing_in_turing_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&turing_etm0_out_funnel_turing>;
+ };
+ };
+ };
+ };
+
+ tpdm_turing: tpdm@6860000 {
+ compatible = "qcom,coresight-tpdm";
+ reg = <0x6860000 0x1000>;
+ reg-names = "tpdm-base";
+
+ coresight-name = "coresight-tpdm-turing";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
+ port {
+ tpdm_turing_out_funnel_turing: endpoint {
+ remote-endpoint =
+ <&funnel_turing_in_tpdm_turing>;
+ };
+ };
+ };
+
funnel_ddr_0: funnel@69e2000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
@@ -1279,6 +1377,30 @@
};
};
+ cti_ddr0: cti@69e1000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
+ reg = <0x69e1000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-ddr0";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_ddr1: cti@69e4000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
+ reg = <0x69e4000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-ddr1";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
cti0: cti@6010000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b966>;
@@ -1315,6 +1437,10 @@
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
+
+ qcom,cti-gpio-trigout = <4>;
+ pinctrl-names = "cti-trigout-pctrl";
+ pinctrl-0 = <&trigout_a>;
};
cti3: cti@6013000 {
@@ -1591,6 +1717,20 @@
clock-names = "apb_pclk";
};
+ turing_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+
+ coresight-name = "coresight-turing-etm0";
+ qcom,inst-id = <1>;
+
+ port{
+ turing_etm0_out_funnel_turing: endpoint {
+ remote-endpoint =
+ <&funnel_turing_in_turing_etm0>;
+ };
+ };
+ };
+
dummy_eud: dummy_sink {
compatible = "qcom,coresight-dummy";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index bfbaabb..0ada391 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -77,13 +77,16 @@
#cooling-cells = <2>;
clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
- <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
<&clock_gpucc GPU_CC_CXO_CLK>,
<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
- <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+ <&clock_gpucc GPU_CC_CX_GMU_CLK>,
+ <&clock_gpucc GPU_CC_AHB_CLK>,
+ <&clock_gpucc GPU_CC_GX_CXO_CLK>;
- clock-names = "core_clk", "iface_clk", "rbbmtimer_clk",
- "mem_clk", "mem_iface_clk";
+ clock-names = "core_clk", "rbbmtimer_clk", "mem_clk",
+ "mem_iface_clk", "gmu_clk", "ahb_clk",
+ "cxo_clk";
qcom,isense-clk-on-level = <1>;
@@ -248,13 +251,13 @@
clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>,
- <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
<&clock_gpucc GPU_CC_CXO_CLK>,
<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
- <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+ <&clock_gpucc GPU_CC_AHB_CLK>;
- clock-names = "gmu_clk", "ahb_clk", "cxo_clk",
- "axi_clk", "memnoc_clk";
+ clock-names = "gmu_clk", "cxo_clk", "axi_clk",
+ "memnoc_clk", "ahb_clk";
qcom,gmu-pwrlevels {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 4391189..803843c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -102,6 +102,10 @@
qcom,led-strings-list = [01 02];
};
+&mdss_mdp {
+ #cooling-cells = <2>;
+};
+
&ufsphy_mem {
compatible = "qcom,ufs-phy-qmp-v3";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index d6af58b..bc535d1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2558,6 +2558,18 @@
drive-strength = <2>; /* 2 MA */
};
};
+
+ trigout_a: trigout_a {
+ mux {
+ pins = "gpio62", "gpio51";
+ function = "qdss_cti";
+ };
+ config {
+ pins = "gpio62", "gpio51";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 1d5bf3a..a4dc4753 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -22,6 +22,10 @@
qcom,battery-data = <&qrd_batterydata>;
};
+&mdss_mdp {
+ #cooling-cells = <2>;
+};
+
&soc {
sound-tavil {
qcom,wsa-max-devs = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 6989f326..f6c1d76 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -74,11 +74,12 @@
qcom,cpr-step-quot-init-min = <11>;
qcom,cpr-step-quot-init-max = <12>;
qcom,cpr-count-mode = <0>; /* All at once */
- qcom,cpr-count-repeat = <1>;
+ qcom,cpr-count-repeat = <20>;
qcom,cpr-down-error-step-limit = <1>;
qcom,cpr-up-error-step-limit = <1>;
qcom,cpr-corner-switch-delay-time = <1042>;
qcom,cpr-voltage-settling-time = <1760>;
+ qcom,cpr-reset-step-quot-loop-en;
qcom,voltage-step = <4000>;
qcom,voltage-base = <352000>;
@@ -103,7 +104,7 @@
thread@1 {
qcom,cpr-thread-id = <1>;
qcom,cpr-consecutive-up = <0>;
- qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-consecutive-down = <0>;
qcom,cpr-up-threshold = <2>;
qcom,cpr-down-threshold = <2>;
@@ -180,7 +181,7 @@
thread@0 {
qcom,cpr-thread-id = <0>;
qcom,cpr-consecutive-up = <0>;
- qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-consecutive-down = <0>;
qcom,cpr-up-threshold = <2>;
qcom,cpr-down-threshold = <2>;
@@ -264,11 +265,12 @@
qcom,cpr-step-quot-init-min = <9>;
qcom,cpr-step-quot-init-max = <14>;
qcom,cpr-count-mode = <0>; /* All at once */
- qcom,cpr-count-repeat = <1>;
+ qcom,cpr-count-repeat = <20>;
qcom,cpr-down-error-step-limit = <1>;
qcom,cpr-up-error-step-limit = <1>;
qcom,cpr-corner-switch-delay-time = <1042>;
qcom,cpr-voltage-settling-time = <1760>;
+ qcom,cpr-reset-step-quot-loop-en;
qcom,apm-threshold-voltage = <800000>;
qcom,apm-crossover-voltage = <880000>;
@@ -296,7 +298,7 @@
thread@0 {
qcom,cpr-thread-id = <0>;
qcom,cpr-consecutive-up = <0>;
- qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-consecutive-down = <0>;
qcom,cpr-up-threshold = <2>;
qcom,cpr-down-threshold = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index e56073c..efd8f45 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -107,8 +107,8 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
clock-names = "src_byte_clk", "src_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
@@ -116,6 +116,7 @@
pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>;
vddio-supply = <&pm8998_l14>;
@@ -130,8 +131,8 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
clock-names = "src_byte_clk", "src_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
@@ -139,6 +140,7 @@
pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>;
vddio-supply = <&pm8998_l14>;
@@ -153,8 +155,8 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
clock-names = "src_byte_clk", "src_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
@@ -162,6 +164,7 @@
pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_sharp_1080_cmd>;
vddio-supply = <&pm8998_l14>;
@@ -176,8 +179,8 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
clock-names = "src_byte_clk", "src_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
@@ -185,6 +188,7 @@
pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>;
vddio-supply = <&pm8998_l14>;
@@ -222,8 +226,8 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
clock-names = "src_byte_clk", "src_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
@@ -231,6 +235,7 @@
pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>;
vddio-supply = <&pm8998_l14>;
@@ -245,8 +250,8 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
clock-names = "src_byte_clk", "src_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
@@ -254,6 +259,7 @@
pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>;
vddio-supply = <&pm8998_l14>;
@@ -268,8 +274,8 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
clock-names = "src_byte_clk", "src_pixel_clk";
pinctrl-names = "panel_active", "panel_suspend";
@@ -277,6 +283,7 @@
pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>;
vddio-supply = <&pm8998_l14>;
@@ -296,43 +303,43 @@
};
&dsi_dual_nt35597_truly_video {
- qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
};
&dsi_dual_nt35597_truly_cmd {
- qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
};
&dsi_nt35597_truly_dsc_cmd {
- qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 05 03 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0b>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
};
&dsi_nt35597_truly_dsc_video {
- qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 05 03 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0b>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
};
&dsi_sharp_4k_dsc_video {
- qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
- qcom,mdss-dsi-t-clk-post = <0x0a>;
- qcom,mdss-dsi-t-clk-pre = <0x1e>;
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 06 04 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x0c>;
+ qcom,mdss-dsi-t-clk-pre = <0x27>;
};
&dsi_sharp_4k_dsc_cmd {
- qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
- qcom,mdss-dsi-t-clk-post = <0x0a>;
- qcom,mdss-dsi-t-clk-pre = <0x1e>;
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 06 04 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x0c>;
+ qcom,mdss-dsi-t-clk-pre = <0x27>;
};
&dsi_dual_sharp_1080_120hz_cmd {
- qcom,mdss-dsi-panel-timings = [00 24 09 09 26 24 09 09 06 03 04];
+ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 09 06 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0f>;
qcom,mdss-dsi-t-clk-pre = <0x36>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index cb5d924..7812a48 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -37,8 +37,8 @@
interrupts = <0 83 0>;
interrupt-controller;
#interrupt-cells = <1>;
- iommus = <&apps_smmu 0x880>, <&apps_smmu 0x888>,
- <&apps_smmu 0xc80>, <&apps_smmu 0xc88>;
+ iommus = <&apps_smmu 0x880 0x0>, <&apps_smmu 0x888 0x0>,
+ <&apps_smmu 0xc80 0x0>, <&apps_smmu 0xc88 0x0>;
#address-cells = <1>;
#size-cells = <0>;
@@ -97,8 +97,6 @@
1 5 9 13>;
qcom,sde-sspp-excl-rect = <1 1 1 1
1 1 1 1>;
- qcom,sde-sspp-smart-dma-priority = <5 6 7 8 1 2 3 4>;
- qcom,sde-smart-dma-rev = "smart_dma_v2";
qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>;
@@ -118,6 +116,9 @@
qcom,sde-wb-linewidth = <4096>;
qcom,sde-mixer-blendstages = <0xb>;
qcom,sde-highest-bank-bit = <0x2>;
+ qcom,sde-ubwc-version = <0x200>;
+ qcom,sde-ubwc-static = <0x100>;
+ qcom,sde-ubwc-swizzle = <1>;
qcom,sde-panic-per-pipe;
qcom,sde-has-cdp;
qcom,sde-has-src-split;
@@ -238,12 +239,10 @@
<&clock_gcc GCC_DISP_AHB_CLK>,
<&clock_gcc GCC_DISP_AXI_CLK>,
<&clock_dispcc DISP_CC_MDSS_AHB_CLK>,
- <&clock_dispcc DISP_CC_MDSS_ROT_CLK_SRC>,
<&clock_dispcc DISP_CC_MDSS_ROT_CLK>,
<&clock_dispcc DISP_CC_MDSS_AXI_CLK>;
clock-names = "gcc_iface", "gcc_bus",
- "iface_clk", "rot_core_clk",
- "rot_clk", "axi_clk";
+ "iface_clk", "rot_clk", "axi_clk";
interrupt-parent = <&mdss_mdp>;
interrupts = <2 0>;
@@ -260,14 +259,14 @@
smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
compatible = "qcom,smmu_sde_rot_unsec";
- iommus = <&apps_smmu 0x1090>;
+ iommus = <&apps_smmu 0x1090 0x0>;
gdsc-mdss-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>;
};
smmu_rot_sec: qcom,smmu_rot_sec_cb {
status = "disabled";
compatible = "qcom,smmu_sde_rot_sec";
- iommus = <&apps_smmu 0x1091>;
+ iommus = <&apps_smmu 0x1091 0x0>;
gdsc-mdss-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index c80343a..aac63ee 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -303,6 +303,13 @@
qcom,reset-ep-after-lpm-resume;
};
+ usb_audio_qmi_dev {
+ compatible = "qcom,usb-audio-qmi-dev";
+ iommus = <&apps_smmu 0x182c>;
+ qcom,usb-audio-stream-id = <0xc>;
+ qcom,usb-audio-intr-num = <2>;
+ };
+
usb_nop_phy: usb_nop_phy {
compatible = "usb-nop-xceiv";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 4fdf383..efd8c32 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -16,3 +16,7 @@
model = "Qualcomm Technologies, Inc. SDM845 V2";
qcom,msm-id = <321 0x20000>;
};
+
+&spmi_debug_bus {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index b9dc816..6f4b4ca 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -97,9 +97,9 @@
compatible = "qcom,msm-vidc,context-bank";
label = "venus_ns";
iommus =
- <&apps_smmu 0x10a0>,
- <&apps_smmu 0x10a8>,
- <&apps_smmu 0x10b0>;
+ <&apps_smmu 0x10a0 0x0>,
+ <&apps_smmu 0x10a8 0x0>,
+ <&apps_smmu 0x10b0 0x0>;
buffer-types = <0xfff>;
virtual-addr-pool = <0x70800000 0x6f800000>;
};
@@ -108,10 +108,10 @@
compatible = "qcom,msm-vidc,context-bank";
label = "venus_sec_bitstream";
iommus =
- <&apps_smmu 0x10a1>,
- <&apps_smmu 0x10a9>,
- <&apps_smmu 0x10a5>,
- <&apps_smmu 0x10ad>;
+ <&apps_smmu 0x10a1 0x0>,
+ <&apps_smmu 0x10a9 0x0>,
+ <&apps_smmu 0x10a5 0x0>,
+ <&apps_smmu 0x10ad 0x0>;
buffer-types = <0x241>;
virtual-addr-pool = <0x4b000000 0x25800000>;
qcom,secure-context-bank;
@@ -121,8 +121,8 @@
compatible = "qcom,msm-vidc,context-bank";
label = "venus_sec_pixel";
iommus =
- <&apps_smmu 0x10a3>,
- <&apps_smmu 0x10ab>;
+ <&apps_smmu 0x10a3 0x0>,
+ <&apps_smmu 0x10ab 0x0>;
buffer-types = <0x106>;
virtual-addr-pool = <0x25800000 0x25800000>;
qcom,secure-context-bank;
@@ -132,9 +132,9 @@
compatible = "qcom,msm-vidc,context-bank";
label = "venus_sec_non_pixel";
iommus =
- <&apps_smmu 0x10a4>,
- <&apps_smmu 0x10ac>,
- <&apps_smmu 0x10b4>;
+ <&apps_smmu 0x10a4 0x0>,
+ <&apps_smmu 0x10ac 0x0>,
+ <&apps_smmu 0x10b4 0x0>;
buffer-types = <0x480>;
virtual-addr-pool = <0x1000000 0x24800000>;
qcom,secure-context-bank;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 54e0162..5660841 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -553,6 +553,7 @@
qcom,fuse-disable-bit = <12>;
#address-cells = <2>;
#size-cells = <0>;
+ status = "disabled";
qcom,pm8998-debug@0 {
compatible = "qcom,spmi-pmic";
@@ -1020,6 +1021,29 @@
mbox-names = "qdss_clk";
};
+ ufs_ice: ufsice@1d90000 {
+ compatible = "qcom,ice";
+ reg = <0x1d90000 0x8000>;
+ qcom,enable-ice-clk;
+ clock-names = "ufs_core_clk", "bus_clk",
+ "iface_clk", "ice_core_clk";
+ clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>,
+ <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>,
+ <&clock_gcc GCC_UFS_PHY_AHB_CLK>,
+ <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>;
+ qcom,op-freq-hz = <0>, <0>, <0>, <300000000>;
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ qcom,msm-bus,name = "ufs_ice_noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 650 0 0>, /* No vote */
+ <1 650 1000 0>; /* Max. bandwidth */
+ qcom,bus-vector-names = "MIN",
+ "MAX";
+ qcom,instance-type = "ufs";
+ };
+
ufsphy_mem: ufsphy_mem@1d87000 {
reg = <0x1d87000 0xda8>; /* PHY regs */
reg-names = "phy_mem";
@@ -1043,6 +1067,7 @@
interrupts = <0 265 0>;
phys = <&ufsphy_mem>;
phy-names = "ufsphy";
+ ufs-qcom-crypto = <&ufs_ice>;
lanes-per-direction = <2>;
dev-ref-clk-freq = <0>; /* 19.2 MHz */
@@ -1289,9 +1314,12 @@
<0x1f65000 0x008>,
<0x1f64000 0x008>,
<0x4180000 0x020>,
- <0xc2b0000 0x004>;
+ <0xc2b0000 0x004>,
+ <0xb2e0100 0x004>,
+ <0x4180044 0x004>;
reg-names = "qdsp6_base", "halt_q6", "halt_modem",
- "halt_nc", "rmb_base", "restart_reg";
+ "halt_nc", "rmb_base", "restart_reg",
+ "pdc_sync", "alt_reset";
clocks = <&clock_rpmh RPMH_CXO_CLK>,
<&clock_gcc GCC_MSS_CFG_AHB_CLK>,
@@ -1536,76 +1564,76 @@
qcom,msm_fastrpc_compute_cb1 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1401>,
- <&apps_smmu 0x1421>;
+ iommus = <&apps_smmu 0x1401 0x0>,
+ <&apps_smmu 0x1421 0x0>;
};
qcom,msm_fastrpc_compute_cb2 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1402>,
- <&apps_smmu 0x1422>;
+ iommus = <&apps_smmu 0x1402 0x0>,
+ <&apps_smmu 0x1422 0x0>;
};
qcom,msm_fastrpc_compute_cb3 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1403>,
- <&apps_smmu 0x1423>;
+ iommus = <&apps_smmu 0x1403 0x0>,
+ <&apps_smmu 0x1423 0x0>;
};
qcom,msm_fastrpc_compute_cb4 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1404>,
- <&apps_smmu 0x1424>;
+ iommus = <&apps_smmu 0x1404 0x0>,
+ <&apps_smmu 0x1424 0x0>;
};
qcom,msm_fastrpc_compute_cb5 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1405>,
- <&apps_smmu 0x1425>;
+ iommus = <&apps_smmu 0x1405 0x0>,
+ <&apps_smmu 0x1425 0x0>;
};
qcom,msm_fastrpc_compute_cb6 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1406>,
- <&apps_smmu 0x1426>;
+ iommus = <&apps_smmu 0x1406 0x0>,
+ <&apps_smmu 0x1426 0x0>;
};
qcom,msm_fastrpc_compute_cb7 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1407>,
- <&apps_smmu 0x1427>;
+ iommus = <&apps_smmu 0x1407 0x0>,
+ <&apps_smmu 0x1427 0x0>;
};
qcom,msm_fastrpc_compute_cb8 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
- iommus = <&apps_smmu 0x1408>,
- <&apps_smmu 0x1428>;
+ iommus = <&apps_smmu 0x1408 0x0>,
+ <&apps_smmu 0x1428 0x0>;
};
qcom,msm_fastrpc_compute_cb9 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
qcom,secure-context-bank;
- iommus = <&apps_smmu 0x1409>,
- <&apps_smmu 0x1419>,
- <&apps_smmu 0x1429>;
+ iommus = <&apps_smmu 0x1409 0x0>,
+ <&apps_smmu 0x1419 0x0>,
+ <&apps_smmu 0x1429 0x0>;
};
qcom,msm_fastrpc_compute_cb10 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
qcom,secure-context-bank;
- iommus = <&apps_smmu 0x140A>,
- <&apps_smmu 0x141A>,
- <&apps_smmu 0x142A>;
+ iommus = <&apps_smmu 0x140A 0x0>,
+ <&apps_smmu 0x141A 0x0>,
+ <&apps_smmu 0x142A 0x0>;
};
qcom,msm_fastrpc_compute_cb11 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "adsprpc-smd";
- iommus = <&apps_smmu 0x1823>;
+ iommus = <&apps_smmu 0x1823 0x0>;
};
qcom,msm_fastrpc_compute_cb12 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "adsprpc-smd";
- iommus = <&apps_smmu 0x1824>;
+ iommus = <&apps_smmu 0x1824 0x0>;
};
};
@@ -2147,6 +2175,65 @@
hyplog-size-offset = <0x414>;
};
+ qcom_cedev: qcedev@1de0000 {
+ compatible = "qcom,qcedev";
+ reg = <0x1de0000 0x20000>,
+ <0x1dc4000 0x24000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 272 0>;
+ qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,bam-ee = <0>;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <125 512 0 0>,
+ <125 512 393600 393600>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ clocks = <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_AHB_CLK>,
+ <&clock_gcc GCC_CE1_AXI_CLK>;
+ qcom,ce-opp-freq = <171430000>;
+ };
+
+ qcom_crypto: qcrypto@1de0000 {
+ compatible = "qcom,qcrypto";
+ reg = <0x1de0000 0x20000>,
+ <0x1dc4000 0x24000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 272 0>;
+ qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,bam-ee = <0>;
+ qcom,ce-hw-shared;
+ qcom,clk-mgmt-sus-res;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <125 512 0 0>,
+ <125 512 393600 393600>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ clocks = <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_AHB_CLK>,
+ <&clock_gcc GCC_CE1_AXI_CLK>;
+ qcom,ce-opp-freq = <171430000>;
+ qcom,use-sw-aes-cbc-ecb-ctr-algo;
+ qcom,use-sw-aes-xts-algo;
+ qcom,use-sw-aes-ccm-algo;
+ qcom,use-sw-ahash-algo;
+ qcom,use-sw-aead-algo;
+ qcom,use-sw-hmac-algo;
+ };
+
qcom,msm_gsi {
compatible = "qcom,msm_gsi";
};
@@ -2300,18 +2387,18 @@
ipa_smmu_ap: ipa_smmu_ap {
compatible = "qcom,ipa-smmu-ap-cb";
- iommus = <&apps_smmu 0x720>;
+ iommus = <&apps_smmu 0x720 0x0>;
qcom,iova-mapping = <0x20000000 0x40000000>;
};
ipa_smmu_wlan: ipa_smmu_wlan {
compatible = "qcom,ipa-smmu-wlan-cb";
- iommus = <&apps_smmu 0x721>;
+ iommus = <&apps_smmu 0x721 0x0>;
};
ipa_smmu_uc: ipa_smmu_uc {
compatible = "qcom,ipa-smmu-uc-cb";
- iommus = <&apps_smmu 0x722>;
+ iommus = <&apps_smmu 0x722 0x0>;
qcom,iova-mapping = <0x40000000 0x20000000>;
};
};
@@ -2355,7 +2442,7 @@
cmd_db: qcom,cmd-db@861e0000 {
compatible = "qcom,cmd-db";
- reg = <0x861e0000 0x4000>;
+ reg = <0xc3f000c 8>;
};
dcc: dcc_v2@10a2000 {
@@ -2378,8 +2465,8 @@
<0xa0000000 0x10000000>,
<0xb0000000 0x10000>;
reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
- iommus = <&apps_smmu 0x0040>,
- <&apps_smmu 0x0041>;
+ iommus = <&apps_smmu 0x0040 0x0>,
+ <&apps_smmu 0x0041 0x0>;
interrupts = <0 414 0 /* CE0 */ >,
<0 415 0 /* CE1 */ >,
<0 416 0 /* CE2 */ >,
@@ -3555,3 +3642,44 @@
#include "sdm845-audio.dtsi"
#include "sdm845-gpu.dtsi"
#include "sdm845-usb.dtsi"
+
+&pm8998_temp_alarm {
+ cooling-maps {
+ trip0_cpu0 {
+ trip = <&pm8998_trip0>;
+ cooling-device = <&CPU0 21 21>;
+ };
+ trip0_cpu4 {
+ trip = <&pm8998_trip0>;
+ cooling-device = <&CPU4 21 21>;
+ };
+ trip1_cpu1 {
+ trip = <&pm8998_trip1>;
+ cooling-device = <&CPU1 22 22>;
+ };
+ trip1_cpu2 {
+ trip = <&pm8998_trip1>;
+ cooling-device = <&CPU2 22 22>;
+ };
+ trip1_cpu3 {
+ trip = <&pm8998_trip1>;
+ cooling-device = <&CPU3 22 22>;
+ };
+ trip1_cpu4 {
+ trip = <&pm8998_trip1>;
+ cooling-device = <&CPU4 22 22>;
+ };
+ trip1_cpu5 {
+ trip = <&pm8998_trip1>;
+ cooling-device = <&CPU5 22 22>;
+ };
+ trip1_cpu6 {
+ trip = <&pm8998_trip1>;
+ cooling-device = <&CPU6 22 22>;
+ };
+ trip1_cpu7 {
+ trip = <&pm8998_trip1>;
+ cooling-device = <&CPU7 22 22>;
+ };
+ };
+};
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index fa6bae8..7f00787 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -336,6 +336,7 @@
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_QCOM_KGSL=y
CONFIG_DRM=y
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
CONFIG_DRM_SDE_RSC=y
@@ -445,6 +446,8 @@
CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_QCOM_LLCC=y
CONFIG_QCOM_SDM845_LLCC=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
@@ -473,10 +476,12 @@
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_ICNSS=y
CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_AVTIMER=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_APSS_CORE_EA=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index a71aa64..4fdbffa 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -462,6 +462,8 @@
CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_QCOM_LLCC=y
CONFIG_QCOM_SDM845_LLCC=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_CORE_HANG_DETECT=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
@@ -493,11 +495,13 @@
CONFIG_ICNSS=y
CONFIG_ICNSS_DEBUG=y
CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_AVTIMER=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_APSS_CORE_EA=y
CONFIG_QCOM_DCC_V2=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
@@ -596,6 +600,7 @@
CONFIG_CORESIGHT_TPDA=y
CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a95e1e5..f18ae62 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -229,20 +229,22 @@
static int fw_lookup_and_allocate_buf(const char *fw_name,
struct firmware_cache *fwc,
struct firmware_buf **buf, void *dbuf,
- size_t size)
+ size_t size, unsigned int opt_flags)
{
struct firmware_buf *tmp;
spin_lock(&fwc->lock);
- tmp = __fw_lookup_buf(fw_name);
- if (tmp) {
- kref_get(&tmp->ref);
- spin_unlock(&fwc->lock);
- *buf = tmp;
- return 1;
+ if (!(opt_flags & FW_OPT_NOCACHE)) {
+ tmp = __fw_lookup_buf(fw_name);
+ if (tmp) {
+ kref_get(&tmp->ref);
+ spin_unlock(&fwc->lock);
+ *buf = tmp;
+ return 1;
+ }
}
tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size);
- if (tmp)
+ if (tmp && !(opt_flags & FW_OPT_NOCACHE))
list_add(&tmp->list, &fwc->head);
spin_unlock(&fwc->lock);
@@ -1051,7 +1053,8 @@
*/
static int
_request_firmware_prepare(struct firmware **firmware_p, const char *name,
- struct device *device, void *dbuf, size_t size)
+ struct device *device, void *dbuf, size_t size,
+ unsigned int opt_flags)
{
struct firmware *firmware;
struct firmware_buf *buf;
@@ -1069,7 +1072,8 @@
return 0; /* assigned */
}
- ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size);
+ ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size,
+ opt_flags);
/*
* bind with 'buf' now to avoid warning in failure path
@@ -1147,7 +1151,8 @@
goto out;
}
- ret = _request_firmware_prepare(&fw, name, device, buf, size);
+ ret = _request_firmware_prepare(&fw, name, device, buf, size,
+ opt_flags);
if (ret <= 0) /* error or already assigned */
goto out;
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index b248b1b..1b545d6 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1709,8 +1709,14 @@
}
}
+ /*
+ * The Fabia PLLs only have 16 bits to program the fractional divider.
+ * Hence the programmed rate might be slightly different than the
+ * requested one.
+ */
if ((core->flags & CLK_SET_RATE_PARENT) && parent &&
- best_parent_rate != parent->rate)
+ (DIV_ROUND_CLOSEST(best_parent_rate, 1000) !=
+ DIV_ROUND_CLOSEST(parent->rate, 1000)))
top = clk_calc_new_rates(parent, best_parent_rate);
out:
@@ -2345,6 +2351,56 @@
NULL,
};
+static void clk_state_subtree(struct clk_core *c)
+{
+ int vdd_level = 0;
+ struct clk_core *child;
+
+ if (!c)
+ return;
+
+ if (c->vdd_class) {
+ vdd_level = clk_find_vdd_level(c, c->rate);
+ if (vdd_level < 0)
+ vdd_level = 0;
+ }
+
+ trace_clk_state(c->name, c->prepare_count, c->enable_count,
+ c->rate, vdd_level);
+
+ hlist_for_each_entry(child, &c->children, child_node)
+ clk_state_subtree(child);
+}
+
+static int clk_state_show(struct seq_file *s, void *data)
+{
+ struct clk_core *c;
+ struct hlist_head **lists = (struct hlist_head **)s->private;
+
+ clk_prepare_lock();
+
+ for (; *lists; lists++)
+ hlist_for_each_entry(c, *lists, child_node)
+ clk_state_subtree(c);
+
+ clk_prepare_unlock();
+
+ return 0;
+}
+
+
+static int clk_state_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_state_show, inode->i_private);
+}
+
+static const struct file_operations clk_state_fops = {
+ .open = clk_state_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
int level)
{
@@ -2980,6 +3036,11 @@
if (!d)
return -ENOMEM;
+ d = debugfs_create_file("trace_clocks", 0444, rootdir, &all_lists,
+ &clk_state_fops);
+ if (!d)
+ return -ENOMEM;
+
mutex_lock(&clk_debug_lock);
hlist_for_each_entry(core, &clk_debug_list, debug_node)
clk_debug_create_one(core, rootdir);
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 6ff621d..d15d1bb 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -307,6 +307,15 @@
u64 quotient;
int alpha_bw = ALPHA_BITWIDTH;
+ /*
+ * The PLLs parent rate is zero probably since the parent hasn't
+ * registered yet. Return early with the requested rate.
+ */
+ if (!prate) {
+ pr_debug("PLLs parent rate hasn't been initialized.\n");
+ return rate;
+ }
+
quotient = rate;
remainder = do_div(quotient, prate);
*l = quotient;
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 3daefbc..2cb9d05 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -23,9 +23,10 @@
#define VCO_DELAY_USEC 1
-#define MHZ_375 375000000UL
-#define MHZ_750 750000000UL
-#define MHZ_1500 1500000000UL
+#define MHZ_250 250000000UL
+#define MHZ_500 500000000UL
+#define MHZ_1000 1000000000UL
+#define MHZ_1100 1100000000UL
#define MHZ_1900 1900000000UL
#define MHZ_3000 3000000000UL
@@ -99,6 +100,7 @@
u32 frac_div_start_low;
u32 frac_div_start_mid;
u32 frac_div_start_high;
+ u32 pll_clock_inverters;
u32 ssc_stepsize_low;
u32 ssc_stepsize_high;
u32 ssc_div_per_low;
@@ -209,20 +211,36 @@
u64 dec, dec_multiple;
u32 frac;
u64 multiplier;
+ u32 i;
target_freq = rsc->vco_current_rate;
pr_debug("target_freq = %llu\n", target_freq);
if (config->div_override) {
computed_output_div = config->output_div;
+
+ /*
+ * Computed_output_div = 2 ^ div_log
+ * To get div_log from output div just get the index of the
+ * 1 bit in the value.
+ * div_log ranges from 0-3. so check the 4 lsbs
+ */
+
+ for (i = 0; i < 4; i++) {
+ if (computed_output_div & (1 << i)) {
+ div_log = i;
+ break;
+ }
+ }
+
} else {
- if (target_freq < MHZ_375) {
+ if (target_freq < MHZ_250) {
computed_output_div = 8;
div_log = 3;
- } else if (target_freq < MHZ_750) {
+ } else if (target_freq < MHZ_500) {
computed_output_div = 4;
div_log = 2;
- } else if (target_freq < MHZ_1500) {
+ } else if (target_freq < MHZ_1000) {
computed_output_div = 2;
div_log = 1;
} else {
@@ -251,6 +269,10 @@
regs->pll_prop_gain_rate = 10;
else
regs->pll_prop_gain_rate = 12;
+ if (pll_freq < MHZ_1100)
+ regs->pll_clock_inverters = 8;
+ else
+ regs->pll_clock_inverters = 0;
regs->pll_outdiv_rate = div_log;
regs->pll_lockdet_rate = config->lock_timer;
@@ -375,7 +397,7 @@
MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06);
MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10);
- MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters);
}
@@ -1085,7 +1107,7 @@
static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
.ref_clk_rate = 19200000UL,
- .min_rate = 1500000000UL,
+ .min_rate = 1000000000UL,
.max_rate = 3500000000UL,
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_vco_clk",
@@ -1098,7 +1120,7 @@
static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
.ref_clk_rate = 19200000UL,
- .min_rate = 1500000000UL,
+ .min_rate = 1000000000UL,
.max_rate = 3500000000UL,
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_vco_clk",
@@ -1219,7 +1241,7 @@
static struct clk_regmap_mux dsi0pll_byteclk_mux = {
.shift = 0,
- .width = 0,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0_phy_pll_out_byteclk",
@@ -1233,7 +1255,7 @@
static struct clk_regmap_mux dsi1pll_byteclk_mux = {
.shift = 0,
- .width = 0,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1_phy_pll_out_byteclk",
@@ -1247,7 +1269,7 @@
static struct clk_regmap_mux dsi0pll_pclk_src_mux = {
.shift = 0,
- .width = 0,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_pclk_src_mux",
@@ -1262,7 +1284,7 @@
static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
.shift = 0,
- .width = 0,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_pclk_src_mux",
@@ -1307,7 +1329,7 @@
static struct clk_regmap_mux dsi0pll_pclk_mux = {
.shift = 0,
- .width = 0,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0_phy_pll_out_dsiclk",
@@ -1321,7 +1343,7 @@
static struct clk_regmap_mux dsi1pll_pclk_mux = {
.shift = 0,
- .width = 0,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1_phy_pll_out_dsiclk",
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 550a59c..5db1897 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -441,15 +441,14 @@
{
u32 cntkctl = arch_timer_get_cntkctl();
- /* Disable user access to the timers and the physical counter */
+ /* Disable user access to the timers */
/* Also disable virtual event stream */
cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
| ARCH_TIMER_USR_VT_ACCESS_EN
- | ARCH_TIMER_VIRT_EVT_EN
- | ARCH_TIMER_USR_PCT_ACCESS_EN);
+ | ARCH_TIMER_VIRT_EVT_EN);
- /* Enable user access to the virtual counter */
- cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
+ /* Enable user access to the virtual and physical counters */
+ cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN | ARCH_TIMER_USR_PCT_ACCESS_EN;
arch_timer_set_cntkctl(cntkctl);
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index fd02eba..f61b78a 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -385,58 +385,6 @@
Select this to offload Samsung S5PV210 or S5PC110, Exynos from AES
algorithms execution.
-config CRYPTO_DEV_QCE50
- bool
-
-config FIPS_ENABLE
- bool "FIPS140-2 compliant build"
- default n
- help
- This flag is used to make current build FIPS140-2
- compliant. This flag will enable the patch of code
- which will perform this task. Please select Y here
- to enable.
-
-config CRYPTO_DEV_QCRYPTO
- tristate "QTI Crypto accelerator"
- select CRYPTO_DES
- select CRYPTO_ALGAPI
- select CRYPTO_AUTHENC
- select CRYPTO_BLKCIPHER
- default n
- help
- This driver supports QTI crypto acceleration
- for kernel clients. To compile this driver as a module,
- choose M here: the module will be called qcrypto. Please
- select Y here to enable.
-
-config CRYPTO_DEV_QCOM_MSM_QCE
- tristate "QTI Crypto Engine (QCE) module"
- default n
- help
- This driver supports QTI Crypto Engine 5.0.
- To compile this driver as a module, choose M here: the
- module is called qce50.
-
-config CRYPTO_DEV_QCEDEV
- tristate "QCEDEV Interface to CE module"
- default n
- help
- This driver supports QTI QCEDEV Crypto Engine 5.0.
- This exposes the interface to the QCE hardware accelerator
- via IOCTLs.
-
- To compile this driver as a module, choose M here: the
- module will be called qcedev.
-
-config CRYPTO_DEV_OTA_CRYPTO
- tristate "OTA Crypto module"
- help
- This driver supports QTI OTA Crypto in the FSM9xxx.
- To compile this driver as a module, choose M here: the
- module will be called ota_crypto. Please select Y here
- to enable.
-
config CRYPTO_DEV_NX
bool "Support for IBM PowerPC Nest (NX) cryptographic acceleration"
depends on PPC64
@@ -550,7 +498,49 @@
help
This driver supports Qualcomm crypto engine accelerator
hardware. To compile this driver as a module, choose M here. The
- module will be called qcrypto.
+ module will be called qcrypt.
+
+config CRYPTO_DEV_QCOM_MSM_QCE
+ tristate "QTI Crypto Engine (QCE) module"
+ depends on ARCH_QCOM
+ help
+ This driver supports QTI Crypto Engine accelerator hardware, which
+ is present on SDM845. This is the core crypto driver which adds
+ CE5.0 functionalities. To compile this driver as a module, choose
+ M here. The module will be called QCE50.
+
+config CRYPTO_DEV_QCRYPTO
+ tristate "QTI Crypto accelerator"
+ depends on ARCH_QCOM
+ select CRYPTO_DES
+ select CRYPTO_ALGAPI
+ select CRYPTO_AUTHENC
+ select CRYPTO_BLKCIPHER
+ help
+ This driver supports QTI crypto acceleration
+ for kernel clients. To compile this driver as a module,
+ choose M here: the module will be called qcrypto. Please
+ select Y here to enable.
+
+config CRYPTO_DEV_QCEDEV
+ tristate "QCEDEV Interface to CE module"
+ depends on ARCH_QCOM
+ help
+ This driver supports QTI QCEDEV Crypto Engine 5.0.
+ This exposes the interface to the QCE hardware accelerator
+ via IOCTLs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qcedev.
+
+config CRYPTO_DEV_OTA_CRYPTO
+ tristate "OTA Crypto module"
+ depends on ARCH_QCOM
+ help
+ This driver supports QTI OTA Crypto in the FSM9xxx.
+ To compile this driver as a module, choose M here: the
+ module will be called ota_crypto. Please select Y here
+ to enable.
config CRYPTO_DEV_VMX
bool "Support for VMX cryptographic acceleration instructions"
diff --git a/drivers/crypto/msm/Kconfig b/drivers/crypto/msm/Kconfig
index 0f4568b..3011aa6 100644
--- a/drivers/crypto/msm/Kconfig
+++ b/drivers/crypto/msm/Kconfig
@@ -2,7 +2,7 @@
config CRYPTO_DEV_QCOM_ICE
tristate "Inline Crypto Module"
default n
- depends on PFK && BLK_DEV_DM
+ depends on BLK_DEV_DM
help
This driver supports Inline Crypto Engine for QTI chipsets, MSM8994
and later, to accelerate crypto operations for storage needs.
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index ba6825e..b411726 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -21,12 +21,31 @@
#include <linux/cdev.h>
#include <linux/regulator/consumer.h>
#include <linux/msm-bus.h>
-#include <linux/pfk.h>
#include <crypto/ice.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/qseecomi.h>
#include "iceregs.h"
+#ifdef CONFIG_PFK
+#include <linux/pfk.h>
+#else
+#include <linux/bio.h>
+static inline int pfk_load_key_start(const struct bio *bio,
+ struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async)
+{
+ return 0;
+}
+
+static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
+{
+ return 0;
+}
+
+static inline void pfk_clear_on_reset(void)
+{
+}
+#endif
+
#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff)))
diff --git a/drivers/crypto/qce/Makefile b/drivers/crypto/qce/Makefile
index 348dc31..7f584ee 100644
--- a/drivers/crypto/qce/Makefile
+++ b/drivers/crypto/qce/Makefile
@@ -1,5 +1,5 @@
-obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypto.o
-qcrypto-objs := core.o \
+obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypt.o
+qcrypt-objs := core.o \
common.o \
dma.o \
sha.o \
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index d7cc425..53c0f8a 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -143,25 +143,27 @@
{ \
struct devfreq *df = to_devfreq(dev); \
struct hwmon_node *hw = df->data; \
- int ret; \
+ int ret, numvals; \
unsigned int i = 0, val; \
+ char **strlist; \
\
- do { \
- ret = kstrtoint(buf, 10, &val); \
+ strlist = argv_split(GFP_KERNEL, buf, &numvals); \
+ if (!strlist) \
+ return -ENOMEM; \
+ numvals = min(numvals, n - 1); \
+ for (i = 0; i < numvals; i++) { \
+ ret = kstrtouint(strlist[i], 10, &val); \
if (ret) \
- break; \
- buf = strnchr(buf, PAGE_SIZE, ' '); \
- if (buf) \
- buf++; \
+ goto out; \
val = max(val, _min); \
val = min(val, _max); \
hw->name[i] = val; \
- i++; \
- } while (buf && i < n - 1); \
- if (i < 1) \
- return -EINVAL; \
+ } \
+ ret = count; \
+out: \
+ argv_free(strlist); \
hw->name[i] = 0; \
- return count; \
+ return ret; \
}
#define gov_list_attr(__attr, n, min, max) \
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 106511c..86db16e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -1373,6 +1373,11 @@
if (rc)
pr_err("%s: Failed to enable dsi clamps. rc=%d\n",
__func__, rc);
+
+ rc = dsi_display_phy_reset_config(display, false);
+ if (rc)
+ pr_err("%s: Failed to reset phy, rc=%d\n",
+ __func__, rc);
} else {
/* Make sure that controller is not in ULPS state when
* the DSI link is not active.
@@ -1428,6 +1433,13 @@
}
}
+ rc = dsi_display_phy_reset_config(display, true);
+ if (rc) {
+ pr_err("%s: Failed to reset phy, rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+
rc = dsi_display_set_clamp(display, false);
if (rc) {
pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
@@ -2973,18 +2985,11 @@
goto error_phy_disable;
}
- rc = dsi_display_phy_reset_config(display, true);
- if (rc) {
- pr_err("[%s] failed to setup DSI controller, rc=%d\n",
- display->name, rc);
- goto error_ctrl_deinit;
- }
-
rc = dsi_display_set_clk_src(display);
if (rc) {
pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
display->name, rc);
- goto error_phy_reset_off;
+ goto error_ctrl_deinit;
}
rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
@@ -2992,7 +2997,7 @@
if (rc) {
pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
display->name, rc);
- goto error_phy_reset_off;
+ goto error_ctrl_deinit;
}
rc = dsi_display_ctrl_host_enable(display);
@@ -3015,8 +3020,6 @@
error_ctrl_link_off:
(void)dsi_display_clk_ctrl(display->dsi_clk_handle,
DSI_LINK_CLK, DSI_CLK_OFF);
-error_phy_reset_off:
- (void)dsi_display_phy_reset_config(display, false);
error_ctrl_deinit:
(void)dsi_display_ctrl_deinit(display);
error_phy_disable:
@@ -3233,11 +3236,6 @@
pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
display->name, rc);
- rc = dsi_display_phy_reset_config(display, false);
- if (rc)
- pr_err("[%s] failed to disable DSI PHY reset config, rc=%d\n",
- display->name, rc);
-
rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
DSI_CORE_CLK, DSI_CLK_OFF);
if (rc)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
index 8250da3..174be9f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
@@ -37,7 +37,7 @@
readl_relaxed((dsi_hw)->disp_cc_base + (off))
#define DSI_DISP_CC_W32(dsi_hw, off, val) \
do {\
- pr_err("[DSI_%d][%s] - [0x%08x]\n", \
+ pr_debug("[DSI_%d][%s] - [0x%08x]\n", \
(dsi_hw)->index, #off, val); \
writel_relaxed((val), (dsi_hw)->disp_cc_base + (off)); \
} while (0)
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 4471d0b..934bea1 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -164,6 +164,7 @@
/* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME,
CONNECTOR_PROP_TOPOLOGY_CONTROL,
+ CONNECTOR_PROP_AUTOREFRESH,
/* total # of properties */
CONNECTOR_PROP_COUNT
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index e3f8261..9f8d7ee 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -21,6 +21,9 @@
#define BL_NODE_NAME_SIZE 32
+/* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */
+#define AUTOREFRESH_MAX_FRAME_CNT 6
+
#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
@@ -990,6 +993,10 @@
msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
+ msm_property_install_range(&c_conn->property_info, "autorefresh",
+ 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
+ CONNECTOR_PROP_AUTOREFRESH);
+
/* enum/bitmask properties */
msm_property_install_enum(&c_conn->property_info, "topology_name",
DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 6bae083..f2d78cb 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -808,6 +808,44 @@
return 0;
}
+static int _sde_crtc_check_autorefresh(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *crtc_state;
+ struct drm_connector *conn;
+ struct drm_connector_state *conn_state;
+ int i;
+
+ if (!crtc || !state)
+ return -EINVAL;
+
+ sde_crtc = to_sde_crtc(crtc);
+ crtc_state = to_sde_crtc_state(state);
+
+ if (sde_kms_rect_is_null(&crtc_state->crtc_roi))
+ return 0;
+
+ /* partial update active, check if autorefresh is also requested */
+ for_each_connector_in_state(state->state, conn, conn_state, i) {
+ uint64_t autorefresh;
+
+ if (!conn_state || conn_state->crtc != crtc)
+ continue;
+
+ autorefresh = sde_connector_get_property(conn_state,
+ CONNECTOR_PROP_AUTOREFRESH);
+ if (autorefresh) {
+ SDE_ERROR(
+ "%s: autorefresh & partial crtc roi incompatible %llu\n",
+ sde_crtc->name, autorefresh);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
struct drm_crtc_state *state, int lm_idx)
{
@@ -953,6 +991,10 @@
if (rc)
return rc;
+ rc = _sde_crtc_check_autorefresh(crtc, state);
+ if (rc)
+ return rc;
+
for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
if (rc)
@@ -2074,6 +2116,33 @@
crtc->state = &cstate->base;
}
+static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en)
+{
+ if (!sde_crtc) {
+ SDE_ERROR("invalid crtc\n");
+ return -EINVAL;
+ } else if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) {
+ SDE_DEBUG("crtc%d vblank enable\n", sde_crtc->base.base.id);
+ if (!sde_crtc->suspend)
+ _sde_crtc_vblank_enable_nolock(sde_crtc, true);
+ } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) {
+ SDE_ERROR("crtc%d invalid vblank disable\n",
+ sde_crtc->base.base.id);
+ return -EINVAL;
+ } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) {
+ SDE_DEBUG("crtc%d vblank disable\n", sde_crtc->base.base.id);
+ if (!sde_crtc->suspend)
+ _sde_crtc_vblank_enable_nolock(sde_crtc, false);
+ } else {
+ SDE_DEBUG("crtc%d vblank %s refcount:%d\n",
+ sde_crtc->base.base.id,
+ en ? "enable" : "disable",
+ atomic_read(&sde_crtc->vblank_refcount));
+ }
+
+ return 0;
+}
+
static void sde_crtc_disable(struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc;
@@ -2103,13 +2172,9 @@
crtc->base.id);
SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->vblank_refcount),
SDE_EVTLOG_FUNC_CASE1);
- drm_for_each_encoder(encoder, crtc->dev) {
- if (encoder->crtc != crtc)
- continue;
- sde_encoder_register_vblank_callback(encoder, NULL,
- NULL);
- }
- atomic_set(&sde_crtc->vblank_refcount, 0);
+ while (atomic_read(&sde_crtc->vblank_refcount))
+ if (_sde_crtc_vblank_no_lock(sde_crtc, false))
+ break;
}
if (atomic_read(&sde_crtc->frame_pending)) {
@@ -2463,7 +2528,7 @@
int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
{
struct sde_crtc *sde_crtc;
- int rc = 0;
+ int rc;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -2472,25 +2537,9 @@
sde_crtc = to_sde_crtc(crtc);
mutex_lock(&sde_crtc->crtc_lock);
- if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) {
- SDE_DEBUG("crtc%d vblank enable\n", crtc->base.id);
- if (!sde_crtc->suspend)
- _sde_crtc_vblank_enable_nolock(sde_crtc, true);
- } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) {
- SDE_ERROR("crtc%d invalid vblank disable\n", crtc->base.id);
- rc = -EINVAL;
- } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) {
- SDE_DEBUG("crtc%d vblank disable\n", crtc->base.id);
- if (!sde_crtc->suspend)
- _sde_crtc_vblank_enable_nolock(sde_crtc, false);
- } else {
- SDE_DEBUG("crtc%d vblank %s refcount:%d\n",
- crtc->base.id,
- en ? "enable" : "disable",
- atomic_read(&sde_crtc->vblank_refcount));
- }
-
+ rc = _sde_crtc_vblank_no_lock(sde_crtc, en);
mutex_unlock(&sde_crtc->crtc_lock);
+
return rc;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 7ad0955..98ba711 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -316,6 +316,21 @@
}
/**
+ * sde_crtc_frame_pending - retun the number of pending frames
+ * @crtc: Pointer to drm crtc object
+ */
+static inline int sde_crtc_frame_pending(struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc;
+
+ if (!crtc)
+ return -EINVAL;
+
+ sde_crtc = to_sde_crtc(crtc);
+ return atomic_read(&sde_crtc->frame_pending);
+}
+
+/**
* sde_crtc_vblank - enable or disable vblanks for this crtc
* @crtc: Pointer to drm crtc object
* @en: true to enable vblanks, false to disable
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 742ea20..3357642 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -34,6 +34,7 @@
#include "sde_encoder_phys.h"
#include "sde_power_handle.h"
#include "sde_hw_dsc.h"
+#include "sde_crtc.h"
#define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\
(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
@@ -58,6 +59,56 @@
#define MISR_BUFF_SIZE 256
+#define IDLE_TIMEOUT 64
+
+/**
+ * enum sde_enc_rc_events - events for resource control state machine
+ * @SDE_ENC_RC_EVENT_KICKOFF:
+ * This event happens at NORMAL priority.
+ * Event that signals the start of the transfer. When this event is
+ * received, enable MDP/DSI core clocks and request RSC with CMD state.
+ * Regardless of the previous state, the resource should be in ON state
+ * at the end of this event.
+ * @SDE_ENC_RC_EVENT_FRAME_DONE:
+ * This event happens at INTERRUPT level.
+ * Event signals the end of the data transfer after the PP FRAME_DONE
+ * event. At the end of this event, a delayed work is scheduled to go to
+ * IDLE_PC state after IDLE_TIMEOUT time.
+ * @SDE_ENC_RC_EVENT_STOP:
+ * This event happens at NORMAL priority.
+ * When this event is received, disable all the MDP/DSI core clocks
+ * and request RSC with IDLE state. Resource state should be in OFF
+ * at the end of the event.
+ * @SDE_ENC_RC_EARLY_WAKEUP
+ * This event happens at NORMAL priority from a work item.
+ * Event signals that there will be frame update soon and the driver should
+ * wake up early to update the frame with minimum latency.
+ * @SDE_ENC_RC_EVENT_ENTER_IDLE:
+ * This event happens at NORMAL priority from a work item.
+ * Event signals that there were no frame updates for IDLE_TIMEOUT time.
+ * This would disable MDP/DSI core clocks and request RSC with IDLE state
+ * and change the resource state to IDLE.
+ */
+enum sde_enc_rc_events {
+ SDE_ENC_RC_EVENT_KICKOFF = 1,
+ SDE_ENC_RC_EVENT_FRAME_DONE,
+ SDE_ENC_RC_EVENT_STOP,
+ SDE_ENC_RC_EVENT_EARLY_WAKE_UP,
+ SDE_ENC_RC_EVENT_ENTER_IDLE
+};
+
+/*
+ * enum sde_enc_rc_states - states that the resource control maintains
+ * @SDE_ENC_RC_STATE_OFF: Resource is in OFF state
+ * @SDE_ENC_RC_STATE_ON: Resource is in ON state
+ * @SDE_ENC_RC_STATE_IDLE: Resource is in IDLE state
+ */
+enum sde_enc_rc_states {
+ SDE_ENC_RC_STATE_OFF,
+ SDE_ENC_RC_STATE_ON,
+ SDE_ENC_RC_STATE_IDLE
+};
+
/**
* struct sde_encoder_virt - virtual encoder. Container of one or more physical
* encoders. Virtual encoder manages one "logical" display. Physical
@@ -91,7 +142,16 @@
* @crtc_frame_event: callback event
* @frame_done_timeout: frame done timeout in Hz
* @frame_done_timer: watchdog timer for frame done event
+ * @rsc_client: rsc client pointer
+ * @rsc_state_init: boolean to indicate rsc config init
+ * @disp_info: local copy of msm_display_info struct
* @misr_enable: misr enable/disable status
+ * @idle_pc_supported: indicate if idle power collaps is supported
+ * @rc_lock: resource control mutex lock to protect
+ * virt encoder over various state changes
+ * @rc_state: resource controller state
+ * @delayed_off_work: delayed worker to schedule disabling of
+ * clks and resources after IDLE_TIMEOUT time.
*/
struct sde_encoder_virt {
struct drm_encoder base;
@@ -120,9 +180,14 @@
struct timer_list frame_done_timer;
struct sde_rsc_client *rsc_client;
+ bool rsc_state_init;
struct msm_display_info disp_info;
- bool rsc_state_update;
bool misr_enable;
+
+ bool idle_pc_supported;
+ struct mutex rc_lock;
+ enum sde_enc_rc_states rc_state;
+ struct delayed_work delayed_off_work;
};
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -700,6 +765,11 @@
sde_enc = to_sde_encoder_virt(drm_enc);
disp_info = &sde_enc->disp_info;
+ if (!sde_enc->rsc_client) {
+ SDE_DEBUG("rsc client not created\n");
+ return 0;
+ }
+
/**
* only primary command mode panel can request CMD state.
* all other panels/displays can request for VID state including
@@ -710,14 +780,14 @@
disp_info->is_primary) ? SDE_RSC_CMD_STATE :
SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
- if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_update
+ if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init
&& disp_info->is_primary) {
rsc_config.fps = disp_info->frame_rate;
rsc_config.vtotal = disp_info->vtotal;
rsc_config.prefill_lines = disp_info->prefill_lines;
rsc_config.jitter = disp_info->jitter;
/* update it only once */
- sde_enc->rsc_state_update = true;
+ sde_enc->rsc_state_init = true;
ret = sde_rsc_client_state_update(sde_enc->rsc_client,
rsc_state, &rsc_config,
@@ -748,6 +818,277 @@
return disp_info->is_primary ? sde_enc->rsc_client : NULL;
}
+static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
+ bool enable)
+{
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+ struct sde_encoder_virt *sde_enc;
+ int i;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ priv = drm_enc->dev->dev_private;
+ sde_kms = to_sde_kms(priv->kms);
+
+ SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable);
+ SDE_EVT32(DRMID(drm_enc), enable);
+
+ if (!sde_enc->cur_master) {
+ SDE_ERROR("encoder master not set\n");
+ return;
+ }
+
+ if (enable) {
+ /* enable SDE core clks */
+ sde_power_resource_enable(&priv->phandle,
+ sde_kms->core_client, true);
+
+ /* enable DSI clks */
+ sde_connector_clk_ctrl(sde_enc->cur_master->connector, true);
+
+ /* enable all the irq */
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+ if (phys && phys->ops.irq_control)
+ phys->ops.irq_control(phys, true);
+ }
+
+ /* enable RSC */
+ sde_encoder_update_rsc_client(drm_enc, true);
+
+ } else {
+
+ /* disable RSC */
+ sde_encoder_update_rsc_client(drm_enc, false);
+
+ /* disable all the irq */
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ struct sde_encoder_phys *phys =
+ sde_enc->phys_encs[i];
+
+ if (phys && phys->ops.irq_control)
+ phys->ops.irq_control(phys, false);
+ }
+
+ /* disable DSI clks */
+ sde_connector_clk_ctrl(sde_enc->cur_master->connector, false);
+
+ /* disable SDE core clks */
+ sde_power_resource_enable(&priv->phandle,
+ sde_kms->core_client, false);
+ }
+
+}
+
+static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
+ u32 sw_event)
+{
+ bool schedule_off = false;
+ struct sde_encoder_virt *sde_enc;
+
+ if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
+ SDE_ERROR("invalid parameters\n");
+ return -EINVAL;
+ }
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
+ /*
+ * when idle_pc is not supported, process only KICKOFF and STOP
+ * event and return early for other events (ie video mode).
+ */
+ if (!sde_enc->idle_pc_supported &&
+ (sw_event != SDE_ENC_RC_EVENT_KICKOFF &&
+ sw_event != SDE_ENC_RC_EVENT_STOP))
+ return 0;
+
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc_supported:%d\n", sw_event,
+ sde_enc->idle_pc_supported);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
+ sde_enc->rc_state, SDE_EVTLOG_FUNC_ENTRY);
+
+ switch (sw_event) {
+ case SDE_ENC_RC_EVENT_KICKOFF:
+ /* cancel delayed off work, if any */
+ if (cancel_delayed_work_sync(&sde_enc->delayed_off_work))
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
+ sw_event);
+
+ mutex_lock(&sde_enc->rc_lock);
+
+ /* return if the resource control is already in ON state */
+ if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) {
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in ON state\n",
+ sw_event);
+ mutex_unlock(&sde_enc->rc_lock);
+ return 0;
+ }
+
+ /* enable all the clks and resources */
+ _sde_encoder_resource_control_helper(drm_enc, true);
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1);
+ sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
+
+ mutex_unlock(&sde_enc->rc_lock);
+ break;
+
+ case SDE_ENC_RC_EVENT_FRAME_DONE:
+ /*
+ * mutex lock is not used as this event happens at interrupt
+ * context. And locking is not required as, the other events
+ * like KICKOFF and STOP does a wait-for-idle before executing
+ * the resource_control
+ */
+ if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
+ SDE_ERROR_ENC(sde_enc, "sw_event:%d,rc:%d-unexpected\n",
+ sw_event, sde_enc->rc_state);
+ return -EINVAL;
+ }
+
+ /*
+ * schedule off work item only when there are no
+ * frames pending
+ */
+ if (sde_crtc_frame_pending(drm_enc->crtc) > 1) {
+ SDE_DEBUG_ENC(sde_enc, "skip schedule work");
+ return 0;
+ }
+
+ /* schedule delayed off work */
+ schedule_delayed_work(&sde_enc->delayed_off_work,
+ msecs_to_jiffies(IDLE_TIMEOUT));
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_EVTLOG_FUNC_CASE2);
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
+ sw_event);
+ break;
+
+ case SDE_ENC_RC_EVENT_STOP:
+ /* cancel delayed off work, if any */
+ if (cancel_delayed_work_sync(&sde_enc->delayed_off_work))
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
+ sw_event);
+
+ mutex_lock(&sde_enc->rc_lock);
+
+ /* return if the resource control is already in OFF state */
+ if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
+ sw_event);
+ mutex_unlock(&sde_enc->rc_lock);
+ return 0;
+ }
+
+ /*
+ * disable the clks and resources only if the resource control
+ * is in ON state, otherwise the clks and resources would have
+ * been disabled while going into IDLE state
+ */
+ if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON)
+ _sde_encoder_resource_control_helper(drm_enc, false);
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE3);
+ sde_enc->rc_state = SDE_ENC_RC_STATE_OFF;
+
+ mutex_unlock(&sde_enc->rc_lock);
+ break;
+
+ case SDE_ENC_RC_EVENT_EARLY_WAKE_UP:
+ /* cancel delayed off work, if any */
+ if (cancel_delayed_work_sync(&sde_enc->delayed_off_work)) {
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
+ sw_event);
+ schedule_off = true;
+ }
+
+ mutex_lock(&sde_enc->rc_lock);
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ schedule_off, SDE_EVTLOG_FUNC_CASE4);
+
+ /* return if the resource control is in OFF state */
+ if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
+ sw_event);
+ mutex_unlock(&sde_enc->rc_lock);
+ return 0;
+ }
+
+ /*
+ * enable all the clks and resources if resource control is
+ * coming out of IDLE state
+ */
+ if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
+ _sde_encoder_resource_control_helper(drm_enc, true);
+ sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
+ schedule_off = true;
+ }
+
+ /*
+ * schedule off work when there are no frames pending and
+ * 1. early wakeup cancelled off work
+ * 2. early wakeup changed the rc_state to ON - this is to
+ * handle cases where early wakeup is called but no
+ * frame updates
+ */
+ if (schedule_off && !sde_crtc_frame_pending(drm_enc->crtc)) {
+ /* schedule delayed off work */
+ schedule_delayed_work(&sde_enc->delayed_off_work,
+ msecs_to_jiffies(IDLE_TIMEOUT));
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
+ sw_event);
+ }
+
+ mutex_unlock(&sde_enc->rc_lock);
+ break;
+
+ case SDE_ENC_RC_EVENT_ENTER_IDLE:
+ mutex_lock(&sde_enc->rc_lock);
+
+ if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
+ sw_event, sde_enc->rc_state);
+ mutex_unlock(&sde_enc->rc_lock);
+ return 0;
+ }
+
+ /* disable all the clks and resources */
+ _sde_encoder_resource_control_helper(drm_enc, false);
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+ SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE5);
+ sde_enc->rc_state = SDE_ENC_RC_STATE_IDLE;
+
+ mutex_unlock(&sde_enc->rc_lock);
+ break;
+
+ default:
+ SDE_ERROR("unexpected sw_event: %d\n", sw_event);
+ break;
+ }
+
+ SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
+ sde_enc->rc_state, SDE_EVTLOG_FUNC_EXIT);
+ return 0;
+}
+
+static void sde_encoder_off_work(struct work_struct *work)
+{
+ struct delayed_work *dw = to_delayed_work(work);
+ struct sde_encoder_virt *sde_enc = container_of(dw,
+ struct sde_encoder_virt, delayed_off_work);
+
+ if (!sde_enc) {
+ SDE_ERROR("invalid sde encoder\n");
+ return;
+ }
+
+ sde_encoder_resource_control(&sde_enc->base,
+ SDE_ENC_RC_EVENT_ENTER_IDLE);
+}
+
static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
struct drm_display_mode *mode,
struct drm_display_mode *adj_mode)
@@ -831,6 +1172,8 @@
static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = NULL;
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
int i = 0;
int ret = 0;
@@ -846,37 +1189,56 @@
}
sde_enc = to_sde_encoder_virt(drm_enc);
+ priv = drm_enc->dev->dev_private;
+ sde_kms = to_sde_kms(priv->kms);
+
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return;
+ }
SDE_DEBUG_ENC(sde_enc, "\n");
SDE_EVT32(DRMID(drm_enc));
- ret = _sde_encoder_power_enable(sde_enc, true);
- if (ret)
- return;
-
sde_enc->cur_master = NULL;
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+ if (phys && phys->ops.is_master && phys->ops.is_master(phys)) {
+ SDE_DEBUG_ENC(sde_enc, "master is now idx %d\n", i);
+ sde_enc->cur_master = phys;
+ break;
+ }
+ }
+
+ if (!sde_enc->cur_master) {
+ SDE_ERROR("virt encoder has no master! num_phys %d\n", i);
+ return;
+ }
+
+ ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF);
+ if (ret) {
+ SDE_ERROR_ENC(sde_enc, "sde resource control failed: %d\n",
+ ret);
+ return;
+ }
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys) {
- if (phys->ops.is_master && phys->ops.is_master(phys)) {
- SDE_DEBUG_ENC(sde_enc,
- "master is now idx %d\n", i);
- sde_enc->cur_master = phys;
- } else if (phys->ops.enable) {
- phys->ops.enable(phys);
- }
- }
+ if (phys && (phys != sde_enc->cur_master) && phys->ops.enable)
+ phys->ops.enable(phys);
}
- sde_encoder_update_rsc_client(drm_enc, true);
-
- if (!sde_enc->cur_master)
- SDE_ERROR("virt encoder has no master! num_phys %d\n", i);
- else if (sde_enc->cur_master->ops.enable)
+ if (sde_enc->cur_master && sde_enc->cur_master->ops.enable)
sde_enc->cur_master->ops.enable(sde_enc->cur_master);
+ if (sde_enc->cur_master && sde_enc->cur_master->hw_mdptop &&
+ sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
+ sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
+ sde_enc->cur_master->hw_mdptop,
+ sde_kms->catalog);
+
if (_sde_is_dsc_enabled(sde_enc)) {
ret = _sde_encoder_dsc_setup(sde_enc);
if (ret)
@@ -914,9 +1276,8 @@
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys) {
- if (phys->ops.disable && !phys->ops.is_master(phys))
- phys->ops.disable(phys);
+ if (phys && phys->ops.disable && !phys->ops.is_master(phys)) {
+ phys->ops.disable(phys);
phys->connector = NULL;
}
}
@@ -927,17 +1288,19 @@
del_timer_sync(&sde_enc->frame_done_timer);
}
- sde_encoder_update_rsc_client(drm_enc, false);
-
if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
sde_enc->cur_master->ops.disable(sde_enc->cur_master);
- sde_enc->cur_master = NULL;
- SDE_DEBUG_ENC(sde_enc, "cleared master\n");
+ sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP);
+
+ if (sde_enc->cur_master) {
+ sde_enc->cur_master->connector = NULL;
+ sde_enc->cur_master = NULL;
+ }
+
+ SDE_DEBUG_ENC(sde_enc, "encoder disabled\n");
sde_rm_release(&sde_kms->rm, drm_enc);
-
- _sde_encoder_power_enable(sde_enc, false);
}
static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
@@ -1066,6 +1429,9 @@
atomic_set(&sde_enc->frame_done_timeout, 0);
del_timer(&sde_enc->frame_done_timer);
+ sde_encoder_resource_control(drm_enc,
+ SDE_ENC_RC_EVENT_FRAME_DONE);
+
if (sde_enc->crtc_frame_event_cb)
sde_enc->crtc_frame_event_cb(
sde_enc->crtc_frame_event_cb_data,
@@ -1308,6 +1674,8 @@
}
}
+ sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF);
+
/* if any phys needs reset, reset all phys, in-order */
if (needs_hw_reset) {
for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -1798,6 +2166,9 @@
phys_params.comp_type = disp_info->comp_info.comp_type;
+ if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
+ sde_enc->idle_pc_supported = sde_kms->catalog->has_idle_pc;
+
mutex_lock(&sde_enc->enc_lock);
for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) {
/*
@@ -1958,6 +2329,9 @@
sde_enc->rsc_client = NULL;
}
+ mutex_init(&sde_enc->rc_lock);
+ INIT_DELAYED_WORK(&sde_enc->delayed_off_work, sde_encoder_off_work);
+
memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info));
SDE_DEBUG_ENC(sde_enc, "created\n");
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index da155b0..6942292 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -117,6 +117,7 @@
* @collect_misr: Collects MISR data on frame update
* @hw_reset: Issue HW recovery such as CTL reset and clear
* SDE_ENC_ERR_NEEDS_HW_RESET state
+ * @irq_control: Handler to enable/disable all the encoder IRQs
*/
struct sde_encoder_phys_ops {
@@ -150,6 +151,7 @@
bool enable, u32 frame_count);
u32 (*collect_misr)(struct sde_encoder_phys *phys_enc);
void (*hw_reset)(struct sde_encoder_phys *phys_enc);
+ void (*irq_control)(struct sde_encoder_phys *phys, bool enable);
};
/**
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 5b59828..a4f40f2 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -363,6 +363,78 @@
return 0;
}
+static int sde_encoder_phys_cmd_control_vblank_irq(
+ struct sde_encoder_phys *phys_enc,
+ bool enable)
+{
+ struct sde_encoder_phys_cmd *cmd_enc =
+ to_sde_encoder_phys_cmd(phys_enc);
+ int ret = 0;
+
+ if (!phys_enc) {
+ SDE_ERROR("invalid encoder\n");
+ return -EINVAL;
+ }
+
+ /* Slave encoders don't report vblank */
+ if (!sde_encoder_phys_cmd_is_master(phys_enc))
+ goto end;
+
+ SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
+ __builtin_return_address(0),
+ enable, atomic_read(&phys_enc->vblank_refcount));
+
+ SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+ enable, atomic_read(&phys_enc->vblank_refcount));
+
+ if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
+ ret = sde_encoder_phys_cmd_register_irq(phys_enc,
+ SDE_IRQ_TYPE_PING_PONG_RD_PTR,
+ INTR_IDX_RDPTR,
+ sde_encoder_phys_cmd_pp_rd_ptr_irq,
+ "pp_rd_ptr");
+ else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
+ ret = sde_encoder_phys_cmd_unregister_irq(phys_enc,
+ INTR_IDX_RDPTR);
+
+end:
+ if (ret)
+ SDE_ERROR_CMDENC(cmd_enc,
+ "control vblank irq error %d, enable %d\n",
+ ret, enable);
+
+ return ret;
+}
+
+void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc,
+ bool enable)
+{
+ if (!phys_enc || _sde_encoder_phys_is_ppsplit_slave(phys_enc))
+ return;
+
+ if (enable) {
+ sde_encoder_phys_cmd_register_irq(phys_enc,
+ SDE_IRQ_TYPE_PING_PONG_COMP,
+ INTR_IDX_PINGPONG,
+ sde_encoder_phys_cmd_pp_tx_done_irq,
+ "pp_tx_done");
+
+ sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true);
+
+ sde_encoder_phys_cmd_register_irq(phys_enc,
+ SDE_IRQ_TYPE_INTF_UNDER_RUN,
+ INTR_IDX_UNDERRUN,
+ sde_encoder_phys_cmd_underrun_irq,
+ "underrun");
+ } else {
+ sde_encoder_phys_cmd_unregister_irq(
+ phys_enc, INTR_IDX_UNDERRUN);
+ sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
+ sde_encoder_phys_cmd_unregister_irq(
+ phys_enc, INTR_IDX_PINGPONG);
+ }
+}
+
static void sde_encoder_phys_cmd_tearcheck_config(
struct sde_encoder_phys *phys_enc)
{
@@ -477,56 +549,12 @@
return _sde_encoder_phys_is_ppsplit(phys_enc);
}
-static int sde_encoder_phys_cmd_control_vblank_irq(
- struct sde_encoder_phys *phys_enc,
- bool enable)
-{
- struct sde_encoder_phys_cmd *cmd_enc =
- to_sde_encoder_phys_cmd(phys_enc);
- int ret = 0;
-
- if (!phys_enc) {
- SDE_ERROR("invalid encoder\n");
- return -EINVAL;
- }
-
- /* Slave encoders don't report vblank */
- if (!sde_encoder_phys_cmd_is_master(phys_enc))
- goto end;
-
- SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
- __builtin_return_address(0),
- enable, atomic_read(&phys_enc->vblank_refcount));
-
- SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
- enable, atomic_read(&phys_enc->vblank_refcount));
-
- if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
- ret = sde_encoder_phys_cmd_register_irq(phys_enc,
- SDE_IRQ_TYPE_PING_PONG_RD_PTR,
- INTR_IDX_RDPTR,
- sde_encoder_phys_cmd_pp_rd_ptr_irq,
- "pp_rd_ptr");
- else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
- ret = sde_encoder_phys_cmd_unregister_irq(phys_enc,
- INTR_IDX_RDPTR);
-
-end:
- if (ret)
- SDE_ERROR_CMDENC(cmd_enc,
- "control vblank irq error %d, enable %d\n",
- ret, enable);
-
- return ret;
-}
-
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);
struct sde_hw_ctl *ctl;
u32 flush_mask = 0;
- int ret;
if (!phys_enc || !phys_enc->hw_ctl) {
SDE_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0);
@@ -543,38 +571,6 @@
sde_encoder_phys_cmd_pingpong_config(phys_enc);
- if (_sde_encoder_phys_is_ppsplit_slave(phys_enc))
- goto update_flush;
-
- /* Both master and slave need to register for pp_tx_done */
- ret = sde_encoder_phys_cmd_register_irq(phys_enc,
- SDE_IRQ_TYPE_PING_PONG_COMP,
- INTR_IDX_PINGPONG,
- sde_encoder_phys_cmd_pp_tx_done_irq,
- "pp_tx_done");
- if (ret)
- return;
-
- ret = sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true);
- if (ret) {
- sde_encoder_phys_cmd_unregister_irq(phys_enc,
- INTR_IDX_PINGPONG);
- return;
- }
-
- ret = sde_encoder_phys_cmd_register_irq(phys_enc,
- SDE_IRQ_TYPE_INTF_UNDER_RUN,
- INTR_IDX_UNDERRUN,
- sde_encoder_phys_cmd_underrun_irq,
- "underrun");
- if (ret) {
- sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
- sde_encoder_phys_cmd_unregister_irq(phys_enc,
- INTR_IDX_PINGPONG);
- return;
- }
-
-update_flush:
ctl = phys_enc->hw_ctl;
ctl->ops.get_bitmask_intf(ctl, &flush_mask, cmd_enc->intf_idx);
ctl->ops.update_pending_flush(ctl, flush_mask);
@@ -613,21 +609,9 @@
SDE_EVT32(DRMID(phys_enc->parent),
phys_enc->hw_pp->idx - PINGPONG_0, ret);
}
-
- sde_encoder_phys_cmd_unregister_irq(
- phys_enc, INTR_IDX_UNDERRUN);
- sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
- sde_encoder_phys_cmd_unregister_irq(
- phys_enc, INTR_IDX_PINGPONG);
}
phys_enc->enable_state = SDE_ENC_DISABLED;
-
- if (atomic_read(&phys_enc->vblank_refcount))
- SDE_ERROR("enc:%d role:%d invalid vblank refcount %d\n",
- phys_enc->parent->base.id,
- phys_enc->split_role,
- atomic_read(&phys_enc->vblank_refcount));
}
static void sde_encoder_phys_cmd_destroy(struct sde_encoder_phys *phys_enc)
@@ -723,6 +707,7 @@
ops->trigger_start = sde_encoder_helper_trigger_start;
ops->needs_single_flush = sde_encoder_phys_cmd_needs_single_flush;
ops->hw_reset = sde_encoder_helper_hw_reset;
+ ops->irq_control = sde_encoder_phys_cmd_irq_control;
}
struct sde_encoder_phys *sde_encoder_phys_cmd_init(
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 29f00f7..df099d3 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -227,16 +227,18 @@
struct sde_encoder_phys_vid *vid_enc =
to_sde_encoder_phys_vid(phys_enc);
struct intf_prog_fetch f = { 0 };
- struct intf_timing_params *timing = &vid_enc->timing_params;
+ struct intf_timing_params *timing;
u32 vfp_fetch_lines = 0;
u32 horiz_total = 0;
u32 vert_total = 0;
u32 rot_fetch_start_vsync_counter = 0;
unsigned long lock_flags;
- if (WARN_ON_ONCE(!vid_enc->hw_intf->ops.setup_rot_start))
+ if (!phys_enc || !vid_enc->hw_intf ||
+ !vid_enc->hw_intf->ops.setup_rot_start)
return;
+ timing = &vid_enc->timing_params;
vfp_fetch_lines = programmable_fetch_get_num_lines(vid_enc, timing);
if (vfp_fetch_lines && rot_fetch_lines) {
vert_total = get_vertical_total(timing);
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index e7f3df7..c3477b5 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -1072,7 +1072,8 @@
DRM_ERROR("invalid handle for plane %d\n", i);
return -EINVAL;
}
- bos_total_size += bos[i]->size;
+ if ((i == 0) || (bos[i] != bos[0]))
+ bos_total_size += bos[i]->size;
}
if (bos_total_size < layout.total_size) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index cfa3b5e..b8ab066 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -120,6 +120,7 @@
SRC_SPLIT,
DIM_LAYER,
SMART_DMA_REV,
+ IDLE_PC,
SDE_PROP_MAX,
};
@@ -313,6 +314,7 @@
{SRC_SPLIT, "qcom,sde-has-src-split", false, PROP_TYPE_BOOL},
{DIM_LAYER, "qcom,sde-has-dim-layer", false, PROP_TYPE_BOOL},
{SMART_DMA_REV, "qcom,sde-smart-dma-rev", false, PROP_TYPE_STRING},
+ {IDLE_PC, "qcom,sde-has-idle-pc", false, PROP_TYPE_BOOL},
};
static struct sde_prop_type sde_perf_prop[] = {
@@ -2214,6 +2216,7 @@
cfg->has_src_split = PROP_VALUE_ACCESS(prop_value, SRC_SPLIT, 0);
cfg->has_dim_layer = PROP_VALUE_ACCESS(prop_value, DIM_LAYER, 0);
+ cfg->has_idle_pc = PROP_VALUE_ACCESS(prop_value, IDLE_PC, 0);
end:
kfree(prop_value);
return rc;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 97da08f..b5f83ad 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -713,6 +713,7 @@
* @ubwc_version UBWC feature version (0x0 for not supported)
* @has_sbuf indicate if stream buffer is available
* @sbuf_headroom stream buffer headroom in lines
+ * @has_idle_pc indicate if idle power collapse feature is supported
* @dma_formats Supported formats for dma pipe
* @cursor_formats Supported formats for cursor pipe
* @vig_formats Supported formats for vig pipe
@@ -735,6 +736,7 @@
u32 ubwc_version;
bool has_sbuf;
u32 sbuf_headroom;
+ bool has_idle_pc;
u32 mdss_count;
struct sde_mdss_base_cfg mdss[MAX_BLOCKS];
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index f1b9c32..8df4de2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -25,6 +25,9 @@
{
int i;
+ if (!m || !addr || !b)
+ return ERR_PTR(-EINVAL);
+
for (i = 0; i < m->dspp_count; i++) {
if (dspp == m->dspp[i].id) {
b->base_off = addr;
@@ -43,6 +46,9 @@
{
int i = 0, ret;
+ if (!c || !c->cap || !c->cap->sblk)
+ return;
+
for (i = 0; i < SDE_DSPP_MAX; i++) {
if (!test_bit(i, &features))
continue;
@@ -119,6 +125,9 @@
struct sde_hw_dspp *c;
struct sde_dspp_cfg *cfg;
+ if (!addr || !m)
+ return ERR_PTR(-EINVAL);
+
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index 6020476..70b3e56 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -192,6 +192,7 @@
* should be called once before accessing every dspp.
* @idx: DSPP index for which driver object is required
* @addr: Mapped register io address of MDP
+ * @Return: pointer to structure or ERR_PTR
*/
struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
void __iomem *addr,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
index d5289c0..24f16c6 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
@@ -31,9 +31,9 @@
#define MDP_INTF_4_OFF 0x6D000
#define MDP_AD4_0_OFF 0x7D000
#define MDP_AD4_1_OFF 0x7E000
-#define MDP_AD4_INTR_EN_OFF 0x41c
-#define MDP_AD4_INTR_CLEAR_OFF 0x424
-#define MDP_AD4_INTR_STATUS_OFF 0x420
+#define MDP_AD4_INTR_EN_OFF 0x41c
+#define MDP_AD4_INTR_CLEAR_OFF 0x424
+#define MDP_AD4_INTR_STATUS_OFF 0x420
/**
* WB interrupt status bit definitions
@@ -87,7 +87,7 @@
* Pingpong Secondary interrupt status bit definitions
*/
#define SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE BIT(0)
-#define SDE_INTR_PING_PONG_S0_WR_PTR BIT(4)
+#define SDE_INTR_PING_PONG_S0_WR_PTR BIT(4)
#define SDE_INTR_PING_PONG_S0_RD_PTR BIT(8)
#define SDE_INTR_PING_PONG_S0_TEAR_DETECTED BIT(22)
#define SDE_INTR_PING_PONG_S0_TE_DETECTED BIT(28)
@@ -109,6 +109,15 @@
#define SDE_INTR_PING_PONG_3_TE_DETECTED BIT(27)
/**
+ * Ctl start interrupt status bit definitions
+ */
+#define SDE_INTR_CTL_0_START BIT(9)
+#define SDE_INTR_CTL_1_START BIT(10)
+#define SDE_INTR_CTL_2_START BIT(11)
+#define SDE_INTR_CTL_3_START BIT(12)
+#define SDE_INTR_CTL_4_START BIT(13)
+
+/**
* Concurrent WB overflow interrupt status bit definitions
*/
#define SDE_INTR_CWB_2_OVERFLOW BIT(14)
@@ -325,15 +334,21 @@
{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
- /* irq_idx: 40-43 */
+ /* irq_idx: 40 */
{ SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_S0,
SDE_INTR_PING_PONG_S0_RD_PTR, 1},
- { SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
- { SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
- { SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
- /* irq_idx: 44-47 */
- { SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
- { SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
+ /* irq_idx: 41-45 */
+ { SDE_IRQ_TYPE_CTL_START, CTL_0,
+ SDE_INTR_CTL_0_START, 1},
+ { SDE_IRQ_TYPE_CTL_START, CTL_1,
+ SDE_INTR_CTL_1_START, 1},
+ { SDE_IRQ_TYPE_CTL_START, CTL_2,
+ SDE_INTR_CTL_2_START, 1},
+ { SDE_IRQ_TYPE_CTL_START, CTL_3,
+ SDE_INTR_CTL_3_START, 1},
+ { SDE_IRQ_TYPE_CTL_START, CTL_4,
+ SDE_INTR_CTL_4_START, 1},
+ /* irq_idx: 46-47 */
{ SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_2, SDE_INTR_CWB_2_OVERFLOW, 1},
{ SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_3, SDE_INTR_CWB_3_OVERFLOW, 1},
/* irq_idx: 48-51 */
@@ -696,6 +711,9 @@
static void sde_hw_intr_set_mask(struct sde_hw_intr *intr, uint32_t reg_off,
uint32_t mask)
{
+ if (!intr)
+ return;
+
SDE_REG_WRITE(&intr->hw, reg_off, mask);
}
@@ -710,6 +728,9 @@
u32 irq_status;
unsigned long irq_flags;
+ if (!intr)
+ return;
+
/*
* The dispatcher will save the IRQ status before calling here.
* Now need to go through each IRQ status and find matching
@@ -726,6 +747,10 @@
start_idx = reg_idx * 32;
end_idx = start_idx + 32;
+ if (start_idx >= ARRAY_SIZE(sde_irq_map) ||
+ end_idx > ARRAY_SIZE(sde_irq_map))
+ continue;
+
/*
* Search through matching intr status from irq map.
* start_idx and end_idx defined the search range in
@@ -769,6 +794,9 @@
const char *dbgstr = NULL;
uint32_t cache_irq_mask;
+ if (!intr)
+ return -EINVAL;
+
if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) {
pr_err("invalid IRQ index: [%d]\n", irq_idx);
return -EINVAL;
@@ -810,6 +838,9 @@
const char *dbgstr = NULL;
uint32_t cache_irq_mask;
+ if (!intr)
+ return -EINVAL;
+
if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) {
pr_err("invalid IRQ index: [%d]\n", irq_idx);
return -EINVAL;
@@ -846,6 +877,9 @@
{
int i;
+ if (!intr)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++)
SDE_REG_WRITE(&intr->hw, sde_intr_set[i].clr_off, 0xffffffff);
@@ -856,6 +890,9 @@
{
int i;
+ if (!intr)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++)
SDE_REG_WRITE(&intr->hw, sde_intr_set[i].en_off, 0x00000000);
@@ -865,15 +902,23 @@
static int sde_hw_intr_get_valid_interrupts(struct sde_hw_intr *intr,
uint32_t *mask)
{
+ if (!intr || !mask)
+ return -EINVAL;
+
*mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1
| IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP;
+
return 0;
}
static int sde_hw_intr_get_interrupt_sources(struct sde_hw_intr *intr,
uint32_t *sources)
{
+ if (!intr || !sources)
+ return -EINVAL;
+
*sources = SDE_REG_READ(&intr->hw, HW_INTR_STATUS);
+
return 0;
}
@@ -883,6 +928,9 @@
u32 enable_mask;
unsigned long irq_flags;
+ if (!intr)
+ return;
+
spin_lock_irqsave(&intr->status_lock, irq_flags);
for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) {
/* Read interrupt status */
@@ -909,6 +957,9 @@
int reg_idx;
unsigned long irq_flags;
+ if (!intr)
+ return;
+
spin_lock_irqsave(&intr->mask_lock, irq_flags);
reg_idx = sde_irq_map[irq_idx].reg_idx;
@@ -925,6 +976,9 @@
unsigned long irq_flags;
u32 intr_status;
+ if (!intr)
+ return 0;
+
spin_lock_irqsave(&intr->mask_lock, irq_flags);
reg_idx = sde_irq_map[irq_idx].reg_idx;
@@ -959,7 +1013,7 @@
static struct sde_mdss_base_cfg *__intr_offset(struct sde_mdss_cfg *m,
void __iomem *addr, struct sde_hw_blk_reg_map *hw)
{
- if (m->mdp_count == 0)
+ if (!m || !addr || !hw || m->mdp_count == 0)
return NULL;
hw->base_off = addr;
@@ -971,9 +1025,13 @@
struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr,
struct sde_mdss_cfg *m)
{
- struct sde_hw_intr *intr = kzalloc(sizeof(*intr), GFP_KERNEL);
+ struct sde_hw_intr *intr;
struct sde_mdss_base_cfg *cfg;
+ if (!addr || !m)
+ return ERR_PTR(-EINVAL);
+
+ intr = kzalloc(sizeof(*intr), GFP_KERNEL);
if (!intr)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
index 7805df1..aaba1be 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
@@ -25,7 +25,7 @@
#define IRQ_SOURCE_DSI1 BIT(5)
#define IRQ_SOURCE_HDMI BIT(8)
#define IRQ_SOURCE_EDP BIT(12)
-#define IRQ_SOURCE_MHL BIT(16)
+#define IRQ_SOURCE_MHL BIT(16)
/**
* sde_intr_type - HW Interrupt Type
@@ -55,6 +55,7 @@
* @SDE_IRQ_TYPE_SFI_CMD_2_OUT: DSI CMD2 static frame INTR out-of static
* @SDE_IRQ_TYPE_PROG_LINE: Programmable Line interrupt
* @SDE_IRQ_TYPE_AD4_BL_DONE: AD4 backlight
+ * @SDE_IRQ_TYPE_CTL_START: Control start
* @SDE_IRQ_TYPE_RESERVED: Reserved for expansion
*/
enum sde_intr_type {
@@ -84,6 +85,7 @@
SDE_IRQ_TYPE_SFI_CMD_2_OUT,
SDE_IRQ_TYPE_PROG_LINE,
SDE_IRQ_TYPE_AD4_BL_DONE,
+ SDE_IRQ_TYPE_CTL_START,
SDE_IRQ_TYPE_RESERVED,
};
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index 01fe3c8..d15b804 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -574,9 +574,16 @@
rot_cmd.video_mode = data->video_mode;
rot_cmd.fps = data->fps;
+
+ /*
+ * DRM rotation property is specified in counter clockwise direction
+ * whereas rotator h/w rotates in clockwise direction.
+ * Convert rotation property to clockwise 90 by toggling h/v flip
+ */
rot_cmd.rot90 = data->rot90;
- rot_cmd.hflip = data->hflip;
- rot_cmd.vflip = data->vflip;
+ rot_cmd.hflip = data->rot90 ? !data->hflip : data->hflip;
+ rot_cmd.vflip = data->rot90 ? !data->vflip : data->vflip;
+
rot_cmd.secure = data->secure;
rot_cmd.clkrate = data->clkrate;
rot_cmd.data_bw = 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index b20b3bc..cf54611 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -39,13 +39,15 @@
static void sde_hw_setup_split_pipe(struct sde_hw_mdp *mdp,
struct split_pipe_cfg *cfg)
{
- struct sde_hw_blk_reg_map *c = &mdp->hw;
+ struct sde_hw_blk_reg_map *c;
u32 upper_pipe = 0;
u32 lower_pipe = 0;
if (!mdp || !cfg)
return;
+ c = &mdp->hw;
+
if (cfg->en) {
if (cfg->mode == INTF_MODE_CMD) {
lower_pipe = FLD_SPLIT_DISPLAY_CMD;
@@ -107,9 +109,14 @@
static void sde_hw_setup_cdm_output(struct sde_hw_mdp *mdp,
struct cdm_output_cfg *cfg)
{
- struct sde_hw_blk_reg_map *c = &mdp->hw;
+ struct sde_hw_blk_reg_map *c;
u32 out_ctl = 0;
+ if (!mdp || !cfg)
+ return;
+
+ c = &mdp->hw;
+
if (cfg->wb_en)
out_ctl |= BIT(24);
else if (cfg->intf_en)
@@ -121,11 +128,16 @@
static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp,
enum sde_clk_ctrl_type clk_ctrl, bool enable)
{
- struct sde_hw_blk_reg_map *c = &mdp->hw;
+ struct sde_hw_blk_reg_map *c;
u32 reg_off, bit_off;
u32 reg_val, new_val;
bool clk_forced_on;
+ if (!mdp)
+ return false;
+
+ c = &mdp->hw;
+
if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX)
return false;
@@ -150,9 +162,14 @@
static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
struct sde_danger_safe_status *status)
{
- struct sde_hw_blk_reg_map *c = &mdp->hw;
+ struct sde_hw_blk_reg_map *c;
u32 value;
+ if (!mdp || !status)
+ return;
+
+ c = &mdp->hw;
+
value = SDE_REG_READ(c, DANGER_STATUS);
status->mdp = (value >> 0) & 0x3;
status->sspp[SSPP_VIG0] = (value >> 4) & 0x3;
@@ -178,9 +195,14 @@
static void sde_hw_get_safe_status(struct sde_hw_mdp *mdp,
struct sde_danger_safe_status *status)
{
- struct sde_hw_blk_reg_map *c = &mdp->hw;
+ struct sde_hw_blk_reg_map *c;
u32 value;
+ if (!mdp || !status)
+ return;
+
+ c = &mdp->hw;
+
value = SDE_REG_READ(c, SAFE_STATUS);
status->mdp = (value >> 0) & 0x1;
status->sspp[SSPP_VIG0] = (value >> 4) & 0x1;
@@ -205,11 +227,32 @@
static void sde_hw_setup_dce(struct sde_hw_mdp *mdp, u32 dce_sel)
{
- struct sde_hw_blk_reg_map *c = &mdp->hw;
+ struct sde_hw_blk_reg_map *c;
+
+ if (!mdp)
+ return;
+
+ c = &mdp->hw;
SDE_REG_WRITE(c, DCE_SEL, dce_sel);
}
+void sde_hw_reset_ubwc(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m)
+{
+ struct sde_hw_blk_reg_map c;
+
+ if (!mdp || !m)
+ return;
+
+ if (!IS_UBWC_20_SUPPORTED(m->ubwc_version))
+ return;
+
+ /* force blk offset to zero to access beginning of register region */
+ c = mdp->hw;
+ c.blk_off = 0x0;
+ SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static);
+}
+
static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
unsigned long cap)
{
@@ -220,6 +263,7 @@
ops->get_danger_status = sde_hw_get_danger_status;
ops->get_safe_status = sde_hw_get_safe_status;
ops->setup_dce = sde_hw_setup_dce;
+ ops->reset_ubwc = sde_hw_reset_ubwc;
}
static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
@@ -229,6 +273,9 @@
{
int i;
+ if (!m || !addr || !b)
+ return ERR_PTR(-EINVAL);
+
for (i = 0; i < m->mdp_count; i++) {
if (mdp == m->mdp[i].id) {
b->base_off = addr;
@@ -243,25 +290,6 @@
return ERR_PTR(-EINVAL);
}
-static inline void _sde_hw_mdptop_init_ubwc(void __iomem *addr,
- const struct sde_mdss_cfg *m)
-{
- struct sde_hw_blk_reg_map hw;
-
- if (!addr || !m)
- return;
-
- if (!IS_UBWC_20_SUPPORTED(m->ubwc_version))
- return;
-
- memset(&hw, 0, sizeof(hw));
- hw.base_off = addr;
- hw.blk_off = 0x0;
- hw.hwversion = m->hwversion;
- hw.log_mask = SDE_DBG_MASK_TOP;
- SDE_REG_WRITE(&hw, UBWC_STATIC, m->mdp[0].ubwc_static);
-}
-
struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
void __iomem *addr,
const struct sde_mdss_cfg *m)
@@ -294,8 +322,6 @@
mdp->hw.xin_id);
sde_dbg_set_sde_top_offset(mdp->hw.blk_off);
- _sde_hw_mdptop_init_ubwc(addr, m);
-
return mdp;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 9cb0c55..7511358 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -148,6 +148,13 @@
*/
void (*get_safe_status)(struct sde_hw_mdp *mdp,
struct sde_danger_safe_status *status);
+
+ /**
+ * reset_ubwc - reset top level UBWC configuration
+ * @mdp: mdp top context driver
+ * @m: pointer to mdss catalog data
+ */
+ void (*reset_ubwc)(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m);
};
struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 8662207..93268be 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1961,21 +1961,29 @@
ret = sde_plane_rot_submit_command(plane, state,
SDE_HW_ROT_CMD_VALIDATE);
- } else if (sde_plane_enabled(state)) {
+ } else {
SDE_DEBUG("plane%d.%d bypass rotator\n", plane->base.id,
rstate->sequence_id);
/* bypass rotator - initialize output setting as input */
+ for (i = 0; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
+ rstate->out_fb_modifier[i] = state->fb ?
+ state->fb->modifier[i] : 0x0;
+
+ if (state->fb) {
+ rstate->out_fb_pixel_format = state->fb->pixel_format;
+ rstate->out_fb_flags = state->fb->flags;
+ rstate->out_fb_width = state->fb->width;
+ rstate->out_fb_height = state->fb->height;
+ } else {
+ rstate->out_fb_pixel_format = 0x0;
+ rstate->out_fb_flags = 0x0;
+ rstate->out_fb_width = 0;
+ rstate->out_fb_height = 0;
+ }
+
rstate->out_rotation = rstate->in_rotation;
- rstate->out_fb_pixel_format = state->fb->pixel_format;
-
- for (i = 0.; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
- rstate->out_fb_modifier[i] = state->fb->modifier[i];
-
- rstate->out_fb_flags = state->fb->flags;
- rstate->out_fb_width = state->fb->width;
- rstate->out_fb_height = state->fb->height;
rstate->out_src_x = state->src_x;
rstate->out_src_y = state->src_y;
rstate->out_src_w = state->src_w;
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 3618479..1e4f6b1 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -841,7 +841,15 @@
goto data_bus_hdl_err;
}
- if (!phandle->rsc_client_init) {
+ /*
+ * - When the target is RSCC enabled, regulator should
+ * be enabled by the s/w only for the first time during
+ * bootup. After that, RSCC hardware takes care of enabling/
+ * disabling it.
+ * - When the target is not RSCC enabled, regulator should
+ * be totally handled by the software.
+ */
+ if (!phandle->rsc_client) {
rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
enable);
if (rc) {
@@ -883,7 +891,7 @@
sde_power_reg_bus_update(phandle->reg_bus_hdl,
max_usecase_ndx);
- if (!phandle->rsc_client_init)
+ if (!phandle->rsc_client)
msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
enable);
sde_power_data_bus_update(&phandle->data_bus_handle, enable);
@@ -901,7 +909,7 @@
rsc_err:
sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
reg_bus_hdl_err:
- if (!phandle->rsc_client_init)
+ if (!phandle->rsc_client)
msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
vreg_err:
sde_power_data_bus_update(&phandle->data_bus_handle, 0);
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index b26ef9f..d753f0a 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -16,9 +16,9 @@
#define MAX_CLIENT_NAME_LEN 128
-#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 64000
+#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 2000000000
#define SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0
-#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 64000
+#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 2000000000
#define SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0
#include <linux/sde_io_util.h>
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index d762904..f35d77b 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -28,16 +28,19 @@
#include <drm/drmP.h>
#include <drm/drm_irq.h>
#include "sde_rsc_priv.h"
+#include "sde_dbg.h"
-/* this time is ~0.02ms */
-#define RSC_BACKOFF_TIME_NS 20000
+/* worst case time to execute the one tcs vote(sleep/wake) - ~1ms */
+#define TCS_CASE_EXECUTION_TIME 1064000
-/* next two values should be same based on doc */
+/* this time is ~1ms - only wake tcs in any mode */
+#define RSC_BACKOFF_TIME_NS (TCS_CASE_EXECUTION_TIME + 100)
-/* this time is ~0.2ms */
-#define RSC_MODE_THRESHOLD_TIME_IN_NS 200000
-/* this time is ~0.2ms */
-#define RSC_TIME_SLOT_0_NS 200000
+/* this time is ~1ms - only wake TCS in mode-0 */
+#define RSC_MODE_THRESHOLD_TIME_IN_NS ((TCS_CASE_EXECUTION_TIME >> 1) + 100)
+
+/* this time is ~2ms - sleep+ wake TCS in mode-1 */
+#define RSC_TIME_SLOT_0_NS ((TCS_CASE_EXECUTION_TIME * 2) + 100)
#define DEFAULT_PANEL_FPS 60
#define DEFAULT_PANEL_JITTER 5
@@ -74,6 +77,7 @@
{
struct sde_rsc_client *client;
struct sde_rsc_priv *rsc;
+ static int id;
if (!client_name) {
pr_err("client name is null- not supported\n");
@@ -83,7 +87,7 @@
return ERR_PTR(-EINVAL);
} else if (!rsc_prv_list[rsc_index]) {
pr_err("rsc not probed yet or not available\n");
- return ERR_PTR(-EINVAL);
+ return NULL;
}
rsc = rsc_prv_list[rsc_index];
@@ -95,12 +99,14 @@
strlcpy(client->name, client_name, MAX_RSC_CLIENT_NAME_LEN);
client->current_state = SDE_RSC_IDLE_STATE;
client->rsc_index = rsc_index;
+ client->id = id;
if (is_primary_client)
rsc->primary_client = client;
pr_debug("client %s rsc index:%d primary:%d\n", client_name,
rsc_index, is_primary_client);
list_add(&client->list, &rsc->client_list);
+ id++;
mutex_unlock(&rsc->client_lock);
return client;
@@ -502,6 +508,8 @@
return -EINVAL;
mutex_lock(&rsc->client_lock);
+ SDE_EVT32(caller_client->id, caller_client->current_state,
+ state, rsc->current_state, SDE_EVTLOG_FUNC_ENTRY);
caller_client->crtc_id = crtc_id;
caller_client->current_state = state;
@@ -559,14 +567,20 @@
if (rc == STATE_UPDATE_NOT_ALLOWED) {
rc = 0;
+ SDE_EVT32(caller_client->id, caller_client->current_state,
+ state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE1);
goto clk_disable;
} else if (rc) {
pr_debug("state:%d update failed rc:%d\n", state, rc);
+ SDE_EVT32(caller_client->id, caller_client->current_state,
+ state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE2);
goto clk_disable;
}
pr_debug("state switch successfully complete: %d\n", state);
rsc->current_state = state;
+ SDE_EVT32(caller_client->id, caller_client->current_state,
+ state, rsc->current_state, SDE_EVTLOG_FUNC_EXIT);
clk_disable:
if (rsc->current_state == SDE_RSC_IDLE_STATE)
@@ -1063,9 +1077,6 @@
pr_err("sde rsc:get display rsc failed ret:%d\n", ret);
goto sde_rsc_fail;
}
- rpmh_invalidate(rsc->disp_rsc);
- /* call flush to disable the disp rsc interrupt */
- rpmh_flush(rsc->disp_rsc);
ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper");
if (ret) {
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index b63fbc6..c87dac4 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -95,6 +95,7 @@
#define SDE_RSCC_F1_QTMR_V1_CNTP_CTL 0x302C
#define MAX_CHECK_LOOPS 500
+#define POWER_CTRL_BIT_12 12
static void rsc_event_trigger(struct sde_rsc_priv *rsc, uint32_t event_type)
{
@@ -191,27 +192,27 @@
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18,
0xa138ebaa, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c,
- 0xe0a581e1, rsc->debug_mode);
+ 0xaca581e1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20,
- 0x82e2a2ed, rsc->debug_mode);
+ 0xe2a2ede0, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24,
- 0x88ea8a39, rsc->debug_mode);
+ 0xea8a3982, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28,
- 0xa6e9a920, rsc->debug_mode);
+ 0xa920888c, rsc->debug_mode);
/* tcs sleep sequence */
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c,
- 0xa92089e6, rsc->debug_mode);
+ 0x89e6a6e9, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30,
- 0x89e7a7e9, rsc->debug_mode);
+ 0xa7e9a920, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x34,
- 0x00000020, rsc->debug_mode);
+ 0x002079e7, rsc->debug_mode);
/* branch address */
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0,
- 0x29, rsc->debug_mode);
+ 0x2b, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0,
- 0x2f, rsc->debug_mode);
+ 0x31, rsc->debug_mode);
return 0;
}
@@ -266,7 +267,7 @@
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0,
mode_0_start_addr, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0,
- 0x80000010, rsc->debug_mode);
+ 0x80000000, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0,
rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0,
@@ -275,7 +276,7 @@
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1,
mode_1_start_addr, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1,
- 0x80000010, rsc->debug_mode);
+ 0x80000000, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1,
rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1,
@@ -284,9 +285,9 @@
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2,
mode_2_start_addr, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2,
- 0x80000010, rsc->debug_mode);
+ 0x80000000, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2,
- rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+ 0x0, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2,
rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
@@ -297,6 +298,7 @@
{
int rc;
int count, wrapper_status;
+ unsigned long reg;
if (rsc->power_collapse_block)
return -EINVAL;
@@ -355,6 +357,18 @@
if (rc) {
pr_err("vdd fs is still enabled\n");
goto end;
+ } else {
+ rc = -EINVAL;
+ /* this wait is required to turn off the rscc clocks */
+ for (count = MAX_CHECK_LOOPS; count > 0; count--) {
+ reg = dss_reg_r(&rsc->wrapper_io,
+ SDE_RSCC_PWR_CTRL, rsc->debug_mode);
+ if (test_bit(POWER_CTRL_BIT_12, ®)) {
+ rc = 0;
+ break;
+ }
+ usleep_range(1, 2);
+ }
}
if ((rsc->current_state == SDE_RSC_VID_STATE) ||
@@ -458,9 +472,6 @@
0x1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
0x0, rsc->debug_mode);
- dss_reg_w(&rsc->drv_io,
- SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, 0x7,
- rsc->debug_mode);
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
reg |= (BIT(0) | BIT(8));
@@ -484,9 +495,6 @@
reg &= ~(BIT(1) | BIT(0));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
- dss_reg_w(&rsc->drv_io,
- SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, 0x5,
- rsc->debug_mode);
/* make sure that solver mode is override */
wmb();
@@ -501,9 +509,6 @@
reg &= ~(BIT(8) | BIT(0));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
- dss_reg_w(&rsc->drv_io,
- SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, 0x5,
- rsc->debug_mode);
/* make sure that solver mode is disabled */
wmb();
break;
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 3c3f99f..fb41f95 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -125,7 +125,7 @@
unsigned int mmu_base = 0, mmu_range = 0, cur_range;
/* enable access protection to privileged registers */
- kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL, 0x00000007);
+ kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL, 0x00000003);
if (mmu_prot) {
mmu_base = mmu_prot->base;
@@ -235,6 +235,9 @@
/* Set the AHB default slave response to "ERROR" */
kgsl_regwrite(device, A6XX_CP_AHB_CNTL, 0x1);
+ /* Turn on performance counters */
+ kgsl_regwrite(device, A6XX_RBBM_PERFCTR_CNTL, 0x1);
+
if (of_property_read_u32(device->pdev->dev.of_node,
"qcom,highest-bank-bit", &bit))
bit = MIN_HBB;
@@ -282,8 +285,9 @@
kgsl_regwrite(device, A6XX_UCHE_MODE_CNTL, (glbl_inv << 29) |
(mal << 23) | (bit << 21));
+ /* Set hang detection threshold to 4 million cycles (0x3FFFF*16) */
kgsl_regwrite(device, A6XX_RBBM_INTERFACE_HANG_INT_CNTL,
- (1 << 30) | 0x4000);
+ (1 << 30) | 0x3ffff);
kgsl_regwrite(device, A6XX_UCHE_CLIENT_PF, 1);
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index ed5b714..1cb0259 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1045,6 +1045,13 @@
*/
if (drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
set_bit(KGSL_FT_DISABLE, &cmdobj->fault_policy);
+ /*
+ * Set the fault tolerance policy to FT_REPLAY - As context wants
+ * to invalidate it after a replay attempt fails. This doesn't
+ * require to execute the default FT policy.
+ */
+ else if (drawctxt->base.flags & KGSL_CONTEXT_INVALIDATE_ON_FAULT)
+ set_bit(KGSL_FT_REPLAY, &cmdobj->fault_policy);
else
cmdobj->fault_policy = adreno_dev->ft_policy;
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index f77d438..f217822 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -342,13 +342,14 @@
struct kgsl_device *device = dev_priv->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int ret;
- unsigned long local;
+ unsigned int local;
local = *flags & (KGSL_CONTEXT_PREAMBLE |
KGSL_CONTEXT_NO_GMEM_ALLOC |
KGSL_CONTEXT_PER_CONTEXT_TS |
KGSL_CONTEXT_USER_GENERATED_TS |
KGSL_CONTEXT_NO_FAULT_TOLERANCE |
+ KGSL_CONTEXT_INVALIDATE_ON_FAULT |
KGSL_CONTEXT_CTX_SWITCH |
KGSL_CONTEXT_PRIORITY_MASK |
KGSL_CONTEXT_TYPE_MASK |
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 32175f5..fbff535 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -54,10 +54,21 @@
/* Read always on registers */
if (!adreno_is_a3xx(adreno_dev)) {
- adreno_readreg64(adreno_dev,
- ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
- ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
- &time->ticks);
+ if (kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) {
+ uint32_t val_lo, val_hi;
+
+ adreno_read_gmureg(adreno_dev,
+ ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO, &val_lo);
+ adreno_read_gmureg(adreno_dev,
+ ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI, &val_hi);
+
+ time->ticks = (val_lo | ((uint64_t)val_hi << 32));
+ } else {
+ adreno_readreg64(adreno_dev,
+ ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
+ ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
+ &time->ticks);
+ }
/* Mask hi bits as they may be incorrect on some targets */
if (ADRENO_GPUREV(adreno_dev) >= 400 &&
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 15f68bf..8f49bc7 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1627,7 +1627,8 @@
/* If no profiling buffer was specified, clear the flag */
if (cmdobj->profiling_buf_entry == NULL)
- DRAWOBJ(cmdobj)->flags &= ~KGSL_DRAWOBJ_PROFILING;
+ DRAWOBJ(cmdobj)->flags &=
+ ~(unsigned long)KGSL_DRAWOBJ_PROFILING;
}
result = device->ftbl->queue_cmds(dev_priv, context, drawobj,
@@ -1716,7 +1717,8 @@
/* If no profiling buffer was specified, clear the flag */
if (cmdobj->profiling_buf_entry == NULL)
- DRAWOBJ(cmdobj)->flags &= ~KGSL_DRAWOBJ_PROFILING;
+ DRAWOBJ(cmdobj)->flags &=
+ ~(unsigned long)KGSL_DRAWOBJ_PROFILING;
}
result = device->ftbl->queue_cmds(dev_priv, context, drawobj,
@@ -2041,7 +2043,7 @@
unsigned long flags_requested = (VM_READ | VM_WRITE);
if (flags & KGSL_MEMFLAGS_GPUREADONLY)
- flags_requested &= ~VM_WRITE;
+ flags_requested &= ~(unsigned long)VM_WRITE;
if ((vma->vm_flags & flags_requested) == flags_requested)
return 0;
@@ -2135,7 +2137,7 @@
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = (uint64_t) size;
entry->memdesc.useraddr = hostptr;
- entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ADDR;
+ entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ADDR;
if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
int ret;
@@ -2166,7 +2168,7 @@
static void _setup_cache_mode(struct kgsl_mem_entry *entry,
struct vm_area_struct *vma)
{
- unsigned int mode;
+ uint64_t mode;
pgprot_t pgprot = vma->vm_page_prot;
if (pgprot_val(pgprot) == pgprot_val(pgprot_noncached(pgprot)))
@@ -2525,7 +2527,7 @@
entry->memdesc.size = 0;
/* USE_CPU_MAP is not impemented for ION. */
entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);
- entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ION;
+ entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ION;
sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
@@ -3028,8 +3030,9 @@
if ((flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT ==
KGSL_CACHEMODE_WRITETHROUGH) {
flags &= ~((uint64_t) KGSL_CACHEMODE_MASK);
- flags |= (KGSL_CACHEMODE_WRITEBACK << KGSL_CACHEMODE_SHIFT) &
- KGSL_CACHEMODE_MASK;
+ flags |= (uint64_t)((KGSL_CACHEMODE_WRITEBACK <<
+ KGSL_CACHEMODE_SHIFT) &
+ KGSL_CACHEMODE_MASK);
}
return flags;
}
@@ -3083,8 +3086,9 @@
KGSL_MAX_ALIGN >> 10);
flags &= ~((uint64_t) KGSL_MEMALIGN_MASK);
- flags |= (ilog2(KGSL_MAX_ALIGN) << KGSL_MEMALIGN_SHIFT) &
- KGSL_MEMALIGN_MASK;
+ flags |= (uint64_t)((ilog2(KGSL_MAX_ALIGN) <<
+ KGSL_MEMALIGN_SHIFT) &
+ KGSL_MEMALIGN_MASK);
}
/* For now only allow allocations up to 4G */
@@ -3975,7 +3979,8 @@
if (param->flags & KGSL_GPUOBJ_SET_INFO_TYPE) {
entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK);
- entry->memdesc.flags |= param->type << KGSL_MEMTYPE_SHIFT;
+ entry->memdesc.flags |= (uint64_t)(param->type <<
+ KGSL_MEMTYPE_SHIFT);
}
kgsl_mem_entry_put(entry);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index d955aa0..db105c5 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -80,6 +80,7 @@
{ KGSL_CONTEXT_PER_CONTEXT_TS, "PER_CONTEXT_TS" }, \
{ KGSL_CONTEXT_USER_GENERATED_TS, "USER_TS" }, \
{ KGSL_CONTEXT_NO_FAULT_TOLERANCE, "NO_FT" }, \
+ { KGSL_CONTEXT_INVALIDATE_ON_FAULT, "INVALIDATE_ON_FAULT" }, \
{ KGSL_CONTEXT_PWR_CONSTRAINT, "PWR" }, \
{ KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 86d4d61..938c96d 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1608,6 +1608,8 @@
ret = PTR_ERR(mmu->defaultpagetable);
mmu->defaultpagetable = NULL;
return ret;
+ } else if (mmu->defaultpagetable == NULL) {
+ return -ENOMEM;
}
}
@@ -2598,7 +2600,7 @@
static const struct {
char *feature;
- int bit;
+ unsigned long bit;
} kgsl_iommu_features[] = {
{ "qcom,retention", KGSL_MMU_RETENTION },
{ "qcom,global_pt", KGSL_MMU_GLOBAL_PAGETABLE },
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index b3e2b6a..a9a3c94 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -67,7 +67,9 @@
"isense_clk",
"rbcpr_clk",
"iref_clk",
- "gmu_clk"
+ "gmu_clk",
+ "ahb_clk",
+ "cxo_clk"
};
static unsigned int ib_votes[KGSL_MAX_BUSLEVELS];
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 62ee597..6b22fd4 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -25,7 +25,7 @@
#define KGSL_PWR_ON 0xFFFF
-#define KGSL_MAX_CLKS 15
+#define KGSL_MAX_CLKS 17
#define KGSL_MAX_REGULATORS 2
#define KGSL_MAX_PWRLEVELS 10
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 07a54d9..7636a42 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -927,8 +927,7 @@
&data->bin.ctxt_aware_target_pwrlevel))
data->bin.ctxt_aware_target_pwrlevel = 1;
- if ((data->bin.ctxt_aware_target_pwrlevel < 0) ||
- (data->bin.ctxt_aware_target_pwrlevel >
+ if ((data->bin.ctxt_aware_target_pwrlevel >
pwr->num_pwrlevels))
data->bin.ctxt_aware_target_pwrlevel = 1;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 10b37ae..dd41e4e 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -131,8 +131,9 @@
if (align > 32)
align = 32;
- memdesc->flags &= ~KGSL_MEMALIGN_MASK;
- memdesc->flags |= (align << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
+ memdesc->flags &= ~(uint64_t)KGSL_MEMALIGN_MASK;
+ memdesc->flags |= (uint64_t)((align << KGSL_MEMALIGN_SHIFT) &
+ KGSL_MEMALIGN_MASK);
return 0;
}
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 94b2e2f9..e233e76 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/clk.h>
+#include <dt-bindings/clock/qcom,aop-qmp.h>
#include <linux/coresight.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
@@ -940,6 +941,14 @@
atomic_t *refcnts = NULL;
struct coresight_device *csdev;
struct coresight_connection *conns = NULL;
+ struct clk *pclk;
+
+ pclk = clk_get(desc->dev, "apb_pclk");
+ if (!IS_ERR(pclk)) {
+ ret = clk_set_rate(pclk, QDSS_CLK_LEVEL_DYNAMIC);
+ if (ret)
+ dev_err(desc->dev, "clk set rate failed\n");
+ }
csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
if (!csdev) {
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e66f404..aac7161 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -69,6 +69,13 @@
struct dm_stats_aux stats_aux;
};
+union map_info *dm_get_rq_mapinfo(struct request *rq)
+{
+ if (rq && rq->end_io_data)
+ return &((struct dm_rq_target_io *)rq->end_io_data)->info;
+ return NULL;
+}
+
#define MINOR_ALLOCED ((void *)-1)
/*
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index c897669..19de267 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
index f8c864f..87707b1 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
@@ -1 +1,3 @@
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o cam_req_mgr_workq.o
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o cam_req_mgr_workq.o cam_mem_mgr.o
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
new file mode 100644
index 0000000..f3ef0e9
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -0,0 +1,968 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-MEM-MGR %s:%d " fmt, __func__, __LINE__
+
+#ifdef CONFIG_MEM_MGR_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+#include <asm/cacheflush.h>
+
+#include "cam_req_mgr_util.h"
+#include "cam_mem_mgr.h"
+#include "cam_smmu_api.h"
+
+static struct cam_mem_table tbl;
+
+static int cam_mem_util_map_cpu_va(struct ion_handle *hdl,
+ uint64_t *vaddr,
+ size_t *len)
+{
+ *vaddr = (uintptr_t)ion_map_kernel(tbl.client, hdl);
+ if (IS_ERR_OR_NULL((void *)*vaddr)) {
+ pr_err("kernel map fail");
+ return -ENOSPC;
+ }
+
+ if (ion_handle_get_size(tbl.client, hdl, len)) {
+ pr_err("kernel get len failed");
+ ion_unmap_kernel(tbl.client, hdl);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+static int cam_mem_util_get_dma_dir(uint32_t flags)
+{
+ int rc = -EINVAL;
+
+ if (flags & CAM_MEM_FLAG_HW_READ_ONLY)
+ rc = DMA_TO_DEVICE;
+ else if (flags & CAM_MEM_FLAG_HW_WRITE_ONLY)
+ rc = DMA_FROM_DEVICE;
+ else if (flags & CAM_MEM_FLAG_HW_READ_WRITE)
+ rc = DMA_BIDIRECTIONAL;
+
+ return rc;
+}
+
+static int cam_mem_util_client_create(void)
+{
+ int rc = 0;
+
+ tbl.client = msm_ion_client_create("camera_global_pool");
+ if (IS_ERR_OR_NULL(tbl.client)) {
+ pr_err("fail to create client\n");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static void cam_mem_util_client_destroy(void)
+{
+ ion_client_destroy(tbl.client);
+ tbl.client = NULL;
+}
+
+int cam_mem_mgr_init(void)
+{
+ int rc;
+ int i;
+ int bitmap_size;
+
+ memset(tbl.bufq, 0, sizeof(tbl.bufq));
+
+ rc = cam_mem_util_client_create();
+ if (rc < 0) {
+ pr_err("fail to create ion client\n");
+ goto client_fail;
+ }
+
+ bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long);
+ tbl.bitmap = kzalloc(sizeof(bitmap_size), GFP_KERNEL);
+ if (!tbl.bitmap) {
+ rc = -ENOMEM;
+ goto bitmap_fail;
+ }
+ tbl.bits = bitmap_size * BITS_PER_BYTE;
+ bitmap_zero(tbl.bitmap, tbl.bits);
+ /* We need to reserve slot 0 because 0 is invalid */
+ set_bit(0, tbl.bitmap);
+
+ for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
+ tbl.bufq[i].fd = -1;
+ tbl.bufq[i].buf_handle = -1;
+ }
+ mutex_init(&tbl.m_lock);
+ return rc;
+
+bitmap_fail:
+ cam_mem_util_client_destroy();
+client_fail:
+ return rc;
+}
+
+static int cam_mem_mgr_cleanup_table(void)
+{
+ int i;
+
+ mutex_lock(&tbl.m_lock);
+ for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
+ if (!tbl.bufq[i].active) {
+ CDBG("Buffer inactive at idx=%d, continuing\n", i);
+ continue;
+ } else {
+ pr_err("Active buffer at idx=%d, possible leak\n", i);
+ }
+
+ mutex_lock(&tbl.bufq[i].q_lock);
+ ion_free(tbl.client, tbl.bufq[i].i_hdl);
+ tbl.bufq[i].fd = -1;
+ tbl.bufq[i].flags = 0;
+ tbl.bufq[i].buf_handle = -1;
+ tbl.bufq[i].vaddr = 0;
+ tbl.bufq[i].len = 0;
+ memset(tbl.bufq[i].hdls, 0,
+ sizeof(int32_t) * tbl.bufq[i].num_hdl);
+ tbl.bufq[i].num_hdl = 0;
+ tbl.bufq[i].i_hdl = NULL;
+ tbl.bufq[i].active = false;
+ mutex_unlock(&tbl.bufq[i].q_lock);
+ mutex_destroy(&tbl.bufq[i].q_lock);
+ }
+ bitmap_zero(tbl.bitmap, tbl.bits);
+ /* We need to reserve slot 0 because 0 is invalid */
+ set_bit(0, tbl.bitmap);
+ mutex_unlock(&tbl.m_lock);
+
+ return 0;
+}
+
+void cam_mem_mgr_deinit(void)
+{
+ cam_mem_mgr_cleanup_table();
+ mutex_lock(&tbl.m_lock);
+ bitmap_zero(tbl.bitmap, tbl.bits);
+ kfree(tbl.bitmap);
+ tbl.bitmap = NULL;
+ cam_mem_util_client_destroy();
+ mutex_unlock(&tbl.m_lock);
+ mutex_destroy(&tbl.m_lock);
+}
+
+static int32_t cam_mem_get_slot(void)
+{
+ int32_t idx;
+
+ mutex_lock(&tbl.m_lock);
+ idx = find_first_zero_bit(tbl.bitmap, tbl.bits);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ mutex_unlock(&tbl.m_lock);
+ return -ENOMEM;
+ }
+
+ set_bit(idx, tbl.bitmap);
+ tbl.bufq[idx].active = true;
+ mutex_init(&tbl.bufq[idx].q_lock);
+ mutex_unlock(&tbl.m_lock);
+
+ return idx;
+}
+
+static void cam_mem_put_slot(int32_t idx)
+{
+ mutex_lock(&tbl.m_lock);
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].active = false;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ mutex_destroy(&tbl.bufq[idx].q_lock);
+ clear_bit(idx, tbl.bitmap);
+ mutex_unlock(&tbl.m_lock);
+}
+
+int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
+ uint64_t *iova_ptr, size_t *len_ptr)
+{
+ int rc = 0, idx;
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+ return -EINVAL;
+
+ if (!tbl.bufq[idx].active)
+ return -EINVAL;
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ if (buf_handle != tbl.bufq[idx].buf_handle) {
+ rc = -EINVAL;
+ goto handle_mismatch;
+ }
+
+ rc = cam_smmu_get_iova(mmu_handle,
+ tbl.bufq[idx].fd,
+ iova_ptr,
+ len_ptr);
+ if (rc < 0)
+ pr_err("fail to get buf hdl :%d", buf_handle);
+
+handle_mismatch:
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_get_io_buf);
+
+int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr, size_t *len)
+{
+ int rc = 0;
+ int idx;
+ struct ion_handle *ion_hdl = NULL;
+ uint64_t kvaddr = 0;
+ size_t klen = 0;
+
+ if (!buf_handle || !vaddr_ptr || !len)
+ return -EINVAL;
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+ return -EINVAL;
+
+ if (!tbl.bufq[idx].active)
+ return -EPERM;
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ if (buf_handle != tbl.bufq[idx].buf_handle) {
+ rc = -EINVAL;
+ goto exit_func;
+ }
+
+ ion_hdl = tbl.bufq[idx].i_hdl;
+ if (!ion_hdl) {
+ pr_err("Invalid ION handle\n");
+ rc = -EINVAL;
+ goto exit_func;
+ }
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) {
+ if (!tbl.bufq[idx].kmdvaddr) {
+ rc = cam_mem_util_map_cpu_va(ion_hdl,
+ &kvaddr, &klen);
+ if (rc)
+ goto exit_func;
+ tbl.bufq[idx].kmdvaddr = kvaddr;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit_func;
+ }
+
+ *vaddr_ptr = tbl.bufq[idx].kmdvaddr;
+ *len = tbl.bufq[idx].len;
+
+exit_func:
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_get_cpu_buf);
+
+int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd)
+{
+ int rc = 0, idx;
+ uint32_t ion_cache_ops;
+ unsigned long ion_flag = 0;
+
+ if (!cmd)
+ return -EINVAL;
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+ return -EINVAL;
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+
+ if (!tbl.bufq[idx].active) {
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ if (cmd->buf_handle != tbl.bufq[idx].buf_handle) {
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ rc = ion_handle_get_flags(tbl.client, tbl.bufq[idx].i_hdl,
+ &ion_flag);
+ if (rc) {
+ pr_err("cache get flags failed %d\n", rc);
+ goto fail;
+ }
+
+ if (ION_IS_CACHED(ion_flag)) {
+ switch (cmd->mem_cache_ops) {
+ case CAM_MEM_CLEAN_CACHE:
+ ion_cache_ops = ION_IOC_CLEAN_CACHES;
+ break;
+ case CAM_MEM_INV_CACHE:
+ ion_cache_ops = ION_IOC_INV_CACHES;
+ break;
+ case CAM_MEM_CLEAN_INV_CACHE:
+ ion_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+ break;
+ default:
+ pr_err("invalid cache ops :%d", cmd->mem_cache_ops);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ rc = msm_ion_do_cache_op(tbl.client,
+ tbl.bufq[idx].i_hdl,
+ (void *)tbl.bufq[idx].vaddr,
+ tbl.bufq[idx].len,
+ ion_cache_ops);
+ if (rc)
+ pr_err("cache operation failed %d\n", rc);
+ }
+fail:
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_cache_ops);
+
+static int cam_mem_util_get_ion_buffer(size_t len,
+ size_t align,
+ unsigned int heap_id_mask,
+ unsigned int flags,
+ struct ion_handle **hdl,
+ int *fd)
+{
+ int rc = 0;
+
+ *hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags);
+ if (IS_ERR_OR_NULL(*hdl))
+ return -ENOMEM;
+
+ *fd = ion_share_dma_buf_fd(tbl.client, *hdl);
+ if (*fd < 0) {
+ pr_err("dma buf get fd fail");
+ rc = -EINVAL;
+ goto get_fd_fail;
+ }
+
+ return rc;
+
+get_fd_fail:
+ ion_free(tbl.client, *hdl);
+ return rc;
+}
+
+static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd,
+ struct ion_handle **hdl,
+ int *fd)
+{
+ uint32_t heap_id;
+ uint32_t ion_flag = 0;
+ int rc;
+
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID);
+ else
+ heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+
+ if (cmd->flags & CAM_MEM_FLAG_CACHE)
+ ion_flag |= ION_FLAG_CACHED;
+ else
+ ion_flag &= ~ION_FLAG_CACHED;
+
+ rc = cam_mem_util_get_ion_buffer(cmd->len,
+ cmd->align,
+ heap_id,
+ ion_flag,
+ hdl,
+ fd);
+
+ return rc;
+}
+
+
+static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd)
+{
+ if (!cmd->flags) {
+ pr_err("Invalid flags\n");
+ return -EINVAL;
+ }
+
+ if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) {
+ pr_err("Num of mmu hdl exceeded maximum(%d)\n",
+ CAM_MEM_MMU_MAX_HANDLE);
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE &&
+ cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) {
+ pr_err("Kernel mapping in secure mode not allowed");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd)
+{
+ if (!cmd->flags) {
+ pr_err("Invalid flags\n");
+ return -EINVAL;
+ }
+
+ if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) {
+ pr_err("Num of mmu hdl exceeded maximum(%d)\n",
+ CAM_MEM_MMU_MAX_HANDLE);
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE &&
+ cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) {
+ pr_err("Kernel mapping in secure mode not allowed");
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+ pr_err("Shared memory buffers are not allowed to be mapped\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cam_mem_util_map_hw_va(uint32_t flags,
+ int32_t *mmu_hdls,
+ int32_t num_hdls,
+ int fd,
+ dma_addr_t *hw_vaddr,
+ size_t *len,
+ enum cam_smmu_region_id region)
+{
+ int i;
+ int rc = -1;
+ int dir = cam_mem_util_get_dma_dir(flags);
+
+ if (dir < 0) {
+ pr_err("fail to map DMA direction\n");
+ return dir;
+ }
+
+ if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_map_sec_iova(mmu_hdls[i],
+ fd,
+ dir,
+ (dma_addr_t *)hw_vaddr,
+ len);
+
+ if (rc < 0) {
+ pr_err("Failed to securely map to smmu");
+ goto multi_map_fail;
+ }
+ }
+ } else {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_map_iova(mmu_hdls[i],
+ fd,
+ dir,
+ (dma_addr_t *)hw_vaddr,
+ len,
+ region);
+
+ if (rc < 0) {
+ pr_err("Failed to map to smmu");
+ goto multi_map_fail;
+ }
+ }
+ }
+
+ return rc;
+multi_map_fail:
+ if (flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ for (--i; i > 0; i--)
+ cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+ else
+ for (--i; i > 0; i--)
+ cam_smmu_unmap_iova(mmu_hdls[i],
+ fd,
+ CAM_SMMU_REGION_IO);
+ return rc;
+
+}
+
+int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd)
+{
+ int rc;
+ int32_t idx;
+ struct ion_handle *ion_hdl;
+ int ion_fd;
+ dma_addr_t hw_vaddr = 0;
+ size_t len;
+
+ if (!cmd) {
+ pr_err(" Invalid argument\n");
+ return -EINVAL;
+ }
+ len = cmd->len;
+
+ rc = cam_mem_util_check_flags(cmd);
+ if (rc) {
+ pr_err("Invalid flags: flags = %X\n", cmd->flags);
+ return rc;
+ }
+
+ rc = cam_mem_util_ion_alloc(cmd,
+ &ion_hdl,
+ &ion_fd);
+ if (rc) {
+ pr_err("Ion allocation failed\n");
+ return rc;
+ }
+
+ idx = cam_mem_get_slot();
+ if (idx < 0) {
+ rc = -ENOMEM;
+ goto slot_fail;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE ||
+ cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+
+ enum cam_smmu_region_id region;
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE)
+ region = CAM_SMMU_REGION_IO;
+
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+ region = CAM_SMMU_REGION_SHARED;
+
+ rc = cam_mem_util_map_hw_va(cmd->flags,
+ cmd->mmu_hdls,
+ cmd->num_hdl,
+ ion_fd,
+ &hw_vaddr,
+ &len,
+ region);
+ if (rc)
+ goto map_hw_fail;
+ }
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].fd = ion_fd;
+ tbl.bufq[idx].flags = cmd->flags;
+ tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, ion_fd);
+ tbl.bufq[idx].kmdvaddr = 0;
+
+ if (cmd->num_hdl > 0)
+ tbl.bufq[idx].vaddr = hw_vaddr;
+ else
+ tbl.bufq[idx].vaddr = 0;
+
+ tbl.bufq[idx].i_hdl = ion_hdl;
+ tbl.bufq[idx].len = cmd->len;
+ tbl.bufq[idx].num_hdl = cmd->num_hdl;
+ memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
+ sizeof(int32_t) * cmd->num_hdl);
+ tbl.bufq[idx].is_imported = false;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+
+ cmd->out.buf_handle = tbl.bufq[idx].buf_handle;
+ cmd->out.fd = tbl.bufq[idx].fd;
+ cmd->out.vaddr = 0;
+
+ CDBG("buf handle: %x, fd: %d, len: %zu\n",
+ cmd->out.buf_handle, cmd->out.fd,
+ tbl.bufq[idx].len);
+
+ return rc;
+
+map_hw_fail:
+ cam_mem_put_slot(idx);
+slot_fail:
+ ion_free(tbl.client, ion_hdl);
+ return rc;
+}
+
+int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd)
+{
+ int32_t idx;
+ int rc;
+ struct ion_handle *ion_hdl;
+ dma_addr_t hw_vaddr = 0;
+ size_t len = 0;
+
+ if (!cmd || (cmd->fd < 0)) {
+ pr_err("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE)
+ return -EINVAL;
+
+ rc = cam_mem_util_check_map_flags(cmd);
+ if (rc) {
+ pr_err("Invalid flags: flags = %X\n", cmd->flags);
+ return rc;
+ }
+
+ ion_hdl = ion_import_dma_buf_fd(tbl.client, cmd->fd);
+ if (IS_ERR_OR_NULL((void *)(ion_hdl))) {
+ pr_err("Failed to import ion fd\n");
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) {
+ rc = cam_mem_util_map_hw_va(cmd->flags,
+ cmd->mmu_hdls,
+ cmd->num_hdl,
+ cmd->fd,
+ &hw_vaddr,
+ &len,
+ CAM_SMMU_REGION_IO);
+ if (rc)
+ goto map_fail;
+ }
+
+ idx = cam_mem_get_slot();
+ if (idx < 0) {
+ rc = -ENOMEM;
+ goto map_fail;
+ }
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].fd = cmd->fd;
+ tbl.bufq[idx].flags = cmd->flags;
+ tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, cmd->fd);
+ tbl.bufq[idx].kmdvaddr = 0;
+
+ if (cmd->num_hdl > 0)
+ tbl.bufq[idx].vaddr = hw_vaddr;
+ else
+ tbl.bufq[idx].vaddr = 0;
+
+ tbl.bufq[idx].i_hdl = ion_hdl;
+ tbl.bufq[idx].len = len;
+ tbl.bufq[idx].num_hdl = cmd->num_hdl;
+ memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
+ sizeof(int32_t) * cmd->num_hdl);
+ tbl.bufq[idx].is_imported = true;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+
+ cmd->out.buf_handle = tbl.bufq[idx].buf_handle;
+ cmd->out.vaddr = 0;
+
+ return rc;
+
+map_fail:
+ ion_free(tbl.client, ion_hdl);
+ return rc;
+}
+
+static int cam_mem_util_unmap_hw_va(int32_t idx,
+ enum cam_smmu_region_id region)
+{
+ int i;
+ uint32_t flags;
+ int32_t *mmu_hdls;
+ int num_hdls;
+ int fd;
+ int rc = -EINVAL;
+
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index\n");
+ return rc;
+ }
+
+ flags = tbl.bufq[idx].flags;
+ mmu_hdls = tbl.bufq[idx].hdls;
+ num_hdls = tbl.bufq[idx].num_hdl;
+ fd = tbl.bufq[idx].fd;
+
+ if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+ if (rc < 0)
+ goto unmap_end;
+ }
+ } else {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_unmap_iova(mmu_hdls[i],
+ fd,
+ region);
+ if (rc < 0)
+ goto unmap_end;
+ }
+ }
+
+unmap_end:
+ return rc;
+}
+
+static int cam_mem_util_unmap(int32_t idx)
+{
+ int rc = 0;
+ enum cam_smmu_region_id region;
+
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index\n");
+ return -EINVAL;
+ }
+
+ CDBG("Flags = %X\n", tbl.bufq[idx].flags);
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)
+ if (tbl.bufq[idx].i_hdl && tbl.bufq[idx].kmdvaddr)
+ ion_unmap_kernel(tbl.client, tbl.bufq[idx].i_hdl);
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE)
+ region = CAM_SMMU_REGION_IO;
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+ region = CAM_SMMU_REGION_SHARED;
+
+ rc = cam_mem_util_unmap_hw_va(idx,
+ region);
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].flags = 0;
+ tbl.bufq[idx].buf_handle = -1;
+ tbl.bufq[idx].vaddr = 0;
+ memset(tbl.bufq[idx].hdls, 0,
+ sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE);
+
+ CDBG("Ion handle at idx = %d freeing = %pK, fd = %d\n",
+ idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd);
+
+ if (tbl.bufq[idx].i_hdl && !tbl.bufq[idx].is_imported) {
+ CDBG("Freeing up non-imported buffer at fd = %d, hdl = %pK",
+ tbl.bufq[idx].fd,
+ tbl.bufq[idx].i_hdl);
+ ion_free(tbl.client, tbl.bufq[idx].i_hdl);
+ tbl.bufq[idx].i_hdl = NULL;
+ } else {
+ CDBG("Not freeing up imported buffer at fd = %d",
+ tbl.bufq[idx].fd);
+ }
+
+ tbl.bufq[idx].fd = -1;
+ tbl.bufq[idx].is_imported = false;
+ tbl.bufq[idx].i_hdl = NULL;
+ tbl.bufq[idx].len = 0;
+ tbl.bufq[idx].num_hdl = 0;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ cam_mem_put_slot(idx);
+
+ return rc;
+}
+
+int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd)
+{
+ int idx;
+ int rc;
+
+ if (!cmd) {
+ pr_err("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index extracted from mem handle\n");
+ return -EINVAL;
+ }
+
+ if (!tbl.bufq[idx].active) {
+ pr_err("Released buffer state should be active\n");
+ return -EINVAL;
+ }
+
+ if (tbl.bufq[idx].buf_handle != cmd->buf_handle) {
+ pr_err("Released buf handle not matching within table\n");
+ return -EINVAL;
+ }
+
+ CDBG("Releasing hdl = %u\n", cmd->buf_handle);
+ rc = cam_mem_util_unmap(idx);
+
+ return rc;
+}
+
+int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
+ struct cam_mem_mgr_memory_desc *out)
+{
+ struct ion_handle *hdl;
+ int ion_fd;
+ int rc = 0;
+ uint32_t heap_id;
+ int32_t ion_flag = 0;
+ uint64_t kvaddr;
+ dma_addr_t iova = 0;
+ size_t request_len = 0;
+ int32_t idx;
+ uint32_t mem_handle;
+ int32_t smmu_hdl = 0;
+ int32_t num_hdl = 0;
+ enum cam_smmu_region_id region;
+
+ if (!inp || !out) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (inp->region != CAM_MEM_MGR_REGION_SHARED &&
+ inp->region != CAM_MEM_MGR_REGION_NON_SECURE_IO) {
+ pr_err("Invalid flags for request mem\n");
+ return -EINVAL;
+ }
+
+ if (inp->flags & CAM_MEM_FLAG_CACHE)
+ ion_flag |= ION_FLAG_CACHED;
+ else
+ ion_flag &= ~ION_FLAG_CACHED;
+
+ heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+
+ rc = cam_mem_util_get_ion_buffer(inp->size,
+ inp->align,
+ heap_id,
+ ion_flag,
+ &hdl,
+ &ion_fd);
+
+ if (rc) {
+ pr_err("ION alloc failed for shared buffer\n");
+ goto ion_fail;
+ } else {
+ CDBG("Got ION fd = %d, hdl = %pK\n", ion_fd, hdl);
+ }
+
+ rc = cam_mem_util_map_cpu_va(hdl, &kvaddr, &request_len);
+ if (rc) {
+ pr_err("Failed to get kernel vaddr\n");
+ goto map_fail;
+ }
+
+ if (!inp->smmu_hdl) {
+ pr_err("Invalid SMMU handle\n");
+ rc = -EINVAL;
+ goto smmu_fail;
+ }
+
+ if (inp->region == CAM_MEM_MGR_REGION_SHARED)
+ region = CAM_SMMU_REGION_SHARED;
+
+ if (inp->region == CAM_MEM_MGR_REGION_NON_SECURE_IO)
+ region = CAM_SMMU_REGION_IO;
+
+ rc = cam_smmu_map_iova(inp->smmu_hdl,
+ ion_fd,
+ CAM_SMMU_MAP_RW,
+ &iova,
+ &request_len,
+ region);
+
+ if (rc < 0) {
+ pr_err("SMMU mapping failed\n");
+ goto smmu_fail;
+ }
+
+ smmu_hdl = inp->smmu_hdl;
+ num_hdl = 1;
+
+ idx = cam_mem_get_slot();
+ if (idx < 0) {
+ rc = -ENOMEM;
+ goto slot_fail;
+ }
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ mem_handle = GET_MEM_HANDLE(idx, ion_fd);
+ tbl.bufq[idx].fd = ion_fd;
+ tbl.bufq[idx].flags = inp->flags;
+ tbl.bufq[idx].buf_handle = mem_handle;
+ tbl.bufq[idx].kmdvaddr = kvaddr;
+
+ tbl.bufq[idx].vaddr = iova;
+
+ tbl.bufq[idx].i_hdl = hdl;
+ tbl.bufq[idx].len = inp->size;
+ tbl.bufq[idx].num_hdl = num_hdl;
+ memcpy(tbl.bufq[idx].hdls, &smmu_hdl,
+ sizeof(int32_t));
+ tbl.bufq[idx].is_imported = false;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+
+ out->kva = kvaddr;
+ out->iova = (uint32_t)iova;
+ out->smmu_hdl = smmu_hdl;
+ out->mem_handle = mem_handle;
+ out->len = inp->size;
+ out->region = inp->region;
+
+ return rc;
+slot_fail:
+ cam_smmu_unmap_iova(inp->smmu_hdl,
+ ion_fd,
+ inp->region);
+smmu_fail:
+ ion_unmap_kernel(tbl.client, hdl);
+map_fail:
+ ion_free(tbl.client, hdl);
+ion_fail:
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_request_mem);
+
+int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp)
+{
+ int32_t idx;
+ int rc;
+
+ if (!inp) {
+ pr_err("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index extracted from mem handle\n");
+ return -EINVAL;
+ }
+
+ if (!tbl.bufq[idx].active) {
+ pr_err("Released buffer state should be active\n");
+ return -EINVAL;
+ }
+
+ if (tbl.bufq[idx].buf_handle != inp->mem_handle) {
+ pr_err("Released buf handle not matching within table\n");
+ return -EINVAL;
+ }
+
+ CDBG("Releasing hdl = %X\n", inp->mem_handle);
+ rc = cam_mem_util_unmap(idx);
+
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_release_mem);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h
new file mode 100644
index 0000000..c5f839b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h
@@ -0,0 +1,121 @@
+/* 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 _CAM_MEM_MGR_H_
+#define _CAM_MEM_MGR_H_
+
+#include <media/cam_req_mgr.h>
+#include "cam_mem_mgr_api.h"
+
+#define CAM_MEM_BUFQ_MAX 1024
+
+/**
+ * struct cam_mem_buf_queue
+ *
+ * @i_hdl: ion handle for the buffer
+ * @q_lock: mutex lock for buffer
+ * @hdls: list of mapped handles
+ * @num_hdl: number of handles
+ * @fd: file descriptor of buffer
+ * @buf_handle: unique handle for buffer
+ * @align: alignment for allocation
+ * @len: size of buffer
+ * @flags: attributes of buffer
+ * @vaddr: IOVA of buffer
+ * @kmdvaddr: Kernel virtual address
+ * @active: state of the buffer
+ * @is_imported: Flag indicating if buffer is imported from an FD in user space
+ */
+struct cam_mem_buf_queue {
+ struct ion_handle *i_hdl;
+ struct mutex q_lock;
+ int32_t hdls[CAM_MEM_MMU_MAX_HANDLE];
+ int32_t num_hdl;
+ int32_t fd;
+ int32_t buf_handle;
+ int32_t align;
+ size_t len;
+ uint32_t flags;
+ uint64_t vaddr;
+ uint64_t kmdvaddr;
+ bool active;
+ bool is_imported;
+};
+
+/**
+ * struct cam_mem_table
+ *
+ * @m_lock: mutex lock for table
+ * @bitmap: bitmap of the mem mgr utility
+ * @bits: max bits of the utility
+ * @client: ion client pointer
+ * @bufq: array of buffers
+ */
+struct cam_mem_table {
+ struct mutex m_lock;
+ void *bitmap;
+ size_t bits;
+ struct ion_client *client;
+ struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX];
+};
+
+/**
+ * @brief: Allocates and maps buffer
+ *
+ * @cmd: Allocation information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd);
+
+/**
+ * @brief: Releases a buffer reference
+ *
+ * @cmd: Buffer release information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd);
+
+/**
+ * @brief Maps a buffer
+ *
+ * @cmd: Buffer mapping information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd);
+
+/**
+ * @brief: Perform cache ops on the buffer
+ *
+ * @cmd: Cache ops information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd);
+
+/**
+ * @brief: Initializes the memory manager
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_init(void);
+
+/**
+ * @brief: Tears down the memory manager
+ *
+ * @return None
+ */
+void cam_mem_mgr_deinit(void);
+
+#endif /* _CAM_MEM_MGR_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
new file mode 100644
index 0000000..32a754e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
@@ -0,0 +1,105 @@
+/* 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 _CAM_MEM_MGR_API_H_
+#define _CAM_MEM_MGR_API_H_
+
+#include <media/cam_req_mgr.h>
+
+/* Region IDs for memory manager */
+#define CAM_MEM_MGR_REGION_FIRMWARE 0
+#define CAM_MEM_MGR_REGION_SHARED 1
+#define CAM_MEM_MGR_REGION_NON_SECURE_IO 2
+#define CAM_MEM_MGR_REGION_SECURE_IO 3
+#define CAM_MEM_MGR_REGION_SCRATCH 4
+
+/**
+ * struct cam_mem_mgr_request_desc
+ *
+ * @size : Size of memory requested for allocation
+ * @align : Alignment of requested memory
+ * @smmu_hdl: SMMU handle to identify context bank where memory will be mapped
+ * @flags : Flags to indicate cached/uncached property
+ * @region : Region where memory should be allocated
+ */
+struct cam_mem_mgr_request_desc {
+ uint64_t size;
+ uint64_t align;
+ int32_t smmu_hdl;
+ uint32_t flags;
+ uint32_t region;
+};
+
+/**
+ * struct cam_mem_mgr_memory_desc
+ *
+ * @kva : Kernel virtual address of allocated memory
+ * @iova : IOVA of allocated memory
+ * @smmu_hdl : SMMU handle of allocated memory
+ * @mem_handle : Mem handle identifying allocated memory
+ * @len : Length of allocated memory
+ * @region : Region to which allocated memory belongs
+ */
+struct cam_mem_mgr_memory_desc {
+ uint64_t kva;
+ uint32_t iova;
+ int32_t smmu_hdl;
+ uint32_t mem_handle;
+ uint64_t len;
+ uint32_t region;
+};
+
+/**
+ * @brief: Requests a memory buffer
+ *
+ * @inp: Information specifying requested buffer properties
+ * @out: Information about allocated buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
+ struct cam_mem_mgr_memory_desc *out);
+
+/**
+ * @brief: Releases a memory buffer
+ *
+ * @inp: Information specifying buffer to be released
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp);
+
+/**
+ * @brief: Returns IOVA information about buffer
+ *
+ * @buf_handle: Handle of the buffer
+ * @mmu_handle: SMMU handle where buffer is mapped
+ * @iova_ptr : Pointer to mmu's iova
+ * @len_ptr : Length of the buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
+ uint64_t *iova_ptr, size_t *len_ptr);
+/**
+ * @brief: Returns CPU address information about buffer
+ *
+ * @buf_handle: Handle for the buffer
+ * @vaddr_ptr : pointer to kernel virtual address
+ * @len_ptr : Length of the buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr,
+ size_t *len);
+
+#endif /* _CAM_MEM_MGR_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index f3af1bd..43b020c6 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, 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
@@ -24,6 +24,7 @@
#include "cam_req_mgr_util.h"
#include "cam_req_mgr_core.h"
#include "cam_subdev.h"
+#include "cam_mem_mgr.h"
#define CAM_REQ_MGR_EVENT_MAX 30
@@ -115,7 +116,18 @@
spin_unlock_bh(&g_dev.cam_eventq_lock);
g_dev.open_cnt++;
+ rc = cam_mem_mgr_init();
+ if (rc) {
+ g_dev.open_cnt--;
+ pr_err("mem mgr init failed\n");
+ goto mem_mgr_init_fail;
+ }
+ mutex_unlock(&g_dev.cam_lock);
+ return rc;
+
+mem_mgr_init_fail:
+ v4l2_fh_release(filep);
end:
mutex_unlock(&g_dev.cam_lock);
return rc;
@@ -154,6 +166,7 @@
spin_unlock_bh(&g_dev.cam_eventq_lock);
cam_req_mgr_util_free_hdls();
+ cam_mem_mgr_deinit();
mutex_unlock(&g_dev.cam_lock);
return 0;
@@ -316,6 +329,84 @@
rc = cam_req_mgr_sync_mode(&sync_mode);
}
break;
+ case CAM_REQ_MGR_ALLOC_BUF: {
+ struct cam_mem_mgr_alloc_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_alloc_and_map(&cmd);
+ if (!rc)
+ if (copy_to_user((void *)k_ioctl->handle,
+ &cmd, k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+ }
+ break;
+ case CAM_REQ_MGR_MAP_BUF: {
+ struct cam_mem_mgr_map_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_map(&cmd);
+ if (!rc)
+ if (copy_to_user((void *)k_ioctl->handle,
+ &cmd, k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+ }
+ break;
+ case CAM_REQ_MGR_RELEASE_BUF: {
+ struct cam_mem_mgr_release_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_release(&cmd);
+ }
+ break;
+ case CAM_REQ_MGR_CACHE_OPS: {
+ struct cam_mem_cache_ops_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_cache_ops(&cmd);
+ if (rc)
+ rc = -EINVAL;
+ }
+ break;
default:
return -ENOIOCTLCMD;
}
@@ -444,6 +535,7 @@
static int cam_req_mgr_remove(struct platform_device *pdev)
{
cam_req_mgr_core_device_deinit();
+ cam_mem_mgr_deinit();
cam_req_mgr_util_deinit();
cam_media_device_cleanup();
cam_video_device_cleanup();
@@ -482,6 +574,12 @@
goto req_mgr_util_fail;
}
+ rc = cam_mem_mgr_init();
+ if (rc) {
+ pr_err("mem mgr init failed\n");
+ goto mem_mgr_init_fail;
+ }
+
rc = cam_req_mgr_core_device_init();
if (rc) {
pr_err("core device setup failed\n");
@@ -493,8 +591,12 @@
return rc;
req_mgr_core_fail:
+ cam_mem_mgr_deinit();
+mem_mgr_init_fail:
cam_req_mgr_util_deinit();
req_mgr_util_fail:
+ mutex_destroy(&g_dev.dev_lock);
+ mutex_destroy(&g_dev.cam_lock);
cam_video_device_cleanup();
video_setup_fail:
cam_media_device_cleanup();
diff --git a/drivers/media/platform/msm/camera/cam_smmu/Makefile b/drivers/media/platform/msm/camera/cam_smmu/Makefile
new file mode 100644
index 0000000..3619da7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu_api.o
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
new file mode 100644
index 0000000..f4215b5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -0,0 +1,2284 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-SMMU %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/workqueue.h>
+#include <linux/genalloc.h>
+
+#include "cam_smmu_api.h"
+
+#define SHARED_MEM_POOL_GRANULARITY 12
+
+#define IOMMU_INVALID_DIR -1
+#define BYTE_SIZE 8
+#define COOKIE_NUM_BYTE 2
+#define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE)
+#define COOKIE_MASK ((1<<COOKIE_SIZE)-1)
+#define HANDLE_INIT (-1)
+#define CAM_SMMU_CB_MAX 2
+
+#define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK))
+#define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK)
+
+#ifdef CONFIG_CAM_SMMU_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+struct firmware_alloc_info {
+ struct device *fw_dev;
+ void *fw_kva;
+ dma_addr_t fw_dma_hdl;
+};
+
+struct firmware_alloc_info icp_fw;
+
+struct cam_smmu_work_payload {
+ int idx;
+ struct iommu_domain *domain;
+ struct device *dev;
+ unsigned long iova;
+ int flags;
+ void *token;
+ struct list_head list;
+};
+
+enum cam_protection_type {
+ CAM_PROT_INVALID,
+ CAM_NON_SECURE,
+ CAM_SECURE,
+ CAM_PROT_MAX,
+};
+
+enum cam_iommu_type {
+ CAM_SMMU_INVALID,
+ CAM_QSMMU,
+ CAM_ARM_SMMU,
+ CAM_SMMU_MAX,
+};
+
+enum cam_smmu_buf_state {
+ CAM_SMMU_BUFF_EXIST,
+ CAM_SMMU_BUFF_NOT_EXIST
+};
+
+enum cam_smmu_init_dir {
+ CAM_SMMU_TABLE_INIT,
+ CAM_SMMU_TABLE_DEINIT,
+};
+
+struct scratch_mapping {
+ void *bitmap;
+ size_t bits;
+ unsigned int order;
+ dma_addr_t base;
+};
+
+struct cam_smmu_region_info {
+ dma_addr_t iova_start;
+ size_t iova_len;
+};
+
+struct cam_context_bank_info {
+ struct device *dev;
+ struct dma_iommu_mapping *mapping;
+ dma_addr_t va_start;
+ size_t va_len;
+ const char *name;
+ bool is_secure;
+ uint8_t scratch_buf_support;
+ uint8_t firmware_support;
+ uint8_t shared_support;
+ uint8_t io_support;
+ bool is_fw_allocated;
+
+ struct scratch_mapping scratch_map;
+ struct gen_pool *shared_mem_pool;
+
+ struct cam_smmu_region_info scratch_info;
+ struct cam_smmu_region_info firmware_info;
+ struct cam_smmu_region_info shared_info;
+ struct cam_smmu_region_info io_info;
+
+ struct list_head smmu_buf_list;
+ struct mutex lock;
+ int handle;
+ enum cam_smmu_ops_param state;
+
+ void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *,
+ struct device *, unsigned long,
+ int, void*);
+ void *token[CAM_SMMU_CB_MAX];
+ int cb_count;
+};
+
+struct cam_iommu_cb_set {
+ struct cam_context_bank_info *cb_info;
+ u32 cb_num;
+ u32 cb_init_count;
+ struct work_struct smmu_work;
+ struct mutex payload_list_lock;
+ struct list_head payload_list;
+};
+
+static const struct of_device_id msm_cam_smmu_dt_match[] = {
+ { .compatible = "qcom,msm-cam-smmu", },
+ { .compatible = "qcom,msm-cam-smmu-cb", },
+ { .compatible = "qcom,msm-cam-smmu-fw-dev", },
+ {}
+};
+
+struct cam_dma_buff_info {
+ struct dma_buf *buf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *table;
+ enum dma_data_direction dir;
+ enum cam_smmu_region_id region_id;
+ int iommu_dir;
+ int ref_count;
+ dma_addr_t paddr;
+ struct list_head list;
+ int ion_fd;
+ size_t len;
+ size_t phys_len;
+};
+
+static struct cam_iommu_cb_set iommu_cb_set;
+
+static enum dma_data_direction cam_smmu_translate_dir(
+ enum cam_smmu_map_dir dir);
+
+static int cam_smmu_check_handle_unique(int hdl);
+
+static int cam_smmu_create_iommu_handle(int idx);
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+ int *hdl);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
+ int ion_fd);
+
+static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
+ dma_addr_t base, size_t size,
+ int order);
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+ size_t size,
+ dma_addr_t *iova);
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+ dma_addr_t addr, size_t size);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+ dma_addr_t virt_addr);
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+ enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr,
+ enum cam_smmu_region_id region_id);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+ size_t virt_len,
+ size_t phys_len,
+ unsigned int iommu_dir,
+ dma_addr_t *virt_addr);
+
+static int cam_smmu_unmap_buf_and_remove_from_list(
+ struct cam_dma_buff_info *mapping_info, int idx);
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+ struct cam_dma_buff_info *mapping_info,
+ int idx);
+
+static void cam_smmu_clean_buffer_list(int idx);
+
+static void cam_smmu_print_list(int idx);
+
+static void cam_smmu_print_table(void);
+
+static int cam_smmu_probe(struct platform_device *pdev);
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr);
+
+static void cam_smmu_page_fault_work(struct work_struct *work)
+{
+ int j;
+ int idx;
+ struct cam_smmu_work_payload *payload;
+
+ mutex_lock(&iommu_cb_set.payload_list_lock);
+ if (list_empty(&iommu_cb_set.payload_list)) {
+ pr_err("Payload list empty\n");
+ mutex_unlock(&iommu_cb_set.payload_list_lock);
+ return;
+ }
+
+ payload = list_first_entry(&iommu_cb_set.payload_list,
+ struct cam_smmu_work_payload,
+ list);
+ list_del(&payload->list);
+ mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+ /* Dereference the payload to call the handler */
+ idx = payload->idx;
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ cam_smmu_check_vaddr_in_range(idx, (void *)payload->iova);
+ for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+ if ((iommu_cb_set.cb_info[idx].handler[j])) {
+ iommu_cb_set.cb_info[idx].handler[j](
+ payload->domain,
+ payload->dev,
+ payload->iova,
+ payload->flags,
+ iommu_cb_set.cb_info[idx].token[j]);
+ }
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ kfree(payload);
+}
+
+static void cam_smmu_print_list(int idx)
+{
+ struct cam_dma_buff_info *mapping;
+
+ pr_err("index = %d\n", idx);
+ list_for_each_entry(mapping,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ pr_err("ion_fd = %d, paddr= 0x%pK, len = %u, region = %d\n",
+ mapping->ion_fd, (void *)mapping->paddr,
+ (unsigned int)mapping->len,
+ mapping->region_id);
+ }
+}
+
+static void cam_smmu_print_table(void)
+{
+ int i;
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ pr_err("i= %d, handle= %d, name_addr=%pK\n", i,
+ (int)iommu_cb_set.cb_info[i].handle,
+ (void *)iommu_cb_set.cb_info[i].name);
+ pr_err("dev = %pK\n", iommu_cb_set.cb_info[i].dev);
+ }
+}
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr)
+{
+ struct cam_dma_buff_info *mapping;
+ unsigned long start_addr, end_addr, current_addr;
+
+ current_addr = (unsigned long)vaddr;
+ list_for_each_entry(mapping,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ start_addr = (unsigned long)mapping->paddr;
+ end_addr = (unsigned long)mapping->paddr + mapping->len;
+
+ if (start_addr <= current_addr && current_addr < end_addr) {
+ pr_err("va %pK valid: range:%pK-%pK, fd = %d cb: %s\n",
+ vaddr, (void *)start_addr, (void *)end_addr,
+ mapping->ion_fd,
+ iommu_cb_set.cb_info[idx].name);
+ goto end;
+ } else {
+ CDBG("va %pK is not in this range: %pK-%pK, fd = %d\n",
+ vaddr, (void *)start_addr, (void *)end_addr,
+ mapping->ion_fd);
+ }
+ }
+ pr_err("Cannot find vaddr:%pK in SMMU %s uses invalid virt address\n",
+ vaddr, iommu_cb_set.cb_info[idx].name);
+end:
+ return;
+}
+
+void cam_smmu_reg_client_page_fault_handler(int handle,
+ void (*client_page_fault_handler)(struct iommu_domain *,
+ struct device *, unsigned long,
+ int, void*), void *token)
+{
+ int idx, i = 0;
+
+ if (!token || (handle == HANDLE_INIT)) {
+ pr_err("Error: token is NULL or invalid handle\n");
+ return;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return;
+ }
+
+ if (client_page_fault_handler) {
+ if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) {
+ pr_err("%s Should not regiester more handlers\n",
+ iommu_cb_set.cb_info[idx].name);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return;
+ }
+ iommu_cb_set.cb_info[idx].cb_count++;
+ for (i = 0; i < iommu_cb_set.cb_info[idx].cb_count; i++) {
+ if (iommu_cb_set.cb_info[idx].token[i] == NULL) {
+ iommu_cb_set.cb_info[idx].token[i] = token;
+ iommu_cb_set.cb_info[idx].handler[i] =
+ client_page_fault_handler;
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < CAM_SMMU_CB_MAX; i++) {
+ if (iommu_cb_set.cb_info[idx].token[i] == token) {
+ iommu_cb_set.cb_info[idx].token[i] = NULL;
+ iommu_cb_set.cb_info[idx].handler[i] =
+ NULL;
+ iommu_cb_set.cb_info[idx].cb_count--;
+ break;
+ }
+ }
+ if (i == CAM_SMMU_CB_MAX)
+ pr_err("Error: hdl %x no matching tokens: %s\n",
+ handle, iommu_cb_set.cb_info[idx].name);
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+}
+
+static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
+ struct device *dev, unsigned long iova,
+ int flags, void *token)
+{
+ char *cb_name;
+ int idx;
+ struct cam_smmu_work_payload *payload;
+
+ if (!token) {
+ pr_err("Error: token is NULL\n");
+ pr_err("Error: domain = %pK, device = %pK\n", domain, dev);
+ pr_err("iova = %lX, flags = %d\n", iova, flags);
+ return 0;
+ }
+
+ cb_name = (char *)token;
+ /* Check whether it is in the table */
+ for (idx = 0; idx < iommu_cb_set.cb_num; idx++) {
+ if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name))
+ break;
+ }
+
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: index is not valid, index = %d, token = %s\n",
+ idx, cb_name);
+ return 0;
+ }
+
+ payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC);
+ if (!payload)
+ return 0;
+
+ payload->domain = domain;
+ payload->dev = dev;
+ payload->iova = iova;
+ payload->flags = flags;
+ payload->token = token;
+ payload->idx = idx;
+
+ mutex_lock(&iommu_cb_set.payload_list_lock);
+ list_add_tail(&payload->list, &iommu_cb_set.payload_list);
+ mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+ schedule_work(&iommu_cb_set.smmu_work);
+
+ return 0;
+}
+
+static int cam_smmu_translate_dir_to_iommu_dir(
+ enum cam_smmu_map_dir dir)
+{
+ switch (dir) {
+ case CAM_SMMU_MAP_READ:
+ return IOMMU_READ;
+ case CAM_SMMU_MAP_WRITE:
+ return IOMMU_WRITE;
+ case CAM_SMMU_MAP_RW:
+ return IOMMU_READ|IOMMU_WRITE;
+ case CAM_SMMU_MAP_INVALID:
+ default:
+ pr_err("Error: Direction is invalid. dir = %d\n", dir);
+ break;
+ };
+ return IOMMU_INVALID_DIR;
+}
+
+static enum dma_data_direction cam_smmu_translate_dir(
+ enum cam_smmu_map_dir dir)
+{
+ switch (dir) {
+ case CAM_SMMU_MAP_READ:
+ return DMA_FROM_DEVICE;
+ case CAM_SMMU_MAP_WRITE:
+ return DMA_TO_DEVICE;
+ case CAM_SMMU_MAP_RW:
+ return DMA_BIDIRECTIONAL;
+ case CAM_SMMU_MAP_INVALID:
+ default:
+ pr_err("Error: Direction is invalid. dir = %d\n", (int)dir);
+ break;
+ }
+ return DMA_NONE;
+}
+
+void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops)
+{
+ unsigned int i;
+ int j = 0;
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ iommu_cb_set.cb_info[i].handle = HANDLE_INIT;
+ INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_list);
+ iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH;
+ iommu_cb_set.cb_info[i].dev = NULL;
+ iommu_cb_set.cb_info[i].cb_count = 0;
+ for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+ iommu_cb_set.cb_info[i].token[j] = NULL;
+ iommu_cb_set.cb_info[i].handler[j] = NULL;
+ }
+ if (ops == CAM_SMMU_TABLE_INIT)
+ mutex_init(&iommu_cb_set.cb_info[i].lock);
+ else
+ mutex_destroy(&iommu_cb_set.cb_info[i].lock);
+ }
+}
+
+static int cam_smmu_check_handle_unique(int hdl)
+{
+ int i;
+
+ if (hdl == HANDLE_INIT) {
+ CDBG("iommu handle is init number. Need to try again\n");
+ return 1;
+ }
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT)
+ continue;
+
+ if (iommu_cb_set.cb_info[i].handle == hdl) {
+ CDBG("iommu handle %d conflicts\n", (int)hdl);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * use low 2 bytes for handle cookie
+ */
+static int cam_smmu_create_iommu_handle(int idx)
+{
+ int rand, hdl = 0;
+
+ get_random_bytes(&rand, COOKIE_NUM_BYTE);
+ hdl = GET_SMMU_HDL(idx, rand);
+ CDBG("create handle value = %x\n", (int)hdl);
+ return hdl;
+}
+
+static int cam_smmu_attach_device(int idx)
+{
+ int rc;
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ /* attach the mapping to device */
+ rc = arm_iommu_attach_device(cb->dev, cb->mapping);
+ if (rc < 0) {
+ pr_err("Error: ARM IOMMU attach failed. ret = %d\n", rc);
+ rc = -ENODEV;
+ }
+
+ return rc;
+}
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+ int *hdl)
+{
+ int i;
+ int handle;
+
+ /* create handle and add in the iommu hardware table */
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ if (!strcmp(iommu_cb_set.cb_info[i].name, name)) {
+ mutex_lock(&iommu_cb_set.cb_info[i].lock);
+ if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) {
+ pr_err("Error: %s already got handle 0x%x\n",
+ name,
+ iommu_cb_set.cb_info[i].handle);
+ mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+ return -EINVAL;
+ }
+
+ /* make sure handle is unique */
+ do {
+ handle = cam_smmu_create_iommu_handle(i);
+ } while (cam_smmu_check_handle_unique(handle));
+
+ /* put handle in the table */
+ iommu_cb_set.cb_info[i].handle = handle;
+ iommu_cb_set.cb_info[i].cb_count = 0;
+ *hdl = handle;
+ CDBG("%s creates handle 0x%x\n", name, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+ return 0;
+ }
+ }
+
+ pr_err("Error: Cannot find name %s or all handle exist!\n",
+ name);
+ cam_smmu_print_table();
+ return -EINVAL;
+}
+
+static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
+ dma_addr_t base, size_t size,
+ int order)
+{
+ unsigned int count = size >> (PAGE_SHIFT + order);
+ unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+ int err = 0;
+
+ if (!count) {
+ err = -EINVAL;
+ pr_err("Page count is zero, size passed = %zu\n", size);
+ goto bail;
+ }
+
+ scratch_map->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!scratch_map->bitmap) {
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ scratch_map->base = base;
+ scratch_map->bits = BITS_PER_BYTE * bitmap_size;
+ scratch_map->order = order;
+
+bail:
+ return err;
+}
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+ size_t size,
+ dma_addr_t *iova)
+{
+ unsigned int order = get_order(size);
+ unsigned int align = 0;
+ unsigned int count, start;
+
+ count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+
+ /*
+ * Transparently, add a guard page to the total count of pages
+ * to be allocated
+ */
+ count++;
+
+ if (order > mapping->order)
+ align = (1 << (order - mapping->order)) - 1;
+
+ start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+ count, align);
+
+ if (start > mapping->bits)
+ return -ENOMEM;
+
+ bitmap_set(mapping->bitmap, start, count);
+ *iova = mapping->base + (start << (mapping->order + PAGE_SHIFT));
+
+ return 0;
+}
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+ dma_addr_t addr, size_t size)
+{
+ unsigned int start = (addr - mapping->base) >>
+ (mapping->order + PAGE_SHIFT);
+ unsigned int count = ((size >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+
+ if (!addr) {
+ pr_err("Error: Invalid address\n");
+ return -EINVAL;
+ }
+
+ if (start + count > mapping->bits) {
+ pr_err("Error: Invalid page bits in scratch map\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Transparently, add a guard page to the total count of pages
+ * to be freed
+ */
+ count++;
+ bitmap_clear(mapping->bitmap, start, count);
+
+ return 0;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+ dma_addr_t virt_addr)
+{
+ struct cam_dma_buff_info *mapping;
+
+ list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->paddr == virt_addr) {
+ CDBG("Found virtual address %lx\n",
+ (unsigned long)virt_addr);
+ return mapping;
+ }
+ }
+
+ pr_err("Error: Cannot find virtual address %lx by index %d\n",
+ (unsigned long)virt_addr, idx);
+ return NULL;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
+ int ion_fd)
+{
+ struct cam_dma_buff_info *mapping;
+
+ list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->ion_fd == ion_fd) {
+ CDBG(" find ion_fd %d\n", ion_fd);
+ return mapping;
+ }
+ }
+
+ pr_err("Error: Cannot find fd %d by index %d\n",
+ ion_fd, idx);
+ return NULL;
+}
+
+static void cam_smmu_clean_buffer_list(int idx)
+{
+ int ret;
+ struct cam_dma_buff_info *mapping_info, *temp;
+
+ list_for_each_entry_safe(mapping_info, temp,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ CDBG("Free mapping address %pK, i = %d, fd = %d\n",
+ (void *)mapping_info->paddr, idx,
+ mapping_info->ion_fd);
+
+ if (mapping_info->ion_fd == 0xDEADBEEF)
+ /* Clean up scratch buffers */
+ ret = cam_smmu_free_scratch_buffer_remove_from_list(
+ mapping_info, idx);
+ else
+ /* Clean up regular mapped buffers */
+ ret = cam_smmu_unmap_buf_and_remove_from_list(
+ mapping_info,
+ idx);
+
+ if (ret < 0) {
+ pr_err("Buffer delete failed: idx = %d\n", idx);
+ pr_err("Buffer delete failed: addr = %lx, fd = %d\n",
+ (unsigned long)mapping_info->paddr,
+ mapping_info->ion_fd);
+ /*
+ * Ignore this error and continue to delete other
+ * buffers in the list
+ */
+ continue;
+ }
+ }
+}
+
+static int cam_smmu_attach(int idx)
+{
+ int ret;
+
+ if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) {
+ ret = -EALREADY;
+ } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+ ret = cam_smmu_attach_device(idx);
+ if (ret < 0) {
+ pr_err("Error: ATTACH fail\n");
+ return -ENODEV;
+ }
+ iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH;
+ ret = 0;
+ } else {
+ pr_err("Error: Not detach/attach: %d\n",
+ iommu_cb_set.cb_info[idx].state);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int cam_smmu_detach_device(int idx)
+{
+ int rc = 0;
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ /* detach the mapping to device if not already detached */
+ if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+ rc = -EALREADY;
+ } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) {
+ arm_iommu_detach_device(cb->dev);
+ iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
+ }
+
+ return rc;
+}
+
+static int cam_smmu_alloc_iova(size_t size,
+ int32_t smmu_hdl, uint32_t *iova)
+{
+ int rc = 0;
+ int idx;
+ uint32_t vaddr = 0;
+
+ if (!iova || !size || (smmu_hdl == HANDLE_INIT)) {
+ pr_err("Error: Input args are invalid\n");
+ return -EINVAL;
+ }
+
+ CDBG("Allocating iova size = %zu for smmu hdl=%X\n", size, smmu_hdl);
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, smmu_hdl);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].shared_support) {
+ pr_err("Error: Shared memory not supported for hdl = %X\n",
+ smmu_hdl);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ vaddr = gen_pool_alloc(iommu_cb_set.cb_info[idx].shared_mem_pool, size);
+ if (!vaddr)
+ return -ENOMEM;
+
+ *iova = vaddr;
+
+get_addr_end:
+ return rc;
+}
+
+static int cam_smmu_free_iova(uint32_t addr, size_t size,
+ int32_t smmu_hdl)
+{
+ int rc = 0;
+ int idx;
+
+ if (!size || (smmu_hdl == HANDLE_INIT)) {
+ pr_err("Error: Input args are invalid\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, smmu_hdl);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ gen_pool_free(iommu_cb_set.cb_info[idx].shared_mem_pool, addr, size);
+
+get_addr_end:
+ return rc;
+}
+
+int cam_smmu_alloc_firmware(int32_t smmu_hdl,
+ dma_addr_t *iova,
+ uint64_t *cpuva,
+ size_t *len)
+{
+ int rc;
+ int32_t idx;
+ size_t firmware_len = 0;
+ size_t firmware_start = 0;
+ struct iommu_domain *domain;
+
+ if (!iova || !len || !cpuva || (smmu_hdl == HANDLE_INIT)) {
+ pr_err("Error: Input args are invalid\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].firmware_support) {
+ pr_err("Firmware memory not supported for this SMMU handle\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].is_fw_allocated) {
+ pr_err("Trying to allocate twice\n");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ }
+
+ firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len;
+ firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+ CDBG("Firmware area len from DT = %zu\n", firmware_len);
+
+ icp_fw.fw_kva = dma_alloc_coherent(icp_fw.fw_dev,
+ firmware_len,
+ &icp_fw.fw_dma_hdl,
+ GFP_KERNEL);
+ if (!icp_fw.fw_kva) {
+ pr_err("FW memory alloc failed\n");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ } else {
+ CDBG("DMA alloc returned fw = %pK, hdl = %pK\n",
+ icp_fw.fw_kva, (void *)icp_fw.fw_dma_hdl);
+ }
+
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ rc = iommu_map(domain,
+ firmware_start,
+ icp_fw.fw_dma_hdl,
+ firmware_len,
+ IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV);
+
+ if (rc) {
+ pr_err("Failed to map FW into IOMMU\n");
+ rc = -ENOMEM;
+ goto alloc_fail;
+ }
+ iommu_cb_set.cb_info[idx].is_fw_allocated = true;
+
+ *iova = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+ *cpuva = (uint64_t)icp_fw.fw_kva;
+ *len = firmware_len;
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+
+ return rc;
+
+alloc_fail:
+ dma_free_coherent(icp_fw.fw_dev,
+ firmware_len,
+ icp_fw.fw_kva,
+ icp_fw.fw_dma_hdl);
+unlock_and_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_alloc_firmware);
+
+int cam_smmu_dealloc_firmware(int32_t smmu_hdl)
+{
+ int rc = 0;
+ int32_t idx;
+ size_t firmware_len = 0;
+ size_t firmware_start = 0;
+ struct iommu_domain *domain;
+ size_t unmapped = 0;
+
+ if (smmu_hdl == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].firmware_support) {
+ pr_err("Firmware memory not supported for this SMMU handle\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (!iommu_cb_set.cb_info[idx].is_fw_allocated) {
+ pr_err("Trying to deallocate firmware that is not allocated\n");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ }
+
+ firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len;
+ firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ unmapped = iommu_unmap(domain,
+ firmware_start,
+ firmware_len);
+
+ if (unmapped != firmware_len) {
+ pr_err("Only %zu unmapped out of total %zu\n",
+ unmapped,
+ firmware_len);
+ rc = -EINVAL;
+ }
+
+ dma_free_coherent(icp_fw.fw_dev,
+ firmware_len,
+ icp_fw.fw_kva,
+ icp_fw.fw_dma_hdl);
+
+ icp_fw.fw_kva = 0;
+ icp_fw.fw_dma_hdl = 0;
+
+ iommu_cb_set.cb_info[idx].is_fw_allocated = false;
+
+unlock_and_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_dealloc_firmware);
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+ enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr,
+ enum cam_smmu_region_id region_id)
+{
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+ struct dma_buf *buf = NULL;
+ struct dma_buf_attachment *attach = NULL;
+ struct sg_table *table = NULL;
+ struct iommu_domain *domain;
+ size_t size = 0;
+ uint32_t iova = 0;
+
+ /* allocate memory for each buffer information */
+ buf = dma_buf_get(ion_fd);
+ if (IS_ERR_OR_NULL(buf)) {
+ rc = PTR_ERR(buf);
+ pr_err("Error: dma get buf failed. fd = %d\n", ion_fd);
+ goto err_out;
+ }
+
+ attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ rc = PTR_ERR(attach);
+ pr_err("Error: dma buf attach failed\n");
+ goto err_put;
+ }
+
+ table = dma_buf_map_attachment(attach, dma_dir);
+ if (IS_ERR_OR_NULL(table)) {
+ rc = PTR_ERR(table);
+ pr_err("Error: dma buf map attachment failed\n");
+ goto err_detach;
+ }
+
+ if (region_id == CAM_SMMU_REGION_SHARED) {
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ if (!domain) {
+ pr_err("CB has no domain set\n");
+ goto err_unmap_sg;
+ }
+
+ rc = cam_smmu_alloc_iova(*len_ptr,
+ iommu_cb_set.cb_info[idx].handle,
+ &iova);
+
+ if (rc < 0) {
+ pr_err("IOVA alloc failed for shared memory\n");
+ goto err_unmap_sg;
+ }
+
+ size = iommu_map_sg(domain,
+ iova,
+ table->sgl,
+ table->nents,
+ IOMMU_READ | IOMMU_WRITE);
+
+ if (size < 0) {
+ pr_err("IOMMU mapping failed\n");
+ rc = cam_smmu_free_iova(iova,
+ size,
+ iommu_cb_set.cb_info[idx].handle);
+
+ if (rc)
+ pr_err("IOVA free failed\n");
+ rc = -ENOMEM;
+ goto err_unmap_sg;
+ } else {
+ CDBG("iommu_map_sg returned %zu\n", size);
+ *paddr_ptr = iova;
+ *len_ptr = size;
+ }
+ } else if (region_id == CAM_SMMU_REGION_IO) {
+ rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev,
+ table->sgl, table->nents, dma_dir, buf);
+
+ if (rc != table->nents) {
+ pr_err("Error: msm_dma_map_sg_lazy failed\n");
+ rc = -ENOMEM;
+ goto err_unmap_sg;
+ } else {
+ *paddr_ptr = sg_dma_address(table->sgl);
+ *len_ptr = (size_t)sg_dma_len(table->sgl);
+ }
+ } else {
+ pr_err("Error: Wrong region id passed for %s\n", __func__);
+ rc = -EINVAL;
+ goto err_unmap_sg;
+ }
+
+ if (table->sgl) {
+ CDBG("DMA buf: %pK, device: %pK, attach: %pK, table: %pK\n",
+ (void *)buf,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)attach, (void *)table);
+ CDBG("table sgl: %pK, rc: %d, dma_address: 0x%x\n",
+ (void *)table->sgl, rc,
+ (unsigned int)table->sgl->dma_address);
+ } else {
+ rc = -EINVAL;
+ pr_err("Error: table sgl is null\n");
+ goto err_unmap_sg;
+ }
+
+ /* fill up mapping_info */
+ mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+ if (!mapping_info) {
+ rc = -ENOSPC;
+ goto err_alloc;
+ }
+ mapping_info->ion_fd = ion_fd;
+ mapping_info->buf = buf;
+ mapping_info->attach = attach;
+ mapping_info->table = table;
+ mapping_info->paddr = *paddr_ptr;
+ mapping_info->len = *len_ptr;
+ mapping_info->dir = dma_dir;
+ mapping_info->ref_count = 1;
+ mapping_info->region_id = region_id;
+
+ if (!*paddr_ptr || !*len_ptr) {
+ pr_err("Error: Space Allocation failed!\n");
+ kfree(mapping_info);
+ rc = -ENOSPC;
+ goto err_alloc;
+ }
+ CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+ /* add to the list */
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+ return 0;
+
+err_alloc:
+ if (region_id == CAM_SMMU_REGION_SHARED) {
+ cam_smmu_free_iova(iova,
+ size,
+ iommu_cb_set.cb_info[idx].handle);
+
+ iommu_unmap(iommu_cb_set.cb_info[idx].mapping->domain,
+ *paddr_ptr,
+ *len_ptr);
+ } else if (region_id == CAM_SMMU_REGION_IO) {
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ table->sgl,
+ table->nents,
+ dma_dir,
+ buf);
+ }
+err_unmap_sg:
+ dma_buf_unmap_attachment(attach, table, dma_dir);
+err_detach:
+ dma_buf_detach(buf, attach);
+err_put:
+ dma_buf_put(buf);
+err_out:
+ return rc;
+}
+
+static int cam_smmu_unmap_buf_and_remove_from_list(
+ struct cam_dma_buff_info *mapping_info,
+ int idx)
+{
+ int rc;
+ size_t size;
+ struct iommu_domain *domain;
+
+ if ((!mapping_info->buf) || (!mapping_info->table) ||
+ (!mapping_info->attach)) {
+ pr_err("Error: Invalid params dev = %pK, table = %pK\n",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)mapping_info->table);
+ pr_err("Error:dma_buf = %pK, attach = %pK\n",
+ (void *)mapping_info->buf,
+ (void *)mapping_info->attach);
+ return -EINVAL;
+ }
+
+ if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) {
+ CDBG("Removing SHARED buffer paddr = %pK, len = %zu\n",
+ (void *)mapping_info->paddr, mapping_info->len);
+
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+
+ size = iommu_unmap(domain,
+ mapping_info->paddr,
+ mapping_info->len);
+
+ if (size != mapping_info->len) {
+ pr_err("IOMMU unmap failed\n");
+ pr_err("Unmapped = %zu, requested = %zu\n",
+ size,
+ mapping_info->len);
+ }
+
+ rc = cam_smmu_free_iova(mapping_info->paddr,
+ mapping_info->len,
+ iommu_cb_set.cb_info[idx].handle);
+
+ if (rc)
+ pr_err("IOVA free failed\n");
+
+ } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) {
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ mapping_info->table->sgl, mapping_info->table->nents,
+ mapping_info->dir, mapping_info->buf);
+ }
+
+ dma_buf_unmap_attachment(mapping_info->attach,
+ mapping_info->table, mapping_info->dir);
+ dma_buf_detach(mapping_info->buf, mapping_info->attach);
+ dma_buf_put(mapping_info->buf);
+
+ mapping_info->buf = NULL;
+
+ list_del_init(&mapping_info->list);
+
+ /* free one buffer */
+ kfree(mapping_info);
+ return 0;
+}
+
+static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx,
+ int ion_fd, dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ struct cam_dma_buff_info *mapping;
+
+ list_for_each_entry(mapping,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ if (mapping->ion_fd == ion_fd) {
+ mapping->ref_count++;
+ *paddr_ptr = mapping->paddr;
+ *len_ptr = mapping->len;
+ return CAM_SMMU_BUFF_EXIST;
+ }
+ }
+
+ return CAM_SMMU_BUFF_NOT_EXIST;
+}
+
+int cam_smmu_get_handle(char *identifier, int *handle_ptr)
+{
+ int ret = 0;
+
+ if (!identifier) {
+ pr_err("Error: iommu hardware name is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!handle_ptr) {
+ pr_err("Error: handle pointer is NULL\n");
+ return -EINVAL;
+ }
+
+ /* create and put handle in the table */
+ ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr);
+ if (ret < 0)
+ pr_err("Error: %s get handle fail\n", identifier);
+
+ return ret;
+}
+EXPORT_SYMBOL(cam_smmu_get_handle);
+
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
+{
+ int ret = 0, idx;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: Index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return -EINVAL;
+ }
+
+ switch (ops) {
+ case CAM_SMMU_ATTACH: {
+ ret = cam_smmu_attach(idx);
+ break;
+ }
+ case CAM_SMMU_DETACH: {
+ ret = cam_smmu_detach_device(idx);
+ break;
+ }
+ case CAM_SMMU_VOTE:
+ case CAM_SMMU_DEVOTE:
+ default:
+ pr_err("Error: idx = %d, ops = %d\n", idx, ops);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return ret;
+}
+EXPORT_SYMBOL(cam_smmu_ops);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+ size_t virt_len,
+ size_t phys_len,
+ unsigned int iommu_dir,
+ dma_addr_t *virt_addr)
+{
+ unsigned long nents = virt_len / phys_len;
+ struct cam_dma_buff_info *mapping_info = NULL;
+ size_t unmapped;
+ dma_addr_t iova = 0;
+ struct scatterlist *sg;
+ int i = 0;
+ int rc;
+ struct iommu_domain *domain = NULL;
+ struct page *page;
+ struct sg_table *table = NULL;
+
+ CDBG("%s: nents = %lu, idx = %d, virt_len = %zx\n",
+ __func__, nents, idx, virt_len);
+ CDBG("%s: phys_len = %zx, iommu_dir = %d, virt_addr = %pK\n",
+ __func__, phys_len, iommu_dir, virt_addr);
+
+ /*
+ * This table will go inside the 'mapping' structure
+ * where it will be held until put_scratch_buffer is called
+ */
+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!table) {
+ rc = -ENOMEM;
+ goto err_table_alloc;
+ }
+
+ rc = sg_alloc_table(table, nents, GFP_KERNEL);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto err_sg_alloc;
+ }
+
+ page = alloc_pages(GFP_KERNEL, get_order(phys_len));
+ if (!page) {
+ rc = -ENOMEM;
+ goto err_page_alloc;
+ }
+
+ /* Now we create the sg list */
+ for_each_sg(table->sgl, sg, table->nents, i)
+ sg_set_page(sg, page, phys_len, 0);
+
+
+ /* Get the domain from within our cb_set struct and map it*/
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+
+ rc = cam_smmu_alloc_scratch_va(&iommu_cb_set.cb_info[idx].scratch_map,
+ virt_len, &iova);
+
+ if (rc < 0) {
+ pr_err("Could not find valid iova for scratch buffer");
+ goto err_iommu_map;
+ }
+
+ if (iommu_map_sg(domain,
+ iova,
+ table->sgl,
+ table->nents,
+ iommu_dir) != virt_len) {
+ pr_err("iommu_map_sg() failed");
+ goto err_iommu_map;
+ }
+
+ /* Now update our mapping information within the cb_set struct */
+ mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+ if (!mapping_info) {
+ rc = -ENOMEM;
+ goto err_mapping_info;
+ }
+
+ mapping_info->ion_fd = 0xDEADBEEF;
+ mapping_info->buf = NULL;
+ mapping_info->attach = NULL;
+ mapping_info->table = table;
+ mapping_info->paddr = iova;
+ mapping_info->len = virt_len;
+ mapping_info->iommu_dir = iommu_dir;
+ mapping_info->ref_count = 1;
+ mapping_info->phys_len = phys_len;
+ mapping_info->region_id = CAM_SMMU_REGION_SCRATCH;
+
+ CDBG("%s: paddr = %pK, len = %zx, phys_len = %zx",
+ __func__, (void *)mapping_info->paddr,
+ mapping_info->len, mapping_info->phys_len);
+
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+ *virt_addr = (dma_addr_t)iova;
+
+ CDBG("%s: mapped virtual address = %lx\n", __func__,
+ (unsigned long)*virt_addr);
+ return 0;
+
+err_mapping_info:
+ unmapped = iommu_unmap(domain, iova, virt_len);
+ if (unmapped != virt_len)
+ pr_err("Unmapped only %zx instead of %zx", unmapped, virt_len);
+err_iommu_map:
+ __free_pages(page, get_order(phys_len));
+err_page_alloc:
+ sg_free_table(table);
+err_sg_alloc:
+ kfree(table);
+err_table_alloc:
+ return rc;
+}
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+ struct cam_dma_buff_info *mapping_info,
+ int idx)
+{
+ int rc = 0;
+ size_t unmapped;
+ struct iommu_domain *domain =
+ iommu_cb_set.cb_info[idx].mapping->domain;
+ struct scratch_mapping *scratch_map =
+ &iommu_cb_set.cb_info[idx].scratch_map;
+
+ if (!mapping_info->table) {
+ pr_err("Error: Invalid params: dev = %pK, table = %pK",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)mapping_info->table);
+ return -EINVAL;
+ }
+
+ /* Clean up the mapping_info struct from the list */
+ unmapped = iommu_unmap(domain, mapping_info->paddr, mapping_info->len);
+ if (unmapped != mapping_info->len)
+ pr_err("Unmapped only %zx instead of %zx",
+ unmapped, mapping_info->len);
+
+ rc = cam_smmu_free_scratch_va(scratch_map,
+ mapping_info->paddr,
+ mapping_info->len);
+ if (rc < 0) {
+ pr_err("Error: Invalid iova while freeing scratch buffer\n");
+ rc = -EINVAL;
+ }
+
+ __free_pages(sg_page(mapping_info->table->sgl),
+ get_order(mapping_info->phys_len));
+ sg_free_table(mapping_info->table);
+ kfree(mapping_info->table);
+ list_del_init(&mapping_info->list);
+
+ kfree(mapping_info);
+ mapping_info = NULL;
+
+ return rc;
+}
+
+int cam_smmu_get_scratch_iova(int handle,
+ enum cam_smmu_map_dir dir,
+ dma_addr_t *paddr_ptr,
+ size_t virt_len,
+ size_t phys_len)
+{
+ int idx, rc;
+ unsigned int iommu_dir;
+
+ if (!paddr_ptr || !virt_len || !phys_len) {
+ pr_err("Error: Input pointer or lengths invalid\n");
+ return -EINVAL;
+ }
+
+ if (virt_len < phys_len) {
+ pr_err("Error: virt_len > phys_len\n");
+ return -EINVAL;
+ }
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ iommu_dir = cam_smmu_translate_dir_to_iommu_dir(dir);
+ if (iommu_dir == IOMMU_INVALID_DIR) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+ pr_err("Error: Context bank does not support scratch bufs\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n",
+ __func__, handle, idx, dir);
+ CDBG("%s: virt_len = %zx, phys_len = %zx\n",
+ __func__, phys_len, virt_len);
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Err:Dev %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!IS_ALIGNED(virt_len, PAGE_SIZE)) {
+ pr_err("Requested scratch buffer length not page aligned\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!IS_ALIGNED(virt_len, phys_len)) {
+ pr_err("Requested virt length not aligned with phys length\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = cam_smmu_alloc_scratch_buffer_add_to_list(idx,
+ virt_len,
+ phys_len,
+ iommu_dir,
+ paddr_ptr);
+ if (rc < 0)
+ pr_err("Error: mapping or add list fail\n");
+
+error:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_put_scratch_iova(int handle,
+ dma_addr_t paddr)
+{
+ int idx;
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+ pr_err("Error: Context bank does not support scratch buffers\n");
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ /* Based on virtual address and index, we can find mapping info
+ * of the scratch buffer
+ */
+ mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params\n");
+ rc = -ENODEV;
+ goto handle_err;
+ }
+
+ /* unmapping one buffer from device */
+ rc = cam_smmu_free_scratch_buffer_remove_from_list(mapping_info, idx);
+ if (rc < 0) {
+ pr_err("Error: unmap or remove list fail\n");
+ goto handle_err;
+ }
+
+handle_err:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_map_sec_iova(int handle, int ion_fd,
+ enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ /* not implemented yet */
+ return -EPERM;
+}
+EXPORT_SYMBOL(cam_smmu_map_sec_iova);
+
+int cam_smmu_map_iova(int handle, int ion_fd,
+ enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr, enum cam_smmu_region_id region_id)
+{
+ int idx, rc;
+ enum dma_data_direction dma_dir;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Input pointers are invalid\n");
+ return -EINVAL;
+ }
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ if (region_id != CAM_SMMU_REGION_SHARED)
+ *len_ptr = (size_t)0;
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Err:Dev %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr,
+ len_ptr);
+ if (buf_state == CAM_SMMU_BUFF_EXIST) {
+ CDBG("ion_fd:%d already in the list, give same addr back",
+ ion_fd);
+ rc = 0;
+ goto get_addr_end;
+ }
+ rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+ paddr_ptr, len_ptr, region_id);
+ if (rc < 0)
+ pr_err("mapping or add list fail\n");
+
+get_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_map_iova);
+
+
+int cam_smmu_get_iova(int handle, int ion_fd,
+ dma_addr_t *paddr_ptr, size_t *len_ptr)
+{
+ int idx, rc = 0;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Error: Input pointers are invalid\n");
+ return -EINVAL;
+ }
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
+ if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) {
+ CDBG("ion_fd:%d not in the mapped list", ion_fd);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+get_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_get_iova);
+
+int cam_smmu_unmap_sec_iova(int handle, int ion_fd)
+{
+ /* not implemented yet */
+ return -EPERM;
+}
+EXPORT_SYMBOL(cam_smmu_unmap_sec_iova);
+
+int cam_smmu_unmap_iova(int handle,
+ int ion_fd,
+ enum cam_smmu_region_id region_id)
+{
+ int idx, rc;
+ struct cam_dma_buff_info *mapping_info;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto unmap_end;
+ }
+
+ /* Based on ion fd and index, we can find mapping info of buffer */
+ mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+ idx, ion_fd);
+ rc = -EINVAL;
+ goto unmap_end;
+ }
+
+ mapping_info->ref_count--;
+ if (mapping_info->ref_count > 0) {
+ CDBG("There are still %u buffer(s) with same fd %d",
+ mapping_info->ref_count, mapping_info->ion_fd);
+ rc = 0;
+ goto unmap_end;
+ }
+
+ /* Unmapping one buffer from device */
+ CDBG("SMMU: removing buffer idx = %d\n", idx);
+ rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx);
+ if (rc < 0)
+ pr_err("Error: unmap or remove list fail\n");
+
+unmap_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_unmap_iova);
+
+int cam_smmu_put_iova(int handle, int ion_fd)
+{
+ int idx;
+ int rc = 0;
+ struct cam_dma_buff_info *mapping_info;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ /* based on ion fd and index, we can find mapping info of buffer */
+ mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+ idx, ion_fd);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ mapping_info->ref_count--;
+
+put_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_put_iova);
+
+int cam_smmu_destroy_handle(int handle)
+{
+ int idx;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return -EINVAL;
+ }
+
+ if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) {
+ pr_err("Client %s buffer list is not clean!\n",
+ iommu_cb_set.cb_info[idx].name);
+ cam_smmu_print_list(idx);
+ cam_smmu_clean_buffer_list(idx);
+ }
+
+ iommu_cb_set.cb_info[idx].cb_count = 0;
+ iommu_cb_set.cb_info[idx].handle = HANDLE_INIT;
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return 0;
+}
+EXPORT_SYMBOL(cam_smmu_destroy_handle);
+
+static void cam_smmu_deinit_cb(struct cam_context_bank_info *cb)
+{
+ arm_iommu_detach_device(cb->dev);
+
+ if (cb->io_support && cb->mapping) {
+ arm_iommu_release_mapping(cb->mapping);
+ cb->mapping = NULL;
+ }
+
+ if (cb->shared_support) {
+ gen_pool_destroy(cb->shared_mem_pool);
+ cb->shared_mem_pool = NULL;
+ }
+
+ if (cb->scratch_buf_support) {
+ kfree(cb->scratch_map.bitmap);
+ cb->scratch_map.bitmap = NULL;
+ }
+}
+
+static void cam_smmu_release_cb(struct platform_device *pdev)
+{
+ int i = 0;
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++)
+ cam_smmu_deinit_cb(&iommu_cb_set.cb_info[i]);
+
+ devm_kfree(&pdev->dev, iommu_cb_set.cb_info);
+ iommu_cb_set.cb_num = 0;
+}
+
+static int cam_smmu_setup_cb(struct cam_context_bank_info *cb,
+ struct device *dev)
+{
+ int rc = 0;
+
+ if (!cb || !dev) {
+ pr_err("Error: invalid input params\n");
+ return -EINVAL;
+ }
+
+ cb->dev = dev;
+ cb->is_fw_allocated = false;
+
+ /* Create a pool with 4K granularity for supporting shared memory */
+ if (cb->shared_support) {
+ cb->shared_mem_pool = gen_pool_create(
+ SHARED_MEM_POOL_GRANULARITY, -1);
+
+ if (!cb->shared_mem_pool)
+ return -ENOMEM;
+
+ rc = gen_pool_add(cb->shared_mem_pool,
+ cb->shared_info.iova_start,
+ cb->shared_info.iova_len,
+ -1);
+
+ CDBG("Shared mem start->%lX\n",
+ (unsigned long)cb->shared_info.iova_start);
+ CDBG("Shared mem len->%zu\n", cb->shared_info.iova_len);
+
+ if (rc) {
+ pr_err("Genpool chunk creation failed\n");
+ gen_pool_destroy(cb->shared_mem_pool);
+ cb->shared_mem_pool = NULL;
+ return rc;
+ }
+ }
+
+ if (cb->scratch_buf_support) {
+ rc = cam_smmu_init_scratch_map(&cb->scratch_map,
+ cb->scratch_info.iova_start,
+ cb->scratch_info.iova_len,
+ 0);
+ if (rc < 0) {
+ pr_err("Error: failed to create scratch map\n");
+ rc = -ENODEV;
+ goto end;
+ }
+ }
+
+ /* create a virtual mapping */
+ if (cb->io_support) {
+ cb->mapping = arm_iommu_create_mapping(&platform_bus_type,
+ cb->io_info.iova_start, cb->io_info.iova_len);
+ if (IS_ERR(cb->mapping)) {
+ pr_err("Error: create mapping Failed\n");
+ rc = -ENODEV;
+ goto end;
+ }
+ } else {
+ pr_err("Context bank does not have IO region\n");
+ rc = -ENODEV;
+ goto end;
+ }
+
+ return rc;
+end:
+ if (cb->shared_support) {
+ gen_pool_destroy(cb->shared_mem_pool);
+ cb->shared_mem_pool = NULL;
+ }
+
+ if (cb->scratch_buf_support) {
+ kfree(cb->scratch_map.bitmap);
+ cb->scratch_map.bitmap = NULL;
+ }
+
+ return rc;
+}
+
+static int cam_alloc_smmu_context_banks(struct device *dev)
+{
+ struct device_node *domains_child_node = NULL;
+
+ if (!dev) {
+ pr_err("Error: Invalid device\n");
+ return -ENODEV;
+ }
+
+ iommu_cb_set.cb_num = 0;
+
+ /* traverse thru all the child nodes and increment the cb count */
+ for_each_available_child_of_node(dev->of_node, domains_child_node) {
+ if (of_device_is_compatible(domains_child_node,
+ "qcom,msm-cam-smmu-cb"))
+ iommu_cb_set.cb_num++;
+
+ if (of_device_is_compatible(domains_child_node,
+ "qcom,qsmmu-cam-cb"))
+ iommu_cb_set.cb_num++;
+ }
+
+ if (iommu_cb_set.cb_num == 0) {
+ pr_err("Error: no context banks present\n");
+ return -ENOENT;
+ }
+
+ /* allocate memory for the context banks */
+ iommu_cb_set.cb_info = devm_kzalloc(dev,
+ iommu_cb_set.cb_num * sizeof(struct cam_context_bank_info),
+ GFP_KERNEL);
+
+ if (!iommu_cb_set.cb_info) {
+ pr_err("Error: cannot allocate context banks\n");
+ return -ENOMEM;
+ }
+
+ cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_INIT);
+ iommu_cb_set.cb_init_count = 0;
+
+ CDBG("no of context banks :%d\n", iommu_cb_set.cb_num);
+ return 0;
+}
+
+static int cam_smmu_get_memory_regions_info(struct device_node *of_node,
+ struct cam_context_bank_info *cb)
+{
+ int rc = 0;
+ struct device_node *mem_map_node = NULL;
+ struct device_node *child_node = NULL;
+ const char *region_name;
+ int num_regions = 0;
+
+ if (!of_node || !cb) {
+ pr_err("Invalid argument(s)\n");
+ return -EINVAL;
+ }
+
+ mem_map_node = of_get_child_by_name(of_node, "iova-mem-map");
+ if (!mem_map_node) {
+ pr_err("iova-mem-map not present\n");
+ return -EINVAL;
+ }
+
+ for_each_available_child_of_node(mem_map_node, child_node) {
+ uint32_t region_start;
+ uint32_t region_len;
+ uint32_t region_id;
+
+ num_regions++;
+ rc = of_property_read_string(child_node,
+ "iova-region-name", ®ion_name);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("IOVA region not found\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(child_node,
+ "iova-region-start", ®ion_start);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("Failed to read iova-region-start\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(child_node,
+ "iova-region-len", ®ion_len);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("Failed to read iova-region-len\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(child_node,
+ "iova-region-id", ®ion_id);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("Failed to read iova-region-id\n");
+ return -EINVAL;
+ }
+
+ switch (region_id) {
+ case CAM_SMMU_REGION_FIRMWARE:
+ cb->firmware_support = 1;
+ cb->firmware_info.iova_start = region_start;
+ cb->firmware_info.iova_len = region_len;
+ break;
+ case CAM_SMMU_REGION_SHARED:
+ cb->shared_support = 1;
+ cb->shared_info.iova_start = region_start;
+ cb->shared_info.iova_len = region_len;
+ break;
+ case CAM_SMMU_REGION_SCRATCH:
+ cb->scratch_buf_support = 1;
+ cb->scratch_info.iova_start = region_start;
+ cb->scratch_info.iova_len = region_len;
+ break;
+ case CAM_SMMU_REGION_IO:
+ cb->io_support = 1;
+ cb->io_info.iova_start = region_start;
+ cb->io_info.iova_len = region_len;
+ break;
+ default:
+ pr_err("Incorrect region id present in DT file: %d\n",
+ region_id);
+ }
+
+ CDBG("Found label -> %s\n", cb->name);
+ CDBG("Found region -> %s\n", region_name);
+ CDBG("region_start -> %X\n", region_start);
+ CDBG("region_len -> %X\n", region_len);
+ CDBG("region_id -> %X\n", region_id);
+ }
+ of_node_put(mem_map_node);
+
+ if (!num_regions) {
+ pr_err("No memory regions found, at least one needed\n");
+ rc = -ENODEV;
+ }
+
+ return rc;
+}
+
+static int cam_populate_smmu_context_banks(struct device *dev,
+ enum cam_iommu_type type)
+{
+ int rc = 0;
+ struct cam_context_bank_info *cb;
+ struct device *ctx = NULL;
+
+ if (!dev) {
+ pr_err("Error: Invalid device\n");
+ return -ENODEV;
+ }
+
+ /* check the bounds */
+ if (iommu_cb_set.cb_init_count >= iommu_cb_set.cb_num) {
+ pr_err("Error: populate more than allocated cb\n");
+ rc = -EBADHANDLE;
+ goto cb_init_fail;
+ }
+
+ /* read the context bank from cb set */
+ cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count];
+
+ /* set the name of the context bank */
+ rc = of_property_read_string(dev->of_node, "label", &cb->name);
+ if (rc < 0) {
+ pr_err("Error: failed to read label from sub device\n");
+ goto cb_init_fail;
+ }
+
+ rc = cam_smmu_get_memory_regions_info(dev->of_node,
+ cb);
+ if (rc < 0) {
+ pr_err("Error: Getting region info\n");
+ return rc;
+ }
+
+ /* set up the iommu mapping for the context bank */
+ if (type == CAM_QSMMU) {
+ pr_err("Error: QSMMU ctx not supported for : %s\n", cb->name);
+ return -ENODEV;
+ }
+
+ ctx = dev;
+ CDBG("getting Arm SMMU ctx : %s\n", cb->name);
+
+ rc = cam_smmu_setup_cb(cb, ctx);
+ if (rc < 0) {
+ pr_err("Error: failed to setup cb : %s\n", cb->name);
+ goto cb_init_fail;
+ }
+
+ if (cb->io_support && cb->mapping)
+ iommu_set_fault_handler(cb->mapping->domain,
+ cam_smmu_iommu_fault_handler,
+ (void *)cb->name);
+
+ /* increment count to next bank */
+ iommu_cb_set.cb_init_count++;
+
+ CDBG("X: cb init count :%d\n", iommu_cb_set.cb_init_count);
+
+cb_init_fail:
+ return rc;
+}
+
+static int cam_smmu_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct device *dev = &pdev->dev;
+
+ if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) {
+ rc = cam_alloc_smmu_context_banks(dev);
+ if (rc < 0) {
+ pr_err("Error: allocating context banks\n");
+ return -ENOMEM;
+ }
+ }
+ if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-cb")) {
+ rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU);
+ if (rc < 0) {
+ pr_err("Error: populating context banks\n");
+ return -ENOMEM;
+ }
+ return rc;
+ }
+ if (of_device_is_compatible(dev->of_node, "qcom,qsmmu-cam-cb")) {
+ rc = cam_populate_smmu_context_banks(dev, CAM_QSMMU);
+ if (rc < 0) {
+ pr_err("Error: populating context banks\n");
+ return -ENOMEM;
+ }
+ return rc;
+ }
+
+ if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-fw-dev")) {
+ icp_fw.fw_dev = &pdev->dev;
+ icp_fw.fw_kva = NULL;
+ icp_fw.fw_dma_hdl = 0;
+ return rc;
+ }
+
+ /* probe through all the subdevices */
+ rc = of_platform_populate(pdev->dev.of_node, msm_cam_smmu_dt_match,
+ NULL, &pdev->dev);
+ if (rc < 0) {
+ pr_err("Error: populating devices\n");
+ } else {
+ INIT_WORK(&iommu_cb_set.smmu_work, cam_smmu_page_fault_work);
+ mutex_init(&iommu_cb_set.payload_list_lock);
+ INIT_LIST_HEAD(&iommu_cb_set.payload_list);
+ }
+
+ return rc;
+}
+
+static int cam_smmu_remove(struct platform_device *pdev)
+{
+ /* release all the context banks and memory allocated */
+ cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT);
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu"))
+ cam_smmu_release_cb(pdev);
+ return 0;
+}
+
+static struct platform_driver cam_smmu_driver = {
+ .probe = cam_smmu_probe,
+ .remove = cam_smmu_remove,
+ .driver = {
+ .name = "msm_cam_smmu",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_cam_smmu_dt_match,
+ },
+};
+
+static int __init cam_smmu_init_module(void)
+{
+ return platform_driver_register(&cam_smmu_driver);
+}
+
+static void __exit cam_smmu_exit_module(void)
+{
+ platform_driver_unregister(&cam_smmu_driver);
+}
+
+module_init(cam_smmu_init_module);
+module_exit(cam_smmu_exit_module);
+MODULE_DESCRIPTION("MSM Camera SMMU driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
new file mode 100644
index 0000000..76e9135
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
@@ -0,0 +1,255 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _CAM_SMMU_API_H_
+#define _CAM_SMMU_API_H_
+
+#include <linux/dma-direction.h>
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/random.h>
+#include <linux/spinlock_types.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+
+/*Enum for possible CAM SMMU operations */
+enum cam_smmu_ops_param {
+ CAM_SMMU_ATTACH,
+ CAM_SMMU_DETACH,
+ CAM_SMMU_VOTE,
+ CAM_SMMU_DEVOTE,
+ CAM_SMMU_OPS_INVALID
+};
+
+enum cam_smmu_map_dir {
+ CAM_SMMU_MAP_READ,
+ CAM_SMMU_MAP_WRITE,
+ CAM_SMMU_MAP_RW,
+ CAM_SMMU_MAP_INVALID
+};
+
+enum cam_smmu_region_id {
+ CAM_SMMU_REGION_FIRMWARE,
+ CAM_SMMU_REGION_SHARED,
+ CAM_SMMU_REGION_SCRATCH,
+ CAM_SMMU_REGION_IO
+};
+
+/**
+ * @brief : Gets an smmu handle
+ *
+ * @param identifier: Unique identifier to be used by clients which they
+ * should get from device tree. CAM SMMU driver will
+ * not enforce how this string is obtained and will
+ * only validate this against the list of permitted
+ * identifiers
+ * @param handle_ptr: Based on the indentifier, CAM SMMU drivier will
+ * fill the handle pointed by handle_ptr
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_handle(char *identifier, int *handle_ptr);
+
+/**
+ * @brief : Performs IOMMU operations
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH
+ * or CAM_SMMU_DETACH
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param op);
+
+/**
+ * @brief : Maps IOVA for calling driver
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ * DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @dma_addr : Pointer to physical address where mapped address will be
+ * returned if region_id is CAM_SMMU_REGION_IO. If region_id is
+ * CAM_SMMU_REGION_SHARED, dma_addr is used as an input parameter
+ * which specifies the cpu virtual address to map.
+ * @len : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_map_iova(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ dma_addr_t *dma_addr, size_t *len_ptr,
+ enum cam_smmu_region_id region_id);
+
+/**
+ * @brief : Unmaps IOVA for calling driver
+ *
+ * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_unmap_iova(int handle,
+ int ion_fd,
+ enum cam_smmu_region_id region_id);
+
+/**
+ * @brief : Allocates a scratch buffer
+ *
+ * This function allocates a scratch virtual buffer of length virt_len in the
+ * device virtual address space mapped to phys_len physically contiguous bytes
+ * in that device's SMMU.
+ *
+ * virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each
+ * other, otherwise -EINVAL is returned.
+ *
+ * -EINVAL will be returned if virt_len is less than phys_len.
+ *
+ * Passing a too large phys_len might also cause failure if that much size is
+ * not available for allocation in a physically contiguous way.
+ *
+ * @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param dir : Direction of mapping which will translate to IOMMU_READ
+ * IOMMU_WRITE or a bit mask of both.
+ * @param paddr_ptr: Device virtual address that the client device will be
+ * able to read from/write to
+ * @param virt_len : Virtual length of the scratch buffer
+ * @param phys_len : Physical length of the scratch buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_get_scratch_iova(int handle,
+ enum cam_smmu_map_dir dir,
+ dma_addr_t *paddr_ptr,
+ size_t virt_len,
+ size_t phys_len);
+
+/**
+ * @brief : Frees a scratch buffer
+ *
+ * This function frees a scratch buffer and releases the corresponding SMMU
+ * mappings.
+ *
+ * @param handle : Handle to identify the CAMSMMU client (IFE, ICP, etc.)
+ * @param paddr : Device virtual address of client's scratch buffer that
+ * will be freed.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_put_scratch_iova(int handle,
+ dma_addr_t paddr);
+
+/**
+ *@brief : Destroys an smmu handle
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_destroy_handle(int handle);
+
+/**
+ * @brief : Finds index by handle in the smmu client table
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @return Index of SMMU client. Nagative in case of error.
+ */
+int cam_smmu_find_index_by_handle(int hdl);
+
+/**
+ * @brief : Registers smmu fault handler for client
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param client_page_fault_handler: It is triggered in IOMMU page fault
+ * @param token: It is input param when trigger page fault handler
+ */
+void cam_smmu_reg_client_page_fault_handler(int handle,
+ void (*client_page_fault_handler)(struct iommu_domain *,
+ struct device *, unsigned long,
+ int, void*), void *token);
+
+/**
+ * @brief Maps memory from an ION fd into IOVA space
+ *
+ * @param handle: SMMU handle identifying the context bank to map to
+ * @param ion_fd: ION fd of memory to map to
+ * @param paddr_ptr: Pointer IOVA address that will be returned
+ * @param len_ptr: Length of memory mapped
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_iova(int handle, int ion_fd,
+ dma_addr_t *paddr_ptr, size_t *len_ptr);
+/**
+ * @brief Unmaps memory from context bank
+ *
+ * @param handle: SMMU handle identifying the context bank
+ * @param ion_fd: ION fd of memory to unmap
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_put_iova(int handle, int ion_fd);
+
+/**
+ * @brief Maps secure memory for SMMU handle
+ *
+ * @param handle: SMMU handle identifying context bank
+ * @param ion_fd: ION fd to map securely
+ * @param dir: DMA Direction for the mapping
+ * @param dma_addr: Returned IOVA address after mapping
+ * @param len_ptr: Length of memory mapped
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_map_sec_iova(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ dma_addr_t *dma_addr, size_t *len_ptr);
+
+/**
+ * @brief Unmaps secure memopry for SMMU handle
+ *
+ * @param handle: SMMU handle identifying context bank
+ * @param ion_fd: ION fd to unmap
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_unmap_sec_iova(int handle, int ion_fd);
+
+
+/**
+ * @brief Allocates firmware for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying context bank
+ * @param iova: IOVA address of allocated firmware
+ * @param kvaddr: CPU mapped address of allocated firmware
+ * @param len: Length of allocated firmware memory
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_alloc_firmware(int32_t smmu_hdl,
+ dma_addr_t *iova,
+ uint64_t *kvaddr,
+ size_t *len);
+
+/**
+ * @brief Deallocates firmware memory for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying the context bank
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_dealloc_firmware(int32_t smmu_hdl);
+#endif /* _CAM_SMMU_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
index 4f5bf87..ecc62c8 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
@@ -57,6 +57,48 @@
return 0;
}
+uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table,
+ uint32_t *sync_objs,
+ uint32_t num_objs)
+{
+ int i;
+ struct sync_table_row *child_row = NULL;
+ int success_count = 0;
+ int active_count = 0;
+
+ if (!table || !sync_objs)
+ return CAM_SYNC_STATE_SIGNALED_ERROR;
+
+ /*
+ * We need to arrive at the state of the merged object based on
+ * counts of error, active and success states of all children objects
+ */
+ for (i = 0; i < num_objs; i++) {
+ child_row = table + sync_objs[i];
+ switch (child_row->state) {
+ case CAM_SYNC_STATE_SIGNALED_ERROR:
+ return CAM_SYNC_STATE_SIGNALED_ERROR;
+ case CAM_SYNC_STATE_SIGNALED_SUCCESS:
+ success_count++;
+ break;
+ case CAM_SYNC_STATE_ACTIVE:
+ active_count++;
+ break;
+ default:
+ pr_err("Invalid state of child object during merge\n");
+ return CAM_SYNC_STATE_SIGNALED_ERROR;
+ }
+ }
+
+ if (active_count)
+ return CAM_SYNC_STATE_ACTIVE;
+
+ if (success_count == num_objs)
+ return CAM_SYNC_STATE_SIGNALED_SUCCESS;
+
+ return CAM_SYNC_STATE_SIGNALED_ERROR;
+}
+
int cam_sync_init_group_object(struct sync_table_row *table,
uint32_t idx,
uint32_t *sync_objs,
@@ -113,12 +155,16 @@
row->type = CAM_SYNC_TYPE_GROUP;
row->sync_id = idx;
- row->state = CAM_SYNC_STATE_ACTIVE;
+ row->state = cam_sync_util_get_group_object_state(table,
+ sync_objs, num_objs);
row->remaining = num_objs;
init_completion(&row->signaled);
INIT_LIST_HEAD(&row->callback_list);
INIT_LIST_HEAD(&row->user_payload_list);
+ if (row->state != CAM_SYNC_STATE_ACTIVE)
+ complete_all(&row->signaled);
+
spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
return 0;
}
@@ -208,6 +254,11 @@
int i;
struct sync_table_row *row = NULL;
+ if (num_objs <= 1) {
+ pr_err("Single object merge is not allowed\n");
+ return -EINVAL;
+ }
+
for (i = 0; i < num_objs; i++) {
row = sync_dev->sync_table + sync_obj[i];
spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 3bf6ce0..9194b44 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -96,7 +96,6 @@
* @SDE_CAPS_R1_WB: MDSS V1.x WB block
* @SDE_CAPS_R3_WB: MDSS V3.x WB block
* @SDE_CAPS_R3_1P5_DOWNSCALE: 1.5x downscale rotator support
- * @SDE_CAPS_MIN_BUS_VOTE: minimum bus vote prior to power enable
* @SDE_CAPS_SBUF_1: stream buffer support for inline rotation
* @SDE_CAPS_UBWC_2: universal bandwidth compression version 2
*/
@@ -105,7 +104,6 @@
SDE_CAPS_R3_WB,
SDE_CAPS_R3_1P5_DOWNSCALE,
SDE_CAPS_SEC_ATTACH_DETACH_SMMU,
- SDE_CAPS_MIN_BUS_VOTE,
SDE_CAPS_SBUF_1,
SDE_CAPS_UBWC_2,
SDE_CAPS_MAX,
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 9a28700..30fda07 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -25,6 +25,7 @@
#include <linux/msm-bus-board.h>
#include <linux/regulator/consumer.h>
#include <linux/dma-direction.h>
+#include <linux/sde_rsc.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/secure_buffer.h>
#include <asm/cacheflush.h>
@@ -293,14 +294,13 @@
SDEROT_DBG("core_clk %lu\n", total_clk_rate);
ATRACE_INT("core_clk", total_clk_rate);
- sde_rotator_set_clk_rate(mgr, total_clk_rate, SDE_ROTATOR_CLK_ROT_CORE);
+ sde_rotator_set_clk_rate(mgr, total_clk_rate, SDE_ROTATOR_CLK_MDSS_ROT);
return 0;
}
static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on)
{
- struct sde_rot_data_type *mdata = sde_rot_get_mdata();
int ret;
if (WARN_ON(mgr->regulator_enable == on)) {
@@ -311,7 +311,7 @@
SDEROT_EVTLOG(on);
SDEROT_DBG("%s: rotator regulators\n", on ? "Enable" : "Disable");
- if (test_bit(SDE_CAPS_MIN_BUS_VOTE, mdata->sde_caps_map) && on) {
+ if (on) {
mgr->minimum_bw_vote = mgr->enable_bw_vote;
sde_rotator_update_perf(mgr);
}
@@ -319,8 +319,13 @@
if (mgr->ops_hw_pre_pmevent)
mgr->ops_hw_pre_pmevent(mgr, on);
- ret = sde_rot_enable_vreg(mgr->module_power.vreg_config,
- mgr->module_power.num_vreg, on);
+ if (mgr->rsc_client)
+ ret = sde_rsc_client_state_update(mgr->rsc_client,
+ on ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE,
+ NULL, -1);
+ else
+ ret = sde_rot_enable_vreg(mgr->module_power.vreg_config,
+ mgr->module_power.num_vreg, on);
if (ret) {
SDEROT_WARN("Rotator regulator failed to %s\n",
on ? "enable" : "disable");
@@ -330,7 +335,7 @@
if (mgr->ops_hw_post_pmevent)
mgr->ops_hw_post_pmevent(mgr, on);
- if (test_bit(SDE_CAPS_MIN_BUS_VOTE, mdata->sde_caps_map) && !on) {
+ if (!on) {
mgr->minimum_bw_vote = 0;
sde_rotator_update_perf(mgr);
}
@@ -407,13 +412,13 @@
if (ret)
goto error_mdss_axi;
ret = sde_rotator_enable_clk(mgr,
- SDE_ROTATOR_CLK_ROT_CORE);
- if (ret)
- goto error_rot_core;
- ret = sde_rotator_enable_clk(mgr,
SDE_ROTATOR_CLK_MDSS_ROT);
if (ret)
goto error_mdss_rot;
+ ret = sde_rotator_enable_clk(mgr,
+ SDE_ROTATOR_CLK_MDSS_ROT_SUB);
+ if (ret)
+ goto error_rot_sub;
/* Active+Sleep */
msm_bus_scale_client_update_context(
@@ -421,8 +426,9 @@
mgr->data_bus.curr_bw_uc_idx);
trace_rot_bw_ao_as_context(0);
} else {
+ sde_rotator_disable_clk(mgr,
+ SDE_ROTATOR_CLK_MDSS_ROT_SUB);
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT);
- sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_GCC_AXI);
@@ -438,9 +444,9 @@
}
return ret;
+error_rot_sub:
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT);
error_mdss_rot:
- sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
-error_rot_core:
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
error_mdss_axi:
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
@@ -551,6 +557,12 @@
if (!input)
dir = DMA_FROM_DEVICE;
+ if (buffer->plane_count > SDE_ROT_MAX_PLANES) {
+ SDEROT_ERR("buffer plane_count exceeds MAX_PLANE limit:%d\n",
+ buffer->plane_count);
+ return -EINVAL;
+ }
+
data->sbuf = buffer->sbuf;
data->scid = buffer->scid;
data->writeback = buffer->writeback;
@@ -2731,11 +2743,19 @@
sde_rotator_search_dt_clk(pdev, mgr, "axi_clk",
SDE_ROTATOR_CLK_MDSS_AXI, true) ||
sde_rotator_search_dt_clk(pdev, mgr, "rot_core_clk",
- SDE_ROTATOR_CLK_ROT_CORE, true) ||
- sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
- SDE_ROTATOR_CLK_MDSS_ROT, true))
+ SDE_ROTATOR_CLK_MDSS_ROT, false))
rc = -EINVAL;
+ /*
+ * If 'MDSS_ROT' is already present, place 'rot_clk' under
+ * MDSS_ROT_SUB. Otherwise, place it directly into MDSS_ROT.
+ */
+ if (sde_rotator_get_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT))
+ rc = sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
+ SDE_ROTATOR_CLK_MDSS_ROT_SUB, true);
+ else
+ rc = sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
+ SDE_ROTATOR_CLK_MDSS_ROT, true);
clk_err:
return rc;
}
@@ -2766,9 +2786,21 @@
{
int ret;
- ret = sde_rotator_get_dt_vreg_data(&pdev->dev, &mgr->module_power);
- if (ret)
+ mgr->rsc_client = sde_rsc_client_create(
+ SDE_RSC_INDEX, "sde_rotator_core", false);
+ if (IS_ERR(mgr->rsc_client)) {
+ ret = PTR_ERR(mgr->rsc_client);
+ pr_err("rsc client create returned %d\n", ret);
+ mgr->rsc_client = NULL;
return ret;
+ }
+
+ if (!mgr->rsc_client) {
+ ret = sde_rotator_get_dt_vreg_data(
+ &pdev->dev, &mgr->module_power);
+ if (ret)
+ return ret;
+ }
ret = sde_rotator_register_clk(pdev, mgr);
if (ret)
@@ -2788,9 +2820,15 @@
{
struct platform_device *pdev = mgr->pdev;
- sde_rotator_put_dt_vreg_data(&pdev->dev, &mgr->module_power);
sde_rotator_unregister_clk(mgr);
sde_rotator_bus_scale_unregister(mgr);
+
+ if (mgr->rsc_client) {
+ sde_rsc_client_destroy(mgr->rsc_client);
+ mgr->rsc_client = NULL;
+ } else {
+ sde_rotator_put_dt_vreg_data(&pdev->dev, &mgr->module_power);
+ }
}
int sde_rotator_core_init(struct sde_rot_mgr **pmgr,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 819f57b..0051e96 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -125,7 +125,7 @@
enum sde_rotator_clk_type {
SDE_ROTATOR_CLK_MDSS_AHB,
SDE_ROTATOR_CLK_MDSS_AXI,
- SDE_ROTATOR_CLK_ROT_CORE,
+ SDE_ROTATOR_CLK_MDSS_ROT_SUB,
SDE_ROTATOR_CLK_MDSS_ROT,
SDE_ROTATOR_CLK_MNOC_AHB,
SDE_ROTATOR_CLK_GCC_AHB,
@@ -373,6 +373,7 @@
* @reg_bus: register bus configuration state
* @module_power: power/clock configuration state
* @regulator_enable: true if foot switch is enabled; false otherwise
+ * @rsc_client: pointer to rsc client handle
* @res_ref_cnt: reference count of how many times resource is requested
* @rot_enable_clk_cnt: reference count of how many times clock is requested
* @rot_clk: array of rotator and periphery clocks
@@ -417,6 +418,8 @@
struct sde_module_power module_power;
bool regulator_enable;
+ struct sde_rsc_client *rsc_client;
+
int res_ref_cnt;
int rot_enable_clk_cnt;
struct sde_rot_clk *rot_clk;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 15ecc10..90b7194 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -438,6 +438,8 @@
{
struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q);
struct sde_rotator_device *rot_dev = ctx->rot_dev;
+ struct sde_rotator_request *request;
+ struct list_head *curr, *next;
int i;
int ret;
@@ -458,6 +460,21 @@
sde_rot_mgr_lock(rot_dev->mgr);
sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
sde_rot_mgr_unlock(rot_dev->mgr);
+ list_for_each_safe(curr, next, &ctx->pending_list) {
+ request = container_of(curr, struct sde_rotator_request,
+ list);
+
+ SDEDEV_DBG(rot_dev->dev, "cancel request s:%d\n",
+ ctx->session_id);
+ mutex_unlock(q->lock);
+ cancel_work_sync(&request->submit_work);
+ cancel_work_sync(&request->retire_work);
+ mutex_lock(q->lock);
+ spin_lock(&ctx->list_lock);
+ list_del_init(&request->list);
+ list_add_tail(&request->list, &ctx->retired_list);
+ spin_unlock(&ctx->list_lock);
+ }
}
sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 8f2746d..1bab010 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -2366,7 +2366,6 @@
/* features exposed via mdss h/w version */
if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400)) {
SDEROT_DBG("Supporting sys cache inline rotation\n");
- set_bit(SDE_CAPS_MIN_BUS_VOTE, mdata->sde_caps_map);
set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map);
set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map);
rot->inpixfmts = sde_hw_rotator_v4_inpixfmts;
@@ -2597,6 +2596,11 @@
}
if ((src_w != dst_w) || (src_h != dst_h)) {
+ if (!dst_w || !dst_h) {
+ SDEROT_DBG("zero output width/height not support\n");
+ ret = -EINVAL;
+ goto dnsc_err;
+ }
if ((src_w % dst_w) || (src_h % dst_h)) {
SDEROT_DBG("non integral scale not support\n");
ret = -EINVAL;
@@ -3078,9 +3082,9 @@
goto error_hw_rev_init;
/* set rotator CBCR to shutoff memory/periphery on clock off.*/
- clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
+ clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_MDSS_ROT].clk,
CLKFLAG_NORETAIN_MEM);
- clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
+ clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_MDSS_ROT].clk,
CLKFLAG_NORETAIN_PERIPH);
mdata->sde_rot_hw = rot;
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index ac6ded0..7215fdf 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -920,6 +920,8 @@
pkt->session_id = hash32_ptr(session);
pkt->num_properties = 1;
+ dprintk(VIDC_DBG, "Setting HAL Property = 0x%x\n", ptype);
+
switch (ptype) {
case HAL_CONFIG_FRAME_RATE:
{
@@ -1273,6 +1275,7 @@
hfi->qp_packed = hal_quant->qpi | hal_quant->qpp << 8 |
hal_quant->qpb << 16;
hfi->layer_id = hal_quant->layer_id;
+ hfi->enable = hal_quant->enable;
pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
break;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 3d3b7e9..a86c677 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -23,7 +23,6 @@
#define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS MIN_NUM_CAPTURE_BUFFERS
#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
#define MB_SIZE_IN_PIXEL (16 * 16)
-#define MAX_OPERATING_FRAME_RATE (300 << 16)
#define OPERATING_FRAME_RATE_STEP (1 << 16)
static const char *const mpeg_video_stream_format[] = {
@@ -360,7 +359,7 @@
.name = "Set Decoder Operating rate",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
- .maximum = MAX_OPERATING_FRAME_RATE,
+ .maximum = INT_MAX,
.default_value = 0,
.step = OPERATING_FRAME_RATE_STEP,
},
@@ -368,17 +367,6 @@
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
-static u32 get_frame_size_nv12(int plane,
- u32 height, u32 width)
-{
- return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
-}
-
-static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
-{
- return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
-}
-
static u32 get_frame_size_compressed_full_yuv(int plane,
u32 max_mbs_per_frame, u32 size_per_mb)
{
@@ -391,11 +379,6 @@
return (max_mbs_per_frame * size_per_mb * 3/2)/2;
}
-static u32 get_frame_size_nv12_ubwc_10bit(int plane, u32 height, u32 width)
-{
- return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
-}
-
static u32 get_frame_size(struct msm_vidc_inst *inst,
const struct msm_vidc_format *fmt,
int fmt_type, int plane)
@@ -446,7 +429,7 @@
.name = "UBWC YCbCr Semiplanar 4:2:0 10bit",
.description = "UBWC Y/CbCr 4:2:0 10bit",
.fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
- .get_frame_size = get_frame_size_nv12_ubwc_10bit,
+ .get_frame_size = get_frame_size_tp10_ubwc,
.type = CAPTURE_PORT,
},
{
@@ -681,7 +664,7 @@
inst->bufq[OUTPUT_PORT].num_planes = 1;
inst->bufq[CAPTURE_PORT].num_planes = 1;
inst->prop.fps = DEFAULT_FPS;
- inst->operating_rate = 0;
+ inst->clk_data.operating_rate = 0;
memcpy(&inst->fmts[OUTPUT_PORT], &vdec_formats[2],
sizeof(struct msm_vidc_format));
memcpy(&inst->fmts[CAPTURE_PORT], &vdec_formats[0],
@@ -968,8 +951,12 @@
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
dprintk(VIDC_DBG,
"inst(%pK) operating rate changed from %d to %d\n",
- inst, inst->operating_rate >> 16, ctrl->val >> 16);
- inst->operating_rate = ctrl->val;
+ inst, inst->clk_data.operating_rate >> 16,
+ ctrl->val >> 16);
+ inst->clk_data.operating_rate = ctrl->val;
+
+ msm_vidc_update_operating_rate(inst);
+
break;
default:
break;
@@ -980,8 +967,8 @@
if (!rc && property_id) {
dprintk(VIDC_DBG,
- "Control: HAL property=%#x,ctrl: id=%#x,value=%#x\n",
- property_id, ctrl->id, ctrl->val);
+ "Control: Name = %s, ID = 0x%x Value = %d\n",
+ ctrl->name, ctrl->id, ctrl->val);
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, property_id, pdata);
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index e198d8e..19a21ab 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -23,7 +23,6 @@
#define DEFAULT_BIT_RATE 64000
#define BIT_RATE_STEP 100
#define DEFAULT_FRAME_RATE 15
-#define MAX_OPERATING_FRAME_RATE (300 << 16)
#define OPERATING_FRAME_RATE_STEP (1 << 16)
#define MAX_SLICE_BYTE_SIZE ((MAX_BIT_RATE)>>3)
#define MIN_SLICE_BYTE_SIZE 512
@@ -286,6 +285,17 @@
.qmenu = NULL,
},
{
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK,
+ .name = "QP mask for diff frame types",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 7,
+ .default_value = 7,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
.name = "Intra Period for B frames",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -867,7 +877,7 @@
.name = "Set Encoder Operating rate",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
- .maximum = MAX_OPERATING_FRAME_RATE,
+ .maximum = INT_MAX,
.default_value = 0,
.step = OPERATING_FRAME_RATE_STEP,
},
@@ -983,26 +993,6 @@
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
-static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
-{
- return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
-}
-
-static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
-{
- return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
-}
-
-static u32 get_frame_size_rgba(int plane, u32 height, u32 width)
-{
- return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888, width, height);
-}
-
-static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
-{
- return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
-}
-
static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
{
int sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2;
@@ -1060,6 +1050,13 @@
.get_frame_size = get_frame_size_nv21,
.type = OUTPUT_PORT,
},
+ {
+ .name = "TP10 UBWC 4:2:0",
+ .description = "TP10 UBWC 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
+ .get_frame_size = get_frame_size_tp10_ubwc,
+ .type = OUTPUT_PORT,
+ },
};
static int msm_venc_set_csc(struct msm_vidc_inst *inst);
@@ -1224,7 +1221,7 @@
bitrate.bit_rate = ctrl->val;
bitrate.layer_id = 0;
pdata = &bitrate;
- inst->bitrate = ctrl->val;
+ inst->clk_data.bitrate = ctrl->val;
break;
}
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
@@ -1644,43 +1641,65 @@
pdata = &baselayerid;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP: {
- struct v4l2_ctrl *qpp, *qpb;
+ struct v4l2_ctrl *qpp, *qpb, *mask;
property_id = HAL_CONFIG_VENC_FRAME_QP;
qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP);
qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP);
+ mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK);
quant.qpi = ctrl->val;
quant.qpp = qpp->val;
quant.qpb = qpb->val;
+ quant.enable = mask->val;
quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
pdata = &quant;
break;
}
case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP: {
- struct v4l2_ctrl *qpi, *qpb;
+ struct v4l2_ctrl *qpi, *qpb, *mask;
property_id = HAL_CONFIG_VENC_FRAME_QP;
qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP);
qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP);
+ mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK);
quant.qpp = ctrl->val;
quant.qpi = qpi->val;
quant.qpb = qpb->val;
+ quant.enable = mask->val;
quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
pdata = &quant;
break;
}
case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP: {
- struct v4l2_ctrl *qpp, *qpi;
+ struct v4l2_ctrl *qpp, *qpi, *mask;
property_id = HAL_CONFIG_VENC_FRAME_QP;
qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP);
qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP);
+ mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK);
quant.qpb = ctrl->val;
quant.qpp = qpp->val;
quant.qpi = qpi->val;
+ quant.enable = mask->val;
+ quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
+ pdata = &quant;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK: {
+ struct v4l2_ctrl *qpi, *qpp, *qpb;
+
+ property_id = HAL_CONFIG_VENC_FRAME_QP;
+ qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP);
+ qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP);
+ qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP);
+
+ quant.qpi = qpi->val;
+ quant.qpp = qpp->val;
+ quant.qpb = qpb->val;
+ quant.enable = ctrl->val;
quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
pdata = &quant;
break;
@@ -1714,8 +1733,12 @@
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
dprintk(VIDC_DBG,
"inst(%pK) operating rate changed from %d to %d\n",
- inst, inst->operating_rate >> 16, ctrl->val >> 16);
- inst->operating_rate = ctrl->val;
+ inst, inst->clk_data.operating_rate >> 16,
+ ctrl->val >> 16);
+ inst->clk_data.operating_rate = ctrl->val;
+
+ msm_vidc_update_operating_rate(inst);
+
break;
case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
{
@@ -1798,6 +1821,7 @@
else
enable.enable = 0;
pdata = &enable;
+ inst->clk_data.low_latency_mode = (bool) enable.enable;
break;
}
case V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8:
@@ -1835,9 +1859,9 @@
#undef TRY_GET_CTRL
if (!rc && property_id) {
- dprintk(VIDC_DBG, "Control: HAL property=%x,ctrl_value=%d\n",
- property_id,
- ctrl->val);
+ dprintk(VIDC_DBG,
+ "Control: Name = %s, ID = 0x%x Value = %d\n",
+ ctrl->name, ctrl->id, ctrl->val);
rc = call_hfi_op(hdev, session_set_property,
(void *)inst->session, property_id, pdata);
}
@@ -1852,7 +1876,7 @@
struct v4l2_ext_control *control;
struct hfi_device *hdev;
struct hal_ltr_mode ltr_mode;
- u32 property_id = 0, layer_id = MSM_VIDC_ALL_LAYER_ID;
+ u32 property_id = 0;
void *pdata = NULL;
struct msm_vidc_capability *cap = NULL;
struct hal_aspect_ratio sar;
@@ -1930,76 +1954,75 @@
pdata = &blur_res;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_LAYER_ID:
- layer_id = control[i].value;
+ qp.layer_id = control[i].value;
+ /* Enable QP for all frame types by default */
+ qp.enable = 7;
+ qp_range.layer_id = control[i].value;
i++;
while (i < ctrl->count) {
switch (control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP:
qp.qpi = control[i].value;
- qp.layer_id = layer_id;
property_id =
HAL_CONFIG_VENC_FRAME_QP;
pdata = &qp;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP:
qp.qpp = control[i].value;
- qp.layer_id = layer_id;
property_id =
HAL_CONFIG_VENC_FRAME_QP;
pdata = &qp;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP:
qp.qpb = control[i].value;
- qp.layer_id = layer_id;
+ property_id =
+ HAL_CONFIG_VENC_FRAME_QP;
+ pdata = &qp;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK:
+ qp.enable = control[i].value;
property_id =
HAL_CONFIG_VENC_FRAME_QP;
pdata = &qp;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MIN:
qp_range.qpi_min = control[i].value;
- qp_range.layer_id = layer_id;
property_id =
HAL_PARAM_VENC_SESSION_QP_RANGE;
pdata = &qp_range;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MIN:
qp_range.qpp_min = control[i].value;
- qp_range.layer_id = layer_id;
property_id =
- HAL_PARAM_VENC_SESSION_QP_RANGE;
+ HAL_PARAM_VENC_SESSION_QP_RANGE;
pdata = &qp_range;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MIN:
qp_range.qpb_min = control[i].value;
- qp_range.layer_id = layer_id;
property_id =
HAL_PARAM_VENC_SESSION_QP_RANGE;
pdata = &qp_range;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MAX:
qp_range.qpi_max = control[i].value;
- qp_range.layer_id = layer_id;
property_id =
HAL_PARAM_VENC_SESSION_QP_RANGE;
pdata = &qp_range;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MAX:
qp_range.qpp_max = control[i].value;
- qp_range.layer_id = layer_id;
property_id =
HAL_PARAM_VENC_SESSION_QP_RANGE;
pdata = &qp_range;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX:
qp_range.qpb_max = control[i].value;
- qp_range.layer_id = layer_id;
property_id =
HAL_PARAM_VENC_SESSION_QP_RANGE;
pdata = &qp_range;
break;
case V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE:
bitrate.bit_rate = control[i].value;
- bitrate.layer_id = layer_id;
property_id =
HAL_CONFIG_VENC_TARGET_BITRATE;
pdata = &bitrate;
@@ -2051,7 +2074,7 @@
/* To start with, both ports are 1 plane each */
inst->bufq[OUTPUT_PORT].num_planes = 1;
inst->bufq[CAPTURE_PORT].num_planes = 1;
- inst->operating_rate = 0;
+ inst->clk_data.operating_rate = 0;
memcpy(&inst->fmts[CAPTURE_PORT], &venc_formats[4],
sizeof(struct msm_vidc_format));
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index e071037..8f97b15 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1433,7 +1433,9 @@
"Failed to move inst: %pK to start done state\n", inst);
goto fail_start;
}
- msm_dcvs_init(inst);
+
+ msm_clock_data_reset(inst);
+
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
rc = msm_comm_queue_output_buffers(inst);
@@ -1519,6 +1521,9 @@
dprintk(VIDC_ERR,
"Failed to move inst: %pK to state %d\n",
inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+
+ msm_clock_data_reset(inst);
+
return rc;
}
@@ -1971,10 +1976,11 @@
inst->session_type = session_type;
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
- inst->freq = 0;
- inst->core_id = VIDC_CORE_ID_DEFAULT;
+ inst->clk_data.min_freq = 0;
+ inst->clk_data.curr_freq = 0;
+ inst->clk_data.bitrate = 0;
+ inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
inst->bit_depth = MSM_VIDC_BIT_DEPTH_8;
- inst->bitrate = 0;
inst->pic_struct = MSM_VIDC_PIC_STRUCT_PROGRESSIVE;
inst->colour_space = MSM_VIDC_BT601_6_525;
inst->profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
@@ -2037,6 +2043,8 @@
goto fail_init;
}
+ msm_comm_scale_clocks_and_bus(inst);
+
inst->debugfs_root =
msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index d43ae5a..cd518fb 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -23,17 +23,12 @@
struct msm_vidc_inst *inst = NULL;
struct vidc_bus_vote_data *vote_data = NULL;
- if (!core) {
+ if (!core || !core->device) {
dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, core);
return -EINVAL;
}
hdev = core->device;
- if (!hdev) {
- dprintk(VIDC_ERR, "%s Invalid device handle: %pK\n",
- __func__, hdev);
- return -EINVAL;
- }
mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list)
@@ -65,12 +60,17 @@
vote_data[i].height = max(inst->prop.height[CAPTURE_PORT],
inst->prop.height[OUTPUT_PORT]);
- if (inst->operating_rate)
- vote_data[i].fps = (inst->operating_rate >> 16) ?
- inst->operating_rate >> 16 : 1;
+ if (inst->clk_data.operating_rate)
+ vote_data[i].fps =
+ (inst->clk_data.operating_rate >> 16) ?
+ inst->clk_data.operating_rate >> 16 : 1;
else
vote_data[i].fps = inst->prop.fps;
+ if (!msm_vidc_clock_scaling ||
+ inst->clk_data.buffer_counter < DCVS_FTB_WINDOW)
+ vote_data[i].power_mode = VIDC_POWER_TURBO;
+
/*
* TODO: support for OBP-DBP split mode hasn't been yet
* implemented, once it is, this part of code needs to be
@@ -126,18 +126,19 @@
int buffers_outside_fw = 0;
struct msm_vidc_core *core;
struct hal_buffer_requirements *output_buf_req;
- struct dcvs_stats *dcvs;
+ struct clock_data *dcvs;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
return -EINVAL;
}
- if (!inst->dcvs_mode) {
+
+ if (!inst->clk_data.dcvs_mode) {
dprintk(VIDC_DBG, "DCVS is not enabled\n");
return 0;
}
- dcvs = &inst->dcvs;
+ dcvs = &inst->clk_data;
core = inst->core;
mutex_lock(&inst->lock);
@@ -210,7 +211,7 @@
}
mutex_unlock(&inst->freqs.lock);
- inst->dcvs.buffer_counter++;
+ inst->clk_data.buffer_counter++;
}
@@ -227,12 +228,13 @@
/* If current requirement is within DCVS limits, try DCVS. */
- if (freq < inst->dcvs.load_high) {
+ if (freq < inst->clk_data.load_high) {
dprintk(VIDC_DBG, "Calling DCVS now\n");
// TODO calling DCVS here may reduce the residency. Re-visit.
msm_dcvs_scale_clocks(inst);
- freq = inst->dcvs.load;
+ freq = inst->clk_data.load;
}
+ dprintk(VIDC_PROF, "%s Inst %pK : Freq = %lu\n", __func__, inst, freq);
return freq;
}
@@ -274,9 +276,10 @@
unsigned long freq = 0;
unsigned long vpp_cycles = 0, vsp_cycles = 0;
u32 vpp_cycles_per_mb;
- u32 mbs_per_frame;
+ u32 mbs_per_second;
- mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+ mbs_per_second = msm_comm_get_inst_load(inst,
+ LOAD_CALC_NO_QUIRKS);
/*
* Calculate vpp, vsp cycles separately for encoder and decoder.
@@ -286,17 +289,17 @@
if (inst->session_type == MSM_VIDC_ENCODER) {
vpp_cycles_per_mb = inst->flags & VIDC_LOW_POWER ?
- inst->entry->low_power_cycles :
- inst->entry->vpp_cycles;
+ inst->clk_data.entry->low_power_cycles :
+ inst->clk_data.entry->vpp_cycles;
- vsp_cycles = mbs_per_frame * inst->entry->vsp_cycles;
+ vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
/* 10 / 7 is overhead factor */
- vsp_cycles += (inst->bitrate * 10) / 7;
+ vsp_cycles += (inst->clk_data.bitrate * 10) / 7;
} else if (inst->session_type == MSM_VIDC_DECODER) {
- vpp_cycles = mbs_per_frame * inst->entry->vpp_cycles;
+ vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles;
- vsp_cycles = mbs_per_frame * inst->entry->vsp_cycles;
+ vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
/* 10 / 7 is overhead factor */
vsp_cycles += (inst->prop.fps * filled_len * 8 * 10) / 7;
@@ -306,6 +309,8 @@
return freq;
}
+ dprintk(VIDC_PROF, "%s Inst %pK : Freq = %lu\n", __func__, inst, freq);
+
freq = max(vpp_cycles, vsp_cycles);
return freq;
@@ -321,7 +326,7 @@
hdev = core->device;
allowed_clks_tbl = core->resources.allowed_clks_tbl;
- if (!hdev || !allowed_clks_tbl) {
+ if (!allowed_clks_tbl) {
dprintk(VIDC_ERR,
"%s Invalid parameters\n", __func__);
return -EINVAL;
@@ -329,35 +334,104 @@
mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
- freq += temp->freq;
+ freq += temp->clk_data.curr_freq;
}
for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) {
rate = allowed_clks_tbl[i].clock_rate;
if (rate >= freq)
break;
}
+ core->min_freq = freq;
+ core->curr_freq = rate;
mutex_unlock(&core->lock);
- core->freq = rate;
- dprintk(VIDC_PROF, "Voting for freq = %lu", freq);
+ dprintk(VIDC_PROF, "Min freq = %lu Current Freq = %lu\n",
+ core->min_freq, core->curr_freq);
rc = call_hfi_op(hdev, scale_clocks,
- hdev->hfi_device_data, rate);
+ hdev->hfi_device_data, core->curr_freq);
return rc;
}
-static unsigned long msm_vidc_max_freq(struct msm_vidc_inst *inst)
+static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core)
{
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
unsigned long freq = 0;
- allowed_clks_tbl = inst->core->resources.allowed_clks_tbl;
+ allowed_clks_tbl = core->resources.allowed_clks_tbl;
freq = allowed_clks_tbl[0].clock_rate;
dprintk(VIDC_PROF, "Max rate = %lu", freq);
return freq;
}
+int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst)
+{
+ struct v4l2_ctrl *ctrl = NULL;
+ struct msm_vidc_inst *temp;
+ struct msm_vidc_core *core;
+ unsigned long max_freq, freq_left, ops_left, load, cycles, freq = 0;
+ unsigned long mbs_per_frame;
+
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+ return -EINVAL;
+ }
+ core = inst->core;
+
+ mutex_lock(&core->lock);
+ max_freq = msm_vidc_max_freq(core);
+ list_for_each_entry(temp, &core->instances, list) {
+ if (temp == inst ||
+ temp->state < MSM_VIDC_START_DONE ||
+ temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
+ continue;
+
+ freq += temp->clk_data.min_freq;
+ }
+
+ freq_left = max_freq - freq;
+
+ list_for_each_entry(temp, &core->instances, list) {
+
+ mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+ cycles = temp->clk_data.entry->vpp_cycles;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ cycles = temp->flags & VIDC_LOW_POWER ?
+ inst->clk_data.entry->low_power_cycles :
+ cycles;
+
+ load = cycles * mbs_per_frame;
+
+ ops_left = load ? (freq_left / load) : 0;
+ /* Convert remaining operating rate to Q16 format */
+ ops_left = ops_left << 16;
+
+ ctrl = v4l2_ctrl_find(&temp->ctrl_handler,
+ V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE);
+ if (ctrl) {
+ dprintk(VIDC_DBG,
+ "%s: Before Range = %lld --> %lld\n",
+ ctrl->name, ctrl->minimum, ctrl->maximum);
+ dprintk(VIDC_DBG,
+ "%s: Before Def value = %lld Cur val = %d\n",
+ ctrl->name, ctrl->default_value, ctrl->val);
+ v4l2_ctrl_modify_range(ctrl, ctrl->minimum,
+ ctrl->val + ops_left, ctrl->step,
+ ctrl->minimum);
+ dprintk(VIDC_DBG,
+ "%s: Updated Range = %lld --> %lld\n",
+ ctrl->name, ctrl->minimum, ctrl->maximum);
+ dprintk(VIDC_DBG,
+ "%s: Updated Def value = %lld Cur val = %d\n",
+ ctrl->name, ctrl->default_value, ctrl->val);
+ }
+ }
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
{
struct vb2_buf_entry *temp, *next;
@@ -365,9 +439,10 @@
u32 filled_len = 0;
ion_phys_addr_t device_addr = 0;
- if (inst->dcvs.buffer_counter < DCVS_FTB_WINDOW) {
- freq = msm_vidc_max_freq(inst);
- goto decision_done;
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
+ __func__, inst);
+ return -EINVAL;
}
mutex_lock(&inst->pendingq.lock);
@@ -381,7 +456,7 @@
mutex_unlock(&inst->pendingq.lock);
if (!filled_len || !device_addr) {
- freq = inst->freq;
+ dprintk(VIDC_PROF, "No Change in frequency\n");
goto decision_done;
}
@@ -391,8 +466,15 @@
freq = msm_vidc_adjust_freq(inst);
+ inst->clk_data.min_freq = freq;
+
+ if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW ||
+ !msm_vidc_clock_scaling)
+ inst->clk_data.curr_freq = msm_vidc_max_freq(inst->core);
+ else
+ inst->clk_data.curr_freq = freq;
+
decision_done:
- inst->freq = freq;
msm_vidc_set_clocks(inst->core);
return 0;
}
@@ -422,29 +504,29 @@
int msm_dcvs_try_enable(struct msm_vidc_inst *inst)
{
- bool force_disable = false;
-
if (!inst) {
dprintk(VIDC_ERR, "%s: Invalid args: %p\n", __func__, inst);
return -EINVAL;
}
- force_disable = inst->session_type == MSM_VIDC_ENCODER ?
- !msm_vidc_enc_dcvs_mode :
- !msm_vidc_dec_dcvs_mode;
-
- if (force_disable || inst->flags & VIDC_THUMBNAIL) {
- dprintk(VIDC_PROF, "Thumbnail sessions don't need DCVS : %pK\n",
- inst);
- inst->dcvs.extra_capture_buffer_count = 0;
- inst->dcvs.extra_output_buffer_count = 0;
+ if (!msm_vidc_clock_scaling ||
+ inst->flags & VIDC_THUMBNAIL ||
+ inst->clk_data.low_latency_mode) {
+ dprintk(VIDC_PROF,
+ "This session doesn't need DCVS : %pK\n",
+ inst);
+ inst->clk_data.extra_capture_buffer_count = 0;
+ inst->clk_data.extra_output_buffer_count = 0;
+ inst->clk_data.dcvs_mode = false;
return false;
}
- inst->dcvs_mode = true;
+ inst->clk_data.dcvs_mode = true;
// TODO : Update with proper number based on on-target tuning.
- inst->dcvs.extra_capture_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
- inst->dcvs.extra_output_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
+ inst->clk_data.extra_capture_buffer_count =
+ DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
+ inst->clk_data.extra_output_buffer_count =
+ DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
return true;
}
@@ -482,6 +564,12 @@
struct clock_profile_entry *entry = NULL;
int fourcc;
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
+ __func__, inst);
+ return -EINVAL;
+ }
+
clk_freq_tbl = &inst->core->resources.clock_freq_tbl;
fourcc = inst->session_type == MSM_VIDC_DECODER ?
inst->fmts[OUTPUT_PORT].fourcc :
@@ -498,7 +586,7 @@
inst->session_type);
if (matched) {
- inst->entry = entry;
+ inst->clk_data.entry = entry;
break;
}
}
@@ -512,7 +600,7 @@
return rc;
}
-static inline void msm_dcvs_print_dcvs_stats(struct dcvs_stats *dcvs)
+static inline void msm_dcvs_print_dcvs_stats(struct clock_data *dcvs)
{
dprintk(VIDC_DBG,
"DCVS: Load_Low %d, Load High %d\n",
@@ -524,31 +612,31 @@
dcvs->min_threshold, dcvs->max_threshold);
}
-void msm_dcvs_init(struct msm_vidc_inst *inst)
+void msm_clock_data_reset(struct msm_vidc_inst *inst)
{
struct msm_vidc_core *core;
- int i = 0;
+ int i = 0, rc = 0;
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
u64 total_freq = 0, rate = 0, load;
int cycles;
- struct dcvs_stats *dcvs;
+ struct clock_data *dcvs;
dprintk(VIDC_DBG, "Init DCVS Load\n");
if (!inst || !inst->core) {
- dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+ dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
+ __func__, inst);
return;
}
core = inst->core;
- dcvs = &inst->dcvs;
- inst->dcvs = (struct dcvs_stats){0};
+ dcvs = &inst->clk_data;
load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
- cycles = inst->entry->vpp_cycles;
+ cycles = inst->clk_data.entry->vpp_cycles;
allowed_clks_tbl = core->resources.allowed_clks_tbl;
if (inst->session_type == MSM_VIDC_ENCODER) {
cycles = inst->flags & VIDC_LOW_POWER ?
- inst->entry->low_power_cycles :
+ inst->clk_data.entry->low_power_cycles :
cycles;
dcvs->buffer_type = HAL_BUFFER_INPUT;
@@ -573,7 +661,17 @@
dcvs->load = dcvs->load_high = rate;
dcvs->load_low = allowed_clks_tbl[i+1].clock_rate;
+ inst->clk_data.buffer_counter = 0;
+
msm_dcvs_print_dcvs_stats(dcvs);
+
+ msm_vidc_update_operating_rate(inst);
+
+ rc = msm_comm_scale_clocks_and_bus(inst);
+
+ if (rc)
+ dprintk(VIDC_ERR, "%s Failed to scale Clocks and Bus\n",
+ __func__);
}
int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
@@ -585,23 +683,26 @@
}
return buffer_type == HAL_BUFFER_INPUT ?
- inst->dcvs.extra_output_buffer_count :
- inst->dcvs.extra_capture_buffer_count;
+ inst->clk_data.extra_output_buffer_count :
+ inst->clk_data.extra_capture_buffer_count;
}
int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst)
{
int rc = 0;
- bool low_latency_mode;
struct hfi_device *hdev;
struct hal_video_work_mode pdata;
struct hal_enable latency;
- hdev = inst->core->device;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR,
+ "%s Invalid args: Inst = %pK\n",
+ __func__, inst);
+ return -EINVAL;
+ }
- low_latency_mode = msm_comm_g_ctrl_for_id(inst,
- V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE);
- if (low_latency_mode) {
+ hdev = inst->core->device;
+ if (inst->clk_data.low_latency_mode) {
pdata.video_work_mode = VIDC_WORK_MODE_1;
goto decision_done;
}
@@ -636,7 +737,7 @@
decision_done:
- inst->work_mode = pdata.video_work_mode;
+ inst->clk_data.work_mode = pdata.video_work_mode;
rc = call_hfi_op(hdev, session_set_property,
(void *)inst->session, HAL_PARAM_VIDEO_WORK_MODE,
(void *)&pdata);
@@ -646,7 +747,8 @@
/* For WORK_MODE_1, set Low Latency mode by default to HW. */
- if (inst->work_mode == VIDC_WORK_MODE_1) {
+ if (inst->session_type == MSM_VIDC_ENCODER &&
+ inst->clk_data.work_mode == VIDC_WORK_MODE_1) {
latency.enable = 1;
rc = call_hfi_op(hdev, session_set_property,
(void *)inst->session, HAL_PARAM_VENC_LOW_LATENCY,
@@ -675,8 +777,8 @@
return 0;
}
mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
- if (inst->core->resources.max_hq_mbs_per_frame > mbs_per_frame ||
- inst->core->resources.max_hq_fps > inst->prop.fps) {
+ if (mbs_per_frame >= inst->core->resources.max_hq_mbs_per_frame ||
+ inst->prop.fps >= inst->core->resources.max_hq_fps) {
enable = true;
}
@@ -692,9 +794,12 @@
__func__, inst);
goto fail_power_mode_set;
}
- inst->flags |= VIDC_LOW_POWER;
- dprintk(VIDC_PROF, "Power Save Mode set for inst: %pK\n", inst);
+ inst->flags = enable ?
+ inst->flags | VIDC_LOW_POWER :
+ inst->flags & ~VIDC_LOW_POWER;
+ dprintk(VIDC_PROF,
+ "Power Save Mode for inst: %pK Enable = %d\n", inst, enable);
fail_power_mode_set:
return rc;
}
@@ -704,15 +809,10 @@
{
struct msm_vidc_inst *inst = NULL;
- if (!core) {
- dprintk(VIDC_ERR, "Invalid args: %pK\n", core);
- return -EINVAL;
- }
-
dprintk(VIDC_PROF, "Core %d : Moving all inst to LP mode\n", core_id);
mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
- if (inst->core_id == core_id &&
+ if (inst->clk_data.core_id == core_id &&
inst->session_type == MSM_VIDC_ENCODER)
msm_vidc_power_save_mode_enable(inst, true);
}
@@ -731,19 +831,19 @@
list_for_each_entry(inst, &core->instances, list) {
u32 cycles, lp_cycles;
- if (!inst->core_id && core_id)
+ if (!(inst->clk_data.core_id && core_id))
continue;
if (inst->session_type == MSM_VIDC_DECODER) {
- cycles = lp_cycles = inst->entry->vpp_cycles;
+ cycles = lp_cycles = inst->clk_data.entry->vpp_cycles;
} else if (inst->session_type == MSM_VIDC_ENCODER) {
lp_mode |= inst->flags & VIDC_LOW_POWER;
cycles = lp_mode ?
- inst->entry->low_power_cycles :
- inst->entry->vpp_cycles;
+ inst->clk_data.entry->low_power_cycles :
+ inst->clk_data.entry->vpp_cycles;
} else {
continue;
}
- if (inst->core_id == 3)
+ if (inst->clk_data.core_id == 3)
cycles = cycles / 2;
current_inst_mbs_per_sec = msm_comm_get_inst_load(inst,
@@ -768,10 +868,17 @@
min_load = 0, min_lp_load = 0;
u32 min_core_id, min_lp_core_id;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR,
+ "%s Invalid args: Inst = %pK\n",
+ __func__, inst);
+ return -EINVAL;
+ }
+
core = inst->core;
hdev = core->device;
- max_freq = msm_vidc_max_freq(inst);
- inst->core_id = 0;
+ max_freq = msm_vidc_max_freq(inst->core);
+ inst->clk_data.core_id = 0;
core0_load = get_core_load(core, VIDC_CORE_ID_1, false);
core1_load = get_core_load(core, VIDC_CORE_ID_2, false);
@@ -786,11 +893,11 @@
VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
lp_cycles = inst->session_type == MSM_VIDC_ENCODER ?
- inst->entry->low_power_cycles :
- inst->entry->vpp_cycles;
+ inst->clk_data.entry->low_power_cycles :
+ inst->clk_data.entry->vpp_cycles;
current_inst_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS) *
- inst->entry->vpp_cycles;
+ inst->clk_data.entry->vpp_cycles;
current_inst_lp_load = msm_comm_get_inst_load(inst,
LOAD_CALC_NO_QUIRKS) * lp_cycles;
@@ -814,7 +921,7 @@
if (inst->session_type == MSM_VIDC_ENCODER && hier_mode) {
if (current_inst_load / 2 + core0_load <= max_freq &&
current_inst_load / 2 + core1_load <= max_freq) {
- inst->core_id = VIDC_CORE_ID_3;
+ inst->clk_data.core_id = VIDC_CORE_ID_3;
msm_vidc_power_save_mode_enable(inst, false);
goto decision_done;
}
@@ -825,32 +932,32 @@
core0_lp_load <= max_freq &&
current_inst_lp_load / 2 +
core1_lp_load <= max_freq) {
- inst->core_id = VIDC_CORE_ID_3;
+ inst->clk_data.core_id = VIDC_CORE_ID_3;
msm_vidc_power_save_mode_enable(inst, true);
goto decision_done;
}
}
if (current_inst_load + min_load < max_freq) {
- inst->core_id = min_core_id;
+ inst->clk_data.core_id = min_core_id;
dprintk(VIDC_DBG,
"Selected normally : Core ID = %d\n",
- inst->core_id);
+ inst->clk_data.core_id);
msm_vidc_power_save_mode_enable(inst, false);
} else if (current_inst_lp_load + min_load < max_freq) {
/* Move current instance to LP and return */
- inst->core_id = min_core_id;
+ inst->clk_data.core_id = min_core_id;
dprintk(VIDC_DBG,
"Selected by moving current to LP : Core ID = %d\n",
- inst->core_id);
+ inst->clk_data.core_id);
msm_vidc_power_save_mode_enable(inst, true);
} else if (current_inst_lp_load + min_lp_load < max_freq) {
/* Move all instances to LP mode and return */
- inst->core_id = min_lp_core_id;
+ inst->clk_data.core_id = min_lp_core_id;
dprintk(VIDC_DBG,
"Moved all inst's to LP: Core ID = %d\n",
- inst->core_id);
+ inst->clk_data.core_id);
msm_vidc_move_core_to_power_save_mode(core, min_lp_core_id);
} else {
rc = -EINVAL;
@@ -860,7 +967,7 @@
}
decision_done:
- core_info.video_core_enable_mask = inst->core_id;
+ core_info.video_core_enable_mask = inst->clk_data.core_id;
rc = call_hfi_op(hdev, session_set_property,
(void *)inst->session,
@@ -874,3 +981,4 @@
return rc;
}
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index d01f074..fe4822b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -31,7 +31,8 @@
/* Considering one safeguard buffer */
#define DCVS_BUFFER_SAFEGUARD (DCVS_DEC_EXTRA_OUTPUT_BUFFERS - 1)
-void msm_dcvs_init(struct msm_vidc_inst *inst);
+void msm_clock_data_reset(struct msm_vidc_inst *inst);
+int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst);
int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
enum hal_buffer buffer_type);
int msm_dcvs_try_enable(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 853edf5..d4562ce 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -584,9 +584,9 @@
capture_port_mbs = NUM_MBS_PER_FRAME(inst->prop.width[CAPTURE_PORT],
inst->prop.height[CAPTURE_PORT]);
- if (inst->operating_rate) {
- fps = (inst->operating_rate >> 16) ?
- inst->operating_rate >> 16 : 1;
+ if (inst->clk_data.operating_rate) {
+ fps = (inst->clk_data.operating_rate >> 16) ?
+ inst->clk_data.operating_rate >> 16 : 1;
/*
* Check if operating rate is less than fps.
* If Yes, then use fps to scale clocks
@@ -2510,7 +2510,7 @@
}
tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level);
- freq = core->freq;
+ freq = core->curr_freq;
is_turbo = is_core_turbo(core, freq);
dprintk(VIDC_DBG,
@@ -4738,9 +4738,9 @@
return 0;
}
- // Finish FLUSH As Soon As Possible.
- inst->dcvs.buffer_counter = 0;
- msm_comm_scale_clocks_and_bus(inst);
+ /* Finish FLUSH As Soon As Possible. */
+
+ msm_clock_data_reset(inst);
msm_comm_flush_dynamic_buffers(inst);
@@ -5474,7 +5474,7 @@
}
core = inst->core;
- dprintk(VIDC_ERR, "Venus core frequency = %lu", core->freq);
+ dprintk(VIDC_ERR, "Venus core frequency = %lu", core->curr_freq);
mutex_lock(&core->lock);
dprintk(VIDC_ERR, "Printing instance info that caused Error\n");
msm_comm_print_inst_info(inst);
@@ -5520,3 +5520,28 @@
mutex_unlock(&inst->lock);
return rc;
}
+
+u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+u32 get_frame_size_rgba(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888, width, height);
+}
+
+u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
+}
+
+u32 get_frame_size_tp10_ubwc(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 9c7eec5..098063d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -98,4 +98,9 @@
int msm_comm_v4l2_to_hal(int id, int value);
int msm_comm_hal_to_v4l2(int id, int value);
int msm_comm_session_continue(void *instance);
+u32 get_frame_size_nv12(int plane, u32 height, u32 width);
+u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width);
+u32 get_frame_size_rgba(int plane, u32 height, u32 width);
+u32 get_frame_size_nv21(int plane, u32 height, u32 width);
+u32 get_frame_size_tp10_ubwc(int plane, u32 height, u32 width);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 15ee8a8..f62c132 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -26,12 +26,10 @@
int msm_vidc_fw_low_power_mode = 1;
int msm_vidc_hw_rsp_timeout = 2000;
bool msm_vidc_fw_coverage = !true;
-bool msm_vidc_dec_dcvs_mode = true;
-bool msm_vidc_enc_dcvs_mode = true;
bool msm_vidc_sys_idle_indicator = !true;
int msm_vidc_firmware_unload_delay = 15000;
bool msm_vidc_thermal_mitigation_disabled = !true;
-bool msm_vidc_bitrate_clock_scaling = true;
+bool msm_vidc_clock_scaling = true;
bool msm_vidc_debug_timeout = !true;
#define MAX_DBG_BUF_SIZE 4096
@@ -174,8 +172,6 @@
__debugfs_create(x32, "fw_level", &msm_vidc_fw_debug) &&
__debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) &&
__debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) &&
- __debugfs_create(bool, "dcvs_dec_mode", &msm_vidc_dec_dcvs_mode) &&
- __debugfs_create(bool, "dcvs_enc_mode", &msm_vidc_enc_dcvs_mode) &&
__debugfs_create(u32, "fw_low_power_mode",
&msm_vidc_fw_low_power_mode) &&
__debugfs_create(u32, "debug_output", &msm_vidc_debug_out) &&
@@ -186,8 +182,8 @@
&msm_vidc_firmware_unload_delay) &&
__debugfs_create(bool, "disable_thermal_mitigation",
&msm_vidc_thermal_mitigation_disabled) &&
- __debugfs_create(bool, "bitrate_clock_scaling",
- &msm_vidc_bitrate_clock_scaling) &&
+ __debugfs_create(bool, "clock_scaling",
+ &msm_vidc_clock_scaling) &&
__debugfs_create(bool, "debug_timeout",
&msm_vidc_debug_timeout);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index cf5ce22..f5c8e5a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -59,12 +59,10 @@
extern int msm_vidc_fw_low_power_mode;
extern int msm_vidc_hw_rsp_timeout;
extern bool msm_vidc_fw_coverage;
-extern bool msm_vidc_dec_dcvs_mode;
-extern bool msm_vidc_enc_dcvs_mode;
extern bool msm_vidc_sys_idle_indicator;
extern int msm_vidc_firmware_unload_delay;
extern bool msm_vidc_thermal_mitigation_disabled;
-extern bool msm_vidc_bitrate_clock_scaling;
+extern bool msm_vidc_clock_scaling;
extern bool msm_vidc_debug_timeout;
#define VIDC_MSG_PRIO2STRING(__level) ({ \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 53bc068..37bccbd 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -52,7 +52,7 @@
/* Maintains the number of FTB's between each FBD over a window */
-#define DCVS_FTB_WINDOW 32
+#define DCVS_FTB_WINDOW 16
#define V4L2_EVENT_VIDC_BASE 10
@@ -205,7 +205,7 @@
int ebd;
};
-struct dcvs_stats {
+struct clock_data {
int buffer_counter;
int load;
int load_low;
@@ -215,6 +215,15 @@
unsigned int extra_capture_buffer_count;
unsigned int extra_output_buffer_count;
enum hal_buffer buffer_type;
+ bool dcvs_mode;
+ unsigned long bitrate;
+ unsigned long min_freq;
+ unsigned long curr_freq;
+ u32 operating_rate;
+ struct clock_profile_entry *entry;
+ u32 core_id;
+ enum hal_work_mode work_mode;
+ bool low_latency_mode;
};
struct profile_data {
@@ -259,7 +268,8 @@
struct msm_vidc_capability *capabilities;
struct delayed_work fw_unload_work;
bool smmu_fault_handled;
- unsigned long freq;
+ unsigned long min_freq;
+ unsigned long curr_freq;
};
struct msm_vidc_inst {
@@ -293,28 +303,21 @@
void *priv;
struct msm_vidc_debug debug;
struct buf_count count;
- struct dcvs_stats dcvs;
+ struct clock_data clk_data;
enum msm_vidc_modes flags;
struct msm_vidc_capability capability;
u32 buffer_size_limit;
enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
struct v4l2_ctrl **ctrls;
- bool dcvs_mode;
enum msm_vidc_pixel_depth bit_depth;
struct kref kref;
- unsigned long bitrate;
- unsigned long freq;
u32 buffers_held_in_driver;
atomic_t in_flush;
u32 pic_struct;
u32 colour_space;
- u32 operating_rate;
u32 profile;
u32 level;
u32 entropy_mode;
- struct clock_profile_entry *entry;
- u32 core_id;
- enum hal_work_mode work_mode;
};
extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index f8e0a6a..8752378 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -595,6 +595,7 @@
u32 qpp;
u32 qpb;
u32 layer_id;
+ u32 enable;
};
struct hal_quantization_range {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index d6c4bcb..77164be 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -536,7 +536,8 @@
struct hfi_quantization {
u32 qp_packed;
u32 layer_id;
- u32 reserved[4];
+ u32 enable;
+ u32 reserved[3];
};
struct hfi_quantization_range {
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index bacecbd..f37d64c 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -45,27 +45,36 @@
compat_caddr_t bitmap;
};
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+static int get_v4l2_window32(struct v4l2_window __user *kp,
+ struct v4l2_window32 __user *up)
{
+ u32 clipcount = 0;
+
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
- copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
- get_user(kp->field, &up->field) ||
- get_user(kp->chromakey, &up->chromakey) ||
- get_user(kp->clipcount, &up->clipcount))
+ !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_window)) ||
+ copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
+ copy_in_user(&kp->field, &up->field, sizeof(up->field)) ||
+ copy_in_user(&kp->chromakey, &up->chromakey,
+ sizeof(up->chromakey)) ||
+ copy_in_user(&kp->clipcount, &up->clipcount,
+ sizeof(up->clipcount)))
return -EFAULT;
- if (kp->clipcount > 2048)
+ if (get_user(clipcount, &kp->clipcount))
+ return -EFAULT;
+ if (clipcount > 2048)
return -EINVAL;
- if (kp->clipcount) {
+ if (clipcount) {
struct v4l2_clip32 __user *uclips;
struct v4l2_clip __user *kclips;
- int n = kp->clipcount;
+ int n = clipcount;
compat_caddr_t p;
if (get_user(p, &up->clips))
return -EFAULT;
uclips = compat_ptr(p);
kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
- kp->clips = kclips;
+ if (put_user(kclips, &kp->clips))
+ return -EFAULT;
while (--n >= 0) {
if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
return -EFAULT;
@@ -74,89 +83,106 @@
uclips += 1;
kclips += 1;
}
- } else
- kp->clips = NULL;
- return 0;
-}
-
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
-{
- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
- put_user(kp->field, &up->field) ||
- put_user(kp->chromakey, &up->chromakey) ||
- put_user(kp->clipcount, &up->clipcount))
+ } else {
+ if (put_user(NULL, &kp->clips))
return -EFAULT;
+ }
return 0;
}
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+static int put_v4l2_window32(struct v4l2_window __user *kp,
+ struct v4l2_window32 __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
+ if (copy_in_user(&up->w, &kp->w, sizeof(up->w)) ||
+ copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
+ copy_in_user(&up->chromakey, &kp->chromakey,
+ sizeof(up->chromakey)) ||
+ copy_in_user(&up->clipcount, &kp->clipcount,
+ sizeof(up->clipcount)))
return -EFAULT;
return 0;
}
-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+static inline int get_v4l2_pix_format(struct v4l2_pix_format __user *kp,
+ struct v4l2_pix_format __user *up)
+{
+ if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format)))
+ return -EFAULT;
+ return 0;
+}
+
+static inline int get_v4l2_pix_format_mplane(
+ struct v4l2_pix_format_mplane __user *kp,
struct v4l2_pix_format_mplane __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+ if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+static inline int put_v4l2_pix_format(struct v4l2_pix_format __user *kp,
+ struct v4l2_pix_format __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+ if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+static inline int put_v4l2_pix_format_mplane(
+ struct v4l2_pix_format_mplane __user *kp,
struct v4l2_pix_format_mplane __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+ if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
return -EFAULT;
return 0;
}
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+static inline int get_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
+ struct v4l2_vbi_format __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
+ if (copy_in_user(kp, up, sizeof(struct v4l2_vbi_format)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+static inline int put_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
+ struct v4l2_vbi_format __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
+ if (copy_in_user(up, kp, sizeof(struct v4l2_vbi_format)))
return -EFAULT;
return 0;
}
-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+static inline int get_v4l2_sliced_vbi_format(
+ struct v4l2_sliced_vbi_format __user *kp,
+ struct v4l2_sliced_vbi_format __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+ if (copy_in_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+static inline int put_v4l2_sliced_vbi_format(
+ struct v4l2_sliced_vbi_format __user *kp,
+ struct v4l2_sliced_vbi_format __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+ if (copy_in_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
return -EFAULT;
return 0;
}
-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+static inline int get_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
+ struct v4l2_sdr_format __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
+ if (copy_in_user(kp, up, sizeof(struct v4l2_sdr_format)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+static inline int put_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
+ struct v4l2_sdr_format __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
+ if (copy_in_user(up, kp, sizeof(struct v4l2_sdr_format)))
return -EFAULT;
return 0;
}
@@ -191,12 +217,17 @@
__u32 reserved[8];
};
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
+ struct v4l2_format32 __user *up)
{
- if (get_user(kp->type, &up->type))
+ u32 type;
+
+ if (copy_in_user(&kp->type, &up->type, sizeof(up->type)))
return -EFAULT;
- switch (kp->type) {
+ if (get_user(type, &kp->type))
+ return -EFAULT;
+ switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
@@ -223,27 +254,39 @@
}
}
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_format32(struct v4l2_format __user *kp,
+ struct v4l2_format32 __user *up)
{
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
+ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
+ !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_format)))
return -EFAULT;
return __get_v4l2_format32(kp, up);
}
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
+ struct v4l2_create_buffers32 __user *up)
{
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
- copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
+ !access_ok(VERIFY_WRITE, kp,
+ sizeof(struct v4l2_create_buffers)) ||
+ copy_in_user(kp, up,
+ offsetof(struct v4l2_create_buffers32, format)))
return -EFAULT;
return __get_v4l2_format32(&kp->format, &up->format);
}
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __put_v4l2_format32(struct v4l2_format __user *kp,
+ struct v4l2_format32 __user *up)
{
- if (put_user(kp->type, &up->type))
+ u32 type;
+
+ if (copy_in_user(&up->type, &kp->type, sizeof(up->type)))
return -EFAULT;
- switch (kp->type) {
+ if (get_user(type, &kp->type))
+ return -EFAULT;
+
+ switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
@@ -270,18 +313,24 @@
}
}
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int put_v4l2_format32(struct v4l2_format __user *kp,
+ struct v4l2_format32 __user *up)
{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
+ !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_format)))
return -EFAULT;
return __put_v4l2_format32(kp, up);
}
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
+ struct v4l2_create_buffers32 __user *up)
{
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
- copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+ !access_ok(VERIFY_READ, kp,
+ sizeof(struct v4l2_create_buffers)) ||
+ copy_in_user(up, kp,
+ offsetof(struct v4l2_create_buffers32, format)) ||
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
return -EFAULT;
return __put_v4l2_format32(&kp->format, &up->format);
}
@@ -295,24 +344,30 @@
__u32 reserved[4];
};
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int get_v4l2_standard32(struct v4l2_standard __user *kp,
+ struct v4l2_standard32 __user *up)
{
/* other fields are not set by the user, nor used by the driver */
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
- get_user(kp->index, &up->index))
+ !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_standard)) ||
+ copy_in_user(&kp->index, &up->index, sizeof(up->index)))
return -EFAULT;
return 0;
}
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int put_v4l2_standard32(struct v4l2_standard __user *kp,
+ struct v4l2_standard32 __user *up)
{
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
- put_user(kp->index, &up->index) ||
- put_user(kp->id, &up->id) ||
- copy_to_user(up->name, kp->name, 24) ||
- copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
- put_user(kp->framelines, &up->framelines) ||
- copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
+ !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_standard)) ||
+ copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
+ copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
+ copy_in_user(up->name, kp->name, 24) ||
+ copy_in_user(&up->frameperiod, &kp->frameperiod,
+ sizeof(up->frameperiod)) ||
+ copy_in_user(&up->framelines, &kp->framelines,
+ sizeof(up->framelines)) ||
+ copy_in_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
return -EFAULT;
return 0;
}
@@ -360,6 +415,10 @@
if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
copy_in_user(&up->data_offset, &up32->data_offset,
+ sizeof(__u32)) ||
+ copy_in_user(up->reserved, up32->reserved,
+ sizeof(up->reserved)) ||
+ copy_in_user(&up->length, &up32->length,
sizeof(__u32)))
return -EFAULT;
@@ -386,7 +445,9 @@
{
if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
copy_in_user(&up32->data_offset, &up->data_offset,
- sizeof(__u32)))
+ sizeof(__u32)) ||
+ copy_in_user(up32->reserved, up->reserved,
+ sizeof(up32->reserved)))
return -EFAULT;
/* For MMAP, driver might've set up the offset, so copy it back.
@@ -404,34 +465,48 @@
return 0;
}
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
+ struct v4l2_buffer32 __user *up)
{
struct v4l2_plane32 __user *uplane32;
struct v4l2_plane __user *uplane;
compat_caddr_t p;
int num_planes;
+ struct timeval time;
+ u32 plane_count, memory, type;
int ret;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
- get_user(kp->index, &up->index) ||
- get_user(kp->type, &up->type) ||
- get_user(kp->flags, &up->flags) ||
- get_user(kp->memory, &up->memory) ||
- get_user(kp->length, &up->length))
+ !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_buffer)) ||
+ copy_in_user(&kp->index, &up->index, sizeof(up->index)) ||
+ copy_in_user(&kp->type, &up->type, sizeof(up->type)) ||
+ copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
+ copy_in_user(&kp->memory, &up->memory, sizeof(up->memory)) ||
+ copy_in_user(&kp->length, &up->length, sizeof(up->length)))
return -EFAULT;
- if (V4L2_TYPE_IS_OUTPUT(kp->type))
- if (get_user(kp->bytesused, &up->bytesused) ||
- get_user(kp->field, &up->field) ||
- get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
- get_user(kp->timestamp.tv_usec,
- &up->timestamp.tv_usec))
+ if (get_user(type, &kp->type))
+ return -EFAULT;
+ if (V4L2_TYPE_IS_OUTPUT(type))
+ if (copy_in_user(&kp->bytesused, &up->bytesused,
+ sizeof(up->bytesused)) ||
+ copy_in_user(&kp->field, &up->field,
+ sizeof(up->field)) ||
+ get_user(time.tv_sec, &up->timestamp.tv_sec) ||
+ get_user(time.tv_usec, &up->timestamp.tv_usec) ||
+ put_user(time.tv_sec, &kp->timestamp.tv_sec) ||
+ put_user(time.tv_usec, &kp->timestamp.tv_usec))
return -EFAULT;
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
- num_planes = kp->length;
+ if (get_user(memory, &kp->memory))
+ return -EFAULT;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ if (get_user(plane_count, &kp->length))
+ return -EFAULT;
+ num_planes = plane_count;
if (num_planes == 0) {
- kp->m.planes = NULL;
+ if (put_user(NULL, &kp->m.planes))
+ return -EFAULT;
/* num_planes == 0 is legal, e.g. when userspace doesn't
* need planes array on DQBUF*/
return 0;
@@ -449,37 +524,43 @@
* by passing a very big num_planes value */
uplane = compat_alloc_user_space(num_planes *
sizeof(struct v4l2_plane));
- kp->m.planes = (__force struct v4l2_plane *)uplane;
+ if (put_user(uplane, &kp->m.planes))
+ return -EFAULT;
while (--num_planes >= 0) {
- ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+ ret = get_v4l2_plane32(uplane, uplane32, memory);
if (ret)
return ret;
++uplane;
++uplane32;
}
} else {
- switch (kp->memory) {
+ switch (memory) {
case V4L2_MEMORY_MMAP:
- if (get_user(kp->m.offset, &up->m.offset))
+ if (copy_in_user(&kp->m.offset, &up->m.offset,
+ sizeof(up->m.offset)))
return -EFAULT;
break;
case V4L2_MEMORY_USERPTR:
{
compat_long_t tmp;
+ unsigned long userptr;
if (get_user(tmp, &up->m.userptr))
return -EFAULT;
- kp->m.userptr = (unsigned long)compat_ptr(tmp);
+ userptr = (unsigned long)compat_ptr(tmp);
+ put_user(userptr, &kp->m.userptr);
}
break;
case V4L2_MEMORY_OVERLAY:
- if (get_user(kp->m.offset, &up->m.offset))
+ if (copy_in_user(&kp->m.offset, &up->m.offset,
+ sizeof(up->m.offset)))
return -EFAULT;
break;
case V4L2_MEMORY_DMABUF:
- if (get_user(kp->m.fd, &up->m.fd))
+ if (copy_in_user(&kp->m.fd, &up->m.fd,
+ sizeof(up->m.fd)))
return -EFAULT;
break;
}
@@ -488,65 +569,86 @@
return 0;
}
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
+ struct v4l2_buffer32 __user *up)
{
struct v4l2_plane32 __user *uplane32;
struct v4l2_plane __user *uplane;
compat_caddr_t p;
int num_planes;
int ret;
+ struct timeval time;
+ u32 memory, type, length;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
- put_user(kp->index, &up->index) ||
- put_user(kp->type, &up->type) ||
- put_user(kp->flags, &up->flags) ||
- put_user(kp->memory, &up->memory))
- return -EFAULT;
+ !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_buffer)) ||
+ copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
+ copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
+ copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
+ copy_in_user(&up->memory, &kp->memory, sizeof(up->memory)))
+ return -EFAULT;
- if (put_user(kp->bytesused, &up->bytesused) ||
- put_user(kp->field, &up->field) ||
- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
- put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
- copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
- put_user(kp->sequence, &up->sequence) ||
- put_user(kp->reserved2, &up->reserved2) ||
- put_user(kp->reserved, &up->reserved) ||
- put_user(kp->length, &up->length))
- return -EFAULT;
+ if (copy_in_user(&up->bytesused, &kp->bytesused,
+ sizeof(up->bytesused)) ||
+ copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
+ get_user(time.tv_sec, &kp->timestamp.tv_sec) ||
+ get_user(time.tv_usec, &kp->timestamp.tv_usec) ||
+ put_user(time.tv_sec, &up->timestamp.tv_sec) ||
+ put_user(time.tv_usec, &up->timestamp.tv_usec) ||
+ copy_in_user(&up->timecode, &kp->timecode,
+ sizeof(struct v4l2_timecode)) ||
+ copy_in_user(&up->sequence, &kp->sequence,
+ sizeof(up->sequence)) ||
+ copy_in_user(&up->reserved2, &kp->reserved2,
+ sizeof(up->reserved2)) ||
+ copy_in_user(&up->reserved, &kp->reserved,
+ sizeof(up->reserved)) ||
+ copy_in_user(&up->length, &kp->length, sizeof(up->length)))
+ return -EFAULT;
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
- num_planes = kp->length;
+ if (get_user(type, &kp->type) ||
+ get_user(memory, &kp->memory) ||
+ get_user(length, &kp->length))
+ return -EINVAL;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ num_planes = length;
if (num_planes == 0)
return 0;
- uplane = (__force struct v4l2_plane __user *)kp->m.planes;
+ if (get_user(uplane, &kp->m.planes))
+ return -EFAULT;
if (get_user(p, &up->m.planes))
return -EFAULT;
uplane32 = compat_ptr(p);
while (--num_planes >= 0) {
- ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+ ret = put_v4l2_plane32(uplane, uplane32, memory);
if (ret)
return ret;
++uplane;
++uplane32;
}
} else {
- switch (kp->memory) {
+ switch (memory) {
case V4L2_MEMORY_MMAP:
- if (put_user(kp->m.offset, &up->m.offset))
+ if (copy_in_user(&up->m.offset, &kp->m.offset,
+ sizeof(up->m.offset)))
return -EFAULT;
break;
case V4L2_MEMORY_USERPTR:
- if (put_user(kp->m.userptr, &up->m.userptr))
+ if (copy_in_user(&up->m.userptr, &kp->m.userptr,
+ sizeof(up->m.userptr)))
return -EFAULT;
break;
case V4L2_MEMORY_OVERLAY:
- if (put_user(kp->m.offset, &up->m.offset))
+ if (copy_in_user(&up->m.offset, &kp->m.offset,
+ sizeof(up->m.offset)))
return -EFAULT;
break;
case V4L2_MEMORY_DMABUF:
- if (put_user(kp->m.fd, &up->m.fd))
+ if (copy_in_user(&up->m.fd, &kp->m.fd,
+ sizeof(up->m.fd)))
return -EFAULT;
break;
}
@@ -571,29 +673,39 @@
} fmt;
};
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+ struct v4l2_framebuffer32 __user *up)
{
u32 tmp;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
+ !access_ok(VERIFY_WRITE, kp,
+ sizeof(struct v4l2_framebuffer)) ||
get_user(tmp, &up->base) ||
- get_user(kp->capability, &up->capability) ||
- get_user(kp->flags, &up->flags) ||
- copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
+ put_user(compat_ptr(tmp), &kp->base) ||
+ copy_in_user(&kp->capability, &up->capability,
+ sizeof(up->capability)) ||
+ copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
+ copy_in_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
return -EFAULT;
- kp->base = (__force void *)compat_ptr(tmp);
+
return 0;
}
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+ struct v4l2_framebuffer32 __user *up)
{
- u32 tmp = (u32)((unsigned long)kp->base);
+ unsigned long base;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
- put_user(tmp, &up->base) ||
- put_user(kp->capability, &up->capability) ||
- put_user(kp->flags, &up->flags) ||
- copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
+ !access_ok(VERIFY_READ, kp,
+ sizeof(struct v4l2_framebuffer)) ||
+ copy_from_user(&base, &kp->base, sizeof(base)) ||
+ put_user((u32)base, &up->base) ||
+ copy_in_user(&up->capability, &kp->capability,
+ sizeof(up->capability)) ||
+ copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
+ copy_in_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
return -EFAULT;
return 0;
}
@@ -611,16 +723,18 @@
/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
Otherwise it is identical to the 32-bit version. */
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+static inline int get_v4l2_input32(struct v4l2_input __user *kp,
+ struct v4l2_input32 __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
+ if (copy_in_user(kp, up, sizeof(struct v4l2_input32)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+static inline int put_v4l2_input32(struct v4l2_input __user *kp,
+ struct v4l2_input32 __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
+ if (copy_in_user(up, kp, sizeof(struct v4l2_input32)))
return -EFAULT;
return 0;
}
@@ -661,23 +775,33 @@
}
}
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int get_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
+ struct v4l2_ext_controls32 __user *up)
{
struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols;
int n;
compat_caddr_t p;
+ u32 count;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
- get_user(kp->which, &up->which) ||
- get_user(kp->count, &up->count) ||
- get_user(kp->error_idx, &up->error_idx) ||
- copy_from_user(kp->reserved, up->reserved,
- sizeof(kp->reserved)))
+ !access_ok(VERIFY_WRITE, kp,
+ sizeof(struct v4l2_ext_controls)) ||
+ copy_in_user(&kp->which, &up->which,
+ sizeof(up->which)) ||
+ copy_in_user(&kp->count, &up->count, sizeof(up->count)) ||
+ copy_in_user(&kp->error_idx, &up->error_idx,
+ sizeof(up->error_idx)) ||
+ copy_in_user(kp->reserved, up->reserved,
+ sizeof(up->reserved)))
return -EFAULT;
- n = kp->count;
+
+ if (get_user(count, &kp->count))
+ return -EFAULT;
+ n = count;
if (n == 0) {
- kp->controls = NULL;
+ if (put_user(NULL, &kp->controls))
+ return -EINVAL;
return 0;
}
if (get_user(p, &up->controls))
@@ -687,7 +811,9 @@
n * sizeof(struct v4l2_ext_control32)))
return -EFAULT;
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
- kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+ if (put_user(kcontrols, &kp->controls))
+ return -EFAULT;
+
while (--n >= 0) {
u32 id;
@@ -710,23 +836,33 @@
return 0;
}
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int put_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
+ struct v4l2_ext_controls32 __user *up)
{
struct v4l2_ext_control32 __user *ucontrols;
- struct v4l2_ext_control __user *kcontrols =
- (__force struct v4l2_ext_control __user *)kp->controls;
- int n = kp->count;
+ struct v4l2_ext_control __user *kcontrols;
+ int n;
+ u32 count;
compat_caddr_t p;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
- put_user(kp->which, &up->which) ||
- put_user(kp->count, &up->count) ||
- put_user(kp->error_idx, &up->error_idx) ||
- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ !access_ok(VERIFY_READ, kp,
+ sizeof(struct v4l2_ext_controls)) ||
+ copy_in_user(&up->which, &kp->which,
+ sizeof(up->which)) ||
+ copy_in_user(&up->count, &kp->count,
+ sizeof(up->count)) ||
+ copy_in_user(&up->error_idx, &kp->error_idx,
+ sizeof(up->error_idx)) ||
+ copy_in_user(up->reserved, kp->reserved,
+ sizeof(up->reserved)) ||
+ get_user(count, &kp->count) ||
+ get_user(kcontrols, &kp->controls))
return -EFAULT;
- if (!kp->count)
+ if (!count)
return 0;
+ n = count;
if (get_user(p, &up->controls))
return -EFAULT;
ucontrols = compat_ptr(p);
@@ -766,16 +902,22 @@
__u32 reserved[8];
};
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+static int put_v4l2_event32(struct v4l2_event __user *kp,
+ struct v4l2_event32 __user *up)
{
+ struct timespec ts;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
- put_user(kp->type, &up->type) ||
- copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
- put_user(kp->pending, &up->pending) ||
- put_user(kp->sequence, &up->sequence) ||
- compat_put_timespec(&kp->timestamp, &up->timestamp) ||
- put_user(kp->id, &up->id) ||
- copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
+ !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_event)) ||
+ copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
+ copy_in_user(&up->u, &kp->u, sizeof(up->u)) ||
+ copy_in_user(&up->pending, &kp->pending,
+ sizeof(up->pending)) ||
+ copy_in_user(&up->sequence, &kp->sequence,
+ sizeof(up->sequence)) ||
+ copy_from_user(&ts, &kp->timestamp, sizeof(ts)) ||
+ compat_put_timespec(&ts, &up->timestamp) ||
+ copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
+ copy_in_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
return -EFAULT;
return 0;
}
@@ -788,31 +930,39 @@
compat_caddr_t edid;
};
-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int get_v4l2_edid32(struct v4l2_edid __user *kp,
+ struct v4l2_edid32 __user *up)
{
u32 tmp;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
- get_user(kp->pad, &up->pad) ||
- get_user(kp->start_block, &up->start_block) ||
- get_user(kp->blocks, &up->blocks) ||
+ !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_edid)) ||
+ copy_in_user(&kp->pad, &up->pad, sizeof(up->pad)) ||
+ copy_in_user(&kp->start_block, &up->start_block,
+ sizeof(up->start_block)) ||
+ copy_in_user(&kp->blocks, &up->blocks, sizeof(up->blocks)) ||
get_user(tmp, &up->edid) ||
- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+ put_user(compat_ptr(tmp), &kp->edid) ||
+ copy_in_user(kp->reserved, up->reserved,
+ sizeof(kp->reserved)))
return -EFAULT;
- kp->edid = (__force u8 *)compat_ptr(tmp);
return 0;
}
-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int put_v4l2_edid32(struct v4l2_edid __user *kp,
+ struct v4l2_edid32 __user *up)
{
- u32 tmp = (u32)((unsigned long)kp->edid);
+ unsigned long ptr;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
- put_user(kp->pad, &up->pad) ||
- put_user(kp->start_block, &up->start_block) ||
- put_user(kp->blocks, &up->blocks) ||
- put_user(tmp, &up->edid) ||
- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_edid)) ||
+ copy_in_user(&up->pad, &kp->pad, sizeof(up->pad)) ||
+ copy_in_user(&up->start_block, &kp->start_block,
+ sizeof(up->start_block)) ||
+ copy_in_user(&up->blocks, &kp->blocks, sizeof(up->blocks)) ||
+ copy_from_user(&ptr, &kp->edid, sizeof(ptr)) ||
+ put_user((u32)ptr, &up->edid) ||
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
return -EFAULT;
return 0;
}
@@ -859,11 +1009,16 @@
struct v4l2_edid v2edid;
unsigned long vx;
int vi;
- } karg;
+ } *karg;
void __user *up = compat_ptr(arg);
int compatible_arg = 1;
long err = 0;
+ karg = compat_alloc_user_space(sizeof(*karg));
+ if (karg == NULL) {
+ return -EFAULT;
+ }
+
/* First, convert the command. */
switch (cmd) {
case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
@@ -899,7 +1054,8 @@
case VIDIOC_STREAMOFF:
case VIDIOC_S_INPUT:
case VIDIOC_S_OUTPUT:
- err = get_user(karg.vi, (s32 __user *)up);
+ err = copy_in_user(&karg->vi, (s32 __user *)up,
+ sizeof(karg->vi));
compatible_arg = 0;
break;
@@ -910,19 +1066,19 @@
case VIDIOC_G_EDID:
case VIDIOC_S_EDID:
- err = get_v4l2_edid32(&karg.v2edid, up);
+ err = get_v4l2_edid32(&karg->v2edid, up);
compatible_arg = 0;
break;
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
case VIDIOC_TRY_FMT:
- err = get_v4l2_format32(&karg.v2f, up);
+ err = get_v4l2_format32(&karg->v2f, up);
compatible_arg = 0;
break;
case VIDIOC_CREATE_BUFS:
- err = get_v4l2_create32(&karg.v2crt, up);
+ err = get_v4l2_create32(&karg->v2crt, up);
compatible_arg = 0;
break;
@@ -930,12 +1086,12 @@
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
- err = get_v4l2_buffer32(&karg.v2b, up);
+ err = get_v4l2_buffer32(&karg->v2b, up);
compatible_arg = 0;
break;
case VIDIOC_S_FBUF:
- err = get_v4l2_framebuffer32(&karg.v2fb, up);
+ err = get_v4l2_framebuffer32(&karg->v2fb, up);
compatible_arg = 0;
break;
@@ -944,19 +1100,19 @@
break;
case VIDIOC_ENUMSTD:
- err = get_v4l2_standard32(&karg.v2s, up);
+ err = get_v4l2_standard32(&karg->v2s, up);
compatible_arg = 0;
break;
case VIDIOC_ENUMINPUT:
- err = get_v4l2_input32(&karg.v2i, up);
+ err = get_v4l2_input32(&karg->v2i, up);
compatible_arg = 0;
break;
case VIDIOC_G_EXT_CTRLS:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_TRY_EXT_CTRLS:
- err = get_v4l2_ext_controls32(&karg.v2ecs, up);
+ err = get_v4l2_ext_controls32(&karg->v2ecs, up);
compatible_arg = 0;
break;
case VIDIOC_DQEVENT:
@@ -969,11 +1125,7 @@
if (compatible_arg)
err = native_ioctl(file, cmd, (unsigned long)up);
else {
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- err = native_ioctl(file, cmd, (unsigned long)&karg);
- set_fs(old_fs);
+ err = native_ioctl(file, cmd, (unsigned long)karg);
}
/* Special case: even after an error we need to put the
@@ -983,7 +1135,7 @@
case VIDIOC_G_EXT_CTRLS:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_TRY_EXT_CTRLS:
- if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+ if (put_v4l2_ext_controls32(&karg->v2ecs, up))
err = -EFAULT;
break;
}
@@ -995,44 +1147,44 @@
case VIDIOC_S_OUTPUT:
case VIDIOC_G_INPUT:
case VIDIOC_G_OUTPUT:
- err = put_user(((s32)karg.vi), (s32 __user *)up);
+ err = copy_in_user(up, &karg->vi, sizeof(s32));
break;
case VIDIOC_G_FBUF:
- err = put_v4l2_framebuffer32(&karg.v2fb, up);
+ err = put_v4l2_framebuffer32(&karg->v2fb, up);
break;
case VIDIOC_DQEVENT:
- err = put_v4l2_event32(&karg.v2ev, up);
+ err = put_v4l2_event32(&karg->v2ev, up);
break;
case VIDIOC_G_EDID:
case VIDIOC_S_EDID:
- err = put_v4l2_edid32(&karg.v2edid, up);
+ err = put_v4l2_edid32(&karg->v2edid, up);
break;
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
case VIDIOC_TRY_FMT:
- err = put_v4l2_format32(&karg.v2f, up);
+ err = put_v4l2_format32(&karg->v2f, up);
break;
case VIDIOC_CREATE_BUFS:
- err = put_v4l2_create32(&karg.v2crt, up);
+ err = put_v4l2_create32(&karg->v2crt, up);
break;
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
- err = put_v4l2_buffer32(&karg.v2b, up);
+ err = put_v4l2_buffer32(&karg->v2b, up);
break;
case VIDIOC_ENUMSTD:
- err = put_v4l2_standard32(&karg.v2s, up);
+ err = put_v4l2_standard32(&karg->v2s, up);
break;
case VIDIOC_ENUMINPUT:
- err = put_v4l2_input32(&karg.v2i, up);
+ err = put_v4l2_input32(&karg->v2i, up);
break;
}
return err;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2c02d2d..877c4d1 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -5869,7 +5869,8 @@
* It will return false if it is GPCE based crypto instance or
* ICE is setup properly
*/
- if (qseecom_enable_ice_setup(create_key_req.usage))
+ ret = qseecom_enable_ice_setup(create_key_req.usage);
+ if (ret)
goto free_buf;
do {
@@ -5998,7 +5999,8 @@
* It will return false if it is GPCE based crypto instance or
* ICE is setup properly
*/
- if (qseecom_enable_ice_setup(wipe_key_req.usage))
+ ret = qseecom_enable_ice_setup(wipe_key_req.usage);
+ if (ret)
goto free_buf;
ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 6523cb0..16c9096 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -6764,12 +6764,12 @@
PCIE_DBG(pcie_dev, "RC%d: PM_Enter_L23 is NOT received\n",
pcie_dev->rc_idx);
- msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
-
if (pcie_dev->use_pinctrl && pcie_dev->pins_sleep)
pinctrl_select_state(pcie_dev->pinctrl,
pcie_dev->pins_sleep);
+ msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
+
PCIE_DBG(pcie_dev, "RC%d: exit\n", pcie_dev->rc_idx);
return ret;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index af4d4c8..fb42ef7 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3679,6 +3679,7 @@
* pipe will be unsuspended as part of
* enabling IPA clocks
*/
+ mutex_lock(&ipa_ctx->sps_pm.sps_pm_lock);
if (!atomic_read(
&ipa_ctx->sps_pm.dec_clients)
) {
@@ -3691,6 +3692,7 @@
1);
ipa_sps_process_irq_schedule_rel();
}
+ mutex_unlock(&ipa_ctx->sps_pm.sps_pm_lock);
} else {
resource = ipa2_get_rm_resource_from_ep(i);
res = ipa_rm_request_resource_with_timer(
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index e474a40..b60c7a6 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1480,17 +1480,24 @@
void ipa_delete_dflt_flt_rules(u32 ipa_ep_idx)
{
+ struct ipa_flt_tbl *tbl;
struct ipa_ep_context *ep = &ipa_ctx->ep[ipa_ep_idx];
mutex_lock(&ipa_ctx->lock);
if (ep->dflt_flt4_rule_hdl) {
+ tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
__ipa_del_flt_rule(ep->dflt_flt4_rule_hdl);
ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v4);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt4_rule_hdl = 0;
}
if (ep->dflt_flt6_rule_hdl) {
+ tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
__ipa_del_flt_rule(ep->dflt_flt6_rule_hdl);
ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v6);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt6_rule_hdl = 0;
}
mutex_unlock(&ipa_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 83fd2b2..30f5712 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -3620,6 +3620,8 @@
* pipe will be unsuspended as part of
* enabling IPA clocks
*/
+ mutex_lock(&ipa3_ctx->transport_pm.
+ transport_pm_mutex);
if (!atomic_read(
&ipa3_ctx->transport_pm.dec_clients)
) {
@@ -3632,6 +3634,8 @@
1);
ipa3_process_irq_schedule_rel();
}
+ mutex_unlock(&ipa3_ctx->transport_pm.
+ transport_pm_mutex);
} else {
resource = ipa3_get_rm_resource_from_ep(i);
res =
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 9d25e4a..89dd274 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -1004,6 +1004,7 @@
struct ipa3_ep_context *ep;
int empty;
int result;
+ int i;
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1038,7 +1039,17 @@
if (IPA_CLIENT_IS_CONS(ep->client))
cancel_delayed_work_sync(&ep->sys->replenish_rx_work);
flush_workqueue(ep->sys->wq);
- result = ipa3_stop_gsi_channel(clnt_hdl);
+ /* channel stop might fail on timeout if IPA is busy */
+ for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
+ result = ipa3_stop_gsi_channel(clnt_hdl);
+ if (result == GSI_STATUS_SUCCESS)
+ break;
+
+ if (result != -GSI_STATUS_AGAIN &&
+ result != -GSI_STATUS_TIMED_OUT)
+ break;
+ }
+
if (result != GSI_STATUS_SUCCESS) {
IPAERR("GSI stop chan err: %d.\n", result);
ipa_assert();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index 0cc1206..ff763c4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -1389,16 +1389,23 @@
void ipa3_delete_dflt_flt_rules(u32 ipa_ep_idx)
{
struct ipa3_ep_context *ep = &ipa3_ctx->ep[ipa_ep_idx];
+ struct ipa3_flt_tbl *tbl;
mutex_lock(&ipa3_ctx->lock);
if (ep->dflt_flt4_rule_hdl) {
+ tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
__ipa_del_flt_rule(ep->dflt_flt4_rule_hdl);
ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v4);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt4_rule_hdl = 0;
}
if (ep->dflt_flt6_rule_hdl) {
+ tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
__ipa_del_flt_rule(ep->dflt_flt6_rule_hdl);
ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v6);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt6_rule_hdl = 0;
}
mutex_unlock(&ipa3_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 5a38db3..f066d94 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4352,21 +4352,30 @@
memset(&mem, 0, sizeof(mem));
- for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
- IPADBG("Calling gsi_stop_channel\n");
+ if (IPA_CLIENT_IS_PROD(ep->client)) {
+ IPADBG("Calling gsi_stop_channel ch:%lu\n",
+ ep->gsi_chan_hdl);
res = gsi_stop_channel(ep->gsi_chan_hdl);
- IPADBG("gsi_stop_channel returned %d\n", res);
+ IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+ ep->gsi_chan_hdl, res);
+ goto end_sequence;
+ }
+
+ for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
+ IPADBG("Calling gsi_stop_channel ch:%lu\n",
+ ep->gsi_chan_hdl);
+ res = gsi_stop_channel(ep->gsi_chan_hdl);
+ IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+ ep->gsi_chan_hdl, res);
if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
goto end_sequence;
- if (IPA_CLIENT_IS_CONS(ep->client)) {
- IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
- /* Send a 1B packet DMA_TASK to IPA and try again */
- res = ipa3_inject_dma_task_for_gsi();
- if (res) {
- IPAERR("Failed to inject DMA TASk for GSI\n");
- goto end_sequence;
- }
+ IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
+ /* Send a 1B packet DMA_TASK to IPA and try again */
+ res = ipa3_inject_dma_task_for_gsi();
+ if (res) {
+ IPAERR("Failed to inject DMA TASk for GSI\n");
+ goto end_sequence;
}
/* sleep for short period to flush IPA */
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index 9566e24..c45fb0d 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -177,6 +177,7 @@
#define CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN BIT(27)
#define CPR4_REG_MISC 0x700
+#define CPR4_MISC_RESET_STEP_QUOT_LOOP_EN BIT(2)
#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK GENMASK(23, 20)
#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT 20
#define CPR4_MISC_TEMP_SENSOR_ID_START_MASK GENMASK(27, 24)
@@ -723,6 +724,11 @@
int thread_id = 0;
u64 temp;
+ if (ctrl->reset_step_quot_loop_en)
+ cpr3_masked_write(ctrl, CPR4_REG_MISC,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
+
if (ctrl->supports_hw_closed_loop) {
if (ctrl->saw_use_unit_mV)
pmic_step_size = ctrl->step_volt / 1000;
@@ -1355,6 +1361,11 @@
}
}
+ if (ctrl->reset_step_quot_loop_en)
+ cpr3_masked_write(ctrl, CPR4_REG_MISC,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
+
if (ctrl->saw_use_unit_mV)
pmic_step_size = ctrl->step_volt / 1000;
cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 570ddfc..8535020 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -756,6 +756,12 @@
* @panic_notifier: Notifier block registered to global panic notifier list.
* @support_ldo300_vreg: Boolean value which indicates that this CPR controller
* manages an underlying LDO regulator of type LDO300.
+ * @reset_step_quot_loop_en: Boolean value which indicates that this CPR
+ * controller should be configured to reset step_quot on
+ * each loop_en = 0 transition. This configuration allows
+ * the CPR controller to first use the default step_quot
+ * and then later switch to the run-time calibrated
+ * step_quot.
*
* This structure contains both configuration and runtime state data. The
* elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
@@ -866,6 +872,7 @@
struct cpr3_panic_regs_info *panic_regs_info;
struct notifier_block panic_notifier;
bool support_ldo300_vreg;
+ bool reset_step_quot_loop_en;
};
/* Used for rounding voltages to the closest physically available set point. */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 648d396..3035155 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -1224,6 +1224,14 @@
}
/*
+ * Reset step_quot to default on each loop_en = 0 transition is
+ * optional.
+ */
+ ctrl->reset_step_quot_loop_en
+ = of_property_read_bool(ctrl->dev->of_node,
+ "qcom,cpr-reset-step-quot-loop-en");
+
+ /*
* Regulator device handles are not necessary for CPRh controllers
* since communication with the regulators is completely managed
* in hardware.
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 69e3032..3311380 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -655,3 +655,11 @@
memory location. These messages provide statistical information about
the low power modes that RPM enters. The drivers outputs the message
via a debugfs node.
+
+config QCOM_FORCE_WDOG_BITE_ON_PANIC
+ bool "QCOM force watchdog bite"
+ depends on QCOM_WATCHDOG_V2
+ help
+ This forces a watchdog bite when the device restarts due to a
+ kernel panic. On certain MSM SoCs, this provides us
+ additional debugging information.
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index 0c2ba4d..5cc04c0 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -241,18 +241,28 @@
static int cmd_db_dev_probe(struct platform_device *pdev)
{
- struct resource *res;
+ struct resource res;
+ void __iomem *dict;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
+ dict = of_iomap(pdev->dev.of_node, 0);
+ if (!dict) {
cmd_db_status = -ENOMEM;
goto failed;
}
- start_addr = devm_ioremap_resource(&pdev->dev, res);
+ /*
+ * Read start address and size of the command DB address from
+ * shared dictionary location
+ */
+ res.start = readl_relaxed(dict);
+ res.end = res.start + readl_relaxed(dict + 0x4);
+ res.flags = IORESOURCE_MEM;
+ iounmap(dict);
- cmd_db_header = devm_kzalloc(&pdev->dev, sizeof(*cmd_db_header),
- GFP_KERNEL);
+ start_addr = devm_ioremap_resource(&pdev->dev, &res);
+
+ cmd_db_header = devm_kzalloc(&pdev->dev,
+ sizeof(*cmd_db_header), GFP_KERNEL);
if (!cmd_db_header) {
cmd_db_status = -ENOMEM;
diff --git a/drivers/soc/qcom/glink_private.h b/drivers/soc/qcom/glink_private.h
index c837bd8..9810207 100644
--- a/drivers/soc/qcom/glink_private.h
+++ b/drivers/soc/qcom/glink_private.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -700,6 +700,7 @@
* edge: The G-Link edge name for the channel associated with
* this callback data
* do_cleanup_data: Structure containing the G-Link SSR do_cleanup message.
+ * cb_kref: Kref object to maintain cb_data reference.
*/
struct ssr_notify_data {
bool tx_done;
@@ -707,6 +708,7 @@
bool responded;
const char *edge;
struct do_cleanup_msg *do_cleanup_data;
+ struct kref cb_kref;
};
/**
@@ -741,6 +743,7 @@
int notify_list_len;
bool link_up;
spinlock_t link_up_lock;
+ spinlock_t cb_lock;
};
/**
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index b24598a..4737288 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -115,6 +115,44 @@
static atomic_t responses_remaining = ATOMIC_INIT(0);
static wait_queue_head_t waitqueue;
+/**
+ * cb_data_release() - Free cb_data and set to NULL
+ * @kref_ptr: pointer to kref.
+ *
+ * This function releses cb_data.
+ */
+static inline void cb_data_release(struct kref *kref_ptr)
+{
+ struct ssr_notify_data *cb_data;
+
+ cb_data = container_of(kref_ptr, struct ssr_notify_data, cb_kref);
+ kfree(cb_data);
+}
+
+/**
+ * check_and_get_cb_data() - Try to get reference to kref of cb_data
+ * @ss_info: pointer to subsystem info structure.
+ *
+ * Return: NULL is cb_data is NULL, pointer to cb_data otherwise
+ */
+static struct ssr_notify_data *check_and_get_cb_data(
+ struct subsys_info *ss_info)
+{
+ struct ssr_notify_data *cb_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ss_info->cb_lock, flags);
+ if (ss_info->cb_data == NULL) {
+ GLINK_SSR_LOG("<SSR> %s: cb_data is NULL\n", __func__);
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
+ return 0;
+ }
+ kref_get(&ss_info->cb_data->cb_kref);
+ cb_data = ss_info->cb_data;
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
+ return cb_data;
+}
+
static void rx_done_cb_worker(struct work_struct *work)
{
struct rx_done_ch_work *rx_done_work =
@@ -340,8 +378,10 @@
if (WARN_ON(!ss_info->cb_data))
return;
- kfree(ss_info->cb_data);
+ spin_lock_irqsave(&ss_info->cb_lock, flags);
+ kref_put(&ss_info->cb_data->cb_kref, cb_data_release);
ss_info->cb_data = NULL;
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
kfree(close_work);
}
@@ -508,13 +548,18 @@
return -ENODEV;
}
handle = ss_info_channel->handle;
- ss_leaf_entry->cb_data = ss_info_channel->cb_data;
+ ss_leaf_entry->cb_data = check_and_get_cb_data(
+ ss_info_channel);
+ if (!ss_leaf_entry->cb_data) {
+ GLINK_SSR_LOG("<SSR> %s: CB data is NULL\n", __func__);
+ atomic_dec(&responses_remaining);
+ continue;
+ }
spin_lock_irqsave(&ss_info->link_up_lock, flags);
if (IS_ERR_OR_NULL(ss_info_channel->handle) ||
- !ss_info_channel->cb_data ||
!ss_info_channel->link_up ||
- ss_info_channel->cb_data->event
+ ss_leaf_entry->cb_data->event
!= GLINK_CONNECTED) {
GLINK_SSR_LOG(
@@ -527,6 +572,8 @@
spin_unlock_irqrestore(&ss_info->link_up_lock, flags);
atomic_dec(&responses_remaining);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
continue;
}
spin_unlock_irqrestore(&ss_info->link_up_lock, flags);
@@ -537,6 +584,8 @@
GLINK_SSR_ERR(
"%s %s: Could not allocate do_cleanup_msg\n",
"<SSR>", __func__);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
return -ENOMEM;
}
@@ -568,6 +617,8 @@
__func__);
}
atomic_dec(&responses_remaining);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
continue;
}
@@ -597,10 +648,12 @@
__func__);
}
atomic_dec(&responses_remaining);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
continue;
}
-
sequence_number++;
+ kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
}
wait_ret = wait_event_timeout(waitqueue,
@@ -609,6 +662,21 @@
list_for_each_entry(ss_leaf_entry, &ss_info->notify_list,
notify_list_node) {
+ ss_info_channel =
+ get_info_for_subsystem(ss_leaf_entry->ssr_name);
+ if (ss_info_channel == NULL) {
+ GLINK_SSR_ERR(
+ "<SSR> %s: unable to find subsystem name\n",
+ __func__);
+ continue;
+ }
+
+ ss_leaf_entry->cb_data = check_and_get_cb_data(
+ ss_info_channel);
+ if (!ss_leaf_entry->cb_data) {
+ GLINK_SSR_LOG("<SSR> %s: CB data is NULL\n", __func__);
+ continue;
+ }
if (!wait_ret && !IS_ERR_OR_NULL(ss_leaf_entry->cb_data)
&& !ss_leaf_entry->cb_data->responded) {
GLINK_SSR_ERR("%s %s: Subsystem %s %s\n",
@@ -627,6 +695,7 @@
if (!IS_ERR_OR_NULL(ss_leaf_entry->cb_data))
ss_leaf_entry->cb_data->responded = false;
+ kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
}
complete(¬ifications_successful_complete);
return 0;
@@ -645,6 +714,7 @@
struct glink_open_config open_cfg;
struct ssr_notify_data *cb_data = NULL;
void *handle = NULL;
+ unsigned long flags;
if (!ss_info) {
GLINK_SSR_ERR("<SSR> %s: ss_info structure invalid\n",
@@ -661,7 +731,10 @@
cb_data->responded = false;
cb_data->event = GLINK_SSR_EVENT_INIT;
cb_data->edge = ss_info->edge;
+ spin_lock_irqsave(&ss_info->cb_lock, flags);
ss_info->cb_data = cb_data;
+ kref_init(&cb_data->cb_kref);
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
memset(&open_cfg, 0, sizeof(struct glink_open_config));
@@ -877,6 +950,7 @@
ss_info->link_state_handle = NULL;
ss_info->cb_data = NULL;
spin_lock_init(&ss_info->link_up_lock);
+ spin_lock_init(&ss_info->cb_lock);
nb = kmalloc(sizeof(struct restart_notifier_block), GFP_KERNEL);
if (!nb) {
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 91d6349..c950367 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -337,8 +337,8 @@
tcs_cmd_gen(cur_bcm, &cmdlist_active[k],
cur_bcm->node_vec[ACTIVE_CTX].vec_a,
cur_bcm->node_vec[ACTIVE_CTX].vec_b, commit);
- k++;
last_tcs = k;
+ k++;
cur_bcm->updated = true;
}
}
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index fb3d7d9..c5ba279 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -75,6 +75,10 @@
#define MSS_RESTART_ID 0xA
#define MSS_MAGIC 0XAABADEAD
+
+#define MSS_PDC_OFFSET 8
+#define MSS_PDC_MASK BIT(MSS_PDC_OFFSET)
+
enum scm_cmd {
PAS_MEM_SETUP_CMD = 2,
};
@@ -204,6 +208,33 @@
clk_disable_unprepare(drv->ahb_clk);
}
+static void pil_mss_pdc_sync(struct q6v5_data *drv, bool pdc_sync)
+{
+ u32 val = 0;
+
+ if (drv->pdc_sync) {
+ val = readl_relaxed(drv->pdc_sync);
+ if (pdc_sync)
+ val |= MSS_PDC_MASK;
+ else
+ val &= ~MSS_PDC_MASK;
+ writel_relaxed(val, drv->pdc_sync);
+ /* Ensure PDC is written before next write */
+ wmb();
+ udelay(2);
+ }
+}
+
+static void pil_mss_alt_reset(struct q6v5_data *drv, u32 val)
+{
+ if (drv->alt_reset) {
+ writel_relaxed(val, drv->alt_reset);
+ /* Ensure alt reset is written before restart reg */
+ wmb();
+ udelay(2);
+ }
+}
+
static int pil_mss_restart_reg(struct q6v5_data *drv, u32 mss_restart)
{
int ret = 0;
@@ -235,6 +266,32 @@
return ret;
}
+static int pil_mss_assert_resets(struct q6v5_data *drv)
+{
+ int ret = 0;
+
+ pil_mss_pdc_sync(drv, 1);
+ pil_mss_alt_reset(drv, 1);
+ ret = pil_mss_restart_reg(drv, true);
+
+ return ret;
+}
+
+static int pil_mss_deassert_resets(struct q6v5_data *drv)
+{
+ int ret = 0;
+
+ ret = pil_mss_restart_reg(drv, 0);
+ if (ret)
+ return ret;
+ /* Wait 6 32kHz sleep cycles for reset */
+ udelay(200);
+ pil_mss_alt_reset(drv, 0);
+ pil_mss_pdc_sync(drv, false);
+
+ return ret;
+}
+
static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
{
struct device *dev = drv->desc.dev;
@@ -304,7 +361,10 @@
ret);
}
- ret = pil_mss_restart_reg(drv, 1);
+ pil_mss_assert_resets(drv);
+ /* Wait 6 32kHz sleep cycles for reset */
+ udelay(200);
+ ret = pil_mss_deassert_resets(drv);
if (drv->is_booted) {
pil_mss_disable_clks(drv);
@@ -450,6 +510,7 @@
{
struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
phys_addr_t start_addr = pil_get_entry_addr(pil);
+ u32 debug_val;
int ret;
if (drv->mba_dp_phys)
@@ -463,15 +524,22 @@
if (ret)
goto err_power;
- /* Deassert reset to subsystem and wait for propagation */
- ret = pil_mss_restart_reg(drv, 0);
- if (ret)
- goto err_restart;
-
ret = pil_mss_enable_clks(drv);
if (ret)
goto err_clks;
+ /* Save state of modem debug register before full reset */
+ debug_val = readl_relaxed(drv->reg_base + QDSP6SS_DBG_CFG);
+
+ /* Assert reset to subsystem */
+ pil_mss_assert_resets(drv);
+ /* Wait 6 32kHz sleep cycles for reset */
+ udelay(200);
+ ret = pil_mss_deassert_resets(drv);
+ if (ret)
+ goto err_restart;
+
+ writel_relaxed(debug_val, drv->reg_base + QDSP6SS_DBG_CFG);
if (modem_dbg_cfg)
writel_relaxed(modem_dbg_cfg, drv->reg_base + QDSP6SS_DBG_CFG);
@@ -519,12 +587,11 @@
err_q6v5_reset:
modem_log_rmb_regs(drv->rmb_base);
+err_restart:
pil_mss_disable_clks(drv);
if (drv->ahb_clk_vote)
clk_disable_unprepare(drv->ahb_clk);
err_clks:
- pil_mss_restart_reg(drv, 1);
-err_restart:
pil_mss_power_down(drv);
err_power:
return ret;
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index bbde4b6..df0c609c 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -284,6 +284,20 @@
if (!q6->restart_reg)
return -ENOMEM;
+ q6->pdc_sync = NULL;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pdc_sync");
+ if (res) {
+ q6->pdc_sync = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
+ }
+
+ q6->alt_reset = NULL;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "alt_reset");
+ if (res) {
+ q6->alt_reset = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
+ }
+
q6->vreg = NULL;
prop = of_find_property(pdev->dev.of_node, "vdd_mss-supply", NULL);
diff --git a/drivers/soc/qcom/pil-q6v5.h b/drivers/soc/qcom/pil-q6v5.h
index 1725253..9b4c811 100644
--- a/drivers/soc/qcom/pil-q6v5.h
+++ b/drivers/soc/qcom/pil-q6v5.h
@@ -44,6 +44,8 @@
void __iomem *axi_halt_mss;
void __iomem *axi_halt_nc;
void __iomem *restart_reg;
+ void __iomem *pdc_sync;
+ void __iomem *alt_reset;
struct regulator *vreg;
struct regulator *vreg_cx;
struct regulator *vreg_mx;
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index 2855a15..d8c5a8f 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -56,9 +56,13 @@
* Set up the wake up value offset from the current time.
* Convert us to ns to allow div by 19.2 Mhz tick timer.
*/
- sleep_val *= NSEC_PER_USEC;
- do_div(sleep_val, NSEC_PER_SEC/ARCH_TIMER_HZ);
- sleep_val += arch_counter_get_cntvct();
+ if (sleep_val) {
+ sleep_val *= NSEC_PER_USEC;
+ do_div(sleep_val, NSEC_PER_SEC/ARCH_TIMER_HZ);
+ sleep_val += arch_counter_get_cntvct();
+ } else {
+ sleep_val = ~0ULL;
+ }
return setup_wakeup(sleep_val);
}
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index 74f5ce0..bfaf7c7 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -57,6 +57,7 @@
#define LIMITS_DOMAIN_MIN 0x444D494E
#define LIMITS_TEMP_DEFAULT 75000
+#define LIMITS_TEMP_HIGH_THRESH_MAX 120000
#define LIMITS_LOW_THRESHOLD_OFFSET 500
#define LIMITS_POLLING_DELAY_MS 10
#define LIMITS_CLUSTER_0_REQ 0x179C1B04
@@ -259,7 +260,7 @@
struct limits_dcvs_hw *hw = (struct limits_dcvs_hw *)data;
int ret = 0;
- if (high < LIMITS_LOW_THRESHOLD_OFFSET || low < 0) {
+ if (high >= LIMITS_TEMP_HIGH_THRESH_MAX || low < 0) {
pr_err("Value out of range low:%d high:%d\n",
low, high);
return -EINVAL;
diff --git a/drivers/thermal/qpnp-temp-alarm.c b/drivers/thermal/qpnp-temp-alarm.c
index e86a297..09c95e5 100644
--- a/drivers/thermal/qpnp-temp-alarm.c
+++ b/drivers/thermal/qpnp-temp-alarm.c
@@ -28,6 +28,8 @@
#include <linux/thermal.h>
#include <linux/qpnp/qpnp-adc.h>
+#include "thermal_core.h"
+
#define QPNP_TM_DRIVER_NAME "qcom,qpnp-temp-alarm"
enum qpnp_tm_registers {
@@ -97,7 +99,6 @@
unsigned int subtype;
enum qpnp_tm_adc_type adc_type;
int temperature;
- enum thermal_device_mode mode;
unsigned int thresh;
unsigned int clock_rate;
unsigned int stage;
@@ -105,18 +106,12 @@
int irq;
enum qpnp_vadc_channels adc_channel;
u16 base_addr;
- bool allow_software_override;
struct qpnp_vadc_chip *vadc_dev;
};
/* Delay between TEMP_STAT IRQ going high and status value changing in ms. */
#define STATUS_REGISTER_DELAY_MS 40
-enum pmic_thermal_override_mode {
- SOFTWARE_OVERRIDE_DISABLED = 0,
- SOFTWARE_OVERRIDE_ENABLED,
-};
-
/* This array maps from GEN2 alarm state to GEN1 alarm stage */
const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3};
@@ -156,28 +151,6 @@
return rc;
}
-
-static inline int qpnp_tm_shutdown_override(struct qpnp_tm_chip *chip,
- enum pmic_thermal_override_mode mode)
-{
- int rc = 0;
- u8 reg;
-
- if (chip->allow_software_override) {
- reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
- reg |= (chip->clock_rate << SHUTDOWN_CTRL1_CLK_RATE_SHIFT)
- & SHUTDOWN_CTRL1_CLK_RATE_MASK;
-
- if (mode == SOFTWARE_OVERRIDE_ENABLED)
- reg |= SHUTDOWN_CTRL1_OVERRIDE_STAGE2
- | SHUTDOWN_CTRL1_OVERRIDE_STAGE3;
-
- rc = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, ®, 1);
- }
-
- return rc;
-}
-
static int qpnp_tm_update_temp(struct qpnp_tm_chip *chip)
{
struct qpnp_vadc_result adc_result;
@@ -274,10 +247,9 @@
return 0;
}
-static int qpnp_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
- int *temperature)
+static int qpnp_tz_get_temp_no_adc(void *data, int *temperature)
{
- struct qpnp_tm_chip *chip = thermal->devdata;
+ struct qpnp_tm_chip *chip = (struct qpnp_tm_chip *)data;
int rc;
if (!temperature)
@@ -292,10 +264,9 @@
return 0;
}
-static int qpnp_tz_get_temp_qpnp_adc(struct thermal_zone_device *thermal,
- int *temperature)
+static int qpnp_tz_get_temp_qpnp_adc(void *data, int *temperature)
{
- struct qpnp_tm_chip *chip = thermal->devdata;
+ struct qpnp_tm_chip *chip = (struct qpnp_tm_chip *)data;
int rc;
if (!temperature)
@@ -314,121 +285,12 @@
return 0;
}
-static int qpnp_tz_get_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode *mode)
-{
- struct qpnp_tm_chip *chip = thermal->devdata;
-
- if (!mode)
- return -EINVAL;
-
- *mode = chip->mode;
-
- return 0;
-}
-
-static int qpnp_tz_set_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode mode)
-{
- struct qpnp_tm_chip *chip = thermal->devdata;
- int rc = 0;
-
- if (mode != chip->mode) {
- if (mode == THERMAL_DEVICE_ENABLED)
- rc = qpnp_tm_shutdown_override(chip,
- SOFTWARE_OVERRIDE_ENABLED);
- else
- rc = qpnp_tm_shutdown_override(chip,
- SOFTWARE_OVERRIDE_DISABLED);
-
- chip->mode = mode;
- }
-
- return rc;
-}
-
-static int qpnp_tz_get_trip_type(struct thermal_zone_device *thermal,
- int trip, enum thermal_trip_type *type)
-{
- if (trip < 0 || !type)
- return -EINVAL;
-
- switch (trip) {
- case TRIP_STAGE3:
- *type = THERMAL_TRIP_CRITICAL;
- break;
- case TRIP_STAGE2:
- *type = THERMAL_TRIP_HOT;
- break;
- case TRIP_STAGE1:
- *type = THERMAL_TRIP_HOT;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int qpnp_tz_get_trip_temp(struct thermal_zone_device *thermal,
- int trip, int *temperature)
-{
- struct qpnp_tm_chip *chip = thermal->devdata;
- int thresh_temperature;
-
- if (trip < 0 || !temperature)
- return -EINVAL;
-
- thresh_temperature = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN;
-
- switch (trip) {
- case TRIP_STAGE3:
- thresh_temperature += 2 * TEMP_STAGE_STEP;
- break;
- case TRIP_STAGE2:
- thresh_temperature += TEMP_STAGE_STEP;
- break;
- case TRIP_STAGE1:
- break;
- default:
- return -EINVAL;
- }
-
- *temperature = thresh_temperature;
-
- return 0;
-}
-
-static int qpnp_tz_get_crit_temp(struct thermal_zone_device *thermal,
- int *temperature)
-{
- struct qpnp_tm_chip *chip = thermal->devdata;
-
- if (!temperature)
- return -EINVAL;
-
- *temperature = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
- 2 * TEMP_STAGE_STEP;
-
- return 0;
-}
-
-static struct thermal_zone_device_ops qpnp_thermal_zone_ops_no_adc = {
+static struct thermal_zone_of_device_ops qpnp_thermal_zone_ops_no_adc = {
.get_temp = qpnp_tz_get_temp_no_adc,
- .get_mode = qpnp_tz_get_mode,
- .set_mode = qpnp_tz_set_mode,
- .get_trip_type = qpnp_tz_get_trip_type,
- .get_trip_temp = qpnp_tz_get_trip_temp,
- .get_crit_temp = qpnp_tz_get_crit_temp,
};
-static struct thermal_zone_device_ops qpnp_thermal_zone_ops_qpnp_adc = {
+static struct thermal_zone_of_device_ops qpnp_thermal_zone_ops_qpnp_adc = {
.get_temp = qpnp_tz_get_temp_qpnp_adc,
- .get_mode = qpnp_tz_get_mode,
- .set_mode = qpnp_tz_set_mode,
- .get_trip_type = qpnp_tz_get_trip_type,
- .get_trip_temp = qpnp_tz_get_trip_temp,
- .get_crit_temp = qpnp_tz_get_crit_temp,
};
static void qpnp_tm_work(struct work_struct *work)
@@ -474,11 +336,7 @@
chip->tm_name, stage_new, chip->stage,
chip->thresh, chip->temperature);
- thermal_zone_device_update(chip->tz_dev,
- THERMAL_EVENT_UNSPECIFIED);
-
- /* Notify user space */
- sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");
+ of_thermal_handle_trip(chip->tz_dev);
}
bail:
@@ -539,7 +397,7 @@
struct device_node *node;
unsigned int base;
struct qpnp_tm_chip *chip;
- struct thermal_zone_device_ops *tz_ops;
+ struct thermal_zone_of_device_ops *tz_ops;
char *tm_name;
u32 default_temperature;
int rc = 0;
@@ -640,9 +498,6 @@
else
tz_ops = &qpnp_thermal_zone_ops_no_adc;
- chip->allow_software_override
- = of_property_read_bool(node, "qcom,allow-override");
-
default_temperature = DEFAULT_NO_ADC_TEMP;
rc = of_property_read_u32(node, "qcom,default-temp",
&default_temperature);
@@ -686,18 +541,8 @@
}
}
- /* Start in HW control; switch to SW control when user changes mode. */
- chip->mode = THERMAL_DEVICE_DISABLED;
- rc = qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
- if (rc) {
- dev_err(&pdev->dev,
- "%s: qpnp_tm_shutdown_override() failed, rc=%d\n",
- __func__, rc);
- goto err_cancel_work;
- }
-
- chip->tz_dev = thermal_zone_device_register(tm_name, TRIP_NUM, 0, chip,
- tz_ops, NULL, 0, 0);
+ chip->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
+ tz_ops);
if (chip->tz_dev == NULL) {
dev_err(&pdev->dev,
"%s: thermal_zone_device_register() failed.\n",
@@ -717,7 +562,7 @@
return 0;
err_free_tz:
- thermal_zone_device_unregister(chip->tz_dev);
+ thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev);
err_cancel_work:
cancel_delayed_work_sync(&chip->irq_work);
kfree(chip->tm_name);
@@ -731,10 +576,9 @@
{
struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev);
+ thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev);
dev_set_drvdata(&pdev->dev, NULL);
- thermal_zone_device_unregister(chip->tz_dev);
kfree(chip->tm_name);
- qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
free_irq(chip->irq, chip);
cancel_delayed_work_sync(&chip->irq_work);
kfree(chip);
@@ -742,38 +586,6 @@
return 0;
}
-#ifdef CONFIG_PM
-static int qpnp_tm_suspend(struct device *dev)
-{
- struct qpnp_tm_chip *chip = dev_get_drvdata(dev);
-
- /* Clear override bits in suspend to allow hardware control */
- qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
-
- return 0;
-}
-
-static int qpnp_tm_resume(struct device *dev)
-{
- struct qpnp_tm_chip *chip = dev_get_drvdata(dev);
-
- /* Override hardware actions so software can control */
- if (chip->mode == THERMAL_DEVICE_ENABLED)
- qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_ENABLED);
-
- return 0;
-}
-
-static const struct dev_pm_ops qpnp_tm_pm_ops = {
- .suspend = qpnp_tm_suspend,
- .resume = qpnp_tm_resume,
-};
-
-#define QPNP_TM_PM_OPS (&qpnp_tm_pm_ops)
-#else
-#define QPNP_TM_PM_OPS NULL
-#endif
-
static const struct of_device_id qpnp_tm_match_table[] = {
{ .compatible = QPNP_TM_DRIVER_NAME, },
{}
@@ -789,7 +601,6 @@
.name = QPNP_TM_DRIVER_NAME,
.of_match_table = qpnp_tm_match_table,
.owner = THIS_MODULE,
- .pm = QPNP_TM_PM_OPS,
},
.probe = qpnp_tm_probe,
.remove = qpnp_tm_remove,
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index df9be34..da1a0e6 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -94,8 +94,10 @@
#define UART_OVERSAMPLING (32)
#define STALE_TIMEOUT (16)
+#define DEFAULT_BITS_PER_CHAR (10)
#define GENI_UART_NR_PORTS (15)
#define DEF_FIFO_DEPTH_WORDS (16)
+#define DEF_TX_WM (2)
#define DEF_FIFO_WIDTH_BITS (32)
#define UART_CORE2X_VOTE (10000)
#define DEFAULT_SE_CLK (19200000)
@@ -134,6 +136,7 @@
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
unsigned int rx_last);
+static unsigned int msm_geni_serial_tx_empty(struct uart_port *port);
static atomic_t uart_line_id = ATOMIC_INIT(0);
@@ -232,7 +235,7 @@
}
static void msm_geni_serial_setup_tx(struct uart_port *uport,
- unsigned int xmit_size)
+ unsigned int xmit_size)
{
u32 m_cmd = 0;
@@ -324,7 +327,6 @@
int b = (int) c;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- se_config_packing(uport->membase, 8, 1, false);
geni_write_reg_nolog(port->tx_wm, uport->membase,
SE_GENI_TX_WATERMARK_REG);
msm_geni_serial_setup_tx(uport, 1);
@@ -358,10 +360,11 @@
__msm_geni_serial_console_write(struct uart_port *uport, const char *s,
unsigned int count)
{
- struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
int new_line = 0;
int i;
int bytes_to_send = count;
+ int fifo_depth = DEF_FIFO_DEPTH_WORDS;
+ int tx_wm = DEF_TX_WM;
for (i = 0; i < count; i++) {
if (s[i] == '\n')
@@ -369,14 +372,13 @@
}
bytes_to_send += new_line;
- se_config_packing(uport->membase, 8, 1, false);
- geni_write_reg_nolog(port->tx_wm, uport->membase,
+ geni_write_reg_nolog(tx_wm, uport->membase,
SE_GENI_TX_WATERMARK_REG);
msm_geni_serial_setup_tx(uport, bytes_to_send);
i = 0;
while (i < count) {
u32 chars_to_write = 0;
- u32 avail_fifo_bytes = (port->tx_fifo_depth - port->tx_wm);
+ u32 avail_fifo_bytes = (fifo_depth - tx_wm);
/*
* If the WM bit never set, then the Tx state machine is not
* in a valid state, so break, cancel/abort any existing
@@ -473,10 +475,12 @@
unsigned int geni_m_irq_en;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+ if (!msm_geni_serial_tx_empty(uport))
+ return;
+
geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
geni_m_irq_en |= M_TX_FIFO_WATERMARK_EN;
- se_config_packing(uport->membase, 8, 4, false);
geni_write_reg_nolog(port->tx_wm, uport->membase,
SE_GENI_TX_WATERMARK_REG);
geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
@@ -516,6 +520,8 @@
{
unsigned int geni_s_irq_en;
unsigned int geni_m_irq_en;
+ unsigned long cfg0, cfg1;
+ unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
msm_geni_serial_abort_rx(uport);
geni_s_irq_en = geni_read_reg_nolog(uport->membase,
@@ -524,7 +530,10 @@
SE_GENI_M_IRQ_EN);
geni_s_irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
geni_m_irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
-
+ se_get_packing_config(8, 4, false, &cfg0, &cfg1);
+ geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_RX_PACKING_CFG0);
+ geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_RX_PACKING_CFG1);
+ geni_write_reg_nolog(rxstale, uport->membase, SE_UART_RX_STALE_CNT);
geni_setup_s_cmd(uport->membase, UART_START_READ, 0);
geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN);
geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
@@ -622,7 +631,8 @@
int i = 0;
unsigned int tx_fifo_status;
unsigned int xmit_size;
- unsigned int fifo_width_bytes = msm_port->tx_fifo_width >> 3;
+ unsigned int fifo_width_bytes =
+ (uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3));
tx_fifo_status = geni_read_reg_nolog(uport->membase,
SE_GENI_TX_FIFO_STATUS);
@@ -664,6 +674,8 @@
wmb();
}
msm_geni_serial_poll_cancel_tx(uport);
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(uport);
exit_handle_tx:
return ret;
}
@@ -765,17 +777,32 @@
{
int ret = 0;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ unsigned long cfg0, cfg1;
- /* For now only assume FIFO mode. */
- msm_port->xfer_mode = FIFO_MODE;
- set_rfr_wm(msm_port);
- ret = geni_se_init(uport->membase, msm_port->xfer_mode,
+
+ if (!uart_console(uport)) {
+ /* For now only assume FIFO mode. */
+ msm_port->xfer_mode = FIFO_MODE;
+ set_rfr_wm(msm_port);
+ ret = geni_se_init(uport->membase, msm_port->xfer_mode,
msm_port->rx_wm, msm_port->rx_rfr);
- if (ret) {
- dev_err(uport->dev, "%s: Fail\n", __func__);
- goto exit_portsetup;
+ if (ret) {
+ dev_err(uport->dev, "%s: Fail\n", __func__);
+ goto exit_portsetup;
+ }
+ se_get_packing_config(8, 4, false, &cfg0, &cfg1);
+ geni_write_reg_nolog(cfg0, uport->membase,
+ SE_GENI_TX_PACKING_CFG0);
+ geni_write_reg_nolog(cfg1, uport->membase,
+ SE_GENI_TX_PACKING_CFG1);
+ } else {
+ set_rfr_wm(msm_port);
+ se_get_packing_config(8, 1, false, &cfg0, &cfg1);
+ geni_write_reg_nolog(cfg0, uport->membase,
+ SE_GENI_TX_PACKING_CFG0);
+ geni_write_reg_nolog(cfg1, uport->membase,
+ SE_GENI_TX_PACKING_CFG1);
}
-
msm_port->port_setup = true;
/*
* Ensure Port setup related IO completes before returning to
@@ -848,7 +875,7 @@
static void geni_serial_write_term_regs(struct uart_port *uport, u32 loopback,
u32 tx_trans_cfg, u32 tx_parity_cfg, u32 rx_trans_cfg,
u32 rx_parity_cfg, u32 bits_per_char, u32 stop_bit_len,
- u32 rxstale, u32 s_clk_cfg)
+ u32 s_clk_cfg)
{
geni_write_reg_nolog(loopback, uport->membase, SE_UART_LOOPBACK_CFG);
geni_write_reg_nolog(tx_trans_cfg, uport->membase,
@@ -865,7 +892,6 @@
SE_UART_RX_WORD_LEN);
geni_write_reg_nolog(stop_bit_len, uport->membase,
SE_UART_TX_STOP_BIT_LEN);
- geni_write_reg_nolog(rxstale, uport->membase, SE_UART_RX_STALE_CNT);
geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_M_CLK_CFG);
geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_S_CLK_CFG);
}
@@ -901,7 +927,6 @@
unsigned int rx_trans_cfg;
unsigned int rx_parity_cfg;
unsigned int stop_bit_len;
- unsigned int rxstale;
unsigned int clk_div;
unsigned long ser_clk_cfg = 0;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
@@ -966,8 +991,6 @@
break;
}
- /* stale timer, set this to 16 characters. */
- rxstale = bits_per_char * STALE_TIMEOUT;
/* stop bits */
if (termios->c_cflag & CSTOPB)
@@ -984,7 +1007,7 @@
geni_serial_write_term_regs(uport, port->loopback, tx_trans_cfg,
tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
- stop_bit_len, rxstale, ser_clk_cfg);
+ stop_bit_len, ser_clk_cfg);
exit_set_termios:
return;
@@ -1066,7 +1089,6 @@
{
struct uart_port *uport = &dev->port;
int ret = 0;
- struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
u32 tx_trans_cfg = 0;
u32 tx_parity_cfg = 0;
u32 rx_trans_cfg = 0;
@@ -1078,6 +1100,7 @@
u32 baud = 115200;
u32 clk_div;
unsigned long clk_rate;
+ unsigned long cfg0, cfg1;
if (!uport->membase) {
ret = -ENOMEM;
@@ -1089,13 +1112,8 @@
goto exit_geni_serial_earlyconsetup;
}
- msm_port->xfer_mode = FIFO_MODE;
- set_rfr_wm(msm_port);
- msm_port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
- msm_port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
- msm_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
- geni_se_init(uport->membase, msm_port->xfer_mode, msm_port->rx_wm,
- msm_port->rx_rfr);
+ geni_se_init(uport->membase, FIFO_MODE, (DEF_FIFO_DEPTH_WORDS >> 1),
+ (DEF_FIFO_DEPTH_WORDS - 2));
/*
* Ignore Flow control.
* Disable Tx Parity.
@@ -1120,6 +1138,9 @@
s_clk_cfg |= SER_CLK_EN;
s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
+ se_get_packing_config(8, 1, false, &cfg0, &cfg1);
+ geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0);
+ geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1);
/*
* Make an unconditional cancel on the main sequencer to reset
@@ -1128,7 +1149,7 @@
msm_geni_serial_poll_cancel_tx(uport);
geni_serial_write_term_regs(uport, 0, tx_trans_cfg,
tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
- stop_bit, rx_stale, s_clk_cfg);
+ stop_bit, s_clk_cfg);
dev->con->write = msm_geni_serial_early_console_write;
dev->con->setup = NULL;
@@ -1435,9 +1456,11 @@
struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
struct uart_port *uport = &port->uport;
- if (uart_console(uport))
+ if (uart_console(uport)) {
+ se_geni_resources_on(&port->serial_rsc);
uart_resume_port((struct uart_driver *)uport->private_data,
uport);
+ }
return 0;
}
#else
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index bda14ef..744ea4f 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -125,6 +125,7 @@
* BVEC_POOL_IDX()
*/
#define BIO_RESET_BITS 10
+#define BIO_INLINECRYPT 15
/*
* We support 6 different bvec pools, the last one is magic in that it
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index cb4387d..5a10db5 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -479,11 +479,11 @@
return rx_fifo_depth;
}
-static inline void se_config_packing(void __iomem *base, int bpw,
- int pack_words, bool msb_to_lsb)
+static inline void se_get_packing_config(int bpw, int pack_words,
+ bool msb_to_lsb, unsigned long *cfg0,
+ unsigned long *cfg1)
{
u32 cfg[4] = {0};
- unsigned long cfg0, cfg1;
int len = ((bpw < 8) ? (bpw - 1) : 7);
int idx = ((msb_to_lsb == 1) ? len : 0);
int iter = (bpw * pack_words) >> 3;
@@ -495,8 +495,16 @@
if (i == iter - 1)
cfg[i] |= 1;
}
- cfg0 = cfg[0] | (cfg[1] << 10);
- cfg1 = cfg[2] | (cfg[3] << 10);
+ *cfg0 = cfg[0] | (cfg[1] << 10);
+ *cfg1 = cfg[2] | (cfg[3] << 10);
+}
+
+static inline void se_config_packing(void __iomem *base, int bpw,
+ int pack_words, bool msb_to_lsb)
+{
+ unsigned long cfg0, cfg1;
+
+ se_get_packing_config(bpw, pack_words, msb_to_lsb, &cfg0, &cfg1);
geni_write_reg(cfg0, base, SE_GENI_TX_PACKING_CFG0);
geni_write_reg(cfg1, base, SE_GENI_TX_PACKING_CFG1);
geni_write_reg(cfg0, base, SE_GENI_RX_PACKING_CFG0);
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index 60cc768..f3fa9e6 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -79,6 +79,7 @@
* @current_state: current client state
* @crtc_id: crtc_id associated with this rsc client.
* @rsc_index: rsc index of a client - only index "0" valid.
+ * @id: Index of client. It will be assigned during client_create call
* @list: list to attach client master list
*/
struct sde_rsc_client {
@@ -86,6 +87,7 @@
short current_state;
int crtc_id;
u32 rsc_index;
+ u32 id;
struct list_head list;
};
diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h
index 7586072..ad19e73 100644
--- a/include/trace/events/clk.h
+++ b/include/trace/events/clk.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 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
@@ -192,6 +192,42 @@
TP_ARGS(core, phase)
);
+DECLARE_EVENT_CLASS(clk_state_dump,
+
+ TP_PROTO(const char *name, unsigned int prepare_count,
+ unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+ TP_ARGS(name, prepare_count, enable_count, rate, vdd_level),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(unsigned int, prepare_count)
+ __field(unsigned int, enable_count)
+ __field(unsigned long, rate)
+ __field(unsigned int, vdd_level)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->prepare_count = prepare_count;
+ __entry->enable_count = enable_count;
+ __entry->rate = rate;
+ __entry->vdd_level = vdd_level;
+ ),
+
+ TP_printk("%s\tprepare:enable cnt [%u:%u]\trate: vdd_level [%lu:%u]",
+ __get_str(name), __entry->prepare_count, __entry->enable_count,
+ __entry->rate, __entry->vdd_level)
+);
+
+DEFINE_EVENT(clk_state_dump, clk_state,
+
+ TP_PROTO(const char *name, unsigned int prepare_count,
+ unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+ TP_ARGS(name, prepare_count, enable_count, rate, vdd_level)
+);
+
#endif /* _TRACE_CLK_H */
/* This part must be outside protection */
diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h
index c190446..f05155b 100644
--- a/include/uapi/linux/msm_kgsl.h
+++ b/include/uapi/linux/msm_kgsl.h
@@ -67,6 +67,8 @@
#define KGSL_CONTEXT_TYPE_RS 4
#define KGSL_CONTEXT_TYPE_UNKNOWN 0x1E
+#define KGSL_CONTEXT_INVALIDATE_ON_FAULT 0x10000000
+
#define KGSL_CONTEXT_INVALID 0xffffffff
/*
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index a62870e..cf96ac1 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1061,6 +1061,8 @@
(V4L2_CID_MPEG_MSM_VIDC_BASE + 106)
#define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 107)
+#define V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 108)
enum v4l2_mpeg_vidc_video_venc_iframesize_type {
V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT,
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 68db5e1..b736755 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -190,9 +190,6 @@
#define CAM_REQ_MGR_MAP_BUF (CAM_COMMON_OPCODE_MAX + 10)
#define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11)
#define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12)
-#define CAM_REQ_MGR_GET_MMU_HDLS_DEBUG (CAM_COMMON_OPCODE_MAX + 13)
-#define CAM_REQ_MGR_GET_IO_BUF_DEBUG (CAM_COMMON_OPCODE_MAX + 14)
-#define CAM_REQ_MGR_GET_KMD_BUF_DEBUG (CAM_COMMON_OPCODE_MAX + 15)
/* end of cam_req_mgr opcodes */
#define CAM_MEM_FLAG_HW_READ_WRITE (1<<0)
@@ -206,6 +203,7 @@
#define CAM_MEM_FLAG_STATS_BUF_TYPE (1<<8)
#define CAM_MEM_FLAG_PACKET_BUF_TYPE (1<<9)
#define CAM_MEM_FLAG_CACHE (1<<10)
+#define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11)
#define CAM_MEM_MMU_MAX_HANDLE 16
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e318878..35ad69f 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -70,7 +70,7 @@
MODULE_PARM_DESC(bss_entries_limit,
"limit to number of scan BSS entries (per wiphy, default 1000)");
-#define IEEE80211_SCAN_RESULT_EXPIRE (7 * HZ)
+#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
static void bss_free(struct cfg80211_internal_bss *bss)
{
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index f93db0e..a0d45ef 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2438,15 +2438,6 @@
$herecurr);
}
$shorttext = AFTER_SHORTTEXT;
- } elsif (length($line) > (SHORTTEXT_LIMIT +
- $shorttext_exspc)
- && $line !~ /^:([0-7]{6}\s){2}
- ([[:xdigit:]]+\.*
- \s){2}\w+\s\w+/xms) {
- WARN("LONG_COMMIT_TEXT",
- "commit text line over " .
- SHORTTEXT_LIMIT .
- " characters\n" . $herecurr);
} elsif ($line=~/^\s*change-id:/i ||
$line=~/^\s*signed-off-by:/i ||
$line=~/^\s*crs-fixed:/i ||
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 2b8c9c7..304bf47 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -155,6 +155,21 @@
u32 index;
};
+enum pinctrl_pin_state {
+ STATE_DISABLE = 0, /* All pins are in sleep state */
+ STATE_MI2S_ACTIVE, /* IS2 = active, TDM = sleep */
+ STATE_TDM_ACTIVE, /* IS2 = sleep, TDM = active */
+};
+
+struct msm_pinctrl_info {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *mi2s_disable;
+ struct pinctrl_state *tdm_disable;
+ struct pinctrl_state *mi2s_active;
+ struct pinctrl_state *tdm_active;
+ enum pinctrl_pin_state curr_state;
+};
+
struct msm_asoc_mach_data {
u32 mclk_freq;
int us_euro_gpio; /* used by gpio driver API */
@@ -162,6 +177,7 @@
struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
struct snd_info_entry *codec_root;
+ struct msm_pinctrl_info pinctrl_info;
};
struct msm_asoc_wcd93xx_codec {
@@ -170,6 +186,9 @@
void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
};
+static const char *const pin_states[] = {"sleep", "i2s-active",
+ "tdm-active"};
+
enum {
TDM_0 = 0,
TDM_1,
@@ -509,6 +528,7 @@
.key_code[7] = 0,
.linein_th = 5000,
.moisture_en = true,
+ .mbhc_micbias = MIC_BIAS_2,
.anc_micbias = MIC_BIAS_2,
.enable_anc_mic_detect = false,
};
@@ -3802,6 +3822,275 @@
return ret;
}
+static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info,
+ enum pinctrl_pin_state new_state)
+{
+ int ret = 0;
+ int curr_state = 0;
+
+ if (pinctrl_info == NULL) {
+ pr_err("%s: pinctrl_info is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ curr_state = pinctrl_info->curr_state;
+ pinctrl_info->curr_state = new_state;
+ pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
+ pin_states[curr_state], pin_states[pinctrl_info->curr_state]);
+
+ if (curr_state == pinctrl_info->curr_state) {
+ pr_debug("%s: Already in same state\n", __func__);
+ goto err;
+ }
+
+ if (curr_state != STATE_DISABLE &&
+ pinctrl_info->curr_state != STATE_DISABLE) {
+ pr_debug("%s: state already active cannot switch\n", __func__);
+ ret = -EIO;
+ goto err;
+ }
+
+ switch (pinctrl_info->curr_state) {
+ case STATE_MI2S_ACTIVE:
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_active);
+ if (ret) {
+ pr_err("%s: MI2S state select failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ case STATE_TDM_ACTIVE:
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->tdm_active);
+ if (ret) {
+ pr_err("%s: TDM state select failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ case STATE_DISABLE:
+ if (curr_state == STATE_MI2S_ACTIVE) {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_disable);
+ } else {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->tdm_disable);
+ }
+ if (ret) {
+ pr_err("%s: state disable failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ default:
+ pr_err("%s: TLMM pin state is invalid\n", __func__);
+ return -EINVAL;
+ }
+
+err:
+ return ret;
+}
+
+static void msm_release_pinctrl(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ if (pinctrl_info->pinctrl) {
+ devm_pinctrl_put(pinctrl_info->pinctrl);
+ pinctrl_info->pinctrl = NULL;
+ }
+}
+
+static int msm_get_pinctrl(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = NULL;
+ struct pinctrl *pinctrl;
+ int ret;
+
+ pinctrl_info = &pdata->pinctrl_info;
+
+ if (pinctrl_info == NULL) {
+ pr_err("%s: pinctrl_info is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR_OR_NULL(pinctrl)) {
+ pr_err("%s: Unable to get pinctrl handle\n", __func__);
+ return -EINVAL;
+ }
+ pinctrl_info->pinctrl = pinctrl;
+
+ /* get all the states handles from Device Tree */
+ pinctrl_info->mi2s_disable = pinctrl_lookup_state(pinctrl,
+ "quat-mi2s-sleep");
+ if (IS_ERR(pinctrl_info->mi2s_disable)) {
+ pr_err("%s: could not get mi2s_disable pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->mi2s_active = pinctrl_lookup_state(pinctrl,
+ "quat-mi2s-active");
+ if (IS_ERR(pinctrl_info->mi2s_active)) {
+ pr_err("%s: could not get mi2s_active pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->tdm_disable = pinctrl_lookup_state(pinctrl,
+ "quat-tdm-sleep");
+ if (IS_ERR(pinctrl_info->tdm_disable)) {
+ pr_err("%s: could not get tdm_disable pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->tdm_active = pinctrl_lookup_state(pinctrl,
+ "quat-tdm-active");
+ if (IS_ERR(pinctrl_info->tdm_active)) {
+ pr_err("%s: could not get tdm_active pinstate\n",
+ __func__);
+ goto err;
+ }
+ /* Reset the TLMM pins to a default state */
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_disable);
+ if (ret != 0) {
+ pr_err("%s: Disable TLMM pins failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ pinctrl_info->curr_state = STATE_DISABLE;
+
+ return 0;
+
+err:
+ devm_pinctrl_put(pinctrl);
+ pinctrl_info->pinctrl = NULL;
+ return -EINVAL;
+}
+
+static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) {
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ } else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) {
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ } else {
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n",
+ __func__, cpu_dai->id, channels->max, rate->max,
+ params_format(params));
+
+ return 0;
+}
+
+static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width, slots;
+ unsigned int slot_mask;
+ unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ /*2 slot config - bits 0 and 1 set for the first two slots */
+ slot_mask = 0x0000FFFF >> (16-slots);
+ slot_width = 32;
+ channels = slots;
+
+ pr_debug("%s: slot_width %d slots %d\n", __func__, slot_width, slots);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: slot_width %d\n", __func__, slot_width);
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ 0, NULL, channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ pr_err("%s: invalid use case, err:%d\n",
+ __func__, ret);
+ }
+
+end:
+ return ret;
+}
+
+static int sdm845_tdm_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static void sdm845_tdm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+
+}
+
+static struct snd_soc_ops sdm845_tdm_be_ops = {
+ .hw_params = sdm845_tdm_snd_hw_params,
+ .startup = sdm845_tdm_snd_startup,
+ .shutdown = sdm845_tdm_snd_shutdown
+};
+
static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
@@ -3809,6 +4098,9 @@
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int index = cpu_dai->id;
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -3822,6 +4114,14 @@
__func__, cpu_dai->id);
goto err;
}
+ if (index == QUAT_MI2S) {
+ ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+ if (ret) {
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+ goto err;
+ }
+ }
/*
* Muxtex protection in case the same MI2S
* interface using for both TX and RX so
@@ -3874,6 +4174,9 @@
int ret;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int index = rtd->cpu_dai->id;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -3892,6 +4195,13 @@
}
}
mutex_unlock(&mi2s_intf_conf[index].lock);
+
+ if (index == QUAT_MI2S) {
+ ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+ }
}
static struct snd_soc_ops msm_mi2s_be_ops = {
@@ -4929,8 +5239,8 @@
.no_pcm = 1,
.dpcm_playback = 1,
.id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm_tdm_be_ops,
+ .be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+ .ops = &sdm845_tdm_be_ops,
.ignore_suspend = 1,
},
{
@@ -6296,6 +6606,17 @@
dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
ret);
+ /* Parse pinctrl info from devicetree */
+ ret = msm_get_pinctrl(pdev);
+ if (!ret) {
+ pr_debug("%s: pinctrl parsing successful\n", __func__);
+ } else {
+ dev_dbg(&pdev->dev,
+ "%s: Parsing pinctrl failed with %d. Cannot use Ports\n",
+ __func__, ret);
+ ret = 0;
+ }
+
msm_i2s_auxpcm_init(pdev);
is_initial_boot = true;
@@ -6307,6 +6628,7 @@
return 0;
err:
+ msm_release_pinctrl(pdev);
devm_kfree(&pdev->dev, pdata);
return ret;
}
@@ -6323,6 +6645,7 @@
}
msm_i2s_auxpcm_deinit();
+ msm_release_pinctrl(pdev);
snd_soc_unregister_card(card);
return 0;
}