From 726235eb79723f647473567af8d6f75555e2f2be Mon Sep 17 00:00:00 2001 From: "Sodhi, Vunny" Date: Thu, 27 Aug 2026 10:25:38 +0800 Subject: [PATCH 01/17] Add OV13B10 direct MIPI camera support Register the OV13B10 ACPI HID and sensor model for direct-MIPI discovery. Use the sensor active format when configuring direct-MIPI capture, and add OV13B10 entity handling to format propagation. Signed-off-by: Sodhi, Vunny --- script/acpi/mc-setup.sh | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index c0afe0d9..ba8794cc 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -33,6 +33,7 @@ # Known sensor / SerDes HIDs: # INTC10CD = D4XX camera (entity prefixes: "DS5 mux", "D4XX depth/rgb/ir/imu") # INTC113C = ISX031 camera (entity prefix: "isx031") +# OVTI13B1 = OV13B10 camera (entity prefix: "ov13b10") # INTC1138 = MAX9295 / MAX96717 serializer (entity prefix: "max96717") # INTC1137 = MAX9296A deserializer (entity prefix: "max9296a") # INTC1139 = MAX96724 deserializer (entity prefix: "max96724") @@ -84,16 +85,19 @@ declare -A SENSOR_MODEL=( [INTC10CD]=d4xx [INTC113C]=isx031 [INTC10C0]=ar0234 + [OVTI13B1]=ov13b10 ) declare -A SENSOR_PREFIX=( [INTC10CD]="DS5 mux" [INTC113C]="isx031" [INTC10C0]="ar0234" + [OVTI13B1]="ov13b10" ) # ---- Direct MIPI sensor HIDs (no GMSL deserializer) ------------------------ declare -A MIPI_SENSOR_HID=( [INTC113C]=isx031 + [OVTI13B1]=ov13b10 ) # ---- Serializer / Deserializer HID -> v4l entity prefix --------------------- @@ -119,11 +123,13 @@ declare -A MODEL_STREAMS=( [d4xx]="depth rgb ir imu" [isx031]="yuv" [ar0234]="raw" + [ov13b10]="raw" ) declare -A MODEL_DEFAULT_STREAMS=( [d4xx]="depth rgb" [isx031]="yuv" [ar0234]="raw" + [ov13b10]="raw" ) # STREAM_NODE: per-stream capture-node index (also used as the v4l2 @@ -491,15 +497,16 @@ detect_mipi_csi2() { setup_mipi_cameras() { [ "$NUM_MIPI" -eq 0 ] && return 0 echo -e "\nConfiguring direct MIPI cameras..." - local i model cam csi2 node fmt size s pixfmt w h ipu + local i model cam csi2 node fmt size s pixfmt w h ipu detected for ((i = 0; i < NUM_MIPI; i++)); do model=${MIPI_MODEL[$i]} cam=${MIPI_BA[$i]} csi2=${MIPI_CSI2[$i]} node=${MIPI_CAP[$i]} for s in ${MODEL_DEFAULT_STREAMS[$model]}; do - fmt=${STREAM_FMT[$s]} - size=${STREAM_SIZE[$s]} + detected=$(sensor_active_format "$model" "$cam" "$s" "${STREAM_NODE[$s]}") || \ + die "cannot read active format from ${model} camera ${cam}" + read -r fmt size <<<"$detected" break done echo " ${MIPI_PREFIX[$i]} $cam -> $csi2 -> /dev/video$node ($fmt/$size)" @@ -636,6 +643,8 @@ sensor_entity_pad() { case "$model" in d4xx) SENSOR_ENTITY="D4XX ${stream} ${cam}"; SENSOR_PAD=0; SENSOR_SID=0 ;; isx031) SENSOR_ENTITY="isx031 ${cam}"; SENSOR_PAD=0; SENSOR_SID=$sid ;; + ar0234) SENSOR_ENTITY="ar0234 ${cam}"; SENSOR_PAD=0; SENSOR_SID=$sid ;; + ov13b10) SENSOR_ENTITY="ov13b10 ${cam}"; SENSOR_PAD=0; SENSOR_SID=0 ;; *) return 1 ;; esac } @@ -1259,6 +1268,9 @@ for k in "${!CFG_LINKS[@]}"; do ar0234) mc_v "\"ar0234 ${cam}\":0/${sid} [fmt:${fmt}/${size} field:none]" ;; + ov13b10) + mc_v "\"ov13b10 ${cam}\":0/${sid} [fmt:${fmt}/${size} field:none]" + ;; esac fps=${CFG_STREAM_FPS["${k}_${s}"]} if [ -n "${CFG_STREAM_FPS_APPLY["${k}_${s}"]:-}" ] && From 6d0a359fe9c901eabe308cf30300176060298a6a Mon Sep 17 00:00:00 2001 From: "Sodhi, Vunny" Date: Thu, 27 Aug 2026 11:58:50 +0800 Subject: [PATCH 02/17] acpi: ipu7: add direct MIPI OV13B10 camera SSDT overlay Add SSDT overlay for dual OV13B10 sensors on IPU75XA IPU7 platform: - CAM0: I2C1, MIPI port 0, 4 lanes, reset GPIO pin 10 (COM1 C_D_E_H pad 10) - CAM1: I2C2, MIPI port 2, 2 lanes, reset GPIO pin 1 (COM1 C_D_E_H pad 1) Use OV13B10 common include for direct MIPI camera resources and device properties, aligned with existing direct-MIPI camera overlays. Signed-off-by: Sodhi, Vunny --- acpi/ipu7/_mipi_cam_common_ov13b10.asl | 132 +++++++++++++++++++++++++ acpi/ipu7/mipi_ov13b10.asl | 110 +++++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 acpi/ipu7/_mipi_cam_common_ov13b10.asl create mode 100644 acpi/ipu7/mipi_ov13b10.asl diff --git a/acpi/ipu7/_mipi_cam_common_ov13b10.asl b/acpi/ipu7/_mipi_cam_common_ov13b10.asl new file mode 100644 index 00000000..f99401eb --- /dev/null +++ b/acpi/ipu7/_mipi_cam_common_ov13b10.asl @@ -0,0 +1,132 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2026 Intel Corporation. + * + * Description: Common template for a direct MIPI CSI-2 OV13B10 camera device. + * This include provides the body of a CAMx device for native MIPI. + * + * CAM-level defines expected by caller: + * CAM_I2C_BUS - Camera I2C bus path (e.g. "\\_SB.PC00.I2C1") + * CAM_I2C_ADDR - Camera I2C slave address (e.g. 0x0010) + * CAM_TO_MIPI_PORT - Connected IPU MIPI port index (e.g. 0, 1, 2) + * CAM_LANES - Number of MIPI data lanes (e.g. 2, 4) + * CAM_RESET_GPIO_CTLR - GPIO controller path for RESET (e.g. "\\_SB.GPI1") + * CAM_POWER_GPIO_CTLR - GPIO controller path for POWER_EN (e.g. "\\_SB.GPI0") + * CAM_RESET_PIN - GPIO pin number for RESET + * CAM_POWER_PIN - GPIO pin number for POWER_EN + * CAM_RESET_GPIORSC - GPIO resource index used by reset-gpios: + * 0 = first GpioIo (_CRS RESET), 1 = second GpioIo (_CRS POWER_EN) + * CAM_RESET_ACTIVE_LOW - RESET GPIO polarity (1: active low, 0: active high) + * CAM_IPU_PATH - IPU path string (e.g. "\\_SB.PC00.IPU0") + * CAM_IPU_REF - IPU namespace reference (e.g. \_SB.PC00.IPU0) + * CAM_GPIO_REF - Device self-reference for reset-gpios (e.g. ^CAM0) + */ +Method (_STA, 0, NotSerialized) // _STA: Status +{ + Return (0x0F) +} + +Method (_HID, 0, NotSerialized) // _HID: Hardware ID +{ + Return ("OVTI13B1") // OV13B10 +} + +Name (_DEP, Package (0x01) // _DEP: Dependencies +{ + CAM_IPU_REF +}) + +Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings +{ + /* + * mipi-disco-img.c will use the information in CSI2Bus to create fwnode. + * CAMx Local Port -> IPU Remote Port + * CAMx PRT0 -> IPU PRTx (selected by CAM_TO_MIPI_PORT) + */ + CSI2Bus( + DeviceInitiated, // SlaveMode + 1, // PhyType (1 for DPHY) + 0, // LocalPort (sensor local port) + CAM_IPU_PATH, // ResourceSource (Path to IPU) + CAM_TO_MIPI_PORT, // ResourceSourceIndex (IPU PRTx) + , // ResourceUsage + , // DescriptorName + ) // VendorData + + I2cSerialBusV2 ( + CAM_I2C_ADDR, // SlaveAddress + ControllerInitiated, // SlaveMode + 400000, // I2C ConnectionSpeed + AddressingMode7Bit, // AddressingMode + CAM_I2C_BUS, // ResourceSource + 0x00, // ResourceSourceIndex + ResourceConsumer, // ResourceUsage + , // DescriptorName + Exclusive, // Shared + ) // VendorData + + /* GPIO for sensor RESET (directly from SoC GPIO controller) */ + GpioIo ( + Exclusive, // Shared (Not shared) + PullNone, // PinConfig (No need for pulls) + 0, // DebounceTimeout + 0, // DriveStrength + IoRestrictionOutputOnly,// IoRestriction (Only used as output) + CAM_RESET_GPIO_CTLR, // ResourceSource (GPIO controller) + 0) // ResourceSourceIndex (Must be 0) + { + CAM_RESET_PIN // Pin number + } + + /* GPIO for sensor POWER_EN (optional rail control) */ + GpioIo ( + Exclusive, + PullNone, + 0, + 0, + IoRestrictionOutputOnly, + CAM_POWER_GPIO_CTLR, + 0) + { + CAM_POWER_PIN // Pin number + } +}) + +Name (_DSD, Package () // _DSD: Device-Specific Data +{ + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), // Device Properties + Package () + { + Package () { "mipi-img-clock-frequency", 19200000 }, // 19.2 MHz + /* + * reset-gpios: used by ov13b10.c driver via + * devm_gpiod_get_optional(dev, "reset", ...) + * Format: { , , , } + * resource_index maps to _CRS GpioIo order: 0=RESET, 1=POWER_EN. + */ + Package () { "reset-gpios", Package () { CAM_GPIO_REF, CAM_RESET_GPIORSC, 0, CAM_RESET_ACTIVE_LOW } }, + }, + ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), // Hierarchical Data Extension + Package () + { + /* mipi-img-port here is local camera port used by mipi-disco-img.c. */ + Package () { "mipi-img-port-0", "PRT0" }, + }, +}) + +Name (PRT0, Package () +{ + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), // Device Properties + Package () + { + Package () { "mipi-img-clock-lane", 0 }, +#if CAM_LANES == 4 + Package () { "mipi-img-data-lanes", Package () { 1, 2, 3, 4 } }, +#elif CAM_LANES == 2 + Package () { "mipi-img-data-lanes", Package () { 1, 2 } }, +#else + Package () { "mipi-img-data-lanes", Package () { 1, 2, 3, 4 } }, +#endif + Package () { "mipi-img-link-frequencies", Package () { 560000000 } }, + }, +}) diff --git a/acpi/ipu7/mipi_ov13b10.asl b/acpi/ipu7/mipi_ov13b10.asl new file mode 100644 index 00000000..a6685fe9 --- /dev/null +++ b/acpi/ipu7/mipi_ov13b10.asl @@ -0,0 +1,110 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2026 Intel Corporation. + * + * SSDT overlay: Direct MIPI CSI-2 OV13B10 camera configuration on PTL platform. + * + * This overlay describes a native MIPI-connected OV13B10 sensor (no GMSL SERDES). + * Adjust the CAM_* defines below to match your hardware wiring. + * + * CAM-level defines (set per CAMx, see _mipi_cam_common_ov13b10.asl): + * CAM_I2C_BUS - Camera I2C bus path (e.g. "\\_SB.PC00.I2C1") + * CAM_I2C_ADDR - Camera I2C slave address (0x0010 for OV13B10) + * CAM_TO_MIPI_PORT - Connected IPU0 MIPI port (e.g. 0/1/2) + * CAM_LANES - Number of MIPI data lanes (e.g. 2, 4) + * CAM_RESET_GPIO_CTLR - GPIO controller path for RESET (e.g. "\\_SB.GPI1") + * CAM_POWER_GPIO_CTLR - GPIO controller path for POWER_EN (e.g. "\\_SB.GPI0") + * CAM_RESET_PIN - GPIO pin number for RESET (community-relative) + * CAM_POWER_PIN - GPIO pin number for POWER_EN (community-relative) + * CAM_RESET_GPIORSC - GPIO resource index used by reset-gpios: + * 0 = RESET GpioIo resource, 1 = POWER_EN GpioIo resource + * CAM_RESET_ACTIVE_LOW - RESET GPIO polarity (1: active low, 0: active high) + * CAM_IPU_PATH - IPU path string (e.g. "\\_SB.PC00.IPU0") + * CAM_IPU_REF - IPU namespace reference (e.g. \_SB.PC00.IPU0) + * CAM_GPIO_REF - Device self-reference for reset-gpios (e.g. ^CAM0) + * + * Default configuration (from BIOS table for OV13B10 on IPU75XA): + * CAM0: I2C1, MIPI port 0, 4 lanes, RESET COM1 C_D_E_H pad 10 (GPI1 pin 27), + * POWER_EN COM0 C_D_E_H pad 5 (GPI0 pin 29) + * CAM1: I2C2, MIPI port 2, 2 lanes, RESET COM1 C_D_E_H pad 1 (GPI1 pin 36), + * POWER_EN COM0 C_D_E_H pad 8 (GPI0 pin 32) + */ + +DefinitionBlock ("", "SSDT", 2, "", "IMG_IPU", 0x20260827) +{ + External (_SB.PC00, DeviceObj) + External (_SB.PC00.IPU0, DeviceObj) + External (_SB.GPI1, DeviceObj) // GPIO controller COM1 for RESET + External (_SB.GPI0, DeviceObj) // GPIO controller COM0 for POWER_EN + + Include ("_ipu.asl") + + Scope (\_SB.PC00) + { + Device (CAM0) + { + #define CAM_I2C_BUS "\\_SB.PC00.I2C1" + #define CAM_I2C_ADDR 0x0010 + #define CAM_TO_MIPI_PORT 0 + #define CAM_LANES 4 + #define CAM_RESET_GPIO_CTLR "\\_SB.GPI1" + #define CAM_POWER_GPIO_CTLR "\\_SB.GPI0" + #define CAM_RESET_PIN 27 // COM1 C_D_E_H pad 10 + #define CAM_POWER_PIN 29 // COM0 C_D_E_H pad 5 (Power_En) + // Use POWER_EN GPIO resource for probe-time toggling. + #define CAM_RESET_GPIORSC 1 + // Logical low maps to physical high (enable rail). + #define CAM_RESET_ACTIVE_LOW 1 + #define CAM_IPU_PATH "\\_SB.PC00.IPU0" + #define CAM_IPU_REF \_SB.PC00.IPU0 + #define CAM_GPIO_REF ^CAM0 + #include "_mipi_cam_common_ov13b10.asl" + #undef CAM_I2C_BUS + #undef CAM_I2C_ADDR + #undef CAM_TO_MIPI_PORT + #undef CAM_LANES + #undef CAM_RESET_GPIO_CTLR + #undef CAM_POWER_GPIO_CTLR + #undef CAM_RESET_PIN + #undef CAM_POWER_PIN + #undef CAM_RESET_GPIORSC + #undef CAM_RESET_ACTIVE_LOW + #undef CAM_IPU_PATH + #undef CAM_IPU_REF + #undef CAM_GPIO_REF + } + + Device (CAM1) + { + #define CAM_I2C_BUS "\\_SB.PC00.I2C2" + #define CAM_I2C_ADDR 0x0010 + #define CAM_TO_MIPI_PORT 2 + #define CAM_LANES 2 + #define CAM_RESET_GPIO_CTLR "\\_SB.GPI1" + #define CAM_POWER_GPIO_CTLR "\\_SB.GPI0" + #define CAM_RESET_PIN 36 // COM1 C_D_E_H pad 1 + #define CAM_POWER_PIN 32 // COM0 C_D_E_H pad 8 (Power_En) + // Use POWER_EN GPIO resource for probe-time toggling. + #define CAM_RESET_GPIORSC 1 + // Logical low maps to physical high (enable rail). + #define CAM_RESET_ACTIVE_LOW 1 + #define CAM_IPU_PATH "\\_SB.PC00.IPU0" + #define CAM_IPU_REF \_SB.PC00.IPU0 + #define CAM_GPIO_REF ^CAM1 + #include "_mipi_cam_common_ov13b10.asl" + #undef CAM_I2C_BUS + #undef CAM_I2C_ADDR + #undef CAM_TO_MIPI_PORT + #undef CAM_LANES + #undef CAM_RESET_GPIO_CTLR + #undef CAM_POWER_GPIO_CTLR + #undef CAM_RESET_PIN + #undef CAM_POWER_PIN + #undef CAM_RESET_GPIORSC + #undef CAM_RESET_ACTIVE_LOW + #undef CAM_IPU_PATH + #undef CAM_IPU_REF + #undef CAM_GPIO_REF + } + } +} From a68d376a0d26945147368adcd201b2faa6634d2e Mon Sep 17 00:00:00 2001 From: "Sodhi, Vunny" Date: Thu, 27 Aug 2026 17:35:54 +0800 Subject: [PATCH 03/17] acpi: ipu8: add direct MIPI OV13B10 camera SSDT overlay Add SSDT overlay for dual OV13B10 sensors on NVL IPU8 platform: - CAM0: I2C1, MIPI port 0, 4 lanes, reset GPIO pin 36 (COM1 C_E_V pad 10) - CAM1: I2C0, MIPI port 2, 2 lanes, reset GPIO pin 11 (COM1 B_D_F_S pad 11) Use OV13B10 common include for direct MIPI camera resources and device properties, aligned with existing direct-MIPI camera overlays. Signed-off-by: Sodhi, Vunny --- acpi/ipu8/_mipi_cam_common_ov13b10.asl | 132 +++++++++++++++++++++++++ acpi/ipu8/mipi_ov13b10.asl | 108 ++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 acpi/ipu8/_mipi_cam_common_ov13b10.asl create mode 100644 acpi/ipu8/mipi_ov13b10.asl diff --git a/acpi/ipu8/_mipi_cam_common_ov13b10.asl b/acpi/ipu8/_mipi_cam_common_ov13b10.asl new file mode 100644 index 00000000..6706671f --- /dev/null +++ b/acpi/ipu8/_mipi_cam_common_ov13b10.asl @@ -0,0 +1,132 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2026 Intel Corporation. + * + * Description: Common template for a direct MIPI CSI-2 OV13B10 camera device. + * This include provides the body of a CAMx device for native MIPI. + * + * CAM-level defines expected by caller: + * CAM_I2C_BUS - Camera I2C bus path (e.g. "\\_SB.PC00.I2C1") + * CAM_I2C_ADDR - Camera I2C slave address (e.g. 0x0010) + * CAM_TO_MIPI_PORT - Connected IPU MIPI port index (e.g. 0, 1, 2) + * CAM_LANES - Number of MIPI data lanes (e.g. 2, 4) + * CAM_RESET_GPIO_CTLR - GPIO controller path for RESET (e.g. "\\_SB.GPI1") + * CAM_POWER_GPIO_CTLR - GPIO controller path for POWER_EN (e.g. "\\_SB.GPI0") + * CAM_RESET_PIN - GPIO pin number for RESET + * CAM_POWER_PIN - GPIO pin number for POWER_EN + * CAM_RESET_GPIORSC - GPIO resource index used by reset-gpios: + * 0 = first GpioIo (_CRS RESET), 1 = second GpioIo (_CRS POWER_EN) + * CAM_RESET_ACTIVE_LOW - RESET GPIO polarity (1: active low, 0: active high) + * CAM_IPU_PATH - IPU path string (e.g. "\\_SB.PC00.IPU0") + * CAM_IPU_REF - IPU namespace reference (e.g. \_SB.PC00.IPU0) + * CAM_GPIO_REF - Device self-reference for reset-gpios (e.g. ^CAM0) + */ +Method (_STA, 0, NotSerialized) // _STA: Status +{ + Return (0x0F) +} + +Method (_HID, 0, NotSerialized) // _HID: Hardware ID +{ + Return ("OVTI13B1") // OV13B10 +} + +Name (_DEP, Package (0x01) // _DEP: Dependencies +{ + CAM_IPU_REF +}) + +Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings +{ + /* + * mipi-disco-img.c will use the information in CSI2Bus to create fwnode. + * CAMx Local Port -> IPU Remote Port + * CAMx PRT0 -> IPU PRTx (selected by CAM_TO_MIPI_PORT) + */ + CSI2Bus( + DeviceInitiated, // SlaveMode + 1, // PhyType (1 for DPHY) + 0, // LocalPort (sensor local port) + CAM_IPU_PATH, // ResourceSource (Path to IPU) + CAM_TO_MIPI_PORT, // ResourceSourceIndex (IPU PRTx) + , // ResourceUsage + , // DescriptorName + ) // VendorData + + I2cSerialBusV2 ( + CAM_I2C_ADDR, // SlaveAddress + ControllerInitiated, // SlaveMode + 400000, // I2C ConnectionSpeed + AddressingMode7Bit, // AddressingMode + CAM_I2C_BUS, // ResourceSource + 0x00, // ResourceSourceIndex + ResourceConsumer, // ResourceUsage + , // DescriptorName + Exclusive, // Shared + ) // VendorData + + /* GPIO for sensor RESET (directly from SoC GPIO controller) */ + GpioIo ( + Exclusive, // Shared (Not shared) + PullNone, // PinConfig (No need for pulls) + 0, // DebounceTimeout + 0, // DriveStrength + IoRestrictionOutputOnly,// IoRestriction (Only used as output) + CAM_RESET_GPIO_CTLR, // ResourceSource (GPIO controller) + 0) // ResourceSourceIndex (Must be 0) + { + CAM_RESET_PIN // Pin number + } + + /* GPIO for sensor POWER_EN (optional rail control) */ + GpioIo ( + Exclusive, + PullNone, + 0, + 0, + IoRestrictionOutputOnly, + CAM_POWER_GPIO_CTLR, + 0) + { + CAM_POWER_PIN // Pin number + } +}) + +Name (_DSD, Package () // _DSD: Device-Specific Data +{ + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), // Device Properties + Package () + { + Package () { "mipi-img-clock-frequency", 19200000 }, // 19.2 MHz + /* + * reset-gpios: used by ov13b10.c driver via + * devm_gpiod_get_optional(dev, "reset", ...) + * Format: { , , , } + * resource_index maps to _CRS GpioIo order: 0=RESET, 1=POWER_EN. + */ + Package () { "reset-gpios", Package () { CAM_GPIO_REF, CAM_RESET_GPIORSC, 0, CAM_RESET_ACTIVE_LOW } }, + }, + ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), // Hierarchical Data Extension + Package () + { + /* mipi-img-port here is local camera port used by mipi-disco-img.c. */ + Package () { "mipi-img-port-0", "PRT0" }, + }, +}) + +Name (PRT0, Package () +{ + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), // Device Properties + Package () + { + Package () { "mipi-img-clock-lane", 0 }, +#if CAM_LANES == 4 + Package () { "mipi-img-data-lanes", Package () { 1, 2, 3, 4 } }, +#elif CAM_LANES == 2 + Package () { "mipi-img-data-lanes", Package () { 1, 2 } }, +#else + Package () { "mipi-img-data-lanes", Package () { 1, 2, 3, 4 } }, +#endif + Package () { "mipi-img-link-frequencies", Package () { 560000000 } }, + }, +}) diff --git a/acpi/ipu8/mipi_ov13b10.asl b/acpi/ipu8/mipi_ov13b10.asl new file mode 100644 index 00000000..1bb986db --- /dev/null +++ b/acpi/ipu8/mipi_ov13b10.asl @@ -0,0 +1,108 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2026 Intel Corporation. + * + * SSDT overlay: Direct MIPI CSI-2 OV13B10 camera configuration on NVL platform. + * + * This overlay describes a native MIPI-connected OV13B10 sensor (no GMSL SERDES). + * Adjust the CAM_* defines below to match your hardware wiring. + * + * CAM-level defines (set per CAMx, see _mipi_cam_common_ov13b10.asl): + * CAM_I2C_BUS - Camera I2C bus path (e.g. "\\_SB.PC00.I2C1") + * CAM_I2C_ADDR - Camera I2C slave address (0x0010 for OV13B10) + * CAM_TO_MIPI_PORT - Connected IPU0 MIPI port (e.g. 0/1/2) + * CAM_LANES - Number of MIPI data lanes (e.g. 2, 4) + * CAM_RESET_GPIO_CTLR - GPIO controller path for RESET (e.g. "\\_SB.GPI1") + * CAM_POWER_GPIO_CTLR - GPIO controller path for POWER_EN (e.g. "\\_SB.GPI0") + * CAM_RESET_PIN - GPIO pin number for RESET (community-relative) + * CAM_POWER_PIN - GPIO pin number for POWER_EN (community-relative) + * CAM_RESET_GPIORSC - GPIO resource index used by reset-gpios: + * 0 = RESET GpioIo resource, 1 = POWER_EN GpioIo resource + * CAM_RESET_ACTIVE_LOW - RESET GPIO polarity (1: active low, 0: active high) + * CAM_IPU_PATH - IPU path string (e.g. "\\_SB.PC00.IPU0") + * CAM_IPU_REF - IPU namespace reference (e.g. \_SB.PC00.IPU0) + * CAM_GPIO_REF - Device self-reference for reset-gpios (e.g. ^CAM0) + * + * Default configuration (from BIOS NVS for OV13B10 on NVL IPU8): + * CAM0: I2C1, MIPI port 0, 4 lanes + * RESET COM1 C_E_V pad 10 (GPI1 pin 36) + * POWER_EN COM0 C_E_V pad 5 (GPI0 pin 32) + * CAM1: I2C0, MIPI port 2, 2 lanes + * RESET COM1 B_D_F_S pad 11 (GPI1 pin 11) + * POWER_EN COM0 C_E_V pad 8 (GPI0 pin 35) + */ + +DefinitionBlock ("", "SSDT", 2, "", "IMG_IPU", 0x20260827) +{ + External (_SB.PC00, DeviceObj) + External (_SB.PC00.IPU0, DeviceObj) + External (_SB.GPI1, DeviceObj) // GPIO controller COM1 for RESET + External (_SB.GPI0, DeviceObj) // GPIO controller COM0 for POWER_EN + + Include ("_ipu.asl") + + Scope (\_SB.PC00) + { + Device (CAM0) + { + #define CAM_I2C_BUS "\\_SB.PC00.I2C1" + #define CAM_I2C_ADDR 0x0010 + #define CAM_TO_MIPI_PORT 0 + #define CAM_LANES 4 + #define CAM_RESET_GPIO_CTLR "\\_SB.GPI1" + #define CAM_POWER_GPIO_CTLR "\\_SB.GPI0" + #define CAM_RESET_PIN 36 // COM1 C_E_V pad 10 + #define CAM_POWER_PIN 32 // COM0 C_E_V pad 5 (Power_En) + #define CAM_RESET_GPIORSC 1 + #define CAM_RESET_ACTIVE_LOW 1 + #define CAM_IPU_PATH "\\_SB.PC00.IPU0" + #define CAM_IPU_REF \_SB.PC00.IPU0 + #define CAM_GPIO_REF ^CAM0 + #include "_mipi_cam_common_ov13b10.asl" + #undef CAM_I2C_BUS + #undef CAM_I2C_ADDR + #undef CAM_TO_MIPI_PORT + #undef CAM_LANES + #undef CAM_RESET_GPIO_CTLR + #undef CAM_POWER_GPIO_CTLR + #undef CAM_RESET_PIN + #undef CAM_POWER_PIN + #undef CAM_RESET_GPIORSC + #undef CAM_RESET_ACTIVE_LOW + #undef CAM_IPU_PATH + #undef CAM_IPU_REF + #undef CAM_GPIO_REF + } + + Device (CAM1) + { + #define CAM_I2C_BUS "\\_SB.PC00.I2C0" + #define CAM_I2C_ADDR 0x0010 + #define CAM_TO_MIPI_PORT 2 + #define CAM_LANES 2 + #define CAM_RESET_GPIO_CTLR "\\_SB.GPI1" + #define CAM_POWER_GPIO_CTLR "\\_SB.GPI0" + #define CAM_RESET_PIN 11 // COM1 B_D_F_S pad 11 + #define CAM_POWER_PIN 35 // COM0 C_E_V pad 8 (Power_En) + #define CAM_RESET_GPIORSC 1 + #define CAM_RESET_ACTIVE_LOW 1 + #define CAM_IPU_PATH "\\_SB.PC00.IPU0" + #define CAM_IPU_REF \_SB.PC00.IPU0 + #define CAM_GPIO_REF ^CAM1 + #include "_mipi_cam_common_ov13b10.asl" + #undef CAM_I2C_BUS + #undef CAM_I2C_ADDR + #undef CAM_TO_MIPI_PORT + #undef CAM_LANES + #undef CAM_RESET_GPIO_CTLR + #undef CAM_POWER_GPIO_CTLR + #undef CAM_RESET_PIN + #undef CAM_POWER_PIN + #undef CAM_RESET_GPIORSC + #undef CAM_RESET_ACTIVE_LOW + #undef CAM_IPU_PATH + #undef CAM_IPU_REF + #undef CAM_GPIO_REF + } + } +} From 01afea6bdf2cab83d11087a336ed696ba0677580 Mon Sep 17 00:00:00 2001 From: "Sodhi, Vunny" Date: Fri, 21 Aug 2026 10:55:41 +0800 Subject: [PATCH 04/17] media: maxim-serdes, d4xx: fix RGB stream stuck after S3 resume After S3 (s2idle) resume, the MAX96717 serializer's cached runtime state (pipe->enabled, phy->active, streams_masks) remained stale from before suspend. When enable_streams() ran post-resume, idempotency guards saw the cached state matched the requested state and skipped re-enabling pipes and PHYs that were actually disabled in hardware by max_ser_init(). This caused the second stream (RGB on VC1) to have its serializer pipe and PHY left disabled, so data from the D457 sensor never reached the CSI-2 output despite the sensor FW confirming it was streaming. Fix by clearing all cached serializer runtime state in max_ser_resume() after hardware re-initialization, so enable_streams() detects a real delta and reprograms the hardware. Also implement d4xx ds5_suspend/ds5_resume to clear stale streaming flags and reinitialize D457 FW (MIPI lanes, data rate, stream reset) on resume, and propagate errors from ds5_enable/disable_streams. Signed-off-by: Sodhi, Vunny --- drivers/media/i2c/d4xx.c | 37 +++++++++++++++++------- drivers/media/i2c/maxim-serdes/max_ser.c | 13 +++++++++ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/d4xx.c b/drivers/media/i2c/d4xx.c index 4f197860..25657e60 100644 --- a/drivers/media/i2c/d4xx.c +++ b/drivers/media/i2c/d4xx.c @@ -2618,7 +2618,7 @@ static int ds5_sensor_set_stream(struct v4l2_subdev *sd, u64 streams_mask, int e if (ret) goto restore_s_state; - dev_dbg(&state->client->dev, "%s: starting stream with VC %d. reg %x val %x\n", + dev_dbg(&state->client->dev, "%s: starting stream with VC %d. reg %x val %x\n", __func__, vc_id, DS5_START_STOP_STREAM, DS5_STREAM_START | sensor->stream_cfg.stream_id); ret = ds5_write(state, DS5_START_STOP_STREAM, DS5_STREAM_START | sensor->stream_cfg.stream_id); @@ -2684,11 +2684,11 @@ static int ds5_sensor_set_stream(struct v4l2_subdev *sd, u64 streams_mask, int e ds5_read(state, config_status_base, &status); ds5_read(state, stream_status_base, &streaming); dev_dbg(&state->client->dev, - "%s: %s %s, stream_status 0x%x:%x, config_status 0x%x:%x ret=%d\n", - __func__, ds5_get_sensor_name(state), - (enable)?"START":"STOP", - stream_status_base, streaming, - config_status_base, status, ret); + "%s: %s %s, stream_status 0x%x:%x, config_status 0x%x:%x ret=%d\n", + __func__, ds5_get_sensor_name(state), + (enable) ? "START" : "STOP", + stream_status_base, streaming, + config_status_base, status, ret); return 0; @@ -2712,13 +2712,12 @@ static int ds5_enable_streams(struct v4l2_subdev *subdev, return 0; } + static int ds5_disable_streams(struct v4l2_subdev *subdev, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - ds5_sensor_set_stream(subdev, streams_mask, false); - - return 0; + return ds5_sensor_set_stream(subdev, streams_mask, false); } // v4l2 ops for all @@ -5146,13 +5145,29 @@ static void ds5_update_pad_format(const struct ds5_resolution *resolutions, static int __maybe_unused ds5_suspend(struct device *dev) { - //TODO: add resume handling in future + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ds5 *ds5 = container_of(sd, struct ds5, mux.sd.subdev); + + ds5->depth.sensor.streaming = false; + ds5->rgb.sensor.streaming = false; + ds5->ir.sensor.streaming = false; + ds5->imu.sensor.streaming = false; + return 0; } static int __maybe_unused ds5_resume(struct device *dev) { - //TODO: add resume handling in future + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ds5 *ds5 = container_of(sd, struct ds5, mux.sd.subdev); + int ret; + + ret = ds5_hw_init(client, ds5); + if (ret) + return ret; + return 0; } diff --git a/drivers/media/i2c/maxim-serdes/max_ser.c b/drivers/media/i2c/maxim-serdes/max_ser.c index 7c64abff..b928a34d 100644 --- a/drivers/media/i2c/maxim-serdes/max_ser.c +++ b/drivers/media/i2c/maxim-serdes/max_ser.c @@ -2346,6 +2346,8 @@ EXPORT_SYMBOL_NS_GPL(max_ser_suspend, "MAX_SERDES"); int max_ser_resume(struct max_ser *ser) { struct max_ser_priv *priv = ser->priv; + unsigned int num_pads = max_ser_num_pads(ser); + unsigned int i; int ret; ret = max_ser_init(priv); @@ -2362,6 +2364,17 @@ int max_ser_resume(struct max_ser *ser) if (ret) return ret; + /* HW was reset; clear cached state so enable_streams() reprograms. */ + for (i = 0; i < ser->ops->num_pipes; i++) + ser->pipes[i].enabled = false; + + for (i = 0; i < ser->ops->num_phys; i++) + ser->phys[i].active = false; + + ser->active = false; + ser->tpg_entry = NULL; + memset(priv->streams_masks, 0, num_pads * sizeof(*priv->streams_masks)); + dev_dbg(priv->dev, "Serializer resumed\n"); return 0; From 05a5ccf7e43ccbf4a77b0524b7aaa37c5b583ef9 Mon Sep 17 00:00:00 2001 From: "Sodhi, Vunny" Date: Thu, 27 Aug 2026 14:26:56 +0800 Subject: [PATCH 05/17] media: d4xx: Implement proper suspend/resume functionality - Add mutex locking in suspend/resume for thread safety - Actually stop streaming by writing DS5_STREAM_STOP to firmware instead of just clearing streaming flags - Control reset GPIO in suspend (low) and resume (high) to properly power cycle the sensor - Add 200ms delay after GPIO high for sensor I2C readiness - Add error logging on resume failure Similar to isx031.c suspend/resume implementation. Signed-off-by: Sodhi, Vunny --- drivers/media/i2c/d4xx.c | 49 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/d4xx.c b/drivers/media/i2c/d4xx.c index 25657e60..b78613e1 100644 --- a/drivers/media/i2c/d4xx.c +++ b/drivers/media/i2c/d4xx.c @@ -5149,10 +5149,35 @@ static int __maybe_unused ds5_suspend(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ds5 *ds5 = container_of(sd, struct ds5, mux.sd.subdev); - ds5->depth.sensor.streaming = false; - ds5->rgb.sensor.streaming = false; - ds5->ir.sensor.streaming = false; - ds5->imu.sensor.streaming = false; + mutex_lock(&ds5->mutex); + + /* Stop streaming for all active sensors */ + if (ds5->depth.sensor.streaming) { + if (!ds5_write(ds5, DS5_START_STOP_STREAM, + DS5_STREAM_STOP | DS5_STREAM_DEPTH)) + ds5->depth.sensor.streaming = false; + } + if (ds5->rgb.sensor.streaming) { + if (!ds5_write(ds5, DS5_START_STOP_STREAM, + DS5_STREAM_STOP | DS5_STREAM_RGB)) + ds5->rgb.sensor.streaming = false; + } + if (ds5->ir.sensor.streaming) { + if (!ds5_write(ds5, DS5_START_STOP_STREAM, + DS5_STREAM_STOP | DS5_STREAM_IR)) + ds5->ir.sensor.streaming = false; + } + if (ds5->imu.sensor.streaming) { + if (!ds5_write(ds5, DS5_START_STOP_STREAM, + DS5_STREAM_STOP | DS5_STREAM_IMU)) + ds5->imu.sensor.streaming = false; + } + + mutex_unlock(&ds5->mutex); + + /* Set reset GPIO low to power off sensor */ + if (!IS_ERR_OR_NULL(ds5->reset_gpio)) + gpiod_set_value_cansleep(ds5->reset_gpio, 0); return 0; } @@ -5164,9 +5189,23 @@ static int __maybe_unused ds5_resume(struct device *dev) struct ds5 *ds5 = container_of(sd, struct ds5, mux.sd.subdev); int ret; + /* Set reset GPIO high to power on sensor */ + if (!IS_ERR_OR_NULL(ds5->reset_gpio)) { + gpiod_set_value_cansleep(ds5->reset_gpio, 1); + /* Wait for sensor to power up and be ready for I2C */ + msleep(200); + } + + mutex_lock(&ds5->mutex); + ret = ds5_hw_init(client, ds5); - if (ret) + if (ret) { + dev_err(&client->dev, "Failed to reinitialize sensor: %d\n", ret); + mutex_unlock(&ds5->mutex); return ret; + } + + mutex_unlock(&ds5->mutex); return 0; } From 2f57c36e7facd3d8c9795753a3c84b92df743495 Mon Sep 17 00:00:00 2001 From: "Sodhi, Vunny" Date: Tue, 1 Sep 2026 11:09:07 +0800 Subject: [PATCH 06/17] Update IPU6 and IPU7 driver submodules - IPU6 driver submodule: a810b67d4857db8440fe7271f34fce421c74621c - IPU7 driver submodule: 495acc90feb09d8008c0a6228fb8bb4c6415ca62 Signed-off-by: Sodhi, Vunny --- ipu6-drivers | 2 +- ipu7-drivers | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipu6-drivers b/ipu6-drivers index 504893c3..a810b67d 160000 --- a/ipu6-drivers +++ b/ipu6-drivers @@ -1 +1 @@ -Subproject commit 504893c3bd71240742be6430a6a46e1f5176a01f +Subproject commit a810b67d4857db8440fe7271f34fce421c74621c diff --git a/ipu7-drivers b/ipu7-drivers index bed9b71d..495acc90 160000 --- a/ipu7-drivers +++ b/ipu7-drivers @@ -1 +1 @@ -Subproject commit bed9b71d5be56d0e24c771c7a6ec83fd0a9db433 +Subproject commit 495acc90feb09d8008c0a6228fb8bb4c6415ca62 From 2dbfd631eecf7a51c965b858a1fc01d5de6e55e6 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Fri, 21 Aug 2026 12:10:12 +0800 Subject: [PATCH 07/17] script: mc-setup: Remove TOKEN for 2D sensors There is no point calling out streams for 2D sensor since they only have single stream, and will only take up 1 capture node. Remove the 2D sensors from MODEL_STREAMS and MODEL_DEFAULT_STREAMS to reduce the maintenance effort and also reduce the blocks to modify when there are new sensors. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 86 +++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index ba8794cc..d613d802 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -69,8 +69,8 @@ # To add a new sensor model: # 1. Add its ACPI HID -> model name in SENSOR_MODEL. # 2. Add its ACPI HID -> v4l-subdev entity prefix in SENSOR_PREFIX. -# 3. List the model's stream tokens in MODEL_STREAMS and pick defaults in -# MODEL_DEFAULT_STREAMS. +# 3. For multi-stream models, list the stream tokens in MODEL_STREAMS and +# select their defaults in MODEL_DEFAULT_STREAMS. # 4. For each new stream token, set STREAM_NODE (and STREAM_MUXPAD if it # flows through a d4xx-style mux). # 5. If your new media-bus code isn't covered, extend MBUS_TO_PIXFMT. @@ -117,21 +117,23 @@ declare -A MAX_LINKS_BY_PREFIX=( ) # ---- Per-model stream definitions ------------------------------------------- -# MODEL_STREAMS: every stream token a model can produce. -# MODEL_DEFAULT_STREAMS: streams enabled when no `stream=` is given on the CLI. +# MODEL_STREAMS: stream tokens selectable for multi-stream models. +# MODEL_DEFAULT_STREAMS: streams enabled for those models when no `stream=` is +# given on the CLI. declare -A MODEL_STREAMS=( [d4xx]="depth rgb ir imu" - [isx031]="yuv" - [ar0234]="raw" - [ov13b10]="raw" ) declare -A MODEL_DEFAULT_STREAMS=( [d4xx]="depth rgb" - [isx031]="yuv" - [ar0234]="raw" - [ov13b10]="raw" ) +fixed_stream_for_model() { + case "$1" in + isx031|ar0234) echo single ;; + *) return 1 ;; + esac +} + # STREAM_NODE: per-stream capture-node index (also used as the v4l2 # source_stream id on the mux/serializer chain -- d4xx in particular asserts # this matches the sensor's hard-coded vc_id, so pick stable values). @@ -140,8 +142,7 @@ declare -A STREAM_NODE=( [rgb]=1 [ir]=2 [imu]=3 - [yuv]=0 - [raw]=0 + [single]=0 ) # Keep capture-node groups consistent across 2-link and 4-link deserializers: @@ -503,12 +504,9 @@ setup_mipi_cameras() { cam=${MIPI_BA[$i]} csi2=${MIPI_CSI2[$i]} node=${MIPI_CAP[$i]} - for s in ${MODEL_DEFAULT_STREAMS[$model]}; do - detected=$(sensor_active_format "$model" "$cam" "$s" "${STREAM_NODE[$s]}") || \ - die "cannot read active format from ${model} camera ${cam}" - read -r fmt size <<<"$detected" - break - done + s=$(fixed_stream_for_model "$model") || continue + fmt=${STREAM_FMT[$s]} + size=${STREAM_SIZE[$s]} echo " ${MIPI_PREFIX[$i]} $cam -> $csi2 -> /dev/video$node ($fmt/$size)" mc_v "\"${MIPI_PREFIX[$i]} ${cam}\":0 [fmt:${fmt}/${size} field:none]" mc_v "\"${csi2}\":0 [fmt:${fmt}/${size} field:none]" @@ -602,20 +600,23 @@ print_topology() { # # CLI: # mc-setup.sh # default per-model streams, all DES -# mc-setup.sh [des=D,]link=N[,stream=][,res=WxH][,format=MBUS_CODE] ... -# mc-setup.sh [des=D,]link=N,stream=[TOKEN,res=WxH,format=MBUS_CODE,fps=FPS],\ +# +# Sample syntax (Items in [] are optional.) +# mc-setup.sh [des=D,]link=N[,stream=][,res=WxH][,format=MBUS_CODE][,fps=FPS] +# +# Sample Single Stream Use Case can omit stream. +# mc-setup.sh des=D,link=N,res=WxH,format=MBUS_CODE,fps=FPS +# +# Sample Multi Stream Use Case +# mc-setup.sh des=D,link=N,stream=[TOKEN,res=WxH,format=MBUS_CODE,fps=FPS],\ # [TOKEN,res=WxH,format=MBUS_CODE,fps=FPS] ... # -# When des= is omitted, des=0 is assumed (matches the legacy single-DES CLI). +# TOKEN is only applicable for multi-stream sensors as specified in MODEL_STREAMS. +# Other 2D sensors do not need stream=, it is default to `single`. # -# Stream tokens by sensor model: -# d4xx: depth | rgb | ir | imu -# isx031: yuv +# D4xx defaults to depth,rgb when no stream is specified. # -# Default streams when no stream is specified for a link: -# d4xx -> depth,rgb -# isx031 -> yuv -# applied to every link discovered under every deserializer. +# When des= is omitted, des=0 is assumed (matches the legacy single-DES CLI). # # Capture-node layout (per DES) -- STREAM-MAJOR: # csi2_pad = STREAM_NODE[s] * CSI2_STREAM_STRIDE + l @@ -829,10 +830,9 @@ sensor_set_fps() { echo "${BASH_REMATCH[1]}" } -# Is stream token $1 declared as valid for model $2? +# Is stream token $1 selectable for model $2? stream_valid_for_model() { local s=$1 model=$2 t - [ -n "${MODEL_STREAMS[$model]:-}" ] || return 1 for t in ${MODEL_STREAMS[$model]}; do [ "$t" = "$s" ] && return 0 done @@ -918,13 +918,17 @@ declare -A CFG_STREAM_FORMAT=() declare -A CFG_STREAM_FPS_REQUEST=() if [ "$#" -eq 0 ]; then - # Default: program every discovered link with its model's default streams. + # Default: program every discovered link with its default or fixed stream. for ((d = 0; d < NUM_DES; d++)); do for l in ${LINKS_OF[$d]}; do key="${d}_${l}" CFG_DES+=("$d") CFG_LINKS+=("$l") - CFG_STREAMS+=("${MODEL_DEFAULT_STREAMS[${CAM_MODEL[$key]}]}") + model=${CAM_MODEL[$key]} + streams=${MODEL_DEFAULT_STREAMS[$model]:-} + [ -n "$streams" ] || streams=$(fixed_stream_for_model "$model") \ + || die "no stream configuration for $model" + CFG_STREAMS+=("$streams") CFG_RES+=("") CFG_FORMAT+=("") done @@ -1015,11 +1019,17 @@ else (( des < NUM_DES )) || die "des=$des out of range (have ${NUM_DES} DES)" key="${des}_${link}" [ -n "${CAM_MODEL[$key]:-}" ] || die "no camera discovered on DES${des} link ${link}" - [ -n "$streams" ] || streams=${MODEL_DEFAULT_STREAMS[${CAM_MODEL[$key]}]} - for s in $streams; do - stream_valid_for_model "$s" "${CAM_MODEL[$key]}" \ - || die "stream '$s' invalid for ${CAM_MODEL[$key]} on DES${des} link ${link}" - done + model=${CAM_MODEL[$key]} + if [ -n "${MODEL_STREAMS[$model]:-}" ]; then + [ -n "$streams" ] || streams=${MODEL_DEFAULT_STREAMS[$model]} + for s in $streams; do + stream_valid_for_model "$s" "$model" \ + || die "stream '$s' invalid for $model on DES${des} link ${link}" + done + else + streams=$(fixed_stream_for_model "$model") \ + || die "no stream configuration for $model" + fi CFG_DES+=("$des") CFG_LINKS+=("$link") CFG_STREAMS+=("$streams") @@ -1168,7 +1178,7 @@ for k in "${!CFG_LINKS[@]}"; do # Stream IDs along the mux->serializer->deserializer chain are fixed # per sensor sub-stream (see STREAM_NODE): depth=0, rgb=1, ir=2, imu=3, - # yuv=0. The d4xx driver in particular asserts that the route's + # single=0. The d4xx driver in particular asserts that the route's # source_stream on the mux matches the sensor's hard-coded vc_id, so # we must use STREAM_NODE[$s] -- not a sequential 0..n-1 index -- as # the stream identifier everywhere downstream of the sensor. From 3f68363953849bd71797cb098c259bfc1d3d20a4 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Fri, 21 Aug 2026 13:57:14 +0800 Subject: [PATCH 08/17] script: mc-setup: Fix MIPI flow and comment blocks Update comments to match with latest implementation. Fix MIPI so that it uses sensor_active_format to get active format and resolution before calling media-ctl. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 58 +++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index d613d802..6e6ca6a8 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -129,7 +129,7 @@ declare -A MODEL_DEFAULT_STREAMS=( fixed_stream_for_model() { case "$1" in - isx031|ar0234) echo single ;; + isx031|ar0234|ov13b10) echo single ;; *) return 1 ;; esac } @@ -498,15 +498,17 @@ detect_mipi_csi2() { setup_mipi_cameras() { [ "$NUM_MIPI" -eq 0 ] && return 0 echo -e "\nConfiguring direct MIPI cameras..." - local i model cam csi2 node fmt size s pixfmt w h ipu detected + local i model cam csi2 node fmt size s sid detected pixfmt w h ipu for ((i = 0; i < NUM_MIPI; i++)); do model=${MIPI_MODEL[$i]} cam=${MIPI_BA[$i]} csi2=${MIPI_CSI2[$i]} node=${MIPI_CAP[$i]} s=$(fixed_stream_for_model "$model") || continue - fmt=${STREAM_FMT[$s]} - size=${STREAM_SIZE[$s]} + sid=${STREAM_NODE[$s]} + detected=$(sensor_active_format "$model" "$cam" "$s" "$sid") || \ + die "cannot read active format from MIPI${i} ${model} sensor" + read -r fmt size <<<"$detected" echo " ${MIPI_PREFIX[$i]} $cam -> $csi2 -> /dev/video$node ($fmt/$size)" mc_v "\"${MIPI_PREFIX[$i]} ${cam}\":0 [fmt:${fmt}/${size} field:none]" mc_v "\"${csi2}\":0 [fmt:${fmt}/${size} field:none]" @@ -766,6 +768,7 @@ sensor_validate_format_size() { sensor_validate_fps() { local model=$1 cam=$2 stream=$3 sid=$4 fmt=$5 size=$6 local requested_fps=$7 active_fps=$8 context=$9 dev codes line code name + local format_size_changed=${10} local interval_args intervals candidate selected_fps max_fps supported=0 selected_fps=${requested_fps:-$active_fps} @@ -806,11 +809,20 @@ sensor_validate_fps() { } fi done <<<"$intervals" - if (( ! supported )) && [ -n "$max_fps" ]; then - printf "WARN: %s: FPS '%s' is unsupported with %s/%s; " \ - "$context" "$selected_fps" "$fmt" "$size" >&2 - printf "using largest supported FPS '%s'\n" "$max_fps" >&2 + if (( format_size_changed )) && [ -z "$requested_fps" ] && [ -n "$max_fps" ]; then selected_fps=$max_fps + elif (( ! supported )) && [ -n "$max_fps" ]; then + if (( format_size_changed )); then + printf "WARN: %s: FPS '%s' is unsupported with %s/%s; " \ + "$context" "$selected_fps" "$fmt" "$size" >&2 + printf "using largest supported FPS '%s'\n" "$max_fps" >&2 + selected_fps=$max_fps + else + [ -z "$requested_fps" ] || printf \ + "WARN: %s: FPS '%s' is unsupported; retaining active FPS '%s'\n" \ + "$context" "$requested_fps" "$active_fps" >&2 + selected_fps=$active_fps + fi fi echo "$selected_fps" } @@ -913,6 +925,7 @@ declare -a CFG_LINKS=() declare -a CFG_STREAMS=() declare -a CFG_RES=() declare -a CFG_FORMAT=() +declare -a CFG_FPS=() declare -A CFG_STREAM_RES=() declare -A CFG_STREAM_FORMAT=() declare -A CFG_STREAM_FPS_REQUEST=() @@ -931,11 +944,12 @@ if [ "$#" -eq 0 ]; then CFG_STREAMS+=("$streams") CFG_RES+=("") CFG_FORMAT+=("") + CFG_FPS+=("") done done else for arg in "$@"; do - des=""; link=""; streams=""; res=""; format="" + des=""; link=""; streams=""; res=""; format=""; fps="" declare -A arg_stream_res=() declare -A arg_stream_format=() declare -A arg_stream_fps=() @@ -993,6 +1007,7 @@ else stream=*) streams+="${streams:+ }${kv#stream=}" ;; res=*) res=${kv#res=} ;; format=*) format=${kv#format=} ;; + fps=*) fps=${kv#fps=} ;; *) if is_known_stream "$kv"; then streams+="${streams:+ }$kv" @@ -1008,6 +1023,8 @@ else || die "res must be WIDTHxHEIGHT (got '$res')" [ -z "$format" ] || [[ $format =~ ^[[:alnum:]_]+$ ]] \ || die "format must be a media-bus code (got '$format')" + [ -z "$fps" ] || [[ $fps =~ ^[0-9]+([.][0-9]+)?$ ]] \ + || die "fps must be numeric (got '$fps')" # Default des=0 when only one DES is present and des= was omitted. if [ -z "$des" ]; then if [ "$NUM_DES" -gt 1 ]; then @@ -1027,19 +1044,25 @@ else || die "stream '$s' invalid for $model on DES${des} link ${link}" done else - streams=$(fixed_stream_for_model "$model") \ + fixed_stream=$(fixed_stream_for_model "$model") \ || die "no stream configuration for $model" + if [ -n "$streams" ] && [ "$streams" != "$fixed_stream" ]; then + echo "WARN: $model on DES${des} link ${link}: replacing requested" \ + "stream '$streams' with fixed stream '$fixed_stream'" >&2 + fi + streams=$fixed_stream fi CFG_DES+=("$des") CFG_LINKS+=("$link") CFG_STREAMS+=("$streams") CFG_RES+=("$res") CFG_FORMAT+=("$format") + CFG_FPS+=("$fps") k=$((${#CFG_LINKS[@]} - 1)) for s in $streams; do CFG_STREAM_RES["${k}_${s}"]=${arg_stream_res[$s]:-} CFG_STREAM_FORMAT["${k}_${s}"]=${arg_stream_format[$s]:-} - CFG_STREAM_FPS_REQUEST["${k}_${s}"]=${arg_stream_fps[$s]:-} + CFG_STREAM_FPS_REQUEST["${k}_${s}"]=${arg_stream_fps[$s]:-${CFG_FPS[$k]}} done unset arg_stream_res arg_stream_format arg_stream_fps done @@ -1052,8 +1075,10 @@ else done fi -# Resolve and validate each selected stream's format and size. Requested values -# win when the sensor advertises support; otherwise retain its active settings. +# Resolve and validate each selected stream's format, size and FPS. Unsupported +# FPS requests retain the active FPS when format/size stay unchanged. After an +# effective format/size change, an unsupported or omitted FPS uses the largest +# FPS advertised for the new mode. declare -A CFG_STREAM_FMT=() declare -A CFG_STREAM_SIZE=() declare -A CFG_STREAM_FPS=() @@ -1080,6 +1105,11 @@ for k in "${!CFG_LINKS[@]}"; do "$requested_fmt" "$requested_size" "$detected_fmt" "$detected_size" \ "DES${d} link ${l} stream ${s}") read -r CFG_STREAM_FMT["${k}_${s}"] CFG_STREAM_SIZE["${k}_${s}"] <<<"$validated" + format_size_changed=0 + if [ "${CFG_STREAM_FMT["${k}_${s}"]}" != "$detected_fmt" ] || \ + [ "${CFG_STREAM_SIZE["${k}_${s}"]}" != "$detected_size" ]; then + format_size_changed=1 + fi active_fps=$(sensor_active_fps "$model" "$cam" "$s" "$sid") || active_fps="" if [ -n "$active_fps" ]; then CFG_STREAM_FPS["${k}_${s}"]=$(sensor_validate_fps \ @@ -1087,7 +1117,7 @@ for k in "${!CFG_LINKS[@]}"; do "${CFG_STREAM_FMT["${k}_${s}"]}" \ "${CFG_STREAM_SIZE["${k}_${s}"]}" \ "${CFG_STREAM_FPS_REQUEST["${k}_${s}"]}" "$active_fps" \ - "DES${d} link ${l} stream ${s}") + "DES${d} link ${l} stream ${s}" "$format_size_changed") else [ -z "${CFG_STREAM_FPS_REQUEST["${k}_${s}"]}" ] || \ echo "WARN: DES${d} link ${l} stream ${s}: FPS control unavailable" >&2 From f5f03e53f24aa72e7745d998b2746f0c156d1627 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Wed, 5 Aug 2026 16:21:04 +0800 Subject: [PATCH 09/17] script: mc-setup: Fix ir and imu stream nodes Depth node remains 0,1,2,3 RGB node remains 4,5,6,7 IR node now uses 6,7,4,5 IMU node now uses 2,3,0,1 This is to fit in all streams within 8 video nodes. Hence, there are certain combinations that are not supported if the capture node collides. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 50 ++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 6e6ca6a8..95dbe6bb 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -145,10 +145,25 @@ declare -A STREAM_NODE=( [single]=0 ) -# Keep capture-node groups consistent across 2-link and 4-link deserializers: -# depth uses offsets 0..3, rgb 4..7, -# TODO: ir and imu to have different offsets. -CSI2_STREAM_STRIDE=4 +# Capture-node placement is independent of STREAM_NODE. Depth and IMU share +# bank 0..3; RGB and IR share bank 4..7. Rotating IR and IMU by two links gives +# this D4XX camera 1..4 mapping: +# depth=0,1,2,3 rgb=4,5,6,7 ir=6,7,4,5 imu=2,3,0,1 +CSI2_NODE_BANK_SIZE=4 +declare -A STREAM_CAPTURE_BASE=( + [depth]=0 + [rgb]=4 + [ir]=4 + [imu]=0 + [single]=0 +) +declare -A STREAM_LINK_ROTATION=( + [depth]=0 + [rgb]=0 + [ir]=2 + [imu]=2 + [single]=0 +) # STREAM_MUXPAD: sink pad on a d4xx-style mux subdev. Only needed for streams # that flow through such a mux, usually a 3D sensor. @@ -623,12 +638,11 @@ print_topology() { # Capture-node layout (per DES) -- STREAM-MAJOR: # csi2_pad = STREAM_NODE[s] * CSI2_STREAM_STRIDE + l # node = CAPTURE_BASE[d] + csi2_pad -# Nodes are grouped by stream type in fixed groups of four for both max9296a -# and max96724: depth lands on base+0..3, rgb on base+4..7, etc. Unused links -# leave gaps on 2-link deserializers. For 1-stream sensors like isx031, links -# land on base+0..3 directly. The CSI2 RX cap is IPU*_NR_OF_CSI2_SRC_PADS; -# set IPU_CSI2_SRC_PADS to match (commonly 8 or 16). The resulting pad must -# stay within that. +# This keeps all D4XX streams within eight capture nodes using the permutation +# documented above. Streams that resolve to the same node cannot be enabled +# together and are rejected. For 1-stream sensors like isx031, links land on +# base+0..3 directly. The CSI2 RX cap is IPU*_NR_OF_CSI2_SRC_PADS; set +# IPU_CSI2_SRC_PADS to match (commonly 8 or 16). # # v4l2 source_stream tag at the deserializer source pad / CSI2 sink pad is # allocated separately as a compact per-DES sequential id (0..3), because @@ -1130,11 +1144,10 @@ done # IPU7 CSI2 RX source-pad cap (16 with the D4XX patch, 8 otherwise). IPU_CSI2_SRC_PADS=${IPU_CSI2_SRC_PADS:-16} -# Compute csi2_pad per (cfg_index, stream) using a stream-major formula: -# all 'depth' across links first, then all 'rgb', etc. For 1-stream sensors -# (isx031) this collapses to csi2_pad == link, so 4 links land on the first -# four capture nodes. +# Compute csi2_pad per (cfg_index, stream) using the configured capture bank +# and link rotation. For isx031 this collapses to csi2_pad == link. declare -A CSI2_PAD=() +declare -A CSI2_PAD_OWNER=() # Compact v4l2 source_stream id assigned to each (cfg_index, stream) at the # deserializer source pad and at the CSI2 sink pad. The kernel-side max96724 # / max_des state machine bounds the per-pipe stream-id field at 2 bits @@ -1148,12 +1161,19 @@ for k in "${!CFG_LINKS[@]}"; do l=${CFG_LINKS[$k]} key="${d}_${l}" for s in ${CFG_STREAMS[$k]}; do - pad=$(( STREAM_NODE[$s] * CSI2_STREAM_STRIDE + l )) + pad=$(( STREAM_CAPTURE_BASE[$s] + + (l + STREAM_LINK_ROTATION[$s]) % CSI2_NODE_BANK_SIZE )) if (( pad >= IPU_CSI2_SRC_PADS )); then die "DES${d} link ${l} stream ${s}: csi2_pad ${pad} exceeds CSI2 src-pad cap "\ "(${IPU_CSI2_SRC_PADS}); reduce active links/streams or rebuild the kernel with a "\ "higher *_NR_OF_CSI2_SRC_PADS" fi + pad_key="${d}_${pad}" + if [ -n "${CSI2_PAD_OWNER[$pad_key]:-}" ]; then + die "DES${d} link ${l} stream ${s}: capture node offset ${pad} conflicts with "\ + "${CSI2_PAD_OWNER[$pad_key]}" + fi + CSI2_PAD_OWNER[$pad_key]="link ${l} stream ${s}" CSI2_PAD["${k}_${s}"]=$pad ds=${DES_STREAM_NEXT[$d]:-0} From fed8d2bf5e2838472dc48a310e1eac9933a5f680 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Wed, 5 Aug 2026 17:15:05 +0800 Subject: [PATCH 10/17] script: mc-setup: Fix invalid res when changing format When changing format, if current resolution is not supported by the format, select the largest resolution supported by the format. Then, checks the FPS supported by the resolution. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 95dbe6bb..153ced62 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -697,13 +697,14 @@ sensor_active_fps() { } # Print the requested format/size after checking the sensor's advertised -# format-resolution combinations. Retain the active value for unsupported -# fields. +# format-resolution combinations. Retain the active format when unsupported; +# use the largest resolution advertised for a supported format. sensor_validate_format_size() { local model=$1 cam=$2 stream=$3 sid=$4 requested_fmt=$5 requested_size=$6 local active_fmt=$7 active_size=$8 context=$9 dev codes line code name local selected_fmt selected_size selected_code sizes supported - local min_w min_h max_w max_h req_w req_h + local min_w min_h max_w max_h req_w req_h largest_w largest_h + local area largest_area=0 local range_re range_re='Size[[:space:]]Range:[[:space:]]([0-9]+)x([0-9]+)' @@ -755,24 +756,40 @@ sensor_validate_format_size() { if [[ $line =~ $range_re ]]; then min_w=${BASH_REMATCH[1]}; min_h=${BASH_REMATCH[2]} max_w=${BASH_REMATCH[3]}; max_h=${BASH_REMATCH[4]} + area=$(( max_w * max_h )) + if (( area > largest_area )); then + largest_area=$area + largest_w=$max_w + largest_h=$max_h + fi req_w=${requested_size%x*}; req_h=${requested_size#*x} if (( req_w >= min_w && req_w <= max_w && req_h >= min_h && req_h <= max_h )); then supported=1 - break fi elif [[ $line =~ Size:[[:space:]]Discrete[[:space:]]([0-9]+)x([0-9]+) ]]; then + max_w=${BASH_REMATCH[1]}; max_h=${BASH_REMATCH[2]} + area=$(( max_w * max_h )) + if (( area > largest_area )); then + largest_area=$area + largest_w=$max_w + largest_h=$max_h + fi req_w=${requested_size%x*}; req_h=${requested_size#*x} - if (( req_w == BASH_REMATCH[1] && req_h == BASH_REMATCH[2] )); then + if (( req_w == max_w && req_h == max_h )); then supported=1 - break fi fi done <<<"$sizes" if [ -n "$sizes" ] && (( ! supported )); then printf "WARN: %s: resolution '%s' is unsupported with format '%s'; " \ "$context" "$requested_size" "$selected_fmt" >&2 - printf "retaining current active resolution '%s'\n" "$active_size" >&2 - selected_size=$active_size + if (( largest_area > 0 )); then + selected_size="${largest_w}x${largest_h}" + printf "using largest supported resolution '%s'\n" "$selected_size" >&2 + else + printf "retaining current active resolution '%s'\n" "$active_size" >&2 + selected_size=$active_size + fi fi fi From 5d8ba8eb8ed6050c74d7d85814584cb1a5ce52f9 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Sun, 9 Aug 2026 01:18:54 +0800 Subject: [PATCH 11/17] script: mc-setup: patches: Add RGB888_1X24 support d4xx IR stream has RGB888_1X24 format. Add the format into script and ipu7-drivers. Signed-off-by: Khai Wen, Ng --- .../0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch | 8 +++----- .../0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch | 3 ++- .../0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch | 8 +++----- script/acpi/mc-setup.sh | 3 ++- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/patches/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch b/patches/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch index 96d3907f..fd2b83b5 100644 --- a/patches/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch +++ b/patches/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch @@ -41,7 +41,7 @@ WARN_ON(1); --- a/ipu7-drivers/drivers/media/pci/intel/ipu7/ipu7-isys-video.c +++ b/ipu7-drivers/drivers/media/pci/intel/ipu7/ipu7-isys-video.c -@@ -82,7 +82,7 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { +@@ -84,11 +84,20 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { {V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, IPU_INSYS_FRAME_FORMAT_UYVY}, {V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16, @@ -50,10 +50,8 @@ {V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16, IPU_INSYS_FRAME_FORMAT_RGB565}, {V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, -@@ -91,6 +91,15 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { - IPU_INSYS_FRAME_FORMAT_RGB565}, - {V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, - IPU_INSYS_FRAME_FORMAT_RGBA888}, +- IPU_INSYS_FRAME_FORMAT_RGBA888}, ++ IPU_INSYS_FRAME_FORMAT_RGB888}, + /* D4XX specific */ + {V4L2_PIX_FMT_Z16, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, + IPU_INSYS_FRAME_FORMAT_UYVY}, diff --git a/patches/6.18/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch b/patches/6.18/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch index c0742f43..feafdaef 100644 --- a/patches/6.18/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch +++ b/patches/6.18/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch @@ -50,7 +50,8 @@ {V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16, IPU_INSYS_FRAME_FORMAT_RGB565}, {V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, - IPU_INSYS_FRAME_FORMAT_RGBA888}, +- IPU_INSYS_FRAME_FORMAT_RGBA888}, ++ IPU_INSYS_FRAME_FORMAT_RGB888}, + /* D4XX specific */ + {V4L2_PIX_FMT_Z16, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, + IPU_INSYS_FRAME_FORMAT_UYVY}, diff --git a/patches/7.0/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch b/patches/7.0/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch index 96d3907f..fd2b83b5 100644 --- a/patches/7.0/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch +++ b/patches/7.0/0006-media-pci-ipu7-Add-D4XX-support-to-IPU7.patch @@ -41,7 +41,7 @@ WARN_ON(1); --- a/ipu7-drivers/drivers/media/pci/intel/ipu7/ipu7-isys-video.c +++ b/ipu7-drivers/drivers/media/pci/intel/ipu7/ipu7-isys-video.c -@@ -82,7 +82,7 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { +@@ -84,11 +84,20 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { {V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, IPU_INSYS_FRAME_FORMAT_UYVY}, {V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16, @@ -50,10 +50,8 @@ {V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16, IPU_INSYS_FRAME_FORMAT_RGB565}, {V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, -@@ -91,6 +91,15 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { - IPU_INSYS_FRAME_FORMAT_RGB565}, - {V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, - IPU_INSYS_FRAME_FORMAT_RGBA888}, +- IPU_INSYS_FRAME_FORMAT_RGBA888}, ++ IPU_INSYS_FRAME_FORMAT_RGB888}, + /* D4XX specific */ + {V4L2_PIX_FMT_Z16, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, + IPU_INSYS_FRAME_FORMAT_UYVY}, diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 153ced62..3a1a9fd9 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -178,6 +178,7 @@ declare -A STREAM_MUXPAD=( declare -A MBUS_TO_PIXFMT=( [UYVY8_1X16]="UYVY" [YUYV8_1X16]="YUYV" + [RGB888_1X24]="BGR3" [VYUY8_1X16]="Y8I " # IR -> interleaved 8-bit greyscale [Y8_1X8]="GREY" [SGRBG10_1X10]="BA10" # AR0234 RAW Bayer SGRBG 10-bit @@ -1380,7 +1381,7 @@ for k in "${!CFG_LINKS[@]}"; do h=${size#*x} v4l2-ctl -d "/dev/video${node}" \ --set-fmt-video="width=${w},height=${h},pixelformat=${pixfmt}" \ - >/dev/null + >/dev/null || die "cannot set /dev/video${node} to ${pixfmt} ${size}" done done From 1561100e72cb406a067c6eb4833293561f4c7206 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Fri, 21 Aug 2026 17:49:58 +0800 Subject: [PATCH 12/17] script: mc-setup: Add Z16 for FIXED format If getting default format from D457, depth stream returns FIXED. This format is interpreted by IPU driver as Z16. Add a format conversion in mc-setup to set Z16 correctly towards IPU capture node. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 3a1a9fd9..7cab7982 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -176,6 +176,7 @@ declare -A STREAM_MUXPAD=( # ---- Media-bus -> V4L2 pixelformat fourcc (used on capture nodes) ----------- declare -A MBUS_TO_PIXFMT=( + [FIXED]="Z16 " [UYVY8_1X16]="UYVY" [YUYV8_1X16]="YUYV" [RGB888_1X24]="BGR3" From 7be5383890d42a14dbc6c5ccadadf1d7bedcfb2b Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Wed, 26 Aug 2026 15:50:33 +0800 Subject: [PATCH 13/17] script: mc-setup: Check MODEL with MODEL_STREAMS Rejects Models with invalid stream token. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 7cab7982..908e540c 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -521,7 +521,8 @@ setup_mipi_cameras() { cam=${MIPI_BA[$i]} csi2=${MIPI_CSI2[$i]} node=${MIPI_CAP[$i]} - s=$(fixed_stream_for_model "$model") || continue + s=$(fixed_stream_for_model "$model") \ + || die "no stream configuration for MIPI${i} $model" sid=${STREAM_NODE[$s]} detected=$(sensor_active_format "$model" "$cam" "$s" "$sid") || \ die "cannot read active format from MIPI${i} ${model} sensor" @@ -877,8 +878,9 @@ sensor_set_fps() { # Is stream token $1 selectable for model $2? stream_valid_for_model() { - local s=$1 model=$2 t - for t in ${MODEL_STREAMS[$model]}; do + local s=$1 model=$2 streams=${MODEL_STREAMS[$2]:-} t + [ -n "$streams" ] || return 1 + for t in $streams; do [ "$t" = "$s" ] && return 0 done return 1 From dbcebd9dfe8d91108aeb8f58655a8e0d12fe0f9c Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Wed, 26 Aug 2026 16:47:52 +0800 Subject: [PATCH 14/17] script: mc-setup: Trim whitespaces between and within stream TOKEN There might be unintentional white space when running script, such as stream=[depth], [rgb]; or stream=[depth m res=xxx]. Add handling to trim white spaces unless intentional whitespace that is within quote, such as format='Z16 '. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 908e540c..48d72c9b 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -995,6 +995,7 @@ else stream_specs=${arg#*,stream=} arg=${arg%%,stream=*} while [ -n "$stream_specs" ]; do + stream_specs=${stream_specs#"${stream_specs%%[![:space:]]*}"} if [[ $stream_specs =~ ^\[([^][]+)\](,(.*))?$ ]]; then stream_spec=${BASH_REMATCH[1]} stream_specs=${BASH_REMATCH[3]} @@ -1003,6 +1004,11 @@ else fi IFS=',' read -ra stream_parts <<<"$stream_spec" + for stream_part_idx in "${!stream_parts[@]}"; do + stream_part=${stream_parts[$stream_part_idx]} + stream_part=${stream_part#"${stream_part%%[![:space:]]*}"} + stream_parts[$stream_part_idx]=${stream_part%"${stream_part##*[![:space:]]}"} + done s=${stream_parts[0]} is_known_stream "$s" || die "unknown stream '$s' in '$stream_spec'" [ -z "${arg_stream_res[$s]+x}" ] && \ From 28100cf72e9a4c46291c4787204825b65a1cd803 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Wed, 26 Aug 2026 17:03:15 +0800 Subject: [PATCH 15/17] script: mc-setup: Fix comment block Remove STREAM-MAJOR comments. Remove unused variable. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 48d72c9b..6fb0344e 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -632,20 +632,22 @@ print_topology() { # [TOKEN,res=WxH,format=MBUS_CODE,fps=FPS] ... # # TOKEN is only applicable for multi-stream sensors as specified in MODEL_STREAMS. -# Other 2D sensors do not need stream=, it is default to `single`. +# Other 2D sensors do not need stream=, they default to `single`. # # D4xx defaults to depth,rgb when no stream is specified. # # When des= is omitted, des=0 is assumed (matches the legacy single-DES CLI). # -# Capture-node layout (per DES) -- STREAM-MAJOR: -# csi2_pad = STREAM_NODE[s] * CSI2_STREAM_STRIDE + l +# Capture-node layout (per DES): +# csi2_pad = STREAM_CAPTURE_BASE[s] + +# ((l + STREAM_LINK_ROTATION[s]) % CSI2_NODE_BANK_SIZE) # node = CAPTURE_BASE[d] + csi2_pad -# This keeps all D4XX streams within eight capture nodes using the permutation -# documented above. Streams that resolve to the same node cannot be enabled -# together and are rejected. For 1-stream sensors like isx031, links land on -# base+0..3 directly. The CSI2 RX cap is IPU*_NR_OF_CSI2_SRC_PADS; set -# IPU_CSI2_SRC_PADS to match (commonly 8 or 16). +# This places each stream in its configured capture bank and rotates selected +# streams across links using the permutation documented above. Streams that +# resolve to the same node cannot be enabled together and are rejected. For +# 1-stream sensors like isx031, links land on base+0..3 directly. The CSI2 RX +# cap is IPU*_NR_OF_CSI2_SRC_PADS; set IPU_CSI2_SRC_PADS to match (commonly 8 +# or 16). # # v4l2 source_stream tag at the deserializer source pad / CSI2 sink pad is # allocated separately as a compact per-DES sequential id (0..3), because @@ -878,7 +880,7 @@ sensor_set_fps() { # Is stream token $1 selectable for model $2? stream_valid_for_model() { - local s=$1 model=$2 streams=${MODEL_STREAMS[$2]:-} t + local s=$1 streams=${MODEL_STREAMS[$2]:-} t [ -n "$streams" ] || return 1 for t in $streams; do [ "$t" = "$s" ] && return 0 From 4c936d625db33391599fcf049bbdbe7102a8f952 Mon Sep 17 00:00:00 2001 From: "Khai Wen, Ng" Date: Wed, 2 Sep 2026 00:12:12 +0800 Subject: [PATCH 16/17] script: mc-setup: Add Format mapping table for D4XX Depth MEDIA_BUS_FMT_FIXED caused mismatch with video node where Z16 is mapped to UYVY8_1X16 due to patch 0006. Add a STREAM_FORMAT_MAP table that specifically map depth stream FIXED format as UYVY8_1X16 throughout the pipeline. To add new mapping, follow sensor_stream_format syntax. Signed-off-by: Khai Wen, Ng --- script/acpi/mc-setup.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/script/acpi/mc-setup.sh b/script/acpi/mc-setup.sh index 6fb0344e..58957623 100755 --- a/script/acpi/mc-setup.sh +++ b/script/acpi/mc-setup.sh @@ -186,6 +186,10 @@ declare -A MBUS_TO_PIXFMT=( ) mbus_to_pixfmt() { echo "${MBUS_TO_PIXFMT[$1]:-}"; } +declare -A STREAM_FORMAT_MAP=( + [d4xx_depth_FIXED]=UYVY8_1X16 +) + # ============================================================================= # end of USER CONFIGURATION # ============================================================================= @@ -1123,6 +1127,7 @@ fi # effective format/size change, an unsupported or omitted FPS uses the largest # FPS advertised for the new mode. declare -A CFG_STREAM_FMT=() +declare -A CFG_STREAM_PIXFMT=() declare -A CFG_STREAM_SIZE=() declare -A CFG_STREAM_FPS=() declare -A CFG_STREAM_FPS_APPLY=() @@ -1147,7 +1152,10 @@ for k in "${!CFG_LINKS[@]}"; do validated=$(sensor_validate_format_size "$model" "$cam" "$s" "$sid" \ "$requested_fmt" "$requested_size" "$detected_fmt" "$detected_size" \ "DES${d} link ${l} stream ${s}") - read -r CFG_STREAM_FMT["${k}_${s}"] CFG_STREAM_SIZE["${k}_${s}"] <<<"$validated" + read -r selected_fmt CFG_STREAM_SIZE["${k}_${s}"] <<<"$validated" + CFG_STREAM_PIXFMT["${k}_${s}"]=$(mbus_to_pixfmt "$selected_fmt") + format_key="${model}_${s}_${selected_fmt}" + CFG_STREAM_FMT["${k}_${s}"]=${STREAM_FORMAT_MAP[$format_key]:-$selected_fmt} format_size_changed=0 if [ "${CFG_STREAM_FMT["${k}_${s}"]}" != "$detected_fmt" ] || \ [ "${CFG_STREAM_SIZE["${k}_${s}"]}" != "$detected_size" ]; then @@ -1385,7 +1393,7 @@ for k in "${!CFG_LINKS[@]}"; do d=${CFG_DES[$k]} for s in ${CFG_STREAMS[$k]}; do node=$(( CAPTURE_BASE[d] + CSI2_PAD["${k}_${s}"] )) - pixfmt=$(mbus_to_pixfmt "${CFG_STREAM_FMT["${k}_${s}"]}") + pixfmt=${CFG_STREAM_PIXFMT["${k}_${s}"]} [ -z "$pixfmt" ] && continue size=${CFG_STREAM_SIZE["${k}_${s}"]} w=${size%x*} From fa9bdf53d9979e998291050d53986372b9abb0b0 Mon Sep 17 00:00:00 2001 From: "Seng Guan, Chng" Date: Wed, 2 Sep 2026 10:14:56 +0800 Subject: [PATCH 17/17] Update ASL based on LGE requirement ASL update. Change 3 D3 cameras from channel 0,1 to channel 1,2. Change d457 camera from DES1 channel 2 to DES 1 channel 1. Signed-off-by: Seng Guan, Chng --- .../3_d3_isx031_1_d457_frame_sync.asl | 75 +++++++++---------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/acpi/ipu7/robinson_bay/3_d3_isx031_1_d457_frame_sync.asl b/acpi/ipu7/robinson_bay/3_d3_isx031_1_d457_frame_sync.asl index 19c233f7..17d82898 100644 --- a/acpi/ipu7/robinson_bay/3_d3_isx031_1_d457_frame_sync.asl +++ b/acpi/ipu7/robinson_bay/3_d3_isx031_1_d457_frame_sync.asl @@ -64,8 +64,8 @@ * Make sure DESCH_CH, DESCH_SER, DESCH_CAM, DESCH_CH_PATH, DESCH_SER_PATH, * DESCH_SER_REF, DESCH_SER_GPIOREF are all updated if connection changed. * - * 3x D3 ISX031 on MIPI-0 (0, 90, 270), --> DES0, channel 0,1,3 : frame sync enabled - * 1x RealSense on MIPI-2 (180) --> DES1, channel 2 : frame sync disabled + * 3x D3 ISX031 on MIPI-0 (90, 180, 270), --> DES0, channel 1,2,3 : frame sync enabled + * 1x RealSense on MIPI-2 (90) --> DES1, channel 1 : frame sync disabled * */ @@ -94,22 +94,21 @@ DefinitionBlock ("", "SSDT", 2, "", "IMG_ROB", 0x20260827) #define DES_FSIN_GPIO_PIN 7 #include "_des_common_max96724.asl" - // Channel 0 (D3 MFP8 fsync) - #define DESCH_LINK_NUM 0 - #define DESCH_CH CH00 - #define DESCH_SER SER0 - #define DESCH_CAM CAM0 + // Channel 1/acpi 2 (D3 MFP8 fsync) + #define DESCH_CH CH01 + #define DESCH_SER SER1 + #define DESCH_CAM CAM1 + #define DESCH_CH_PATH "\\_SB.PC00.DES0.CH01" + #define DESCH_SER_PATH "\\_SB.PC00.DES0.CH01.SER1" + #define DESCH_SER_REF \_SB.PC00.DES0.CH01.SER1 + #define DESCH_LINK_NUM 1 #define DESCH_SER_I2C 0x40 - #define DESCH_CH_PATH "\\_SB.PC00.DES0.CH00" - #define DESCH_SER_PATH "\\_SB.PC00.DES0.CH00.SER0" - #define DESCH_SER_REF \_SB.PC00.DES0.CH00.SER0 - #define DESCH_SER_GPIOREF ^^SER0 - #define CAM_ALIAS 0x54 - #define CAM_LANES 4 + #define DESCH_SER_GPIOREF ^^SER1 #define DESCH_SER_EXTRA_GPIO_PIN 8 #define DESCH_SER_FSYNC_RX_ID 7 + #define CAM_ALIAS 0x55 + #define CAM_LANES 4 #include "_des_ch_common_isx031.asl" - #undef DESCH_CH #undef DESCH_SER #undef DESCH_CAM @@ -128,19 +127,19 @@ DefinitionBlock ("", "SSDT", 2, "", "IMG_ROB", 0x20260827) #undef CAM_ALIAS #undef CAM_LANES - // Channel 1 (D3 MFP8 fsync) - #define DESCH_CH CH01 - #define DESCH_SER SER1 - #define DESCH_CAM CAM1 - #define DESCH_CH_PATH "\\_SB.PC00.DES0.CH01" - #define DESCH_SER_PATH "\\_SB.PC00.DES0.CH01.SER1" - #define DESCH_SER_REF \_SB.PC00.DES0.CH01.SER1 - #define DESCH_LINK_NUM 1 + // Channel 2/acpi 3 (D3 MFP8 fsync) + #define DESCH_CH CH02 + #define DESCH_SER SER2 + #define DESCH_CAM CAM2 + #define DESCH_CH_PATH "\\_SB.PC00.DES0.CH02" + #define DESCH_SER_PATH "\\_SB.PC00.DES0.CH02.SER2" + #define DESCH_SER_REF \_SB.PC00.DES0.CH02.SER2 + #define DESCH_LINK_NUM 2 #define DESCH_SER_I2C 0x40 - #define DESCH_SER_GPIOREF ^^SER1 + #define DESCH_SER_GPIOREF ^^SER2 #define DESCH_SER_EXTRA_GPIO_PIN 8 #define DESCH_SER_FSYNC_RX_ID 7 - #define CAM_ALIAS 0x55 + #define CAM_ALIAS 0x56 #define CAM_LANES 4 #include "_des_ch_common_isx031.asl" #undef DESCH_CH @@ -161,19 +160,19 @@ DefinitionBlock ("", "SSDT", 2, "", "IMG_ROB", 0x20260827) #undef CAM_ALIAS #undef CAM_LANES - // Channel 3 (D3 MFP8 fsync) + // Channel 3/acpi 4 (D3 MFP8 fsync) #define DESCH_CH CH03 #define DESCH_SER SER3 #define DESCH_CAM CAM3 #define DESCH_CH_PATH "\\_SB.PC00.DES0.CH03" #define DESCH_SER_PATH "\\_SB.PC00.DES0.CH03.SER3" #define DESCH_SER_REF \_SB.PC00.DES0.CH03.SER3 - #define DESCH_SER_EXTRA_GPIO_PIN 8 - #define DESCH_SER_FSYNC_RX_ID 7 #define DESCH_LINK_NUM 3 #define DESCH_SER_I2C 0x40 #define DESCH_SER_GPIOREF ^^SER3 - #define CAM_ALIAS 0x56 + #define DESCH_SER_EXTRA_GPIO_PIN 8 + #define DESCH_SER_FSYNC_RX_ID 7 + #define CAM_ALIAS 0x57 #define CAM_LANES 4 #include "_des_ch_common_isx031.asl" #undef DESCH_CH @@ -229,22 +228,22 @@ DefinitionBlock ("", "SSDT", 2, "", "IMG_ROB", 0x20260827) // #define DES_FSIN_GPIO_PIN 7 #include "_des_common_max96724.asl" - // Channel 2 (D457 MFP0 fsync) - #define DESCH_LINK_NUM 2 - #define DESCH_CH CH02 - #define DESCH_SER SER2 - #define DESCH_CAM CAM2 + // Channel 1 (D457 MFP0 fsync) + #define DESCH_LINK_NUM 1 + #define DESCH_CH CH01 + #define DESCH_SER SER1 + #define DESCH_CAM CAM1 #define DESCH_SER_I2C 0x40 - #define DESCH_CH_PATH "\\_SB.PC00.DES1.CH02" - #define DESCH_SER_PATH "\\_SB.PC00.DES1.CH02.SER2" - #define DESCH_SER_REF \_SB.PC00.DES1.CH02.SER2 - #define DESCH_SER_GPIOREF ^^SER2 + #define DESCH_CH_PATH "\\_SB.PC00.DES1.CH01" + #define DESCH_SER_PATH "\\_SB.PC00.DES1.CH01.SER1" + #define DESCH_SER_REF \_SB.PC00.DES1.CH01.SER1 + #define DESCH_SER_GPIOREF ^^SER1 #define DESCH_SER_X_VC Package () { 0 } #define DESCH_SER_Y_VC Package () { 1 } #define DESCH_SER_Z_VC Package () { 2 } #define DESCH_SER_U_VC Package () { 3 } // #define DESCH_SER_FSYNC_RX_ID 0 - #define CAM_ALIAS 0x54 + #define CAM_ALIAS 0x55 #define CAM_LANES 2 #include "_des_ch_common_d457.asl" #undef DESCH_CH