* [PATCH v2 0/4] arm: ras: Add DT frontend support for ARM RAS
From: Umang Chheda @ 2026-07-20 8:19 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Ruidong Tian, Tony Luck, Borislav Petkov,
Umang Chheda
Cc: devicetree, linux-kernel, linux-arm-msm, linux-acpi,
linux-arm-kernel, linux-edac, faruque.ansari, avaneesh.dwivedi
This series adds Device Tree support for the ARM64 RAS driver
introduced by Ruidong Tian [1]. The existing driver supports ACPI-based
platforms via the AEST table, this series extends it to DT-based
platforms without any changes to the core driver.
How to test with QEMU
--------------------------
Tian Ruidong's QEMU fork [2] emulates AEST MMIO error records on the
virt machine. To test the DT frontend:
1. Build QEMU:
git clone https://github.com/winterddd/qemu.git
cd qemu
git checkout c5e2d5dec9fd62ba622314c40bff0fbecb4dfb34
./configure --target-list=aarch64-softmmu
make -j$(nproc)
2. Build the kernel with:
CONFIG_ARM64_RAS_EXTN=y
CONFIG_RAS=y
CONFIG_ACPI_AEST=y
CONFIG_ARM64_RAS_DRIVER=y
CONFIG_ARM64_RAS_DT=y
3. Add the following DT node to your virt machine DTB. The QEMU
fork maps GIC error source at 0x017a00000 (SPI 0x0d).
ras-gic-dist@17a00000 {
compatible = "arm,ras-gic";
reg = <0x0 0x17a00000 0x0 0x10000>;
reg-names = "err-group";
arm,group-format = <ARM_RAS_GROUP_4K>;
arm,num-records = <1>;
arm,record-impl = /bits/ 64 <0x1>;
arm,status-reporting = /bits/ 64 <0x0>;
arm,gic-ref = <&gic>;
interrupts = <GIC_SPI 0x0d 0x04>;
interrupt-names = "fhi";
};
4. Boot QEMU with acpi=off:
./qemu-system-aarch64 \
-machine virt,accel=tcg,gic-version=3 \
-cpu cortex-a57 -m 2G -smp 4 \
-kernel Image -dtb virt-aest.dtb \
-append "console=ttyAMA0 acpi=off earlycon" \
-nographic
5. Verify probe:
dmesg | grep "DT RAS"
# Expected: DT RAS: registered 1 RAS error source(s) from DT
ls /sys/kernel/debug/aest/
6. Inject a CE error via the QEMU MMIO fault injection registers.
The QEMU device accepts 64-bit accesses only (use devmem with
the 64-bit width flag):
devmem 0x090e0808 64 0x40000001
This triggers QEMU's error_record_inj_write() which sets
ERR<n>STATUS.V=1 and asserts the IRQ. The kernel driver's
aest_irq_func() fires, reads the status, and logs:
arm64_ras: {2}[Hardware Error]: Hardware error from AEST gic.90e0000
arm64_ras: {2}[Hardware Error]: Error from GIC type 0x0 instance 0x8005
arm64_ras: {2}[Hardware Error]: ERR0FR: 0x48a5
arm64_ras: {2}[Hardware Error]: ERR0CTRL: 0x108
arm64_ras: {2}[Hardware Error]: ERR0STATUS: 0x40000001
Testing
-------
- Validated Processor error nodes/sources for L1-L2 and L3 caches error
on Qualcomm's lemans-evk and monaco-evk boards with DT boot.
- Validated CE and UE injection via debugfs soft_inject.
- Validated GIC and SMMU error sources on QEMU.
[1] https://lore.kernel.org/lkml/20260122094656.73399-1-tianruidong@linux.alibaba.com/
[2] https://github.com/winterddd/qemu/tree/error_record
---
Changes in v2:
- Rebased on top of Ruidong Tian's v7 RAS driver series and reworked
the DT frontend to match the new driver architecture.
- Moved RAS error source nodes to the DT root, removed the arm,aest
container node as suggested by Rob Herring.
- Dropped arm,processor-flags and arm,resource-type properties, these
are now inferred from the interrupt type and cache phandle
respectively.
- Renamed compatible strings from arm,aest-* to arm,ras-* and the
dt-bindings header from aest.h to arm-ras.h to avoid ACPI terminology
in DT bindings.
---
Umang Chheda (4):
dt-bindings: arm: ras: Introduce bindings for ARM RAS error sources
arm64: ras: Add Device Tree frontend
arm64: dts: qcom: monaco: add RAS error source nodes
arm64: dts: qcom: lemans: add RAS error source nodes
.../bindings/arm/arm,ras-error-source.yaml | 330 +++++++++++++++
arch/arm64/boot/dts/qcom/lemans.dtsi | 30 ++
arch/arm64/boot/dts/qcom/monaco.dtsi | 30 ++
drivers/ras/arm64/Kconfig | 25 +-
drivers/ras/arm64/Makefile | 2 +
drivers/ras/arm64/ras-of.c | 383 ++++++++++++++++++
include/dt-bindings/arm/arm-ras.h | 11 +
7 files changed, 806 insertions(+), 5 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/arm,ras-error-source.yaml
create mode 100644 drivers/ras/arm64/ras-of.c
create mode 100644 include/dt-bindings/arm/arm-ras.h
--
2.34.1
^ permalink raw reply
* [PATCH v2 1/4] dt-bindings: arm: ras: Introduce bindings for ARM RAS error sources
From: Umang Chheda @ 2026-07-20 8:19 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Ruidong Tian, Tony Luck, Borislav Petkov,
Umang Chheda
Cc: devicetree, linux-kernel, linux-arm-msm, linux-acpi,
linux-arm-kernel, linux-edac, faruque.ansari, avaneesh.dwivedi
In-Reply-To: <20260720081954.1858180-1-umang.chheda@oss.qualcomm.com>
ARMv8 and later processors implement the RAS (Reliability,
Availability and Serviceability) extensions, exposing hardware
error records through a standardised register interface.
Add Device Tree bindings to describe RAS error sources.
Signed-off-by: Umang Chheda <umang.chheda@oss.qualcomm.com>
---
.../bindings/arm/arm,ras-error-source.yaml | 330 ++++++++++++++++++
include/dt-bindings/arm/arm-ras.h | 11 +
2 files changed, 341 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/arm,ras-error-source.yaml
create mode 100644 include/dt-bindings/arm/arm-ras.h
diff --git a/Documentation/devicetree/bindings/arm/arm,ras-error-source.yaml b/Documentation/devicetree/bindings/arm/arm,ras-error-source.yaml
new file mode 100644
index 000000000000..add7063a1a62
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/arm,ras-error-source.yaml
@@ -0,0 +1,330 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/arm,ras-error-source.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM RAS error source
+
+maintainers:
+ - Umang Chheda <umang.chheda@oss.qualcomm.com>
+
+description: |
+ ARMv8 and later processors implement the Reliability, Availability and
+ Serviceability (RAS) extensions. Hardware blocks that support RAS expose
+ one or more error records through a standardised register interface. Each
+ error record captures information about a detected hardware error (cache
+ ECC fault, TLB parity error, interconnect error, etc.) and can optionally
+ signal the OS via an interrupt.
+
+ Each DT node described by this binding represents one RAS error source —
+ a hardware block that exposes a set of error records. Error records are
+ accessed either through system registers (for processor-local resources
+ such as L1/L2 caches and TLBs) or through a memory-mapped register window
+ (for shared or off-core resources such as L3 caches, SMMUs and GICs).
+
+properties:
+ compatible:
+ description:
+ Identifies the class of hardware block this error source belongs to.
+ arm,ras-processor covers processor error sources (cache, TLB, etc.).
+ arm,ras-smmu covers SMMU error sources.
+ arm,ras-gic covers GIC error sources.
+ enum:
+ - arm,ras-processor
+ - arm,ras-smmu
+ - arm,ras-gic
+
+ reg:
+ description:
+ Register windows for this error source. When absent the error records
+ are accessed through system registers (ERRSELR_EL1 + ERX*_EL1).
+ When present, the first range is the primary error-record window;
+ additional named ranges are identified by reg-names.
+ minItems: 1
+ maxItems: 4
+
+ reg-names:
+ description:
+ Names for the optional additional register windows beyond the primary
+ error-record window. err-group is the error group status register
+ window (ERRGSR). fault-inject is the fault injection register window
+ (ERXPFG*). irq-config is the interrupt routing configuration window.
+ minItems: 1
+ maxItems: 3
+ items:
+ enum:
+ - err-group
+ - fault-inject
+ - irq-config
+
+ interrupts:
+ description:
+ Interrupts signalled by this error source. The first interrupt is the
+ Fault Handling Interrupt (FHI), fired when a corrected error counter
+ overflows or a deferred error is detected. The optional second
+ interrupt is the Error Recovery Interrupt (ERI), fired when an
+ uncorrected recoverable error is detected.
+ minItems: 1
+ maxItems: 2
+
+ interrupt-names:
+ description:
+ Names identifying the interrupts. "fhi" is the Fault Handling
+ Interrupt; "eri" is the optional Error Recovery Interrupt.
+ minItems: 1
+ maxItems: 2
+ items:
+ enum:
+ - fhi
+ - eri
+
+ arm,group-format:
+ description:
+ Page granularity of the memory-mapped error record group register
+ window. Determines the ioremap size and the number of error group
+ status registers (ERRGSR) available. Required when reg is present.
+ Use the ARM_RAS_GROUP_* constants from <dt-bindings/arm/arm-ras.h>.
+ 0 (ARM_RAS_GROUP_4K) is a 4 KiB window with 1 ERRGSR supporting up
+ to 64 records. 1 (ARM_RAS_GROUP_16K) is 16 KiB with 4 ERRGSRs and
+ up to 256 records. 2 (ARM_RAS_GROUP_64K) is 64 KiB with 14 ERRGSRs
+ and up to 896 records.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2]
+
+ arm,num-records:
+ description:
+ Total number of error records in this error source, including both
+ implemented and unimplemented slots.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+
+ arm,record-impl:
+ description:
+ Bitmap of implemented error records. Bit N set to 1 means error
+ record N is present and active in this error source. Bit N set to 0
+ means record N is not implemented and must be skipped. The array
+ length must equal the number of ERRGSRs implied by arm,group-format
+ (1 element for 4K, 4 for 16K, 14 for 64K). For system-register
+ nodes (no reg property) a single u64 element is used.
+ $ref: /schemas/types.yaml#/definitions/uint64-array
+ minItems: 1
+ maxItems: 14
+
+ arm,status-reporting:
+ description:
+ Bitmap indicating which implemented error records must be polled
+ directly by the OS. Bit N set to 1 means record N does not report
+ through the ERRGSR and must be polled by reading its ERX_STATUS
+ register directly in the interrupt handler. Bit N set to 0 means
+ record N reports its status through the ERRGSR and will be discovered
+ via the ERRGSR scan path. For system-register nodes (no reg property)
+ there is no ERRGSR, so every implemented record must be polled
+ directly; arm,status-reporting must equal arm,record-impl for all
+ system-register nodes. Array length as for arm,record-impl.
+ $ref: /schemas/types.yaml#/definitions/uint64-array
+ minItems: 1
+ maxItems: 14
+
+ arm,addressing-mode:
+ description:
+ Bitmap indicating the type of address reported in the error address
+ register (ERX_ADDR) for each error record. Bit N set to 0 means
+ record N reports a System Physical Address (SPA) that the OS can use
+ directly. Bit N set to 1 means record N reports a node-specific
+ Logical Address (LA) that requires platform-specific translation to
+ obtain a SPA. Array length as for arm,record-impl.
+ $ref: /schemas/types.yaml#/definitions/uint64-array
+ minItems: 1
+ maxItems: 14
+
+ # Processor error source properties (arm,ras-processor only)
+
+ cache:
+ description:
+ Phandle to the cache node (L1, L2, or L3) that this processor error
+ source monitors. The referenced node must have compatible = "cache"
+ and a cache-level property identifying the level in the hierarchy.
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ # SMMU error source properties (arm,ras-smmu only)
+
+ iommus:
+ description:
+ Phandle to the SMMU node that this error source monitors.
+ maxItems: 1
+
+ # GIC error source properties (arm,ras-gic only)
+
+ arm,gic-ref:
+ description:
+ Phandle to the GIC node that this error source monitors.
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+required:
+ - compatible
+ - arm,num-records
+ - arm,record-impl
+ - arm,status-reporting
+
+allOf:
+ - if:
+ required:
+ - reg
+ then:
+ required:
+ - arm,group-format
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: arm,ras-processor
+ then:
+ required:
+ - cache
+ properties:
+ cache: {}
+ else:
+ properties:
+ cache: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: arm,ras-smmu
+ then:
+ required:
+ - iommus
+ properties:
+ iommus: {}
+ else:
+ properties:
+ iommus: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: arm,ras-gic
+ then:
+ required:
+ - arm,gic-ref
+ properties:
+ arm,gic-ref: {}
+ else:
+ properties:
+ arm,gic-ref: false
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/arm/arm-ras.h>
+
+ / {
+ compatible = "qcom,sa8775p-ride", "qcom,sa8775p";
+ model = "Qualcomm Technologies, Inc. SA8775P RAS example";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&intc>;
+
+ intc: interrupt-controller@17100000 {
+ compatible = "arm,gic-v3";
+ reg = <0x0 0x17100000 0x0 0x10000>,
+ <0x0 0x17180000 0x0 0x100000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ next-level-cache = <&l2_0>;
+
+ l2_0: l2-cache {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
+
+ l3_0: l3-cache {
+ compatible = "cache";
+ cache-level = <3>;
+ cache-unified;
+ };
+ };
+ };
+ };
+
+ /*
+ * Per-PE L1/L2 cache RAS error source. System-register access,
+ * per-CPU PPI. Record 0 is implemented (arm,record-impl bit 0
+ * set). arm,status-reporting equals arm,record-impl because
+ * system-register nodes have no ERRGSR; record 0 must be polled.
+ */
+ ras-l1l2-0 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <1>;
+ arm,record-impl = /bits/ 64 <0x1>;
+ arm,status-reporting = /bits/ 64 <0x1>;
+ cache = <&l2_0>;
+ interrupts = <GIC_PPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "fhi";
+ };
+
+ ras-l3-cluster0 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <2>;
+ arm,record-impl = /bits/ 64 <0x2>;
+ arm,status-reporting = /bits/ 64 <0x2>;
+ cache = <&l3_0>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "fhi";
+ };
+ };
+
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/arm/arm-ras.h>
+
+ / {
+ compatible = "qcom,sa8775p-ride", "qcom,sa8775p";
+ model = "Qualcomm Technologies, Inc. SA8775P RAS example";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&gic>;
+
+ /*
+ * GICv3 interrupt controller with RAS support.
+ */
+ gic: interrupt-controller@17b00000 {
+ compatible = "arm,gic-v3";
+ reg = <0x0 0x17b00000 0x0 0x10000>,
+ <0x0 0x17b60000 0x0 0x100000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ ras-gic-dist@17a00000 {
+ compatible = "arm,ras-gic";
+ reg = <0x0 0x17a00000 0x0 0x10000>;
+ reg-names = "err-group";
+ arm,group-format = <ARM_RAS_GROUP_4K>;
+ arm,num-records = <1>;
+ arm,record-impl = /bits/ 64 <0x1>;
+ arm,status-reporting = /bits/ 64 <0x0>;
+ arm,gic-ref = <&gic>;
+ interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "fhi";
+ };
+ };
diff --git a/include/dt-bindings/arm/arm-ras.h b/include/dt-bindings/arm/arm-ras.h
new file mode 100644
index 000000000000..c2f4e1f8243e
--- /dev/null
+++ b/include/dt-bindings/arm/arm-ras.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_ARM_RAS_H
+#define _DT_BINDINGS_ARM_RAS_H
+
+/* arm,group-format - error record group register window page size */
+#define ARM_RAS_GROUP_4K 0 /* 4 KiB, 1 ERRGSR */
+#define ARM_RAS_GROUP_16K 1 /* 16 KiB, 4 ERRGSRs */
+#define ARM_RAS_GROUP_64K 2 /* 64 KiB, 14 ERRGSRs */
+
+#endif /* _DT_BINDINGS_ARM_RAS_H */
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/4] arm64: ras: Add Device Tree frontend
From: Umang Chheda @ 2026-07-20 8:19 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Ruidong Tian, Tony Luck, Borislav Petkov,
Umang Chheda
Cc: devicetree, linux-kernel, linux-arm-msm, linux-acpi,
linux-arm-kernel, linux-edac, faruque.ansari, avaneesh.dwivedi
In-Reply-To: <20260720081954.1858180-1-umang.chheda@oss.qualcomm.com>
Add a Device Tree frontend for the ARM64 RAS driver, allowing it
to be used on platforms without ACPI firmware.
The error sources defined in DT are registered as arm64_ras platform
devices at boot. The frontend produces the same software fwnode properties
as the ACPI path, so the core driver probes DT and ACPI nodes identically
without any firmware-specific knowledge.
Signed-off-by: Umang Chheda <umang.chheda@oss.qualcomm.com>
---
drivers/ras/arm64/Kconfig | 25 ++-
drivers/ras/arm64/Makefile | 2 +
drivers/ras/arm64/ras-of.c | 383 +++++++++++++++++++++++++++++++++++++
3 files changed, 405 insertions(+), 5 deletions(-)
create mode 100644 drivers/ras/arm64/ras-of.c
diff --git a/drivers/ras/arm64/Kconfig b/drivers/ras/arm64/Kconfig
index dcdeaa216d67..8bdb219bc90f 100644
--- a/drivers/ras/arm64/Kconfig
+++ b/drivers/ras/arm64/Kconfig
@@ -1,16 +1,31 @@
# SPDX-License-Identifier: GPL-2.0
#
-# ARM Error Source Table Support
+# ARM RAS driver
#
# Copyright (c) 2025, Alibaba Group.
#
+config ARM64_RAS_DT
+ bool "ARM64 RAS Device Tree support"
+ depends on ARM64_RAS_EXTN && OF
+ help
+ Enable Device Tree support for the ARM64 RAS driver.
+
+ When selected, RAS error sources described in the Device Tree
+ (arm,ras-processor, arm,ras-smmu, arm,ras-gic etc) are registered
+ as platform devices at boot, allowing the driver to be used on
+ platforms without ACPI firmware.
+
config ARM64_RAS_DRIVER
tristate "ARM64 RAS Driver"
- depends on ARM64 && ACPI_AEST && RAS
+ depends on ARM64 && (ACPI_AEST || ARM64_RAS_DT) && RAS
help
- This is the RAS driver for the arm64 architecture. It depends on
- the Arm Error Source Table (AEST) to provide basic register and
- interrupt information.
+ This is the RAS driver for the arm64 architecture. It uses the
+ ARMv8 RAS extension register interface to discover, configure,
+ and handle hardware errors from processor caches, SMMUs, and GICs.
+
+ On ACPI systems the error source topology is provided by the AEST
+ ACPI table (requires ACPI_AEST). On Device Tree systems it is
+ provided by "arm,ras-*" nodes in the DT root (requires ARM64_RAS_DT).
If set, the kernel will report and process hardware errors.
diff --git a/drivers/ras/arm64/Makefile b/drivers/ras/arm64/Makefile
index 6897798f7314..aee2f9de37f6 100644
--- a/drivers/ras/arm64/Makefile
+++ b/drivers/ras/arm64/Makefile
@@ -7,3 +7,5 @@ arm64_ras-y += ras-sysfs.o
arm64_ras-y += ras-inject.o
arm64_ras-y += ras-cmn.o
arm64_ras-y += ras-storm.o
+
+obj-$(CONFIG_ARM64_RAS_DT) += ras-of.o
diff --git a/drivers/ras/arm64/ras-of.c b/drivers/ras/arm64/ras-of.c
new file mode 100644
index 000000000000..e1aa8e13c077
--- /dev/null
+++ b/drivers/ras/arm64/ras-of.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+#include <linux/acpi_aest.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "DT RAS: " fmt
+
+/* Maximum number of software fwnode properties per RAS node */
+#define RAS_OF_MAX_PROPS 20
+
+static const unsigned long ras_of_type_processor __initconst =
+ ACPI_AEST_PROCESSOR_ERROR_NODE;
+static const unsigned long ras_of_type_smmu __initconst =
+ ACPI_AEST_SMMU_ERROR_NODE;
+static const unsigned long ras_of_type_gic __initconst =
+ ACPI_AEST_GIC_ERROR_NODE;
+
+static const struct of_device_id ras_of_match[] __initconst = {
+ { .compatible = "arm,ras-processor", .data = &ras_of_type_processor },
+ { .compatible = "arm,ras-smmu", .data = &ras_of_type_smmu },
+ { .compatible = "arm,ras-gic", .data = &ras_of_type_gic },
+ { }
+};
+
+static const char * const __initconst ras_of_irq_res_names[] = {
+ [ACPI_AEST_NODE_FAULT_HANDLING] = AEST_FHI_NAME,
+ [ACPI_AEST_NODE_ERROR_RECOVERY] = AEST_ERI_NAME,
+};
+
+static const char * const __initconst ras_of_dt_irq_names[] = {
+ "fhi", "eri"
+};
+
+static int __init ras_of_build_node_data(struct device_node *np,
+ u8 node_type, int index,
+ int fhi_virq,
+ u8 **data_out, u32 *size_out)
+{
+ *data_out = NULL;
+ *size_out = 0;
+
+ switch (node_type) {
+ case ACPI_AEST_PROCESSOR_ERROR_NODE: {
+ /*
+ * Allocate the processor header plus the cache sub-structure.
+ * resource_type is inferred from the presence of the 'cache'
+ * phandle: if present the resource is a cache, otherwise it
+ * is treated as a generic processor resource.
+ * flags (SHARED/GLOBAL) are inferred from the interrupt type:
+ * a PPI is per-PE (global); an SPI is shared across a cluster.
+ */
+ size_t total = sizeof(struct acpi_aest_processor) +
+ sizeof(struct acpi_aest_processor_cache);
+ struct acpi_aest_processor_cache *c;
+ struct acpi_aest_processor *proc;
+ struct device_node *cache_np;
+ u8 pflags;
+
+ proc = kzalloc(total, GFP_KERNEL);
+ if (!proc)
+ return -ENOMEM;
+
+ cache_np = of_parse_phandle(np, "cache", 0);
+ if (cache_np) {
+ proc->resource_type = ACPI_AEST_CACHE_RESOURCE;
+ c = (struct acpi_aest_processor_cache *)(proc + 1);
+ /*
+ * alloc_ras_node_name() reads c->cache_reference as
+ * the name disambiguator for shared/global nodes.
+ */
+ c->cache_reference = cache_np->phandle;
+ of_node_put(cache_np);
+ } else {
+ proc->resource_type = ACPI_AEST_GENERIC_RESOURCE;
+ }
+
+ /*
+ * Infer scope from the FHI interrupt type: a PPI is
+ * per-PE (set GLOBAL); an SPI is cluster-shared (set SHARED).
+ * alloc_ras_node_name() uses flags to choose the name format.
+ */
+ pflags = irq_is_percpu(fhi_virq) ?
+ ACPI_AEST_PROC_FLAG_GLOBAL :
+ ACPI_AEST_PROC_FLAG_SHARED;
+ proc->flags = pflags;
+ proc->processor_id = (u32)index;
+
+ *data_out = (u8 *)proc;
+ *size_out = (u32)total;
+ break;
+ }
+ case ACPI_AEST_SMMU_ERROR_NODE: {
+ struct acpi_aest_smmu *smmu;
+ struct device_node *smmu_np;
+
+ smmu = kzalloc_obj(smmu, GFP_KERNEL);
+ if (!smmu)
+ return -ENOMEM;
+
+ smmu_np = of_parse_phandle(np, "iommus", 0);
+ if (smmu_np) {
+ smmu->iort_node_reference = smmu_np->phandle;
+ of_node_put(smmu_np);
+ }
+
+ *data_out = (u8 *)smmu;
+ *size_out = sizeof(*smmu);
+ break;
+ }
+ case ACPI_AEST_GIC_ERROR_NODE: {
+ struct acpi_aest_gic *gic;
+ struct device_node *gic_np;
+
+ gic = kzalloc_obj(gic, GFP_KERNEL);
+ if (!gic)
+ return -ENOMEM;
+
+ gic_np = of_parse_phandle(np, "arm,gic-ref", 0);
+ if (gic_np) {
+ gic->instance_id = gic_np->phandle;
+ of_node_put(gic_np);
+ }
+ *data_out = (u8 *)gic;
+ *size_out = sizeof(*gic);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Determine the register access type from the DT node:
+ * no reg -> system-register access (ERRSELR_EL1 + ERX*_EL1)
+ * 1 range -> memory-mapped access
+ * 2+ ranges -> single-record memory-mapped access
+ */
+static u8 __init ras_of_interface_type(struct device_node *np)
+{
+ int addr_cells, size_cells, reg_len;
+
+ if (!of_property_present(np, "reg"))
+ return ACPI_AEST_NODE_SYSTEM_REGISTER;
+
+ addr_cells = of_n_addr_cells(np);
+ size_cells = of_n_size_cells(np);
+ if (addr_cells <= 0 || size_cells <= 0)
+ return ACPI_AEST_NODE_SYSTEM_REGISTER;
+
+ reg_len = of_property_count_elems_of_size(np, "reg", sizeof(u32));
+ if (reg_len <= 0)
+ return ACPI_AEST_NODE_SYSTEM_REGISTER;
+
+ if (reg_len <= addr_cells + size_cells)
+ return ACPI_AEST_NODE_MEMORY_MAPPED;
+
+ return ACPI_AEST_NODE_SINGLE_RECORD_MEMORY_MAPPED;
+}
+
+static resource_size_t __init ras_of_mem_size(u32 gfmt)
+{
+ switch (gfmt) {
+ case ACPI_AEST_NODE_GROUP_FORMAT_16K:
+ return SZ_16K;
+ case ACPI_AEST_NODE_GROUP_FORMAT_64K:
+ return SZ_64K;
+ default:
+ return SZ_4K;
+ }
+}
+
+static u32 __init ras_of_virq_to_gsiv(int virq)
+{
+ struct irq_data *irqd = irq_get_irq_data(virq);
+
+ return irqd ? (u32)irqd->hwirq : 0;
+}
+
+static int __init ras_of_attach_fwnode(struct device_node *np,
+ struct platform_device *pdev,
+ u8 node_type, u8 itype, u32 gfmt,
+ int index, int fhi_virq,
+ u32 fhi_gsiv, u32 eri_gsiv)
+{
+ u64 rec_impl[14] = { };
+ u64 stat_rep[14] = { };
+ u64 addr_mode[14] = { };
+ u64 err_group_base = 0, fault_inject_base = 0, irq_cfg_base = 0;
+ struct property_entry props[RAS_OF_MAX_PROPS] = { };
+ struct resource res;
+ u8 *node_data = NULL;
+ u32 node_data_size = 0;
+ u32 nrec = 1;
+ int group_len, p = 0, i, ret;
+
+ of_property_read_u32(np, "arm,num-records", &nrec);
+
+ switch (gfmt) {
+ case ACPI_AEST_NODE_GROUP_FORMAT_16K:
+ group_len = 4;
+ break;
+ case ACPI_AEST_NODE_GROUP_FORMAT_64K:
+ group_len = 14;
+ break;
+ default:
+ group_len = 1;
+ break;
+ }
+
+ of_property_read_u64_array(np, "arm,record-impl", rec_impl, group_len);
+ of_property_read_u64_array(np, "arm,status-reporting", stat_rep, group_len);
+ of_property_read_u64_array(np, "arm,addressing-mode", addr_mode, group_len);
+
+ /*
+ * DT binding: bit=1 means record IS implemented.
+ * ras-core.c uses for_each_clear_bit() on record_implemented, so
+ * bit=0 means implemented internally. Invert before storing.
+ */
+ for (i = 0; i < group_len; i++)
+ rec_impl[i] = ~rec_impl[i];
+
+ /* Named MMIO windows — only present on memory-mapped nodes */
+ if (itype != ACPI_AEST_NODE_SYSTEM_REGISTER) {
+ int idx;
+
+ idx = of_property_match_string(np, "reg-names", "err-group");
+ if (idx >= 0 && !of_address_to_resource(np, idx, &res))
+ err_group_base = res.start;
+
+ idx = of_property_match_string(np, "reg-names", "fault-inject");
+ if (idx >= 0 && !of_address_to_resource(np, idx, &res))
+ fault_inject_base = res.start;
+
+ idx = of_property_match_string(np, "reg-names", "irq-config");
+ if (idx >= 0 && !of_address_to_resource(np, idx, &res))
+ irq_cfg_base = res.start;
+ }
+
+ ret = ras_of_build_node_data(np, node_type, index, fhi_virq,
+ &node_data, &node_data_size);
+ if (ret)
+ return ret;
+
+ props[p++] = PROPERTY_ENTRY_U8("arm,node-type", node_type);
+ props[p++] = PROPERTY_ENTRY_U8("arm,interface-type", itype);
+ props[p++] = PROPERTY_ENTRY_U8("arm,group-format", (u8)gfmt);
+ props[p++] = PROPERTY_ENTRY_U32("arm,error-records-count", nrec);
+ props[p++] = PROPERTY_ENTRY_U32("arm,error-records-index", 0);
+ props[p++] = PROPERTY_ENTRY_U32("arm,interface-flags", 0);
+ props[p++] = PROPERTY_ENTRY_U64_ARRAY_LEN("arm,record-implemented",
+ rec_impl, group_len);
+ props[p++] = PROPERTY_ENTRY_U64_ARRAY_LEN("arm,status-reporting",
+ stat_rep, group_len);
+ props[p++] = PROPERTY_ENTRY_U64_ARRAY_LEN("arm,addressing-mode",
+ addr_mode, group_len);
+ props[p++] = PROPERTY_ENTRY_U64("arm,error-group-base", err_group_base);
+ props[p++] = PROPERTY_ENTRY_U64("arm,fault-inject-base", fault_inject_base);
+ props[p++] = PROPERTY_ENTRY_U64("arm,interrupt-config-base", irq_cfg_base);
+ props[p++] = PROPERTY_ENTRY_U32("arm,fhi-gsiv", fhi_gsiv);
+ props[p++] = PROPERTY_ENTRY_U32("arm,eri-gsiv", eri_gsiv);
+
+ if (node_data && node_data_size)
+ props[p++] = PROPERTY_ENTRY_U8_ARRAY_LEN("arm,node-specific-data",
+ node_data, node_data_size);
+
+ ret = device_create_managed_software_node(&pdev->dev, props, NULL);
+
+ kfree(node_data);
+ return ret;
+}
+
+static int __init ras_of_init_one_node(struct device_node *np, u8 node_type,
+ int index)
+{
+ struct resource res[AEST_MAX_INTERRUPT_PER_NODE + 1] = { };
+ struct platform_device *pdev;
+ u32 gfmt = ACPI_AEST_NODE_GROUP_FORMAT_4K;
+ u32 gsiv[AEST_MAX_INTERRUPT_PER_NODE] = { };
+ int virq[AEST_MAX_INTERRUPT_PER_NODE] = { };
+ int nres = 0, ret, i;
+ u8 itype;
+
+ itype = ras_of_interface_type(np);
+ of_property_read_u32(np, "arm,group-format", &gfmt);
+
+ pdev = platform_device_alloc("arm64_ras", PLATFORM_DEVID_AUTO);
+ if (!pdev)
+ return -ENOMEM;
+
+ if (itype != ACPI_AEST_NODE_SYSTEM_REGISTER) {
+ struct resource mmio_res;
+
+ ret = of_address_to_resource(np, 0, &mmio_res);
+ if (ret) {
+ pr_err("node %pOF: missing 'reg' for MMIO interface\n", np);
+ goto err_put;
+ }
+ res[nres].name = AEST_NODE_NAME;
+ res[nres].start = mmio_res.start;
+ res[nres].end = mmio_res.start + ras_of_mem_size(gfmt) - 1;
+ res[nres].flags = IORESOURCE_MEM;
+ nres++;
+ }
+
+ for (i = 0; i < AEST_MAX_INTERRUPT_PER_NODE; i++) {
+ int irq_num = of_irq_get_byname(np, ras_of_dt_irq_names[i]);
+
+ if (irq_num <= 0)
+ continue;
+
+ gsiv[i] = ras_of_virq_to_gsiv(irq_num);
+ virq[i] = irq_num;
+
+ res[nres].name = ras_of_irq_res_names[i];
+ res[nres].start = irq_num;
+ res[nres].end = irq_num;
+ res[nres].flags = IORESOURCE_IRQ;
+ nres++;
+ }
+
+ ret = platform_device_add_resources(pdev, res, nres);
+ if (ret)
+ goto err_put;
+
+ ret = ras_of_attach_fwnode(np, pdev, node_type, itype, gfmt, index,
+ virq[ACPI_AEST_NODE_FAULT_HANDLING],
+ gsiv[ACPI_AEST_NODE_FAULT_HANDLING],
+ gsiv[ACPI_AEST_NODE_ERROR_RECOVERY]);
+ if (ret)
+ goto err_put;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto err_put;
+
+ pr_debug("registered RAS node %pOF as arm64_ras.%d\n", np, pdev->id);
+ return 0;
+
+err_put:
+ platform_device_put(pdev);
+ return ret;
+}
+
+static int __init ras_of_init(void)
+{
+ const struct of_device_id *match;
+ struct device_node *np;
+ int index = 0, ret;
+
+ if (!acpi_disabled)
+ return 0;
+
+ for_each_matching_node_and_match(np, ras_of_match, &match) {
+ u8 node_type = *(const unsigned long *)match->data;
+
+ ret = ras_of_init_one_node(np, node_type, index++);
+ if (ret) {
+ pr_err("failed to register RAS node %pOF: %d\n",
+ np, ret);
+ of_node_put(np);
+ return ret;
+ }
+ }
+
+ if (index)
+ pr_info("registered %d RAS error source(s) from DT\n", index);
+
+ return 0;
+}
+subsys_initcall_sync(ras_of_init);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 3/4] arm64: dts: qcom: monaco: add RAS error source nodes
From: Umang Chheda @ 2026-07-20 8:19 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Ruidong Tian, Tony Luck, Borislav Petkov,
Umang Chheda
Cc: devicetree, linux-kernel, linux-arm-msm, linux-acpi,
linux-arm-kernel, linux-edac, faruque.ansari, avaneesh.dwivedi
In-Reply-To: <20260720081954.1858180-1-umang.chheda@oss.qualcomm.com>
Add RAS error source nodes for the Monaco SoC.
Two processor error sources are described: a per-PE node covering the
L1/L2 cache hierarchy using a PPI, and two shared L3 cache nodes for
the two CPU clusters using SPIs.
Co-developed-by: Faruque Ansari <faruque.ansari@oss.qualcomm.com>
Signed-off-by: Faruque Ansari <faruque.ansari@oss.qualcomm.com>
Signed-off-by: Umang Chheda <umang.chheda@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/monaco.dtsi | 30 ++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 64fc0d592282..4fbd1dc9a147 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -724,6 +724,36 @@ system_pd: power-domain-system {
};
};
+ ras-l1l2-0 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <1>;
+ arm,record-impl = /bits/ 64 <0x1>;
+ arm,status-reporting = /bits/ 64 <0x1>;
+ cache = <&l2_0>;
+ interrupts = <GIC_PPI 0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "fhi";
+ };
+
+ ras-l3-cluster0 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <2>;
+ arm,record-impl = /bits/ 64 <0x2>;
+ arm,status-reporting = /bits/ 64 <0x2>;
+ cache = <&l3_0>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "fhi";
+ };
+
+ ras-l3-cluster1 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <2>;
+ arm,record-impl = /bits/ 64 <0x2>;
+ arm,status-reporting = /bits/ 64 <0x2>;
+ cache = <&l3_1>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "fhi";
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
--
2.34.1
^ permalink raw reply related
* [PATCH v2 4/4] arm64: dts: qcom: lemans: add RAS error source nodes
From: Umang Chheda @ 2026-07-20 8:19 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Ruidong Tian, Tony Luck, Borislav Petkov,
Umang Chheda
Cc: devicetree, linux-kernel, linux-arm-msm, linux-acpi,
linux-arm-kernel, linux-edac, faruque.ansari, avaneesh.dwivedi
In-Reply-To: <20260720081954.1858180-1-umang.chheda@oss.qualcomm.com>
Add RAS error source nodes for the Lemans SoC.
Two processor error sources are described: a per-PE node covering
the L1/L2 cache hierarchy using a PPI, and two shared L3 cache
nodes for the two CPU clusters using SPIs.
Co-developed-by: Faruque Ansari <faruque.ansari@oss.qualcomm.com>
Signed-off-by: Faruque Ansari <faruque.ansari@oss.qualcomm.com>
Signed-off-by: Umang Chheda <umang.chheda@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/lemans.dtsi | 30 ++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 3b0539e27b51..64d3370cba82 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -619,6 +619,36 @@ system_pd: power-domain-system {
};
};
+ ras-l1l2-0 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <1>;
+ arm,record-impl = /bits/ 64 <0x1>;
+ arm,status-reporting = /bits/ 64 <0x1>;
+ cache = <&l2_0>;
+ interrupts = <GIC_PPI 0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "fhi";
+ };
+
+ ras-l3-cluster0 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <2>;
+ arm,record-impl = /bits/ 64 <0x2>;
+ arm,status-reporting = /bits/ 64 <0x2>;
+ cache = <&l3_0>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "fhi";
+ };
+
+ ras-l3-cluster1 {
+ compatible = "arm,ras-processor";
+ arm,num-records = <2>;
+ arm,record-impl = /bits/ 64 <0x2>;
+ arm,status-reporting = /bits/ 64 <0x2>;
+ cache = <&l3_1>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "fhi";
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v13 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Loic Poulain @ 2026-07-20 8:21 UTC (permalink / raw)
To: Bryan O'Donoghue
Cc: Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
Bryan O'Donoghue, Vladimir Zapolskiy, linux-arm-msm,
linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <20260720-x1e-csi2-phy-v13-2-160c31958863@linaro.org>
On Mon, Jul 20, 2026 at 3:14 AM Bryan O'Donoghue
<bryan.odonoghue@linaro.org> wrote:
>
> Add a new MIPI CSI2 driver in DPHY mode initially. The entire set of
> existing CAMSS CSI PHY init sequences are imported in order to save time
> and effort in later patches.
>
> The following devices are supported in this drop:
> "qcom,x1e80100-csi2-phy"
>
> In-line with other PHY drivers the process node is included in the name.
> Data-lane and clock lane positioning and polarity selection via newly
> amended struct phy_configure_opts_mipi_dphy{} is supported.
>
> The Qualcomm 3PH class of PHYs can do both DPHY and CPHY mode. For now only
> DPHY is supported.
>
> In porting some of the logic over from camss-csiphy*.c to here its also
> possible to rationalise some of the code.
>
> In particular use of regulator_bulk and clk_bulk as well as dropping the
> seemingly useless and unused interrupt handler.
>
> The PHY sequences and a lot of the logic that goes with them are well
> proven in CAMSS and mature so the main thing to watch out for here is how
> to get the right sequencing of regulators, clocks and register-writes.
>
> The register init sequence table is imported verbatim from the existing
> CAMSS csiphy driver. A follow-up series will rework the table to extract
> the repetitive per-lane pattern into a loop.
>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
> MAINTAINERS | 10 +
> drivers/phy/qualcomm/Kconfig | 15 +
> drivers/phy/qualcomm/Makefile | 5 +
> drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 385 ++++++++++++++++++
> drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c | 449 +++++++++++++++++++++
> drivers/phy/qualcomm/phy-qcom-mipi-csi2.h | 97 +++++
> 6 files changed, 961 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 15011f5752a99..a203b41475ea4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22296,6 +22296,16 @@ S: Maintained
> F: Documentation/devicetree/bindings/media/qcom,*-iris.yaml
> F: drivers/media/platform/qcom/iris/
>
> +QUALCOMM MIPI CSI2 PHY DRIVER
> +M: Bryan O'Donoghue <bod@kernel.org>
> +L: linux-phy@lists.infradead.org
> +L: linux-media@vger.kernel.org
> +L: linux-arm-msm@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/phy/qcom,*-csi2-phy.yaml
> +F: drivers/phy/qualcomm/phy-qcom-mipi-csi2*.c
> +F: drivers/phy/qualcomm/phy-qcom-mipi-csi2*.h
> +
> QUALCOMM NAND CONTROLLER DRIVER
> M: Manivannan Sadhasivam <mani@kernel.org>
> L: linux-mtd@lists.infradead.org
> diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
> index 60a0ead127fa9..cd6959e69bef7 100644
> --- a/drivers/phy/qualcomm/Kconfig
> +++ b/drivers/phy/qualcomm/Kconfig
> @@ -28,6 +28,21 @@ config PHY_QCOM_EDP
> Enable this driver to support the Qualcomm eDP PHY found in various
> Qualcomm chipsets.
>
> +config PHY_QCOM_MIPI_CSI2
> + tristate "Qualcomm MIPI CSI2 PHY driver"
> + depends on ARCH_QCOM || COMPILE_TEST
> + depends on OF
> + depends on PM
> + depends on PM_OPP
> + depends on COMMON_CLK
> + select GENERIC_PHY
> + select GENERIC_PHY_MIPI_DPHY
> + help
> + Enable this to support the MIPI CSI2 PHY driver found in various
> + Qualcomm chipsets. This PHY is used to connect MIPI CSI2
> + camera sensors to the CSI Decoder in the Qualcomm Camera Subsystem
> + CAMSS.
> +
> config PHY_QCOM_IPQ4019_USB
> tristate "Qualcomm IPQ4019 USB PHY driver"
> depends on OF && (ARCH_QCOM || COMPILE_TEST)
> diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
> index b71a6a0bed3f1..382cb594b06b6 100644
> --- a/drivers/phy/qualcomm/Makefile
> +++ b/drivers/phy/qualcomm/Makefile
> @@ -6,6 +6,11 @@ obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
> obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
> obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o
> obj-$(CONFIG_PHY_QCOM_M31_EUSB) += phy-qcom-m31-eusb2.o
> +
> +phy-qcom-mipi-csi2-objs += phy-qcom-mipi-csi2-core.o \
> + phy-qcom-mipi-csi2-3ph-dphy.o
> +obj-$(CONFIG_PHY_QCOM_MIPI_CSI2) += phy-qcom-mipi-csi2.o
> +
> obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
>
> obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o phy-qcom-qmp-usbc.o
> diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
> new file mode 100644
> index 0000000000000..966d79c98f9b2
> --- /dev/null
> +++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
> @@ -0,0 +1,385 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Qualcomm MSM Camera Subsystem - CSIPHY Module 3phase v1.0
> + *
> + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2016-2026 Linaro Ltd.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/time64.h>
> +
> +#include "phy-qcom-mipi-csi2.h"
> +
> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(offset, n) ((offset) + 0x4 * (n))
> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL0_PHY_SW_RESET BIT(0)
> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE BIT(7)
> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B BIT(0)
> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID BIT(1)
> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL10_IRQ_CLEAR_CMD BIT(0)
> +#define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(offset, n) ((offset) + 0xb0 + 0x4 * (n))
> +
> +#define CSIPHY_2PH_LN_CSI_2PHASE_CTRL9n(n) ((0x200 * (n)) + 0x24)
> +
> +/*
> + * 3 phase CSI has 19 common status regs with only 0-10 being used
> + * and 11-18 being reserved.
> + */
> +#define CSI_COMMON_STATUS_NUM 11
> +/*
> + * There are a number of common control registers
> + * The offset to clear the CSIPHY IRQ status starts @ 22
> + * So to clear CSI_COMMON_STATUS0 this is CSI_COMMON_CONTROL22, STATUS1 is
> + * CONTROL23 and so on
> + */
> +#define CSI_CTRL_STATUS_INDEX 22
> +
> +/*
> + * There are 43 COMMON_CTRL registers with regs after # 33 being reserved
> + */
> +#define CSI_CTRL_MAX 33
> +
> +#define CSIPHY_DEFAULT_PARAMS 0
> +#define CSIPHY_SETTLE_CNT_LOWER_BYTE 2
> +#define CSIPHY_SKEW_CAL 7
> +
> +/* 4nm 2PH v 2.1.2 2p5Gbps 4 lane DPHY mode */
> +static const struct
> +mipi_csi2phy_lane_regs lane_regs_x1e80100[] = {
> + /* Power up lanes 2ph mode */
> + {.reg_addr = 0x101c, .reg_data = 0x7a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x1018, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> +
> + {.reg_addr = 0x0094, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x00a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0090, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0098, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0094, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0030, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0000, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0038, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x002c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0034, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x001c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0014, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x003c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0004, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0020, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0008, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0010, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0094, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x005c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0060, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0064, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
> +
> + {.reg_addr = 0x0e94, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0ea0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e90, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e98, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e94, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e30, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e28, .reg_data = 0x04, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e00, .reg_data = 0x80, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e0c, .reg_data = 0xff, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e38, .reg_data = 0x1f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e2c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e34, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e1c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e14, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e3c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e04, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e20, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e08, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0e10, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> +
> + {.reg_addr = 0x0494, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x04a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0490, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0498, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0494, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0430, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0400, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0438, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x042c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0434, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x041c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0414, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x043c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0404, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0420, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0408, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0410, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0494, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x045c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0460, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0464, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
> +
> + {.reg_addr = 0x0894, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x08a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0890, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0898, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0894, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0830, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0800, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0838, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x082c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0834, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x081c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0814, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x083c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0804, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0820, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0808, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0810, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0894, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x085c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0860, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0864, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
> +
> + {.reg_addr = 0x0c94, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0ca0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c90, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c98, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c94, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c30, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c00, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c38, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c2c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c34, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c1c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c14, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c3c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c04, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c20, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c08, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0c10, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c94, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0c5c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0c60, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0c64, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
> +};
> +
> +static inline const struct mipi_csi2phy_device_regs *
> +csi2phy_dev_to_regs(struct mipi_csi2phy_device *csi2phy)
> +{
> + return &csi2phy->soc_cfg->reg_info;
> +}
> +
> +static void phy_qcom_mipi_csi2_hw_version_read(struct mipi_csi2phy_device *csi2phy)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> + u32 tmp;
> +
> + writel(CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 6));
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 12));
> + csi2phy->hw_version = tmp;
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 13));
> + csi2phy->hw_version |= (tmp << 8) & 0xFF00;
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 14));
> + csi2phy->hw_version |= (tmp << 16) & 0xFF0000;
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 15));
> + csi2phy->hw_version |= (tmp << 24) & 0xFF000000;
> +
> + dev_dbg_once(csi2phy->dev, "CSIPHY 3PH HW Version = 0x%08x\n", csi2phy->hw_version);
> +}
> +
> +/*
> + * phy_qcom_mipi_csi2_reset - Perform software reset on CSIPHY module
> + * @phy_qcom_mipi_csi2: CSIPHY device
> + */
> +static void phy_qcom_mipi_csi2_reset(struct mipi_csi2phy_device *csi2phy)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> +
> + writel(CSIPHY_3PH_CMN_CSI_COMMON_CTRL0_PHY_SW_RESET,
> + csi2phy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 0));
> + usleep_range(5000, 8000);
> + writel(0x0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 0));
> +}
> +
> +/*
> + * phy_qcom_mipi_csi2_settle_cnt_calc - Calculate settle count value
> + *
> + * Helper function to calculate settle count value. This is
> + * based on the CSI2 T_hs_settle parameter which in turn
> + * is calculated based on the CSI2 transmitter link frequency.
> + *
> + * Return settle count.
> + */
> +static u8 phy_qcom_mipi_csi2_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate)
> +{
> + u32 t_hs_prepare_max_ps;
> + u32 timer_period_ps;
> + u32 t_hs_settle_ps;
> + u8 settle_cnt;
> + u32 ui_ps;
> +
> + ui_ps = div64_u64(PSEC_PER_SEC, link_freq);
> + ui_ps /= 2;
> + t_hs_prepare_max_ps = 85000 + 6 * ui_ps;
> + t_hs_settle_ps = t_hs_prepare_max_ps;
> +
> + timer_period_ps = div_u64(PSEC_PER_SEC, timer_clk_rate);
> +
> + if ((t_hs_settle_ps / timer_period_ps) < 6)
> + return 0;
> +
> + settle_cnt = t_hs_settle_ps / timer_period_ps - 6;
> +
> + return settle_cnt;
> +}
> +
> +static void
> +phy_qcom_mipi_csi2_gen2_config_lanes(struct mipi_csi2phy_device *csi2phy,
> + u8 settle_cnt)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> + const struct mipi_csi2phy_lane_regs *r = regs->init_seq;
> + int i, array_size = regs->lane_array_size;
> + u32 val;
> +
> + for (i = 0; i < array_size; i++, r++) {
> + switch (r->param_type) {
> + case CSIPHY_SETTLE_CNT_LOWER_BYTE:
> + val = settle_cnt & 0xff;
> + break;
> + case CSIPHY_SKEW_CAL:
> + /* TODO: support application of skew from dt flag */
> + continue;
> + default:
> + val = r->reg_data;
> + break;
> + }
> + writel(val, csi2phy->base + r->reg_addr);
> + if (r->delay_us)
> + udelay(r->delay_us);
> + }
> +}
> +
> +static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
> + struct mipi_csi2phy_stream_cfg *cfg)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> + struct mipi_csi2phy_lanes_cfg *lane_cfg = &cfg->lane_cfg;
> + u8 settle_cnt;
> + u8 val;
> + int i;
> +
> + if (cfg->link_freq <= 0)
> + return -EINVAL;
> +
> + settle_cnt = phy_qcom_mipi_csi2_settle_cnt_calc(cfg->link_freq, csi2phy->timer_clk_rate);
> + if (!settle_cnt)
> + return -ENODEV;
> +
> + /*
> + * CSI_COMMON_CTRL5 is a physical lane power-up bitmap:
> + * - Bits [0,2,4,6] → D-PHY data lanes(LN0, LN2, LN4, LN6)
> + * - Bits [1,3,5] → C-PHY trio lanes(LN1, LN3, LN5)
> + * - Bit [7] → D-PHY clock lane(LNCK) dedicated clock enable
> + */
> + val = BIT(lane_cfg->clk.pos);
> + for (i = 0; i < cfg->num_data_lanes; i++)
> + val |= BIT(lane_cfg->data[i].pos * 2);
> +
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 5));
> +
> + /* Lane configuration for polarity @ CSIPHY-base + CTRL9 */
> + for (i = 0; i < cfg->num_data_lanes; i++) {
> + if (lane_cfg->data[i].pol) {
> + u8 pos = lane_cfg->data[i].pos;
> +
> + writel(BIT(2), csi2phy->base + CSIPHY_2PH_LN_CSI_2PHASE_CTRL9n(pos * 2));
> + }
> + }
> +
> + if (lane_cfg->clk.pol)
> + writel(BIT(2), csi2phy->base + CSIPHY_2PH_LN_CSI_2PHASE_CTRL9n(lane_cfg->clk.pos));
> +
> + val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B;
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 6));
> +
> + val = 0x02;
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 7));
> +
> + val = 0x00;
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 0));
> +
> + phy_qcom_mipi_csi2_gen2_config_lanes(csi2phy, settle_cnt);
> +
> + /* IRQ_MASK registers - disable all interrupts */
> + for (i = CSI_COMMON_STATUS_NUM; i < CSI_CTRL_STATUS_INDEX; i++) {
> + writel(0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, i));
> + }
> +
> + return 0;
> +}
> +
> +static void
> +phy_qcom_mipi_csi2_lanes_disable(struct mipi_csi2phy_device *csi2phy,
> + struct mipi_csi2phy_stream_cfg *cfg)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> +
> + writel(0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 5));
> +
> + writel(0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 6));
> +}
> +
> +static const struct mipi_csi2phy_hw_ops phy_qcom_mipi_csi2_ops_3ph_1_0 = {
> + .hw_version_read = phy_qcom_mipi_csi2_hw_version_read,
> + .reset = phy_qcom_mipi_csi2_reset,
> + .lanes_enable = phy_qcom_mipi_csi2_lanes_enable,
> + .lanes_disable = phy_qcom_mipi_csi2_lanes_disable,
> +};
> +
> +static const char * const x1e_clks[] = {
> + "core",
> + "timer",
> + "ahb"
> +};
> +
> +static const char * const x1e_supplies[] = {
> + "vdda-0p9",
> + "vdda-1p2"
> +};
> +
> +static struct mipi_csi2_genpd x1e_genpds[] = {
> + { .name = "top", .scaled = false },
> + { .name = "mmcx", .scaled = true },
> + { .name = "mx", .scaled = true },
> +};
> +
> +const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_4nm_x1e = {
> + .ops = &phy_qcom_mipi_csi2_ops_3ph_1_0,
> + .reg_info = {
> + .init_seq = lane_regs_x1e80100,
> + .lane_array_size = ARRAY_SIZE(lane_regs_x1e80100),
> + .common_regs_offset = 0x1000,
> + },
> + .supply_names = (const char **)x1e_supplies,
> + .num_supplies = ARRAY_SIZE(x1e_supplies),
> + .clk_names = (const char **)x1e_clks,
> + .num_clk = ARRAY_SIZE(x1e_clks),
> + .genpds = x1e_genpds,
> + .num_genpds = ARRAY_SIZE(x1e_genpds),
> +};
> diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
> new file mode 100644
> index 0000000000000..aae049f0ec160
> --- /dev/null
> +++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
> @@ -0,0 +1,449 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2026, Linaro Ltd.
> + */
> +
> +#include <dt-bindings/phy/phy.h>
> +#include <linux/clk.h>
> +#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/pm_opp.h>
> +#include <linux/phy/phy.h>
> +#include <linux/phy/phy-mipi-dphy.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +
> +#include "phy-qcom-mipi-csi2.h"
> +
> +static int
> +phy_qcom_mipi_csi2_set_clock_rates(struct mipi_csi2phy_device *csi2phy,
> + s64 link_freq)
> +{
> + struct device *dev = csi2phy->dev;
> + unsigned long opp_rate = link_freq / 4;
> + struct dev_pm_opp *opp;
> + long timer_rate;
> + int i, pstate;
> + int ret;
> +
> + opp = dev_pm_opp_find_freq_ceil(dev, &opp_rate);
> + if (IS_ERR(opp)) {
> + dev_err(csi2phy->dev, "Couldn't find ceiling for %lld Hz\n",
> + link_freq);
> + return PTR_ERR(opp);
> + }
> +
> + pstate = 0;
> + for (i = 0; i < csi2phy->pd_list->num_pds; i++) {
> + unsigned int perf;
> +
> + if (!csi2phy->soc_cfg->genpds[i].scaled)
> + continue;
> +
> + perf = dev_pm_opp_get_required_pstate(opp, pstate);
> + pstate += 1;
> +
> + ret = dev_pm_genpd_set_performance_state(csi2phy->pd_list->pd_devs[i], perf);
> + if (ret) {
> + dev_err(csi2phy->dev, "Couldn't set perf state %u\n",
> + perf);
> + dev_pm_opp_put(opp);
> + goto unset_pstate;
> + }
> + }
> + dev_pm_opp_put(opp);
> +
> + ret = dev_pm_opp_set_rate(dev, opp_rate);
> + if (ret) {
> + dev_err(csi2phy->dev, "dev_pm_opp_set_rate() fail\n");
> + goto unset_opp_rate;
> + }
> +
> + timer_rate = clk_round_rate(csi2phy->timer_clk, link_freq / 4);
> + if (timer_rate <= 0) {
> + ret = -ENODEV;
> + goto unset_opp_rate;
> + }
> +
> + ret = clk_set_rate(csi2phy->timer_clk, timer_rate);
> + if (ret)
> + goto unset_opp_rate;
> +
> + csi2phy->timer_clk_rate = timer_rate;
> +
> + return 0;
> +
> +unset_opp_rate:
> + dev_pm_opp_set_rate(dev, 0);
> +
> +unset_pstate:
> + while (i--) {
> + if (!csi2phy->soc_cfg->genpds[i].scaled)
> + continue;
> +
> + dev_pm_genpd_set_performance_state(csi2phy->pd_list->pd_devs[i], 0);
> + }
> +
> + return ret;
> +}
> +
> +static int phy_qcom_mipi_csi2_configure(struct phy *phy,
> + union phy_configure_opts *opts)
> +{
> + struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
> + struct phy_configure_opts_mipi_dphy *dphy_cfg = &opts->mipi_dphy;
> + struct mipi_csi2phy_stream_cfg *stream_cfg = &csi2phy->stream_cfg;
> + int ret;
> +
> + ret = phy_mipi_dphy_config_validate(dphy_cfg);
> + if (ret)
> + return ret;
> +
> + if (dphy_cfg->lanes < 1 || dphy_cfg->lanes > CSI2_MAX_DATA_LANES)
> + return -EINVAL;
> +
> + stream_cfg->link_freq = dphy_cfg->hs_clk_rate;
> +
> + return 0;
> +}
> +
> +static int phy_qcom_mipi_csi2_power_on(struct phy *phy)
> +{
> + struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
> + const struct mipi_csi2phy_hw_ops *ops = csi2phy->soc_cfg->ops;
> + int i, ret;
> +
> + ret = regulator_bulk_enable(csi2phy->soc_cfg->num_supplies,
> + csi2phy->supplies);
> + if (ret)
> + return ret;
> +
> + ret = pm_runtime_resume_and_get(csi2phy->dev);
> + if (ret < 0)
> + goto disable_regulators;
> +
> + ret = phy_qcom_mipi_csi2_set_clock_rates(csi2phy, csi2phy->stream_cfg.link_freq);
> + if (ret)
> + goto poweroff_phy;
> +
> + ret = clk_bulk_prepare_enable(csi2phy->soc_cfg->num_clk,
> + csi2phy->clks);
> + if (ret) {
> + dev_err(csi2phy->dev, "failed to enable clocks, %d\n", ret);
> + goto unset_rate;
> + }
> +
> + ops->reset(csi2phy);
> +
> + ops->hw_version_read(csi2phy);
> +
> + ret = ops->lanes_enable(csi2phy, &csi2phy->stream_cfg);
> + if (ret)
> + goto unset_clocks;
> +
> + return 0;
> +
> +unset_clocks:
> + clk_bulk_disable_unprepare(csi2phy->soc_cfg->num_clk,
> + csi2phy->clks);
> +
> +unset_rate:
> + dev_pm_opp_set_rate(csi2phy->dev, 0);
> +
> + for (i = 0; i < csi2phy->pd_list->num_pds; i++) {
> + if (!csi2phy->soc_cfg->genpds[i].scaled)
> + continue;
> +
> + dev_pm_genpd_set_performance_state(csi2phy->pd_list->pd_devs[i], 0);
> + }
> +
> +poweroff_phy:
> + pm_runtime_put_sync(csi2phy->dev);
> +
> +disable_regulators:
> + regulator_bulk_disable(csi2phy->soc_cfg->num_supplies,
> + csi2phy->supplies);
> +
> + return ret;
> +}
> +
> +static int phy_qcom_mipi_csi2_power_off(struct phy *phy)
> +{
> + struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
> + const struct mipi_csi2phy_hw_ops *ops = csi2phy->soc_cfg->ops;
> + int i;
> +
> + ops->lanes_disable(csi2phy, &csi2phy->stream_cfg);
> +
> + clk_bulk_disable_unprepare(csi2phy->soc_cfg->num_clk,
> + csi2phy->clks);
> +
> + dev_pm_opp_set_rate(csi2phy->dev, 0);
> +
> + for (i = 0; i < csi2phy->pd_list->num_pds; i++) {
> + if (!csi2phy->soc_cfg->genpds[i].scaled)
> + continue;
> +
> + dev_pm_genpd_set_performance_state(csi2phy->pd_list->pd_devs[i], 0);
> + }
> +
> + pm_runtime_put_sync(csi2phy->dev);
> +
> + regulator_bulk_disable(csi2phy->soc_cfg->num_supplies,
> + csi2phy->supplies);
> +
> + return 0;
> +}
> +
> +static const struct phy_ops phy_qcom_mipi_csi2_ops = {
> + .configure = phy_qcom_mipi_csi2_configure,
> + .power_on = phy_qcom_mipi_csi2_power_on,
> + .power_off = phy_qcom_mipi_csi2_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct phy *qcom_csi2_phy_xlate(struct device *dev,
> + const struct of_phandle_args *args)
> +{
> + struct mipi_csi2phy_device *csi2phy = dev_get_drvdata(dev);
> +
> + if (args->args_count < 1 || args->args[0] != PHY_TYPE_DPHY) {
> + dev_err(csi2phy->dev, "invalid phy mode in DTB\n");
> + return ERR_PTR(-EOPNOTSUPP);
> + }
> +
> + csi2phy->phy_mode = args->args[0];
> +
> + return csi2phy->phy;
> +}
> +
> +static int phy_qcom_mipi_csi2_attach_pm_domains(struct mipi_csi2phy_device *csi2phy)
> +{
> + struct dev_pm_domain_attach_data pd_data = { 0 };
> + const char **pd_names;
> + int i;
> +
> + pd_names = devm_kzalloc(csi2phy->dev,
> + sizeof(char *) * csi2phy->soc_cfg->num_genpds,
> + GFP_KERNEL);
> + if (!pd_names)
> + return -ENOMEM;
> +
> + for (i = 0; i < csi2phy->soc_cfg->num_genpds; i++)
> + pd_names[i] = csi2phy->soc_cfg->genpds[i].name;
> +
> + pd_data.pd_names = pd_names;
> + pd_data.num_pd_names = csi2phy->soc_cfg->num_genpds;
> +
> + return devm_pm_domain_attach_list(csi2phy->dev, &pd_data,
> + &csi2phy->pd_list);
> +}
> +
> +static int phy_qcom_mipi_csi2_parse_routing(struct mipi_csi2phy_device *csi2phy)
> +{
> + struct mipi_csi2phy_stream_cfg *stream_cfg = &csi2phy->stream_cfg;
> + u32 lane_polarities[CSI2_MAX_DATA_LANES + 1];
> + u32 data_lanes[CSI2_MAX_DATA_LANES];
> + struct device *dev = csi2phy->dev;
> + struct fwnode_handle *ep;
> + int num_polarities;
> + int num_data_lanes;
> + int i, ret;
> +
> + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 1, 0);
> + if (ep) {
> + fwnode_handle_put(ep);
> + dev_err(dev, "DPHY split mode is not supported\n");
> + return -EOPNOTSUPP;
> + }
> +
> + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
> + if (!ep) {
> + dev_err(dev, "Missing port@0\n");
> + return -ENODEV;
> + }
> +
> + num_data_lanes = fwnode_property_count_u32(ep, "data-lanes");
> + if (num_data_lanes < 1 || num_data_lanes > CSI2_MAX_DATA_LANES) {
> + ret = -EINVAL;
> + dev_err(dev, "Invalid data-lanes count: %d\n", num_data_lanes);
> + goto out_put;
> + }
> + stream_cfg->num_data_lanes = num_data_lanes;
> +
> + ret = fwnode_property_read_u32_array(ep, "data-lanes", data_lanes,
> + stream_cfg->num_data_lanes);
> + if (ret) {
> + dev_err(dev, "Failed to read data-lanes: %d\n", ret);
> + goto out_put;
> + }
> +
> + /* lane-polarities: optional, up to num_data_lanes + 1 entries */
> + memset(lane_polarities, 0x00, sizeof(lane_polarities));
> + num_polarities = fwnode_property_count_u32(ep, "lane-polarities");
> + if (num_polarities > 0) {
> + if (num_polarities != stream_cfg->num_data_lanes + 1) {
> + ret = -EINVAL;
> + dev_err(dev, "clock+data-lane %d/polarities %d mismatch\n",
> + stream_cfg->num_data_lanes + 1, num_polarities);
> + goto out_put;
> + }
> +
> + ret = fwnode_property_read_u32_array(ep, "lane-polarities", lane_polarities,
> + num_polarities);
> + if (ret) {
> + dev_err(dev, "Failed to read lane-polarities: %d\n", ret);
> + goto out_put;
> + }
> + }
> +
> + csi2phy->stream_cfg.lane_cfg.clk.pos = CSI2_DEFAULT_CLK_LANE;
> + csi2phy->stream_cfg.lane_cfg.clk.pol = lane_polarities[0];
> +
> + for (i = 0; i < csi2phy->stream_cfg.num_data_lanes; i++) {
> + if (data_lanes[i] >= CSI2_MAX_DATA_LANES) {
> + dev_err(dev, "Invalid lane %d\n", data_lanes[i]);
> + ret = -EINVAL;
> + goto out_put;
> + }
> + csi2phy->stream_cfg.lane_cfg.data[i].pos = data_lanes[i];
> + csi2phy->stream_cfg.lane_cfg.data[i].pol = lane_polarities[i + 1];
> + }
> +
> + ret = 0;
> +
> +out_put:
> + fwnode_handle_put(ep);
> +
> + return ret;
> +}
> +
> +static int phy_qcom_mipi_csi2_probe(struct platform_device *pdev)
> +{
> + unsigned int i, num_clk, num_supplies;
> + struct mipi_csi2phy_device *csi2phy;
> + struct phy_provider *phy_provider;
> + struct device *dev = &pdev->dev;
> + struct phy *generic_phy;
> + int ret;
> +
> + csi2phy = devm_kzalloc(dev, sizeof(*csi2phy), GFP_KERNEL);
> + if (!csi2phy)
> + return -ENOMEM;
> +
> + csi2phy->dev = dev;
> + dev_set_drvdata(dev, csi2phy);
> +
> + csi2phy->soc_cfg = device_get_match_data(&pdev->dev);
> +
> + if (!csi2phy->soc_cfg)
> + return -EINVAL;
> +
> + num_clk = csi2phy->soc_cfg->num_clk;
> +
> + ret = phy_qcom_mipi_csi2_parse_routing(csi2phy);
> + if (ret)
> + return ret;
> +
> + ret = phy_qcom_mipi_csi2_attach_pm_domains(csi2phy);
> + if (ret < 0 || csi2phy->pd_list == NULL) {
> + if (ret == 0)
> + ret = -ENODEV;
> + return dev_err_probe(dev, ret, "Failed to attach power-domain list\n");
> + }
> +
> + ret = devm_pm_runtime_enable(dev);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "Failed to enable pm runtime\n");
> +
> + ret = devm_clk_bulk_get_all(dev, &csi2phy->clks);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "Failed to get clocks\n");
> +
> + if (num_clk != ret) {
> + return dev_err_probe(dev, -ENODEV, "clock count %d expected %d\n",
> + ret, num_clk);
> + }
> +
> + for (i = 0; i < num_clk; i++) {
> + if (!csi2phy->clks[i].id)
> + return dev_err_probe(dev, -EINVAL, "Missing clock-names\n");
> +
> + if (!strcmp(csi2phy->clks[i].id, "timer")) {
> + csi2phy->timer_clk = csi2phy->clks[i].clk;
> + break;
> + }
> + }
> + if (!csi2phy->timer_clk)
> + return dev_err_probe(dev, -ENODEV, "no timer clock\n");
> +
> + ret = devm_pm_opp_set_clkname(dev, "core");
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to set opp clkname\n");
> +
> + ret = devm_pm_opp_of_add_table(dev);
> + if (ret)
> + return dev_err_probe(dev, ret, "invalid OPP table in device tree\n");
> +
> + num_supplies = csi2phy->soc_cfg->num_supplies;
> + csi2phy->supplies = devm_kzalloc(dev, sizeof(*csi2phy->supplies) * num_supplies,
> + GFP_KERNEL);
> + if (!csi2phy->supplies)
> + return -ENOMEM;
> +
> + for (i = 0; i < num_supplies; i++)
> + csi2phy->supplies[i].supply = csi2phy->soc_cfg->supply_names[i];
> +
> + ret = devm_regulator_bulk_get(dev, num_supplies, csi2phy->supplies);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "failed to get regulator supplies\n");
> +
> + csi2phy->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(csi2phy->base))
> + return PTR_ERR(csi2phy->base);
> +
> + generic_phy = devm_phy_create(dev, NULL, &phy_qcom_mipi_csi2_ops);
> + if (IS_ERR(generic_phy)) {
> + ret = PTR_ERR(generic_phy);
> + return dev_err_probe(dev, ret, "failed to create phy\n");
> + }
> + csi2phy->phy = generic_phy;
> +
> + phy_set_drvdata(generic_phy, csi2phy);
> +
> + phy_provider = devm_of_phy_provider_register(dev, qcom_csi2_phy_xlate);
> + if (!IS_ERR(phy_provider))
> + dev_dbg(dev, "Registered MIPI CSI2 PHY device\n");
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id phy_qcom_mipi_csi2_of_match_table[] = {
> + { .compatible = "qcom,x1e80100-csi2-phy", .data = &mipi_csi2_dphy_4nm_x1e },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, phy_qcom_mipi_csi2_of_match_table);
> +
> +static struct platform_driver phy_qcom_mipi_csi2_driver = {
> + .probe = phy_qcom_mipi_csi2_probe,
> + .driver = {
> + .name = "qcom-mipi-csi2-phy",
> + .of_match_table = phy_qcom_mipi_csi2_of_match_table,
> + },
> +};
> +
> +module_platform_driver(phy_qcom_mipi_csi2_driver);
> +
> +MODULE_DESCRIPTION("Qualcomm MIPI CSI2 PHY driver");
> +MODULE_AUTHOR("Bryan O'Donoghue <bod@kernel.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
> new file mode 100644
> index 0000000000000..7e55ae0073704
> --- /dev/null
> +++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
> @@ -0,0 +1,97 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + *
> + * Qualcomm MIPI CSI2 CPHY/DPHY driver
> + *
> + * Copyright (C) 2025 Linaro Ltd.
> + */
> +#ifndef __PHY_QCOM_MIPI_CSI2_H__
> +#define __PHY_QCOM_MIPI_CSI2_H__
> +
> +#include <linux/phy/phy.h>
> +
> +#define CSI2_MAX_DATA_LANES 4
> +#define CSI2_DEFAULT_CLK_LANE 7
> +
> +struct mipi_csi2phy_lane {
> + u8 pos;
> + u8 pol;
> +};
> +
> +struct mipi_csi2phy_lanes_cfg {
> + struct mipi_csi2phy_lane data[CSI2_MAX_DATA_LANES];
> + struct mipi_csi2phy_lane clk;
> +};
> +
> +struct mipi_csi2phy_stream_cfg {
> + s64 link_freq;
> + u8 num_data_lanes;
> + struct mipi_csi2phy_lanes_cfg lane_cfg;
> +};
> +
> +struct mipi_csi2phy_device;
> +
> +struct mipi_csi2phy_hw_ops {
> + void (*hw_version_read)(struct mipi_csi2phy_device *csi2phy_dev);
> + void (*reset)(struct mipi_csi2phy_device *csi2phy_dev);
> + int (*lanes_enable)(struct mipi_csi2phy_device *csi2phy_dev,
> + struct mipi_csi2phy_stream_cfg *cfg);
> + void (*lanes_disable)(struct mipi_csi2phy_device *csi2phy_dev,
> + struct mipi_csi2phy_stream_cfg *cfg);
> +};
> +
> +struct mipi_csi2phy_lane_regs {
> + const s32 reg_addr;
> + const s32 reg_data;
> + const u32 delay_us;
> + const u32 param_type;
> +};
> +
> +struct mipi_csi2phy_device_regs {
> + const struct mipi_csi2phy_lane_regs *init_seq;
> + const int lane_array_size;
> + const u32 common_regs_offset;
> +};
> +
> +struct mipi_csi2_genpd {
> + const char *name;
> + bool scaled;
> +};
> +
> +struct mipi_csi2phy_soc_cfg {
> + const struct mipi_csi2phy_hw_ops *ops;
> + const struct mipi_csi2phy_device_regs reg_info;
> +
> + const char ** const supply_names;
> + const unsigned int num_supplies;
> +
> + const char ** const clk_names;
> + const unsigned int num_clk;
> +
> + const struct mipi_csi2_genpd *genpds;
> + const unsigned int num_genpds;
> +};
> +
> +struct mipi_csi2phy_device {
> + struct device *dev;
> + u8 phy_mode;
> +
> + struct phy *phy;
> + void __iomem *base;
> +
> + struct clk_bulk_data *clks;
> + struct clk *timer_clk;
> + u32 timer_clk_rate;
> +
> + struct regulator_bulk_data *supplies;
> + struct dev_pm_domain_list *pd_list;
> +
> + const struct mipi_csi2phy_soc_cfg *soc_cfg;
> + struct mipi_csi2phy_stream_cfg stream_cfg;
> +
> + u32 hw_version;
> +};
> +
> +extern const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_4nm_x1e;
> +
> +#endif /* __PHY_QCOM_MIPI_CSI2_H__ */
>
> --
> 2.54.0
>
>
^ permalink raw reply
* Re: [PATCH v5 1/2] arm64: dts: qcom: sdm845-google: Add dual front IMX355 cameras
From: Konrad Dybcio @ 2026-07-20 8:24 UTC (permalink / raw)
To: david, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Petr Hodina, Richard Acayan, linux-arm-msm, devicetree,
linux-kernel, phone-devel
In-Reply-To: <20260719-pixel3-camera-v5-1-99593f1bd8ec@ixit.cz>
On 7/19/26 8:03 PM, David Heidelberg via B4 Relay wrote:
> From: David Heidelberg <david@ixit.cz>
>
> The Pixel 3 features two front-facing Sony IMX355 sensors with
> different focal lengths (standard and wide-angle).
>
> Sensors are connected via CSIPHY port 1 and 2 and controlled over CCI
> I2C1, using MCLK2 as the clock source.
>
> This enables support for the dual front camera configuration.
>
> Signed-off-by: David Heidelberg <david@ixit.cz>
> ---
[...]
> @@ -127,16 +128,48 @@ vreg_s4a_1p8: regulator-vreg-s4a-1p8 {
/\ is regulator-foo
> regulator-min-microvolt = <1800000>;
> regulator-max-microvolt = <1800000>;
> regulator-always-on;
> regulator-boot-on;
>
> vin-supply = <&vph_pwr>;
> };
>
\/ this is foo-regulator, please stick to the former
> + camera_front_avdd: front-cam-avdd-regulator {
> + compatible = "regulator-fixed";
> + regulator-name = "front_cam_avdd";
[...]
> + cam_front_avdd_default_pin: cam-avdd-default-pins {
> + pins = "gpio8";
> + function = "gpio";
> + drive-strength = <2>;
> + bias-disable;
> + };
> +
> + cam_front_aux_reset_default_pin: cam-front-aux-reset-default-pins {
> + pins = "gpio9";
> + function = "gpio";
> + drive-strength = <2>;
> + bias-disable;
> + };
> +
> + cam_front_aux_avdd_default_pin: cam-avdd-aux-default-pins {
> + pins = "gpio14";
> + function = "gpio";
> + drive-strength = <2>;
> + bias-disable;
> + };
> +
> + cam_front_reset_default_pin: cam-front-reset-default-pins {
> + pins = "gpio21";
> + function = "gpio";
> + drive-strength = <2>;
> + bias-disable;
> + };
This addition fails dtbs_check
Konrad
^ permalink raw reply
* Re: [PATCH v5 2/2] arm64: dts: qcom: sdm845-google: Enable PMI8998 camera flash LEDs
From: Konrad Dybcio @ 2026-07-20 8:26 UTC (permalink / raw)
To: david, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Petr Hodina, Richard Acayan, linux-arm-msm, devicetree,
linux-kernel, phone-devel
In-Reply-To: <20260719-pixel3-camera-v5-2-99593f1bd8ec@ixit.cz>
On 7/19/26 8:03 PM, David Heidelberg via B4 Relay wrote:
> From: David Heidelberg <david@ixit.cz>
>
> Enable the PMI8998 flash LED block and describe two white flash LEDs
> used for the rear camera.
>
> Configure the LED in flash mode with hardware limits matching the
> original device configuration, including maximum current and timeout.
>
> In contrary to downstream, we can control both LEDs separately.
Progress!
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH v8 3/3] thermal/drivers/imx: Add calibration offset support
From: Frieder Schrempf @ 2026-07-20 8:27 UTC (permalink / raw)
To: CHENG Haoning (BCSC/ENG1)
Cc: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
linux-pm@vger.kernel.org, devicetree@vger.kernel.org,
imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <PAWPR10MB7415DE998EA3CCA639F14EF2C2C32@PAWPR10MB7415.EURPRD10.PROD.OUTLOOK.COM>
On 20.07.26 04:10, CHENG Haoning (BCSC/ENG1) wrote:
> [Sie erhalten nicht h?ufig E-Mails von haoning.cheng@cn.bosch.com. Weitere Informationen, warum dies wichtig ist, finden Sie unter https://aka.ms/LearnAboutSenderIdentification ]
>
> On 2026-07-17 06:23:44+00:00, CHENG Haoning (BCSC/ENG1) wrote:
>> On Wed, Jul 15, 2026 at 11:06:07AM +0200, Frieder Schrempf wrote:
>>
>>> On 14.07.26 12:28, Haoning CHENG via B4 Relay wrote:
>>>
>>> Sorry to chime in so late. I just want to understand what this
>>> calibration offset is about. Why would there be a need of a
>>> board-specific offset? The sensor is in the SoC and if you add a
>>> board-specific offset, you no longer measure the SoC core temperature,
>>> right?
>>>
>>> How would you determine the offset in the first place? How would I know
>>> what fsl,temp-calibration-offset-millicelsius should be set to? I could
>>> put a sensor on the SoC case and use the delta as offset, but then I
>>> would just account for the thermal resistance of the casing and not
>>> measure the SoC core temperature anymore, right?
>>
>> Hi Frieder,
>>
>> Thanks for pointing this out. Your understanding is correct: after
>> applying the offset, the reported value no longer represents the raw
>> SoC die or junction temperature.
>>
>> For this board, the required "SoC temperature" is the package-surface
>> temperature. The offset was derived by comparing the TEMPMON reading
>> against a calibrated external sensor placed near the SoC package
>> surface under steady-state thermal conditions, and is used to
>> approximate the package-surface temperature from the internal TEMPMON
>> reading.
>>
>> The Linux thermal framework does not require a thermal zone to use a
>> specific temperature reference. It only requires the reported
>> temperature and trip points to use the same temperature domain.
>>
>> In this driver, the offset is added in get_temp() and subtracted in
>> set_alarm() and set_panic() when programming the hardware thresholds.
>> This keeps the reported temperature and trip points in the same
>> package-surface temperature domain. Doing this in the driver is
>> necessary because the hardware alarm thresholds must also be offset-
>> corrected; applying the offset only in userspace would cause the
>> TEMPMON IRQ to fire at the wrong die temperature.
>>
>> I agree that "calibration offset" is misleading, since this does not
>> calibrate TEMPMON to a more accurate junction temperature. In the next
>> revision, the commit messages and DT binding have been updated to
>> describe this as a board-specific conversion offset from the internal
>> sensor reading to an estimated package-surface temperature.
>>
>> Thanks,
>> Haoning
> Hi Frieder,
>
> I need to correct my previous reply. After further discussion with our hardware team, the offset does NOT convert die temperature to package-surface temperature.
>
> Their thermal characterization shows that the raw TEMPMON sensor reading itself deviates from the theoretical junction temperature - this deviation exists even at the die level, before any board or package influence. The offset corrects the sensor reading toward the actual junction temperature, so it is a genuine sensor calibration.
>
> Board-level effects may contribute additionally, but they are not the primary reason for this feature. I apologize for the confusion - my earlier description was inaccurate. The v10 series reflects this corrected understanding.
Thanks for the update. If that is the case, then I would still be
interested to know:
1. How is the value for fsl,temp-calibration-offset-millicelsius
determined, if it is not provided by the SoC vendor.
2. Why do we need an additional offset, if there is already a
calibration using the value that NXP stores in the OTPs.
3. Who is supposed to set this property and where does it belong? The
SoC dtsi, the board dts?
Thanks
Frieder
^ permalink raw reply
* Re: [PATCH 2/3] usb: typec: Add Hynetek HUSB320 Type-C controller driver
From: sashiko-bot @ 2026-07-20 8:32 UTC (permalink / raw)
To: Hongyang Zhao; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260720-husb320-v1-2-4a1e259d7dc8@163.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Masking interrupt status bits before Write-1-to-Clear (W1C) clearing causes unhandled or reserved interrupts to remain asserted, leading to an interrupt storm.
- [Medium] The driver incorrectly reports the power role as TYPEC_SOURCE when connected to a Charge-Through Audio Accessory.
--
--- Patch [2]: [PATCH 2/3] usb: typec: Add Hynetek HUSB320 Type-C controller driver ---
commit e0d1ae316e83fd4e771770397178a91c9673d5ac
Author: Hongyang Zhao <hongyang.zhao@163.com>
usb: typec: Add Hynetek HUSB320 Type-C controller driver
This commit adds a new USB Type-C controller driver for the Hynetek HUSB320.
The driver implements autonomous Configuration Channel handling, supporting
attach/detach detection, role switching, and accessory modes.
> diff --git a/drivers/usb/typec/husb320.c b/drivers/usb/typec/husb320.c
> new file mode 100644
> index 0000000000000..fd9f949d9b522
> --- /dev/null
> +++ b/drivers/usb/typec/husb320.c
[ ... ]
> +static enum husb320_state husb320_get_state(unsigned int status,
> + unsigned int type)
> +{
> + if (!(status & HUSB320_STATUS_ATTACHED))
> + return HUSB320_STATE_UNATTACHED;
> +
> + if (type & HUSB320_TYPE_DEBUG_SOURCE)
> + return HUSB320_STATE_DEBUG_SOURCE;
> + if (type & HUSB320_TYPE_DEBUG_SINK)
> + return HUSB320_STATE_DEBUG_SINK;
> + if (type & HUSB320_TYPE_SINK)
> + return HUSB320_STATE_SINK;
> + if (type & HUSB320_TYPE_SOURCE)
> + return HUSB320_STATE_SOURCE;
> + if (type & (HUSB320_TYPE_AUDIO_VBUS | HUSB320_TYPE_AUDIO))
> + return HUSB320_STATE_AUDIO;
[Severity: Medium]
Does mapping HUSB320_TYPE_AUDIO_VBUS to HUSB320_STATE_AUDIO cause
charge-through accessories to be treated exactly the same as standard audio
accessories?
Since husb320_state_power_role() forces TYPEC_SOURCE for HUSB320_STATE_AUDIO,
would this result in incorrectly reporting the host as providing power when
it is actually receiving it?
> +
> + return HUSB320_STATE_UNATTACHED;
> +}
[ ... ]
> +static irqreturn_t husb320_irq_thread(int irq, void *data)
> +{
> + struct husb320 *husb = data;
> + unsigned int interrupt;
> + unsigned int interrupt1;
> + int disable_ret;
> + int ret;
> +
> + mutex_lock(&husb->lock);
> + if (husb->shutting_down) {
> + disable_irq_nosync(irq);
> + mutex_unlock(&husb->lock);
> + return IRQ_HANDLED;
> + }
> +
> + ret = regmap_read(husb->regmap, HUSB320_REG_INTERRUPT, &interrupt);
> + if (ret)
> + goto err;
> +
> + ret = regmap_read(husb->regmap, HUSB320_REG_INTERRUPT1, &interrupt1);
> + if (ret)
> + goto err;
> +
> + interrupt &= HUSB320_INT_VALID;
> + interrupt1 &= HUSB320_INT1_VALID;
> + if (!interrupt && !interrupt1) {
> + mutex_unlock(&husb->lock);
> + return IRQ_NONE;
> + }
> +
> + if (interrupt) {
> + ret = regmap_write(husb->regmap, HUSB320_REG_INTERRUPT,
> + interrupt);
[Severity: High]
If the hardware asserts a reserved or undocumented interrupt bit, will
masking the interrupt variable against HUSB320_INT_VALID prevent that bit
from being cleared when written back?
Could this cause an unhandled hardware interrupt to remain asserted,
leading to an interrupt storm that eventually forces the kernel to disable
the IRQ line?
> + if (ret)
> + goto err;
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720-husb320-v1-0-4a1e259d7dc8@163.com?part=2
^ permalink raw reply
* Re: [PATCH v6 5/6] arm64: dts: qcom: Add device tree for Nord Ride board
From: Konrad Dybcio @ 2026-07-20 8:40 UTC (permalink / raw)
To: Shawn Guo
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bartosz Golaszewski, Deepti Jaggi, devicetree,
linux-arm-msm, linux-kernel
In-Reply-To: <al2iDH2b_YxdHfLO@QCOM-aGQu4IUr3Y>
On 7/20/26 6:20 AM, Shawn Guo wrote:
> On Thu, Jul 16, 2026 at 07:14:56PM +0200, Konrad Dybcio wrote:
>> On 7/16/26 4:26 PM, Shawn Guo wrote:
>>> From: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
>>>
>>> Add initial device tree for the Qualcomm SA8797P Ride reference board,
>>> which is built on Nord GearVM variant.
[...]
>>> +&scmi15 {
>>> + status = "okay";
>>> +};
>>> +
>>> +&scmi23 {
>>> + status = "okay";
>>> +};
>>
>> Why only these ones? Can all of the SCMI servers be enabled?
>
> These are the ones that have actual/enabled client/consumer devices,
> e.g. scmi3 for ufs, scmi11 for uart, scmi23 for thermal sensors.
We normally refrain from enabling resources in the DT only because the
OS (really just Linux) doesn't have the necessary support to cope with
the ""complete"" system description. In this case, there's a firmware
layer drives everything and handles on/off requests gracefully
(hopefully).
> We can enable all the SCMI servers, but I'm afraid that cause kernel
> to map shared memory and issue SMC calls to discover protocols (like
> power domains, DVFS, resets) that have no consumers, which might waste
> a small amount of memory and boot time.
Please give it a shot and see if there's any immediate
problems.
Big SoC requires big init times. Thankfully it also happens to be
fast so it evens out. Maybe we can look into doing async probe for
the related drivers.
My understanding is that most of these SCMI servers are actually
already bound to managing some hardware (or will be in a fw update),
but not all of them have the drivers to utilize that yet. Is that
the case?
Konrad
^ permalink raw reply
* Re: [PATCH] arm64: dts: qcom: sm6125-xiaomi-ginkgo: Add vbus-supply in Type-C connector
From: Konrad Dybcio @ 2026-07-20 8:41 UTC (permalink / raw)
To: Biswapriyo Nath, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Dmitry Baryshkov, linux-arm-msm, devicetree, linux-kernel,
~postmarketos/upstreaming, phone-devel
In-Reply-To: <20260718-ginkgo-vbus-typec-v1-1-d5ed0aa6b78b@gmail.com>
On 7/18/26 5:21 PM, Biswapriyo Nath wrote:
> VBUS supply property was moved from pmi632 typec node to USB-C connector.
> This fixes the following warning in kernel message.
> pmic@2:typec@1500: supply vdd-vbus not found, using dummy regulator
>
> Fixes: c1da9374c3e0 ("arm64: dts: qcom: sm6125-xiaomi-ginkgo: Add PMI632 Type-C property")
> Signed-off-by: Biswapriyo Nath <nathbappai@gmail.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* [PATCH 0/3] drm/msm: Enable dual MDSS power domains
From: Yongxing Mou @ 2026-07-20 8:43 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Krishna Manikandan, Abel Vesa,
Yuanjie Yang, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
Yongxing Mou
Kaanapali (SM8750) and Glymur use two display power domains.
CORE_GDSC powers the main display hardware while INT2_GDSC powers
a subset of SSPP blocks.
The current MDSS implementation only manages the primary display
power domain. SSPPs backed by INT2_GDSC therefore remain inaccessible.
Add dual power-domain support to MDSS, update the DT bindings to
describe both domains, and add INT2_GDSC to the Kaanapali and Glymur
MDSS nodes.
Signed-off-by: Yongxing Mou <yongxing.mou@oss.qualcomm.com>
---
Yongxing Mou (3):
dt-bindings: display: msm: Allow two MDSS power domains
drm/msm/mdss: Enable INT2_GDSC alongside CORE_GDSC
arm64: dts: qcom: Add INT2_GDSC to MDSS on Kaanapali and Glymur
.../bindings/display/msm/mdss-common.yaml | 3 +-
.../bindings/display/msm/qcom,glymur-mdss.yaml | 13 +++++-
.../bindings/display/msm/qcom,kaanapali-mdss.yaml | 13 +++++-
arch/arm64/boot/dts/qcom/glymur.dtsi | 4 +-
arch/arm64/boot/dts/qcom/kaanapali.dtsi | 4 +-
drivers/gpu/drm/msm/msm_mdss.c | 53 +++++++++++++++++++++-
6 files changed, 84 insertions(+), 6 deletions(-)
---
base-commit: bee763d5f341b99cf472afeb508d4988f62a6ca1
change-id: 20260720-msm_gdsc2-cb9230027a2d
Best regards,
--
Yongxing Mou <yongxing.mou@oss.qualcomm.com>
^ permalink raw reply
* [PATCH 1/3] dt-bindings: display: msm: Allow two MDSS power domains
From: Yongxing Mou @ 2026-07-20 8:43 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Krishna Manikandan, Abel Vesa,
Yuanjie Yang, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
Yongxing Mou
In-Reply-To: <20260720-msm_gdsc2-v1-0-4687866d6cb0@oss.qualcomm.com>
Kaanapali (SM8750) and Glymur use two display power domains.
CORE_GDSC powers the main display hardware while INT2_GDSC
powers a subset of SSPP blocks.
Allow the MDSS bindings to describe both power domains and
their corresponding power-domain-names values.
Signed-off-by: Yongxing Mou <yongxing.mou@oss.qualcomm.com>
---
.../devicetree/bindings/display/msm/mdss-common.yaml | 3 ++-
.../devicetree/bindings/display/msm/qcom,glymur-mdss.yaml | 13 ++++++++++++-
.../bindings/display/msm/qcom,kaanapali-mdss.yaml | 13 ++++++++++++-
3 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
index c6305a6e0334..c0b650ffd9ef 100644
--- a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
+++ b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
@@ -31,7 +31,8 @@ properties:
const: mdss
power-domains:
- maxItems: 1
+ minItems: 1
+ maxItems: 2
clocks:
minItems: 2
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml
index 64dde43373ac..685bedb26a12 100644
--- a/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml
+++ b/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml
@@ -38,6 +38,16 @@ properties:
- const: mdp0-mem
- const: cpu-cfg
+ power-domains:
+ items:
+ - description: MDSS core GDSC power domain
+ - description: MDSS INT2 GDSC power domain
+
+ power-domain-names:
+ items:
+ - const: core
+ - const: int2
+
patternProperties:
"^display-controller@[0-9a-f]+$":
type: object
@@ -95,7 +105,8 @@ examples:
resets = <&disp_cc_mdss_core_bcr>;
- power-domains = <&mdss_gdsc>;
+ power-domains = <&mdss_gdsc>, <&mdss_int2_gdsc>;
+ power-domain-names = "core", "int2";
iommus = <&apps_smmu 0x1c00 0x2>;
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml
index 9f935defd6b1..088010f464c3 100644
--- a/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml
+++ b/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml
@@ -40,6 +40,16 @@ properties:
- const: mdp0-mem
- const: cpu-cfg
+ power-domains:
+ items:
+ - description: MDSS core GDSC power domain
+ - description: MDSS INT2 GDSC power domain
+
+ power-domain-names:
+ items:
+ - const: core
+ - const: int2
+
patternProperties:
"^display-controller@[0-9a-f]+$":
type: object
@@ -89,7 +99,8 @@ examples:
<&disp_cc_mdss_ahb_swi_clk>;
resets = <&disp_cc_mdss_core_bcr>;
- power-domains = <&mdss_gdsc>;
+ power-domains = <&mdss_gdsc>, <&mdss_int2_gdsc>;
+ power-domain-names = "core", "int2";
iommus = <&apps_smmu 0x800 0x2>;
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] drm/msm/mdss: Enable INT2_GDSC alongside CORE_GDSC
From: Yongxing Mou @ 2026-07-20 8:43 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Krishna Manikandan, Abel Vesa,
Yuanjie Yang, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
Yongxing Mou
In-Reply-To: <20260720-msm_gdsc2-v1-0-4687866d6cb0@oss.qualcomm.com>
Kaanapali (SM8750) and Glymur use two display power domains.
CORE_GDSC powers the main display hardware while INT2_GDSC powers
a subset of SSPP blocks (VIG2/VIG3/DMA5/DMA6).
The MDSS driver currently relies on the default runtime PM handling
and does not enable the secondary INT2_GDSC. As a result, display
pipes backed by INT2_GDSC remain inaccessible.
Attach and manage both power domains explicitly and enable them
during MDSS runtime PM activation.
Signed-off-by: Yongxing Mou <yongxing.mou@oss.qualcomm.com>
---
drivers/gpu/drm/msm/msm_mdss.c | 53 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c
index 9087c4b290db..63ece55c4f2e 100644
--- a/drivers/gpu/drm/msm/msm_mdss.c
+++ b/drivers/gpu/drm/msm/msm_mdss.c
@@ -13,6 +13,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -44,6 +45,7 @@ struct msm_mdss {
struct icc_path *mdp_path[2];
u32 num_mdp_paths;
struct icc_path *reg_bus_path;
+ struct dev_pm_domain_list *pd_list;
};
static int msm_mdss_parse_data_bus_icc_path(struct device *dev,
@@ -233,6 +235,21 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss)
int ret, i;
u32 hw_rev;
+ /*
+ * Platforms with two power domains (e.g. Kaanapali, Glymur) need both
+ * GDSCs enabled explicitly; the core framework only auto-attaches a
+ * single power domain.
+ */
+ if (msm_mdss->pd_list) {
+ ret = pm_runtime_resume_and_get(msm_mdss->pd_list->pd_devs[0]);
+ if (ret < 0)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(msm_mdss->pd_list->pd_devs[1]);
+ if (ret < 0)
+ goto err_put_core;
+ }
+
/*
* Several components have AXI clocks that can only be turned on if
* the interconnect is enabled (non-zero bandwidth). Let's make sure
@@ -255,7 +272,7 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss)
ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks);
if (ret) {
dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret);
- return ret;
+ goto err_put_int2;
}
/*
@@ -276,6 +293,14 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss)
/* else UBWC 1.0 or none, no params to program */
return ret;
+
+err_put_int2:
+ if (msm_mdss->pd_list)
+ pm_runtime_put_sync(msm_mdss->pd_list->pd_devs[1]);
+err_put_core:
+ if (msm_mdss->pd_list)
+ pm_runtime_put_sync(msm_mdss->pd_list->pd_devs[0]);
+ return ret;
}
static int msm_mdss_disable(struct msm_mdss *msm_mdss)
@@ -290,6 +315,11 @@ static int msm_mdss_disable(struct msm_mdss *msm_mdss)
if (msm_mdss->reg_bus_path)
icc_set_bw(msm_mdss->reg_bus_path, 0, 0);
+ if (msm_mdss->pd_list) {
+ pm_runtime_put_sync(msm_mdss->pd_list->pd_devs[1]);
+ pm_runtime_put_sync(msm_mdss->pd_list->pd_devs[0]);
+ }
+
return 0;
}
@@ -421,6 +451,27 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5
irq_set_chained_handler_and_data(irq, msm_mdss_irq,
msm_mdss);
+ /*
+ * When two power domains are listed in DT, the core framework does not
+ * auto-attach either of them. Attach and manage both explicitly so
+ * that INT2_GDSC (needed for VIG2/VIG3) is enabled alongside the main
+ * CORE_GDSC. Single-domain platforms are unaffected.
+ */
+ if (of_count_phandle_with_args(pdev->dev.of_node, "power-domains",
+ "#power-domain-cells") > 1) {
+ static const char * const mdss_pd_names[] = { "core", "int2" };
+ static const struct dev_pm_domain_attach_data pd_data = {
+ .pd_names = mdss_pd_names,
+ .num_pd_names = ARRAY_SIZE(mdss_pd_names),
+ .pd_flags = PD_FLAG_NO_DEV_LINK,
+ };
+
+ ret = devm_pm_domain_attach_list(&pdev->dev, &pd_data,
+ &msm_mdss->pd_list);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ }
+
pm_runtime_enable(&pdev->dev);
return msm_mdss;
--
2.43.0
^ permalink raw reply related
* [PATCH 3/3] arm64: dts: qcom: Add INT2_GDSC to MDSS on Kaanapali and Glymur
From: Yongxing Mou @ 2026-07-20 8:43 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Krishna Manikandan, Abel Vesa,
Yuanjie Yang, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
Yongxing Mou
In-Reply-To: <20260720-msm_gdsc2-v1-0-4687866d6cb0@oss.qualcomm.com>
Kaanapali (SM8750) and Glymur use two display power domains.
CORE_GDSC powers the main display hardware while INT2_GDSC powers
a subset of SSPP blocks (VIG2/VIG3/DMA5/DMA6).
Add DISP_CC_MDSS_CORE_INT2_GDSC alongside the existing CORE_GDSC
reference in the MDSS node on both platforms and provide matching
power-domain-names entries for the display power domains.
Signed-off-by: Yongxing Mou <yongxing.mou@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/glymur.dtsi | 4 +++-
arch/arm64/boot/dts/qcom/kaanapali.dtsi | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
index dd80da14ab10..1e447c1d69f7 100644
--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
+++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
@@ -4898,7 +4898,9 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
interconnect-names = "mdp0-mem",
"cpu-cfg";
- power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
+ power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>,
+ <&dispcc DISP_CC_MDSS_CORE_INT2_GDSC>;
+ power-domain-names = "core", "int2";
iommus = <&apps_smmu 0x1de0 0x2>;
diff --git a/arch/arm64/boot/dts/qcom/kaanapali.dtsi b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
index ace19b8b12d7..ae851adec5a6 100644
--- a/arch/arm64/boot/dts/qcom/kaanapali.dtsi
+++ b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
@@ -3581,7 +3581,9 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
interconnect-names = "mdp0-mem",
"cpu-cfg";
- power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
+ power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>,
+ <&dispcc DISP_CC_MDSS_CORE_INT2_GDSC>;
+ power-domain-names = "core", "int2";
iommus = <&apps_smmu 0x800 0x2>;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 2/2] arm64: dts: qcom: milos: Add CPU-to-DDR BWMON support
From: Konrad Dybcio @ 2026-07-20 8:48 UTC (permalink / raw)
To: Luca Weiss, Krzysztof Kozlowski, Georgi Djakov, Rob Herring,
Conor Dooley, Bjorn Andersson, Konrad Dybcio, Krzysztof Kozlowski
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm, linux-pm,
devicetree, linux-kernel
In-Reply-To: <20260717-milos-cpu-bwmon-v1-2-dfe0bac9898c@fairphone.com>
On 7/17/26 1:45 PM, Luca Weiss wrote:
> Add a node for the CPU-to-DDR BWMON on the Milos SoC and the
> corresponding OPP table.
>
> Currently, the table is for DDR5, the values for DDR4 are put into a
> TODO comment, until the kernel can differentiate between DDR variants.
>
> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: display: msm: Allow two MDSS power domains
From: Konrad Dybcio @ 2026-07-20 8:49 UTC (permalink / raw)
To: Yongxing Mou, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Krishna Manikandan, Abel Vesa, Yuanjie Yang, Bjorn Andersson,
Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel
In-Reply-To: <20260720-msm_gdsc2-v1-1-4687866d6cb0@oss.qualcomm.com>
On 7/20/26 10:43 AM, Yongxing Mou wrote:
> Kaanapali (SM8750) and Glymur use two display power domains.
> CORE_GDSC powers the main display hardware while INT2_GDSC
> powers a subset of SSPP blocks.
Can they operate independently? Does INT2_GDSC need to be
powered on after CORE_GDSC?
If so, perhaps changing the clock driver to make CORE a parent
of INT2 could be the simpler solution
Konrad
^ permalink raw reply
* Re: [PATCH v5 01/17] spi: dt-bindings: add spi-max-post-config-frequency-hz property
From: Santhosh Kumar K @ 2026-07-20 8:48 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: broonie, robh, krzk+dt, conor+dt, miquel.raynal, richard,
vigneshr, pratyush, mwalle, takahiro.kuwano, linux-spi,
devicetree, linux-kernel, linux-mtd, praneeth, u-kumar1, a-dutta,
Conor Dooley, s-k6
In-Reply-To: <fba1531e-e416-4817-848e-94e9b3f3b501@kernel.org>
On 20/07/26 13:10, Krzysztof Kozlowski wrote:
> On 20/07/2026 09:38, Santhosh Kumar K wrote:
>>>> diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
>>>> index 880a9f624566..12211f8c9f7d 100644
>>>> --- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
>>>> +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
>>>> @@ -45,6 +45,11 @@ properties:
>>>> description:
>>>> Maximum SPI clocking speed of the device in Hz.
>>>>
>>>> + spi-max-post-config-frequency-hz:
>>>> + description:
>>>> + Maximum SPI clock frequency in Hz achievable after controller-side
>>>> + configuration.
>>>
>>> How did you implement my feedback?
>>
>> Three points from your feedback:
>>
>> 1. -hz suffix: added
>>
>> 2. Array property: I still lean towards keeping this as a scalar for
>> now, as we don't have a concrete use case for multiple values today, and
>> supporting two frequencies should be sufficient for the foreseeable
>> future. I had responded to this in the v4 discussion as well, you may
>> have missed that response.
>>
>> 3. maxItems: Since the property remains a scalar, I have not added maxItems.
>
> So how did you make this property scalar?
The -hz suffix constraints the property to a uint32 scalar through the
DT schema framework's property-units.yaml.
Adding an explicit $ref or maxItems for a unit-suffixed property is
rejected by dtbs_check with:
- "Standard unit suffix properties don't need a type $ref"
- "Scalar properties should not have array keywords"
Thanks,
Santhosh.
>
> Best regards,
> Krzysztof
^ permalink raw reply
* Re: [PATCH 5/5] soc: qcom: ubwc: Add Kalambo UBWC config
From: Konrad Dybcio @ 2026-07-20 8:52 UTC (permalink / raw)
To: Gopikrishna Garmidi, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sibi Sankar, Pankaj Patil
Cc: Rajendra Nayak, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260718-b4-kalambo-crd-v1-5-a1069b5a2757@oss.qualcomm.com>
On 7/18/26 2:06 PM, Gopikrishna Garmidi wrote:
> Qualcomm Kalambo is a derivative of the Mahua SoC and shares the same
> Universal Bandwidth Compression (UBWC) configuration. Add the Kalambo
> compatible to the UBWC configuration table to enable support.
>
> Signed-off-by: Gopikrishna Garmidi <gopikrishna.garmidi@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH 4/5] firmware: qcom: scm: Allow QSEECOM on Kalambo CRD
From: Konrad Dybcio @ 2026-07-20 8:52 UTC (permalink / raw)
To: Gopikrishna Garmidi, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sibi Sankar, Pankaj Patil
Cc: Rajendra Nayak, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260718-b4-kalambo-crd-v1-4-a1069b5a2757@oss.qualcomm.com>
On 7/18/26 2:06 PM, Gopikrishna Garmidi wrote:
> Add Kalambo CRD board to the QSEECOM allowlist for enabling access to
> efivars.
>
> Signed-off-by: Gopikrishna Garmidi <gopikrishna.garmidi@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: display: msm: Allow two MDSS power domains
From: sashiko-bot @ 2026-07-20 8:54 UTC (permalink / raw)
To: Yongxing Mou; +Cc: conor+dt, devicetree, robh, dri-devel
In-Reply-To: <20260720-msm_gdsc2-v1-1-4687866d6cb0@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] Relaxing the global maximum number of `power-domains` in `mdss-common.yaml` without restricting legacy schemas allows invalid device trees to pass validation.
- [Medium] Missing `power-domain-names` in the `required` list allows incomplete device trees to pass validation.
- [Medium] Adding an items array to `power-domains` implicitly sets `minItems: 2`, breaking backward compatibility for existing device trees.
--
--- Patch [1]: [PATCH 1/3] dt-bindings: display: msm: Allow two MDSS power domains ---
commit 3afe59087bba460fdef9d8666ba4cb4a97273b44
Author: Yongxing Mou <yongxing.mou@oss.qualcomm.com>
dt-bindings: display: msm: Allow two MDSS power domains
Kaanapali (SM8750) and Glymur use two display power domains.
CORE_GDSC powers the main display hardware while INT2_GDSC
powers a subset of SSPP blocks.
Allow the MDSS bindings to describe both power domains and
their corresponding power-domain-names values.
> diff --git a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
> index c6305a6e03346..c0b650ffd9ef8 100644
> --- a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
> @@ -31,7 +31,8 @@ properties:
> const: mdss
>
> power-domains:
> - maxItems: 1
> + minItems: 1
> + maxItems: 2
[Severity: Medium]
When we relax the global maximum number of power-domains here, does this allow
invalid device trees to pass validation for legacy platforms?
For example, schemas like qcom,sm8550-mdss.yaml include this common schema
but only have 1 hardware power domain. Without explicitly overriding
maxItems to 1 in those legacy schemas, they might silently accept invalid
device trees with 2 power domains.
>
> clocks:
> minItems: 2
> diff --git a/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml
> index 64dde43373ac7..685bedb26a124 100644
> --- a/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/qcom,glymur-mdss.yaml
[ ... ]
> @@ -38,6 +38,16 @@ properties:
> - const: mdp0-mem
> - const: cpu-cfg
>
> + power-domains:
> + items:
> + - description: MDSS core GDSC power domain
> + - description: MDSS INT2 GDSC power domain
[Severity: Medium]
Does adding this items array implicitly set minItems to 2 during dt-schema
evaluation?
If so, this might break backward compatibility for older device trees that
only specify a single power domain. Should minItems: 1 be explicitly
specified here?
> +
> + power-domain-names:
> + items:
> + - const: core
> + - const: int2
[Severity: Medium]
If a device tree specifies 2 power domains but omits power-domain-names,
will it pass schema validation?
The driver might fail to probe at runtime when attempting to attach power
domains by name. Should power-domain-names be conditionally required in the
required list (using an if-then block) when multiple power domains are
provided?
> +
> patternProperties:
> "^display-controller@[0-9a-f]+$":
> type: object
> diff --git a/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml
> index 9f935defd6b12..088010f464c3d 100644
> --- a/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/qcom,kaanapali-mdss.yaml
[ ... ]
> @@ -40,6 +40,16 @@ properties:
> - const: mdp0-mem
> - const: cpu-cfg
>
> + power-domains:
> + items:
> + - description: MDSS core GDSC power domain
> + - description: MDSS INT2 GDSC power domain
[Severity: Medium]
Similar to the glymur binding, does this items array implicitly set minItems
to 2 and break backward compatibility?
> +
> + power-domain-names:
> + items:
> + - const: core
> + - const: int2
[Severity: Medium]
Also similar to the glymur binding, should power-domain-names be conditionally
required to ensure device trees with two power domains provide the necessary
names for the driver?
> +
> patternProperties:
> "^display-controller@[0-9a-f]+$":
> type: object
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720-msm_gdsc2-v1-0-4687866d6cb0@oss.qualcomm.com?part=1
^ permalink raw reply
* Re: [PATCH v5 06/11] Bluetooth: hci_qca: Set 'bt_en_available' based on pwrseq power controllability
From: Bartosz Golaszewski @ 2026-07-20 8:57 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Manivannan Sadhasivam,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
In-Reply-To: <20260720-monza-wireless-v5-6-69ec6743543c@oss.qualcomm.com>
On Mon, 20 Jul 2026 10:04:08 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> A Bluetooth device only needs the non-persistent setup if the host can
> gate its power, so that it is actually reset on the next power-on. When the
> power is controlled by a power sequencer, whether the host can gate it
> depends on the hardware wiring, e.g. the presence of the BT_EN or
> W_DISABLE2# line.
>
> Query the generic pwrseq_is_controllable() helper whenever the BT power
> comes from a sequencer, regardless of which provider it is (M2, WCN, ...).
> If the power is not controllable, clear 'bt_en_available' so that
> HCI_QUIRK_NON_PERSISTENT_SETUP is not set.
>
> This is based on Manivannan's original patch that keyed the decision off
> the W_DISABLE2# device tree property, it now uses the generic pwrseq helper
> and handles the always-on case.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v5 08/11] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
From: Bartosz Golaszewski @ 2026-07-20 8:57 UTC (permalink / raw)
To: Loic Poulain
Cc: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
In-Reply-To: <20260720-monza-wireless-v5-8-69ec6743543c@oss.qualcomm.com>
On Mon, 20 Jul 2026 10:04:10 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable is
> controlled by the W_DISABLE2# signal managed by the pcie-m2 power sequencer
> rather than a dedicated BT enable GPIO.
>
> When the serdev controller has an OF graph (indicating it is connected to
> an M.2 connector), acquire the 'uart' pwrseq target from the connector's
> power sequencer and use it to control BT power instead of the bt-enable
> GPIO. This is factored out into qca_serdev_get_m2_pwrseq().
>
> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH 2/5] arm64: dts: qcom: Add Kalambo SoC
From: Konrad Dybcio @ 2026-07-20 8:57 UTC (permalink / raw)
To: Gopikrishna Garmidi, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sibi Sankar, Pankaj Patil
Cc: Rajendra Nayak, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260718-b4-kalambo-crd-v1-2-a1069b5a2757@oss.qualcomm.com>
On 7/18/26 2:06 PM, Gopikrishna Garmidi wrote:
> Introduce support for the Qualcomm Kalambo SoC. It is derived from Mahua
> with CPU cluster 0 removed, leaving it with just cluster 1. As a result,
> the PDP mailbox and SCP low-priority register windows are updated to
> match the reduced CPU complex. Everything else should work as-is.
>
> Add a label to the Glymur cluster0 cpu-map node to allow its removal on
> derived SoCs.
>
> Signed-off-by: Gopikrishna Garmidi <gopikrishna.garmidi@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/glymur.dtsi | 2 +-
> arch/arm64/boot/dts/qcom/kalambo.dtsi | 29 +++++++++++++++++++++++++++++
> 2 files changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
> index 55d91c696a3a..f2feef362be5 100644
> --- a/arch/arm64/boot/dts/qcom/glymur.dtsi
> +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
> @@ -275,7 +275,7 @@ cpu17: cpu@20500 {
> };
>
> cpu-map {
> - cluster0 {
> + cpu_map_cluster0: cluster0 {
I doubt the code that parses this will be happy about not
being able to start from 'cluster0'
[...]
> +&pdp0_mbox {
> + reg = <0 0x17610000 0 0x8000>, <0 0x1a980000 0 0x8000>;
> +};
Are you sure about this change?
> +&cpu_scp_lpri1 {
> + reg = <0x180 0x60>;
> +};
This is specific to old firmware, at least it was on Glymur, I believe..
Konrad
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox