Merge "dt-bindings: clock: add bindings for kona video cc driver"
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
new file mode 100644
index 0000000..a547067d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -0,0 +1,280 @@
+* Low Power Management Levels
+
+The application processor in MSM can do a variety of C-States for low power
+management. The LPM module performs the System low power modes based on
+the latency/residency information of the individual CPUs and clusters.
+
+LPM-levels defines a hierarchy of low power modes that a cluster and
+clusters/cpus within that cluster can enter. The bottom hierarchy level
+represents the low power modes that a CPU can enter. The CPU low power nodes
+are associated with a cluster that defines the low power modes that a cluster
+can enter. For system involving a hierarchy of clusters, the cluster low power
+modes can be contained within another cluster.
+
+[Top Level Node]
+Required properties:
+
+- compatible: "qcom,lpm-levels"
+
+[Node bindings for qcom,pm-cluster]
+ Required properties:
+ - reg - The numeric cluster id
+ - label: Identifies the cluster name. The name is used when reporting
+ the stats for each low power mode.
+ - qcom,psci-mode-shift: The property is used to determine with bit
+ location of the cluster mode in the composite state ID used to define
+ cluster low power modes in PSCI.
+ - qcom,psci-mode-mask: The property is used to determine with bit
+ mask of the cluster mode in the composite state ID used to define
+ cluster low power modes in PSCI.
+
+Optional properties:
+ - qcom,disable-prediction: This property is used to indicate the LPM
+ governor will not use LPM prediction for this cluster.
+ - qcom,clstr-tmr-add: This property is used as correction timer for
+ wrong prediction by lpm prediction algorithm for cluster predictions.
+ This value should be between 100 to 1500. Higher values would mean
+ longer time staying in shallower state before waking up to select a
+ deeper state in case of wrong prediction.
+ qcom,pm-cluster contains qcom,pm-cluster-level nodes which identify
+ the various low power modes that the cluster can enter. The
+ qcom,pm-cluster node should also include another cluster node or a cpu
+ node that defines their respective low power modes.
+
+[Node bindings for qcom,pm-cluster-level]
+ Required properties:
+ - reg: The numeric cluster level id
+ - label: Name to identify the low power mode in stats
+ module.
+ - qcom,psci-mode: ID to be passed into the PSCI firmware.
+ - qcom,min-child-idx: The minimum level that a child CPU should be in
+ before this level can be chosen. This property is required for all
+ non-default level.
+ - qcom,entry-latency-us: The latency to enter LPM level, in uSec
+ - qcom,exit-latency-us: The latency to exit LPM level, in uSec
+ - qcom,min-residency-us: The minimum residency value from which entering
+ to low power mode is beneficial, in uSec
+
+ Optional properties:
+ - qcom,notify-rpm: When set, the driver configures the sleep and wake
+ sets. It also configures the next wakeup time for APPS.
+ - qcom,is-reset: This boolean property tells whether cluster level need
+ power management notifications to be sent out or not for the drivers to
+ prepare for cluster collapse.
+ - qcom,reset-level: This property is used to determine in this
+ low power mode only control logic power collapse happens or memory
+ logic power collapse aswell happens or retention state.
+ The accepted values for this property are:
+ "LPM_RESET_LVL_NONE" - No power collapse
+ "LPM_RESET_LVL_RET" - Retention state
+ "LPM_RESET_LVL_GDHS" - Only control logic power collapse (GDHS)
+ "LPM_RESET_LVL_PC" - Control logic and memory logic
+ power collapse (PC)
+
+[Node bindings for qcom,pm-cpu]
+qcom,pm-cpu contains the low power modes that a cpu could enter and the CPUs
+that share the parameters.It contains the following properties.
+ - qcom,cpu: List of CPU phandles to identify the CPUs associated with
+ this cluster.
+ - qcom,psci-mode-shift: Same as cluster level fields.
+ - qcom,psci-mode-mask: Same as cluster level fields.
+ - qcom,pm-cpu-levels: The different low power modes that a CPU could
+ enter. The following section explains the required properties of this
+ node.
+
+Optional properties:
+ - qcom,disable-prediction: This property is used to indicate the
+ LPM governor is to disable sleep prediction to this cpu.
+ - qcom,ref-stddev: This property is used as reference standard deviation
+ in lpm prediction algorithm. This value should be between 100 to 1000.
+ Higher value would result in more predictions and thereby resulting in
+ shallower low power modes.
+ - qcom,tmr-add: This property is used as correction timer for wrong
+ prediction by lpm prediction algorithm. This value should be between
+ 100 to 1500. Higher values would mean longer time staying in shallower
+ state before waking up to select a deeper state in case of wrong prediction.
+ - qcom,ref-premature-cnt: This property is used as reference premature
+ count to predict next sleep state by the prediction algorithm. This value
+ should be between 1 to 5. Higher value for this parameter would result in
+ less predictions to disallow deeper low power modes.
+
+[Node bindings for qcom,pm-cpu-levels]
+ Required properties:
+ - reg: The numeric cpu level id
+ - label: Name to identify the low power mode in stats
+ - qcom,psci-cpu-mode: ID to be passed into PSCI firmware.
+ - qcom,entry-latency-us: The latency to enter LPM level, in uSec
+ - qcom,exit-latency-us: The latency to exit LPM level, in uSec
+ - qcom,min-residency-us: The minimum residency value from which entering
+ to low power mode is beneficial, in uSec
+
+ Optional properties:
+ - qcom,is-reset: This boolean property maps to "power state" bit in PSCI
+ state_id configuration. This property will tell whether CPU get reset for
+ a particular LPM or not. This property is also used to notify the drivers
+ in case of cpu reset.
+ - qcom,use-broadcast-timer: Indicates that the timer gets reset during
+ power collapse and the cpu relies on Broadcast timer for scheduled wakeups.
+ Required only for states where the CPUs internal timer state is lost.
+
+[Example dts]
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,pm-cluster@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ label = "L3";
+ qcom,psci-mode-shift = <4>;
+ qcom,psci-mode-mask = <0xfff>;
+
+ qcom,pm-cluster-level@0 { /* D1 */
+ reg = <0>;
+ label = "l3-wfi";
+ qcom,psci-mode = <0x1>;
+ qcom,entry-latency-us = <48>;
+ qcom,exit-latency-us = <51>;
+ qcom,min-residency-us = <99>;
+ };
+
+ qcom,pm-cluster-level@1 { /* D2 */
+ reg = <1>;
+ label = "l3-dyn-ret";
+ qcom,psci-mode = <0x2>;
+ qcom,entry-latency-us = <317>;
+ qcom,exit-latency-us = <659>;
+ qcom,min-residency-us = <4065>;
+ };
+
+ qcom,pm-cluster-level@2 { /* D4, D3 is not supported */
+ reg = <2>;
+ label = "l3-pc";
+ qcom,psci-mode = <0x4>;
+ qcom,entry-latency-us = <814>;
+ qcom,exit-latency-us = <4562>;
+ qcom,min-residency-us = <7085>;
+ qcom,min-child-idx = <2>;
+ qcom,is-reset;
+ };
+
+ qcom,pm-cluster-level@3 { /* Cx off */
+ reg = <3>;
+ label = "cx-off";
+ qcom,psci-mode = <0x224>;
+ qcom,entry-latency-us = <814>;
+ qcom,exit-latency-us = <5562>;
+ qcom,min-residency-us = <9987>;
+ qcom,min-child-idx = <3>;
+ qcom,is-reset;
+ qcom,notify-rpm;
+ };
+
+ qcom,pm-cluster-level@4 { /* LLCC off, AOSS sleep */
+ reg = <4>;
+ label = "llcc-off";
+ qcom,psci-mode = <0xC24>;
+ qcom,entry-latency-us = <814>;
+ qcom,exit-latency-us = <6562>;
+ qcom,min-residency-us = <10100>;
+ qcom,min-child-idx = <3>;
+ qcom,is-reset;
+ qcom,notify-rpm;
+ };
+
+ qcom,pm-cpu@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,psci-mode-shift = <0>;
+ qcom,psci-mode-mask = <0xf>;
+ qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
+
+ qcom,pm-cpu-level@0 { /* C1 */
+ reg = <0>;
+ label = "wfi";
+ qcom,psci-cpu-mode = <0x1>;
+ qcom,entry-latency-us = <40>;
+ qcom,exit-latency-us = <43>;
+ qcom,min-residency-us = <100>;
+ };
+
+ qcom,pm-cpu-level@1 { /* C2D */
+ reg = <1>;
+ label = "ret";
+ qcom,psci-cpu-mode = <0x2>;
+ qcom,entry-latency-us = <81>;
+ qcom,exit-latency-us = <86>;
+ qcom,min-residency-us = <965>;
+ };
+
+ qcom,pm-cpu-level@2 { /* C3 */
+ reg = <2>;
+ label = "pc";
+ qcom,psci-cpu-mode = <0x3>;
+ qcom,entry-latency-us = <273>;
+ qcom,exit-latency-us = <612>;
+ qcom,min-residency-us = <1890>;
+ qcom,is-reset;
+ };
+
+ qcom,pm-cpu-level@3 { /* C4 */
+ reg = <3>;
+ label = "rail-pc";
+ qcom,psci-cpu-mode = <0x4>;
+ qcom,entry-latency-us = <300>;
+ qcom,exit-latency-us = <700>;
+ qcom,min-residency-us = <3934>;
+ qcom,is-reset;
+ };
+ };
+
+ qcom,pm-cpu@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,psci-mode-shift = <0>;
+ qcom,psci-mode-mask = <0xf>;
+ qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>;
+
+ qcom,pm-cpu-level@0 { /* C1 */
+ reg = <0>;
+ label = "wfi";
+ qcom,psci-cpu-mode = <0x1>;
+ qcom,entry-latency-us = <40>;
+ qcom,exit-latency-us = <43>;
+ qcom,min-residency-us = <83>;
+ };
+
+ qcom,pm-cpu-level@1 { /* C2D */
+ reg = <1>;
+ label = "ret";
+ qcom,psci-cpu-mode = <0x2>;
+ qcom,entry-latency-us = <81>;
+ qcom,exit-latency-us = <86>;
+ qcom,min-residency-us = <637>;
+ };
+
+ qcom,pm-cpu-level@2 { /* C3 */
+ reg = <2>;
+ label = "pc";
+ qcom,psci-cpu-mode = <0x3>;
+ qcom,entry-latency-us = <273>;
+ qcom,exit-latency-us = <612>;
+ qcom,min-residency-us = <952>;
+ qcom,is-reset;
+ };
+
+ qcom,pm-cpu-level@3 { /* C4 */
+ reg = <3>;
+ label = "rail-pc";
+ qcom,psci-cpu-mode = <0x4>;
+ qcom,entry-latency-us = <300>;
+ qcom,exit-latency-us = <700>;
+ qcom,min-residency-us = <4488>;
+ qcom,is-reset;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt
new file mode 100644
index 0000000..8b4bc6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt
@@ -0,0 +1,40 @@
+* RPM Stats
+
+RPM maintains a counter of the number of times the SoC entered a deeper sleep
+mode involving lowering or powering down the backbone rails - Cx and Mx and
+the oscillator clock, XO.
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,rpm-stats".
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: The address on the RPM RAM from where the stats are read
+ should be provided as "phys_addr_base". The offset from
+ which the stats are available should be provided as
+ "offset_addr".
+
+- reg-names:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Provides labels for the reg property.
+
+- qcom,num-records:
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies number of records to read from RPM RAM.
+
+EXAMPLE:
+
+ qcom,rpm-stats@c000000 {
+ compatible = "qcom,rpm-stats";
+ reg = <0xC000000 0x1000>, <0x3F0000 0x4>;
+ reg-names = "phys_addr_base", "offset_addr";
+ qcom,num-records = <3>;
+ };
+
diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
new file mode 100644
index 0000000..a53eba5
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
@@ -0,0 +1,31 @@
+* RPMH Master Stats
+
+Differet Subsystems maintains master data in SMEM.
+It tells about the individual masters information at any given
+time like "system sleep counts", "system sleep last entered at"
+and "system sleep accumulated duration" etc. These stats can be
+displayed using the sysfs interface.
+To achieve this, device tree node has been added.
+
+Additionally, RPMH master stats also maintains application processor's
+master stats. It uses profiling units to calculate power down and power
+up stats.
+
+The required properties for rpmh-master-stats are:
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,rpmh-master-stats-v1".
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Specifies physical address of start of profiling unit.
+
+Example:
+
+qcom,rpmh-master-stats {
+ compatible = "qcom,rpmh-master-stats";
+ reg = <0xb221200 0x60>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/system_pm.txt b/Documentation/devicetree/bindings/arm/msm/system_pm.txt
new file mode 100644
index 0000000..9628d9e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/system_pm.txt
@@ -0,0 +1,29 @@
+SYSTEM PM
+
+System PM device is a virtual device that handles all CPU subsystem low power
+mode activties. When entering core shutdown, resource state that were requested
+from the processor may be relinquished and set to idle and restored when the
+cores are brought out of sleep.
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,system-pm".
+
+-mboxes:
+ Usage: optional
+ Value type: <phandle>
+ Definition: phandle the TCS mailbox controller for the CPU subsystem.
+ This property is generally set only for SoCs that use RPMH communication
+ through a mailbox controller.
+
+EXAMPLE
+
+ system_pm {
+ compatible = "qcom,system-pm";
+ mboxes = <&apps_rsc 0>;
+ };
+
+
diff --git a/Documentation/devicetree/bindings/gpu/adreno-busmon.txt b/Documentation/devicetree/bindings/gpu/adreno-busmon.txt
new file mode 100644
index 0000000..f9a99bb
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-busmon.txt
@@ -0,0 +1,16 @@
+Adreno bus monitor device
+
+kgsl-busmon is a psedo device that represents a devfreq bus bandwidth
+governor. If this device is present then two different governors are used
+for GPU DCVS and bus DCVS.
+
+Required properties:
+- compatible: Must be "qcom,kgsl-busmon"
+- label: Device name used for sysfs entry.
+
+Example:
+
+qcom,kgsl-busmon {
+ compatible = "qcom,kgsl-busmon";
+ label = "kgsl-busmon";
+};
diff --git a/Documentation/devicetree/bindings/gpu/adreno-gmu.txt b/Documentation/devicetree/bindings/gpu/adreno-gmu.txt
new file mode 100644
index 0000000..062551e
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-gmu.txt
@@ -0,0 +1,129 @@
+Qualcomm Technologies, Inc. GPU Graphics Management Unit (GMU)
+
+Required properties:
+- compatible :
+ - "qcom,gpu-gmu"
+ - "qcom,gpu-rgmu"
+- reg: Specifies the GMU register base address and size.
+- reg-names: Resource names used for the physical address
+ and length of GMU registers.
+- interrupts: Interrupt mapping for GMU and HFI IRQs.
+- interrupt-names: String property to describe the name of each interrupt.
+
+Bus Scaling Data:
+qcom,msm-bus,name: String property to describe the name of bus client.
+qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases defined in the vectors property.
+qcom,msm-bus,num-paths: This represents the number of paths in each Bus Scaling Usecase.
+qcom,msm-bus,vectors-KBps: A series of 4 cell properties, format of which is:
+ <src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 1
+ <src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 2
+ <.. .. .. ..>, <.. .. .. ..>; // For Bus Scaling Usecase n
+ This property is a series of all vectors for all Bus Scaling Usecases.
+ Each set of vectors for each usecase describes bandwidth votes for a combination
+ of src/dst ports. The driver will set the desired use case based on the selected
+ power level and the desired bandwidth vote will be registered for the port pairs.
+
+GMU GDSC/regulators:
+- regulator-names: List of regulator name strings
+- vddcx-supply: Phandle for vddcx regulator device node.
+- vdd-supply: Phandle for vdd regulator device node.
+
+- clock: List of clocks to be used for GMU register access and DCVS. See
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+ for information about the format. For each clock specified
+ here, there must be a corresponding entry in clock-names
+ (see below).
+
+- clock-names: List of clock names corresponding to the clocks specified in
+ the "clocks" property (above). See
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+ for more info. Currently GMU required these clock names:
+ "gmu_clk", "ahb_clk", "cxo_clk", "axi_clk", "memnoc_clk",
+ "rbcpr_clk"
+
+- qcom,gmu-pwrlevels: device node defines a set of GMU power levels. It has
+ following required properties:
+
+ - compatible : "qcom,gmu-pwrlevels"
+ - qcom,gmu-pwrlevel: a single power level. Each power level has
+ below properties:
+ - reg: index of the powerlevel (0 = highest perf)
+ - qcom, gmu-freq: GMU frequency for the power level in Hz.
+
+- List of sub nodes, one for each of the translation context banks needed
+ for GMU to access system memory in different operating mode. Currently
+ supported names are:
+ - gmu_user: used for GMU 'user' mode address space.
+ - gmu_kernel: used for GMU 'kernel' mode address space.
+ Each sub node has the following required properties:
+
+ - compatible : "qcom,smmu-gmu-user-cb" or "qcom,smmu-gmu-kernel-cb"
+ - iommus : Specifies the SID's used by this context bank, this
+ needs to be <kgsl_smmu SID> pair, kgsl_smmu is the string
+ parsed by iommu driver to match this context bank with the
+ kgsl_smmu device defined in iommu device tree. On targets
+ where the msm iommu driver is used rather than the arm smmu
+ driver, this property may be absent.
+
+Example:
+
+gmu: qcom,gmu@2c6a000 {
+ label = "kgsl-gmu";
+ compatible = "qcom,gpu-gmu";
+
+ reg = <0x2c6a000 0x30000>;
+ reg-names = "kgsl_gmu_reg";
+
+ interrupts = <0 304 0>, <0 305 0>;
+ interrupt-names = "kgsl_gmu_irq", "kgsl_hfi_irq";
+
+ qcom,msm-bus,name = "cnoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 10036 0 0>, // CNOC off
+ <26 10036 0 100>; // CNOC on
+
+ regulator-name = "vddcx", "vdd";
+ vddcx-supply = <&gpu_cx_gdsc>;
+ vdd-supply = <&gpu_gx_gdsc>;
+
+ clocks = <&clock_gpugcc clk_gcc_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_gpucc GPU_CC_RBCPR_CLK>;
+
+ clock-names = "gmu_clk", "ahb_clk", "cxo_clk",
+ "axi_clk", "memnoc_clk", "rbcpr_clk";
+
+ qcom,gmu-pwrlevels {
+
+ compatible = "qcom,gmu-pwrlevels";
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gmu-freq = <500000000>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gmu-freq = <200000000>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gmu-freq = <0>;
+ };
+ };
+
+ gmu_user: gmu_user {
+ compatible = "qcom,smmu-gmu-user-cb";
+ iommus = <&kgsl_smmu 4>;
+ };
+
+ gmu_kernel: gmu_kernel {
+ compatible = "qcom,smmu-gmu-kernel-cb";
+ iommus = <&kgsl_smmu 5>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
new file mode 100644
index 0000000..175c51a
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
@@ -0,0 +1,93 @@
+Qualcomm Technologies, Inc. GPU IOMMU
+
+Required properties:
+
+Required properties:
+- compatible : one of:
+ - "qcom,kgsl-smmu-v1"
+ - "qcom,kgsl-smmu-v2"
+
+- reg : Base address and size of the SMMU.
+
+- clocks : List of clocks to be used during SMMU register access. See
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+ for information about the format. For each clock specified
+ here, there must be a corresponding entry in clock-names
+ (see below).
+
+- clock-names : List of clock names corresponding to the clocks specified in
+ the "clocks" property (above). See
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+ for more info.
+- qcom,protect : The GPU register region which must be protected by a CP
+ protected mode. On some targets this region must cover
+ the entire SMMU register space, on others there
+ is a separate aperture for CP to program context banks.
+
+Optional properties:
+- qcom,micro-mmu-control : Some targets provide an implementation defined
+ register for blocking translation requests during GPU side
+ programming. This property specifies the offset of this
+ register within the iommu register space.
+- qcom,retention : A boolean specifying if retention is supported on this target
+- qcom,global_pt : A boolean specifying if global pagetable should be used.
+ When not set we use per process pagetables
+- qcom,hyp_secure_alloc : A bool specifying if the hypervisor is used on this target
+ for secure buffer allocation
+- qcom,secure_align_mask: A mask for determining how secure buffers need to
+ be aligned
+
+- List of sub nodes, one for each of the translation context banks supported.
+ The driver uses the names of these nodes to determine how they are used,
+ currently supported names are:
+ - gfx3d_user : Used for the 'normal' GPU address space.
+ - gfx3d_secure : Used for the content protection address space.
+ - gfx3d_secure_alt : Used for the content protection address space for alternative SID.
+
+ Each sub node has the following required properties:
+
+ - compatible : "qcom,smmu-kgsl-cb"
+ - iommus : Specifies the SID's used by this context bank, this needs to be
+ <kgsl_smmu SID> pair, kgsl_smmu is the string parsed by iommu
+ driver to match this context bank with the kgsl_smmu device
+ defined in iommu device tree. On targets where the msm iommu
+ driver is used rather than the arm smmu driver, this property
+ may be absent.
+ - qcom,gpu-offset : Offset into the GPU register space for accessing
+ this context bank. On some targets the iommu registers are not
+ part of the GPU's register space, and a separate register aperture
+ is used. Otherwise the same register offsets may be used for CPU
+ or GPU side programming.
+
+Example:
+
+msm_iommu: qcom,kgsl-iommu@2ca0000 {
+ compatible = "qcom,kgsl-smmu-v2";
+ reg = <0x2ca0000 0x10000>;
+ qcom,protect = <0xa0000 0xc000>;
+ clocks = <&clock_mmss clk_gpu_ahb_clk>,
+ <&clock_gcc clk_gcc_mmss_bimc_gfx_clk>,
+ <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+ <&clock_mmss clk_mmss_mmagic_cfg_ahb_clk>;
+ clock-names = "gpu_ahb_clk", "bimc_gfx_clk", "mmagic_ahb_clk", "mmagic_cfg_ahb_clk";
+ qcom,secure_align_mask = <0xfff>;
+ qcom,retention;
+ qcom,global_pt;
+
+ gfx3d_user: gfx3d_user {
+ compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 0>,
+ <&kgsl_smmu 1>;
+ qcom,gpu-offset = <0xa8000>;
+ };
+
+ gfx3d_secure: gfx3d_secure {
+ compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 2>;
+ };
+
+ gfx3d_secure_alt: gfx3d_secure_alt {
+ compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
new file mode 100644
index 0000000..0b4510a
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
@@ -0,0 +1,45 @@
+Qualcomm Technologies, Inc. GPU powerlevels
+
+Powerlevels are defined in sets by qcom,gpu-pwrlevels. Multiple sets (bins)
+can be defined within qcom,gpu-pwrelvel-bins. Each powerlevel defines a
+voltage, bus, bandwidth level, and a DVM value.
+
+- qcom,gpu-pwrlevel-bins: Contains one or more qcom,gpu-pwrlevels sets
+
+Properties:
+- compatible: Must be qcom,gpu-pwrlevel-bins
+- qcom,gpu-pwrlevels: Defines a set of powerlevels
+
+Properties:
+- qcom,speed-bin: Speed bin identifier for the set - must match
+ the value read from the hardware
+- qcom,initial-pwrlevel: GPU wakeup powerlevel
+
+- qcom,gpu-pwrlevel: A single powerlevel
+
+- qcom,ca-target-pwrlevel:
+ This value indicates which qcom,gpu-pwrlevel
+ to jump on in case of context aware power level
+ jump.
+Properties:
+- reg: Index of the powerlevel (0 = highest perf)
+- qcom,gpu-freq GPU frequency for the powerlevel (in Hz)
+- qcom,bus-freq Index to a bus level (defined by the bus
+ settings)
+- qcom,bus-min Minimum bus level to set for the power level
+- qcom,bus-max maximum bus level to set for the power level
+- qcom,dvm-val: Value that is used as a register setting for
+ the ACD power feature. It helps determine the
+ threshold for when ACD activates. 0xFFFFFFFF
+ is the default value, and the setting where
+ ACD will never activate.
+Example:
+
+qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <0>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ qcom,dvm-val = <0xffffffff>;
+};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
new file mode 100644
index 0000000..bbb1f54
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -0,0 +1,471 @@
+Qualcomm Technologies, Inc. GPU
+
+Qualcomm Technologies, Inc. Adreno GPU
+
+Required properties:
+- label: A string used as a descriptive name for the device.
+- compatible: Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d"
+- reg: Specifies the register base address and size, the shader memory
+ base address and size (if it exists), and the base address and size
+ of the CX_DBGC block (if it exists).
+- reg-names: Resource names used for the physical address of device registers
+ and shader memory. "kgsl_3d0_reg_memory" gives the physical address
+ and length of device registers while "kgsl_3d0_shader_memory" gives
+ physical address and length of device shader memory. If
+ specified, "qfprom_memory" gives the range for the efuse
+ registers used for various configuration options. If specified,
+ "kgsl_3d0_cx_dbgc_memory" gives the physical address and length
+ of the CX DBGC block.
+- interrupts: Interrupt mapping for GPU IRQ.
+- interrupt-names: String property to describe the name of the interrupt.
+- qcom,id: An integer used as an identification number for the device.
+- qcom,gpu-bimc-interface-clk-freq:
+ GPU-BIMC interface clock needs to be set to this value for
+ targets where B/W requirements does not meet GPU Turbo use cases.
+- clocks: List of phandle and clock specifier pairs, one pair
+ for each clock input to the device.
+- clock-names: List of clock input name strings sorted in the same
+ order as the clocks property.
+ Current values of clock-names are:
+ "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk",
+ "alt_mem_iface_clk", "rbbmtimer_clk", "alwayson_clk",
+ "iref_clk", "l3_vote"
+ "core_clk" and "iface_clk" are required and others are optional
+
+- qcom,base-leakage-coefficient: Dynamic leakage coefficient.
+- qcom,lm-limit: Current limit for GPU limit management.
+- qcom,isense-clk-on-level: below or equal this power level isense clock is at XO rate,
+ above this powerlevel isense clock is at working frequency.
+
+Bus Scaling Data:
+- qcom,msm-bus,name: String property to describe the name of the 3D graphics processor.
+- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases defined in the vectors property.
+- qcom,msm-bus,active-only: A boolean flag indicating if it is active only.
+- qcom,msm-bus,num-paths: This represents the number of paths in each Bus Scaling Usecase.
+- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, format of which is:
+ <src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 1
+ <src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 2
+ <.. .. .. ..>, <.. .. .. ..>; // For Bus Scaling Usecase n
+ This property is a series of all vectors for all Bus Scaling Usecases.
+ Each set of vectors for each usecase describes bandwidth votes for a combination
+ of src/dst ports. The driver will set the desired use case based on the selected
+ power level and the desired bandwidth vote will be registered for the port pairs.
+ Current values of src are:
+ 0 = MSM_BUS_MASTER_GRAPHICS_3D
+ 1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1
+ 2 = MSM_BUS_MASTER_V_OCMEM_GFX3D
+ Current values of dst are:
+ 0 = MSM_BUS_SLAVE_EBI_CH0
+ 1 = MSM_BUS_SLAVE_OCMEM
+ ab: Represents aggregated bandwidth. This value is 0 for Graphics.
+ ib: Represents instantaneous bandwidth. This value has a range <0 8000 MB/s>
+
+- qcom,ocmem-bus-client: Container for another set of bus scaling properties
+ qcom,msm-bus,name
+ qcom,msm-bus,num-cases
+ qcom,msm-bus,num-paths
+ qcom,msm-bus,vectors-KBps
+ to be used by ocmem msm bus scaling client.
+
+GDSC Oxili Regulators:
+- regulator-names: List of regulator name strings sorted in power-on order
+- vddcx-supply: Phandle for vddcx regulator device node.
+- vdd-supply: Phandle for vdd regulator device node.
+
+IOMMU Data:
+- iommu: Phandle for the KGSL IOMMU device node
+
+GPU Power levels:
+- qcom,gpu-pwrlevel-bins: Container for sets of GPU power levels (see
+ adreno-pwrlevels.txt)
+DCVS Core info
+- qcom,dcvs-core-info Container for the DCVS core info (see
+ dcvs-core-info.txt)
+
+Optional Properties:
+- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
+ and when coming back out of resume
+- qcom,bus-control: Boolean. Enables an independent bus vote from the gpu frequency
+- qcom,bus-width: Bus width in number of bytes. This enables dynamic AB bus voting based on
+ bus width and actual bus transactions.
+- qcom,gpubw-dev: a phandle to a device representing bus bandwidth requirements
+ (see devdw.txt)
+- qcom,idle-timeout: This property represents the time in milliseconds for idle timeout.
+- qcom,no-nap: If it exists software clockgating will be disabled at boot time.
+- qcom,chipid: If it exists this property is used to replace
+ the chip identification read from the GPU hardware.
+ This is used to override faulty hardware readings.
+- qcom,disable-wake-on-touch: Boolean. Disables the GPU power up on a touch input event.
+- qcom,disable-busy-time-burst:
+ Boolean. Disables the busy time burst to avoid switching
+ of power level for large frames based on the busy time limit.
+
+- qcom,pm-qos-active-latency:
+ Right after GPU wakes up from sleep, driver votes for
+ acceptable maximum latency to the pm-qos driver. This
+ voting demands that the system can not go into any
+ power save state *if* the latency to bring system back
+ into active state is more than this value.
+ Value is in microseconds.
+- qcom,pm-qos-wakeup-latency:
+ Similar to the above. Driver votes against deep low
+ power modes right before GPU wakes up from sleep.
+- qcom,l2pc-cpu-mask-latency:
+ The CPU mask latency in microseconds to avoid L2PC
+ on masked CPUs.
+
+- qcom,gpu-cx-ipeak:
+ CX Ipeak is a mitigation scheme which throttles cDSP frequency
+ if all the clients are running at their respective threshold
+ frequencies to limit CX peak current.
+ <phandle bit>
+ phandle - phandle of CX Ipeak device node
+ bit - Every bit corresponds to a client of CX Ipeak
+ driver in the relevant register.
+- qcom, gpu-cx-ipeak-freq:
+ GPU frequency threshold for CX Ipeak voting. GPU votes
+ to CX Ipeak driver when GPU clock crosses this threshold.
+ CX Ipeak can limit peak current based on voting from other clients.
+
+- qcom,force-32bit:
+ Force the GPU to use 32 bit data sizes even if
+ it is capable of doing 64 bit.
+
+- qcom,gpu-speed-bin: GPU speed bin information in the format
+ <offset mask shift>
+ offset - offset of the efuse register from the base.
+ mask - mask for the relevant bits in the efuse register.
+ shift - number of bits to right shift to get the speed bin
+ value.
+- qcom,gpu-disable-fuse: GPU disable fuse
+ <offset mask shift>
+ offset - offset of the efuse register from the base.
+ mask - mask for the relevant bits in the efuse register.
+ shift - number of bits to right shift to get the disable_gpu
+ fuse bit value.
+
+- qcom,soc-hw-rev-efuse: SOC hardware revision fuse information in the format
+ <offset bit_position mask>
+ offset - offset of the efuse register from the base.
+ bit_position - hardware revision starting bit in the efuse register.
+ mask - mask for the relevant bits in the efuse register.
+
+- qcom,highest-bank-bit:
+ Specify the bit of the highest DDR bank. This
+ is programmed into protected registers and also
+ passed to the user as a property.
+- qcom,min-access-length:
+ Specify the minimum access length for the chip.
+ Either 32 or 64 bytes.
+ Based on the above options, program the appropriate bit into
+ certain protected registers and also pass to the user as
+ a property.
+- qcom,ubwc-mode:
+ Specify the ubwc mode for this chip.
+ 1: UBWC 1.0
+ 2: UBWC 2.0
+ 3: UBWC 3.0
+ Based on the ubwc mode, program the appropriate bit into
+ certain protected registers and also pass to the user as
+ a property.
+- qcom,l2pc-cpu-mask:
+ Disables L2PC on masked CPUs when any of Graphics
+ rendering thread is running on masked CPUs.
+ Bit 0 is for CPU-0, bit 1 is for CPU-1...
+
+- qcom,l2pc-update-queue:
+ Disables L2PC on masked CPUs at queue time when it's true.
+
+- qcom,snapshot-size:
+ Specify the size of snapshot in bytes. This will override
+ snapshot size defined in the driver code.
+
+- qcom,enable-ca-jump:
+ Boolean. Enables use of context aware DCVS
+- qcom,ca-busy-penalty:
+ This property represents the time in microseconds required to
+ initiate context aware power level jump.
+- qcom,ca-target-pwrlevel:
+ This value indicates which qcom,gpu-pwrlevel to jump on in case
+ of context aware power level jump.
+
+- qcom,gpu-qdss-stm:
+ <baseAddr size>
+ baseAddr - base address of the gpu channels in the qdss stm memory region
+ size - size of the gpu stm region
+
+- qcom,gpu-qtimer:
+ <baseAddr size>
+ baseAddr - base address of the qtimer memory region
+ size - size of the qtimer region
+
+- qcom,tsens-name:
+ Specify the name of GPU temperature sensor. This name will be used
+ to get the temperature from the thermal driver API.
+
+- qcom,enable-midframe-timer:
+ Boolean. Enables the use of midframe sampling timer. This timer
+ samples the GPU powerstats if the cmdbatch expiry takes longer than
+ the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if
+ target has NAP state enabled.
+
+GPU Quirks:
+- qcom,gpu-quirk-two-pass-use-wfi:
+ Signal the GPU to set Set TWOPASSUSEWFI bit in
+ PC_DBG_ECO_CNTL (5XX and 6XX only)
+- qcom,gpu-quirk-critical-packets:
+ Submit a set of critical PM4 packets when the GPU wakes up
+- qcom,gpu-quirk-fault-detect-mask:
+ Mask out RB1-3 activity signals from HW hang
+ detection logic
+- qcom,gpu-quirk-dp2clockgating-disable:
+ Disable RB sampler data path clock gating optimization
+- qcom,gpu-quirk-lmloadkill-disable:
+ Use register setting to disable local memory(LM) feature
+ to avoid corner case error
+- qcom,gpu-quirk-hfi-use-reg:
+ Use registers to replace DCVS HFI message to avoid GMU failure
+ to access system memory during IFPC
+- qcom,gpu-quirk-limit-uche-gbif-rw:
+ Limit number of read and write transactions from UCHE block to
+ GBIF to avoid possible deadlock between GBIF, SMMU and MEMNOC.
+- qcom,gpu-quirk-mmu-secure-cb-alt:
+ Select alternate secure context bank to generate SID1 for
+ secure playback.
+
+KGSL Memory Pools:
+- qcom,gpu-mempools: Container for sets of GPU mempools.Multiple sets
+ (pools) can be defined within qcom,gpu-mempools.
+ Each mempool defines a pool order, reserved pages,
+ allocation allowed.
+Properties:
+- compatible: Must be qcom,gpu-mempools.
+- qcom,mempool-max-pages: Max pages for all mempools, If not defined there is no limit.
+- qcom,gpu-mempool: Defines a set of mempools.
+
+Properties:
+- reg: Index of the pool (0 = lowest pool order).
+- qcom,mempool-page-size: Size of page.
+- qcom,mempool-reserved: Number of pages reserved at init time for a pool.
+- qcom,mempool-allocate: Allocate memory from the system memory when the
+ reserved pool exhausted.
+
+SOC Hardware revisions:
+- qcom,soc-hw-revisions:
+ Container of sets of SOC hardware revisions specified by
+ qcom,soc-hw-revision.
+Properties:
+- compatible:
+ Must be qcom,soc-hw-revisions.
+
+- qcom,soc-hw-revision:
+ Defines a SOC hardware revision.
+
+Properties:
+- qcom,soc-hw-revision:
+ Identifier for the hardware revision - must match the value read
+ from the hardware.
+- qcom,chipid:
+ GPU Chip ID to be used for this hardware revision.
+- qcom,gpu-quirk-*:
+ GPU quirks applicable for this hardware revision.
+
+GPU LLC slice info:
+- cache-slice-names: List of LLC cache slices for GPU transactions
+ and pagetable walk.
+- cache-slices: phandle to the system LLC driver, cache slice index.
+
+L3 Power levels:
+- qcom,l3-pwrlevels: Container for sets of L3 power levels, the
+ L3 frequency is adjusted according to the
+ performance hint received from userspace.
+
+Properties:
+- compatible: Must be qcom,l3-pwrlevels
+- qcom,l3-pwrlevel: A single L3 powerlevel
+
+Properties:
+- reg: Index of the L3 powerlevel
+ 0 = powerlevel for no L3 vote
+ 1 = powerlevel for medium L3 vote
+ 2 = powerlevel for maximum L3 vote
+- qcom,l3-freq: The L3 frequency for the powerlevel (in Hz)
+
+GPU coresight info:
+The following properties are optional as collecting data via coresight might
+not be supported for every chipset. The documentation for coresight
+properties can be found in:
+Documentation/devicetree/bindings/coresight/coresight.txt
+
+- qcom,gpu-coresights: Container for sets of GPU coresight sources.
+- coresight-id: Unique integer identifier for the bus.
+- coresight-name: Unique descriptive name of the bus.
+- coresight-nr-inports: Number of input ports on the bus.
+- coresight-outports: List of output port numbers on the bus.
+- coresight-child-list: List of phandles pointing to the children of this
+ component.
+- coresight-child-ports: List of input port numbers of the children.
+- coresight-atid: The unique ATID value of the coresight device
+
+Example of A330 GPU in MSM8916:
+
+&soc {
+ msm_gpu: qcom,kgsl-3d0@1c00000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ reg = <0x1c00000 0x10000
+ 0x1c20000 0x20000>;
+ reg-names = "kgsl_3d0_reg_memory" , "kgsl_3d0_shader_memory";
+ interrupts = <0 33 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x03000600>;
+
+ qcom,initial-pwrlevel = <1>;
+
+ /* Idle Timeout = HZ/12 */
+ qcom,idle-timeout = <8>;
+ qcom,strtstp-sleepwake;
+
+ clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>,
+ <&clock_gcc clk_gcc_oxili_ahb_clk>,
+ <&clock_gcc clk_gcc_oxili_gmem_clk>,
+ <&clock_gcc clk_gcc_bimc_gfx_clk>,
+ <&clock_gcc clk_gcc_bimc_gpu_clk>;
+ clock-names = "core_clk", "iface_clk", "mem_clk",
+ "mem_iface_clk", "alt_mem_iface_clk";
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "grp3d";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>,
+ <26 512 0 1600000>,
+ <26 512 0 3200000>,
+ <26 512 0 4264000>;
+
+ /* GDSC oxili regulators */
+ vdd-supply = <&gdsc_oxili_gx>;
+
+ /* IOMMU Data */
+ iommu = <&gfx_iommu>;
+
+ /* Trace bus */
+ coresight-id = <67>;
+ coresight-name = "coresight-gfx";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <5>;
+
+ /* Enable context aware freq. scaling */
+ qcom,enable-ca-jump;
+
+ /* Context aware jump busy penalty in us */
+ qcom,ca-busy-penalty = <12000>;
+
+ /* Context aware jump target power level */
+ qcom,ca-target-pwrlevel = <1>;
+
+ qcom,soc-hw-revisions {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible="qcom,soc-hw-revisions";
+
+ qcom,soc-hw-revision@0 {
+ reg = <0>;
+
+ qcom,chipid = <0x06010500>;
+ qcom,gpu-quirk-hfi-use-reg;
+ qcom,gpu-quirk-limit-uche-gbif-rw;
+ };
+
+ qcom,soc-hw-revision@1 {
+ reg = <1>;
+
+ qcom,chipid = <0x06010501>;
+ qcom,gpu-quirk-hfi-use-reg;
+ };
+ };
+
+ /* GPU Mempools */
+ qcom,gpu-mempools {
+ #address-cells= <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-mempools";
+
+ /* 4K Page Pool configuration */
+ qcom,gpu-mempool@0 {
+ reg = <0>;
+ qcom,mempool-page-size = <4096>;
+ qcom,mempool-reserved = <2048>;
+ qcom,mempool-allocate;
+ };
+ /* 8K Page Pool configuration */
+ qcom,gpu-mempool@1 {
+ reg = <1>;
+ qcom,mempool-page-size = <8192>;
+ qcom,mempool-reserved = <1024>;
+ qcom,mempool-allocate;
+ };
+ /* 64K Page Pool configuration */
+ qcom,gpu-mempool@2 {
+ reg = <2>;
+ qcom,mempool-page-size = <65536>;
+ qcom,mempool-reserved = <256>;
+ };
+ /* 1M Page Pool configuration */
+ qcom,gpu-mempool@3 {
+ reg = <3>;
+ qcom,mempool-page-size = <1048576>;
+ qcom,mempool-reserved = <32>;
+ };
+ };
+
+ /* Power levels */
+ qcom,gpu-pwrlevels-bins {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,gpu-pwrlevels-0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,speed-bin = <0>;
+ qcom,ca-target-pwrlevel = <1>;
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <400000000>;
+ qcom,bus-freq = <3>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <310000000>;
+ qcom,bus-freq = <2>;
+ qcom,io-fraction = <66>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <200000000>;
+ qcom,bus-freq = <1>;
+ qcom,io-fraction = <100>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <27000000>;
+ qcom,bus-freq = <0>;
+ qcom,io-fraction = <0>;
+ };
+ };
+ };
+
+ };
+};
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 1113039..f720ef4 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -180,6 +180,63 @@
property, indicating the number of Stream ID
arguments associated with its phandle.
+** Additional properties for Iommu Clients:
+- qcom,iommu-dma:
+ Optional, String.
+ Can be one of "bypass", "fastmap", "atomic", "disabled".
+--- "default":
+ Standard iommu translation behavior.
+ The iommu framework will automatically create a domain for the client.
+ iommu and DMA apis may not be called in atomic context.
+--- "bypass":
+ DMA APIs will use 1-to-1 translation between dma_addr and phys_addr.
+ Allows using iommu and DMA apis in atomic context.
+--- "fastmap":
+ DMA APIs will run faster, but use several orders of magnitude more memory.
+ Also allows using iommu and DMA apis in atomic context.
+--- "atomic":
+ Allows using iommu and DMA apis in atomic context.
+--- "disabled":
+ The iommu client is responsible for allocating an iommu domain, as
+ well as calling iommu_map to create the desired mappings.
+
+- qcom,iommu-faults:
+ Optional, List of Strings.
+ The SCTLR register setting which affect iommu faults handling.
+ Any combination of the below strings may be used. Mutliple
+ values are accepted.
+--- "default":
+ Any faults are treated as fatal errors.
+--- "no-CFRE":
+ Iommu faults do not return an abort to the client hardware.
+--- "non-fatal":
+ Iommu faults do not trigger a kernel panic.
+--- "stall-disable":
+ Iommu faults do not stall the client while the fault
+ interrupt is being handled.
+
+- qcom,iommu-vmid:
+ Optional, Int.
+ An identifier indicating the security state of the client.
+
+- qcom,iommu-pagetable:
+ Optional, String.
+ Enables coherency for the IOMMU device, but not for the Client.
+--- "default":
+ Pagetables are not coherent nor cached in the system cache..
+--- "coherent"
+ Pagetables are io-coherent.
+--- "LLC"
+ Pagetables may be saved in the system cache.
+--- "LLC_NWA"
+ Pagetables may be saved in the system cache is used, and
+ write-allocate hint is disabled.
+
+- qcom,iommu-earlymap:
+ Optional, Bool.
+ Support creating mappings in the page-table before Stage 1 translation is
+ enabled.
+
** Examples:
/* SMMU with stream matching or stream indexing */
diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt
new file mode 100644
index 0000000..cace019
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt
@@ -0,0 +1,290 @@
+Bindings for Qualcomm Technologies, Inc. WLED driver
+
+WLED (White Light Emitting Diode) driver is used for controlling display
+backlight that is part of PMIC on Qualcomm Technologies, Inc. reference
+platforms. The PMIC is connected to the host processor via SPMI bus.
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: should be one of the below.
+ "qcom,pmi8998-spmi-wled",
+ "qcom,pm8150l-spmi-wled",
+ "qcom,pm6150l-spmi-wled"
+
+- reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Base address and size of the WLED modules.
+
+- reg-names
+ Usage: required
+ Value type: <string>
+ Definition: Names associated with base addresses. should be
+ "wled-ctrl-base", "wled-sink-base".
+
+- interrupts
+ Usage: optional
+ Value type: <prop encoded array>
+ Definition: Interrupts associated with WLED. Interrupts can be
+ specified as per the encoding listed under
+ Documentation/devicetree/bindings/spmi/
+ qcom,spmi-pmic-arb.txt.
+
+- interrupt-names
+ Usage: optional
+ Value type: <string>
+ Definition: Interrupt names associated with the interrupts.
+ Currently supported interrupts are "sc-irq", "ovp-irq",
+ "pre-flash-irq" and "flash-irq". Pre_flash and flash
+ interrupts can be specified only for PMICs that has WLED5.
+
+- label
+ Usage: required
+ Value type: <string>
+ Definition: The name of the backlight device.
+
+- default-brightness
+ Usage: optional
+ Value type: <u32>
+ Definition: Brightness value on boot. Default is 2048.
+ Range of values are:
+ For pmi8998, it is 0-4095.
+ For pm8150l, this can vary from 0-4095 or 0-32767 depending
+ on the brightness control mode. If CABC is enabled, 0-4095
+ range is used.
+
+- max-brightness
+ Usage: optional
+ Value type: <u32>
+ Definition: Maximum brightness level. Allowed values are:
+ For pmi8998, it is 4095.
+ For pm8150l, this can be either 4095 or 32767.
+ If CABC is enabled, this is capped to 4095.
+
+- qcom,fs-current-limit
+ Usage: optional
+ Value type: <u32>
+ Definition: per-string full scale current limit in uA. value from
+ 0 to 30000 with 5000 uA resolution. Default: 25000 uA
+
+- qcom,boost-current-limit
+ Usage: optional
+ Value type: <u32>
+ Definition: ILIM threshold in mA. values are 105, 280, 450, 620, 970,
+ 1150, 1300, 1500. Default: 970 mA
+
+- qcom,switching-freq
+ Usage: optional
+ Value type: <u32>
+ Definition: Switching frequency in KHz. values are
+ 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371,
+ 1600, 1920, 2400, 3200, 4800, 9600.
+ Default: 800 KHz
+
+- qcom,ovp
+ Usage: optional
+ Value type: <u32>
+ Definition: Over-voltage protection limit in mV. values are 31100,
+ 29600, 19600, 18100.
+ Default: 29600 mV
+
+- qcom,string-cfg
+ Usage: optional
+ Value type: <u32>
+ Definition: Bit mask of the WLED strings. Bit 0 to 3 indicates strings
+ 0 to 3 respectively. WLED module has four strings of leds
+ numbered from 0 to 3. Each string of leds are operated
+ individually. Specify the strings using the bit mask. Any
+ combination of led strings can be used.
+ Default value is 15 (b1111).
+
+- qcom,en-cabc
+ Usage: optional
+ Value type: <bool>
+ Definition: Specify if cabc (content adaptive backlight control) is
+ needed.
+
+- qcom,ext-pfet-sc-pro-en
+ Usage: optional
+ Value type: <bool>
+ Definition: Specify if external PFET control for short circuit
+ protection is needed. This is not applicable for PM8150L.
+
+- qcom,auto-calibration
+ Usage: optional
+ Value type: <bool>
+ Definition: Enables auto-calibration of the WLED sink configuration.
+
+- qcom,modulator-sel
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the modulator used for brightness modulation.
+ Allowed values are:
+ 0 - Modulator A
+ 1 - Modulator B
+ If not specified, then modulator A will be used by default.
+ This property is applicable only to WLED5 peripheral.
+
+- qcom,cabc-sel
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the CABC pin signal used for brightness modulation.
+ Allowed values are:
+ 0 - CABC disabled
+ 1 - CABC 1
+ 2 - CABC 2
+ 3 - External signal (e.g. LPG) is used for dimming
+ This property is applicable only to WLED5 peripheral.
+
+- qcom,pmic-revid
+ Usage: optional
+ Value type: <phandle>
+ Definition: If specified, can be used to get PMIC revision information.
+
+- qcom,leds-per-string
+ Usage: optional
+ Value type: <u32>
+ Definition: If specified, can be used to calculate available current
+ during selfie flash operation. If not specified, available
+ current calculated is simply the configured threshold.
+
+Following properties are for child subnodes that are needed for WLED preflash
+(or torch), flash and switch. These child subnodes can be specified only for
+PMICs that has WLED5 (e.g. PM8150L).
+
+For wled_torch child subnode,
+
+- label
+ Usage: required
+ Value type: <string>
+ Definition: Should be "torch".
+
+- qcom,default-led-trigger
+ Usage: optional
+ Value type: <string>
+ Definition: Name for LED trigger. If unspecified, "wled_torch" is used.
+
+- qcom,wled-torch-fsc
+ Usage: optional
+ Value type: <u32>
+ Definition: WLED torch full scale current in mA. This configures the
+ maximum current allowed for torch device. Allowed values
+ are from 5 to 60 mA with a step of 5 mA. If not specified,
+ default value is set to 30 mA.
+
+- qcom,wled-torch-step
+ Usage: optional
+ Value type: <u32>
+ Definition: WLED torch step delay in us. This configures the step delay
+ when the output is ramped up to the desired target current.
+ Allowed values are from 50 to 400 us with a step of 50 us.
+ If not specified, default value is set to 200 us.
+
+- qcom,wled-torch-timer
+ Usage: optional
+ Value type: <u32>
+ Definition: WLED torch safety timer in ms. This configures the safety
+ timer to turn off torch automatically after timer expiry.
+ Allowed values are: 50, 100, 200, 400, 600, 800, 1000 and
+ 1200. If not specified, default value is set to 1200 ms.
+
+For wled_flash child subnode,
+
+- label
+ Usage: required
+ Value type: <string>
+ Definition: Should be "flash".
+
+- qcom,default-led-trigger
+ Usage: optional
+ Value type: <string>
+ Definition: Name for LED trigger. If unspecified, "wled_flash" is used.
+
+- qcom,wled-flash-fsc
+ Usage: optional
+ Value type: <u32>
+ Definition: WLED flash full scale current in mA. This configures the
+ maximum current allowed for flash device. Allowed values
+ are from 5 to 60 mA with a step of 5 mA. If not specified,
+ default value is set to 40 mA.
+
+- qcom,wled-flash-step
+ Usage: optional
+ Value type: <u32>
+ Definition: WLED flash step delay in us. This configures the step delay
+ when the output is ramped up to the desired target current.
+ Allowed values are from 50 to 400 us with a step of 50 us.
+ If not specified, default value is set to 200 us.
+
+- qcom,wled-flash-timer
+ Usage: optional
+ Value type: <u32>
+ Definition: WLED flash safety timer in ms. This configures the safety
+ timer to turn off flash automatically after timer expiry.
+ Allowed values are: 50, 100, 200, 400, 600, 800, 1000 and
+ 1200. If not specified, default value is set to 100 ms.
+
+For wled_switch child subnode,
+
+- label
+ Usage: required
+ Value type: <string>
+ Definition: Should be "switch".
+
+- qcom,default-led-trigger
+ Usage: optional
+ Value type: <string>
+ Definition: Name for LED trigger. If unspecified, "wled_switch" is
+ used.
+
+Example:
+
+qcom-wled@d800 {
+ compatible = "qcom,pmi8998-spmi-wled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xd800 0xd900>;
+ reg-names = "wled-ctrl-base", "wled-sink-base";
+ label = "backlight";
+
+ interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "sc-irq", "ovp-irq";
+ qcom,fs-current-limit = <25000>;
+ qcom,boost-current-limit = <970>;
+ qcom,switching-freq = <800>;
+ qcom,ovp = <29600>;
+ qcom,string-cfg = <15>;
+};
+
+qcom-wled@d800 {
+ compatible = "qcom,pm8150l-spmi-wled";
+ #address-cells = <2>;
+ #size-cells = <0>;
+ reg = <0xd800 0x100>, <0xd900 0x100>;
+ reg-names = "wled-ctrl-base", "wled-sink-base";
+ label = "backlight";
+
+ interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "ovp-irq";
+ qcom,string-cfg = <7>;
+
+ wled_torch: qcom,wled-torch {
+ label = "torch";
+ qcom,wled-torch-fsc = <40>;
+ qcom,wled-torch-step = <300>;
+ qcom,wled-torch-timer = <600>;
+ };
+
+ wled_flash: qcom,wled-flash {
+ label = "flash";
+ qcom,wled-flash-fsc = <60>;
+ qcom,wled-flash-step = <100>;
+ qcom,wled-flash-timer = <200>;
+ };
+
+ wled_switch: qcom,wled-switch {
+ label = "switch";
+ };
+};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
new file mode 100644
index 0000000..8728a1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
@@ -0,0 +1,320 @@
+Qualcomm Technologies Inc. PNP v2 Flash LED
+
+QPNP (Qualcomm Technologies Inc. Plug N Play) Flash LED (Light
+Emitting Diode) driver v2 is used to provide illumination to
+camera sensor when background light is dim to capture good
+picture. It can also be used for flashlight/torch application.
+It is part of PMIC on Qualcomm Technologies Inc. reference platforms.
+
+Main node:
+
+Required properties:
+- compatible : Should be "qcom,qpnp-flash-led-v2"
+- reg : Base address and size for flash LED modules
+- qcom,pmic-revid : phandle of PMIC revid module. This is used to
+ identify the PMIC subtype.
+
+Optional properties:
+- interrupts : Specifies the interrupts associated with flash-led.
+- interrupt-names : Specify the interrupt names associated with interrupts.
+- qcom,hdrm-auto-mode : Boolean type to select headroom auto mode enabled or not
+- qcom,isc-delay-us : Integer type to specify short circuit delay. Valid values are 32, 64,
+ 128, 192. Unit is uS.
+- qcom,warmup-delay-us : Integer type to specify warm up delay. Valid values are 32, 64,
+ 128, 192. Unit is uS.
+- qcom,short-circuit-det : Boolean property which enables short circuit fault detection.
+- qcom,open-circuit-det : Boolean property which enables open circuit fault detection.
+- qcom,vph-droop-det : Boolean property which enables VPH droop detection.
+- qcom,vph-droop-hysteresis-mv : Integer property to specify VPH droop hysteresis. It is only used if
+ qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75.
+ Unit is mV.
+- qcom,vph-droop-threshold-mv : Integer property to specify VPH droop threshold. It is only used if
+ qcom,vph-droop-det is specified. Valid values are
+ 2500 to 3200 with step size of 100. Unit is mV.
+- qcom,vph-droop-debounce-us : Integer property to specify VPH droop debounce time. It is only used
+ if qcom,vph-droop-det is specified. Valid values are 0, 8, 16 and 26.
+ Unit is uS.
+- qcom,led1n2-iclamp-low-ma : Integer property to specify current clamp low
+ level for mitigation. Unit is mA. Allowed
+ values are same as under qcom,max-current.
+- qcom,led1n2-iclamp-mid-ma : Integer property to specify current clamp mid
+ level for mitigation. Unit is mA. Allowed
+ values are same as under qcom,max-current.
+- qcom,led3-iclamp-low-ma : Integer property to specify current clamp low
+ level for mitigation. Unit is mA. Allowed
+ values are same as under qcom,max-current.
+- qcom,led3-iclamp-mid-ma : Integer property to specify current clamp mid
+ level for mitigation. Unit is mA. Allowed
+ values are same as under qcom,max-current.
+- qcom,vled-max-uv : Integer property for flash current predictive mitigation.
+ Default value is 3500000 uV.
+- qcom,ibatt-ocp-threshold-ua : Integer property for flash current predictive mitigation.
+ Default value is 4500000 uA.
+- qcom,rparasitic-uohm : Integer property for flash current predictive mitigation indicating
+ parasitic component of battery resistance. Default value is 0 uOhm.
+- qcom,lmh-ocv-threshold-uv : Required property for flash current preemptive LMH mitigation.
+ Default value is 3700000 uV.
+- qcom,lmh-rbatt-threshold-uohm : Required property for flash current preemptive LMH mitigation.
+ Default value is 400000 uOhm.
+- qcom,lmh-mitigation-sel : Optional property to configure flash current preemptive LMH mitigation.
+ Accepted values are:
+ 0: MITIGATION_DISABLED
+ 1: MITIGATION_BY_ILED_THRESHOLD
+ 2: MITIGATION_BY_SW
+ Default value is 2.
+- qcom,chgr-mitigation-sel : Optional property to configure flash current preemptive charger mitigation.
+ Accepted values are:
+ 0: MITIGATION_DISABLED
+ 1: MITIGATION_BY_ILED_THRESHOLD
+ 2: MITIGATION_BY_SW
+ Default value is 2.
+- qcom,lmh-level : Optional property to configure flash current preemptive LMH mitigation.
+ Accepted values are 0, 1, and 3. Default value is 0.
+- qcom,iled-thrsh-ma : Optional property to configure the led current threshold at which HW
+ preemptive mitigation is triggered. Unit is mA. Default value is 1000.
+ Accepted values are in the range 0 - 3100, with steps of 100.
+ 0 disables autonomous HW mitigation.
+- qcom,thermal-derate-en : Boolean property to enable flash current thermal mitigation.
+- qcom,thermal-derate-current : Array of currrent limits for thermal mitigation. Required if
+ qcom,thermal-derate-en is specified. Unit is mA. Format is
+ qcom,thermal-derate-current = <OTST1_LIMIT, OTST2_LIMIT, OTST3_LIMIT>.
+- qcom,otst-ramp-back-up-dis : Boolean property to disable current ramp
+ backup after thermal derate trigger is
+ deasserted.
+- qcom,thermal-derate-slow : Integer property to specify slow ramping
+ down thermal rate. Unit is in uS. Allowed
+ values are: 128, 256, 512, 1024, 2048, 4096,
+ 8192 and 314592.
+- qcom,thermal-derate-fast : Integer property to specify fast ramping
+ down thermal rate. Unit is in uS. Allowed
+ values are: 32, 64, 96, 128, 256, 384 and
+ 512.
+- qcom,thermal-debounce : Integer property to specify thermal debounce
+ time. It is only used if qcom,thermal-derate-en
+ is specified. Unit is in uS. Allowed values
+ are: 0, 16, 32, 64.
+- qcom,thermal-hysteresis : Integer property to specify thermal derating
+ hysteresis. Unit is in deciDegC. It is only
+ used if qcom,thermal-derate-en is specified.
+ Allowed values are:
+ 0, 15, 30, 45 for pmi8998.
+ 0, 20, 40, 60 for pm660l.
+- qcom,thermal-thrsh1 : Integer property to specify OTST1 threshold
+ for thermal mitigation. Unit is in Celsius.
+ Accepted values are:
+ 85, 79, 73, 67, 109, 103, 97, 91.
+- qcom,thermal-thrsh2 : Integer property to specify OTST2 threshold
+ for thermal mitigation. Unit is in Celsius.
+ Accepted values are:
+ 110, 104, 98, 92, 134, 128, 122, 116.
+- qcom,thermal-thrsh3 : Integer property to specify OTST3 threshold
+ for thermal mitigation. Unit is in Celsius.
+ Accepted values are:
+ 125, 119, 113, 107, 149, 143, 137, 131.
+- qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified
+ value, additional GPIO configuration may be required to provide strobing
+ support. Supported values are:
+ 0: Flash strobe is used for LED1, LED2, LED3
+ 1: Flash strobe is used for LED1, LED2 and GPIO10 is used for LED3
+ 2: Flash strobe is used for LED1; GPIO9 is used for LED2; GPIO10 is used for LED3
+- switchX-supply : phandle of the regulator that needs to be used
+ as a supply for flash switch_X device.
+
+Child node: Contains settings for each individual LED. Each LED channel needs a flash node and
+torch node for itself, and an individual switch node to serve as an overall switch.
+
+Required Properties:
+- label : Type of led that will be used, either "flash", "torch", or "switch.
+- qcom,led-name : Name of the LED.
+- qcom,default-led-trigger : Trigger for the camera flash and torch. Accepted values are
+ "flash0_trigger", "flash1_trigger", "flash2_trigger, "torch0_trigger",
+ "torch1_trigger", "torch2_trigger", and "switch_trigger".
+- qcom,id : ID for each physical LED equipped. In order to handle situation when
+ only 1 or 2 LEDs are installed, flash and torch nodes on LED channel 0
+ should be specified with ID 0; nodes on channel 1 be ID 1, etc. This is
+ not required for switch node.
+- qcom,max-current : Maximum current allowed on this LED. Valid values should be
+ integer from 0 to 1500 inclusive. Flash 2 should have maximum current of
+ 750 per hardware requirement. Unit is mA. For torch, the maximum current
+ is clamped at 500 mA. This is not required for the switch node.
+- qcom,duration-ms : Required property for flash nodes but not needed for torch. Integer
+ type specifying flash duration. Values are from 10ms to 1280ms with
+ 10ms resolution. This is not required for switch node.
+- qcom,led-mask : Required property for switch nodes. Bitmask to indicate which leds are
+ controlled by this switch node. Accepted values are in the range 1 to 7,
+ inclusive. Example:
+ qcom,led-mask = <4>; /* This switch node controls the flash2/torch2 led. */
+
+Optional properties:
+- qcom,current-ma : operational current intensity for LED in mA. Accepted values are a
+ positive integer in the range of 0 to qcom,max-current inclusive.
+- qcom,ires-ua : Integer type to specify current resolution. Accepted values should be
+ 12500, 10000, 7500, and 5000. Unit is uA.
+- qcom,hdrm-voltage-mv : Integer type specifying headroom voltage. Values are from 125mV to 500mV
+ with 25mV resolution. Default setting is 325mV
+- qcom,hdrm-vol-hi-lo-win-mv : Integer type to specify headroom voltage swing range. Values are
+ from 0mV to 375mV with 25mV resolution. Default setting is 100mV.
+- pinctrl-names : Name of the pinctrl configuration that will be used when external GPIOs
+ are used for enabling/disabling, HW strobing of flash LEDs. For more
+ information on using pinctrl, please refer
+ Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt
+ Following are the pinctrl configs that can be specified:
+ "led_enable" : pinctrl config to enable led. This should specify the active
+ configuration defined for each pin or pin group.
+ "led_disable" : pinctrl config to disable led. This should specify the sleep
+ configuration defined for each pin or pin group.
+ "strobe_enable" : pinctrl config to enable hw-strobe. This should specify the
+ active configuration defined for each pin or pin group.
+ "strobe_disable" : pinctrl config to disable hw-strobe. This should specify the
+ sleep configuration defined for each pin or pin group.
+- qcom,hw-strobe-gpio : phandle to specify GPIO for hardware strobing. This is used when there is no
+ pinctrl support or PMIC GPIOs are used.
+- qcom,strobe-sel : Property to select strobe type. If not defined,
+ software strobe will be used. Allowed options are:
+ 0 - SW strobe
+ 1 - HW strobe
+ 2 - LPG strobe
+ LPG strobe is supported only for LED3.
+ If LPG strobe is specified, then strobe control is
+ configured for active high and level triggered. Also
+ qcom,hw-strobe-option should be set to 1 or 2.
+- qcom,hw-strobe-edge-trigger : Boolean property to select trigger type. If defined, hw-strobe is set to
+ be edge triggered. Otherwise, it is level triggered.
+- qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe
+ signal polarity is set to active-low, else it is active-high.
+- qcom,symmetry-en : Boolean property to specify if the flash LEDs under a
+ switch node are controlled symmetrically. This needs
+ to be specified if a group of flash LED channels are
+ connected to a single LED.
+Example:
+ qcom,leds@d300 {
+ compatible = "qcom,qpnp-flash-led-v2";
+ status = "okay";
+ reg = <0xd300 0x100>;
+ label = "flash";
+ interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xd3 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xd3 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xd3 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xd3 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xd3 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xd3 0x6 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xd3 0x7 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "led-fault-irq",
+ "mitigation-irq",
+ "flash-timer-exp-irq",
+ "all-ramp-down-done-irq",
+ "all-ramp-up-done-irq",
+ "led3-ramp-up-done-irq",
+ "led2-ramp-up-done-irq",
+ "led1-ramp-up-done-irq";
+
+ qcom,hdrm-auto-mode;
+ qcom,isc-delay = <192>;
+ switch0-supply = <&pmi8998_bob>;
+
+ pmi8998_flash0: qcom,flash_0 {
+ label = "flash";
+ qcom,led-name = "led:flash_0";
+ qcom,max-current = <1500>;
+ qcom,default-led-trigger =
+ "flash0_trigger";
+ qcom,id = <0>;
+ qcom,current-ma = <1000>;
+ qcom,duration-ms = <1280>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <325>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi8998_flash1: qcom,flash_1 {
+ label = "flash";
+ qcom,led-name = "led:flash_1";
+ qcom,max-current = <1500>;
+ qcom,default-led-trigger =
+ "flash1_trigger";
+ qcom,id = <1>;
+ qcom,current-ma = <1000>;
+ qcom,duration-ms = <1280>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <325>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi8998_flash2: qcom,flash_2 {
+ label = "flash";
+ qcom,led-name = "led:flash_2";
+ qcom,max-current = <750>;
+ qcom,default-led-trigger =
+ "flash2_trigger";
+ qcom,id = <2>;
+ qcom,current-ma = <500>;
+ qcom,duration-ms = <1280>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <325>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ pinctrl-names = "led_enable","led_disable";
+ pinctrl-0 = <&led_enable>;
+ pinctrl-1 = <&led_disable>;
+ };
+
+ pmi8998_torch0: qcom,torch_0 {
+ label = "torch";
+ qcom,led-name = "led:torch_0";
+ qcom,max-current = <500>;
+ qcom,default-led-trigger =
+ "torch0_trigger";
+ qcom,id = <0>;
+ qcom,current-ma = <300>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <325>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi8998_torch1: qcom,torch_1 {
+ label = "torch";
+ qcom,led-name = "led:torch_1";
+ qcom,max-current = <500>;
+ qcom,default-led-trigger =
+ "torch1_trigger";
+ qcom,id = <1>;
+ qcom,current-ma = <300>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <325>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi8998_torch2: qcom,torch_2 {
+ label = "torch";
+ qcom,led-name = "led:torch_2";
+ qcom,max-current = <500>;
+ qcom,default-led-trigger =
+ "torch2_trigger";
+ qcom,id = <2>;
+ qcom,current-ma = <300>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <325>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ pinctrl-names = "led_enable","led_disable";
+ pinctrl-0 = <&led_enable>;
+ pinctrl-1 = <&led_disable>;
+ };
+
+ pmi8998_switch0: qcom,led_switch_0 {
+ label = "switch";
+ qcom,led-name = "led:switch_0";
+ qcom,led-mask = <3>;
+ qcom,default-led-trigger =
+ "switch0_trigger";
+ qcom,symmetry-en;
+ };
+
+ pmi8998_switch1: qcom,led_switch_1 {
+ label = "switch";
+ qcom,led-name = "led:switch_1";
+ qcom,led-mask = <4>;
+ qcom,default-led-trigger =
+ "switch1_trigger";
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt
index 1437062..272e9c0 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt
+++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt
@@ -45,6 +45,8 @@
see:
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
- interrupt-names: Corresponding interrupt name to the interrupts property
+- qcom,can-sleep: Boolean flag indicating that processes waiting on SPMI
+ transactions may sleep
Each child node of SPMI slave id represents a function of the PMIC. In the
example below the rtc device node represents a peripheral of pm8941
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt
new file mode 100644
index 0000000..dd14890
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt
@@ -0,0 +1,19 @@
+QPNP-REVID
+
+QPNP-REVID provides a way to read the PMIC part number and revision.
+
+Required properties:
+- compatible : should be "qcom,qpnp-revid"
+- reg : offset and length of the PMIC peripheral register map.
+
+Optional property:
+- qcom,fab-id-valid: Use this property when support to read Fab
+ identification from REV ID peripheral is available.
+- qcom,tp-rev-valid: Use this property when support to read TP
+ revision identification from REV ID peripheral.
+
+Example:
+ qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
new file mode 100644
index 0000000..4e420fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -0,0 +1,1783 @@
+Qualcomm Technologies, Inc. Audio devices for ALSA sound SoC
+
+* msm-pcm
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+* msm-pcm-low-latency
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+Optional properties:
+
+ - qcom,msm-pcm-low-latency : Flag indicating whether
+ the device node is of type low latency.
+
+ - qcom,latency-level : Flag indicating whether the device node
+ is of type regular low latency or ultra
+ low latency.
+ regular : regular low latency stream
+ ultra : ultra low latency stream
+ ull-pp : ultra low latency stream with post-processing capability
+
+* msm-pcm-dsp-noirq
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp-noirq";
+
+Optional properties:
+
+ - qcom,msm-pcm-low-latency : Flag indicating whether
+ the device node is of type low latency.
+
+ - qcom,latency-level : Flag indicating whether the device node
+ is of type low latency or ultra low latency
+ ultra : ultra low latency stream
+ ull-pp : ultra low latency stream with post-processing capability
+* msm-pcm-routing
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-routing"
+
+* msm-pcm-lpa
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-lpa"
+
+* msm-compr-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-compr-dsp"
+
+* msm-compress-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-compress-dsp"
+
+Optional properties:
+ - qcom,adsp-version:
+ This property can be used to specify the ADSP version/name.
+ Based on ADSP version, we decide if we have to use older
+ ADSP APIs or newer. Right now we are adding "MDSP 1.2" for
+ 8909 purpose. If the ADSP version is anything other than this
+ we use new ADSP APIs.
+
+* msm-voip-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-voip-dsp"
+
+* msm-pcm-voice
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-voice"
+ - qcom,destroy-cvd : Flag indicating whether to destroy cvd at
+ the end of call for low memory targets
+
+* msm-voice-host-pcm
+
+Required properties:
+
+ - compatible : "qcom,msm-voice-host-pcm"
+
+* msm-voice-svc
+
+Required properties:
+
+ - compatible : "qcom,msm-voice-svc"
+
+* msm-stub-codec
+
+Required properties:
+
+ - compatible : "qcom,msm-stub-codec"
+
+* msm-hdmi-dba-codec-rx
+
+Required properties:
+
+ - compatible : "qcom,msm-hdmi-dba-codec-rx"
+ - qcom,dba-bridge-chip: String info to indicate which bridge-chip
+ is used for HDMI using DBA.
+
+* msm-dai-fe
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-fe"
+
+* msm-pcm-afe
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-afe"
+
+* msm-pcm-dtmf
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dtmf"
+ - qcom,msm-pcm-dtmf : Enable DTMF driver in Audio. DTMF driver is
+ used for generation and detection of DTMF tones, when user is in
+ active voice call. APR commands are sent from DTMF driver to ADSP.
+
+* msm-dai-stub
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-stub"
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-stub-dev"
+ - qcom,msm-dai-stub-dev-id : Stub dai port ID value is from 0 to 3.
+ This enables stub CPU dai in Audio. The stub dai is used when
+ there is no real backend in Audio.
+
+* msm-dai-q6-spdif
+
+Optional properties:
+
+ - compatible : "msm-dai-q6-spdif"
+
+* msm-dai-q6-hdmi
+
+Required properties:
+ - compatible : "msm-dai-q6-hdmi"
+ - qcom,msm-dai-q6-dev-id : The hdmi multi channel port ID.
+ It is passed onto the dsp from the apps to form an audio
+ path to the HDMI device. Currently the only supported value
+ is 8, which indicates the rx path used for audio playback
+ on HDMI device.
+
+* msm-lsm-client
+
+Required properties:
+
+ - compatible : "qcom,msm-lsm-client"
+
+* msm-pcm-loopback
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-loopback"
+
+Optional properties:
+
+ - qcom,msm-pcm-loopback-low-latency : Flag indicating whether
+ the device node is of type low latency.
+
+* msm-transcode-loopback
+
+Required properties:
+
+ - compatible : "qcom,msm-transcode-loopback"
+
+* msm-dai-q6
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-q6"
+
+Optional properties:
+
+ - qcom,ext-spk-amp-supply : External speaker amplifier power supply.
+ - qcom,ext-spk-amp-gpio : External speaker amplifier enable signal.
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-dev"
+ - qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID
+ Value is from 16384 to 16397.
+ BT SCO port ID value from 12288 to 12289.
+ RT Proxy port ID values from 224 to 225 and 240 to
+ 241.
+ FM Rx and TX port ID values from 12292 to 12293.
+ incall record Rx and TX port ID values from 32771 to 32772.
+ inCall Music Delivery port ID is 32773.
+ incall Music 2 Delivery port ID is 32770.
+
+* msm_dai_cdc_dma
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-cdc-dma"
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-cdc-dma-dev"
+ - qcom,msm-dai-cdc-dma-dev-id : WSA codec dma port ID
+ Value is from 45056 to 45061.
+ VA codec dma port ID Value is from 45089 to 45091.
+ RX and TX codec dma port ID values from 45120
+ to 45135.
+
+Optional properties:
+
+- qcom,msm-dai-is-island-supported: Defines whether this dai supported in
+ island mode or not.
+ 0 - Unsupported
+ 1 - Supported
+
+* msm-auxpcm
+
+Required properties:
+
+ - compatible : "qcom,msm-auxpcm-dev"
+
+ - qcom,msm-cpudai-auxpcm-mode: mode information. The first value is
+ for 8khz mode, the second is for
+ 16khz
+ 0 - for PCM
+
+ - qcom,msm-cpudai-auxpcm-sync: sync information. The first value is
+ for 8khz mode, the second is for
+ 16khz
+
+ - qcom,msm-cpudai-auxpcm-frame: No.of bytes per frame. The first
+ value is for 8khz mode, the second
+ is for 16khz
+ 5 - 256BPF
+ 4 - 128BPF
+
+ - qcom,msm-cpudai-auxpcm-quant: Type of quantization. The first
+ value is for 8khz mode, the second
+ is for 16khz
+ 2 - Linear quantization
+
+ - qcom,msm-cpudai-auxpcm-num-slots: Number of slots per mode in the
+ msm-cpudai-auxpcm-slot-mapping
+ array.
+ The first value is for 8khz mode, the
+ second is for 16khz. Max number of
+ slots supported by DSP is 4, anything
+ above 4 will be truncated to 4 when
+ sent to DSP.
+
+ - qcom,msm-cpudai-auxpcm-slot-mapping: Array of slot numbers for multi
+ slot scenario. The first array
+ is for 8khz mode, the second is
+ for 16khz. The size of the array
+ is determined by the value in
+ qcom,msm-cpudai-auxpcm-num-slots
+
+ - qcom,msm-cpudai-auxpcm-data: Data field - 0. The first value is
+ for 8khz mode, the second is for
+ 16khz
+
+ - qcom,msm-cpudai-auxpcm-pcm-clk-rate: Clock rate for pcm - 2048000. The
+ first value is for 8khz mode, the
+ second is for 16KHz mode. When clock
+ rate is set to zero, then external
+ clock is assumed.
+
+ - qcom,msm-auxpcm-interface: name of AUXPCM interface "primary"
+ indicates primary AUXPCM interface
+ "secondary" indicates secondary
+ AUXPCM interface
+Optional properties:
+
+- pinctrl-names: Pinctrl state names for each pin
+ group configuration.
+- pinctrl-x: Defines pinctrl state for each pin
+ group
+- qcom,msm-cpudai-afe-clk-ver: Indicates version of AFE clock
+ interface to be used for enabling
+ PCM clock. If not defined, selects
+ default AFE clock interface.
+- qcom,msm-dai-is-island-supported: Defines whether this dai supported in
+ island mode or not.
+ 0 - Unsupported
+ 1 - Supported
+
+* msm-pcm-hostless
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-hostless"
+
+* msm-audio-apr
+
+Required properties:
+
+ - compatible : "qcom,msm-audio-apr"
+ This device is added to represent APR module.
+
+ - qcom,subsys-name: This value provides the subsystem name where codec
+ is present. It can be "apr_modem" or "apr_adsp". This
+ property enable apr driver to receive subsystem up/down
+ notification from modem/adsp.
+
+* msm-ocmem-audio
+
+Required properties:
+
+ - compatible : "qcom,msm-ocmem-audio"
+
+ - qcom,msm_bus,name: Client name
+
+ - qcom,msm_bus,num_cases: Total number of use cases
+
+ - qcom,msm_bus,active_only: Context flag for requests in active
+ or dual (active & sleep) contex
+
+ - qcom,msm_bus,num_paths: Total number of master-slave pairs
+
+ - qcom,msm_bus,vectors: Arrays of unsigned integers
+ representing:
+ master-id, slave-id, arbitrated
+ bandwidth,
+ instantaneous bandwidth
+* wcd9xxx_intc
+
+Required properties:
+
+ - compatible : "qcom,wcd9xxx-irq"
+
+ - interrupt-controller : Mark this device node as an
+ interrupt controller
+
+ - #interrupt-cells : Should be 1
+
+ - interrupt-parent : Parent interrupt controller
+
+ - qcom,gpio-connect Gpio that connects to parent
+ interrupt controller
+
+* audio-ext-clk-up
+
+Required properties:
+
+ - compatible : "qcom,audio-ref-clk"
+
+ - qcom,codec-ext-clk-src: Clock source type like PMIC, LPASS
+ requested to enable reference
+ or external clock.
+
+Optional properties:
+
+ - qcom,codec-lpass-ext-clk-freq: Property used to specify frequency.
+
+ - qcom,codec-lpass-clk-id: Property used to specify LPASS clock
+ ID value.
+
+ - clock-names: Name of the PMIC clock that needs
+ to be enabled for audio ref clock.
+ This clock is set as parent.
+
+ - clocks: phandle reference to the parent
+ clock.
+
+ - qcom,mclk-clk-reg: Indicate the register address for mclk.
+
+ - qcom,use-pinctrl: Indicates pinctrl required or not for this
+ clock node.
+
+* audio_slimslave
+
+Required properties:
+
+ - compatible : "qcom,audio-slimslave"
+
+ - elemental-addr: slimbus slave enumeration address.
+
+* msm-cpe-lsm
+
+Required properties:
+
+ - compatible : "qcom,msm-cpe-lsm"
+ - qcom,msm-cpe-lsm-id : lsm afe port ID. CPE lsm driver uses
+ this property to find out the input afe port ID. Currently
+ only supported values are 1 and 3.
+
+* wcd_us_euro_gpio
+
+Required properties:
+
+ - compatible : "qcom,msm-cdc-pinctrl"
+
+Optional properties:
+ - qcom,lpi-gpios : This boolean property is added if GPIOs are under
+ LPI TLMM.
+
+* msm-dai-slim
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-slim"
+
+ - elemental-addr: slimbus slave enumeration address.
+
+* wcd_gpio_ctrl
+
+Required properties:
+
+ - compatible : "qcom,msm-cdc-pinctrl"
+
+ - qcom,cdc-rst-n-gpio : TLMM GPIO number
+
+ - pinctrl-names: Pinctrl state names for each pin
+ group configuration.
+ - pinctrl-x: Defines pinctrl state for each pin
+ group.
+* msm_cdc_pinctrl
+
+Required properties:
+
+ - compatible : "qcom,msm-cdc-pinctrl"
+
+ - pinctrl-names: Pinctrl state names for each pin
+ group configuration.
+ - pinctrl-x: Defines pinctrl state for each pin
+ group.
+
+* wcd_dsp_glink
+
+Required properties:
+
+ - compatible : "qcom,wcd-dsp-glink"
+ - qcom,wdsp-channels: List of wdsp supported channel names.
+
+* msm_ext_disp_audio_codec_rx
+
+Required properties:
+
+ - compatible : "qcom,msm-ext-disp-audio-codec-rx"
+
+Example:
+
+ qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ };
+
+ qcom,msm-pcm-loopback-low-latency {
+ compatible = "qcom,msm-pcm-loopback";
+ qcom,msm-pcm-loopback-low-latency;
+ };
+
+ qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ qcom,msm-pcm-lpa {
+ compatible = "qcom,msm-pcm-lpa";
+ };
+
+ qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
+ qcom,msm-compress-dsp {
+ compatible = "qcom,msm-compress-dsp";
+ };
+
+ qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ };
+
+ qcom,msm-voice-host-pcm {
+ compatible = "qcom,msm-voice-host-pcm";
+ };
+
+ qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ qcom,msm-pcm-dtmf {
+ compatible = "qcom,msm-pcm-dtmf";
+ };
+
+ qcom,msm-dai-stub {
+ compatible = "qcom,msm-dai-stub";
+ };
+
+ qcom,msm-dai-q6-spdif {
+ compatible = "qcom,msm-dai-q6-spdif";
+ };
+
+ qcom,msm-dai-q6-hdmi {
+ compatible = "qcom,msm-dai-q6-hdmi";
+ qcom,msm-dai-q6-dev-id = <8>;
+ };
+
+ dai_dp: qcom,msm-dai-q6-dp {
+ compatible = "qcom,msm-dai-q6-hdmi";
+ qcom,msm-dai-q6-dev-id = <24608>;
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ qcom,msm-dai-q6-sb-0-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16384>;
+ };
+
+ qcom,msm-dai-q6-sb-0-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16385>;
+ };
+
+ qcom,msm-dai-q6-sb-1-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16386>;
+ };
+
+ qcom,msm-dai-q6-sb-1-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16387>;
+ };
+
+ qcom,msm-dai-q6-sb-3-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16390>;
+ };
+
+ qcom,msm-dai-q6-sb-3-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16391>;
+ };
+
+ qcom,msm-dai-q6-sb-4-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16392>;
+ };
+
+ qcom,msm-dai-q6-sb-4-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16393>;
+ };
+
+ qcom,msm-dai-q6-sb-5-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16395>;
+ };
+
+ qcom,msm-dai-q6-sb-6-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16396>;
+ };
+
+ qcom,msm-dai-q6-sb-6-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16397>;
+ };
+
+ qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+
+ qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
+ };
+
+ qcom,msm-pri-auxpcm {
+ qcom,msm-cpudai-auxpcm-mode = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <4>, <4>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1 0 0 0>, <1 3 0 0>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ compatible = "qcom,msm-auxpcm-dev";
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&pri_aux_pcm_active &pri_aux_pcm_din_active>;
+ pinctrl-1 = <&pri_aux_pcm_sleep &pri_aux_pcm_din_sleep>;
+ };
+
+ qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ audio_apr: qcom,msm-audio-apr {
+ compatible = "qcom,msm-audio-apr";
+ qcom,subsys-name = "apr_adsp";
+ q6core {
+ compatible = "qcom,q6core-audio";
+ bolero: bolero-cdc {
+ compatible = "qcom,bolero-codec";
+ };
+ };
+ };
+
+ qcom,msm-ocmem-audio {
+ compatible = "qcom,msm-ocmem-audio";
+ qcom,msm_bus,name = "audio-ocmem";
+ qcom,msm_bus,num_cases = <2>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <11 604 0 0>,
+ <11 604 32505856 325058560>;
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <72 0>;
+ interrupt-names = "cdc-int";
+ };
+
+ clock_audio: audio_ext_clk {
+ compatible = "qcom,audio-ref-clk";
+ qcom,codec-ext-clk-src = <2>;
+ qcom,codec-lpass-ext-clk-freq = <19200000>;
+ qcom,codec-lpass-clk-id = <1>;
+ clock-names = "osr_clk";
+ clocks = <&clock_rpm clk_div_clk1>;
+ #clock-cells = <1>;
+ pinctrl-names = "sleep", "active";
+ pinctrl-0 = <&spkr_i2s_clk_sleep>;
+ pinctrl-1 = <&spkr_i2s_clk_active>;
+ };
+
+ audio_slimslave {
+ compatible = "qcom,audio-slimslave";
+ elemental-addr = [ff ff ff ff 17 02];
+ };
+
+ msm_dai_slim {
+ compatible = "qcom,msm_dai_slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
+ wcd_gpio_ctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ };
+
+ msm_cdc_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ };
+
+ wcd_dsp_glink {
+ compatible = "qcom,wcd-dsp-glink";
+ };
+
+ msm_ext_disp_audio_codec_rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ };
+
+* msm-dai-mi2s
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-mi2s"
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-mi2s"
+ - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to
+ transfer data to (WCD9XXX) codec.
+ If slimbus interface is used then "msm-dai-q6"
+ needs to be filled with correct data for
+ slimbus interface.
+ The sections "msm-dai-mi2s" is used by MDM or
+ MSM to use I2S interface with codec.
+ This section is used by CPU driver in ASOC MSM
+ to configure MI2S interface. MSM internally
+ has multiple MI2S namely Primary, Secondary,
+ Tertiary and Quaternary MI2S.
+ They are represented with id 0, 1, 2, 3
+ respectively.
+ The field "qcom,msm-dai-q6-mi2s-dev-id"
+ represents which of the MI2S block is used.
+ These MI2S are connected to I2S interface.
+
+ - qcom,msm-mi2s-rx-lines: Each MI2S interface in MSM has one or more SD
+ lines. These lines are used for data transfer
+ between codec and MSM.
+ This element in indicates which output RX lines
+ are used in the MI2S interface.
+
+ - qcom,msm-mi2s-tx-lines: Each MI2S interface in MSM has one or more SD
+ lines. These lines are used for data transfer
+ between codec and MSM.
+ This element in indicates which input TX lines
+ are used in the MI2S interface.
+
+Optional properties:
+
+- pinctrl-names: Pinctrl state names for each pin group
+ configuration.
+- pinctrl-x: Defines pinctrl state for each pin group
+- qcom,msm-dai-is-island-supported: Defines whether this dai supported in
+ island mode or not.
+ 0 - Unsupported
+ 1 - Supported
+
+Example:
+
+qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&tert_mi2s_active &tert_mi2s_sd0_active>;
+ pinctrl-1 = <&tert_mi2s_sleep &tert_mi2s_sd0_sleep>;
+ };
+};
+
+* msm-dai-spdif
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-spdif"
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-spdif"
+ - qcom,msm-dai-q6-dev-id: The SPDIF port ID
+ Value is from 20480 to 20483.
+
+Example:
+
+qcom,msm-dai-spdif {
+ compatible = "qcom,msm-dai-spdif";
+ qcom,msm-dai-q6-spdif-pri-rx {
+ compatible = "qcom,msm-dai-q6-spdif";
+ qcom,msm-dai-q6-dev-id = <20480>;
+ };
+};
+
+* msm-adsp-loader
+
+Required properties:
+ - compatible : "qcom,adsp-loader"
+ - qcom,adsp-state:
+ It is possible that some MSM use PIL to load the ADSP image. While
+ other MSM may use SBL to load the ADSP image at boot. Audio APR needs
+ state of ADSP to register and enable APR to be used for sending commands
+ to ADSP. so adsp-state represents the state of ADSP to ADSP loader.
+ Value of 0 indicates ADSP loader needs to use PIL and value of 2 means
+ ADSP image is already loaded by SBL.
+
+Optional properties:
+ - qcom,proc-img-to-load:
+ This property can be used to override default ADSP
+ loading by PIL. Based on string input, different proc is
+ loaded. Right now we are adding option "modem"
+ for 8916 purpose. Default image will be "adsp" which
+ will load LPASS Q6 for other targets as expected.
+ "adsp" option need not be explicitly mentioned in
+ DTSI file, as it is default option.
+
+Example:
+
+qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <2>;
+ qcom,proc-img-to-load = "modem";
+};
+
+* msm-audio-ion
+
+Required properties:
+ - compatible : "qcom,msm-audio-ion"
+
+Optional properties:
+ - qcom,smmu-version:
+ version ID to provide info regarding smmu version
+ used in chipset. If ARM SMMU HW - use id value as 1,
+ If QSMMU HW - use id value as 2.
+
+ - qcom,smmu-sid-mask:
+ Mask for the Stream ID part of SMMU SID.
+
+ - qcom,smmu-enabled:
+ It is possible that some MSM have SMMU in ADSP. While other MSM use
+ no SMMU. Audio lib introduce wrapper for ION APIs. The wrapper needs
+ presence of SMMU in ADSP to handle ION APIs differently.
+ Presence of this property means ADSP has SMMU in it.
+ - iommus:
+ A phandle parsed by smmu driver. Number of entries will vary across
+ targets.
+
+Example:
+
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion;
+ qcom,smmu-enabled;
+ };
+
+* msm-dai-tdm
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-tdm"
+ - qcom,msm-cpudai-tdm-group-id: ID of the group device. TDM interface
+ supports up to 8 groups:
+ Primary RX: 37120
+ Primary TX: 37121
+ Secondary RX: 37136
+ Secondary TX: 37137
+ Tertiary RX: 37152
+ Tertiary TX: 37153
+ Quaternary RX: 37168
+ Quaternary TX: 37169
+
+ - qcom,msm-cpudai-tdm-group-num-ports: Number of ports in
+ msm-cpudai-tdm-group-port-id array.
+ Max number of ports supported by DSP is 8.
+
+ - qcom,msm-cpudai-tdm-group-port-id: Array of TDM port IDs of the group.
+ The size of the array is determined by
+ the value in msm-cpudai-tdm-group-num-ports.
+ Each group supports up to 8 ports:
+ Primary RX: 36864, 36866, 36868, 36870,
+ 36872, 36874, 36876, 36878
+ Primary TX: 36865, 36867, 36869, 36871,
+ 36873, 36875, 36877, 36879
+ Secondary RX: 36880, 36882, 36884, 36886,
+ 36888, 36890, 36892, 36894
+ Secondary TX: 36881, 36883, 36885, 36887,
+ 36889, 36891, 36893, 36895
+ Tertiary RX: 36896, 36898, 36900, 36902,
+ 36904, 36906, 36908, 36910
+ Tertiary TX: 36897, 36899, 36901, 36903,
+ 36905, 36907, 36909, 36911
+ Quaternary RX: 36912, 36914, 36916, 36918,
+ 36920, 36922, 36924, 36926
+ Quaternary TX: 36913, 36915, 36917, 36919,
+ 36921, 36923, 36925, 36927
+
+ - qcom,msm-cpudai-tdm-clk-rate: Clock rate for tdm - 12288000.
+ When clock rate is set to zero,
+ then external clock is assumed.
+
+ - qcom,msm-cpudai-tdm-clk-internal: Clock Source.
+ 0 - EBIT clock from clk tree
+ 1 - IBIT clock from clk tree
+
+ - qcom,msm-cpudai-tdm-sync-mode: Synchronization setting.
+ 0 - Short sync bit mode
+ 1 - Long sync mode
+ 2 - Short sync slot mode
+
+ - qcom,msm-cpudai-tdm-sync-src: Synchronization source.
+ 0 - External source
+ 1 - Internal source
+
+ - qcom,msm-cpudai-tdm-data-out: Data out signal to drive with other masters.
+ 0 - Disable
+ 1 - Enable
+
+ - qcom,msm-cpudai-tdm-invert-sync: Invert the sync.
+ 0 - Normal
+ 1 - Invert
+
+ - qcom,msm-cpudai-tdm-data-delay: Number of bit clock to delay data
+ with respect to sync edge.
+ 0 - 0 bit clock cycle
+ 1 - 1 bit clock cycle
+ 2 - 2 bit clock cycle
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-tdm"
+ - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID.
+
+ - qcom,msm-cpudai-tdm-data-align: Indicate how data is packed
+ within the slot. For example, 32 slot width in case of
+ sample bit width is 24.
+ 0 - MSB
+ 1 - LSB
+
+Optional properties:
+
+ - qcom,msm-cpudai-tdm-header-start-offset: TDM Custom header start offset
+ in bytes from this sub-frame. The bytes is counted from 0.
+ 0 is mapped to the 1st byte in or out of
+ the digital serial data line this sub-frame belong to.
+ Supported value: 0, 4, 8.
+
+ - qcom,msm-cpudai-tdm-header-width: Header width per frame followed.
+ 2 bytes for MOST/TDM case.
+ Supported value: 2.
+
+ - qcom,msm-cpudai-tdm-header-num-frame-repeat: Number of header followed.
+ Supported value: 8.
+
+ - pinctrl-names: Pinctrl state names for each pin group
+ configuration.
+
+ - pinctrl-x: Defines pinctrl state for each pin group.
+
+ - qcom,msm-dai-is-island-supported: Defines whether this dai supported in
+ island mode or not.
+ 0 - Unsupported
+ 1 - Supported
+
+Example:
+
+ qcom,msm-dai-tdm-quat-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37168>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36912>;
+ qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>;
+ pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>;
+ dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36912>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ qcom,msm-cpudai-tdm-header-start-offset = <0>;
+ qcom,msm-cpudai-tdm-header-width = <2>;
+ qcom,msm-cpudai-tdm-header-num-frame-repeat = <8>;
+ };
+ };
+
+* MSMSTUB ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm8150-asoc-snd-stub" for SM8150 target.
+- qcom,model : The user-visible name of this sound card.
+- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+
+Example:
+
+ sound_stub {
+ compatible = "qcom,sm8150-asoc-snd-stub";
+ qcom,model = "sm8150-stub-snd-card";
+
+ qcom,tasha-mclk-clk-freq = <9600000>;
+ asoc-platform = <&pcm0>;
+ asoc-platform-names = "msm-pcm-dsp.0";
+ asoc-cpu = <&sb_0_rx>, <&sb_0_tx>;
+ asoc-cpu-names = "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <0>;
+ };
+
+* WCD DSP manager driver
+
+Required properties:
+- compatible : "qcom,wcd-dsp-mgr"
+- qcom,wdsp-components : This is phandle list containing the references to the
+ components of the manager driver. Manager driver will
+ register to component framework with these phandles.
+- qcom,img-filename : String property to provide the dsp image file name that is
+ to be read from file system and downloaded to dsp memory
+Optional properties:
+- qcom,wdsp-cmpnt-dev-name : Property that manager driver will parse, but defined
+ in the child's DT entry that is given to manager driver
+ with phandle. This property will be used by the manager
+ driver in case the manager driver cannot match child's
+ of_node pointer to registered phandle.
+
+Example:
+
+ qcom,wcd-dsp-mgr {
+ compatible = "qcom,wcd-dsp-mgr";
+ qcom,wdsp-components = <&wcd934x_cdc 0>,
+ <&wcd_spi_0 1>,
+ <&glink_spi 2>;
+ qcom,img-filename = "cpe_9340";
+ };
+
+Example of child node that would have qcom,wdsp-cmpnt-dev-name property
+
+ wcd934x_cdc: tavil_codec {
+ qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+ };
+
+* msm-mdf
+
+Required properties:
+ - compatible : "qcom,msm-mdf"
+
+Optional subnodes:
+ - qcom,msm_mdf_cb : Child nodes representing the compute context banks.
+
+Subnode Required properties:
+ - compatible : "qcom,msm-mdf-cb"
+ - label: Label describing the subsystem this context bank belongs to.
+
+Subnode Optional properties:
+ - qcom,smmu-enabled:
+ It is possible that some MSM subsystems have SMMU, while other MSM
+ subsystems do not. MDF platform driver needs to handle SMMU APIs
+ differently according to the availability of SMMU.
+ Presence of this property means the subsystem has SMMU in it.
+ - iommus : A list of phandle and IOMMU specifier pairs that describe the
+ IOMMU master interfaces of the device.
+
+Example:
+ qcom,msm-mdf {
+ compatible = "qcom,msm-mdf";
+
+ qcom,msm_mdf_cb1 {
+ compatible = "qcom,msm-mdf-cb";
+ label = "adsp";
+ qcom,smmu-enabled;
+ };
+ qcom,msm_mdf_cb2 {
+ compatible = "qcom,msm-mdf-cb";
+ label = "dsps";
+ };
+ qcom,msm_mdf_cb3 {
+ compatible = "qcom,msm-mdf-cb";
+ label = "modem";
+ };
+ };
+
+* msm-mdf-mem
+
+Required properties:
+ - compatible : "qcom,msm-mdf-mem-region"
+ - qcom,msm-mdf-mem-data-size: indicates the size of memory
+ for MDF purpose
+ - memory-region : CMA region which is owned by this device.
+
+Example:
+ qcom,msm-mdf-mem {
+ compatible = "qcom,msm-mdf-mem-region";
+ memory-region = <&mdf_mem>;
+ };
+
+* SM8150 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm8150-asoc-snd-pahu-aqt" for pahu codec and
+ "qcom,sm8150-asoc-snd-tavil" for tavil codec.
+- qcom,model : The user-visible name of this sound card.
+- qcom,pahu-ext-clk-freq : External CLK frequency value for pahu codec
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+
+Example:
+
+ sound-pahu {
+ compatible = "qcom,sm8150-asoc-snd-pahu-aqt";
+ qcom,model = "sm8150-pahu-aqt-snd-card";
+ qcom,ext-disp-audio-rx;
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+ reg = <0x1711a000 0x4>,
+ <0x1711b000 0x4>,
+ <0x1711c000 0x4>,
+ <0x1711d000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+
+ qcom,audio-routing =
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "AMIC3", "MIC BIAS2",
+ "AMIC4", "MIC BIAS2",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,pahu-ext-clk-freq = <19200000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_hdmi>, <&dai_dp>,
+ <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+ <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+ "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>;
+ asoc-codec-names = "msm-stub-codec.1",
+ "msm-ext-disp-audio-codec-rx";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+
+* QCS405 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,qcs405-asoc-snd".
+- qcom,model : The user-visible name of this sound card.
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+- qcom,wsa_bolero_codec : Property to specify if WSA macro in Bolero codec is used for this target
+- qcom,va_bolero_codec : Property to specify if VA macro in Bolero codec is used for this target
+- qcom,tasha_codec : Property to specify if Tasha codec is used for this target
+- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios.
+- qcom,csra-codec : Property to specify if CSRA66x0 is used for this target
+- qcom,csra-max-devs : Maximum number of CSRA66x0 devices present in the target
+- qcom,csra-devs : List of phandles of all possible CSRA66x0 devices supported for the target
+- qcom,csra-aux-dev-prefix : Name prefix in multi-channel configuration for CSRA66x0 device
+Example:
+
+ qcs405_snd {
+ compatible = "qcom,qcs405-asoc-snd";
+ qcom,wsa_bolero_codec = <1>;
+ qcom,va_bolero_codec = <1>;
+ qcom,tasha_codec = <1>;
+ qcom,ext-disp-audio-rx = <1>;
+ qcom,wcn-btfm = <1>;
+ qcom,mi2s-audio-intf = <1>;
+ qcom,auxpcm-audio-intf = <1>;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+ qcom,audio-routing =
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "AMIC3", "MIC BIAS2",
+ "AMIC4", "MIC BIAS2",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_hdmi>, <&dai_dp>,
+ <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+ <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>,
+ <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>,
+ <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>,
+ <&wsa_cdc_dma_2_tx>, <&va_cdc_dma_0_tx>,
+ <&va_cdc_dma_1_tx>;
+ asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+ "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913",
+ "msm-dai-q6-cdc-dma-dev.45056",
+ "msm-dai-q6-cdc-dma-dev.45057",
+ "msm-dai-q6-cdc-dma-dev.45058",
+ "msm-dai-q6-cdc-dma-dev.45059",
+ "msm-dai-q6-cdc-dma-dev.45061",
+ "msm-dai-q6-cdc-dma-dev.45089",
+ "msm-dai-q6-cdc-dma-dev.45091";
+ asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>,
+ <&bolero>;;
+ asoc-codec-names = "msm-stub-codec.1",
+ "msm-ext-disp-audio-codec-rx",
+ "bolero_codec";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>,
+ <&cdc_dmic56_gpios>, <&cdc_dmic78_gpios>;
+ };
+
+* SM6150 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm6150-asoc-snd".
+- qcom,model : The user-visible name of this sound card.
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+- qcom,codec-aux-devs: This is phandle list containing the references to Auxilary
+ codec devices.
+
+Optional properties:
+- qcom,msm-mi2s-master: This property is used to inform machine driver
+ if MSM is the clock master of mi2s. 1 means master and 0 means slave. The
+ first entry is primary mi2s; the second entry is secondary mi2s, and so on.
+- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL
+ switch type on target typically the switch type will be normally open or
+ normally close, value for this property 0 for normally close and 1 for
+ normally open.
+- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND
+ switch type on target typically the switch type will be normally open or
+ normally close, value for this property 0 for normally close and 1 for
+ normally open.
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+- qcom,ext-disp-audio-rx: Property to specify if Audio over Display port is supported for the target
+- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+- qcom,mi2s-audio-intf: Property to specify if MI2S interface is used for the target
+- qcom,auxpcm-audio-intf: Property to specify if Aux PCM interface is used for the target
+- qcom,tavil_codec : Property to specify if Tavil codec is used for this target
+- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios.
+- qcom,msm_audio_ssr_devs: List the snd event framework clients
+
+Example:
+ sm6150_snd: sound {
+ status = "okay";
+ compatible = "qcom,sm6150-asoc-snd";
+ qcom,ext-disp-audio-rx = <1>;
+ qcom,wcn-btfm = <1>;
+ qcom,mi2s-audio-intf = <1>;
+ qcom,auxpcm-audio-intf = <1>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_dp>,
+ <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_mi2s4>, <&dai_pri_auxpcm>,
+ <&dai_sec_auxpcm>, <&dai_tert_auxpcm>,
+ <&dai_quat_auxpcm>, <&dai_quin_auxpcm>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>,
+ <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>,
+ <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>,
+ <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>,
+ <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>,
+ <&wsa_cdc_dma_2_tx>,
+ <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>,
+ <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>,
+ <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>,
+ <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>,
+ <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>,
+ <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>,
+ <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>,
+ <&tx_cdc_dma_6_tx>, <&tx_cdc_dma_7_tx>;
+ asoc-cpu-names = "msm-dai-q6-dp.24608",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3",
+ "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5",
+ "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16398",
+ "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.16400",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913",
+ "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929",
+ "msm-dai-cdc-dma-dev.45056",
+ "msm-dai-cdc-dma-dev.45057",
+ "msm-dai-cdc-dma-dev.45058",
+ "msm-dai-cdc-dma-dev.45059",
+ "msm-dai-cdc-dma-dev.45061",
+ "msm-dai-cdc-dma-dev.45089",
+ "msm-dai-cdc-dma-dev.45091",
+ "msm-dai-cdc-dma-dev.45120",
+ "msm-dai-cdc-dma-dev.45121",
+ "msm-dai-cdc-dma-dev.45122",
+ "msm-dai-cdc-dma-dev.45123",
+ "msm-dai-cdc-dma-dev.45124",
+ "msm-dai-cdc-dma-dev.45125",
+ "msm-dai-cdc-dma-dev.45126",
+ "msm-dai-cdc-dma-dev.45127",
+ "msm-dai-cdc-dma-dev.45128",
+ "msm-dai-cdc-dma-dev.45129",
+ "msm-dai-cdc-dma-dev.45130",
+ "msm-dai-cdc-dma-dev.45131",
+ "msm-dai-cdc-dma-dev.45133",
+ "msm-dai-cdc-dma-dev.45135";
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>;
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>;
+ asoc-codec = <&stub_codec>, <&bolero>,
+ <&ext_disp_audio_codec>;
+ asoc-codec-names = "msm-stub-codec.1", "bolero-codec",
+ "msm-ext-disp-audio-codec-rx";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ qcom,codec-aux-devs = <&wcd937x_codec>;
+ qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>;
+ };
+};
+
+* MSMSTUB ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm6150-asoc-snd-stub" for SM6150 target.
+- qcom,model : The user-visible name of this sound card.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+
+Example:
+
+ sound_stub {
+ compatible = "qcom,sm6150-asoc-snd-stub";
+ qcom,model = "sm6150-stub-snd-card";
+
+ asoc-platform = <&pcm0>;
+ asoc-platform-names = "msm-pcm-dsp.0";
+ asoc-cpu = <&sb_0_rx>, <&sb_0_tx>;
+ asoc-cpu-names = "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <0>;
+ };
+
+* SA8155 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sa8155-asoc-snd-auto" for auto adp codec and
+ "qcom,sa8155-asoc-snd-auto-custom" for auto custom codec.
+- qcom,model : The user-visible name of this sound card.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,mi2s-audio-intf : Property to specify if MI2S interface is used for the target
+- qcom,auxpcm-audio-intf : Property to specify if AUX PCM interface is used for the target
+- qcom,msm-mi2s-master : List of master/slave configuration for MI2S interfaces
+
+Example:
+
+ sound-adp-star {
+ compatible = "qcom,sa8155-asoc-snd-adp-star";
+ qcom,model = "sa8155-adp-star-snd-card";
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&pcm_noirq>, <&loopback1>, <&pcm_dtmf>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-dsp-noirq", "msm-pcm-loopback.1",
+ "msm-pcm-dtmf";
+ asoc-cpu = <&dai_hdmi>, <&dai_dp>,
+ <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_mi2s4>, <&dai_pri_auxpcm>,
+ <&dai_sec_auxpcm>, <&dai_tert_auxpcm>,
+ <&dai_quat_auxpcm>, <&dai_quin_auxpcm>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>,
+ <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>,
+ <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>,
+ <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>,
+ <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>,
+ <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>,
+ <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
+ <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
+ <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>,
+ <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>,
+ <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>,
+ <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>,
+ <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>,
+ <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>,
+ <&dai_quat_tdm_tx_3>, <&dai_quin_tdm_rx_0>,
+ <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>,
+ <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>,
+ <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>,
+ <&dai_quin_tdm_tx_3>;
+ asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3",
+ "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866",
+ "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867",
+ "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882",
+ "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883",
+ "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
+ "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
+ "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901",
+ "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912",
+ "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916",
+ "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913",
+ "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917",
+ "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36928",
+ "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932",
+ "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929",
+ "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933",
+ "msm-dai-q6-tdm.36935";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ };
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt
new file mode 100644
index 0000000..51c748e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt
@@ -0,0 +1,63 @@
+Qualcomm Technologies, Inc. SPMI Debug Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on various QTI chips. It is an SPMI controller
+with wrapping arbitration logic to allow for multiple on-chip devices to control
+a single SPMI master.
+
+The PMIC Arbiter debug bus is present starting at arbiter version 5. It has
+read and write access to all PMIC peripherals regardless of ownership
+configurations. It cannot be used on production devices because it is disabled
+by an eFuse.
+
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+Supported Properties:
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must be "qcom,spmi-pmic-arb-debug".
+
+- reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: List of address and size pairs. The address of the PMIC
+ arbiter module is required. The address of the debug bus
+ disabling fuse is optional.
+
+- reg-names
+ Usage: required
+ Value type: <stringlist>
+ Definition: Address names. Must include "core" for the PMIC arbiter
+ module and may include "fuse" for the debug bus disabling
+ fuse. The strings must be specified in the same order as
+ the corresponding addresses are specified in the reg
+ property.
+
+- #address-cells
+ Usage: required
+ Value type: <u32>
+ Definition: Must be 2.
+
+- #size-cells
+ Usage: required
+ Value type: <u32>
+ Definition: Must be 0.
+
+- qcom,fuse-disable-bit
+ Usage: required if "fuse" is listed in reg-names property
+ Value type: <u32>
+ Definition: The bit within the fuse register which is set when the debug
+ bus is not available. Supported values are 0 to 31.
+
+Example:
+
+qcom,spmi-debug@6b22000 {
+ compatible = "qcom,spmi-pmic-arb-debug";
+ reg = <0x6b22000 0x60>, <0x7820a8 4>;
+ reg-names = "core", "fuse";
+ qcom,fuse-disable-bit = <12>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+};
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index a48baf2..8c8d2bb 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -51,6 +51,7 @@
- nr_trim_pages (only if CONFIG_MMU=n)
- numa_zonelist_order
- oom_dump_tasks
+- reap_mem_on_sigkill
- oom_kill_allocating_task
- overcommit_kbytes
- overcommit_memory
@@ -654,6 +655,24 @@
==============================================================
+reap_mem_on_sigkill
+
+This enables or disables the memory reaping for a SIGKILL received
+process and that the sending process must have the CAP_KILL capabilities.
+
+If this is set to 1, when a process receives SIGKILL from a process
+that has the capability, CAP_KILL, the process is added into the oom_reaper
+queue which can be picked up by the oom_reaper thread to reap the memory of
+that process. This reaps for the process which received SIGKILL through
+either sys_kill from user or kill_pid from kernel.
+
+If this is set to 0, we are not reaping memory of a SIGKILL, sent through
+either sys_kill from user or kill_pid from kernel, received process.
+
+The default value is 0 (disabled).
+
+==============================================================
+
oom_kill_allocating_task
This enables or disables killing the OOM-triggering task in
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 95571b8..334d136 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -7,11 +7,24 @@
dtb-$(CONFIG_ARCH_QCOM) += msm8994-angler-rev-101.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-mtp.dtb
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+ dtbo-$(CONFIG_ARCH_KONA) += \
+ kona-cdp-overlay.dtbo \
+ kona-mtp-overlay.dtbo \
+ kona-rumi-overlay.dtbo \
+ kona-qrd-overlay.dtbo
+
+kona-cdp-overlay.dtbo-base := kona.dtb
+kona-mtp-overlay.dtbo-base := kona.dtb
+kona-rumi-overlay.dtbo-base := kona.dtb
+kona-qrd-overlay.dtbo-base := kona.dtb
+else
dtb-$(CONFIG_ARCH_KONA) += kona-rumi.dtb \
kona-mtp.dtb \
kona-cdp.dtb \
kona-qrd.dtb
+endif
always := $(dtb-y)
subdir-y := $(dts-dirs)
-clean-files := *.dtb
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/qcom/kona-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/kona-cdp-overlay.dts
new file mode 100644
index 0000000..6f46ce5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-cdp-overlay.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-cdp.dtsi"
+
+/ {
+ model = "CDP";
+ compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp";
+ qcom,board-id = <1 0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/kona-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/kona-mtp-overlay.dts
new file mode 100644
index 0000000..7f40af2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-mtp-overlay.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-mtp.dtsi"
+
+/ {
+ model = "MTP";
+ compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp";
+ qcom,board-id = <8 0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/kona-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/kona-qrd-overlay.dts
new file mode 100644
index 0000000..231e5ef
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-qrd-overlay.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-qrd.dtsi"
+
+/ {
+ model = "QRD";
+ compatible = "qcom,kona-qrd", "qcom,kona", "qcom,qrd";
+ qcom,board-id = <11 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/kona-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/kona-rumi-overlay.dts
new file mode 100644
index 0000000..51e012b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-rumi-overlay.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-rumi.dtsi"
+
+/ {
+ model = "RUMI";
+ compatible = "qcom,kona-rumi", "qcom,kona", "qcom,rumi";
+ qcom,board-id = <15 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/kona-usb.dtsi b/arch/arm64/boot/dts/qcom/kona-usb.dtsi
index 81089fe..0cf2e09 100644
--- a/arch/arm64/boot/dts/qcom/kona-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/kona-usb.dtsi
@@ -13,6 +13,7 @@
reg-names = "core_base";
iommus = <&apps_smmu 0x0 0x0>;
+ qcom,iommu-dma = "disabled";
#address-cells = <1>;
#size-cells = <1>;
ranges;
diff --git a/arch/arm64/boot/dts/qcom/kona.dts b/arch/arm64/boot/dts/qcom/kona.dts
new file mode 100644
index 0000000..2a02297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include "kona.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. kona v1 SoC";
+ compatible = "qcom,kona";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/kona.dtsi b/arch/arm64/boot/dts/qcom/kona.dtsi
index 9c5df6b..d839397 100644
--- a/arch/arm64/boot/dts/qcom/kona.dtsi
+++ b/arch/arm64/boot/dts/qcom/kona.dtsi
@@ -268,7 +268,7 @@
xbl_aop_mem: xbl_aop_region@80700000 {
no-map;
- reg = <0x0 0x80700000 0x0 0x140000>;
+ reg = <0x0 0x80700000 0x0 0x120000>;
};
cmd_db: reserved-memory@80820000 {
@@ -322,46 +322,46 @@
reg = <0x0 0x86615000 0x0 0x2000>;
};
- pil_npu_mem: pil_npu_region@86680000 {
- compatible = "removed-dma-pool";
- no-map;
- reg = <0x0 0x86680000 0x0 0x80000>;
- };
-
- pil_video_mem: pil_video_region@86700000 {
+ pil_npu_mem: pil_npu_region@86700000 {
compatible = "removed-dma-pool";
no-map;
reg = <0x0 0x86700000 0x0 0x500000>;
};
- pil_cvp_mem: pil_cvp_region@86c00000 {
+ pil_video_mem: pil_video_region@86c00000 {
compatible = "removed-dma-pool";
no-map;
reg = <0x0 0x86c00000 0x0 0x500000>;
};
- pil_cdsp_mem: pil_cdsp_region@87100000 {
+ pil_cvp_mem: pil_cvp_region@87100000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x0 0x87100000 0x0 0x800000>;
+ reg = <0x0 0x87100000 0x0 0x500000>;
};
- pil_slpi_mem: pil_slpi_region@87900000 {
+ pil_cdsp_mem: pil_cdsp_region@87600000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x0 0x87900000 0x0 0x1400000>;
+ reg = <0x0 0x87600000 0x0 0x800000>;
};
- pil_adsp_mem: pil_adsp_region@88d00000 {
+ pil_slpi_mem: pil_slpi_region@87e00000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x0 0x88d00000 0x0 0x1a00000>;
+ reg = <0x0 0x87e00000 0x0 0x1500000>;
};
- pil_spss_mem: pil_spss_region@8a700000 {
+ pil_adsp_mem: pil_adsp_region@89300000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x0 0x8a700000 0x0 0x100000>;
+ reg = <0x0 0x89300000 0x0 0x1900000>;
+ };
+
+ pil_spss_mem: pil_spss_region@8ac00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x8ac00000 0x0 0x100000>;
};
/* global autoconfigured region for contiguous allocations */
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
new file mode 100644
index 0000000..6b29c10
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -0,0 +1,628 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+&soc {
+ pcm0: qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ routing: qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ compr: qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
+ pcm1: qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "regular";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ pcm_noirq: qcom,msm-pcm-dsp-noirq {
+ compatible = "qcom,msm-pcm-dsp-noirq";
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ trans_loopback: qcom,msm-transcode-loopback {
+ compatible = "qcom,msm-transcode-loopback";
+ };
+
+ compress: qcom,msm-compress-dsp {
+ compatible = "qcom,msm-compress-dsp";
+ };
+
+ voip: qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ voice: qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ };
+
+ stub_codec: qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ afe: qcom,msm-pcm-afe {
+ compatible = "qcom,msm-pcm-afe";
+ };
+
+ dai_hdmi: qcom,msm-dai-q6-hdmi {
+ compatible = "qcom,msm-dai-q6-hdmi";
+ qcom,msm-dai-q6-dev-id = <8>;
+ };
+
+ dai_dp: qcom,msm-dai-q6-dp {
+ compatible = "qcom,msm-dai-q6-hdmi";
+ qcom,msm-dai-q6-dev-id = <24608>;
+ };
+
+ loopback: qcom,msm-pcm-loopback {
+ compatible = "qcom,msm-pcm-loopback";
+ };
+
+ loopback1: qcom,msm-pcm-loopback-low-latency {
+ compatible = "qcom,msm-pcm-loopback";
+ qcom,msm-pcm-loopback-low-latency;
+ };
+
+ pcm_dtmf: qcom,msm-pcm-dtmf {
+ compatible = "qcom,msm-pcm-dtmf";
+ };
+
+ msm_dai_mi2s: qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s1: qcom,msm-dai-q6-mi2s-sec {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <1>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s2: qcom,msm-dai-q6-mi2s-tert {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <2>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <3>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s4: qcom,msm-dai-q6-mi2s-quin {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <4>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s5: qcom,msm-dai-q6-mi2s-senary {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <6>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+ };
+
+ msm_dai_cdc_dma: qcom,msm-dai-cdc-dma {
+ compatible = "qcom,msm-dai-cdc-dma";
+ wsa_cdc_dma_0_rx: qcom,msm-dai-wsa-cdc-dma-0-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45056>;
+ };
+
+ wsa_cdc_dma_0_tx: qcom,msm-dai-wsa-cdc-dma-0-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45057>;
+ };
+
+ wsa_cdc_dma_1_rx: qcom,msm-dai-wsa-cdc-dma-1-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45058>;
+ };
+
+ wsa_cdc_dma_1_tx: qcom,msm-dai-wsa-cdc-dma-1-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45059>;
+ };
+
+ wsa_cdc_dma_2_tx: qcom,msm-dai-wsa-cdc-dma-2-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45061>;
+ };
+
+ va_cdc_dma_0_tx: qcom,msm-dai-va-cdc-dma-0-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45089>;
+ };
+
+ va_cdc_dma_1_tx: qcom,msm-dai-va-cdc-dma-1-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45091>;
+ };
+
+ rx_cdc_dma_0_rx: qcom,msm-dai-rx-cdc-dma-0-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45104>;
+ };
+
+ rx_cdc_dma_1_rx: qcom,msm-dai-rx-cdc-dma-1-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45106>;
+ };
+
+ rx_cdc_dma_2_rx: qcom,msm-dai-rx-cdc-dma-2-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45108>;
+ };
+
+ rx_cdc_dma_3_rx: qcom,msm-dai-rx-cdc-dma-3-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45110>;
+ };
+
+ rx_cdc_dma_4_rx: qcom,msm-dai-rx-cdc-dma-4-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45112>;
+ };
+
+ rx_cdc_dma_5_rx: qcom,msm-dai-rx-cdc-dma-5-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45114>;
+ };
+
+ rx_cdc_dma_6_rx: qcom,msm-dai-rx-cdc-dma-6-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45116>;
+ };
+
+ rx_cdc_dma_7_rx: qcom,msm-dai-rx-cdc-dma-7-rx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45118>;
+ };
+
+ tx_cdc_dma_0_tx: qcom,msm-dai-tx-cdc-dma-0-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45105>;
+ };
+
+ tx_cdc_dma_1_tx: qcom,msm-dai-tx-cdc-dma-1-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45107>;
+ };
+
+ tx_cdc_dma_2_tx: qcom,msm-dai-tx-cdc-dma-2-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45109>;
+ };
+
+ tx_cdc_dma_3_tx: qcom,msm-dai-tx-cdc-dma-3-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45111>;
+ };
+
+ tx_cdc_dma_4_tx: qcom,msm-dai-tx-cdc-dma-4-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45113>;
+ };
+
+ tx_cdc_dma_5_tx: qcom,msm-dai-tx-cdc-dma-5-tx {
+ compatible = "qcom,msm-dai-cdc-dma-dev";
+ qcom,msm-dai-cdc-dma-dev-id = <45115>;
+ };
+ };
+
+ lsm: qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ int_fm_rx: qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ int_fm_tx: qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
+ afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+
+ incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
+
+ usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28672>;
+ };
+
+ usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28673>;
+ };
+ };
+
+ hostless: qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ audio_apr: qcom,msm-audio-apr {
+ compatible = "qcom,msm-audio-apr";
+ qcom,subsys-name = "apr_adsp";
+
+ msm_audio_ion: qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ qcom,smmu-version = <2>;
+ qcom,smmu-enabled;
+ iommus = <&apps_smmu 0x1801 0x0>;
+ };
+ };
+
+ dai_pri_auxpcm: qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_sec_auxpcm: qcom,msm-sec-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "secondary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_tert_auxpcm: qcom,msm-tert-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "tertiary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_quat_auxpcm: qcom,msm-quat-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "quaternary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_quin_auxpcm: qcom,msm-quin-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "quinary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ hdmi_dba: qcom,msm-hdmi-dba-codec-rx {
+ compatible = "qcom,msm-hdmi-dba-codec-rx";
+ qcom,dba-bridge-chip = "adv7533";
+ };
+
+ qcom,msm-adsp-loader {
+ status = "ok";
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ };
+
+ tdm_pri_rx: qcom,msm-dai-tdm-pri-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37120>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36864>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36864>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_pri_tx: qcom,msm-dai-tdm-pri-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37121>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36865>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36865>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_sec_rx: qcom,msm-dai-tdm-sec-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37136>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36880>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36880>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_sec_tx: qcom,msm-dai-tdm-sec-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37137>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36881>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36881>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_tert_rx: qcom,msm-dai-tdm-tert-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37152>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36896>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_tert_tx: qcom,msm-dai-tdm-tert-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37153>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36897 >;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36897 >;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_quat_rx: qcom,msm-dai-tdm-quat-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37168>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36912>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36912>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_quat_tx: qcom,msm-dai-tdm-quat-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37169>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36913 >;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36913 >;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_quin_rx: qcom,msm-dai-tdm-quin-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37184>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36928>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36928>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ tdm_quin_tx: qcom,msm-dai-tdm-quin-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37185>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36929>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36929>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ dai_pri_spdif_rx: qcom,msm-dai-q6-spdif-pri-rx {
+ compatible = "qcom,msm-dai-q6-spdif";
+ qcom,msm-dai-q6-dev-id = <20480>;
+ };
+
+ dai_pri_spdif_tx: qcom,msm-dai-q6-spdif-pri-tx {
+ compatible = "qcom,msm-dai-q6-spdif";
+ qcom,msm-dai-q6-dev-id = <20481>;
+ };
+
+ dai_sec_spdif_rx: qcom,msm-dai-q6-spdif-sec-rx {
+ compatible = "qcom,msm-dai-q6-spdif";
+ qcom,msm-dai-q6-dev-id = <20482>;
+ };
+
+ dai_sec_spdif_tx: qcom,msm-dai-q6-spdif-sec-tx {
+ compatible = "qcom,msm-dai-q6-spdif";
+ qcom,msm-dai-q6-dev-id = <20483>;
+ };
+};
diff --git a/arch/arm64/configs/vendor/kona-perf_defconfig b/arch/arm64/configs/vendor/kona-perf_defconfig
index e18cfd6..64da0f1 100644
--- a/arch/arm64/configs/vendor/kona-perf_defconfig
+++ b/arch/arm64/configs/vendor/kona-perf_defconfig
@@ -358,6 +358,8 @@
CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000
CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
CONFIG_MSM_PIL_SSR_GENERIC=y
diff --git a/arch/arm64/configs/vendor/kona_defconfig b/arch/arm64/configs/vendor/kona_defconfig
index f799b6e..46084bde 100644
--- a/arch/arm64/configs/vendor/kona_defconfig
+++ b/arch/arm64/configs/vendor/kona_defconfig
@@ -370,6 +370,8 @@
CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000
CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
CONFIG_MSM_PIL_SSR_GENERIC=y
diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h
index 59f2bd8..d922cd7 100644
--- a/arch/arm64/include/asm/dma-iommu.h
+++ b/arch/arm64/include/asm/dma-iommu.h
@@ -32,34 +32,37 @@
#ifdef CONFIG_ARM64_DMA_USE_IOMMU
struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size);
+__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
+ size_t size);
-void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
+void __depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
-int arm_iommu_attach_device(struct device *dev,
+int __depr_arm_iommu_attach_device(struct device *dev,
struct dma_iommu_mapping *mapping);
-void arm_iommu_detach_device(struct device *dev);
+void __depr_arm_iommu_detach_device(struct device *dev);
void arm_iommu_put_dma_cookie(struct iommu_domain *domain);
#else /* !CONFIG_ARM64_DMA_USE_IOMMU */
static inline struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
+__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
+ size_t size)
{
return NULL;
}
-static inline void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+static inline void
+__depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
}
-static inline int arm_iommu_attach_device(struct device *dev,
+static inline int __depr_arm_iommu_attach_device(struct device *dev,
struct dma_iommu_mapping *mapping)
{
return -ENODEV;
}
-static inline void arm_iommu_detach_device(struct device *dev)
+static inline void __depr_arm_iommu_detach_device(struct device *dev)
{
}
diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h
index dd95d33..03a6c256 100644
--- a/arch/arm64/include/asm/string.h
+++ b/arch/arm64/include/asm/string.h
@@ -16,6 +16,7 @@
#ifndef __ASM_STRING_H
#define __ASM_STRING_H
+#ifndef CONFIG_KASAN
#define __HAVE_ARCH_STRRCHR
extern char *strrchr(const char *, int c);
@@ -34,6 +35,13 @@
#define __HAVE_ARCH_STRNLEN
extern __kernel_size_t strnlen(const char *, __kernel_size_t);
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, size_t);
+
+#define __HAVE_ARCH_MEMCHR
+extern void *memchr(const void *, int, __kernel_size_t);
+#endif
+
#define __HAVE_ARCH_MEMCPY
extern void *memcpy(void *, const void *, __kernel_size_t);
extern void *__memcpy(void *, const void *, __kernel_size_t);
@@ -42,16 +50,10 @@
extern void *memmove(void *, const void *, __kernel_size_t);
extern void *__memmove(void *, const void *, __kernel_size_t);
-#define __HAVE_ARCH_MEMCHR
-extern void *memchr(const void *, int, __kernel_size_t);
-
#define __HAVE_ARCH_MEMSET
extern void *memset(void *, int, __kernel_size_t);
extern void *__memset(void *, int, __kernel_size_t);
-#define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void *, const void *, size_t);
-
#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
#define __HAVE_ARCH_MEMCPY_FLUSHCACHE
void memcpy_flushcache(void *dst, const void *src, size_t cnt);
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index 4d37e51..71f776d 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -45,20 +45,23 @@
EXPORT_SYMBOL(memstart_addr);
/* string / mem functions */
+#ifndef CONFIG_KASAN
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memchr);
+#endif
+
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memmove);
-EXPORT_SYMBOL(memchr);
-EXPORT_SYMBOL(memcmp);
/* atomic bitops */
EXPORT_SYMBOL(set_bit);
diff --git a/arch/arm64/lib/memchr.S b/arch/arm64/lib/memchr.S
index 4444c1d..0f164a4 100644
--- a/arch/arm64/lib/memchr.S
+++ b/arch/arm64/lib/memchr.S
@@ -30,7 +30,7 @@
* Returns:
* x0 - address of first occurrence of 'c' or 0
*/
-ENTRY(memchr)
+WEAK(memchr)
and w1, w1, #0xff
1: subs x2, x2, #1
b.mi 2f
diff --git a/arch/arm64/lib/memcmp.S b/arch/arm64/lib/memcmp.S
index 2a4e239..fb295f5 100644
--- a/arch/arm64/lib/memcmp.S
+++ b/arch/arm64/lib/memcmp.S
@@ -58,7 +58,7 @@
limit_wd .req x12
mask .req x13
-ENTRY(memcmp)
+WEAK(memcmp)
cbz limit, .Lret0
eor tmp1, src1, src2
tst tmp1, #7
diff --git a/arch/arm64/lib/strchr.S b/arch/arm64/lib/strchr.S
index dae0cf5..7c83091 100644
--- a/arch/arm64/lib/strchr.S
+++ b/arch/arm64/lib/strchr.S
@@ -29,7 +29,7 @@
* Returns:
* x0 - address of first occurrence of 'c' or 0
*/
-ENTRY(strchr)
+WEAK(strchr)
and w1, w1, #0xff
1: ldrb w2, [x0], #1
cmp w2, w1
diff --git a/arch/arm64/lib/strcmp.S b/arch/arm64/lib/strcmp.S
index 471fe61..7d5d153 100644
--- a/arch/arm64/lib/strcmp.S
+++ b/arch/arm64/lib/strcmp.S
@@ -60,7 +60,7 @@
zeroones .req x10
pos .req x11
-ENTRY(strcmp)
+WEAK(strcmp)
eor tmp1, src1, src2
mov zeroones, #REP8_01
tst tmp1, #7
diff --git a/arch/arm64/lib/strlen.S b/arch/arm64/lib/strlen.S
index 55ccc8e..8e0b142 100644
--- a/arch/arm64/lib/strlen.S
+++ b/arch/arm64/lib/strlen.S
@@ -56,7 +56,7 @@
#define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080
-ENTRY(strlen)
+WEAK(strlen)
mov zeroones, #REP8_01
bic src, srcin, #15
ands tmp1, srcin, #15
diff --git a/arch/arm64/lib/strncmp.S b/arch/arm64/lib/strncmp.S
index e267044..66bd1459 100644
--- a/arch/arm64/lib/strncmp.S
+++ b/arch/arm64/lib/strncmp.S
@@ -64,7 +64,7 @@
mask .req x14
endloop .req x15
-ENTRY(strncmp)
+WEAK(strncmp)
cbz limit, .Lret0
eor tmp1, src1, src2
mov zeroones, #REP8_01
diff --git a/arch/arm64/lib/strnlen.S b/arch/arm64/lib/strnlen.S
index eae38da..355be04 100644
--- a/arch/arm64/lib/strnlen.S
+++ b/arch/arm64/lib/strnlen.S
@@ -59,7 +59,7 @@
#define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080
-ENTRY(strnlen)
+WEAK(strnlen)
cbz limit, .Lhit_limit
mov zeroones, #REP8_01
bic src, srcin, #15
diff --git a/arch/arm64/lib/strrchr.S b/arch/arm64/lib/strrchr.S
index f8e2784..ea84924 100644
--- a/arch/arm64/lib/strrchr.S
+++ b/arch/arm64/lib/strrchr.S
@@ -29,7 +29,7 @@
* Returns:
* x0 - address of last occurrence of 'c' or 0
*/
-ENTRY(strrchr)
+WEAK(strrchr)
mov x3, #0
and w1, w1, #0xff
1: ldrb w2, [x0], #1
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index ce6528b..beb4a2e 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1057,7 +1057,7 @@
iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
if (s1_bypass)
- mapping->ops = &swiotlb_dma_ops;
+ mapping->ops = &arm64_swiotlb_dma_ops;
else if (is_fast)
err = fast_smmu_init_mapping(dev, mapping);
else
@@ -1158,7 +1158,8 @@
* to calling arm_iommu_attach_device() to complete initialization.
*/
struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
+__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
+ size_t size)
{
unsigned int bits = size >> PAGE_SHIFT;
struct dma_iommu_mapping *mapping;
@@ -1184,7 +1185,7 @@
kfree(mapping);
return ERR_PTR(-ENOMEM);
}
-EXPORT_SYMBOL(arm_iommu_create_mapping);
+EXPORT_SYMBOL(__depr_arm_iommu_create_mapping);
/*
* DEPRECATED
@@ -1194,7 +1195,7 @@
* Frees all resources associated with the iommu mapping.
* The device associated with this mapping must be in the 'detached' state
*/
-void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+void __depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
if (!mapping)
return;
@@ -1204,7 +1205,7 @@
kfree(mapping);
}
-EXPORT_SYMBOL(arm_iommu_release_mapping);
+EXPORT_SYMBOL(__depr_arm_iommu_release_mapping);
/**
* DEPRECATED
@@ -1219,7 +1220,7 @@
*
* Only configures dma_ops for a single device in the iommu_group.
*/
-int arm_iommu_attach_device(struct device *dev,
+int __depr_arm_iommu_attach_device(struct device *dev,
struct dma_iommu_mapping *mapping)
{
int err;
@@ -1265,7 +1266,7 @@
pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
return 0;
}
-EXPORT_SYMBOL(arm_iommu_attach_device);
+EXPORT_SYMBOL(__depr_arm_iommu_attach_device);
/**
* DEPRECATED
@@ -1275,7 +1276,7 @@
* Detaches the provided device from a previously attached map.
* This voids the dma operations (dma_map_ops pointer)
*/
-void arm_iommu_detach_device(struct device *dev)
+void __depr_arm_iommu_detach_device(struct device *dev)
{
struct iommu_domain *domain;
int s1_bypass = 0;
@@ -1307,7 +1308,7 @@
pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
}
-EXPORT_SYMBOL(arm_iommu_detach_device);
+EXPORT_SYMBOL(__depr_arm_iommu_detach_device);
#else /*!CONFIG_ARM64_DMA_USE_IOMMU */
diff --git a/crypto/ahash.c b/crypto/ahash.c
index a64c143..78aaf21 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -550,8 +550,8 @@
{
struct crypto_alg *base = &alg->halg.base;
- if (alg->halg.digestsize > PAGE_SIZE / 8 ||
- alg->halg.statesize > PAGE_SIZE / 8 ||
+ if (alg->halg.digestsize > HASH_MAX_DIGESTSIZE ||
+ alg->halg.statesize > HASH_MAX_STATESIZE ||
alg->halg.statesize == 0)
return -EINVAL;
diff --git a/crypto/algapi.c b/crypto/algapi.c
index c0755cf..496fc51 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -57,9 +57,14 @@
if (alg->cra_alignmask & (alg->cra_alignmask + 1))
return -EINVAL;
- if (alg->cra_blocksize > PAGE_SIZE / 8)
+ /* General maximums for all algs. */
+ if (alg->cra_alignmask > MAX_ALGAPI_ALIGNMASK)
return -EINVAL;
+ if (alg->cra_blocksize > MAX_ALGAPI_BLOCKSIZE)
+ return -EINVAL;
+
+ /* Lower maximums for specific alg types. */
if (!alg->cra_type && (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
CRYPTO_ALG_TYPE_CIPHER) {
if (alg->cra_alignmask > MAX_CIPHER_ALIGNMASK)
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index c40a8c7..eb100a0 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -42,7 +42,7 @@
struct aead_tfm {
struct crypto_aead *aead;
- struct crypto_skcipher *null_tfm;
+ struct crypto_sync_skcipher *null_tfm;
};
static inline bool aead_sufficient_data(struct sock *sk)
@@ -75,13 +75,13 @@
return af_alg_sendmsg(sock, msg, size, ivsize);
}
-static int crypto_aead_copy_sgl(struct crypto_skcipher *null_tfm,
+static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm,
struct scatterlist *src,
struct scatterlist *dst, unsigned int len)
{
- SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
- skcipher_request_set_tfm(skreq, null_tfm);
+ skcipher_request_set_sync_tfm(skreq, null_tfm);
skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_BACKLOG,
NULL, NULL);
skcipher_request_set_crypt(skreq, src, dst, len, NULL);
@@ -99,7 +99,7 @@
struct af_alg_ctx *ctx = ask->private;
struct aead_tfm *aeadc = pask->private;
struct crypto_aead *tfm = aeadc->aead;
- struct crypto_skcipher *null_tfm = aeadc->null_tfm;
+ struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm;
unsigned int i, as = crypto_aead_authsize(tfm);
struct af_alg_async_req *areq;
struct af_alg_tsgl *tsgl, *tmp;
@@ -478,7 +478,7 @@
{
struct aead_tfm *tfm;
struct crypto_aead *aead;
- struct crypto_skcipher *null_tfm;
+ struct crypto_sync_skcipher *null_tfm;
tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
if (!tfm)
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index bfcf595..d0cde54 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -239,7 +239,7 @@
struct alg_sock *ask = alg_sk(sk);
struct hash_ctx *ctx = ask->private;
struct ahash_request *req = &ctx->req;
- char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req)) ? : 1];
+ char state[HASH_MAX_STATESIZE];
struct sock *sk2;
struct alg_sock *ask2;
struct hash_ctx *ctx2;
diff --git a/crypto/authenc.c b/crypto/authenc.c
index 4fa8d40..37f54d1 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -33,7 +33,7 @@
struct crypto_authenc_ctx {
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
- struct crypto_skcipher *null;
+ struct crypto_sync_skcipher *null;
};
struct authenc_request_ctx {
@@ -185,9 +185,9 @@
{
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
- SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
- skcipher_request_set_tfm(skreq, ctx->null);
+ skcipher_request_set_sync_tfm(skreq, ctx->null);
skcipher_request_set_callback(skreq, aead_request_flags(req),
NULL, NULL);
skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen,
@@ -318,7 +318,7 @@
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
- struct crypto_skcipher *null;
+ struct crypto_sync_skcipher *null;
int err;
auth = crypto_spawn_ahash(&ictx->auth);
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index 50b8047..80a25cc 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -36,7 +36,7 @@
unsigned int reqoff;
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
- struct crypto_skcipher *null;
+ struct crypto_sync_skcipher *null;
};
struct authenc_esn_request_ctx {
@@ -183,9 +183,9 @@
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
- SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
- skcipher_request_set_tfm(skreq, ctx->null);
+ skcipher_request_set_sync_tfm(skreq, ctx->null);
skcipher_request_set_callback(skreq, aead_request_flags(req),
NULL, NULL);
skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL);
@@ -341,7 +341,7 @@
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
- struct crypto_skcipher *null;
+ struct crypto_sync_skcipher *null;
int err;
auth = crypto_spawn_ahash(&ictx->auth);
diff --git a/crypto/ccm.c b/crypto/ccm.c
index 0a08334..b242fd0 100644
--- a/crypto/ccm.c
+++ b/crypto/ccm.c
@@ -50,7 +50,10 @@
u32 flags;
struct scatterlist src[3];
struct scatterlist dst[3];
- struct skcipher_request skreq;
+ union {
+ struct ahash_request ahreq;
+ struct skcipher_request skreq;
+ };
};
struct cbcmac_tfm_ctx {
@@ -181,7 +184,7 @@
struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
- AHASH_REQUEST_ON_STACK(ahreq, ctx->mac);
+ struct ahash_request *ahreq = &pctx->ahreq;
unsigned int assoclen = req->assoclen;
struct scatterlist sg[3];
u8 *odata = pctx->odata;
@@ -427,7 +430,7 @@
crypto_aead_set_reqsize(
tfm,
align + sizeof(struct crypto_ccm_req_priv_ctx) +
- crypto_skcipher_reqsize(ctr));
+ max(crypto_ahash_reqsize(mac), crypto_skcipher_reqsize(ctr)));
return 0;
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index addca7b..7118fb5e 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -76,7 +76,7 @@
struct cryptd_skcipher_ctx {
atomic_t refcnt;
- struct crypto_skcipher *child;
+ struct crypto_sync_skcipher *child;
};
struct cryptd_skcipher_request_ctx {
@@ -449,14 +449,16 @@
const u8 *key, unsigned int keylen)
{
struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(parent);
- struct crypto_skcipher *child = ctx->child;
+ struct crypto_sync_skcipher *child = ctx->child;
int err;
- crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
- crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) &
+ crypto_sync_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_sync_skcipher_set_flags(child,
+ crypto_skcipher_get_flags(parent) &
CRYPTO_TFM_REQ_MASK);
- err = crypto_skcipher_setkey(child, key, keylen);
- crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) &
+ err = crypto_sync_skcipher_setkey(child, key, keylen);
+ crypto_skcipher_set_flags(parent,
+ crypto_sync_skcipher_get_flags(child) &
CRYPTO_TFM_RES_MASK);
return err;
}
@@ -483,13 +485,13 @@
struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req);
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
- struct crypto_skcipher *child = ctx->child;
- SKCIPHER_REQUEST_ON_STACK(subreq, child);
+ struct crypto_sync_skcipher *child = ctx->child;
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child);
if (unlikely(err == -EINPROGRESS))
goto out;
- skcipher_request_set_tfm(subreq, child);
+ skcipher_request_set_sync_tfm(subreq, child);
skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
@@ -511,13 +513,13 @@
struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req);
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
- struct crypto_skcipher *child = ctx->child;
- SKCIPHER_REQUEST_ON_STACK(subreq, child);
+ struct crypto_sync_skcipher *child = ctx->child;
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child);
if (unlikely(err == -EINPROGRESS))
goto out;
- skcipher_request_set_tfm(subreq, child);
+ skcipher_request_set_sync_tfm(subreq, child);
skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
@@ -568,7 +570,7 @@
if (IS_ERR(cipher))
return PTR_ERR(cipher);
- ctx->child = cipher;
+ ctx->child = (struct crypto_sync_skcipher *)cipher;
crypto_skcipher_set_reqsize(
tfm, sizeof(struct cryptd_skcipher_request_ctx));
return 0;
@@ -578,7 +580,7 @@
{
struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
- crypto_free_skcipher(ctx->child);
+ crypto_free_sync_skcipher(ctx->child);
}
static void cryptd_skcipher_free(struct skcipher_instance *inst)
@@ -1243,7 +1245,7 @@
{
struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(&tfm->base);
- return ctx->child;
+ return &ctx->child->base;
}
EXPORT_SYMBOL_GPL(cryptd_skcipher_child);
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
index 0959b26..0bae599 100644
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -26,7 +26,7 @@
#include <linux/string.h>
static DEFINE_MUTEX(crypto_default_null_skcipher_lock);
-static struct crypto_skcipher *crypto_default_null_skcipher;
+static struct crypto_sync_skcipher *crypto_default_null_skcipher;
static int crypto_default_null_skcipher_refcnt;
static int null_compress(struct crypto_tfm *tfm, const u8 *src,
@@ -152,16 +152,15 @@
MODULE_ALIAS_CRYPTO("digest_null");
MODULE_ALIAS_CRYPTO("cipher_null");
-struct crypto_skcipher *crypto_get_default_null_skcipher(void)
+struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void)
{
- struct crypto_skcipher *tfm;
+ struct crypto_sync_skcipher *tfm;
mutex_lock(&crypto_default_null_skcipher_lock);
tfm = crypto_default_null_skcipher;
if (!tfm) {
- tfm = crypto_alloc_skcipher("ecb(cipher_null)",
- 0, CRYPTO_ALG_ASYNC);
+ tfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0);
if (IS_ERR(tfm))
goto unlock;
@@ -181,7 +180,7 @@
{
mutex_lock(&crypto_default_null_skcipher_lock);
if (!--crypto_default_null_skcipher_refcnt) {
- crypto_free_skcipher(crypto_default_null_skcipher);
+ crypto_free_sync_skcipher(crypto_default_null_skcipher);
crypto_default_null_skcipher = NULL;
}
mutex_unlock(&crypto_default_null_skcipher_lock);
diff --git a/crypto/echainiv.c b/crypto/echainiv.c
index 45819e6..77e607f 100644
--- a/crypto/echainiv.c
+++ b/crypto/echainiv.c
@@ -47,9 +47,9 @@
info = req->iv;
if (req->src != req->dst) {
- SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
- skcipher_request_set_tfm(nreq, ctx->sknull);
+ skcipher_request_set_sync_tfm(nreq, ctx->sknull);
skcipher_request_set_callback(nreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(nreq, req->src, req->dst,
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 0ad879e..e438492 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -50,7 +50,7 @@
struct crypto_rfc4543_ctx {
struct crypto_aead *child;
- struct crypto_skcipher *null;
+ struct crypto_sync_skcipher *null;
u8 nonce[4];
};
@@ -1067,9 +1067,9 @@
unsigned int authsize = crypto_aead_authsize(aead);
unsigned int nbytes = req->assoclen + req->cryptlen -
(enc ? 0 : authsize);
- SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null);
- skcipher_request_set_tfm(nreq, ctx->null);
+ skcipher_request_set_sync_tfm(nreq, ctx->null);
skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL);
skcipher_request_set_crypt(nreq, req->src, req->dst, nbytes, NULL);
@@ -1093,7 +1093,7 @@
struct crypto_aead_spawn *spawn = &ictx->aead;
struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_aead *aead;
- struct crypto_skcipher *null;
+ struct crypto_sync_skcipher *null;
unsigned long align;
int err = 0;
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index 39dbf2f..64a412b 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -73,9 +73,9 @@
info = req->iv;
if (req->src != req->dst) {
- SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
- skcipher_request_set_tfm(nreq, ctx->sknull);
+ skcipher_request_set_sync_tfm(nreq, ctx->sknull);
skcipher_request_set_callback(nreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(nreq, req->src, req->dst,
diff --git a/crypto/shash.c b/crypto/shash.c
index 5d732c6..d21f04d 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -73,13 +73,6 @@
}
EXPORT_SYMBOL_GPL(crypto_shash_setkey);
-static inline unsigned int shash_align_buffer_size(unsigned len,
- unsigned long mask)
-{
- typedef u8 __aligned_largest u8_aligned;
- return len + (mask & ~(__alignof__(u8_aligned) - 1));
-}
-
static int shash_update_unaligned(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
@@ -88,11 +81,17 @@
unsigned long alignmask = crypto_shash_alignmask(tfm);
unsigned int unaligned_len = alignmask + 1 -
((unsigned long)data & alignmask);
- u8 ubuf[shash_align_buffer_size(unaligned_len, alignmask)]
- __aligned_largest;
+ /*
+ * We cannot count on __aligned() working for large values:
+ * https://patchwork.kernel.org/patch/9507697/
+ */
+ u8 ubuf[MAX_ALGAPI_ALIGNMASK * 2];
u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
int err;
+ if (WARN_ON(buf + unaligned_len > ubuf + sizeof(ubuf)))
+ return -EINVAL;
+
if (unaligned_len > len)
unaligned_len = len;
@@ -124,11 +123,17 @@
unsigned long alignmask = crypto_shash_alignmask(tfm);
struct shash_alg *shash = crypto_shash_alg(tfm);
unsigned int ds = crypto_shash_digestsize(tfm);
- u8 ubuf[shash_align_buffer_size(ds, alignmask)]
- __aligned_largest;
+ /*
+ * We cannot count on __aligned() working for large values:
+ * https://patchwork.kernel.org/patch/9507697/
+ */
+ u8 ubuf[MAX_ALGAPI_ALIGNMASK + HASH_MAX_DIGESTSIZE];
u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
int err;
+ if (WARN_ON(buf + ds > ubuf + sizeof(ubuf)))
+ return -EINVAL;
+
err = shash->final(desc, buf);
if (err)
goto out;
@@ -458,9 +463,9 @@
{
struct crypto_alg *base = &alg->base;
- if (alg->digestsize > PAGE_SIZE / 8 ||
- alg->descsize > PAGE_SIZE / 8 ||
- alg->statesize > PAGE_SIZE / 8)
+ if (alg->digestsize > HASH_MAX_DIGESTSIZE ||
+ alg->descsize > HASH_MAX_DESCSIZE ||
+ alg->statesize > HASH_MAX_STATESIZE)
return -EINVAL;
base->cra_type = &crypto_shash_type;
diff --git a/crypto/skcipher.c b/crypto/skcipher.c
index 0bd8c6c..4caab81 100644
--- a/crypto/skcipher.c
+++ b/crypto/skcipher.c
@@ -949,6 +949,30 @@
}
EXPORT_SYMBOL_GPL(crypto_alloc_skcipher);
+struct crypto_sync_skcipher *crypto_alloc_sync_skcipher(
+ const char *alg_name, u32 type, u32 mask)
+{
+ struct crypto_skcipher *tfm;
+
+ /* Only sync algorithms allowed. */
+ mask |= CRYPTO_ALG_ASYNC;
+
+ tfm = crypto_alloc_tfm(alg_name, &crypto_skcipher_type2, type, mask);
+
+ /*
+ * Make sure we do not allocate something that might get used with
+ * an on-stack request: check the request size.
+ */
+ if (!IS_ERR(tfm) && WARN_ON(crypto_skcipher_reqsize(tfm) >
+ MAX_SYNC_SKCIPHER_REQSIZE)) {
+ crypto_free_skcipher(tfm);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return (struct crypto_sync_skcipher *)tfm;
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_sync_skcipher);
+
int crypto_has_skcipher2(const char *alg_name, u32 type, u32 mask)
{
return crypto_type_has_alg(alg_name, &crypto_skcipher_type2,
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 25c75af..c055f57f 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -57,15 +57,17 @@
u8 ctx[];
};
+#define XCBC_BLOCKSIZE 16
+
static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
const u8 *inkey, unsigned int keylen)
{
unsigned long alignmask = crypto_shash_alignmask(parent);
struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent);
- int bs = crypto_shash_blocksize(parent);
u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
int err = 0;
- u8 key1[bs];
+ u8 key1[XCBC_BLOCKSIZE];
+ int bs = sizeof(key1);
if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen)))
return err;
@@ -212,7 +214,7 @@
return PTR_ERR(alg);
switch(alg->cra_blocksize) {
- case 16:
+ case XCBC_BLOCKSIZE:
break;
default:
goto out_put_alg;
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 2dedbc2..15cb8e6 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -52,6 +52,8 @@
#define CNTFRQ 0x10
#define CNTP_TVAL 0x28
#define CNTP_CTL 0x2c
+#define CNTCVAL_LO 0x30
+#define CNTCVAL_HI 0x34
#define CNTV_TVAL 0x38
#define CNTV_CTL 0x3c
@@ -902,6 +904,23 @@
return cpumask_test_cpu(raw_smp_processor_id(), &evtstrm_available);
}
+void arch_timer_mem_get_cval(u32 *lo, u32 *hi)
+{
+ u32 ctrl;
+
+ *lo = *hi = ~0U;
+
+ if (!arch_counter_base)
+ return;
+
+ ctrl = readl_relaxed_no_log(arch_counter_base + CNTV_CTL);
+
+ if (ctrl & ARCH_TIMER_CTRL_ENABLE) {
+ *lo = readl_relaxed_no_log(arch_counter_base + CNTCVAL_LO);
+ *hi = readl_relaxed_no_log(arch_counter_base + CNTCVAL_HI);
+ }
+}
+
static u64 arch_counter_get_cntvct_mem(void)
{
u32 vct_lo, vct_hi, tmp_hi;
diff --git a/drivers/crypto/qce/ablkcipher.c b/drivers/crypto/qce/ablkcipher.c
index ea4d96b..585e1ca 100644
--- a/drivers/crypto/qce/ablkcipher.c
+++ b/drivers/crypto/qce/ablkcipher.c
@@ -189,7 +189,7 @@
memcpy(ctx->enc_key, key, keylen);
return 0;
fallback:
- ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
if (!ret)
ctx->enc_keylen = keylen;
return ret;
@@ -212,9 +212,9 @@
if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
ctx->enc_keylen != AES_KEYSIZE_256) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -245,9 +245,8 @@
memset(ctx, 0, sizeof(*ctx));
tfm->crt_ablkcipher.reqsize = sizeof(struct qce_cipher_reqctx);
- ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(tfm), 0,
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK);
+ ctx->fallback = crypto_alloc_sync_skcipher(crypto_tfm_alg_name(tfm),
+ 0, CRYPTO_ALG_NEED_FALLBACK);
return PTR_ERR_OR_ZERO(ctx->fallback);
}
@@ -255,7 +254,7 @@
{
struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
}
struct qce_ablkcipher_def {
diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h
index 2b0278b..ee055bf 100644
--- a/drivers/crypto/qce/cipher.h
+++ b/drivers/crypto/qce/cipher.h
@@ -22,7 +22,7 @@
struct qce_cipher_ctx {
u8 enc_key[QCE_MAX_KEY_SIZE];
unsigned int enc_keylen;
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
};
/**
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index c80ec1d..0863996 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -397,29 +397,26 @@
return ret;
}
-static int psci_suspend_finisher(unsigned long index)
+static int psci_suspend_finisher(unsigned long state_id)
{
- u32 *state = __this_cpu_read(psci_power_state);
-
- return psci_ops.cpu_suspend(state[index - 1],
+ return psci_ops.cpu_suspend(state_id,
__pa_symbol(cpu_resume));
}
-
-int psci_cpu_suspend_enter(unsigned long index)
+int psci_cpu_suspend_enter(unsigned long state_id)
{
int ret;
- u32 *state = __this_cpu_read(psci_power_state);
+
/*
* idle state index 0 corresponds to wfi, should never be called
* from the cpu_suspend operations
*/
- if (WARN_ON_ONCE(!index))
+ if (WARN_ON_ONCE(!state_id))
return -EINVAL;
- if (!psci_power_state_loses_context(state[index - 1]))
- ret = psci_ops.cpu_suspend(state[index - 1], 0);
+ if (!psci_power_state_loses_context(state_id))
+ ret = psci_ops.cpu_suspend(state_id, 0);
else
- ret = cpu_suspend(index, psci_suspend_finisher);
+ ret = cpu_suspend(state_id, psci_suspend_finisher);
return ret;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 70ea28f..9bc9757 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1787,7 +1787,9 @@
set_bit(SDE_INTF_INPUT_CTRL, &intf->features);
if (IS_SDE_MAJOR_SAME((sde_cfg->hwversion),
- SDE_HW_VER_500))
+ SDE_HW_VER_500) ||
+ IS_SDE_MAJOR_SAME((sde_cfg->hwversion),
+ SDE_HW_VER_600))
set_bit(SDE_INTF_TE, &intf->features);
}
@@ -3633,6 +3635,8 @@
sde_cfg->sui_misr_supported = true;
sde_cfg->sui_block_xin_mask = 0x3F71;
sde_cfg->has_3d_merge_reset = true;
+ clear_bit(MDSS_INTR_AD4_0_INTR, sde_cfg->mdss_irqs);
+ clear_bit(MDSS_INTR_AD4_1_INTR, sde_cfg->mdss_irqs);
} else {
SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
sde_cfg->perf.min_prefill_lines = 0xffff;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 89622b7..c278777 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -2251,7 +2251,7 @@
dev = sde_kms->dev;
/* iterate state object for active secure/non-secure crtc */
- for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
+ for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
if (!crtc_state->active)
continue;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 344e1fd..a093237 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -457,7 +457,7 @@
if (!of_property_read_bool(node, "iommus"))
return 0;
- drvdata->iommu_mapping = arm_iommu_create_mapping(&amba_bustype,
+ drvdata->iommu_mapping = __depr_arm_iommu_create_mapping(&amba_bustype,
0, (SZ_1G * 4ULL));
if (IS_ERR_OR_NULL(drvdata->iommu_mapping)) {
dev_err(drvdata->dev, "Create mapping failed, err = %d\n", ret);
@@ -474,7 +474,8 @@
goto iommu_attach_fail;
}
- ret = arm_iommu_attach_device(drvdata->dev, drvdata->iommu_mapping);
+ ret = __depr_arm_iommu_attach_device(drvdata->dev,
+ drvdata->iommu_mapping);
if (ret) {
dev_err(drvdata->dev, "Attach device failed, err = %d\n", ret);
goto iommu_attach_fail;
@@ -483,7 +484,7 @@
return ret;
iommu_attach_fail:
- arm_iommu_release_mapping(drvdata->iommu_mapping);
+ __depr_arm_iommu_release_mapping(drvdata->iommu_mapping);
iommu_map_err:
drvdata->iommu_mapping = NULL;
return ret;
@@ -494,8 +495,8 @@
if (!drvdata->iommu_mapping)
return;
- arm_iommu_detach_device(drvdata->dev);
- arm_iommu_release_mapping(drvdata->iommu_mapping);
+ __depr_arm_iommu_detach_device(drvdata->dev);
+ __depr_arm_iommu_release_mapping(drvdata->iommu_mapping);
drvdata->iommu_mapping = NULL;
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 40bb47a..bf151f6 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -243,7 +243,6 @@
#define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
#define ARM_SMMU_OPT_FATAL_ASF (1 << 1)
#define ARM_SMMU_OPT_SKIP_INIT (1 << 2)
-#define ARM_SMMU_OPT_DYNAMIC (1 << 3)
#define ARM_SMMU_OPT_3LVL_TABLES (1 << 4)
#define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5)
#define ARM_SMMU_OPT_STATIC_CB (1 << 6)
@@ -383,7 +382,6 @@
{ ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" },
{ ARM_SMMU_OPT_FATAL_ASF, "qcom,fatal-asf" },
{ ARM_SMMU_OPT_SKIP_INIT, "qcom,skip-init" },
- { ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
{ ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" },
{ ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"},
@@ -425,6 +423,10 @@
unsigned long iova,
struct scatterlist *sg,
unsigned int nents, int prot);
+static int arm_smmu_setup_default_domain(struct device *dev,
+ struct iommu_domain *domain);
+static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
+ enum iommu_attr attr, void *data);
static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
@@ -1703,6 +1705,15 @@
if (smmu_domain->smmu)
goto out_unlock;
+ if (domain->type == IOMMU_DOMAIN_DMA) {
+ ret = arm_smmu_setup_default_domain(dev, domain);
+ if (ret) {
+ dev_err(dev, "%s: default domain setup failed\n",
+ __func__);
+ goto out_unlock;
+ }
+ }
+
if (domain->type == IOMMU_DOMAIN_IDENTITY) {
smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS;
smmu_domain->smmu = smmu;
@@ -1711,13 +1722,6 @@
}
dynamic = is_dynamic_domain(domain);
- if (dynamic && !(smmu->options & ARM_SMMU_OPT_DYNAMIC)) {
- dev_err(smmu->dev, "dynamic domains not supported\n");
- ret = -EPERM;
-
- goto out_unlock;
- }
-
/*
* Mapping the requested stage onto what we support is surprisingly
* complicated, mainly because the spec allows S1+S2 SMMUs without
@@ -2015,9 +2019,9 @@
{
struct arm_smmu_domain *smmu_domain;
- /* Do not support DOMAIN_DMA for now */
if (type != IOMMU_DOMAIN_UNMANAGED &&
- type != IOMMU_DOMAIN_IDENTITY)
+ type != IOMMU_DOMAIN_IDENTITY &&
+ type != IOMMU_DOMAIN_DMA)
return NULL;
/*
* Allocate the domain and initialise some of its data structures.
@@ -2028,12 +2032,6 @@
if (!smmu_domain)
return NULL;
- if (type == IOMMU_DOMAIN_DMA && (using_legacy_binding ||
- iommu_get_dma_cookie(&smmu_domain->domain))) {
- kfree(smmu_domain);
- return NULL;
- }
-
mutex_init(&smmu_domain->init_mutex);
spin_lock_init(&smmu_domain->cb_lock);
spin_lock_init(&smmu_domain->sync_lock);
@@ -2520,6 +2518,157 @@
}
}
+static struct device_node *arm_iommu_get_of_node(struct device *dev)
+{
+ struct device_node *np;
+
+ if (!dev->of_node)
+ return NULL;
+
+ np = of_parse_phandle(dev->of_node, "qcom,iommu-group", 0);
+ return np ? np : dev->of_node;
+}
+
+static int arm_smmu_setup_default_domain(struct device *dev,
+ struct iommu_domain *domain)
+{
+ struct device_node *np;
+ int ret;
+ const char *str;
+ int attr = 1;
+ u32 val;
+
+ np = arm_iommu_get_of_node(dev);
+ if (!np)
+ return 0;
+
+ ret = of_property_read_string(np, "qcom,iommu-dma", &str);
+ if (ret)
+ str = "default";
+
+ if (!strcmp(str, "bypass"))
+ __arm_smmu_domain_set_attr(
+ domain, DOMAIN_ATTR_S1_BYPASS, &attr);
+ else if (!strcmp(str, "fastmap"))
+ __arm_smmu_domain_set_attr(
+ domain, DOMAIN_ATTR_FAST, &attr);
+ else if (!strcmp(str, "atomic"))
+ __arm_smmu_domain_set_attr(
+ domain, DOMAIN_ATTR_ATOMIC, &attr);
+ else if (!strcmp(str, "disabled")) {
+ /*
+ * Don't touch hw, and don't allocate irqs or other resources.
+ * Ensure the context bank is set to a valid value per dynamic
+ * attr requirement.
+ */
+ __arm_smmu_domain_set_attr(
+ domain, DOMAIN_ATTR_DYNAMIC, &attr);
+ val = 0;
+ __arm_smmu_domain_set_attr(
+ domain, DOMAIN_ATTR_CONTEXT_BANK, &val);
+ }
+
+ /*
+ * default value:
+ * Stall-on-fault
+ * faults trigger kernel panic
+ * return abort
+ */
+ if (of_property_match_string(np, "qcom,iommu-faults",
+ "stall-disable") >= 0)
+ __arm_smmu_domain_set_attr(domain,
+ DOMAIN_ATTR_CB_STALL_DISABLE, &attr);
+
+ if (of_property_match_string(np, "qcom,iommu-faults", "non-fatal") >= 0)
+ __arm_smmu_domain_set_attr(domain,
+ DOMAIN_ATTR_NON_FATAL_FAULTS, &attr);
+
+ if (of_property_match_string(np, "qcom,iommu-faults", "no-CFRE") >= 0)
+ __arm_smmu_domain_set_attr(
+ domain, DOMAIN_ATTR_NO_CFRE, &attr);
+
+ /* Default value: disabled */
+ ret = of_property_read_u32(np, "qcom,iommu-vmid", &val);
+ if (!ret) {
+ __arm_smmu_domain_set_attr(
+ domain, DOMAIN_ATTR_SECURE_VMID, &val);
+ }
+
+ /* Default value: disabled */
+ ret = of_property_read_string(np, "qcom,iommu-pagetable", &str);
+ if (ret)
+ str = "disabled";
+ if (!strcmp(str, "coherent"))
+ __arm_smmu_domain_set_attr(domain,
+ DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT, &attr);
+ else if (!strcmp(str, "LLC"))
+ __arm_smmu_domain_set_attr(domain,
+ DOMAIN_ATTR_USE_UPSTREAM_HINT, &attr);
+ else if (!strcmp(str, "LLC_NWA"))
+ __arm_smmu_domain_set_attr(domain,
+ DOMAIN_ATTR_USE_LLC_NWA, &attr);
+
+
+ /* Default value: disabled */
+ if (of_property_read_bool(np, "qcom,iommu-earlymap"))
+ __arm_smmu_domain_set_attr(domain,
+ DOMAIN_ATTR_EARLY_MAP, &attr);
+ return 0;
+}
+
+struct lookup_iommu_group_data {
+ struct device_node *np;
+ struct iommu_group *group;
+};
+
+/* This isn't a "fast lookup" since its N^2, but probably good enough */
+static int __bus_lookup_iommu_group(struct device *dev, void *priv)
+{
+ struct lookup_iommu_group_data *data = priv;
+ struct device_node *np;
+ struct iommu_group *group;
+
+ group = iommu_group_get(dev);
+ if (!group)
+ return 0;
+
+ np = of_parse_phandle(dev->of_node, "qcom,iommu-group", 0);
+ if (np != data->np) {
+ iommu_group_put(group);
+ return 0;
+ }
+
+ data->group = group;
+ iommu_group_put(group);
+ return 1;
+}
+
+static struct iommu_group *of_get_device_group(struct device *dev)
+{
+ struct lookup_iommu_group_data data = {0};
+ struct iommu_group *group;
+ int ret;
+
+ data.np = of_parse_phandle(dev->of_node, "qcom,iommu-group", 0);
+ if (!data.np)
+ return NULL;
+
+ ret = bus_for_each_dev(&platform_bus_type, NULL, &data,
+ __bus_lookup_iommu_group);
+ if (ret > 0)
+ return data.group;
+
+ ret = bus_for_each_dev(&pci_bus_type, NULL, &data,
+ __bus_lookup_iommu_group);
+ if (ret > 0)
+ return data.group;
+
+ group = generic_device_group(dev);
+ if (IS_ERR(group))
+ return NULL;
+ return group;
+}
+
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret;
@@ -3040,12 +3189,17 @@
struct iommu_group *group = NULL;
int i, idx;
+ group = of_get_device_group(dev);
for_each_cfg_sme(fwspec, i, idx) {
if (group && smmu->s2crs[idx].group &&
- group != smmu->s2crs[idx].group)
+ group != smmu->s2crs[idx].group) {
+ dev_err(dev, "ID:%x IDX:%x is already in a group!\n",
+ fwspec->ids[i], idx);
return ERR_PTR(-EINVAL);
+ }
- group = smmu->s2crs[idx].group;
+ if (!group)
+ group = smmu->s2crs[idx].group;
}
if (group)
@@ -3074,9 +3228,6 @@
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
int ret = 0;
- if (domain->type != IOMMU_DOMAIN_UNMANAGED)
- return -EINVAL;
-
mutex_lock(&smmu_domain->init_mutex);
switch (attr) {
case DOMAIN_ATTR_NESTING:
@@ -3216,22 +3367,19 @@
return ret;
}
-static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
+static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
+ enum iommu_attr attr, void *data);
+static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
enum iommu_attr attr, void *data)
{
int ret = 0;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- if (domain->type != IOMMU_DOMAIN_UNMANAGED)
- return -EINVAL;
-
- mutex_lock(&smmu_domain->init_mutex);
-
switch (attr) {
case DOMAIN_ATTR_NESTING:
if (smmu_domain->smmu) {
ret = -EPERM;
- goto out_unlock;
+ goto out;
}
if (*(int *)data)
@@ -3347,6 +3495,21 @@
}
ret = 0;
break;
+ default:
+ ret = __arm_smmu_domain_set_attr2(domain, attr, data);
+ }
+out:
+ return ret;
+}
+
+/* yeee-haw */
+static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
+ enum iommu_attr attr, void *data)
+{
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ int ret = 0;
+
+ switch (attr) {
case DOMAIN_ATTR_USE_UPSTREAM_HINT:
case DOMAIN_ATTR_USE_LLC_NWA:
/* can't be changed while attached */
@@ -3409,11 +3572,21 @@
ret = -ENODEV;
}
-out_unlock:
- mutex_unlock(&smmu_domain->init_mutex);
return ret;
}
+static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
+ enum iommu_attr attr, void *data)
+{
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ int ret;
+
+ mutex_lock(&smmu_domain->init_mutex);
+ ret = __arm_smmu_domain_set_attr(domain, attr, data);
+ mutex_unlock(&smmu_domain->init_mutex);
+
+ return ret;
+}
static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
{
u32 mask, fwid = 0;
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 62759e2..b4d1936 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -18,6 +18,8 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/iommu.h>
+#include <linux/of_iommu.h>
+#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -173,6 +175,8 @@
struct list_head list;
struct mutex clk_lock;
unsigned int clk_count;
+ /* Protects domain */
+ struct mutex state_lock;
};
static int iommu_debug_build_phoney_sg_table(struct device *dev,
@@ -219,6 +223,163 @@
sg_free_table(table);
}
+struct iommu_debug_attr {
+ unsigned long dma_type;
+ int vmid;
+};
+
+static struct iommu_debug_attr std_attr = {
+ .dma_type = 0,
+ .vmid = 0,
+};
+
+static struct iommu_debug_attr fastmap_attr = {
+ .dma_type = DOMAIN_ATTR_FAST,
+ .vmid = 0,
+};
+
+static struct iommu_debug_attr secure_attr = {
+ .dma_type = 0,
+ .vmid = VMID_CP_CAMERA,
+};
+
+static int iommu_debug_set_attrs(struct iommu_debug_device *ddev,
+ struct iommu_domain *domain,
+ struct iommu_debug_attr *attrs)
+{
+ int val = 1;
+
+ /* Always set this to avoid clk latency during measurements */
+ iommu_domain_set_attr(domain, DOMAIN_ATTR_ATOMIC, &val);
+
+ if (attrs->dma_type == DOMAIN_ATTR_FAST)
+ iommu_domain_set_attr(domain, DOMAIN_ATTR_FAST, &val);
+
+ if (attrs->vmid != 0)
+ iommu_domain_set_attr(domain,
+ DOMAIN_ATTR_SECURE_VMID, &attrs->vmid);
+
+ return 0;
+}
+
+static void iommu_debug_print_attrs(struct seq_file *s,
+ struct iommu_debug_attr *attrs)
+{
+ seq_puts(s, "Attributes:\n");
+ if (attrs->dma_type == DOMAIN_ATTR_FAST)
+ seq_printf(s, "%s\n",
+ iommu_debug_attr_to_string(attrs->dma_type));
+
+ if (attrs->vmid != 0)
+ seq_printf(s, "SECURE_VMID=%d\n", attrs->vmid);
+}
+
+/*
+ * Set up a new dma allocator for dev
+ * Caller should hold state_lock
+ */
+static int iommu_debug_dma_reconfigure(struct iommu_debug_device *ddev,
+ struct iommu_debug_attr *attrs,
+ u64 dma_base, u64 size)
+{
+
+ const struct iommu_ops *iommu;
+ struct iommu_domain *domain;
+ struct device *dev = ddev->dev;
+ bool coherent;
+
+ if (ddev->domain) {
+ dev_err(dev, "Already attached.\n");
+ return -EBUSY;
+ }
+
+ iommu = of_iommu_configure(dev, dev->of_node);
+ if (!iommu) {
+ dev_err(dev, "Is not associated with an iommu\n");
+ return -EINVAL;
+ }
+
+ coherent = of_dma_is_coherent(dev->of_node);
+
+ if (!dev->iommu_group) {
+ dev_err(dev, "Does not have an iommu group\n");
+ return -EINVAL;
+ }
+
+ /* Detach from the default domain */
+ domain = iommu_get_domain_for_dev(dev);
+ if (domain) {
+ if (domain->type != IOMMU_DOMAIN_DMA) {
+ dev_err(dev, "Attached, but its not a default domain?\n");
+ return -EINVAL;
+ }
+ iommu_detach_group(domain, dev->iommu_group);
+ }
+
+ domain = iommu_domain_alloc(dev->bus);
+ if (!domain) {
+ dev_err(dev, "Allocating iommu domain failed\n");
+ return -EINVAL;
+ }
+
+ domain->is_debug_domain = true;
+
+ if (iommu_debug_set_attrs(ddev, domain, attrs)) {
+ dev_err(dev, "Setting attrs failed\n");
+ goto out_free_domain;
+ }
+
+ if (iommu_attach_group(domain, dev->iommu_group)) {
+ dev_err(dev, "attach group failed\n");
+ goto out_free_domain;
+ }
+
+ /*
+ * Since arch_setup_dma_ops is void, interpret non-null dma-ops
+ * as success.
+ */
+ set_dma_ops(dev, NULL);
+ arch_setup_dma_ops(dev, dma_base, size, iommu, coherent);
+ if (!get_dma_ops(dev)) {
+ dev_err(dev, "arch_setup_dma_ops failed, dma ops are null.\n");
+ goto out_detach_group;
+ }
+
+ ddev->domain = domain;
+ return 0;
+
+out_detach_group:
+ iommu_detach_group(domain, dev->iommu_group);
+out_free_domain:
+ iommu_domain_free(domain);
+ return -EINVAL;
+}
+
+/* Caller should hold state_lock */
+static void iommu_debug_dma_deconfigure(struct iommu_debug_device *ddev)
+{
+ struct iommu_domain *domain;
+ struct device *dev = ddev->dev;
+
+ if (!dev->iommu_group) {
+ dev_err(dev, "Does not have an iommu group\n");
+ return;
+ }
+
+ domain = ddev->domain;
+ if (!domain) {
+ dev_err(dev, "Is not attached\n");
+ return;
+ }
+
+
+ arch_teardown_dma_ops(dev);
+ iommu_detach_group(domain, dev->iommu_group);
+ iommu_domain_free(domain);
+
+ ddev->domain = NULL;
+}
+
static const char * const _size_to_string(unsigned long size)
{
switch (size) {
@@ -265,44 +426,22 @@
DEFINE_SIMPLE_ATTRIBUTE(iommu_debug_nr_iters_ops,
nr_iters_get, nr_iters_set, "%llu\n");
-static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev,
- enum iommu_attr attrs[],
- void *attr_values[], int nattrs,
- const size_t sizes[])
+static void iommu_debug_device_profiling(struct seq_file *s,
+ struct iommu_debug_device *ddev,
+ struct iommu_debug_attr *attrs,
+ const size_t sizes[])
{
- int i;
const size_t *sz;
struct iommu_domain *domain;
+ struct device *dev = ddev->dev;
unsigned long iova = 0x10000;
phys_addr_t paddr = 0xa000;
- domain = iommu_domain_alloc(&platform_bus_type);
- if (!domain) {
- seq_puts(s, "Couldn't allocate domain\n");
+ if (iommu_debug_dma_reconfigure(ddev, attrs, 0, SZ_1G * 4ULL))
return;
- }
+ domain = ddev->domain;
- seq_puts(s, "Domain attributes: [ ");
- for (i = 0; i < nattrs; ++i) {
- /* not all attrs are ints, but this will get us by for now */
- seq_printf(s, "%s=%d%s", iommu_debug_attr_to_string(attrs[i]),
- *((int *)attr_values[i]),
- i < nattrs ? " " : "");
- }
- seq_puts(s, "]\n");
- for (i = 0; i < nattrs; ++i) {
- if (iommu_domain_set_attr(domain, attrs[i], attr_values[i])) {
- seq_printf(s, "Couldn't set %d to the value at %p\n",
- attrs[i], attr_values[i]);
- goto out_domain_free;
- }
- }
-
- if (iommu_attach_group(domain, dev->iommu_group)) {
- seq_puts(s,
- "Couldn't attach new domain to device. Is it already attached?\n");
- goto out_domain_free;
- }
+ iommu_debug_print_attrs(s, attrs);
seq_printf(s, "(average over %d iterations)\n", iters_per_op);
seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map", "iommu_unmap");
@@ -419,9 +558,7 @@
}
out_detach:
- iommu_detach_group(domain, dev->iommu_group);
-out_domain_free:
- iommu_domain_free(domain);
+ iommu_debug_dma_deconfigure(ddev);
}
static int iommu_debug_profiling_show(struct seq_file *s, void *ignored)
@@ -429,14 +566,10 @@
struct iommu_debug_device *ddev = s->private;
const size_t sizes[] = { SZ_4K, SZ_64K, SZ_1M, SZ_2M, SZ_1M * 12,
SZ_1M * 24, SZ_1M * 32, 0 };
- enum iommu_attr attrs[] = {
- DOMAIN_ATTR_ATOMIC,
- };
- int htw_disable = 1, atomic = 1;
- void *attr_values[] = { &htw_disable, &atomic };
- iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
- ARRAY_SIZE(attrs), sizes);
+ mutex_lock(&ddev->state_lock);
+ iommu_debug_device_profiling(s, ddev, &std_attr, sizes);
+ mutex_unlock(&ddev->state_lock);
return 0;
}
@@ -459,15 +592,9 @@
const size_t sizes[] = { SZ_4K, SZ_64K, SZ_1M, SZ_2M, SZ_1M * 12,
SZ_1M * 24, SZ_1M * 32, 0 };
- enum iommu_attr attrs[] = {
- DOMAIN_ATTR_ATOMIC,
- DOMAIN_ATTR_SECURE_VMID,
- };
- int one = 1, secure_vmid = VMID_CP_PIXEL;
- void *attr_values[] = { &one, &secure_vmid };
-
- iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
- ARRAY_SIZE(attrs), sizes);
+ mutex_lock(&ddev->state_lock);
+ iommu_debug_device_profiling(s, ddev, &secure_attr, sizes);
+ mutex_unlock(&ddev->state_lock);
return 0;
}
@@ -490,15 +617,10 @@
{
struct iommu_debug_device *ddev = s->private;
size_t sizes[] = {SZ_4K, SZ_8K, SZ_16K, SZ_64K, 0};
- enum iommu_attr attrs[] = {
- DOMAIN_ATTR_FAST,
- DOMAIN_ATTR_ATOMIC,
- };
- int one = 1;
- void *attr_values[] = { &one, &one };
- iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
- ARRAY_SIZE(attrs), sizes);
+ mutex_lock(&ddev->state_lock);
+ iommu_debug_device_profiling(s, ddev, &fastmap_attr, sizes);
+ mutex_unlock(&ddev->state_lock);
return 0;
}
@@ -524,10 +646,9 @@
struct iommu_debug_device *ddev = s->private;
struct device *dev = ddev->dev;
u64 map_elapsed_ns[10], unmap_elapsed_ns[10];
- struct dma_iommu_mapping *mapping;
+ struct iommu_domain *domain;
dma_addr_t dma_addr;
void *virt;
- int fast = 1;
const char * const extra_labels[] = {
"not coherent",
"coherent",
@@ -537,27 +658,19 @@
DMA_ATTR_SKIP_CPU_SYNC,
};
+ mutex_lock(&ddev->state_lock);
+
virt = kmalloc(1518, GFP_KERNEL);
if (!virt)
goto out;
- mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4ULL);
- if (!mapping) {
- seq_puts(s, "fast_smmu_create_mapping failed\n");
+ if (iommu_debug_dma_reconfigure(ddev, &fastmap_attr, 0, SZ_1G * 4ULL)) {
+ seq_puts(s, "setup failed\n");
goto out_kfree;
}
+ domain = ddev->domain;
- if (iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &fast)) {
- seq_puts(s, "iommu_domain_set_attr failed\n");
- goto out_release_mapping;
- }
-
- if (arm_iommu_attach_device(dev, mapping)) {
- seq_puts(s, "fast_smmu_attach_device failed\n");
- goto out_release_mapping;
- }
-
- if (iommu_enable_config_clocks(mapping->domain)) {
+ if (iommu_enable_config_clocks(domain)) {
seq_puts(s, "Couldn't enable clocks\n");
goto out_detach;
}
@@ -613,14 +726,13 @@
}
out_disable_config_clocks:
- iommu_disable_config_clocks(mapping->domain);
+ iommu_disable_config_clocks(domain);
out_detach:
- arm_iommu_detach_device(dev);
-out_release_mapping:
- arm_iommu_release_mapping(mapping);
+ iommu_debug_dma_deconfigure(ddev);
out_kfree:
kfree(virt);
out:
+ mutex_unlock(&ddev->state_lock);
return 0;
}
@@ -1158,43 +1270,37 @@
void *priv),
void *priv)
{
- struct dma_iommu_mapping *mapping;
+ struct iommu_domain *domain;
struct iommu_debug_device *ddev = s->private;
struct device *dev = ddev->dev;
- int ret = -EINVAL, fast = 1;
+ int ret = -EINVAL;
phys_addr_t pt_phys;
- mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
- (SZ_1G * 4ULL));
- if (!mapping)
+ mutex_lock(&ddev->state_lock);
+ if (iommu_debug_dma_reconfigure(ddev, &fastmap_attr, 0, SZ_1G * 4ULL)) {
+ seq_puts(s, "setup failed\n");
goto out;
-
- if (iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &fast)) {
- seq_puts(s, "iommu_domain_set_attr failed\n");
- goto out_release_mapping;
}
+ domain = ddev->domain;
- if (arm_iommu_attach_device(dev, mapping))
- goto out_release_mapping;
-
- if (iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_PT_BASE_ADDR,
+ if (iommu_domain_get_attr(domain, DOMAIN_ATTR_PT_BASE_ADDR,
&pt_phys)) {
ds_printf(dev, s, "Couldn't get page table base address\n");
goto out_release_mapping;
}
dev_err(dev, "testing with pgtables at %pa\n", &pt_phys);
- if (iommu_enable_config_clocks(mapping->domain)) {
+ if (iommu_enable_config_clocks(domain)) {
ds_printf(dev, s, "Couldn't enable clocks\n");
goto out_release_mapping;
}
- ret = fn(dev, s, mapping->domain, priv);
- iommu_disable_config_clocks(mapping->domain);
+ ret = fn(dev, s, domain, priv);
+ iommu_disable_config_clocks(domain);
- arm_iommu_detach_device(dev);
out_release_mapping:
- arm_iommu_release_mapping(mapping);
+ iommu_debug_dma_deconfigure(ddev);
out:
+ mutex_unlock(&ddev->state_lock);
seq_printf(s, "%s\n", ret ? "FAIL" : "SUCCESS");
return 0;
}
@@ -1228,29 +1334,22 @@
static int iommu_debug_functional_arm_dma_api_show(struct seq_file *s,
void *ignored)
{
- struct dma_iommu_mapping *mapping;
struct iommu_debug_device *ddev = s->private;
struct device *dev = ddev->dev;
size_t sizes[] = {SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12, 0};
int ret = -EINVAL;
- /* Make the size equal to MAX_ULONG */
- mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
- (SZ_1G * 4ULL - 1));
- if (!mapping)
+ mutex_lock(&ddev->state_lock);
+ if (iommu_debug_dma_reconfigure(ddev, &fastmap_attr, 0, SZ_1G * 4ULL))
goto out;
- if (arm_iommu_attach_device(dev, mapping))
- goto out_release_mapping;
+ ret = __functional_dma_api_alloc_test(dev, s, ddev->domain, sizes);
+ ret |= __functional_dma_api_basic_test(dev, s, ddev->domain, sizes);
+ ret |= __functional_dma_api_map_sg_test(dev, s, ddev->domain, sizes);
- ret = __functional_dma_api_alloc_test(dev, s, mapping->domain, sizes);
- ret |= __functional_dma_api_basic_test(dev, s, mapping->domain, sizes);
- ret |= __functional_dma_api_map_sg_test(dev, s, mapping->domain, sizes);
-
- arm_iommu_detach_device(dev);
-out_release_mapping:
- arm_iommu_release_mapping(mapping);
+ iommu_debug_dma_deconfigure(ddev);
out:
+ mutex_unlock(&ddev->state_lock);
seq_printf(s, "%s\n", ret ? "FAIL" : "SUCCESS");
return 0;
}
@@ -1269,181 +1368,60 @@
.release = single_release,
};
-static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev,
- int val, bool is_secure)
-{
- struct iommu_group *group = ddev->dev->iommu_group;
-
- ddev->domain = iommu_domain_alloc(&platform_bus_type);
- if (!ddev->domain) {
- pr_err("Couldn't allocate domain\n");
- return -ENOMEM;
- }
-
- ddev->domain->is_debug_domain = true;
- val = VMID_CP_CAMERA;
- if (is_secure && iommu_domain_set_attr(ddev->domain,
- DOMAIN_ATTR_SECURE_VMID,
- &val)) {
- pr_err("Couldn't set secure vmid to %d\n", val);
- goto out_domain_free;
- }
-
- if (iommu_attach_group(ddev->domain, group)) {
- dev_err(ddev->dev, "Couldn't attach new domain to device\n");
- goto out_domain_free;
- }
-
- return 0;
-
-out_domain_free:
- iommu_domain_free(ddev->domain);
- ddev->domain = NULL;
- return -EIO;
-}
-
-static ssize_t __iommu_debug_dma_attach_write(struct file *file,
- const char __user *ubuf,
- size_t count, loff_t *offset)
-{
- struct iommu_debug_device *ddev = file->private_data;
- struct device *dev = ddev->dev;
- struct dma_iommu_mapping *dma_mapping;
- ssize_t retval = -EINVAL;
- int val;
-
- if (kstrtoint_from_user(ubuf, count, 0, &val)) {
- pr_err("Invalid format. Expected a hex or decimal integer");
- retval = -EFAULT;
- goto out;
- }
-
- if (val) {
- if (dev->archdata.mapping)
- if (dev->archdata.mapping->domain) {
- pr_err("Already attached.\n");
- retval = -EINVAL;
- goto out;
- }
- if (WARN(dev->archdata.iommu,
- "Attachment tracking out of sync with device\n")) {
- retval = -EINVAL;
- goto out;
- }
-
- dma_mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
- (SZ_1G * 4ULL));
-
- if (!dma_mapping)
- goto out;
-
- dma_mapping->domain->is_debug_domain = true;
-
- if (arm_iommu_attach_device(dev, dma_mapping))
- goto out_release_mapping;
-
- ddev->mapping = dma_mapping;
- pr_err("Attached\n");
- } else {
- if (!dev->archdata.mapping) {
- pr_err("No mapping. Did you already attach?\n");
- retval = -EINVAL;
- goto out;
- }
- if (!dev->archdata.mapping->domain) {
- pr_err("No domain. Did you already attach?\n");
- retval = -EINVAL;
- goto out;
- }
- arm_iommu_detach_device(dev);
- arm_iommu_release_mapping(ddev->mapping);
- pr_err("Detached\n");
- }
- retval = count;
- return retval;
-
-out_release_mapping:
- arm_iommu_release_mapping(dma_mapping);
-out:
- return retval;
-}
-
static ssize_t __iommu_debug_attach_write(struct file *file,
const char __user *ubuf,
size_t count, loff_t *offset,
- bool is_secure)
+ struct iommu_debug_attr *attrs)
{
struct iommu_debug_device *ddev = file->private_data;
- struct device *dev = ddev->dev;
- struct iommu_domain *domain;
- ssize_t retval;
- int val;
+ ssize_t retval = -EINVAL;
+ int val, ret;
if (kstrtoint_from_user(ubuf, count, 0, &val)) {
pr_err("Invalid format. Expected a hex or decimal integer");
- retval = -EFAULT;
- goto out;
+ return -EFAULT;
}
+ mutex_lock(&ddev->state_lock);
if (val) {
- if (ddev->domain) {
- pr_err("Iommu-Debug is already attached?\n");
- retval = -EINVAL;
- goto out;
- }
-
- domain = iommu_get_domain_for_dev(dev);
- if (domain) {
- pr_err("Another driver is using this device's iommu\n"
- "Iommu-Debug cannot be used concurrently\n");
- retval = -EINVAL;
- goto out;
- }
- if (iommu_debug_attach_do_attach(ddev, val, is_secure)) {
- retval = -EIO;
- goto out;
- }
- pr_err("Attached\n");
+ ret = iommu_debug_dma_reconfigure(ddev, attrs, 0, SZ_1G * 4ULL);
+ if (!ret)
+ pr_err("Attached\n");
} else {
- if (!ddev->domain) {
- pr_err("Iommu-Debug is not attached?\n");
- retval = -EINVAL;
- goto out;
- }
- iommu_detach_group(ddev->domain, dev->iommu_group);
- iommu_domain_free(ddev->domain);
- ddev->domain = NULL;
+ iommu_debug_dma_deconfigure(ddev);
pr_err("Detached\n");
}
-
+ mutex_unlock(&ddev->state_lock);
retval = count;
-out:
return retval;
}
-static ssize_t iommu_debug_dma_attach_write(struct file *file,
+static ssize_t iommu_debug_secure_attach_write(struct file *file,
const char __user *ubuf,
size_t count, loff_t *offset)
{
- return __iommu_debug_dma_attach_write(file, ubuf, count, offset);
+ return __iommu_debug_attach_write(file, ubuf, count, offset,
+ &secure_attr);
+}
+
+static ssize_t iommu_debug_attach_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ return __iommu_debug_attach_write(file, ubuf, count, offset, &std_attr);
}
-static ssize_t iommu_debug_dma_attach_read(struct file *file, char __user *ubuf,
+static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
size_t count, loff_t *offset)
{
struct iommu_debug_device *ddev = file->private_data;
- struct device *dev = ddev->dev;
char c[2];
if (*offset)
return 0;
- if (!dev->archdata.mapping)
- c[0] = '0';
- else
- c[0] = dev->archdata.mapping->domain ? '1' : '0';
-
+ c[0] = ddev->domain ? '1' : '0';
c[1] = '\n';
if (copy_to_user(ubuf, &c, 2)) {
pr_err("copy_to_user failed\n");
@@ -1456,8 +1434,8 @@
static const struct file_operations iommu_debug_dma_attach_fops = {
.open = simple_open,
- .write = iommu_debug_dma_attach_write,
- .read = iommu_debug_dma_attach_read,
+ .write = iommu_debug_attach_write,
+ .read = iommu_debug_attach_read,
};
static ssize_t iommu_debug_test_virt_addr_read(struct file *file,
@@ -1496,52 +1474,15 @@
.read = iommu_debug_test_virt_addr_read,
};
-static ssize_t iommu_debug_attach_write(struct file *file,
- const char __user *ubuf,
- size_t count, loff_t *offset)
-{
- return __iommu_debug_attach_write(file, ubuf, count, offset,
- false);
-
-}
-
-static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *offset)
-{
- struct iommu_debug_device *ddev = file->private_data;
- char c[2];
-
- if (*offset)
- return 0;
-
- c[0] = ddev->domain ? '1' : '0';
- c[1] = '\n';
- if (copy_to_user(ubuf, &c, 2)) {
- pr_err("copy_to_user failed\n");
- return -EFAULT;
- }
- *offset = 1; /* non-zero means we're done */
-
- return 2;
-}
-
static const struct file_operations iommu_debug_attach_fops = {
.open = simple_open,
.write = iommu_debug_attach_write,
.read = iommu_debug_attach_read,
};
-static ssize_t iommu_debug_attach_write_secure(struct file *file,
- const char __user *ubuf,
- size_t count, loff_t *offset)
-{
- return __iommu_debug_attach_write(file, ubuf, count, offset,
- true);
-}
-
static const struct file_operations iommu_debug_secure_attach_fops = {
.open = simple_open,
- .write = iommu_debug_attach_write_secure,
+ .write = iommu_debug_secure_attach_write,
.read = iommu_debug_attach_read,
};
@@ -1568,7 +1509,6 @@
size_t count, loff_t *offset)
{
struct iommu_debug_device *ddev = file->private_data;
- struct device *dev = ddev->dev;
uint64_t pte;
char buf[100];
ssize_t retval;
@@ -1578,22 +1518,20 @@
pr_err("kptr_restrict needs to be disabled.\n");
return -EPERM;
}
- if (!dev->archdata.mapping) {
- pr_err("No mapping. Did you already attach?\n");
- return -EINVAL;
- }
- if (!dev->archdata.mapping->domain) {
- pr_err("No domain. Did you already attach?\n");
- return -EINVAL;
- }
if (*offset)
return 0;
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
+
memset(buf, 0, sizeof(buf));
- pte = iommu_iova_to_pte(dev->archdata.mapping->domain,
- ddev->iova);
+ pte = iommu_iova_to_pte(ddev->domain, ddev->iova);
if (!pte)
strlcpy(buf, "FAIL\n", sizeof(buf));
@@ -1609,6 +1547,7 @@
retval = buflen;
}
+ mutex_unlock(&ddev->state_lock);
return retval;
}
@@ -1649,14 +1588,17 @@
pr_err("kptr_restrict needs to be disabled.\n");
return -EPERM;
}
- if (!ddev->domain) {
- pr_err("No domain. Did you already attach?\n");
- return -EINVAL;
- }
if (*offset)
return 0;
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
+
memset(buf, 0, 100);
phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
@@ -1678,6 +1620,7 @@
retval = buflen;
}
+ mutex_unlock(&ddev->state_lock);
return retval;
}
@@ -1691,7 +1634,6 @@
size_t count, loff_t *offset)
{
struct iommu_debug_device *ddev = file->private_data;
- struct device *dev = ddev->dev;
phys_addr_t phys;
char buf[100];
ssize_t retval;
@@ -1701,21 +1643,19 @@
pr_err("kptr_restrict needs to be disabled.\n");
return -EPERM;
}
- if (!dev->archdata.mapping) {
- pr_err("No mapping. Did you already attach?\n");
- return -EINVAL;
- }
- if (!dev->archdata.mapping->domain) {
- pr_err("No domain. Did you already attach?\n");
- return -EINVAL;
- }
-
if (*offset)
return 0;
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
+
memset(buf, 0, sizeof(buf));
- phys = iommu_iova_to_phys_hard(dev->archdata.mapping->domain,
+ phys = iommu_iova_to_phys_hard(ddev->domain,
ddev->iova);
if (!phys)
strlcpy(buf, "FAIL\n", sizeof(buf));
@@ -1731,6 +1671,7 @@
retval = buflen;
}
+ mutex_unlock(&ddev->state_lock);
return retval;
}
@@ -1758,11 +1699,6 @@
return -EINVAL;
}
- if (!ddev->domain) {
- pr_err("No domain. Did you already attach?\n");
- return -EINVAL;
- }
-
memset(buf, 0, 100);
if (copy_from_user(buf, ubuf, count)) {
@@ -1797,6 +1733,13 @@
if (kstrtoint(comma3 + 1, 0, &prot))
goto invalid_format;
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
+
ret = iommu_map(ddev->domain, iova, phys, size, prot);
if (ret) {
pr_err("iommu_map failed with %d\n", ret);
@@ -1808,6 +1751,7 @@
pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
&iova, &phys, size, prot);
out:
+ mutex_unlock(&ddev->state_lock);
return retval;
invalid_format:
@@ -1849,23 +1793,11 @@
return -EINVAL;
}
- if (!dev->archdata.mapping) {
- pr_err("No mapping. Did you already attach?\n");
- retval = -EINVAL;
- goto out;
- }
- if (!dev->archdata.mapping->domain) {
- pr_err("No domain. Did you already attach?\n");
- retval = -EINVAL;
- goto out;
- }
-
memset(buf, 0, sizeof(buf));
if (copy_from_user(buf, ubuf, count)) {
pr_err("Couldn't copy from user\n");
- retval = -EFAULT;
- goto out;
+ return -EFAULT;
}
comma1 = strnchr(buf, count, ',');
@@ -1902,6 +1834,13 @@
else
goto invalid_format;
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
+
iova = dma_map_single_attrs(dev, v_addr, size,
DMA_TO_DEVICE, dma_attrs);
@@ -1917,6 +1856,7 @@
ddev->iova = iova;
pr_err("Saved iova=%pa for future PTE commands\n", &iova);
out:
+ mutex_unlock(&ddev->state_lock);
return retval;
invalid_format:
@@ -1932,21 +1872,11 @@
size_t count, loff_t *offset)
{
struct iommu_debug_device *ddev = file->private_data;
- struct device *dev = ddev->dev;
char buf[100];
ssize_t retval;
size_t buflen;
dma_addr_t iova;
- if (!dev->archdata.mapping) {
- pr_err("No mapping. Did you already attach?\n");
- return -EINVAL;
- }
- if (!dev->archdata.mapping->domain) {
- pr_err("No domain. Did you already attach?\n");
- return -EINVAL;
- }
-
if (*offset)
return 0;
@@ -2016,16 +1946,25 @@
if (kstrtosize_t(comma1 + 1, 0, &size))
goto invalid_format;
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
+
unmapped = iommu_unmap(ddev->domain, iova, size);
if (unmapped != size) {
pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
size, unmapped);
- return -EIO;
+ retval = -EIO;
+ goto out;
}
retval = count;
pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
out:
+ mutex_unlock(&ddev->state_lock);
return retval;
invalid_format:
@@ -2057,17 +1996,6 @@
return -EINVAL;
}
- if (!dev->archdata.mapping) {
- pr_err("No mapping. Did you already attach?\n");
- retval = -EINVAL;
- goto out;
- }
- if (!dev->archdata.mapping->domain) {
- pr_err("No domain. Did you already attach?\n");
- retval = -EINVAL;
- goto out;
- }
-
memset(buf, 0, sizeof(buf));
if (copy_from_user(buf, ubuf, count)) {
@@ -2106,11 +2034,18 @@
else
goto invalid_format;
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
dma_unmap_single_attrs(dev, iova, size, DMA_TO_DEVICE, dma_attrs);
retval = count;
pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
out:
+ mutex_unlock(&ddev->state_lock);
return retval;
invalid_format:
@@ -2191,18 +2126,20 @@
struct iommu_debug_device *ddev = file->private_data;
unsigned long flags;
- if (!ddev->domain) {
- pr_err("No domain. Did you already attach?\n");
- return -EINVAL;
- }
-
if (kstrtoul_from_user(ubuf, count, 0, &flags)) {
pr_err("Invalid flags format\n");
return -EFAULT;
}
+ mutex_lock(&ddev->state_lock);
+ if (!ddev->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ mutex_unlock(&ddev->state_lock);
+ return -EINVAL;
+ }
iommu_trigger_fault(ddev->domain, flags);
+ mutex_unlock(&ddev->state_lock);
return count;
}
@@ -2236,6 +2173,7 @@
return -ENODEV;
mutex_init(&ddev->clk_lock);
+ mutex_init(&ddev->state_lock);
ddev->dev = dev;
dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
if (!dir) {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 44097a3..81f93f2 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -756,6 +756,17 @@
To compile this driver as a module, choose M here: the module
will be called leds-nic78bx.
+config LEDS_QPNP_FLASH_V2
+ tristate "Support for QPNP V2 Flash LEDs"
+ depends on LEDS_CLASS && MFD_SPMI_PMIC
+ select LEDS_TRIGGERS
+ help
+ This driver supports the flash V2 LED functionality of Qualcomm
+ Technologies, Inc. QPNP PMICs. This driver supports PMICs starting
+ from PMI8998, PM8150L and their derivatives. It can configure the
+ flash LED target current for several independent channels. It also
+ supports various over current and over temperature mitigation features.
+
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 420b5d2..38b54a8 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@
obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
+obj-$(CONFIG_LEDS_QPNP_FLASH_V2) += leds-qpnp-flash-v2.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
new file mode 100644
index 0000000..eb73621f
--- /dev/null
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -0,0 +1,2670 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt) "flashv2: %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include <linux/leds-qpnp-flash.h>
+#include <linux/leds-qpnp-flash-v2.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/log2.h>
+#include "leds.h"
+
+#define FLASH_LED_REG_LED_STATUS1(base) (base + 0x08)
+#define FLASH_LED_REG_LED_STATUS2(base) (base + 0x09)
+#define FLASH_LED_REG_INT_RT_STS(base) (base + 0x10)
+#define FLASH_LED_REG_SAFETY_TMR(base) (base + 0x40)
+#define FLASH_LED_REG_TGR_CURRENT(base) (base + 0x43)
+#define FLASH_LED_REG_MOD_CTRL(base) (base + 0x46)
+#define FLASH_LED_REG_IRES(base) (base + 0x47)
+#define FLASH_LED_REG_STROBE_CFG(base) (base + 0x48)
+#define FLASH_LED_REG_STROBE_CTRL(base) (base + 0x49)
+#define FLASH_LED_EN_LED_CTRL(base) (base + 0x4C)
+#define FLASH_LED_REG_HDRM_PRGM(base) (base + 0x4D)
+#define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50)
+#define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51)
+#define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52)
+#define FLASH_LED_REG_THERMAL_RMP_DN_RATE(base) (base + 0x55)
+#define FLASH_LED_REG_THERMAL_THRSH1(base) (base + 0x56)
+#define FLASH_LED_REG_THERMAL_THRSH2(base) (base + 0x57)
+#define FLASH_LED_REG_THERMAL_THRSH3(base) (base + 0x58)
+#define FLASH_LED_REG_THERMAL_HYSTERESIS(base) (base + 0x59)
+#define FLASH_LED_REG_THERMAL_DEBOUNCE(base) (base + 0x5A)
+#define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61)
+#define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62)
+#define FLASH_LED_REG_ILED_GRT_THRSH(base) (base + 0x67)
+#define FLASH_LED_REG_LED1N2_ICLAMP_LOW(base) (base + 0x68)
+#define FLASH_LED_REG_LED1N2_ICLAMP_MID(base) (base + 0x69)
+#define FLASH_LED_REG_LED3_ICLAMP_LOW(base) (base + 0x6A)
+#define FLASH_LED_REG_LED3_ICLAMP_MID(base) (base + 0x6B)
+#define FLASH_LED_REG_MITIGATION_SEL(base) (base + 0x6E)
+#define FLASH_LED_REG_MITIGATION_SW(base) (base + 0x6F)
+#define FLASH_LED_REG_LMH_LEVEL(base) (base + 0x70)
+#define FLASH_LED_REG_MULTI_STROBE_CTRL(base) (base + 0x71)
+#define FLASH_LED_REG_LPG_INPUT_CTRL(base) (base + 0x72)
+#define FLASH_LED_REG_CURRENT_DERATE_EN(base) (base + 0x76)
+
+#define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4)
+#define FLASH_LED_CURRENT_MASK GENMASK(6, 0)
+#define FLASH_LED_STROBE_MASK GENMASK(1, 0)
+#define FLASH_HW_STROBE_MASK GENMASK(2, 0)
+#define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0)
+#define FLASH_LED_CURRENT_DERATE_EN_MASK GENMASK(2, 0)
+#define FLASH_LED_VPH_DROOP_DEBOUNCE_MASK GENMASK(1, 0)
+#define FLASH_LED_CHGR_MITIGATION_SEL_MASK GENMASK(5, 4)
+#define FLASH_LED_LMH_MITIGATION_SEL_MASK GENMASK(1, 0)
+#define FLASH_LED_ILED_GRT_THRSH_MASK GENMASK(5, 0)
+#define FLASH_LED_LMH_LEVEL_MASK GENMASK(1, 0)
+#define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4)
+#define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0)
+#define FLASH_LED_THERMAL_HYSTERESIS_MASK GENMASK(1, 0)
+#define FLASH_LED_THERMAL_DEBOUNCE_MASK GENMASK(1, 0)
+#define FLASH_LED_THERMAL_THRSH_MASK GENMASK(2, 0)
+#define FLASH_LED_MOD_CTRL_MASK BIT(7)
+#define FLASH_LED_HW_SW_STROBE_SEL_BIT BIT(2)
+#define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4)
+#define FLASH_LED_LMH_MITIGATION_EN_MASK BIT(0)
+#define FLASH_LED_CHGR_MITIGATION_EN_MASK BIT(4)
+#define THERMAL_OTST1_RAMP_CTRL_MASK BIT(7)
+#define THERMAL_OTST1_RAMP_CTRL_SHIFT 7
+#define THERMAL_DERATE_SLOW_SHIFT 4
+#define THERMAL_DERATE_SLOW_MASK GENMASK(6, 4)
+#define THERMAL_DERATE_FAST_MASK GENMASK(2, 0)
+#define LED1N2_FLASH_ONCE_ONLY_BIT BIT(0)
+#define LED3_FLASH_ONCE_ONLY_BIT BIT(1)
+#define LPG_INPUT_SEL_BIT BIT(0)
+
+#define VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us) (val_us / 8)
+#define VPH_DROOP_HYST_MV_TO_VAL(val_mv) (val_mv / 25)
+#define VPH_DROOP_THRESH_VAL_TO_UV(val) ((val + 25) * 100000)
+#define MITIGATION_THRSH_MA_TO_VAL(val_ma) (val_ma / 100)
+#define THERMAL_HYST_TEMP_TO_VAL(val, divisor) (val / divisor)
+
+#define FLASH_LED_ISC_WARMUP_DELAY_SHIFT 6
+#define FLASH_LED_WARMUP_DELAY_DEFAULT 2
+#define FLASH_LED_ISC_DELAY_DEFAULT 3
+#define FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT 2
+#define FLASH_LED_VPH_DROOP_HYST_SHIFT 4
+#define FLASH_LED_VPH_DROOP_HYST_DEFAULT 2
+#define FLASH_LED_VPH_DROOP_THRESH_DEFAULT 5
+#define FLASH_LED_DEBOUNCE_MAX 3
+#define FLASH_LED_HYSTERESIS_MAX 3
+#define FLASH_LED_VPH_DROOP_THRESH_MAX 7
+#define THERMAL_DERATE_SLOW_MAX 314592
+#define THERMAL_DERATE_FAST_MAX 512
+#define THERMAL_DEBOUNCE_TIME_MAX 64
+#define THERMAL_DERATE_HYSTERESIS_MAX 3
+#define FLASH_LED_THERMAL_THRSH_MIN 3
+#define FLASH_LED_THERMAL_THRSH_MAX 7
+#define FLASH_LED_THERMAL_OTST_LEVELS 3
+#define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000
+#define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000
+#define FLASH_LED_RPARA_DEFAULT_UOHM 0
+#define FLASH_LED_SAFETY_TMR_ENABLE BIT(7)
+#define FLASH_LED_LMH_LEVEL_DEFAULT 0
+#define FLASH_LED_LMH_MITIGATION_ENABLE 1
+#define FLASH_LED_LMH_MITIGATION_DISABLE 0
+#define FLASH_LED_CHGR_MITIGATION_ENABLE BIT(4)
+#define FLASH_LED_CHGR_MITIGATION_DISABLE 0
+#define FLASH_LED_LMH_MITIGATION_SEL_DEFAULT 2
+#define FLASH_LED_MITIGATION_SEL_MAX 2
+#define FLASH_LED_CHGR_MITIGATION_SEL_SHIFT 4
+#define FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT 0xA
+#define FLASH_LED_CHGR_MITIGATION_THRSH_MAX 0x1F
+#define FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV 3700000
+#define FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM 400000
+#define FLASH_LED_IRES_BASE 3
+#define FLASH_LED_IRES_DIVISOR 2500
+#define FLASH_LED_IRES_MIN_UA 5000
+#define FLASH_LED_IRES_DEFAULT_UA 12500
+#define FLASH_LED_IRES_DEFAULT_VAL 0x00
+#define FLASH_LED_HDRM_VOL_SHIFT 4
+#define FLASH_LED_HDRM_VOL_DEFAULT_MV 0x80
+#define FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV 0x04
+#define FLASH_LED_HDRM_VOL_BASE_MV 125
+#define FLASH_LED_HDRM_VOL_STEP_MV 25
+#define FLASH_LED_STROBE_CFG_DEFAULT 0x00
+#define FLASH_LED_HW_STROBE_OPTION_1 0x00
+#define FLASH_LED_HW_STROBE_OPTION_2 0x01
+#define FLASH_LED_HW_STROBE_OPTION_3 0x02
+#define FLASH_LED_ENABLE BIT(0)
+#define FLASH_LED_MOD_ENABLE BIT(7)
+#define FLASH_LED_DISABLE 0x00
+#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
+#define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750
+#define FLASH_LED_IRES5P0_MAX_CURR_MA 640
+#define FLASH_LED_IRES7P5_MAX_CURR_MA 960
+#define FLASH_LED_IRES10P0_MAX_CURR_MA 1280
+#define FLASH_LED_IRES12P5_MAX_CURR_MA 1600
+#define MAX_IRES_LEVELS 4
+
+/* notifier call chain for flash-led irqs */
+static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
+
+enum flash_charger_mitigation {
+ FLASH_DISABLE_CHARGER_MITIGATION,
+ FLASH_HW_CHARGER_MITIGATION_BY_ILED_THRSHLD,
+ FLASH_SW_CHARGER_MITIGATION,
+};
+
+enum flash_led_type {
+ FLASH_LED_TYPE_UNKNOWN,
+ FLASH_LED_TYPE_FLASH,
+ FLASH_LED_TYPE_TORCH,
+};
+
+enum {
+ LED1 = 0,
+ LED2,
+ LED3,
+};
+
+enum strobe_type {
+ SW_STROBE = 0,
+ HW_STROBE,
+ LPG_STROBE,
+};
+
+/*
+ * Configurations for each individual LED
+ */
+struct flash_node_data {
+ struct platform_device *pdev;
+ struct led_classdev cdev;
+ struct pinctrl *strobe_pinctrl;
+ struct pinctrl_state *hw_strobe_state_active;
+ struct pinctrl_state *hw_strobe_state_suspend;
+ int hw_strobe_gpio;
+ int ires_ua;
+ int default_ires_ua;
+ int max_current;
+ int current_ma;
+ int prev_current_ma;
+ u8 duration;
+ u8 id;
+ u8 ires_idx;
+ u8 default_ires_idx;
+ u8 hdrm_val;
+ u8 current_reg_val;
+ u8 strobe_ctrl;
+ u8 strobe_sel;
+ enum flash_led_type type;
+ bool led_on;
+};
+
+
+struct flash_switch_data {
+ struct platform_device *pdev;
+ struct regulator *vreg;
+ struct pinctrl *led_en_pinctrl;
+ struct pinctrl_state *gpio_state_active;
+ struct pinctrl_state *gpio_state_suspend;
+ struct led_classdev cdev;
+ int led_mask;
+ bool regulator_on;
+ bool enabled;
+ bool symmetry_en;
+};
+
+/*
+ * Flash LED configuration read from device tree
+ */
+struct flash_led_platform_data {
+ struct pmic_revid_data *pmic_rev_id;
+ int *thermal_derate_current;
+ int all_ramp_up_done_irq;
+ int all_ramp_down_done_irq;
+ int led_fault_irq;
+ int ibatt_ocp_threshold_ua;
+ int vled_max_uv;
+ int rpara_uohm;
+ int lmh_rbatt_threshold_uohm;
+ int lmh_ocv_threshold_uv;
+ int thermal_derate_slow;
+ int thermal_derate_fast;
+ int thermal_hysteresis;
+ int thermal_debounce;
+ int thermal_thrsh1;
+ int thermal_thrsh2;
+ int thermal_thrsh3;
+ int hw_strobe_option;
+ u32 led1n2_iclamp_low_ma;
+ u32 led1n2_iclamp_mid_ma;
+ u32 led3_iclamp_low_ma;
+ u32 led3_iclamp_mid_ma;
+ u8 isc_delay;
+ u8 warmup_delay;
+ u8 current_derate_en_cfg;
+ u8 vph_droop_threshold;
+ u8 vph_droop_hysteresis;
+ u8 vph_droop_debounce;
+ u8 lmh_mitigation_sel;
+ u8 chgr_mitigation_sel;
+ u8 lmh_level;
+ u8 iled_thrsh_val;
+ bool hdrm_auto_mode_en;
+ bool thermal_derate_en;
+ bool otst_ramp_bkup_en;
+};
+
+/*
+ * Flash LED data structure containing flash LED attributes
+ */
+struct qpnp_flash_led {
+ struct flash_led_platform_data *pdata;
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct flash_node_data *fnode;
+ struct flash_switch_data *snode;
+ struct power_supply *bms_psy;
+ struct notifier_block nb;
+ spinlock_t lock;
+ int num_fnodes;
+ int num_snodes;
+ int enable;
+ int total_current_ma;
+ u16 base;
+ bool trigger_lmh;
+ bool trigger_chgr;
+};
+
+static int thermal_derate_slow_table[] = {
+ 128, 256, 512, 1024, 2048, 4096, 8192, 314592,
+};
+
+static int thermal_derate_fast_table[] = {
+ 32, 64, 96, 128, 256, 384, 512,
+};
+
+static int otst1_threshold_table[] = {
+ 85, 79, 73, 67, 109, 103, 97, 91,
+};
+
+static int otst2_threshold_table[] = {
+ 110, 104, 98, 92, 134, 128, 122, 116,
+};
+
+static int otst3_threshold_table[] = {
+ 125, 119, 113, 107, 149, 143, 137, 131,
+};
+
+static int max_ires_curr_ma_table[MAX_IRES_LEVELS] = {
+ FLASH_LED_IRES12P5_MAX_CURR_MA, FLASH_LED_IRES10P0_MAX_CURR_MA,
+ FLASH_LED_IRES7P5_MAX_CURR_MA, FLASH_LED_IRES5P0_MAX_CURR_MA
+};
+
+static inline int get_current_reg_code(int target_curr_ma, int ires_ua)
+{
+ if (!ires_ua || !target_curr_ma || (target_curr_ma < (ires_ua / 1000)))
+ return 0;
+
+ return DIV_ROUND_CLOSEST(target_curr_ma * 1000, ires_ua) - 1;
+}
+
+static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
+{
+ int rc;
+ uint val;
+
+ rc = regmap_read(led->regmap, addr, &val);
+ if (rc < 0) {
+ pr_err("Unable to read from 0x%04X rc = %d\n", addr, rc);
+ return rc;
+ }
+
+ pr_debug("Read 0x%02X from addr 0x%04X\n", val, addr);
+ *data = (u8)val;
+ return 0;
+}
+
+static int qpnp_flash_led_write(struct qpnp_flash_led *led, u16 addr, u8 data)
+{
+ int rc;
+
+ rc = regmap_write(led->regmap, addr, data);
+ if (rc < 0) {
+ pr_err("Unable to write to 0x%04X rc = %d\n", addr, rc);
+ return rc;
+ }
+
+ pr_debug("Wrote 0x%02X to addr 0x%04X\n", data, addr);
+ return 0;
+}
+
+static int
+qpnp_flash_led_masked_read(struct qpnp_flash_led *led, u16 addr, u8 mask,
+ u8 *val)
+{
+ int rc;
+
+ rc = qpnp_flash_led_read(led, addr, val);
+ if (rc < 0)
+ return rc;
+
+ *val &= mask;
+ return rc;
+}
+
+static int
+qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
+ u8 val)
+{
+ int rc;
+
+ rc = regmap_update_bits(led->regmap, addr, mask, val);
+ if (rc < 0)
+ pr_err("Unable to update bits from 0x%04X, rc = %d\n", addr,
+ rc);
+ else
+ pr_debug("Wrote 0x%02X to addr 0x%04X\n", val, addr);
+
+ return rc;
+}
+
+static enum
+led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
+{
+ return led_cdev->brightness;
+}
+
+static int qpnp_flash_led_headroom_config(struct qpnp_flash_led *led)
+{
+ int rc, i, addr_offset;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ addr_offset = led->fnode[i].id;
+ rc = qpnp_flash_led_write(led,
+ FLASH_LED_REG_HDRM_PRGM(led->base + addr_offset),
+ led->fnode[i].hdrm_val);
+ if (rc < 0)
+ return rc;
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_strobe_config(struct qpnp_flash_led *led)
+{
+ int i, rc, addr_offset;
+ u8 val = 0, mask, strobe_mask = 0, strobe_ctrl;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ val |= 0x1 << led->fnode[i].id;
+
+ if (led->fnode[i].strobe_sel == HW_STROBE) {
+ if (led->fnode[i].id == LED3)
+ strobe_mask |= LED3_FLASH_ONCE_ONLY_BIT;
+ else
+ strobe_mask |= LED1N2_FLASH_ONCE_ONLY_BIT;
+ }
+
+ if (led->fnode[i].id == LED3 &&
+ led->fnode[i].strobe_sel == LPG_STROBE)
+ strobe_mask |= LED3_FLASH_ONCE_ONLY_BIT;
+ /*
+ * As per the hardware recommendation, to use LED2/LED3 in HW
+ * strobe mode, LED1 should be set to HW strobe mode as well.
+ */
+ if (led->fnode[i].strobe_sel == HW_STROBE &&
+ (led->fnode[i].id == LED2 || led->fnode[i].id == LED3)) {
+ mask = FLASH_HW_STROBE_MASK;
+ addr_offset = led->fnode[LED1].id;
+ /*
+ * HW_STROBE: enable, TRIGGER: level,
+ * POLARITY: active high
+ */
+ strobe_ctrl = BIT(2) | BIT(0);
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_STROBE_CTRL(
+ led->base + addr_offset),
+ mask, strobe_ctrl);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MULTI_STROBE_CTRL(led->base),
+ strobe_mask, 0);
+ if (rc < 0)
+ return rc;
+
+ if (led->fnode[LED3].strobe_sel == LPG_STROBE) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LPG_INPUT_CTRL(led->base),
+ LPG_INPUT_SEL_BIT, LPG_INPUT_SEL_BIT);
+ if (rc < 0)
+ return rc;
+ }
+
+ return rc;
+}
+
+static qpnp_flash_led_thermal_config(struct qpnp_flash_led *led)
+{
+ int rc;
+ u8 val, mask;
+
+ val = (led->pdata->otst_ramp_bkup_en << THERMAL_OTST1_RAMP_CTRL_SHIFT);
+ mask = THERMAL_OTST1_RAMP_CTRL_MASK;
+ if (led->pdata->thermal_derate_slow >= 0) {
+ val |= (led->pdata->thermal_derate_slow <<
+ THERMAL_DERATE_SLOW_SHIFT);
+ mask |= THERMAL_DERATE_SLOW_MASK;
+ }
+
+ if (led->pdata->thermal_derate_fast >= 0) {
+ val |= led->pdata->thermal_derate_fast;
+ mask |= THERMAL_DERATE_FAST_MASK;
+ }
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_RMP_DN_RATE(led->base),
+ mask, val);
+ if (rc < 0)
+ return rc;
+
+ if (led->pdata->thermal_debounce >= 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_DEBOUNCE(led->base),
+ FLASH_LED_THERMAL_DEBOUNCE_MASK,
+ led->pdata->thermal_debounce);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->thermal_hysteresis >= 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_HYSTERESIS(led->base),
+ FLASH_LED_THERMAL_HYSTERESIS_MASK,
+ led->pdata->thermal_hysteresis);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->thermal_thrsh1 >= 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH1(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ led->pdata->thermal_thrsh1);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->thermal_thrsh2 >= 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH2(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ led->pdata->thermal_thrsh2);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->thermal_thrsh3 >= 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH3(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ led->pdata->thermal_thrsh3);
+ if (rc < 0)
+ return rc;
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
+{
+ int rc;
+ u8 val = 0;
+
+ rc = qpnp_flash_led_headroom_config(led);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_strobe_config(led);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_write(led,
+ FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(led->base),
+ val);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_ISC_DELAY(led->base),
+ FLASH_LED_ISC_WARMUP_DELAY_MASK,
+ led->pdata->isc_delay);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_WARMUP_DELAY(led->base),
+ FLASH_LED_ISC_WARMUP_DELAY_MASK,
+ led->pdata->warmup_delay);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_CURRENT_DERATE_EN(led->base),
+ FLASH_LED_CURRENT_DERATE_EN_MASK,
+ led->pdata->current_derate_en_cfg);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_thermal_config(led);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_VPH_DROOP_DEBOUNCE(led->base),
+ FLASH_LED_VPH_DROOP_DEBOUNCE_MASK,
+ led->pdata->vph_droop_debounce);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
+ FLASH_LED_VPH_DROOP_THRESHOLD_MASK,
+ led->pdata->vph_droop_threshold);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
+ FLASH_LED_VPH_DROOP_HYSTERESIS_MASK,
+ led->pdata->vph_droop_hysteresis);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SEL(led->base),
+ FLASH_LED_LMH_MITIGATION_SEL_MASK,
+ led->pdata->lmh_mitigation_sel);
+ if (rc < 0)
+ return rc;
+
+ val = led->pdata->chgr_mitigation_sel
+ << FLASH_LED_CHGR_MITIGATION_SEL_SHIFT;
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SEL(led->base),
+ FLASH_LED_CHGR_MITIGATION_SEL_MASK,
+ val);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LMH_LEVEL(led->base),
+ FLASH_LED_LMH_LEVEL_MASK,
+ led->pdata->lmh_level);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_ILED_GRT_THRSH(led->base),
+ FLASH_LED_ILED_GRT_THRSH_MASK,
+ led->pdata->iled_thrsh_val);
+ if (rc < 0)
+ return rc;
+
+ if (led->pdata->led1n2_iclamp_low_ma) {
+ val = get_current_reg_code(led->pdata->led1n2_iclamp_low_ma,
+ led->fnode[LED1].ires_ua);
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base),
+ FLASH_LED_CURRENT_MASK, val);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->led1n2_iclamp_mid_ma) {
+ val = get_current_reg_code(led->pdata->led1n2_iclamp_mid_ma,
+ led->fnode[LED1].ires_ua);
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base),
+ FLASH_LED_CURRENT_MASK, val);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->led3_iclamp_low_ma) {
+ val = get_current_reg_code(led->pdata->led3_iclamp_low_ma,
+ led->fnode[LED3].ires_ua);
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LED3_ICLAMP_LOW(led->base),
+ FLASH_LED_CURRENT_MASK, val);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->led3_iclamp_mid_ma) {
+ val = get_current_reg_code(led->pdata->led3_iclamp_mid_ma,
+ led->fnode[LED3].ires_ua);
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LED3_ICLAMP_MID(led->base),
+ FLASH_LED_CURRENT_MASK, val);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->pdata->hw_strobe_option > 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_STROBE_CFG(led->base),
+ FLASH_LED_STROBE_MASK,
+ led->pdata->hw_strobe_option);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode,
+ int hw_strobe_option, bool on)
+{
+ int rc = 0;
+
+ /*
+ * If the LED controlled by this fnode is not GPIO controlled
+ * for the given strobe_option, return.
+ */
+ if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_1)
+ return 0;
+ else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_2
+ && fnode->id != LED3)
+ return 0;
+ else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_3
+ && fnode->id == LED1)
+ return 0;
+
+ if (gpio_is_valid(fnode->hw_strobe_gpio)) {
+ gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0);
+ } else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active &&
+ fnode->hw_strobe_state_suspend) {
+ rc = pinctrl_select_state(fnode->strobe_pinctrl,
+ on ? fnode->hw_strobe_state_active :
+ fnode->hw_strobe_state_suspend);
+ if (rc < 0) {
+ pr_err("failed to change hw strobe pin state\n");
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led,
+ struct flash_switch_data *snode, bool on)
+{
+ int rc = 0;
+
+ if (!snode || !snode->vreg)
+ return 0;
+
+ if (snode->regulator_on == on)
+ return 0;
+
+ if (on)
+ rc = regulator_enable(snode->vreg);
+ else
+ rc = regulator_disable(snode->vreg);
+
+ if (rc < 0) {
+ pr_err("regulator_%s failed, rc=%d\n",
+ on ? "enable" : "disable", rc);
+ return rc;
+ }
+
+ snode->regulator_on = on ? true : false;
+ return 0;
+}
+
+static int get_property_from_fg(struct qpnp_flash_led *led,
+ enum power_supply_property prop, int *val)
+{
+ int rc;
+ union power_supply_propval pval = {0, };
+
+ if (!led->bms_psy) {
+ pr_err("no bms psy found\n");
+ return -EINVAL;
+ }
+
+ rc = power_supply_get_property(led->bms_psy, prop, &pval);
+ if (rc) {
+ pr_err("bms psy doesn't support reading prop %d rc = %d\n",
+ prop, rc);
+ return rc;
+ }
+
+ *val = pval.intval;
+ return rc;
+}
+
+#define VOLTAGE_HDRM_DEFAULT_MV 350
+static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
+{
+ int i, voltage_hdrm_mv = 0, voltage_hdrm_max = 0;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (led->fnode[i].led_on) {
+ if (led->fnode[i].id < 2) {
+ if (led->fnode[i].current_ma < 750)
+ voltage_hdrm_mv = 125;
+ else if (led->fnode[i].current_ma < 1000)
+ voltage_hdrm_mv = 175;
+ else if (led->fnode[i].current_ma < 1250)
+ voltage_hdrm_mv = 250;
+ else
+ voltage_hdrm_mv = 350;
+ } else {
+ if (led->fnode[i].current_ma < 375)
+ voltage_hdrm_mv = 125;
+ else if (led->fnode[i].current_ma < 500)
+ voltage_hdrm_mv = 175;
+ else if (led->fnode[i].current_ma < 625)
+ voltage_hdrm_mv = 250;
+ else
+ voltage_hdrm_mv = 350;
+ }
+
+ voltage_hdrm_max = max(voltage_hdrm_max,
+ voltage_hdrm_mv);
+ }
+ }
+
+ if (!voltage_hdrm_max)
+ return VOLTAGE_HDRM_DEFAULT_MV;
+
+ return voltage_hdrm_max;
+}
+
+#define UCONV 1000000LL
+#define MCONV 1000LL
+#define FLASH_VDIP_MARGIN 50000
+#define BOB_EFFICIENCY 900LL
+#define VIN_FLASH_MIN_UV 3300000LL
+static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led,
+ int *max_current)
+{
+ int ocv_uv, ibat_now, voltage_hdrm_mv, rc;
+ int rbatt_uohm = 0;
+ int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
+ int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
+
+ /* RESISTANCE = esr_uohm + rslow_uohm */
+ rc = get_property_from_fg(led, POWER_SUPPLY_PROP_RESISTANCE,
+ &rbatt_uohm);
+ if (rc < 0) {
+ pr_err("bms psy does not support resistance, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* If no battery is connected, return max possible flash current */
+ if (!rbatt_uohm) {
+ *max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
+ return 0;
+ }
+
+ rc = get_property_from_fg(led, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv);
+ if (rc < 0) {
+ pr_err("bms psy does not support OCV, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = get_property_from_fg(led, POWER_SUPPLY_PROP_CURRENT_NOW,
+ &ibat_now);
+ if (rc < 0) {
+ pr_err("bms psy does not support current, rc=%d\n", rc);
+ return rc;
+ }
+
+ rbatt_uohm += led->pdata->rpara_uohm;
+ voltage_hdrm_mv = qpnp_flash_led_get_voltage_headroom(led);
+ vph_flash_vdip =
+ VPH_DROOP_THRESH_VAL_TO_UV(led->pdata->vph_droop_threshold)
+ + FLASH_VDIP_MARGIN;
+
+ /* Check if LMH_MITIGATION needs to be triggered */
+ if (!led->trigger_lmh && (ocv_uv < led->pdata->lmh_ocv_threshold_uv ||
+ rbatt_uohm > led->pdata->lmh_rbatt_threshold_uohm)) {
+ led->trigger_lmh = true;
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_LMH_MITIGATION_EN_MASK,
+ FLASH_LED_LMH_MITIGATION_ENABLE);
+ if (rc < 0) {
+ pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Wait for LMH mitigation to take effect */
+ udelay(100);
+
+ return qpnp_flash_led_calc_max_current(led, max_current);
+ }
+
+ /*
+ * Calculate the maximum current that can pulled out of the battery
+ * before the battery voltage dips below a safe threshold.
+ */
+ ibat_safe_ua = div_s64((ocv_uv - vph_flash_vdip) * UCONV,
+ rbatt_uohm);
+
+ if (ibat_safe_ua <= led->pdata->ibatt_ocp_threshold_ua) {
+ /*
+ * If the calculated current is below the OCP threshold, then
+ * use it as the possible flash current.
+ */
+ ibat_flash_ua = ibat_safe_ua - ibat_now;
+ vph_flash_uv = vph_flash_vdip;
+ } else {
+ /*
+ * If the calculated current is above the OCP threshold, then
+ * use the ocp threshold instead.
+ *
+ * Any higher current will be tripping the battery OCP.
+ */
+ ibat_flash_ua = led->pdata->ibatt_ocp_threshold_ua - ibat_now;
+ vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm
+ * led->pdata->ibatt_ocp_threshold_ua, UCONV);
+ }
+ /* Calculate the input voltage of the flash module. */
+ vin_flash_uv = max((led->pdata->vled_max_uv +
+ (voltage_hdrm_mv * MCONV)), VIN_FLASH_MIN_UV);
+ /* Calculate the available power for the flash module. */
+ avail_flash_power_fw = BOB_EFFICIENCY * vph_flash_uv * ibat_flash_ua;
+ /*
+ * Calculate the available amount of current the flash module can draw
+ * before collapsing the battery. (available power/ flash input voltage)
+ */
+ avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
+ pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n",
+ avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh);
+ *max_current = min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
+ (int)(div64_s64(avail_flash_ua, MCONV)));
+ return 0;
+}
+
+static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led,
+ int *thermal_current_lim)
+{
+ int rc;
+ u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
+
+ /* Store THERMAL_THRSHx register values */
+ rc = qpnp_flash_led_masked_read(led,
+ FLASH_LED_REG_THERMAL_THRSH1(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ &thermal_thrsh1);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_read(led,
+ FLASH_LED_REG_THERMAL_THRSH2(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ &thermal_thrsh2);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_read(led,
+ FLASH_LED_REG_THERMAL_THRSH3(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ &thermal_thrsh3);
+ if (rc < 0)
+ return rc;
+
+ /* Lower THERMAL_THRSHx thresholds to minimum */
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH1(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ FLASH_LED_THERMAL_THRSH_MIN);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH2(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ FLASH_LED_THERMAL_THRSH_MIN);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH3(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ FLASH_LED_THERMAL_THRSH_MIN);
+ if (rc < 0)
+ return rc;
+
+ /* Check THERMAL_OTST status */
+ rc = qpnp_flash_led_read(led,
+ FLASH_LED_REG_LED_STATUS2(led->base),
+ &otst_status);
+ if (rc < 0)
+ return rc;
+
+ /* Look up current limit based on THERMAL_OTST status */
+ if (otst_status)
+ *thermal_current_lim =
+ led->pdata->thermal_derate_current[otst_status >> 1];
+
+ /* Restore THERMAL_THRESHx registers to original values */
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH1(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ thermal_thrsh1);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH2(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ thermal_thrsh2);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH3(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ thermal_thrsh3);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led,
+ int *max_avail_current)
+{
+ int thermal_current_lim = 0, rc;
+
+ led->trigger_lmh = false;
+ rc = qpnp_flash_led_calc_max_current(led, max_avail_current);
+ if (rc < 0) {
+ pr_err("Couldn't calculate max_avail_current, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->thermal_derate_en) {
+ rc = qpnp_flash_led_calc_thermal_current_lim(led,
+ &thermal_current_lim);
+ if (rc < 0) {
+ pr_err("Couldn't calculate thermal_current_lim, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ if (thermal_current_lim)
+ *max_avail_current = min(*max_avail_current,
+ thermal_current_lim);
+
+ return 0;
+}
+
+static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
+
+ if (fnode->current_ma)
+ led->total_current_ma += fnode->current_ma
+ - fnode->prev_current_ma;
+ else
+ led->total_current_ma -= fnode->prev_current_ma;
+
+ fnode->prev_current_ma = fnode->current_ma;
+}
+
+static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
+{
+ int i = 0;
+ int prgm_current_ma = value;
+ int min_ma = fnode->ires_ua / 1000;
+ struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
+
+ if (value <= 0)
+ prgm_current_ma = 0;
+ else if (value < min_ma)
+ prgm_current_ma = min_ma;
+
+ fnode->ires_idx = fnode->default_ires_idx;
+ fnode->ires_ua = fnode->default_ires_ua;
+
+ prgm_current_ma = min(prgm_current_ma, fnode->max_current);
+ if (prgm_current_ma > max_ires_curr_ma_table[fnode->ires_idx]) {
+ /* find the matching ires */
+ for (i = MAX_IRES_LEVELS - 1; i >= 0; i--) {
+ if (prgm_current_ma <= max_ires_curr_ma_table[i]) {
+ fnode->ires_idx = i;
+ fnode->ires_ua = FLASH_LED_IRES_MIN_UA +
+ (FLASH_LED_IRES_BASE - fnode->ires_idx) *
+ FLASH_LED_IRES_DIVISOR;
+ break;
+ }
+ }
+ }
+ fnode->current_ma = prgm_current_ma;
+ fnode->cdev.brightness = prgm_current_ma;
+ fnode->current_reg_val = get_current_reg_code(prgm_current_ma,
+ fnode->ires_ua);
+ if (prgm_current_ma)
+ fnode->led_on = true;
+
+ if (led->pdata->chgr_mitigation_sel == FLASH_SW_CHARGER_MITIGATION) {
+ qpnp_flash_led_aggregate_max_current(fnode);
+ led->trigger_chgr = false;
+ if (led->total_current_ma >= 1000)
+ led->trigger_chgr = true;
+ }
+}
+
+static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+ int i, rc, addr_offset;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_EN_LED_CTRL(led->base),
+ snode->led_mask, FLASH_LED_DISABLE);
+ if (rc < 0)
+ return rc;
+
+ if (led->trigger_lmh) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_LMH_MITIGATION_EN_MASK,
+ FLASH_LED_LMH_MITIGATION_DISABLE);
+ if (rc < 0) {
+ pr_err("disable lmh mitigation failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (!led->trigger_chgr) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_CHGR_MITIGATION_EN_MASK,
+ FLASH_LED_CHGR_MITIGATION_DISABLE);
+ if (rc < 0) {
+ pr_err("disable chgr mitigation failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ led->enable--;
+ if (led->enable == 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MOD_CTRL(led->base),
+ FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE);
+ if (rc < 0)
+ return rc;
+ }
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (!led->fnode[i].led_on ||
+ !(snode->led_mask & BIT(led->fnode[i].id)))
+ continue;
+
+ addr_offset = led->fnode[i].id;
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
+ FLASH_LED_CURRENT_MASK, 0);
+ if (rc < 0)
+ return rc;
+
+ led->fnode[i].led_on = false;
+
+ if (led->fnode[i].strobe_sel == HW_STROBE) {
+ rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
+ led->pdata->hw_strobe_option, false);
+ if (rc < 0) {
+ pr_err("Unable to disable hw strobe, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+ }
+
+ if (snode->led_en_pinctrl) {
+ pr_debug("Selecting suspend state for %s\n", snode->cdev.name);
+ rc = pinctrl_select_state(snode->led_en_pinctrl,
+ snode->gpio_state_suspend);
+ if (rc < 0) {
+ pr_err("failed to select pinctrl suspend state rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ snode->enabled = false;
+ return 0;
+}
+
+static int qpnp_flash_led_symmetry_config(struct flash_switch_data *snode)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+ int i, total_curr_ma = 0, num_leds = 0, prgm_current_ma;
+ enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (snode->led_mask & BIT(led->fnode[i].id)) {
+ if (led->fnode[i].type == FLASH_LED_TYPE_FLASH &&
+ led->fnode[i].led_on)
+ type = FLASH_LED_TYPE_FLASH;
+
+ if (led->fnode[i].type == FLASH_LED_TYPE_TORCH &&
+ led->fnode[i].led_on)
+ type = FLASH_LED_TYPE_TORCH;
+ }
+ }
+
+ if (type == FLASH_LED_TYPE_UNKNOWN) {
+ pr_err("Incorrect type possibly because of no active LEDs\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if ((snode->led_mask & BIT(led->fnode[i].id)) &&
+ (led->fnode[i].type == type)) {
+ total_curr_ma += led->fnode[i].current_ma;
+ num_leds++;
+ }
+ }
+
+ if (num_leds > 0 && total_curr_ma > 0) {
+ prgm_current_ma = total_curr_ma / num_leds;
+ } else {
+ pr_err("Incorrect configuration, num_leds: %d total_curr_ma: %d\n",
+ num_leds, total_curr_ma);
+ return -EINVAL;
+ }
+
+ if (prgm_current_ma == 0) {
+ pr_warn("prgm_curr_ma cannot be 0\n");
+ return 0;
+ }
+
+ pr_debug("num_leds: %d total: %d prgm_curr_ma: %d\n", num_leds,
+ total_curr_ma, prgm_current_ma);
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (snode->led_mask & BIT(led->fnode[i].id) &&
+ led->fnode[i].current_ma != prgm_current_ma &&
+ led->fnode[i].type == type) {
+ qpnp_flash_led_node_set(&led->fnode[i],
+ prgm_current_ma);
+ pr_debug("%s LED %d current: %d code: %d ires_ua: %d\n",
+ (type == FLASH_LED_TYPE_FLASH) ?
+ "flash" : "torch",
+ led->fnode[i].id, prgm_current_ma,
+ led->fnode[i].current_reg_val,
+ led->fnode[i].ires_ua);
+ }
+ }
+
+ return 0;
+}
+
+static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+ int rc, i, addr_offset;
+ u8 val, mask;
+
+ if (snode->enabled == on) {
+ pr_debug("Switch node is already %s!\n",
+ on ? "enabled" : "disabled");
+ return 0;
+ }
+
+ if (!on) {
+ rc = qpnp_flash_led_switch_disable(snode);
+ return rc;
+ }
+
+ /* Iterate over all active leds for this switch node */
+ if (snode->symmetry_en) {
+ rc = qpnp_flash_led_symmetry_config(snode);
+ if (rc < 0) {
+ pr_err("Failed to configure current symmetrically, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ val = 0;
+ for (i = 0; i < led->num_fnodes; i++)
+ if (led->fnode[i].led_on &&
+ snode->led_mask & BIT(led->fnode[i].id))
+ val |= led->fnode[i].ires_idx << (led->fnode[i].id * 2);
+
+ rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base),
+ FLASH_LED_CURRENT_MASK, val);
+ if (rc < 0)
+ return rc;
+
+ val = 0;
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (!led->fnode[i].led_on ||
+ !(snode->led_mask & BIT(led->fnode[i].id)))
+ continue;
+
+ addr_offset = led->fnode[i].id;
+ if (led->fnode[i].strobe_sel == SW_STROBE)
+ mask = FLASH_LED_HW_SW_STROBE_SEL_BIT;
+ else
+ mask = FLASH_HW_STROBE_MASK;
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
+ mask, led->fnode[i].strobe_ctrl);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
+ FLASH_LED_CURRENT_MASK, led->fnode[i].current_reg_val);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_write(led,
+ FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset),
+ led->fnode[i].duration);
+ if (rc < 0)
+ return rc;
+
+ val |= FLASH_LED_ENABLE << led->fnode[i].id;
+
+ if (led->fnode[i].strobe_sel == HW_STROBE) {
+ rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
+ led->pdata->hw_strobe_option, true);
+ if (rc < 0) {
+ pr_err("Unable to enable hw strobe rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+ }
+
+ if (snode->led_en_pinctrl) {
+ pr_debug("Selecting active state for %s\n", snode->cdev.name);
+ rc = pinctrl_select_state(snode->led_en_pinctrl,
+ snode->gpio_state_active);
+ if (rc < 0) {
+ pr_err("failed to select pinctrl active state rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ if (led->enable == 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MOD_CTRL(led->base),
+ FLASH_LED_MOD_CTRL_MASK, FLASH_LED_MOD_ENABLE);
+ if (rc < 0)
+ return rc;
+ }
+ led->enable++;
+
+ if (led->trigger_lmh) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_LMH_MITIGATION_EN_MASK,
+ FLASH_LED_LMH_MITIGATION_ENABLE);
+ if (rc < 0) {
+ pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
+ return rc;
+ }
+ /* Wait for LMH mitigation to take effect */
+ udelay(500);
+ }
+
+ if (led->trigger_chgr) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_CHGR_MITIGATION_EN_MASK,
+ FLASH_LED_CHGR_MITIGATION_ENABLE);
+ if (rc < 0) {
+ pr_err("trigger chgr mitigation failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_EN_LED_CTRL(led->base),
+ snode->led_mask, val);
+ if (rc < 0)
+ return rc;
+
+ snode->enabled = true;
+ return 0;
+}
+
+int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+ int *max_current)
+{
+ struct led_classdev *led_cdev;
+ struct flash_switch_data *snode;
+ struct qpnp_flash_led *led;
+ int rc;
+
+ if (!trig) {
+ pr_err("Invalid led_trigger provided\n");
+ return -EINVAL;
+ }
+
+ led_cdev = trigger_to_lcdev(trig);
+ if (!led_cdev) {
+ pr_err("Invalid led_cdev in trigger %s\n", trig->name);
+ return -EINVAL;
+ }
+
+ snode = container_of(led_cdev, struct flash_switch_data, cdev);
+ led = dev_get_drvdata(&snode->pdev->dev);
+
+ if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
+ pr_err("Invalid options %d\n", options);
+ return -EINVAL;
+ }
+
+ if (options & ENABLE_REGULATOR) {
+ rc = qpnp_flash_led_regulator_enable(led, snode, true);
+ if (rc < 0) {
+ pr_err("enable regulator failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (options & DISABLE_REGULATOR) {
+ rc = qpnp_flash_led_regulator_enable(led, snode, false);
+ if (rc < 0) {
+ pr_err("disable regulator failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (options & QUERY_MAX_AVAIL_CURRENT) {
+ rc = qpnp_flash_led_get_max_avail_current(led, max_current);
+ if (rc < 0) {
+ pr_err("query max current failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct flash_node_data *fnode = NULL;
+ struct flash_switch_data *snode = NULL;
+ struct qpnp_flash_led *led = NULL;
+ int rc;
+
+ /*
+ * strncmp() must be used here since a prefix comparison is required
+ * in order to support names like led:switch_0 and led:flash_1.
+ */
+ if (!strncmp(led_cdev->name, "led:switch", strlen("led:switch"))) {
+ snode = container_of(led_cdev, struct flash_switch_data, cdev);
+ led = dev_get_drvdata(&snode->pdev->dev);
+ } else if (!strncmp(led_cdev->name, "led:flash", strlen("led:flash")) ||
+ !strncmp(led_cdev->name, "led:torch",
+ strlen("led:torch"))) {
+ fnode = container_of(led_cdev, struct flash_node_data, cdev);
+ led = dev_get_drvdata(&fnode->pdev->dev);
+ }
+
+ if (!led) {
+ pr_err("Failed to get flash driver data\n");
+ return;
+ }
+
+ spin_lock(&led->lock);
+ if (snode) {
+ rc = qpnp_flash_led_switch_set(snode, value > 0);
+ if (rc < 0)
+ pr_err("Failed to set flash LED switch rc=%d\n", rc);
+ } else if (fnode) {
+ qpnp_flash_led_node_set(fnode, value);
+ }
+
+ spin_unlock(&led->lock);
+}
+
+/* sysfs show function for flash_max_current */
+static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int rc, max_current = 0;
+ struct flash_switch_data *snode;
+ struct qpnp_flash_led *led;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ snode = container_of(led_cdev, struct flash_switch_data, cdev);
+ led = dev_get_drvdata(&snode->pdev->dev);
+
+ rc = qpnp_flash_led_get_max_avail_current(led, &max_current);
+ if (rc < 0)
+ pr_err("query max current failed, rc=%d\n", rc);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", max_current);
+}
+
+/* sysfs attributes exported by flash_led */
+static struct device_attribute qpnp_flash_led_attrs[] = {
+ __ATTR(max_current, 0664, qpnp_flash_led_max_current_show, NULL),
+};
+
+static int flash_led_psy_notifier_call(struct notifier_block *nb,
+ unsigned long ev, void *v)
+{
+ struct power_supply *psy = v;
+ struct qpnp_flash_led *led =
+ container_of(nb, struct qpnp_flash_led, nb);
+
+ if (ev != PSY_EVENT_PROP_CHANGED)
+ return NOTIFY_OK;
+
+ if (!strcmp(psy->desc->name, "bms")) {
+ led->bms_psy = power_supply_get_by_name("bms");
+ if (!led->bms_psy)
+ pr_err("Failed to get bms power_supply\n");
+ else
+ power_supply_unreg_notifier(&led->nb);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int flash_led_psy_register_notifier(struct qpnp_flash_led *led)
+{
+ int rc;
+
+ led->nb.notifier_call = flash_led_psy_notifier_call;
+ rc = power_supply_reg_notifier(&led->nb);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier, rc = %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/* irq handler */
+static irqreturn_t qpnp_flash_led_irq_handler(int irq, void *_led)
+{
+ struct qpnp_flash_led *led = _led;
+ enum flash_led_irq_type irq_type = INVALID_IRQ;
+ int rc;
+ u8 irq_status, led_status1, led_status2;
+
+ pr_debug("irq received, irq=%d\n", irq);
+
+ rc = qpnp_flash_led_read(led,
+ FLASH_LED_REG_INT_RT_STS(led->base), &irq_status);
+ if (rc < 0) {
+ pr_err("Failed to read interrupt status reg, rc=%d\n", rc);
+ goto exit;
+ }
+
+ if (irq == led->pdata->all_ramp_up_done_irq)
+ irq_type = ALL_RAMP_UP_DONE_IRQ;
+ else if (irq == led->pdata->all_ramp_down_done_irq)
+ irq_type = ALL_RAMP_DOWN_DONE_IRQ;
+ else if (irq == led->pdata->led_fault_irq)
+ irq_type = LED_FAULT_IRQ;
+
+ if (irq_type == ALL_RAMP_UP_DONE_IRQ)
+ atomic_notifier_call_chain(&irq_notifier_list,
+ irq_type, NULL);
+
+ if (irq_type == LED_FAULT_IRQ) {
+ rc = qpnp_flash_led_read(led,
+ FLASH_LED_REG_LED_STATUS1(led->base), &led_status1);
+ if (rc < 0) {
+ pr_err("Failed to read led_status1 reg, rc=%d\n", rc);
+ goto exit;
+ }
+
+ rc = qpnp_flash_led_read(led,
+ FLASH_LED_REG_LED_STATUS2(led->base), &led_status2);
+ if (rc < 0) {
+ pr_err("Failed to read led_status2 reg, rc=%d\n", rc);
+ goto exit;
+ }
+
+ if (led_status1)
+ pr_emerg("led short/open fault detected! led_status1=%x\n",
+ led_status1);
+
+ if (led_status2 & FLASH_LED_VPH_DROOP_FAULT_MASK)
+ pr_emerg("led vph_droop fault detected!\n");
+ }
+
+ pr_debug("irq handled, irq_type=%x, irq_status=%x\n", irq_type,
+ irq_status);
+
+exit:
+ return IRQ_HANDLED;
+}
+
+int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&irq_notifier_list, nb);
+}
+
+int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&irq_notifier_list, nb);
+}
+
+static inline u8 get_safety_timer_code(u32 duration_ms)
+{
+ if (!duration_ms)
+ return 0;
+
+ return (duration_ms / 10) - 1;
+}
+
+static inline u8 get_vph_droop_thresh_code(u32 val_mv)
+{
+ if (!val_mv)
+ return 0;
+
+ return (val_mv / 100) - 25;
+}
+
+static int qpnp_flash_led_parse_hw_strobe_dt(struct flash_node_data *fnode)
+{
+ struct device_node *node = fnode->cdev.dev->of_node;
+
+ if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
+ fnode->hw_strobe_gpio = of_get_named_gpio(node,
+ "qcom,hw-strobe-gpio", 0);
+ if (fnode->hw_strobe_gpio < 0) {
+ pr_err("Invalid gpio specified\n");
+ return fnode->hw_strobe_gpio;
+ }
+
+ gpio_direction_output(fnode->hw_strobe_gpio, 0);
+ } else if (fnode->strobe_pinctrl) {
+ fnode->hw_strobe_gpio = -1;
+ fnode->hw_strobe_state_active =
+ pinctrl_lookup_state(fnode->strobe_pinctrl,
+ "strobe_enable");
+ if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) {
+ pr_err("No active pin for hardware strobe, rc=%ld\n",
+ PTR_ERR(fnode->hw_strobe_state_active));
+ fnode->hw_strobe_state_active = NULL;
+ }
+
+ fnode->hw_strobe_state_suspend =
+ pinctrl_lookup_state(fnode->strobe_pinctrl,
+ "strobe_disable");
+ if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) {
+ pr_err("No suspend pin for hardware strobe, rc=%ld\n",
+ PTR_ERR(fnode->hw_strobe_state_suspend));
+ fnode->hw_strobe_state_suspend = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int qpnp_flash_led_parse_strobe_sel_dt(struct qpnp_flash_led *led,
+ struct flash_node_data *fnode,
+ struct device_node *node)
+{
+ int rc;
+ u32 val;
+ u8 hw_strobe = 0, edge_trigger = 0, active_high = 0;
+
+ fnode->strobe_sel = SW_STROBE;
+ rc = of_property_read_u32(node, "qcom,strobe-sel", &val);
+ if (rc < 0) {
+ if (rc != -EINVAL) {
+ pr_err("Unable to read qcom,strobe-sel property\n");
+ return rc;
+ }
+ } else {
+ if (val < SW_STROBE || val > LPG_STROBE) {
+ pr_err("Incorrect strobe selection specified %d\n",
+ val);
+ return -EINVAL;
+ }
+ fnode->strobe_sel = (u8)val;
+ }
+
+ /*
+ * LPG strobe is allowed only for LED3 and HW strobe option should be
+ * option 2 or 3.
+ */
+ if (fnode->strobe_sel == LPG_STROBE) {
+ if (led->pdata->hw_strobe_option ==
+ FLASH_LED_HW_STROBE_OPTION_1) {
+ pr_err("Incorrect strobe option for LPG strobe\n");
+ return -EINVAL;
+ }
+ if (fnode->id != LED3) {
+ pr_err("Incorrect LED chosen for LPG strobe\n");
+ return -EINVAL;
+ }
+ }
+
+ if (fnode->strobe_sel == HW_STROBE) {
+ edge_trigger = of_property_read_bool(node,
+ "qcom,hw-strobe-edge-trigger");
+ active_high = !of_property_read_bool(node,
+ "qcom,hw-strobe-active-low");
+ hw_strobe = 1;
+ } else if (fnode->strobe_sel == LPG_STROBE) {
+ /* LPG strobe requires level trigger and active high */
+ edge_trigger = 0;
+ active_high = 1;
+ hw_strobe = 1;
+ }
+
+ fnode->strobe_ctrl = (hw_strobe << 2) | (edge_trigger << 1) |
+ active_high;
+
+ return 0;
+}
+
+static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
+ struct flash_node_data *fnode, struct device_node *node)
+{
+ const char *temp_string;
+ int rc, min_ma;
+ u32 val;
+
+ fnode->pdev = led->pdev;
+ fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
+ fnode->cdev.brightness_get = qpnp_flash_led_brightness_get;
+
+ rc = of_property_read_string(node, "qcom,led-name", &fnode->cdev.name);
+ if (rc < 0) {
+ pr_err("Unable to read flash LED names\n");
+ return rc;
+ }
+
+ rc = of_property_read_string(node, "label", &temp_string);
+ if (!rc) {
+ if (!strcmp(temp_string, "flash")) {
+ fnode->type = FLASH_LED_TYPE_FLASH;
+ } else if (!strcmp(temp_string, "torch")) {
+ fnode->type = FLASH_LED_TYPE_TORCH;
+ } else {
+ pr_err("Wrong flash LED type\n");
+ return rc;
+ }
+ } else {
+ pr_err("Unable to read flash LED label\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,id", &val);
+ if (!rc) {
+ fnode->id = (u8)val;
+ } else {
+ pr_err("Unable to read flash LED ID\n");
+ return rc;
+ }
+
+ rc = of_property_read_string(node, "qcom,default-led-trigger",
+ &fnode->cdev.default_trigger);
+ if (rc < 0) {
+ pr_err("Unable to read trigger name\n");
+ return rc;
+ }
+
+ fnode->default_ires_ua = fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA;
+ fnode->default_ires_idx = fnode->ires_idx = FLASH_LED_IRES_DEFAULT_VAL;
+ rc = of_property_read_u32(node, "qcom,ires-ua", &val);
+ if (!rc) {
+ fnode->default_ires_ua = fnode->ires_ua = val;
+ fnode->default_ires_idx = fnode->ires_idx =
+ FLASH_LED_IRES_BASE - (val - FLASH_LED_IRES_MIN_UA) /
+ FLASH_LED_IRES_DIVISOR;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read current resolution rc=%d\n", rc);
+ return rc;
+ }
+
+ min_ma = fnode->ires_ua / 1000;
+ rc = of_property_read_u32(node, "qcom,max-current", &val);
+ if (!rc) {
+ if (val < min_ma)
+ val = min_ma;
+ fnode->max_current = val;
+ fnode->cdev.max_brightness = val;
+ } else {
+ pr_err("Unable to read max current, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,current-ma", &val);
+ if (!rc) {
+ if (val < min_ma || val > fnode->max_current)
+ pr_warn("Invalid operational current specified, capping it\n");
+ if (val < min_ma)
+ val = min_ma;
+ if (val > fnode->max_current)
+ val = fnode->max_current;
+ fnode->current_ma = val;
+ fnode->cdev.brightness = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read operational current, rc=%d\n", rc);
+ return rc;
+ }
+
+ fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED;
+ rc = of_property_read_u32(node, "qcom,duration-ms", &val);
+ if (!rc) {
+ fnode->duration = get_safety_timer_code(val);
+ if (fnode->duration)
+ fnode->duration |= FLASH_LED_SAFETY_TMR_ENABLE;
+ } else if (rc == -EINVAL) {
+ if (fnode->type == FLASH_LED_TYPE_FLASH) {
+ pr_err("Timer duration is required for flash LED\n");
+ return rc;
+ }
+ } else {
+ pr_err("Unable to read timer duration\n");
+ return rc;
+ }
+
+ fnode->hdrm_val = FLASH_LED_HDRM_VOL_DEFAULT_MV;
+ rc = of_property_read_u32(node, "qcom,hdrm-voltage-mv", &val);
+ if (!rc) {
+ val = (val - FLASH_LED_HDRM_VOL_BASE_MV) /
+ FLASH_LED_HDRM_VOL_STEP_MV;
+ fnode->hdrm_val = (val << FLASH_LED_HDRM_VOL_SHIFT) &
+ FLASH_LED_HDRM_VOL_MASK;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read headroom voltage\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,hdrm-vol-hi-lo-win-mv", &val);
+ if (!rc) {
+ fnode->hdrm_val |= (val / FLASH_LED_HDRM_VOL_STEP_MV) &
+ ~FLASH_LED_HDRM_VOL_MASK;
+ } else if (rc == -EINVAL) {
+ fnode->hdrm_val |= FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV;
+ } else {
+ pr_err("Unable to read hdrm hi-lo window voltage\n");
+ return rc;
+ }
+
+ rc = qpnp_flash_led_parse_strobe_sel_dt(led, fnode, node);
+ if (rc < 0)
+ return rc;
+
+ rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
+ if (rc < 0) {
+ pr_err("Unable to register led node %d\n", fnode->id);
+ return rc;
+ }
+
+ fnode->cdev.dev->of_node = node;
+ fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev);
+ if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) {
+ pr_debug("No pinctrl defined for %s, err=%ld\n",
+ fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl));
+ fnode->strobe_pinctrl = NULL;
+ }
+
+ if (fnode->strobe_sel == HW_STROBE)
+ return qpnp_flash_led_parse_hw_strobe_dt(fnode);
+
+ return 0;
+}
+
+static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
+ struct flash_switch_data *snode,
+ struct device_node *node)
+{
+ int rc = 0, num;
+ char reg_name[16], reg_sup_name[16];
+
+ rc = of_property_read_string(node, "qcom,led-name", &snode->cdev.name);
+ if (rc < 0) {
+ pr_err("Failed to read switch node name, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = sscanf(snode->cdev.name, "led:switch_%d", &num);
+ if (!rc) {
+ pr_err("No number for switch device?\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_string(node, "qcom,default-led-trigger",
+ &snode->cdev.default_trigger);
+ if (rc < 0) {
+ pr_err("Unable to read trigger name, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask);
+ if (rc < 0) {
+ pr_err("Unable to read led mask rc=%d\n", rc);
+ return rc;
+ }
+
+ snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
+
+ if (snode->led_mask < 1 || snode->led_mask > 7) {
+ pr_err("Invalid value for led-mask\n");
+ return -EINVAL;
+ }
+
+ scnprintf(reg_name, sizeof(reg_name), "switch%d-supply", num);
+ if (of_find_property(led->pdev->dev.of_node, reg_name, NULL)) {
+ scnprintf(reg_sup_name, sizeof(reg_sup_name), "switch%d", num);
+ snode->vreg = devm_regulator_get(&led->pdev->dev, reg_sup_name);
+ if (IS_ERR_OR_NULL(snode->vreg)) {
+ rc = PTR_ERR(snode->vreg);
+ if (rc != -EPROBE_DEFER)
+ pr_err("Failed to get regulator, rc=%d\n", rc);
+ snode->vreg = NULL;
+ return rc;
+ }
+ }
+
+ snode->pdev = led->pdev;
+ snode->cdev.brightness_set = qpnp_flash_led_brightness_set;
+ snode->cdev.brightness_get = qpnp_flash_led_brightness_get;
+ snode->cdev.flags |= LED_KEEP_TRIGGER;
+ rc = led_classdev_register(&led->pdev->dev, &snode->cdev);
+ if (rc < 0) {
+ pr_err("Unable to register led switch node\n");
+ return rc;
+ }
+
+ snode->cdev.dev->of_node = node;
+
+ snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev);
+ if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) {
+ pr_debug("No pinctrl defined for %s, err=%ld\n",
+ snode->cdev.name, PTR_ERR(snode->led_en_pinctrl));
+ snode->led_en_pinctrl = NULL;
+ }
+
+ if (snode->led_en_pinctrl) {
+ snode->gpio_state_active =
+ pinctrl_lookup_state(snode->led_en_pinctrl,
+ "led_enable");
+ if (IS_ERR_OR_NULL(snode->gpio_state_active)) {
+ pr_err("Cannot lookup LED active state\n");
+ devm_pinctrl_put(snode->led_en_pinctrl);
+ snode->led_en_pinctrl = NULL;
+ return PTR_ERR(snode->gpio_state_active);
+ }
+
+ snode->gpio_state_suspend =
+ pinctrl_lookup_state(snode->led_en_pinctrl,
+ "led_disable");
+ if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) {
+ pr_err("Cannot lookup LED disable state\n");
+ devm_pinctrl_put(snode->led_en_pinctrl);
+ snode->led_en_pinctrl = NULL;
+ return PTR_ERR(snode->gpio_state_suspend);
+ }
+ }
+
+ return 0;
+}
+
+static int get_code_from_table(int *table, int len, int value)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (value == table[i])
+ break;
+ }
+
+ if (i == len) {
+ pr_err("Couldn't find %d from table\n", value);
+ return -ENODATA;
+ }
+
+ return i;
+}
+
+static int qpnp_flash_led_parse_thermal_config_dt(struct qpnp_flash_led *led,
+ struct device_node *node)
+{
+ int rc;
+ u32 val;
+
+ led->pdata->thermal_derate_en =
+ of_property_read_bool(node, "qcom,thermal-derate-en");
+
+ if (led->pdata->thermal_derate_en) {
+ led->pdata->thermal_derate_current =
+ devm_kcalloc(&led->pdev->dev,
+ FLASH_LED_THERMAL_OTST_LEVELS,
+ sizeof(int), GFP_KERNEL);
+ if (!led->pdata->thermal_derate_current)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(node,
+ "qcom,thermal-derate-current",
+ led->pdata->thermal_derate_current,
+ FLASH_LED_THERMAL_OTST_LEVELS);
+ if (rc < 0) {
+ pr_err("Unable to read thermal current limits, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ led->pdata->otst_ramp_bkup_en =
+ !of_property_read_bool(node, "qcom,otst-ramp-back-up-dis");
+
+ led->pdata->thermal_derate_slow = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,thermal-derate-slow", &val);
+ if (!rc) {
+ if (val < 0 || val > THERMAL_DERATE_SLOW_MAX) {
+ pr_err("Invalid thermal_derate_slow %d\n", val);
+ return -EINVAL;
+ }
+
+ led->pdata->thermal_derate_slow =
+ get_code_from_table(thermal_derate_slow_table,
+ ARRAY_SIZE(thermal_derate_slow_table), val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read thermal derate slow, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->thermal_derate_fast = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,thermal-derate-fast", &val);
+ if (!rc) {
+ if (val < 0 || val > THERMAL_DERATE_FAST_MAX) {
+ pr_err("Invalid thermal_derate_fast %d\n", val);
+ return -EINVAL;
+ }
+
+ led->pdata->thermal_derate_fast =
+ get_code_from_table(thermal_derate_fast_table,
+ ARRAY_SIZE(thermal_derate_fast_table), val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read thermal derate fast, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->thermal_debounce = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,thermal-debounce", &val);
+ if (!rc) {
+ if (val < 0 || val > THERMAL_DEBOUNCE_TIME_MAX) {
+ pr_err("Invalid thermal_debounce %d\n", val);
+ return -EINVAL;
+ }
+
+ if (val >= 0 && val < 16)
+ led->pdata->thermal_debounce = 0;
+ else
+ led->pdata->thermal_debounce = ilog2(val) - 3;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read thermal debounce, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->thermal_hysteresis = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,thermal-hysteresis", &val);
+ if (!rc) {
+ if (led->pdata->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
+ val = THERMAL_HYST_TEMP_TO_VAL(val, 20);
+ else
+ val = THERMAL_HYST_TEMP_TO_VAL(val, 15);
+
+ if (val < 0 || val > THERMAL_DERATE_HYSTERESIS_MAX) {
+ pr_err("Invalid thermal_derate_hysteresis %d\n", val);
+ return -EINVAL;
+ }
+
+ led->pdata->thermal_hysteresis = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read thermal hysteresis, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->thermal_thrsh1 = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,thermal-thrsh1", &val);
+ if (!rc) {
+ led->pdata->thermal_thrsh1 =
+ get_code_from_table(otst1_threshold_table,
+ ARRAY_SIZE(otst1_threshold_table), val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read thermal thrsh1, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->thermal_thrsh2 = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,thermal-thrsh2", &val);
+ if (!rc) {
+ led->pdata->thermal_thrsh2 =
+ get_code_from_table(otst2_threshold_table,
+ ARRAY_SIZE(otst2_threshold_table), val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read thermal thrsh2, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->thermal_thrsh3 = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,thermal-thrsh3", &val);
+ if (!rc) {
+ led->pdata->thermal_thrsh3 =
+ get_code_from_table(otst3_threshold_table,
+ ARRAY_SIZE(otst3_threshold_table), val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read thermal thrsh3, rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_parse_vph_droop_config_dt(struct qpnp_flash_led *led,
+ struct device_node *node)
+{
+ int rc;
+ u32 val;
+
+ led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val);
+ if (!rc) {
+ led->pdata->vph_droop_debounce =
+ VPH_DROOP_DEBOUNCE_US_TO_VAL(val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read VPH droop debounce, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->vph_droop_debounce > FLASH_LED_DEBOUNCE_MAX) {
+ pr_err("Invalid VPH droop debounce specified\n");
+ return -EINVAL;
+ }
+
+ led->pdata->vph_droop_threshold = FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,vph-droop-threshold-mv", &val);
+ if (!rc) {
+ led->pdata->vph_droop_threshold =
+ get_vph_droop_thresh_code(val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read VPH droop threshold, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->vph_droop_threshold > FLASH_LED_VPH_DROOP_THRESH_MAX) {
+ pr_err("Invalid VPH droop threshold specified\n");
+ return -EINVAL;
+ }
+
+ led->pdata->vph_droop_hysteresis =
+ FLASH_LED_VPH_DROOP_HYST_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,vph-droop-hysteresis-mv", &val);
+ if (!rc) {
+ led->pdata->vph_droop_hysteresis =
+ VPH_DROOP_HYST_MV_TO_VAL(val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read VPH droop hysteresis, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->vph_droop_hysteresis > FLASH_LED_HYSTERESIS_MAX) {
+ pr_err("Invalid VPH droop hysteresis specified\n");
+ return -EINVAL;
+ }
+
+ led->pdata->vph_droop_hysteresis <<= FLASH_LED_VPH_DROOP_HYST_SHIFT;
+ return rc;
+}
+
+static int qpnp_flash_led_parse_iclamp_config_dt(struct qpnp_flash_led *led,
+ struct device_node *node)
+{
+ int rc;
+ u32 val;
+
+ rc = of_property_read_u32(node, "qcom,led1n2-iclamp-low-ma", &val);
+ if (!rc) {
+ led->pdata->led1n2_iclamp_low_ma = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read led1n2_iclamp_low current, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,led1n2-iclamp-mid-ma", &val);
+ if (!rc) {
+ led->pdata->led1n2_iclamp_mid_ma = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read led1n2_iclamp_mid current, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,led3-iclamp-low-ma", &val);
+ if (!rc) {
+ led->pdata->led3_iclamp_low_ma = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read led3_iclamp_low current, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,led3-iclamp-mid-ma", &val);
+ if (!rc) {
+ led->pdata->led3_iclamp_mid_ma = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read led3_iclamp_mid current, rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_parse_lmh_config_dt(struct qpnp_flash_led *led,
+ struct device_node *node)
+{
+ int rc;
+ u32 val;
+
+ led->pdata->lmh_ocv_threshold_uv =
+ FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV;
+ rc = of_property_read_u32(node, "qcom,lmh-ocv-threshold-uv", &val);
+ if (!rc) {
+ led->pdata->lmh_ocv_threshold_uv = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse lmh ocv threshold, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->lmh_rbatt_threshold_uohm =
+ FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM;
+ rc = of_property_read_u32(node, "qcom,lmh-rbatt-threshold-uohm", &val);
+ if (!rc) {
+ led->pdata->lmh_rbatt_threshold_uohm = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse lmh rbatt threshold, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->lmh_level = FLASH_LED_LMH_LEVEL_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,lmh-level", &val);
+ if (!rc) {
+ led->pdata->lmh_level = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse lmh_level, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->lmh_mitigation_sel = FLASH_LED_LMH_MITIGATION_SEL_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,lmh-mitigation-sel", &val);
+ if (!rc) {
+ led->pdata->lmh_mitigation_sel = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse lmh_mitigation_sel, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->lmh_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
+ pr_err("Invalid lmh_mitigation_sel specified\n");
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
+ struct device_node *node)
+{
+ struct device_node *revid_node;
+ int rc;
+ u32 val;
+ bool short_circuit_det, open_circuit_det, vph_droop_det;
+
+ rc = of_property_read_u32(node, "reg", &val);
+ if (rc < 0) {
+ pr_err("Couldn't find reg in node %s, rc = %d\n",
+ node->full_name, rc);
+ return rc;
+ }
+
+ led->base = val;
+ revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
+ if (!revid_node) {
+ pr_err("Missing qcom,pmic-revid property - driver failed\n");
+ return -EINVAL;
+ }
+
+ led->pdata->pmic_rev_id = get_revid_data(revid_node);
+ if (IS_ERR_OR_NULL(led->pdata->pmic_rev_id)) {
+ pr_err("Unable to get pmic_revid rc=%ld\n",
+ PTR_ERR(led->pdata->pmic_rev_id));
+ /*
+ * the revid peripheral must be registered, any failure
+ * here only indicates that the rev-id module has not
+ * probed yet.
+ */
+ return -EPROBE_DEFER;
+ }
+ of_node_put(revid_node);
+
+ pr_debug("PMIC subtype %d Digital major %d\n",
+ led->pdata->pmic_rev_id->pmic_subtype,
+ led->pdata->pmic_rev_id->rev4);
+
+ led->pdata->hdrm_auto_mode_en = of_property_read_bool(node,
+ "qcom,hdrm-auto-mode");
+
+ led->pdata->isc_delay = FLASH_LED_ISC_DELAY_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,isc-delay-us", &val);
+ if (!rc) {
+ led->pdata->isc_delay =
+ val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read ISC delay, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->warmup_delay = FLASH_LED_WARMUP_DELAY_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,warmup-delay-us", &val);
+ if (!rc) {
+ led->pdata->warmup_delay =
+ val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to read WARMUP delay, rc=%d\n", rc);
+ return rc;
+ }
+
+ short_circuit_det =
+ of_property_read_bool(node, "qcom,short-circuit-det");
+ open_circuit_det = of_property_read_bool(node, "qcom,open-circuit-det");
+ vph_droop_det = of_property_read_bool(node, "qcom,vph-droop-det");
+ led->pdata->current_derate_en_cfg = (vph_droop_det << 2) |
+ (open_circuit_det << 1) | short_circuit_det;
+
+ rc = qpnp_flash_led_parse_thermal_config_dt(led, node);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_parse_vph_droop_config_dt(led, node);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_parse_iclamp_config_dt(led, node);
+ if (rc < 0)
+ return rc;
+
+ led->pdata->hw_strobe_option = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
+ if (!rc) {
+ led->pdata->hw_strobe_option = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse hw strobe option, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->vled_max_uv = FLASH_LED_VLED_MAX_DEFAULT_UV;
+ rc = of_property_read_u32(node, "qcom,vled-max-uv", &val);
+ if (!rc) {
+ led->pdata->vled_max_uv = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse vled_max voltage, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->ibatt_ocp_threshold_ua =
+ FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA;
+ rc = of_property_read_u32(node, "qcom,ibatt-ocp-threshold-ua", &val);
+ if (!rc) {
+ led->pdata->ibatt_ocp_threshold_ua = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse ibatt_ocp threshold, rc=%d\n", rc);
+ return rc;
+ }
+
+ led->pdata->rpara_uohm = FLASH_LED_RPARA_DEFAULT_UOHM;
+ rc = of_property_read_u32(node, "qcom,rparasitic-uohm", &val);
+ if (!rc) {
+ led->pdata->rpara_uohm = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse rparasitic, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_flash_led_parse_lmh_config_dt(led, node);
+ if (rc < 0)
+ return rc;
+
+ led->pdata->chgr_mitigation_sel = FLASH_SW_CHARGER_MITIGATION;
+ rc = of_property_read_u32(node, "qcom,chgr-mitigation-sel", &val);
+ if (!rc) {
+ led->pdata->chgr_mitigation_sel = val;
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse chgr_mitigation_sel, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->chgr_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
+ pr_err("Invalid chgr_mitigation_sel specified\n");
+ return -EINVAL;
+ }
+
+ led->pdata->iled_thrsh_val = FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,iled-thrsh-ma", &val);
+ if (!rc) {
+ led->pdata->iled_thrsh_val = MITIGATION_THRSH_MA_TO_VAL(val);
+ } else if (rc != -EINVAL) {
+ pr_err("Unable to parse iled_thrsh_val, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->iled_thrsh_val > FLASH_LED_CHGR_MITIGATION_THRSH_MAX) {
+ pr_err("Invalid iled_thrsh_val specified\n");
+ return -EINVAL;
+ }
+
+ led->pdata->all_ramp_up_done_irq =
+ of_irq_get_byname(node, "all-ramp-up-done-irq");
+ if (led->pdata->all_ramp_up_done_irq < 0)
+ pr_debug("all-ramp-up-done-irq not used\n");
+
+ led->pdata->all_ramp_down_done_irq =
+ of_irq_get_byname(node, "all-ramp-down-done-irq");
+ if (led->pdata->all_ramp_down_done_irq < 0)
+ pr_debug("all-ramp-down-done-irq not used\n");
+
+ led->pdata->led_fault_irq =
+ of_irq_get_byname(node, "led-fault-irq");
+ if (led->pdata->led_fault_irq < 0)
+ pr_debug("led-fault-irq not used\n");
+
+ return 0;
+}
+
+static int qpnp_flash_led_register_interrupts(struct qpnp_flash_led *led)
+{
+ int rc;
+
+ /* setup irqs */
+ if (led->pdata->all_ramp_up_done_irq >= 0) {
+ rc = devm_request_threaded_irq(&led->pdev->dev,
+ led->pdata->all_ramp_up_done_irq,
+ NULL, qpnp_flash_led_irq_handler,
+ IRQF_ONESHOT,
+ "qpnp_flash_led_all_ramp_up_done_irq", led);
+ if (rc < 0) {
+ pr_err("Unable to request all_ramp_up_done(%d) IRQ(err:%d)\n",
+ led->pdata->all_ramp_up_done_irq, rc);
+ return rc;
+ }
+ }
+
+ if (led->pdata->all_ramp_down_done_irq >= 0) {
+ rc = devm_request_threaded_irq(&led->pdev->dev,
+ led->pdata->all_ramp_down_done_irq,
+ NULL, qpnp_flash_led_irq_handler,
+ IRQF_ONESHOT,
+ "qpnp_flash_led_all_ramp_down_done_irq", led);
+ if (rc < 0) {
+ pr_err("Unable to request all_ramp_down_done(%d) IRQ(err:%d)\n",
+ led->pdata->all_ramp_down_done_irq, rc);
+ return rc;
+ }
+ }
+
+ if (led->pdata->led_fault_irq >= 0) {
+ rc = devm_request_threaded_irq(&led->pdev->dev,
+ led->pdata->led_fault_irq,
+ NULL, qpnp_flash_led_irq_handler,
+ IRQF_ONESHOT,
+ "qpnp_flash_led_fault_irq", led);
+ if (rc < 0) {
+ pr_err("Unable to request led_fault(%d) IRQ(err:%d)\n",
+ led->pdata->led_fault_irq, rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int qpnp_flash_led_probe(struct platform_device *pdev)
+{
+ struct qpnp_flash_led *led;
+ struct device_node *node, *temp;
+ const char *temp_string;
+ int rc, i = 0, j = 0;
+
+ node = pdev->dev.of_node;
+ if (!node) {
+ pr_err("No flash LED nodes defined\n");
+ return -ENODEV;
+ }
+
+ led = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_flash_led),
+ GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!led->regmap) {
+ pr_err("Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+
+ led->pdev = pdev;
+ led->pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct flash_led_platform_data), GFP_KERNEL);
+ if (!led->pdata)
+ return -ENOMEM;
+
+ spin_lock_init(&led->lock);
+
+ rc = qpnp_flash_led_parse_common_dt(led, node);
+ if (rc < 0) {
+ pr_err("Failed to parse common flash LED device tree\n");
+ return rc;
+ }
+
+ for_each_available_child_of_node(node, temp) {
+ rc = of_property_read_string(temp, "label", &temp_string);
+ if (rc < 0) {
+ pr_err("Failed to parse label, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (!strcmp("switch", temp_string)) {
+ led->num_snodes++;
+ } else if (!strcmp("flash", temp_string) ||
+ !strcmp("torch", temp_string)) {
+ led->num_fnodes++;
+ } else {
+ pr_err("Invalid label for led node\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!led->num_fnodes) {
+ pr_err("No LED nodes defined\n");
+ return -ECHILD;
+ }
+
+ led->fnode = devm_kcalloc(&pdev->dev, led->num_fnodes,
+ sizeof(*led->fnode), GFP_KERNEL);
+ if (!led->fnode)
+ return -ENOMEM;
+
+ led->snode = devm_kcalloc(&pdev->dev, led->num_snodes,
+ sizeof(*led->snode), GFP_KERNEL);
+ if (!led->snode)
+ return -ENOMEM;
+
+ temp = NULL;
+ i = 0;
+ j = 0;
+ for_each_available_child_of_node(node, temp) {
+ rc = of_property_read_string(temp, "label", &temp_string);
+ if (rc < 0) {
+ pr_err("Failed to parse label, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (!strcmp("flash", temp_string) ||
+ !strcmp("torch", temp_string)) {
+ rc = qpnp_flash_led_parse_each_led_dt(led,
+ &led->fnode[i], temp);
+ if (rc < 0) {
+ pr_err("Unable to parse flash node %d rc=%d\n",
+ i, rc);
+ goto error_led_register;
+ }
+ i++;
+ }
+
+ if (!strcmp("switch", temp_string)) {
+ rc = qpnp_flash_led_parse_and_register_switch(led,
+ &led->snode[j], temp);
+ if (rc < 0) {
+ pr_err("Unable to parse and register switch node, rc=%d\n",
+ rc);
+ goto error_switch_register;
+ }
+ j++;
+ }
+ }
+
+ rc = qpnp_flash_led_register_interrupts(led);
+ if (rc < 0)
+ goto error_switch_register;
+
+ led->bms_psy = power_supply_get_by_name("bms");
+ if (!led->bms_psy) {
+ rc = flash_led_psy_register_notifier(led);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier, rc = %d\n", rc);
+ goto error_switch_register;
+ }
+ }
+
+ rc = qpnp_flash_led_init_settings(led);
+ if (rc < 0) {
+ pr_err("Failed to initialize flash LED, rc=%d\n", rc);
+ goto unreg_notifier;
+ }
+
+ for (i = 0; i < led->num_snodes; i++) {
+ for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
+ rc = sysfs_create_file(&led->snode[i].cdev.dev->kobj,
+ &qpnp_flash_led_attrs[j].attr);
+ if (rc < 0) {
+ pr_err("sysfs creation failed, rc=%d\n", rc);
+ goto sysfs_fail;
+ }
+ }
+ }
+
+ dev_set_drvdata(&pdev->dev, led);
+
+ return 0;
+
+sysfs_fail:
+ for (--j; j >= 0; j--)
+ sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
+ &qpnp_flash_led_attrs[j].attr);
+
+ for (--i; i >= 0; i--) {
+ for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
+ sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
+ &qpnp_flash_led_attrs[j].attr);
+ }
+
+ i = led->num_snodes;
+unreg_notifier:
+ power_supply_unreg_notifier(&led->nb);
+error_switch_register:
+ while (i > 0)
+ led_classdev_unregister(&led->snode[--i].cdev);
+ i = led->num_fnodes;
+error_led_register:
+ while (i > 0)
+ led_classdev_unregister(&led->fnode[--i].cdev);
+
+ return rc;
+}
+
+static int qpnp_flash_led_remove(struct platform_device *pdev)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev);
+ int i, j;
+
+ for (i = 0; i < led->num_snodes; i++) {
+ for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
+ sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
+ &qpnp_flash_led_attrs[j].attr);
+
+ if (led->snode[i].regulator_on)
+ qpnp_flash_led_regulator_enable(led,
+ &led->snode[i], false);
+ }
+
+ while (i > 0)
+ led_classdev_unregister(&led->snode[--i].cdev);
+
+ i = led->num_fnodes;
+ while (i > 0)
+ led_classdev_unregister(&led->fnode[--i].cdev);
+
+ power_supply_unreg_notifier(&led->nb);
+ return 0;
+}
+
+const struct of_device_id qpnp_flash_led_match_table[] = {
+ { .compatible = "qcom,qpnp-flash-led-v2",},
+ { },
+};
+
+static struct platform_driver qpnp_flash_led_driver = {
+ .driver = {
+ .name = "qcom,qpnp-flash-led-v2",
+ .of_match_table = qpnp_flash_led_match_table,
+ },
+ .probe = qpnp_flash_led_probe,
+ .remove = qpnp_flash_led_remove,
+};
+
+static int __init qpnp_flash_led_init(void)
+{
+ return platform_driver_register(&qpnp_flash_led_driver);
+}
+late_initcall(qpnp_flash_led_init);
+
+static void __exit qpnp_flash_led_exit(void)
+{
+ platform_driver_unregister(&qpnp_flash_led_driver);
+}
+module_exit(qpnp_flash_led_exit);
+
+MODULE_DESCRIPTION("QPNP Flash LED driver v2");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("leds:leds-qpnp-flash-v2");
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 7d38e6b..dbb9a36 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -21,6 +21,22 @@
return led_cdev->brightness;
}
+static inline struct led_classdev *trigger_to_lcdev(struct led_trigger *trig)
+{
+ struct led_classdev *led_cdev;
+
+ read_lock(&trig->leddev_list_lock);
+ list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
+ if (!strcmp(led_cdev->default_trigger, trig->name)) {
+ read_unlock(&trig->leddev_list_lock);
+ return led_cdev;
+ }
+ }
+
+ read_unlock(&trig->leddev_list_lock);
+ return NULL;
+}
+
void led_init_core(struct led_classdev *led_cdev);
void led_stop_software_blink(struct led_classdev *led_cdev);
void led_set_brightness_nopm(struct led_classdev *led_cdev,
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index e1fa6ba..bb3096b 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -559,7 +559,12 @@
}
memset(result + size, 0, JOURNAL_MAC_SIZE - size);
} else {
- __u8 digest[size];
+ __u8 digest[HASH_MAX_DIGESTSIZE];
+
+ if (WARN_ON(size > sizeof(digest))) {
+ dm_integrity_io_error(ic, "digest_size", -EINVAL);
+ goto err;
+ }
r = crypto_shash_final(desc, digest);
if (unlikely(r)) {
dm_integrity_io_error(ic, "crypto_shash_final", r);
@@ -1324,7 +1329,7 @@
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
char *checksums;
unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
- char checksums_onstack[ic->tag_size + extra_space];
+ char checksums_onstack[HASH_MAX_DIGESTSIZE];
unsigned sectors_to_process = dio->range.n_sectors;
sector_t sector = dio->range.logical_sector;
@@ -1333,8 +1338,14 @@
checksums = kmalloc((PAGE_SIZE >> SECTOR_SHIFT >> ic->sb->log2_sectors_per_block) * ic->tag_size + extra_space,
GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN);
- if (!checksums)
+ if (!checksums) {
checksums = checksums_onstack;
+ if (WARN_ON(extra_space &&
+ digest_size > sizeof(checksums_onstack))) {
+ r = -EINVAL;
+ goto error;
+ }
+ }
__bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) {
unsigned pos;
@@ -1546,7 +1557,7 @@
} while (++s < ic->sectors_per_block);
#ifdef INTERNAL_VERIFY
if (ic->internal_hash) {
- char checksums_onstack[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)];
+ char checksums_onstack[max(HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack);
if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) {
@@ -1596,7 +1607,7 @@
if (ic->internal_hash) {
unsigned digest_size = crypto_shash_digestsize(ic->internal_hash);
if (unlikely(digest_size > ic->tag_size)) {
- char checksums_onstack[digest_size];
+ char checksums_onstack[HASH_MAX_DIGESTSIZE];
integrity_sector_checksum(ic, logical_sector, (char *)js, checksums_onstack);
memcpy(journal_entry_tag(ic, je), checksums_onstack, ic->tag_size);
} else
@@ -2023,7 +2034,7 @@
unlikely(from_replay) &&
#endif
ic->internal_hash) {
- char test_tag[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)];
+ char test_tag[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block),
(char *)access_journal_data(ic, i, l), test_tag);
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 8306ee0..1c9b878 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -215,12 +215,15 @@
struct dm_verity_fec_io *fio = fec_io(io);
u64 block, ileaved;
u8 *bbuf, *rs_block;
- u8 want_digest[v->digest_size];
+ u8 want_digest[HASH_MAX_DIGESTSIZE];
unsigned n, k;
if (neras)
*neras = 0;
+ if (WARN_ON(v->digest_size > sizeof(want_digest)))
+ return -EINVAL;
+
/*
* read each of the rsn data blocks that are part of the RS block, and
* interleave contents to available bufs
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index eb7aef6..32b3e97 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -394,7 +394,7 @@
strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
client->usecase_ndx = VOTE_INDEX_DISABLE;
client->id = id;
- SDEROT_DBG("bus vote client %s created:%p id :%d\n", client_name,
+ SDEROT_DBG("bus vote client %s created:%pK id :%d\n", client_name,
client, id);
id++;
list_add(&client->list, &sde_res->reg_bus_clist);
@@ -410,7 +410,7 @@
if (!client) {
SDEROT_ERR("reg bus vote: invalid client handle\n");
} else {
- SDEROT_DBG("bus vote client %s destroyed:%p id:%u\n",
+ SDEROT_DBG("bus vote client %s destroyed:%pK id:%u\n",
client->name, client, client->id);
mutex_lock(&sde_res->reg_bus_lock);
list_del_init(&client->list);
@@ -837,7 +837,7 @@
SDEROT_ERR("unable to map SDE ROT VBIF base\n");
goto probe_done;
}
- SDEROT_DBG("SDE ROT VBIF HW Base addr=%p len=0x%x\n",
+ SDEROT_DBG("SDE ROT VBIF HW Base addr=%pK len=0x%x\n",
mdata->vbif_nrt_io.base, mdata->vbif_nrt_io.len);
rc = sde_mdp_parse_dt_misc(pdev, mdata);
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 0c43fa4..a9e358c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -496,7 +496,7 @@
{
if (entry->input_fence) {
SDEROT_EVTLOG(entry->input_fence, 1111);
- SDEROT_DBG("sys_fence_put i:%p\n", entry->input_fence);
+ SDEROT_DBG("sys_fence_put i:%pK\n", entry->input_fence);
sde_rotator_put_sync_fence(entry->input_fence);
entry->input_fence = NULL;
}
@@ -507,7 +507,7 @@
sde_rotator_resync_timeline(entry->fenceq->timeline);
SDEROT_EVTLOG(entry->output_fence, 2222);
- SDEROT_DBG("sys_fence_put o:%p\n", entry->output_fence);
+ SDEROT_DBG("sys_fence_put o:%pK\n", entry->output_fence);
sde_rotator_put_sync_fence(entry->output_fence);
entry->output_fence = NULL;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 82e9648..dd30cbd 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -353,7 +353,7 @@
if (*dump_mem) {
dump_addr = *dump_mem;
- pr_info("%s: start_addr:0x%p end_addr:0x%p reg_addr=0x%X\n",
+ pr_info("%s: start_addr:0x%pK end_addr:0x%pK reg_addr=0x%X\n",
dump_name, dump_addr, dump_addr + (u32)len * 16,
addr);
} else {
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 a5176d9..fe9113f 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -2356,7 +2356,7 @@
ctx->vbinfo_cap[idx].qbuf_ts = ktime_get();
ctx->vbinfo_cap[idx].dqbuf_ts = NULL;
SDEDEV_DBG(ctx->rot_dev->dev,
- "create buffer fence s:%d.%u i:%d f:%p\n",
+ "create buffer fence s:%d.%u i:%d f:%pK\n",
ctx->session_id,
ctx->vbinfo_cap[idx].fence_ts,
idx,
@@ -3045,7 +3045,7 @@
if (!src_buf || !dst_buf) {
SDEDEV_ERR(rot_dev->dev,
- "null buffer in retire s:%d sb:%p db:%p\n",
+ "null buffer in retire s:%d sb:%pK db:%pK\n",
ctx->session_id,
src_buf, dst_buf);
}
@@ -3334,7 +3334,7 @@
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
if (!src_buf || !dst_buf) {
SDEDEV_ERR(rot_dev->dev,
- "null buffer in device run s:%d sb:%p db:%p\n",
+ "null buffer in device run s:%d sb:%pK db:%pK\n",
ctx->session_id,
src_buf, dst_buf);
goto error_process_buffers;
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 e45d010..8148a30 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -972,7 +972,7 @@
if (ctx && (ctx->session_id == session_id) &&
(ctx->sequence_id == sequence_id)) {
SDEROT_DBG(
- "rotCtx sloti[%d][%d] ==> ctx:%p | session-id:%d | sequence-id:%d\n",
+ "rotCtx sloti[%d][%d] ==> ctx:%pK | session-id:%d | sequence-id:%d\n",
q_id, i, ctx, ctx->session_id,
ctx->sequence_id);
return ctx;
@@ -1001,7 +1001,7 @@
if (dbgbuf->dmabuf && (dbgbuf->buflen > 0)) {
dma_buf_begin_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE);
dbgbuf->vaddr = dma_buf_kmap(dbgbuf->dmabuf, 0);
- SDEROT_DBG("vaddr mapping: 0x%p/%ld w:%d/h:%d\n",
+ SDEROT_DBG("vaddr mapping: 0x%pK/%ld w:%d/h:%d\n",
dbgbuf->vaddr, dbgbuf->buflen,
dbgbuf->width, dbgbuf->height);
}
@@ -2046,7 +2046,7 @@
unsigned long flags;
if (rot->irq_num >= 0) {
- SDEROT_DBG("Wait for REGDMA completion, ctx:%p, ts:%X\n",
+ SDEROT_DBG("Wait for REGDMA completion, ctx:%pK, ts:%X\n",
ctx, ctx->timestamp);
rc = wait_event_timeout(ctx->regdma_waitq,
!rot->ops.get_pending_ts(rot, ctx, &swts),
@@ -2230,7 +2230,7 @@
}
data->mapped = true;
- SDEROT_DBG("swts buffer mapped: %pad/%lx va:%p\n", &data->addr,
+ SDEROT_DBG("swts buffer mapped: %pad/%lx va:%pK\n", &data->addr,
data->len, rot->swts_buffer);
sde_smmu_ctrl(0);
@@ -2450,7 +2450,7 @@
if (resinfo->rot->irq_num >= 0)
sde_hw_rotator_enable_irq(resinfo->rot);
- SDEROT_DBG("New rotator resource:%p, priority:%d\n",
+ SDEROT_DBG("New rotator resource:%pK, priority:%d\n",
resinfo, wb_id);
return &resinfo->hw;
@@ -2472,7 +2472,7 @@
resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
SDEROT_DBG(
- "Free rotator resource:%p, priority:%d, active:%d, pending:%d\n",
+ "Free rotator resource:%pK, priority:%d, active:%d, pending:%d\n",
resinfo, hw->wb_id, atomic_read(&hw->num_active),
hw->pending_count);
@@ -2535,7 +2535,7 @@
sde_hw_rotator_put_ctx(ctx);
SDEROT_DBG(
- "New rot CTX:%p, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
+ "New rot CTX:%pK, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
ctx->q_id, ctx->timestamp,
atomic_read(&ctx->hwres->num_active),
@@ -2556,7 +2556,7 @@
return;
SDEROT_DBG(
- "Free rot CTX:%p, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
+ "Free rot CTX:%pK, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
ctx->q_id, ctx->timestamp,
atomic_read(&ctx->hwres->num_active),
@@ -3284,7 +3284,7 @@
ctx->last_regdma_isr_status = isr;
ctx->last_regdma_timestamp = ts;
SDEROT_DBG(
- "regdma complete: ctx:%p, ts:%X\n", ctx, ts);
+ "regdma complete: ctx:%pK, ts:%X\n", ctx, ts);
wake_up_all(&ctx->regdma_waitq);
ts = (ts - 1) & SDE_REGDMA_SWTS_MASK;
@@ -3317,8 +3317,9 @@
ctx->last_regdma_isr_status = isr;
ctx->last_regdma_timestamp = ts;
wake_up_all(&ctx->regdma_waitq);
- SDEROT_DBG("Wakeup rotctx[%d][%d]:%p\n",
- i, j, ctx);
+ SDEROT_DBG(
+ "Wakeup rotctx[%d][%d]:%pK\n",
+ i, j, ctx);
}
}
}
@@ -3541,7 +3542,7 @@
if (ctx) {
SPRINT(
- "rotCtx[%d][%d]:%p\n",
+ "rotCtx[%d][%d]:%pK\n",
i, j, ctx);
++num_active;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
index b1cd754c..70316f4 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
@@ -370,7 +370,7 @@
static inline char __iomem *sde_hw_rotator_get_regdma_segment_base(
struct sde_hw_rotator_context *ctx)
{
- SDEROT_DBG("regdma base @slot[%d]: %p\n",
+ SDEROT_DBG("regdma base @slot[%d]: %pK\n",
sde_hw_rotator_get_regdma_ctxidx(ctx),
ctx->regdma_base);
@@ -389,7 +389,7 @@
u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
char __iomem *addr = ctx->regdma_wrptr;
- SDEROT_DBG("regdma slot[%d] ==> %p\n", idx, addr);
+ SDEROT_DBG("regdma slot[%d] ==> %pK\n", idx, addr);
return addr;
}
@@ -406,7 +406,7 @@
u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
ctx->regdma_wrptr = wrptr;
- SDEROT_DBG("regdma slot[%d] <== %p\n", idx, wrptr);
+ SDEROT_DBG("regdma slot[%d] <== %pK\n", idx, wrptr);
}
/**
@@ -425,7 +425,7 @@
list_add_tail(&ctx->list, &rot->sbuf_ctx[ctx->q_id]);
spin_unlock_irqrestore(&rot->rotisr_lock, flags);
- SDEROT_DBG("rotCtx[%d][%d] <== ctx:%p | session-id:%d\n",
+ SDEROT_DBG("rotCtx[%d][%d] <== ctx:%pK | session-id:%d\n",
ctx->q_id, idx, ctx, ctx->session_id);
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
index 812f2dd..c25b8dc 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
@@ -785,7 +785,7 @@
}
if (!IS_ERR_OR_NULL(data->srcp_dma_buf)) {
- SDEROT_DBG("ion hdl=%p buf=0x%pa\n", data->srcp_dma_buf,
+ SDEROT_DBG("ion hdl=%pK buf=0x%pa\n", data->srcp_dma_buf,
&data->addr);
if (sde_mdp_is_map_needed(data) && data->mapped) {
domain = sde_smmu_get_domain_type(data->flags,
@@ -840,7 +840,7 @@
if (sde_mdp_is_map_needed(data)) {
domain = sde_smmu_get_domain_type(data->flags, rotator);
- SDEROT_DBG("%d domain=%d ihndl=%p\n",
+ SDEROT_DBG("%d domain=%d ihndl=%pK\n",
__LINE__, domain, data->srcp_dma_buf);
data->srcp_attachment =
sde_smmu_dma_buf_attach(data->srcp_dma_buf, dev,
@@ -973,7 +973,7 @@
data->addr += data->offset;
data->len -= data->offset;
- SDEROT_DBG("ihdl=%p buf=0x%pa len=0x%lx\n",
+ SDEROT_DBG("ihdl=%pK buf=0x%pa len=0x%lx\n",
data->srcp_dma_buf, &data->addr, data->len);
} else {
sde_mdp_put_img(data, rotator, dir);
diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c
index e2e95de..234e62b 100644
--- a/drivers/mfd/qcom-spmi-pmic.c
+++ b/drivers/mfd/qcom-spmi-pmic.c
@@ -1,15 +1,5 @@
-/*
- * Copyright (c) 2014, 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved. */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -124,11 +114,23 @@
.fast_io = true,
};
+static const struct regmap_config spmi_regmap_can_sleep_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xffff,
+ .fast_io = false,
+};
+
static int pmic_spmi_probe(struct spmi_device *sdev)
{
+ struct device_node *root = sdev->dev.of_node;
struct regmap *regmap;
- regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
+ if (of_property_read_bool(root, "qcom,can-sleep"))
+ regmap = devm_regmap_init_spmi_ext(sdev,
+ &spmi_regmap_can_sleep_config);
+ else
+ regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index a205750..7ccdc62 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -95,7 +95,7 @@
* State for an MPPE (de)compressor.
*/
struct ppp_mppe_state {
- struct crypto_skcipher *arc4;
+ struct crypto_sync_skcipher *arc4;
struct shash_desc *sha1;
unsigned char *sha1_digest;
unsigned char master_key[MPPE_MAX_KEY_LEN];
@@ -155,15 +155,15 @@
static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
{
struct scatterlist sg_in[1], sg_out[1];
- SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
- skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_sync_tfm(req, state->arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
get_new_key_from_sha(state);
if (!initial_key) {
- crypto_skcipher_setkey(state->arc4, state->sha1_digest,
- state->keylen);
+ crypto_sync_skcipher_setkey(state->arc4, state->sha1_digest,
+ state->keylen);
sg_init_table(sg_in, 1);
sg_init_table(sg_out, 1);
setup_sg(sg_in, state->sha1_digest, state->keylen);
@@ -181,7 +181,8 @@
state->session_key[1] = 0x26;
state->session_key[2] = 0x9e;
}
- crypto_skcipher_setkey(state->arc4, state->session_key, state->keylen);
+ crypto_sync_skcipher_setkey(state->arc4, state->session_key,
+ state->keylen);
skcipher_request_zero(req);
}
@@ -203,7 +204,7 @@
goto out;
- state->arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ state->arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(state->arc4)) {
state->arc4 = NULL;
goto out_free;
@@ -250,7 +251,7 @@
crypto_free_shash(state->sha1->tfm);
kzfree(state->sha1);
}
- crypto_free_skcipher(state->arc4);
+ crypto_free_sync_skcipher(state->arc4);
kfree(state);
out:
return NULL;
@@ -266,7 +267,7 @@
kfree(state->sha1_digest);
crypto_free_shash(state->sha1->tfm);
kzfree(state->sha1);
- crypto_free_skcipher(state->arc4);
+ crypto_free_sync_skcipher(state->arc4);
kfree(state);
}
}
@@ -366,7 +367,7 @@
int isize, int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
int proto;
int err;
struct scatterlist sg_in[1], sg_out[1];
@@ -426,7 +427,7 @@
setup_sg(sg_in, ibuf, isize);
setup_sg(sg_out, obuf, osize);
- skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_sync_tfm(req, state->arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL);
err = crypto_skcipher_encrypt(req);
@@ -480,7 +481,7 @@
int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
unsigned ccount;
int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
struct scatterlist sg_in[1], sg_out[1];
@@ -615,7 +616,7 @@
setup_sg(sg_in, ibuf, 1);
setup_sg(sg_out, obuf, 1);
- skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_sync_tfm(req, state->arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL);
if (crypto_skcipher_decrypt(req)) {
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 29032ca..22c6f8f8 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -12,4 +12,13 @@
This should be enabled to support audio & video over HDMI or
DP for hot pluggable sink devices.
+config QPNP_REVID
+ tristate "QPNP Revision ID Peripheral"
+ depends on SPMI
+ help
+ Say 'y' here to include support for the Qualcomm Technologies, Inc.
+ QPNP REVID peripheral. REVID prints out the PMIC type and revision
+ numbers in the kernel log along with the PMIC option status. The PMIC
+ type is mapped to a QTI chip part number and logged as well.
+
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 6da4b4b..4c286fa 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -3,4 +3,6 @@
#
# Makefile for the MSM specific device drivers.
#
+
obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
+obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
new file mode 100644
index 0000000..f4010aa
--- /dev/null
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/of.h>
+
+#define REVID_REVISION1 0x0
+#define REVID_REVISION2 0x1
+#define REVID_REVISION3 0x2
+#define REVID_REVISION4 0x3
+#define REVID_TYPE 0x4
+#define REVID_SUBTYPE 0x5
+#define REVID_STATUS1 0x8
+#define REVID_SPARE_0 0x60
+#define REVID_TP_REV 0xf1
+#define REVID_FAB_ID 0xf2
+
+#define QPNP_REVID_DEV_NAME "qcom,qpnp-revid"
+
+static const char *const pmic_names[] = {
+ [0] = "Unknown PMIC",
+ [PM8941_SUBTYPE] = "PM8941",
+ [PM8841_SUBTYPE] = "PM8841",
+ [PM8019_SUBTYPE] = "PM8019",
+ [PM8226_SUBTYPE] = "PM8226",
+ [PM8110_SUBTYPE] = "PM8110",
+ [PMA8084_SUBTYPE] = "PMA8084",
+ [PMI8962_SUBTYPE] = "PMI8962",
+ [PMD9635_SUBTYPE] = "PMD9635",
+ [PM8994_SUBTYPE] = "PM8994",
+ [PMI8994_SUBTYPE] = "PMI8994",
+ [PM8916_SUBTYPE] = "PM8916",
+ [PM8004_SUBTYPE] = "PM8004",
+ [PM8909_SUBTYPE] = "PM8909",
+ [PM2433_SUBTYPE] = "PM2433",
+ [PMD9655_SUBTYPE] = "PMD9655",
+ [PM8950_SUBTYPE] = "PM8950",
+ [PMI8950_SUBTYPE] = "PMI8950",
+ [PMK8001_SUBTYPE] = "PMK8001",
+ [PMI8996_SUBTYPE] = "PMI8996",
+ [PM8998_SUBTYPE] = "PM8998",
+ [PMI8998_SUBTYPE] = "PMI8998",
+ [PM8005_SUBTYPE] = "PM8005",
+ [PM8937_SUBTYPE] = "PM8937",
+ [PM660L_SUBTYPE] = "PM660L",
+ [PM660_SUBTYPE] = "PM660",
+ [PMI632_SUBTYPE] = "PMI632",
+ [PMI8937_SUBTYPE] = "PMI8937",
+ [PM8150_SUBTYPE] = "PM8150",
+ [PM8150B_SUBTYPE] = "PM8150B",
+ [PM8150L_SUBTYPE] = "PM8150L",
+ [PM6150_SUBTYPE] = "PM6150",
+};
+
+struct revid_chip {
+ struct list_head link;
+ struct device_node *dev_node;
+ struct pmic_revid_data data;
+};
+
+static LIST_HEAD(revid_chips);
+static DEFINE_MUTEX(revid_chips_lock);
+
+static const struct of_device_id qpnp_revid_match_table[] = {
+ { .compatible = QPNP_REVID_DEV_NAME },
+ {}
+};
+
+static u8 qpnp_read_byte(struct regmap *regmap, u16 addr)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(regmap, addr, &val);
+ if (rc) {
+ pr_err("read failed rc=%d\n", rc);
+ return 0;
+ }
+ return (u8)val;
+}
+
+/**
+ * get_revid_data - Return the revision information of PMIC
+ * @dev_node: Pointer to the revid peripheral of the PMIC for which
+ * revision information is seeked
+ *
+ * CONTEXT: Should be called in non atomic context
+ *
+ * RETURNS: pointer to struct pmic_revid_data filled with the information
+ * about the PMIC revision
+ */
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+ struct revid_chip *revid_chip;
+
+ if (!dev_node)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&revid_chips_lock);
+ list_for_each_entry(revid_chip, &revid_chips, link) {
+ if (dev_node == revid_chip->dev_node) {
+ mutex_unlock(&revid_chips_lock);
+ return &revid_chip->data;
+ }
+ }
+ mutex_unlock(&revid_chips_lock);
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(get_revid_data);
+
+#define PM8941_PERIPHERAL_SUBTYPE 0x01
+#define PM8226_PERIPHERAL_SUBTYPE 0x04
+#define PMD9655_PERIPHERAL_SUBTYPE 0x0F
+#define PMI8950_PERIPHERAL_SUBTYPE 0x11
+#define PMI8937_PERIPHERAL_SUBTYPE 0x37
+static size_t build_pmic_string(char *buf, size_t n, int sid,
+ u8 subtype, u8 rev1, u8 rev2, u8 rev3, u8 rev4)
+{
+ size_t pos = 0;
+ /*
+ * In early versions of PM8941 and PM8226, the major revision number
+ * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
+ * Increment the major revision number here if the chip is an early
+ * version of PM8941 or PM8226.
+ */
+ if (((int)subtype == PM8941_PERIPHERAL_SUBTYPE
+ || (int)subtype == PM8226_PERIPHERAL_SUBTYPE)
+ && rev4 < 0x02)
+ rev4++;
+
+ pos += snprintf(buf + pos, n - pos, "PMIC@SID%d", sid);
+ if (subtype >= ARRAY_SIZE(pmic_names) || subtype == 0)
+ pos += snprintf(buf + pos, n - pos, ": %s (subtype: 0x%02X)",
+ pmic_names[0], subtype);
+ else
+ pos += snprintf(buf + pos, n - pos, ": %s",
+ pmic_names[subtype]);
+ pos += snprintf(buf + pos, n - pos, " v%d.%d", rev4, rev3);
+ if (rev2 || rev1)
+ pos += snprintf(buf + pos, n - pos, ".%d", rev2);
+ if (rev1)
+ pos += snprintf(buf + pos, n - pos, ".%d", rev1);
+ return pos;
+}
+
+#define PMIC_PERIPHERAL_TYPE 0x51
+#define PMIC_STRING_MAXLENGTH 80
+static int qpnp_revid_probe(struct platform_device *pdev)
+{
+ u8 rev1, rev2, rev3, rev4, pmic_type, pmic_subtype, pmic_status;
+ u8 option1, option2, option3, option4, spare0;
+ unsigned int base;
+ int rc, fab_id, tp_rev;
+ char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'};
+ struct revid_chip *revid_chip;
+ struct regmap *regmap;
+
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap) {
+ dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "reg", &base);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't find reg in node = %s rc = %d\n",
+ pdev->dev.of_node->full_name, rc);
+ return rc;
+ }
+ pmic_type = qpnp_read_byte(regmap, base + REVID_TYPE);
+ if (pmic_type != PMIC_PERIPHERAL_TYPE) {
+ pr_err("Invalid REVID peripheral type: %02X\n", pmic_type);
+ return -EINVAL;
+ }
+
+ rev1 = qpnp_read_byte(regmap, base + REVID_REVISION1);
+ rev2 = qpnp_read_byte(regmap, base + REVID_REVISION2);
+ rev3 = qpnp_read_byte(regmap, base + REVID_REVISION3);
+ rev4 = qpnp_read_byte(regmap, base + REVID_REVISION4);
+
+ pmic_subtype = qpnp_read_byte(regmap, base + REVID_SUBTYPE);
+ if (pmic_subtype != PMD9655_PERIPHERAL_SUBTYPE)
+ pmic_status = qpnp_read_byte(regmap, base + REVID_STATUS1);
+ else
+ pmic_status = 0;
+
+ /* special case for PMI8937 */
+ if (pmic_subtype == PMI8950_PERIPHERAL_SUBTYPE) {
+ /* read spare register */
+ spare0 = qpnp_read_byte(regmap, base + REVID_SPARE_0);
+ if (spare0)
+ pmic_subtype = PMI8937_PERIPHERAL_SUBTYPE;
+ }
+
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,fab-id-valid"))
+ fab_id = qpnp_read_byte(regmap, base + REVID_FAB_ID);
+ else
+ fab_id = -EINVAL;
+
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,tp-rev-valid"))
+ tp_rev = qpnp_read_byte(regmap, base + REVID_TP_REV);
+ else
+ tp_rev = -EINVAL;
+
+ revid_chip = devm_kzalloc(&pdev->dev, sizeof(struct revid_chip),
+ GFP_KERNEL);
+ if (!revid_chip)
+ return -ENOMEM;
+
+ revid_chip->dev_node = pdev->dev.of_node;
+ revid_chip->data.rev1 = rev1;
+ revid_chip->data.rev2 = rev2;
+ revid_chip->data.rev3 = rev3;
+ revid_chip->data.rev4 = rev4;
+ revid_chip->data.pmic_subtype = pmic_subtype;
+ revid_chip->data.pmic_type = pmic_type;
+ revid_chip->data.fab_id = fab_id;
+ revid_chip->data.tp_rev = tp_rev;
+
+ if (pmic_subtype < ARRAY_SIZE(pmic_names))
+ revid_chip->data.pmic_name = pmic_names[pmic_subtype];
+ else
+ revid_chip->data.pmic_name = pmic_names[0];
+
+ mutex_lock(&revid_chips_lock);
+ list_add(&revid_chip->link, &revid_chips);
+ mutex_unlock(&revid_chips_lock);
+
+ option1 = pmic_status & 0x3;
+ option2 = (pmic_status >> 2) & 0x3;
+ option3 = (pmic_status >> 4) & 0x3;
+ option4 = (pmic_status >> 6) & 0x3;
+
+ build_pmic_string(pmic_string, PMIC_STRING_MAXLENGTH,
+ to_spmi_device(pdev->dev.parent)->usid,
+ pmic_subtype, rev1, rev2, rev3, rev4);
+ pr_info("%s options: %d, %d, %d, %d\n",
+ pmic_string, option1, option2, option3, option4);
+ return 0;
+}
+
+static struct platform_driver qpnp_revid_driver = {
+ .probe = qpnp_revid_probe,
+ .driver = {
+ .name = QPNP_REVID_DEV_NAME,
+ .of_match_table = qpnp_revid_match_table,
+ },
+};
+
+static int __init qpnp_revid_init(void)
+{
+ return platform_driver_register(&qpnp_revid_driver);
+}
+
+static void __exit qpnp_revid_exit(void)
+{
+ return platform_driver_unregister(&qpnp_revid_driver);
+}
+
+subsys_initcall(qpnp_revid_init);
+module_exit(qpnp_revid_exit);
+
+MODULE_DESCRIPTION("QPNP REVID DRIVER");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_REVID_DEV_NAME);
diff --git a/drivers/soc/qcom/service-locator-private.h b/drivers/soc/qcom/service-locator-private.h
index dcec83b..3142740 100644
--- a/drivers/soc/qcom/service-locator-private.h
+++ b/drivers/soc/qcom/service-locator-private.h
@@ -89,7 +89,7 @@
.data_type = QMI_EOTI, \
.elem_len = 0, \
.elem_size = 0, \
- .is_array = NO_ARRAY, \
+ .array_type = NO_ARRAY, \
.tlv_type = 0x00, \
.offset = 0, \
.ei_array = NULL, \
@@ -100,7 +100,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct servreg_loc_entry_v01,
name),
@@ -109,7 +109,7 @@
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct servreg_loc_entry_v01,
instance_id),
@@ -118,7 +118,7 @@
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct servreg_loc_entry_v01,
service_data_valid),
@@ -127,7 +127,7 @@
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct servreg_loc_entry_v01,
service_data),
@@ -140,7 +140,7 @@
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_loc_indication_register_req_msg_v01,
@@ -150,7 +150,7 @@
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_loc_indication_register_req_msg_v01,
@@ -164,7 +164,7 @@
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_loc_indication_register_resp_msg_v01,
@@ -179,7 +179,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_req_msg_v01,
@@ -189,7 +189,7 @@
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_req_msg_v01,
@@ -199,7 +199,7 @@
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_req_msg_v01,
@@ -213,7 +213,7 @@
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -224,7 +224,7 @@
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -234,7 +234,7 @@
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint16_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -244,7 +244,7 @@
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -254,7 +254,7 @@
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint16_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -264,7 +264,7 @@
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -274,7 +274,7 @@
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -284,7 +284,7 @@
.data_type = QMI_STRUCT,
.elem_len = QMI_SERVREG_LOC_LIST_LENGTH_V01,
.elem_size = sizeof(struct servreg_loc_entry_v01),
- .is_array = VAR_LEN_ARRAY,
+ .array_type = VAR_LEN_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -299,7 +299,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
qmi_servreg_loc_register_service_list_req_msg_v01,
@@ -309,7 +309,7 @@
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_loc_register_service_list_req_msg_v01,
@@ -319,7 +319,7 @@
.data_type = QMI_STRUCT,
.elem_len = QMI_SERVREG_LOC_LIST_LENGTH_V01,
.elem_size = sizeof(struct servreg_loc_entry_v01),
- .is_array = VAR_LEN_ARRAY,
+ .array_type = VAR_LEN_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_loc_register_service_list_req_msg_v01,
@@ -334,7 +334,7 @@
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_loc_register_service_list_resp_msg_v01,
diff --git a/drivers/soc/qcom/service-notifier-private.h b/drivers/soc/qcom/service-notifier-private.h
index 26070f7..fb3d75b 100644
--- a/drivers/soc/qcom/service-notifier-private.h
+++ b/drivers/soc/qcom/service-notifier-private.h
@@ -89,7 +89,7 @@
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
qmi_servreg_notif_register_listener_req_msg_v01,
@@ -99,7 +99,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_notif_register_listener_req_msg_v01,
@@ -107,8 +107,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -117,7 +117,7 @@
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_notif_register_listener_resp_msg_v01,
@@ -128,7 +128,7 @@
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_notif_register_listener_resp_msg_v01,
@@ -139,7 +139,7 @@
.elem_len = 1,
.elem_size = sizeof(
enum qmi_servreg_notif_service_state_enum_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_notif_register_listener_resp_msg_v01,
@@ -147,8 +147,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -157,7 +157,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
qmi_servreg_notif_query_state_req_msg_v01,
@@ -165,8 +165,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -175,7 +175,7 @@
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_notif_query_state_resp_msg_v01,
@@ -186,7 +186,7 @@
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_notif_query_state_resp_msg_v01,
@@ -197,7 +197,7 @@
.elem_len = 1,
.elem_size = sizeof(enum
qmi_servreg_notif_service_state_enum_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
qmi_servreg_notif_query_state_resp_msg_v01,
@@ -205,8 +205,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -216,7 +216,7 @@
.elem_len = 1,
.elem_size = sizeof(enum
qmi_servreg_notif_service_state_enum_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
qmi_servreg_notif_state_updated_ind_msg_v01,
@@ -226,7 +226,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_notif_state_updated_ind_msg_v01,
@@ -236,7 +236,7 @@
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint16_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x03,
.offset = offsetof(struct
qmi_servreg_notif_state_updated_ind_msg_v01,
@@ -244,8 +244,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -254,7 +254,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
qmi_servreg_notif_set_ack_req_msg_v01,
@@ -264,7 +264,7 @@
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint16_t),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_notif_set_ack_req_msg_v01,
@@ -272,8 +272,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -282,7 +282,7 @@
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_notif_set_ack_resp_msg_v01,
@@ -291,8 +291,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -301,7 +301,7 @@
.data_type = QMI_STRING,
.elem_len = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
.elem_size = sizeof(char),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
qmi_servreg_notif_restart_pd_req_msg_v01,
@@ -309,8 +309,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -319,7 +319,7 @@
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
- .is_array = NO_ARRAY,
+ .array_type = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
qmi_servreg_notif_restart_pd_resp_msg_v01,
@@ -328,8 +328,8 @@
},
{
.data_type = QMI_EOTI,
- .is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .array_type = NO_ARRAY,
+ .array_type = QMI_COMMON_TLV_TYPE,
},
};
#endif
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 0d3b70b..633632a 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -24,4 +24,14 @@
This is required for communicating with Qualcomm PMICs and
other devices that have the SPMI interface.
+config SPMI_MSM_PMIC_ARB_DEBUG
+ tristate "QTI SPMI Debug Controller (PMIC Arbiter)"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ built-in SPMI PMIC Arbiter debug interface on Qualcomm Technologies,
+ Inc. (QTI) MSM family processors. This feature is available on chips
+ with PMIC arbiter version 5 and above.
+
endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index fc75104..4f20815 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_SPMI) += spmi.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
+obj-$(CONFIG_SPMI_MSM_PMIC_ARB_DEBUG) += spmi-pmic-arb-debug.o
diff --git a/drivers/spmi/spmi-pmic-arb-debug.c b/drivers/spmi/spmi-pmic-arb-debug.c
new file mode 100644
index 0000000..ce34687
--- /dev/null
+++ b/drivers/spmi/spmi-pmic-arb-debug.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/* PMIC Arbiter debug register offsets */
+#define PMIC_ARB_DEBUG_CMD0 0x00
+#define PMIC_ARB_DEBUG_CMD1 0x04
+#define PMIC_ARB_DEBUG_CMD2 0x08
+#define PMIC_ARB_DEBUG_CMD3 0x0C
+#define PMIC_ARB_DEBUG_STATUS 0x14
+#define PMIC_ARB_DEBUG_WDATA(n) (0x18 + 4 * (n))
+#define PMIC_ARB_DEBUG_RDATA(n) (0x38 + 4 * (n))
+
+/* Transaction status flag bits */
+enum pmic_arb_chnl_status {
+ PMIC_ARB_STATUS_DONE = BIT(0),
+ PMIC_ARB_STATUS_FAILURE = BIT(1),
+ PMIC_ARB_STATUS_DENIED = BIT(2),
+ PMIC_ARB_STATUS_DROPPED = BIT(3),
+};
+
+/* Command Opcodes */
+enum pmic_arb_cmd_op_code {
+ PMIC_ARB_OP_EXT_WRITEL = 0,
+ PMIC_ARB_OP_EXT_READL = 1,
+ PMIC_ARB_OP_EXT_WRITE = 2,
+ PMIC_ARB_OP_RESET = 3,
+ PMIC_ARB_OP_SLEEP = 4,
+ PMIC_ARB_OP_SHUTDOWN = 5,
+ PMIC_ARB_OP_WAKEUP = 6,
+ PMIC_ARB_OP_AUTHENTICATE = 7,
+ PMIC_ARB_OP_MSTR_READ = 8,
+ PMIC_ARB_OP_MSTR_WRITE = 9,
+ PMIC_ARB_OP_EXT_READ = 13,
+ PMIC_ARB_OP_WRITE = 14,
+ PMIC_ARB_OP_READ = 15,
+ PMIC_ARB_OP_ZERO_WRITE = 16,
+};
+
+#define PMIC_ARB_TIMEOUT_US 100
+#define PMIC_ARB_MAX_TRANS_BYTES 8
+#define PMIC_ARB_MAX_SID 0xF
+
+/**
+ * spmi_pmic_arb_debug - SPMI PMIC Arbiter debug object
+ *
+ * @addr: base address of SPMI PMIC arbiter debug module
+ * @lock: lock to synchronize accesses.
+ */
+struct spmi_pmic_arb_debug {
+ void __iomem *addr;
+ raw_spinlock_t lock;
+};
+
+static inline void pmic_arb_debug_write(struct spmi_pmic_arb_debug *pa,
+ u32 offset, u32 val)
+{
+ writel_relaxed(val, pa->addr + offset);
+}
+
+static inline u32 pmic_arb_debug_read(struct spmi_pmic_arb_debug *pa,
+ u32 offset)
+{
+ return readl_relaxed(pa->addr + offset);
+}
+
+/* pa->lock must be held by the caller. */
+static int pmic_arb_debug_wait_for_done(struct spmi_controller *ctrl)
+{
+ struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+ u32 status = 0;
+ u32 timeout = PMIC_ARB_TIMEOUT_US;
+
+ while (timeout--) {
+ status = pmic_arb_debug_read(pa, PMIC_ARB_DEBUG_STATUS);
+
+ if (status & PMIC_ARB_STATUS_DONE) {
+ if (status & PMIC_ARB_STATUS_DENIED) {
+ dev_err(&ctrl->dev, "%s: transaction denied (0x%x)\n",
+ __func__, status);
+ return -EPERM;
+ }
+
+ if (status & PMIC_ARB_STATUS_FAILURE) {
+ dev_err(&ctrl->dev, "%s: transaction failed (0x%x)\n",
+ __func__, status);
+ return -EIO;
+ }
+
+ if (status & PMIC_ARB_STATUS_DROPPED) {
+ dev_err(&ctrl->dev, "%s: transaction dropped (0x%x)\n",
+ __func__, status);
+ return -EIO;
+ }
+
+ return 0;
+ }
+ udelay(1);
+ }
+
+ dev_err(&ctrl->dev, "%s: timeout, status 0x%x\n", __func__, status);
+ return -ETIMEDOUT;
+}
+
+/* pa->lock must be held by the caller. */
+static int pmic_arb_debug_issue_command(struct spmi_controller *ctrl, u8 opc,
+ u8 sid, u16 addr, size_t len)
+{
+ struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+ u16 pid = (addr >> 8) & 0xFF;
+ u16 offset = addr & 0xFF;
+ u8 byte_count = len - 1;
+
+ if (byte_count >= PMIC_ARB_MAX_TRANS_BYTES) {
+ dev_err(&ctrl->dev, "pmic-arb supports 1 to %d bytes per transaction, but %zu requested\n",
+ PMIC_ARB_MAX_TRANS_BYTES, len);
+ return -EINVAL;
+ }
+
+ if (sid > PMIC_ARB_MAX_SID) {
+ dev_err(&ctrl->dev, "pmic-arb supports sid 0 to %u, but %u requested\n",
+ PMIC_ARB_MAX_SID, sid);
+ return -EINVAL;
+ }
+
+ pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD3, offset);
+ pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD2, pid);
+ pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD1, (byte_count << 4) | sid);
+
+ /* Start the transaction */
+ pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD0, opc << 1);
+
+ return pmic_arb_debug_wait_for_done(ctrl);
+}
+
+/* Non-data command */
+static int pmic_arb_debug_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
+{
+ dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid);
+
+ /* Check for valid non-data command */
+ if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
+ return -EINVAL;
+
+ return -EOPNOTSUPP;
+}
+
+static int pmic_arb_debug_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+ u16 addr, u8 *buf, size_t len)
+{
+ struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+ unsigned long flags;
+ int i, rc;
+
+ /* Check the opcode */
+ if (opc >= 0x60 && opc <= 0x7F)
+ opc = PMIC_ARB_OP_READ;
+ else if (opc >= 0x20 && opc <= 0x2F)
+ opc = PMIC_ARB_OP_EXT_READ;
+ else if (opc >= 0x38 && opc <= 0x3F)
+ opc = PMIC_ARB_OP_EXT_READL;
+ else
+ return -EINVAL;
+
+ raw_spin_lock_irqsave(&pa->lock, flags);
+
+ rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len);
+ if (rc)
+ goto done;
+
+ /* Read data from FIFO */
+ for (i = 0; i < len; i++)
+ buf[i] = pmic_arb_debug_read(pa, PMIC_ARB_DEBUG_RDATA(i));
+done:
+ raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+ return rc;
+}
+
+static int pmic_arb_debug_write_cmd(struct spmi_controller *ctrl, u8 opc,
+ u8 sid, u16 addr, const u8 *buf, size_t len)
+{
+ struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+ unsigned long flags;
+ int i, rc;
+
+ if (len > PMIC_ARB_MAX_TRANS_BYTES) {
+ dev_err(&ctrl->dev, "pmic-arb supports 1 to %d bytes per transaction, but %zu requested\n",
+ PMIC_ARB_MAX_TRANS_BYTES, len);
+ return -EINVAL;
+ }
+
+ /* Check the opcode */
+ if (opc >= 0x40 && opc <= 0x5F)
+ opc = PMIC_ARB_OP_WRITE;
+ else if (opc >= 0x00 && opc <= 0x0F)
+ opc = PMIC_ARB_OP_EXT_WRITE;
+ else if (opc >= 0x30 && opc <= 0x37)
+ opc = PMIC_ARB_OP_EXT_WRITEL;
+ else if (opc >= 0x80)
+ opc = PMIC_ARB_OP_ZERO_WRITE;
+ else
+ return -EINVAL;
+
+ raw_spin_lock_irqsave(&pa->lock, flags);
+
+ /* Write data to FIFO */
+ for (i = 0; i < len; i++)
+ pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_WDATA(i), buf[i]);
+
+ rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len);
+
+ raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+ return rc;
+}
+
+static int spmi_pmic_arb_debug_probe(struct platform_device *pdev)
+{
+ struct spmi_pmic_arb_debug *pa;
+ struct spmi_controller *ctrl;
+ struct resource *res;
+ int rc;
+ u32 fuse_val, fuse_bit;
+ void __iomem *fuse_addr;
+
+ /* Check if the debug bus is disabled by a fuse. */
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,fuse-disable-bit",
+ &fuse_bit);
+ if (!rc) {
+ if (fuse_bit > 31) {
+ dev_err(&pdev->dev, "qcom,fuse-disable-bit supports values 0 to 31, but %u specified\n",
+ fuse_bit);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "fuse");
+ if (!res) {
+ dev_err(&pdev->dev, "fuse address not specified\n");
+ return -EINVAL;
+ }
+
+ fuse_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(fuse_addr))
+ return PTR_ERR(fuse_addr);
+
+ fuse_val = readl_relaxed(fuse_addr);
+ devm_iounmap(&pdev->dev, fuse_addr);
+
+ if (fuse_val & BIT(fuse_bit)) {
+ dev_err(&pdev->dev, "SPMI PMIC arbiter debug bus disabled by fuse\n");
+ return -ENODEV;
+ }
+ }
+
+
+ ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
+ if (!ctrl)
+ return -ENOMEM;
+
+ pa = spmi_controller_get_drvdata(ctrl);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+ if (!res) {
+ dev_err(&pdev->dev, "core address not specified\n");
+ rc = -EINVAL;
+ goto err_put_ctrl;
+ }
+
+ pa->addr = devm_ioremap_resource(&ctrl->dev, res);
+ if (IS_ERR(pa->addr)) {
+ rc = PTR_ERR(pa->addr);
+ goto err_put_ctrl;
+ }
+
+ platform_set_drvdata(pdev, ctrl);
+ raw_spin_lock_init(&pa->lock);
+
+ ctrl->cmd = pmic_arb_debug_cmd;
+ ctrl->read_cmd = pmic_arb_debug_read_cmd;
+ ctrl->write_cmd = pmic_arb_debug_write_cmd;
+
+ rc = spmi_controller_add(ctrl);
+ if (rc)
+ goto err_put_ctrl;
+
+ dev_info(&ctrl->dev, "SPMI PMIC arbiter debug bus controller added\n");
+
+ return 0;
+
+err_put_ctrl:
+ spmi_controller_put(ctrl);
+ return rc;
+}
+
+static int spmi_pmic_arb_debug_remove(struct platform_device *pdev)
+{
+ struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+
+ spmi_controller_remove(ctrl);
+ spmi_controller_put(ctrl);
+
+ return 0;
+}
+
+static const struct of_device_id spmi_pmic_arb_debug_match_table[] = {
+ { .compatible = "qcom,spmi-pmic-arb-debug", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, spmi_pmic_arb_debug_match_table);
+
+static struct platform_driver spmi_pmic_arb_debug_driver = {
+ .probe = spmi_pmic_arb_debug_probe,
+ .remove = spmi_pmic_arb_debug_remove,
+ .driver = {
+ .name = "spmi_pmic_arb_debug",
+ .of_match_table = spmi_pmic_arb_debug_match_table,
+ },
+};
+
+int __init spmi_pmic_arb_debug_init(void)
+{
+ return platform_driver_register(&spmi_pmic_arb_debug_driver);
+}
+arch_initcall(spmi_pmic_arb_debug_init);
+
+static void __exit spmi_pmic_arb_debug_exit(void)
+{
+ platform_driver_unregister(&spmi_pmic_arb_debug_driver);
+}
+module_exit(spmi_pmic_arb_debug_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spmi_pmic_arb_debug");
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index f066681..22cc80f 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -90,7 +90,7 @@
/* Maximum number of support PMIC peripherals */
#define PMIC_ARB_MAX_PERIPHS 512
-#define PMIC_ARB_TIMEOUT_US 100
+#define PMIC_ARB_TIMEOUT_US 1000
#define PMIC_ARB_MAX_TRANS_BYTES (8)
#define PMIC_ARB_APID_MASK 0xFF
@@ -491,16 +491,6 @@
dev_err_ratelimited(&pmic_arb->spmic->dev, "%s apid=%d sid=0x%x per=0x%x irq=%d\n",
__func__, apid, sid, per, id);
writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
-
- if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
- (per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1))
- dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n",
- irq_mask, ppid);
-
- if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
- (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1))
- dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n",
- irq_mask, ppid);
}
static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid)
@@ -535,16 +525,28 @@
u8 ee = pmic_arb->ee;
u32 status, enable;
int i, id, apid;
+ /* status based dispatch */
+ bool acc_valid = false;
+ u32 irq_status = 0;
chained_irq_enter(chip, desc);
for (i = first; i <= last; ++i) {
status = readl_relaxed(
ver_ops->owner_acc_status(pmic_arb, ee, i));
+ if (status)
+ acc_valid = true;
+
while (status) {
id = ffs(status) - 1;
status &= ~BIT(id);
apid = id + i * 32;
+ if (apid < pmic_arb->min_apid
+ || apid > pmic_arb->max_apid) {
+ WARN_ONCE(true, "spurious spmi irq received for apid=%d\n",
+ apid);
+ continue;
+ }
enable = readl_relaxed(
ver_ops->acc_enable(pmic_arb, apid));
if (enable & SPMI_PIC_ACC_ENABLE_BIT)
@@ -552,6 +554,28 @@
}
}
+ /* ACC_STATUS is empty but IRQ fired check IRQ_STATUS */
+ if (!acc_valid) {
+ for (i = pmic_arb->min_apid; i <= pmic_arb->max_apid; i++) {
+ /* skip if APPS is not irq owner */
+ if (pmic_arb->apid_data[i].irq_ee != pmic_arb->ee)
+ continue;
+
+ irq_status = readl_relaxed(
+ ver_ops->irq_status(pmic_arb, i));
+ if (irq_status) {
+ enable = readl_relaxed(
+ ver_ops->acc_enable(pmic_arb, i));
+ if (enable & SPMI_PIC_ACC_ENABLE_BIT) {
+ dev_dbg(&pmic_arb->spmic->dev,
+ "Dispatching IRQ for apid=%d status=%x\n",
+ i, irq_status);
+ periph_interrupt(pmic_arb, i);
+ }
+ }
+ }
+ }
+
chained_irq_exit(chip, desc);
}
@@ -689,6 +713,19 @@
.flags = IRQCHIP_MASK_ON_SUSPEND,
};
+static int qpnpint_irq_domain_activate(struct irq_domain *domain,
+ struct irq_data *d, bool reserve)
+{
+ u8 irq = hwirq_to_irq(d->hwirq);
+ u8 buf;
+
+ buf = BIT(irq);
+ qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &buf, 1);
+ qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 1);
+
+ return 0;
+}
+
static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
struct device_node *controller,
const u32 *intspec,
@@ -860,7 +897,8 @@
* version 5, there is more than one APID mapped to each PPID.
* The owner field for each of these mappings specifies the EE which is
* allowed to write to the APID. The owner of the last (highest) APID
- * for a given PPID will receive interrupts from the PPID.
+ * which has the IRQ owner bit set for a given PPID will receive
+ * interrupts from the PPID.
*/
for (i = 0; ; i++, apidd++) {
offset = pmic_arb->ver_ops->apid_map_offset(i);
@@ -883,16 +921,16 @@
apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
prev_apidd = &pmic_arb->apid_data[apid];
- if (valid && is_irq_ee &&
- prev_apidd->write_ee == pmic_arb->ee) {
+ if (!valid || apidd->write_ee == pmic_arb->ee) {
+ /* First PPID mapping or one for this EE */
+ pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
+ } else if (valid && is_irq_ee &&
+ prev_apidd->write_ee == pmic_arb->ee) {
/*
* Duplicate PPID mapping after the one for this EE;
* override the irq owner
*/
prev_apidd->irq_ee = apidd->irq_ee;
- } else if (!valid || is_irq_ee) {
- /* First PPID mapping or duplicate for another EE */
- pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
}
apidd->ppid = ppid;
@@ -961,6 +999,11 @@
offset = 0x10000 * pmic_arb->ee + 0x80 * apid;
break;
case PMIC_ARB_CHANNEL_RW:
+ if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
+ dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
+ sid, addr);
+ return -EPERM;
+ }
offset = 0x10000 * apid;
break;
}
@@ -1121,6 +1164,7 @@
static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
.map = qpnpint_irq_domain_map,
.xlate = qpnpint_irq_domain_dt_translate,
+ .activate = qpnpint_irq_domain_activate,
};
static int spmi_pmic_arb_probe(struct platform_device *pdev)
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index c82ea12..efa917a 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2372,7 +2372,7 @@
clk_disable_unprepare(mdwc->sleep_clk);
if (mdwc->iommu_map) {
- arm_iommu_detach_device(mdwc->dev);
+ __depr_arm_iommu_detach_device(mdwc->dev);
dev_dbg(mdwc->dev, "IOMMU detached\n");
}
}
@@ -2518,7 +2518,7 @@
u32 tmp;
if (mdwc->iommu_map) {
- ret = arm_iommu_attach_device(mdwc->dev,
+ ret = __depr_arm_iommu_attach_device(mdwc->dev,
mdwc->iommu_map);
if (ret)
dev_err(mdwc->dev, "IOMMU attach failed (%d)\n",
@@ -3091,7 +3091,7 @@
if (!of_property_read_bool(node, "iommus"))
return 0;
- mdwc->iommu_map = arm_iommu_create_mapping(&platform_bus_type,
+ mdwc->iommu_map = __depr_arm_iommu_create_mapping(&platform_bus_type,
SMMU_BASE, SMMU_SIZE);
if (IS_ERR_OR_NULL(mdwc->iommu_map)) {
ret = PTR_ERR(mdwc->iommu_map) ?: -ENODEV;
@@ -3118,7 +3118,7 @@
goto release_mapping;
}
- ret = arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map);
+ ret = __depr_arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map);
if (ret) {
dev_err(mdwc->dev, "IOMMU attach failed (%d)\n", ret);
goto release_mapping;
@@ -3128,7 +3128,7 @@
return 0;
release_mapping:
- arm_iommu_release_mapping(mdwc->iommu_map);
+ __depr_arm_iommu_release_mapping(mdwc->iommu_map);
mdwc->iommu_map = NULL;
return ret;
}
@@ -3555,7 +3555,7 @@
/* IOMMU will be reattached upon each resume/connect */
if (mdwc->iommu_map)
- arm_iommu_detach_device(mdwc->dev);
+ __depr_arm_iommu_detach_device(mdwc->dev);
/*
* Clocks and regulators will not be turned on until the first time
@@ -3606,8 +3606,8 @@
uninit_iommu:
if (mdwc->iommu_map) {
- arm_iommu_detach_device(mdwc->dev);
- arm_iommu_release_mapping(mdwc->iommu_map);
+ __depr_arm_iommu_detach_device(mdwc->dev);
+ __depr_arm_iommu_release_mapping(mdwc->iommu_map);
}
of_platform_depopulate(&pdev->dev);
err:
@@ -3687,8 +3687,8 @@
if (mdwc->iommu_map) {
if (!atomic_read(&dwc->in_lpm))
- arm_iommu_detach_device(mdwc->dev);
- arm_iommu_release_mapping(mdwc->iommu_map);
+ __depr_arm_iommu_detach_device(mdwc->dev);
+ __depr_arm_iommu_release_mapping(mdwc->iommu_map);
}
return 0;
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 349e595..99ccc84f 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -96,6 +96,7 @@
extern u64 (*arch_timer_read_counter)(void);
extern struct arch_timer_kvm_info *arch_timer_get_kvm_info(void);
extern bool arch_timer_evtstrm_available(void);
+extern void arch_timer_mem_get_cval(u32 *lo, u32 *hi);
#else
@@ -114,6 +115,10 @@
return false;
}
+static void arch_timer_mem_get_cval(u32 *lo, u32 *hi)
+{
+ *lo = *hi = ~0U;
+}
#endif
#endif
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index bd5e8cc..21371ac 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -20,8 +20,10 @@
/*
* Maximum values for blocksize and alignmask, used to allocate
* static buffers that are big enough for any combination of
- * ciphers and architectures.
+ * algs and architectures. Ciphers have a lower maximum size.
*/
+#define MAX_ALGAPI_BLOCKSIZE 160
+#define MAX_ALGAPI_ALIGNMASK 63
#define MAX_CIPHER_BLOCKSIZE 16
#define MAX_CIPHER_ALIGNMASK 15
diff --git a/include/crypto/cbc.h b/include/crypto/cbc.h
index f5b8bfc..3bf28bee 100644
--- a/include/crypto/cbc.h
+++ b/include/crypto/cbc.h
@@ -113,7 +113,7 @@
unsigned int bsize = crypto_skcipher_blocksize(tfm);
unsigned int nbytes = walk->nbytes;
u8 *src = walk->src.virt.addr;
- u8 last_iv[bsize];
+ u8 last_iv[MAX_CIPHER_BLOCKSIZE];
/* Start of the last block. */
src += nbytes - (nbytes & (bsize - 1)) - bsize;
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 76e432c..2158701 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -151,9 +151,13 @@
void *__ctx[] CRYPTO_MINALIGN_ATTR;
};
+#define HASH_MAX_DIGESTSIZE 64
+#define HASH_MAX_DESCSIZE 360
+#define HASH_MAX_STATESIZE 512
+
#define SHASH_DESC_ON_STACK(shash, ctx) \
char __##shash##_desc[sizeof(struct shash_desc) + \
- crypto_shash_descsize(ctx)] CRYPTO_MINALIGN_ATTR; \
+ HASH_MAX_DESCSIZE] CRYPTO_MINALIGN_ATTR; \
struct shash_desc *shash = (struct shash_desc *)__##shash##_desc
/**
diff --git a/include/crypto/internal/geniv.h b/include/crypto/internal/geniv.h
index 2bcfb93..71be24c 100644
--- a/include/crypto/internal/geniv.h
+++ b/include/crypto/internal/geniv.h
@@ -20,7 +20,7 @@
struct aead_geniv_ctx {
spinlock_t lock;
struct crypto_aead *child;
- struct crypto_skcipher *sknull;
+ struct crypto_sync_skcipher *sknull;
u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
};
diff --git a/include/crypto/null.h b/include/crypto/null.h
index 15aeef6..0ef577c 100644
--- a/include/crypto/null.h
+++ b/include/crypto/null.h
@@ -9,7 +9,7 @@
#define NULL_DIGEST_SIZE 0
#define NULL_IV_SIZE 0
-struct crypto_skcipher *crypto_get_default_null_skcipher(void);
+struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void);
void crypto_put_default_null_skcipher(void);
#endif
diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h
index 2f327f0..45ae894 100644
--- a/include/crypto/skcipher.h
+++ b/include/crypto/skcipher.h
@@ -65,6 +65,10 @@
struct crypto_tfm base;
};
+struct crypto_sync_skcipher {
+ struct crypto_skcipher base;
+};
+
/**
* struct skcipher_alg - symmetric key cipher definition
* @min_keysize: Minimum key size supported by the transformation. This is the
@@ -139,9 +143,17 @@
struct crypto_alg base;
};
-#define SKCIPHER_REQUEST_ON_STACK(name, tfm) \
+#define MAX_SYNC_SKCIPHER_REQSIZE 384
+/*
+ * This performs a type-check against the "tfm" argument to make sure
+ * all users have the correct skcipher tfm for doing on-stack requests.
+ */
+#define SYNC_SKCIPHER_REQUEST_ON_STACK(name, tfm) \
char __##name##_desc[sizeof(struct skcipher_request) + \
- crypto_skcipher_reqsize(tfm)] CRYPTO_MINALIGN_ATTR; \
+ MAX_SYNC_SKCIPHER_REQSIZE + \
+ (!(sizeof((struct crypto_sync_skcipher *)1 == \
+ (typeof(tfm))1))) \
+ ] CRYPTO_MINALIGN_ATTR; \
struct skcipher_request *name = (void *)__##name##_desc
/**
@@ -197,6 +209,9 @@
struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name,
u32 type, u32 mask);
+struct crypto_sync_skcipher *crypto_alloc_sync_skcipher(const char *alg_name,
+ u32 type, u32 mask);
+
static inline struct crypto_tfm *crypto_skcipher_tfm(
struct crypto_skcipher *tfm)
{
@@ -212,6 +227,11 @@
crypto_destroy_tfm(tfm, crypto_skcipher_tfm(tfm));
}
+static inline void crypto_free_sync_skcipher(struct crypto_sync_skcipher *tfm)
+{
+ crypto_free_skcipher(&tfm->base);
+}
+
/**
* crypto_has_skcipher() - Search for the availability of an skcipher.
* @alg_name: is the cra_name / name or cra_driver_name / driver name of the
@@ -280,6 +300,12 @@
return tfm->ivsize;
}
+static inline unsigned int crypto_sync_skcipher_ivsize(
+ struct crypto_sync_skcipher *tfm)
+{
+ return crypto_skcipher_ivsize(&tfm->base);
+}
+
static inline unsigned int crypto_skcipher_alg_chunksize(
struct skcipher_alg *alg)
{
@@ -356,6 +382,12 @@
return crypto_tfm_alg_blocksize(crypto_skcipher_tfm(tfm));
}
+static inline unsigned int crypto_sync_skcipher_blocksize(
+ struct crypto_sync_skcipher *tfm)
+{
+ return crypto_skcipher_blocksize(&tfm->base);
+}
+
static inline unsigned int crypto_skcipher_alignmask(
struct crypto_skcipher *tfm)
{
@@ -379,6 +411,24 @@
crypto_tfm_clear_flags(crypto_skcipher_tfm(tfm), flags);
}
+static inline u32 crypto_sync_skcipher_get_flags(
+ struct crypto_sync_skcipher *tfm)
+{
+ return crypto_skcipher_get_flags(&tfm->base);
+}
+
+static inline void crypto_sync_skcipher_set_flags(
+ struct crypto_sync_skcipher *tfm, u32 flags)
+{
+ crypto_skcipher_set_flags(&tfm->base, flags);
+}
+
+static inline void crypto_sync_skcipher_clear_flags(
+ struct crypto_sync_skcipher *tfm, u32 flags)
+{
+ crypto_skcipher_clear_flags(&tfm->base, flags);
+}
+
/**
* crypto_skcipher_setkey() - set key for cipher
* @tfm: cipher handle
@@ -401,6 +451,12 @@
return tfm->setkey(tfm, key, keylen);
}
+static inline int crypto_sync_skcipher_setkey(struct crypto_sync_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return crypto_skcipher_setkey(&tfm->base, key, keylen);
+}
+
static inline unsigned int crypto_skcipher_default_keysize(
struct crypto_skcipher *tfm)
{
@@ -422,6 +478,14 @@
return __crypto_skcipher_cast(req->base.tfm);
}
+static inline struct crypto_sync_skcipher *crypto_sync_skcipher_reqtfm(
+ struct skcipher_request *req)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+
+ return container_of(tfm, struct crypto_sync_skcipher, base);
+}
+
/**
* crypto_skcipher_encrypt() - encrypt plaintext
* @req: reference to the skcipher_request handle that holds all information
@@ -500,6 +564,12 @@
req->base.tfm = crypto_skcipher_tfm(tfm);
}
+static inline void skcipher_request_set_sync_tfm(struct skcipher_request *req,
+ struct crypto_sync_skcipher *tfm)
+{
+ skcipher_request_set_tfm(req, &tfm->base);
+}
+
static inline struct skcipher_request *skcipher_request_cast(
struct crypto_async_request *req)
{
diff --git a/include/dt-bindings/msm/pm.h b/include/dt-bindings/msm/pm.h
new file mode 100644
index 0000000..f7bb19d
--- /dev/null
+++ b/include/dt-bindings/msm/pm.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __DT_MSM_PM_H__
+#define __DT_MSM_PM_H__
+
+#define LPM_RESET_LVL_NONE 0
+#define LPM_RESET_LVL_RET 1
+#define LPM_RESET_LVL_GDHS 2
+#define LPM_RESET_LVL_PC 3
+
+#define LPM_AFF_LVL_CPU 0
+#define LPM_AFF_LVL_L2 1
+#define LPM_AFF_LVL_CCI 2
+
+#endif
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index ecb53be..5e0aaa5 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -202,7 +202,6 @@
*/
#define __pure __attribute__((pure))
#define __aligned(x) __attribute__((aligned(x)))
-#define __aligned_largest __attribute__((aligned))
#define __printf(a, b) __attribute__((format(printf, a, b)))
#define __scanf(a, b) __attribute__((format(scanf, a, b)))
#define __maybe_unused __attribute__((unused))
diff --git a/include/linux/leds-qpnp-flash-v2.h b/include/linux/leds-qpnp-flash-v2.h
new file mode 100644
index 0000000..b961ab1
--- /dev/null
+++ b/include/linux/leds-qpnp-flash-v2.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __LEDS_QPNP_FLASH_V2_H
+#define __LEDS_QPNP_FLASH_V2_H
+
+#include <linux/leds.h>
+#include <linux/notifier.h>
+
+enum flash_led_irq_type {
+ LED_FAULT_IRQ = BIT(0),
+ MITIGATION_IRQ = BIT(1),
+ FLASH_TIMER_EXP_IRQ = BIT(2),
+ ALL_RAMP_DOWN_DONE_IRQ = BIT(3),
+ ALL_RAMP_UP_DONE_IRQ = BIT(4),
+ LED3_RAMP_UP_DONE_IRQ = BIT(5),
+ LED2_RAMP_UP_DONE_IRQ = BIT(6),
+ LED1_RAMP_UP_DONE_IRQ = BIT(7),
+ INVALID_IRQ = BIT(8),
+};
+
+int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb);
+int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb);
+
+#endif
diff --git a/include/linux/leds-qpnp-flash.h b/include/linux/leds-qpnp-flash.h
new file mode 100644
index 0000000..d820d2c
--- /dev/null
+++ b/include/linux/leds-qpnp-flash.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __LEDS_QPNP_FLASH_H
+#define __LEDS_QPNP_FLASH_H
+
+#include <linux/leds.h>
+
+#define ENABLE_REGULATOR BIT(0)
+#define DISABLE_REGULATOR BIT(1)
+#define QUERY_MAX_AVAIL_CURRENT BIT(2)
+#define QUERY_MAX_CURRENT BIT(3)
+
+#define FLASH_LED_PREPARE_OPTIONS_MASK GENMASK(3, 0)
+
+int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+ int *max_current);
+#ifdef CONFIG_BACKLIGHT_QCOM_SPMI_WLED
+int wled_flash_led_prepare(struct led_trigger *trig, int options,
+ int *max_current);
+#else
+static inline int wled_flash_led_prepare(struct led_trigger *trig, int options,
+ int *max_current)
+{
+ return -EINVAL;
+}
+#endif
+
+#endif
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 816372f..9af7e19 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -119,4 +119,8 @@
extern int sysctl_oom_dump_tasks;
extern int sysctl_oom_kill_allocating_task;
extern int sysctl_panic_on_oom;
+extern int sysctl_reap_mem_on_sigkill;
+
+/* calls for LMK reaper */
+extern void add_to_oom_reaper(struct task_struct *p);
#endif /* _INCLUDE_LINUX_OOM_H */
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
new file mode 100644
index 0000000..7bd1e8e
--- /dev/null
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __QPNP_REVID
+#define __QPNP_REVID
+
+/* Common TYPE for all PMICs */
+#define PMIC_TYPE 0x51
+
+/* PM8994 */
+#define PM8941_SUBTYPE 0x01
+
+#define PM8941_V1P0_REV1 0x00
+#define PM8941_V1P0_REV2 0x00
+#define PM8941_V1P0_REV3 0x00
+#define PM8941_V1P0_REV4 0x01
+
+#define PM8941_V2P0_REV1 0x00
+#define PM8941_V2P0_REV2 0x00
+#define PM8941_V2P0_REV3 0x00
+#define PM8941_V2P0_REV4 0x01
+
+#define PM8941_V3P0_REV1 0x00
+#define PM8941_V3P0_REV2 0x00
+#define PM8941_V3P0_REV3 0x00
+#define PM8941_V3P0_REV4 0x03
+
+#define PM8941_V3P1_REV1 0x00
+#define PM8941_V3P1_REV2 0x00
+#define PM8941_V3P1_REV3 0x01
+#define PM8941_V3P1_REV4 0x03
+
+/* PM8841 */
+#define PM8841_SUBTYPE 0x02
+
+/* PM8019 */
+#define PM8019_SUBTYPE 0x03
+
+/* PM8226 */
+#define PM8226_SUBTYPE 0x04
+
+#define PM8226_V2P2_REV1 0x00
+#define PM8226_V2P2_REV2 0x00
+#define PM8226_V2P2_REV3 0x02
+#define PM8226_V2P2_REV4 0x02
+
+#define PM8226_V2P1_REV1 0x00
+#define PM8226_V2P1_REV2 0x00
+#define PM8226_V2P1_REV3 0x01
+#define PM8226_V2P1_REV4 0x02
+
+#define PM8226_V2P0_REV1 0x00
+#define PM8226_V2P0_REV2 0x00
+#define PM8226_V2P0_REV3 0x00
+#define PM8226_V2P0_REV4 0x02
+
+#define PM8226_V1P0_REV1 0x00
+#define PM8226_V1P0_REV2 0x00
+#define PM8226_V1P0_REV3 0x00
+#define PM8226_V1P0_REV4 0x00
+
+/* PM8110 */
+#define PM8110_SUBTYPE 0x05
+
+#define PM8110_V1P0_REV1 0x00
+#define PM8110_V1P0_REV2 0x00
+#define PM8110_V1P0_REV3 0x00
+#define PM8110_V1P0_REV4 0x01
+
+#define PM8110_V1P1_REV1 0x00
+#define PM8110_V1P1_REV2 0x01
+#define PM8110_V1P1_REV3 0x00
+#define PM8110_V1P1_REV4 0x01
+
+#define PM8110_V1P3_REV1 0x00
+#define PM8110_V1P3_REV2 0x03
+#define PM8110_V1P3_REV3 0x00
+#define PM8110_V1P3_REV4 0x01
+
+#define PM8110_V2P0_REV1 0x00
+#define PM8110_V2P0_REV2 0x00
+#define PM8110_V2P0_REV3 0x00
+#define PM8110_V2P0_REV4 0x02
+
+/* PMA8084 */
+#define PMA8084_SUBTYPE 0x06
+
+/* PMI8962 */
+#define PMI8962_SUBTYPE 0x07
+
+/* PMD9635 */
+#define PMD9635_SUBTYPE 0x08
+/* PM8994 */
+#define PM8994_SUBTYPE 0x09
+
+/* PMI8994 */
+#define PMI8994_TYPE 0x51
+#define PMI8994_SUBTYPE 0x0A
+
+#define PMI8994_V1P0_REV1 0x00
+#define PMI8994_V1P0_REV2 0x00
+#define PMI8994_V1P0_REV3 0x00
+#define PMI8994_V1P0_REV4 0x01
+
+#define PMI8994_V2P0_REV1 0x00
+#define PMI8994_V2P0_REV2 0x00
+#define PMI8994_V2P0_REV3 0x00
+#define PMI8994_V2P0_REV4 0x02
+
+/* PM8916 */
+#define PM8916_SUBTYPE 0x0B
+
+#define PM8916_V1P0_REV1 0x00
+#define PM8916_V1P0_REV2 0x00
+#define PM8916_V1P0_REV3 0x00
+#define PM8916_V1P0_REV4 0x01
+
+#define PM8916_V1P1_REV1 0x00
+#define PM8916_V1P1_REV2 0x00
+#define PM8916_V1P1_REV3 0x01
+#define PM8916_V1P1_REV4 0x01
+
+#define PM8916_V2P0_REV1 0x00
+#define PM8916_V2P0_REV2 0x00
+#define PM8916_V2P0_REV3 0x00
+#define PM8916_V2P0_REV4 0x02
+
+/* PM8004 */
+#define PM8004_SUBTYPE 0x0C
+
+/* PM8909 */
+#define PM8909_SUBTYPE 0x0D
+
+#define PM8909_V1P0_REV1 0x00
+#define PM8909_V1P0_REV2 0x00
+#define PM8909_V1P0_REV3 0x00
+#define PM8909_V1P0_REV4 0x01
+
+#define PM8909_V1P1_REV1 0x00
+#define PM8909_V1P1_REV2 0x00
+#define PM8909_V1P1_REV3 0x01
+#define PM8909_V1P1_REV4 0x01
+
+/* PM2433 */
+#define PM2433_SUBTYPE 0x0E
+
+/* PMD9655 */
+#define PMD9655_SUBTYPE 0x0F
+
+/* PM8950 */
+#define PM8950_SUBTYPE 0x10
+#define PM8950_V1P0_REV4 0x01
+
+#define PM8950_V2P0_REV4 0x02
+
+/* PMI8950 */
+#define PMI8950_SUBTYPE 0x11
+
+/* PMK8001 */
+#define PMK8001_SUBTYPE 0x12
+
+/* PMI8996 */
+#define PMI8996_SUBTYPE 0x13
+
+/* PM8998 */
+#define PM8998_SUBTYPE 0x14
+
+/* PMI8998 */
+#define PMI8998_SUBTYPE 0x15
+
+/* PM660 */
+#define PM660L_SUBTYPE 0x1A
+#define PM660_SUBTYPE 0x1B
+
+/* PM8150 */
+#define PM8150_SUBTYPE 0x1E
+#define PM8150L_SUBTYPE 0x1F
+#define PM8150B_SUBTYPE 0x20
+
+#define PM6150_SUBTYPE 0x28
+#define PM6150L_SUBTYPE 0x1F
+
+/* PMI632 */
+#define PMI632_SUBTYPE 0x25
+
+/* PMI8998 REV_ID */
+#define PMI8998_V1P0_REV1 0x00
+#define PMI8998_V1P0_REV2 0x00
+#define PMI8998_V1P0_REV3 0x00
+#define PMI8998_V1P0_REV4 0x01
+
+#define PMI8998_V1P1_REV1 0x00
+#define PMI8998_V1P1_REV2 0x00
+#define PMI8998_V1P1_REV3 0x01
+#define PMI8998_V1P1_REV4 0x01
+
+#define PMI8998_V2P0_REV1 0x00
+#define PMI8998_V2P0_REV2 0x00
+#define PMI8998_V2P0_REV3 0x00
+#define PMI8998_V2P0_REV4 0x02
+
+/* PM660 REV_ID */
+#define PM660_V1P0_REV1 0x00
+#define PM660_V1P0_REV2 0x00
+#define PM660_V1P0_REV3 0x00
+#define PM660_V1P0_REV4 0x01
+
+#define PM660_V1P1_REV1 0x00
+#define PM660_V1P1_REV2 0x00
+#define PM660_V1P1_REV3 0x01
+#define PM660_V1P1_REV4 0x01
+
+/* PM660L REV_ID */
+#define PM660L_V1P1_REV1 0x00
+#define PM660L_V1P1_REV2 0x00
+#define PM660L_V1P1_REV3 0x01
+#define PM660L_V1P1_REV4 0x01
+
+#define PM660L_V2P0_REV1 0x00
+#define PM660L_V2P0_REV2 0x00
+#define PM660L_V2P0_REV3 0x00
+#define PM660L_V2P0_REV4 0x02
+
+/* PMI632 REV_ID */
+#define PMI632_V1P0_REV1 0x00
+#define PMI632_V1P0_REV2 0x00
+#define PMI632_V1P0_REV3 0x00
+#define PMI632_V1P0_REV4 0x01
+
+/* PM8150B_REV_ID */
+#define PM8150B_V1P0_REV1 0x00
+#define PM8150B_V1P0_REV2 0x00
+#define PM8150B_V1P0_REV3 0x00
+#define PM8150B_V1P0_REV4 0x01
+
+#define PM8150B_V2P0_REV1 0x00
+#define PM8150B_V2P0_REV2 0x00
+#define PM8150B_V2P0_REV3 0x00
+#define PM8150B_V2P0_REV4 0x02
+
+/* PM8150L_REV_ID */
+#define PM8150L_V1P0_REV1 0x00
+#define PM8150L_V1P0_REV2 0x00
+#define PM8150L_V1P0_REV3 0x00
+#define PM8150L_V1P0_REV4 0x01
+
+#define PM8150L_V2P0_REV1 0x00
+#define PM8150L_V2P0_REV2 0x00
+#define PM8150L_V2P0_REV3 0x00
+#define PM8150L_V2P0_REV4 0x02
+
+#define PM8150L_V3P0_REV1 0x00
+#define PM8150L_V3P0_REV2 0x00
+#define PM8150L_V3P0_REV3 0x00
+#define PM8150L_V3P0_REV4 0x03
+
+#define PM6150_V1P0_REV1 0x00
+#define PM6150_V1P0_REV2 0x00
+#define PM6150_V1P0_REV3 0x00
+#define PM6150_V1P0_REV4 0x01
+
+#define PM6150_V1P1_REV1 0x00
+#define PM6150_V1P1_REV2 0x00
+#define PM6150_V1P1_REV3 0x01
+#define PM6150_V1P1_REV4 0x01
+
+#define PM6150_V2P0_REV1 0x00
+#define PM6150_V2P0_REV2 0x00
+#define PM6150_V2P0_REV3 0x00
+#define PM6150_V2P0_REV4 0x02
+
+/* PMI8998 FAB_ID */
+#define PMI8998_FAB_ID_SMIC 0x11
+#define PMI8998_FAB_ID_GF 0x30
+
+/* PM660 FAB_ID */
+#define PM660_FAB_ID_GF 0x0
+#define PM660_FAB_ID_TSMC 0x2
+#define PM660_FAB_ID_MX 0x3
+
+/* PM8005 */
+#define PM8005_SUBTYPE 0x18
+
+/* PM8937 */
+#define PM8937_SUBTYPE 0x19
+
+/* PMI8937 */
+#define PMI8937_SUBTYPE 0x37
+
+/* SMB1381 */
+#define SMB1381_SUBTYPE 0x17
+
+/* SMB1355 */
+#define SMB1355_SUBTYPE 0x1C
+
+struct pmic_revid_data {
+ u8 rev1;
+ u8 rev2;
+ u8 rev3;
+ u8 rev4;
+ u8 pmic_type;
+ u8 pmic_subtype;
+ const char *pmic_name;
+ int fab_id;
+ int tp_rev;
+};
+
+#ifdef CONFIG_QPNP_REVID
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node);
+#else
+static inline
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+ return NULL;
+}
+#endif
+#endif
diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h
index bdf9047..2fb53c7 100644
--- a/include/linux/soc/qcom/qmi.h
+++ b/include/linux/soc/qcom/qmi.h
@@ -88,6 +88,7 @@
#define QMI_ERR_CLIENT_IDS_EXHAUSTED_V01 5
#define QMI_ERR_INVALID_ID_V01 41
#define QMI_ERR_ENCODING_V01 58
+#define QMI_ERR_DISABLED_V01 69
#define QMI_ERR_INCOMPATIBLE_STATE_V01 90
#define QMI_ERR_NOT_SUPPORTED_V01 94
diff --git a/kernel/signal.c b/kernel/signal.c
index 5843c54..b6f24c8 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -41,6 +41,8 @@
#include <linux/compiler.h>
#include <linux/posix-timers.h>
#include <linux/livepatch.h>
+#include <linux/oom.h>
+#include <linux/capability.h>
#define CREATE_TRACE_POINTS
#include <trace/events/signal.h>
@@ -1324,8 +1326,11 @@
ret = check_kill_permission(sig, info, p);
rcu_read_unlock();
- if (!ret && sig)
+ if (!ret && sig) {
ret = do_send_sig_info(sig, info, p, type);
+ if (capable(CAP_KILL) && sig == SIGKILL)
+ add_to_oom_reaper(p);
+ }
return ret;
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c23e0b0..bb60a0b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1271,6 +1271,13 @@
.proc_handler = proc_dointvec,
},
{
+ .procname = "reap_mem_on_sigkill",
+ .data = &sysctl_reap_mem_on_sigkill,
+ .maxlen = sizeof(sysctl_reap_mem_on_sigkill),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
.procname = "overcommit_ratio",
.data = &sysctl_overcommit_ratio,
.maxlen = sizeof(sysctl_overcommit_ratio),
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 1198b32..19aec79 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -52,6 +52,7 @@
int sysctl_panic_on_oom;
int sysctl_oom_kill_allocating_task;
int sysctl_oom_dump_tasks = 1;
+int sysctl_reap_mem_on_sigkill;
/*
* Serializes oom killer invocations (out_of_memory()) from all contexts to
@@ -634,13 +635,21 @@
static void wake_oom_reaper(struct task_struct *tsk)
{
+ /*
+ * Move the lock here to avoid scenario of queuing
+ * the same task by both OOM killer and any other SIGKILL
+ * path.
+ */
+ spin_lock(&oom_reaper_lock);
+
/* tsk is already queued? */
- if (tsk == oom_reaper_list || tsk->oom_reaper_list)
+ if (tsk == oom_reaper_list || tsk->oom_reaper_list) {
+ spin_unlock(&oom_reaper_lock);
return;
+ }
get_task_struct(tsk);
- spin_lock(&oom_reaper_lock);
tsk->oom_reaper_list = oom_reaper_list;
oom_reaper_list = tsk;
spin_unlock(&oom_reaper_lock);
@@ -660,6 +669,16 @@
}
#endif /* CONFIG_MMU */
+static void __mark_oom_victim(struct task_struct *tsk)
+{
+ struct mm_struct *mm = tsk->mm;
+
+ if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) {
+ mmgrab(tsk->signal->oom_mm);
+ set_bit(MMF_OOM_VICTIM, &mm->flags);
+ }
+}
+
/**
* mark_oom_victim - mark the given task as OOM victim
* @tsk: task to mark
@@ -672,18 +691,13 @@
*/
static void mark_oom_victim(struct task_struct *tsk)
{
- struct mm_struct *mm = tsk->mm;
-
WARN_ON(oom_killer_disabled);
/* OOM killer might race with memcg OOM */
if (test_and_set_tsk_thread_flag(tsk, TIF_MEMDIE))
return;
/* oom_mm is bound to the signal struct life time. */
- if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) {
- mmgrab(tsk->signal->oom_mm);
- set_bit(MMF_OOM_VICTIM, &mm->flags);
- }
+ __mark_oom_victim(tsk);
/*
* Make sure that the task is woken up from uninterruptible sleep
@@ -1145,3 +1159,21 @@
out_of_memory(&oc);
mutex_unlock(&oom_lock);
}
+
+void add_to_oom_reaper(struct task_struct *p)
+{
+ if (!sysctl_reap_mem_on_sigkill)
+ return;
+
+ p = find_lock_task_mm(p);
+ if (!p)
+ return;
+
+ get_task_struct(p);
+ if (task_will_free_mem(p)) {
+ __mark_oom_victim(p);
+ wake_oom_reaper(p);
+ }
+ task_unlock(p);
+ put_task_struct(p);
+}
diff --git a/mm/swap_ratio.c b/mm/swap_ratio.c
index 577b8c1..19e459d 100644
--- a/mm/swap_ratio.c
+++ b/mm/swap_ratio.c
@@ -9,8 +9,9 @@
#define SWAP_RATIO_GROUP_START (SWAP_FLAG_PRIO_MASK - 9) /* 32758 */
#define SWAP_RATIO_GROUP_END (SWAP_FLAG_PRIO_MASK) /* 32767 */
-#define SWAP_FAST_WRITES (SWAPFILE_CLUSTER * (SWAP_CLUSTER_MAX / 8))
-#define SWAP_SLOW_WRITES SWAPFILE_CLUSTER
+#define SWAP_FAST_WRITES \
+ ((SWAPFILE_CLUSTER * (SWAP_CLUSTER_MAX / 8)) / SWAP_BATCH)
+#define SWAP_SLOW_WRITES (SWAPFILE_CLUSTER / SWAP_BATCH)
/*
* The fast/slow swap write ratio.
@@ -78,6 +79,12 @@
n = plist_next_entry(&(*si)->avail_lists[node],
struct swap_info_struct,
avail_lists[node]);
+ if (n == *si) {
+ /* No other swap device */
+ ret = -ENODEV;
+ goto skip;
+ }
+
spin_unlock(&swap_avail_lock);
spin_lock(&n->lock);
spin_lock(&swap_avail_lock);
@@ -175,6 +182,9 @@
int swap_ratio(struct swap_info_struct **si, int node)
{
+ if (!sysctl_swap_ratio_enable)
+ return -ENODEV;
+
if (is_swap_ratio_group((*si)->prio))
return swap_ratio_slow(si, node);
else
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 54da4b0..598b764 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -58,6 +58,11 @@
include scripts/Makefile.host
endif
+# Do not include host rules unless needed
+ifneq ($(dtbo-y),)
+include scripts/Makefile.dtbo
+endif
+
ifndef obj
$(warning kbuild: Makefile.build is included improperly)
endif
diff --git a/scripts/Makefile.dtbo b/scripts/Makefile.dtbo
new file mode 100644
index 0000000..ce83b35
--- /dev/null
+++ b/scripts/Makefile.dtbo
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0
+__dtbo := $(sort $(dtbo-y))
+
+dtbo-base := $(sort $(foreach m,$(__dtbo),$($(m)-base)))
+dtbo := $(foreach m,$(__dtbo),$(if $($(m)-base),$(m)))
+
+__dtbo := $(addprefix $(obj)/,$(__dtbo))
+dtbo-base := $(addprefix $(obj)/,$(dtbo-base))
+dtbo := $(addprefix $(obj)/,$(dtbo))
+
+ifneq ($(DTC_OVERLAY_TEST_EXT),)
+DTC_OVERLAY_TEST = $(DTC_OVERLAY_TEST_EXT)
+quiet_cmd_dtbo_verify = VERIFY $@
+cmd_dtbo_verify = $(DTC_OVERLAY_TEST) $(addprefix $(obj)/,$($(@F)-base)) $@ $(dot-target).dtb
+else
+cmd_dtbo_verify = true
+endif
+
+$(obj)/%.dtbo: $(src)/%.dts FORCE
+ $(call if_changed_dep,dtc)
+ $(call if_changed,dtbo_verify)
+
+$(call multi_depend, $(dtbo), , -base)
+
+always += $(dtbo)
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index add49a1..8447951 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -17,33 +17,9 @@
# force LANG to be set to en_US.UTF-8 to get consistent warnings.
allowed_warnings = set([
- "seqiv.c:76",
- "echainiv.c:50",
- "crypto.c:67",
- "shash.c:91",
- "shash.c:127",
- "smp.c:176",
- "xcbc.c:68",
- "hmac.c:56",
- "cbc.c:14",
- "cbc.h:116",
- "cryptd.c:487",
- "cryptd.c:515",
- "ablkcipher.c:215",
- "authenc.c:188",
- "authenc.c:186",
- "authencesn.c:186",
- "libcrc32c.c:45",
- "ppp_mppe.c:158",
- "ppp_mppe.c:369",
- "ppp_mppe.c:483",
- "dm-verity-fec.c:218",
"umid.c:138",
"umid.c:213",
"umid.c:388",
- "shash.c:92",
- "shash.c:128",
- "smp.c:177",
])
# Capture the name of the object file, can find it.