* Re: [PATCH v2 1/3] dt-bindings: power: limits: Describe Qualcomm SPEL hardware
From: Daniel Lezcano @ 2026-06-24 20:41 UTC (permalink / raw)
To: Krzysztof Kozlowski, Manaf Meethalavalappu Pallikunhi
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Rafael J. Wysocki,
Bjorn Andersson, Konrad Dybcio, Gaurav Kohli, linux-arm-msm,
devicetree, linux-kernel, linux-pm
In-Reply-To: <d0528339-8be9-4895-a054-625df96ca926@kernel.org>
Hi Krzysztof,
Le 24/06/2026 à 12:45, Krzysztof Kozlowski a écrit :
> On 23/06/2026 11:47, Manaf Meethalavalappu Pallikunhi wrote:
>> Hi Krzysztof,
>>
>>
>> On 6/22/2026 5:58 PM, Krzysztof Kozlowski wrote:
>>> On Sat, Jun 20, 2026 at 02:09:08AM +0530, Manaf Meethalavalappu Pallikunhi wrote:
>>>> The Qualcomm SoC Power and Electrical Limits (SPEL) provides hardware
>>>> based power monitoring and limiting capabilities for various domains.
>>>>
>>>> Add a DeviceTree binding to describe the SPEL block on Qualcomm's SoC.
>>>>
>>>> Signed-off-by: Manaf Meethalavalappu Pallikunhi <manaf.pallikunhi@oss.qualcomm.com>
>>>> ---
>>>> .../bindings/power/limits/qcom,spel.yaml | 47 ++++++++++++++++++++++
>>>> MAINTAINERS | 6 +++
>>>> 2 files changed, 53 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/power/limits/qcom,spel.yaml b/Documentation/devicetree/bindings/power/limits/qcom,spel.yaml
>>>
>>> What is "limits" directory for? What sort of class of devices fit there?
>>
>> Added for devices that integrate with the powercap framework (exposed
>> via sys/class/powercap). These devices are responsible for enforcing and
>
> That's a driver answer. I asked about class of devices. powercap
> framework is Linux thing, not a class of devices.
>
> Please describe hardware, not Linux frameworks.>>> monitoring power consumption limits across different domains, such as
>> the system, SoC, or specific subsystems. Any other better directory ?
>
> I don't know what is this hardware doing and commit msg is quite short
> on explanation. Power monitoring is usually hwmon, but probably this is
> not a hwmon.
Right, it is relatively new in the device tree bindings. There is the
Intel RAPL which is the same device but it does not belong to the DT
namespace.
RAPL : Running Average Power Limit
SPEL : SoC Power and Electrical Limits
It allows power capping and read the average power consumption for a
specific device (or/and an energy counter)
Basically you can set a power constraint (power limit) to a device and
this one won't consume more than that power (the power limitation
strategy is managed under the hood by the firmware depending on the
device - lower OPP, idle injection, modem weaker signal, etc ...).
The RAPL or the SPEL have a hierarchical power limitation. For example:
SoC
|
------------------------
| |
Cluster0 Cluster1
| |
----------------- -----------------
| | | | | | | |
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
If you specify a power limit to 'SoC', then the power consumption of
Cluster0 + Cluster1 <= SoC
If Cluster0 power consumption decreases, then Cluster1 is allowed to use
more power until Cluster0 + Cluster1 <= SoC
For me it sounds reasonable to put the device description under power/limits
^ permalink raw reply
* [PATCH v6 9/9] arm64: dts: imx8qxp-mek: add parallel ov5640 camera support
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Add parallel ov5640 nodes in imx8qxp-mek and create overlay file to enable
it because it can work at two mode: MIPI CSI and parallel mode.
Reviewed-by: Guoniu Zhou <guoniu.zhou@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
changes in v6
- add Guoniu's reviewed-by tags
changes in v4
- add hsync-active = <1>
changes in v3
- replace csi with cpi.
- use imx8qxp-mek-ov5640-cpi.dtso since csi use imx8qxp-mek-ov5640-csi.dtso
change in v2
- move ov5640 part to overlay file
- rename to imx8qxp-mek-ov5640-parallel.dtso
- remove data-lanes
---
arch/arm64/boot/dts/freescale/Makefile | 3 +
.../boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso | 83 ++++++++++++++++++++++
2 files changed, 86 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 001ca3a12c0ae..3b9e9844f11ef 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -554,6 +554,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek-pcie-ep.dtb
imx8qxp-mek-ov5640-csi-dtbs := imx8qxp-mek.dtb imx8qxp-mek-ov5640-csi.dtbo
dtb-${CONFIG_ARCH_MXC} += imx8qxp-mek-ov5640-csi.dtb
+imx8qxp-mek-ov5640-cpi-dtbs := imx8qxp-mek.dtb imx8qxp-mek-ov5640-cpi.dtbo
+dtb-${CONFIG_ARCH_MXC} += imx8qxp-mek-ov5640-cpi.dtb
+
dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqp-mba8xx.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso b/arch/arm64/boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso
new file mode 100644
index 0000000000000..9fbdd798f17d6
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/imx8-lpcg.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/media/video-interfaces.h>
+#include <dt-bindings/pinctrl/pads-imx8qxp.h>
+
+&cm40_i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ov5640_pi: camera@3c {
+ compatible = "ovti,ov5640";
+ reg = <0x3c>;
+ clocks = <&pi0_misc_lpcg IMX_LPCG_CLK_0>;
+ clock-names = "xclk";
+ assigned-clocks = <&pi0_misc_lpcg IMX_LPCG_CLK_0>;
+ assigned-clock-rates = <24000000>;
+ AVDD-supply = <®_2v8>;
+ DOVDD-supply = <®_1v8>;
+ DVDD-supply = <®_1v5>;
+ pinctrl-0 = <&pinctrl_parallel_cpi>;
+ pinctrl-names = "default";
+ powerdown-gpios = <&lsio_gpio3 2 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&lsio_gpio3 3 GPIO_ACTIVE_LOW>;
+
+ port {
+ ov5640_pi_ep: endpoint {
+ bus-type = <MEDIA_BUS_TYPE_PARALLEL>;
+ bus-width = <8>;
+ hsync-active = <1>;
+ pclk-sample = <1>;
+ remote-endpoint = <¶llel_cpi_in>;
+ vsync-active = <0>;
+ };
+ };
+ };
+};
+
+&iomuxc {
+ pinctrl_parallel_cpi: parallelcpigrp {
+ fsl,pins = <
+ IMX8QXP_CSI_D00_CI_PI_D02 0xc0000041
+ IMX8QXP_CSI_D01_CI_PI_D03 0xc0000041
+ IMX8QXP_CSI_D02_CI_PI_D04 0xc0000041
+ IMX8QXP_CSI_D03_CI_PI_D05 0xc0000041
+ IMX8QXP_CSI_D04_CI_PI_D06 0xc0000041
+ IMX8QXP_CSI_D05_CI_PI_D07 0xc0000041
+ IMX8QXP_CSI_D06_CI_PI_D08 0xc0000041
+ IMX8QXP_CSI_D07_CI_PI_D09 0xc0000041
+
+ IMX8QXP_CSI_MCLK_CI_PI_MCLK 0xc0000041
+ IMX8QXP_CSI_PCLK_CI_PI_PCLK 0xc0000041
+ IMX8QXP_CSI_HSYNC_CI_PI_HSYNC 0xc0000041
+ IMX8QXP_CSI_VSYNC_CI_PI_VSYNC 0xc0000041
+ IMX8QXP_CSI_EN_LSIO_GPIO3_IO02 0xc0000041
+ IMX8QXP_CSI_RESET_LSIO_GPIO3_IO03 0xc0000041
+ >;
+ };
+};
+
+&isi {
+ status = "okay";
+};
+
+¶llel_cpi {
+ status = "okay";
+
+ ports {
+ port@0 {
+ parallel_cpi_in: endpoint {
+ hsync-active = <1>;
+ remote-endpoint = <&ov5640_pi_ep>;
+ };
+ };
+ };
+};
--
2.43.0
^ permalink raw reply related
* [PATCH v6 8/9] arm64: dts: imx8: add camera parallel interface (CPI) node
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Add camera parallel interface (CPI) node.
Reviewed-by: Guoniu Zhou <guoniu.zhou@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
changes in v6
- add Guoniu Zhou's review by
changes in v4
- none
changes in v3
- replace csi with cpi.
changes in v2
- update compatible string to match binding's change
---
arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi | 13 +++++++++++
arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi | 27 +++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi
index a72b2f1c4a1b2..b504f99f6acdb 100644
--- a/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi
@@ -222,6 +222,19 @@ irqsteer_parallel: irqsteer@58260000 {
status = "disabled";
};
+ parallel_cpi: cpi@58261000 {
+ compatible = "fsl,imx8qxp-pcif";
+ reg = <0x58261000 0x1000>;
+ clocks = <&pi0_pxl_lpcg IMX_LPCG_CLK_0>,
+ <&pi0_ipg_lpcg IMX_LPCG_CLK_4>;
+ clock-names = "pixel", "ipg";
+ assigned-clocks = <&clk IMX_SC_R_PI_0 IMX_SC_PM_CLK_PER>;
+ assigned-clock-parents = <&clk IMX_SC_R_PI_0_PLL IMX_SC_PM_CLK_PLL>;
+ assigned-clock-rates = <160000000>;
+ power-domains = <&pd IMX_SC_R_PI_0>;
+ status = "disabled";
+ };
+
pi0_ipg_lpcg: clock-controller@58263004 {
compatible = "fsl,imx8qxp-lpcg";
reg = <0x58263004 0x4>;
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi
index 232cf25dadfcd..5aae15540d6cb 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi
@@ -62,6 +62,14 @@ isi_in_2: endpoint {
remote-endpoint = <&mipi_csi0_out>;
};
};
+
+ port@4 {
+ reg = <4>;
+
+ isi_in_4: endpoint {
+ remote-endpoint = <¶llel_cpi_out>;
+ };
+ };
};
};
@@ -95,3 +103,22 @@ &jpegenc {
&mipi_csi_1 {
status = "disabled";
};
+
+¶llel_cpi {
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ };
+
+ port@1 {
+ reg = <1>;
+
+ parallel_cpi_out: endpoint {
+ remote-endpoint = <&isi_in_4>;
+ };
+ };
+ };
+};
--
2.43.0
^ permalink raw reply related
* [PATCH v6 7/9] media: nxp: add V4L2 subdev driver for camera parallel interface (CPI)
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel, Alice Yuan, Robert Chiras, Zhipeng Wang
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Alice Yuan <alice.yuan@nxp.com>
Add a V4L2 sub-device driver for the CPI controller found on i.MX8QXP,
i.MX8QM, and i.MX93 SoCs. This controller supports parallel camera sensors
and enables image data capture through a parallel interface.
Signed-off-by: Alice Yuan <alice.yuan@nxp.com>
Signed-off-by: Robert Chiras <robert.chiras@nxp.com>
Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change in v6
- Don't use subdev_1to1
- use new api media_async_register_subdev()
- remove used switch -case
Change in v5
- Use subdev_1to1 register function
- Use v4l2_subdev_get_frame_desc_passthrough
- Use dwc csi2 similar logic enable/disable stream
- Add route settup at imx_cpi_init_state()
- Remove V2 register layout support, add it later
change in v4
- remove unnecesary header file.
- use devm_bulk_clk_get().
- update kConfig i.MX8/i.MX9
- Remove define IMX_CPI_DEF_PIX_WIDTH ..., which used once only
- drop get_interface_ctrl_reg1_param
- drop uv-swap
- drop imx_cpi_link_setup by use immutable link.
- use enable/disable_stream() replace depericated .s_stream.
- remove dbg print and reg dump functions.
- use goto/.remove() to do manual cleanup.
- remove imx93 support. Add it later.
change in v3
- replace csi with cpi
- use __free(fwnode_handle) to simpilfy code
- remove imx91 driver data, which is the same as imx93
change in v2
- remove MODULE_ALIAS
- use devm_pm_runtime_enable() and cleanup remove function
- change output format to 1x16. controller convert 2x8 to 1x16 format
---
MAINTAINERS | 1 +
drivers/media/platform/nxp/Kconfig | 12 +
drivers/media/platform/nxp/Makefile | 1 +
drivers/media/platform/nxp/imx-parallel-cpi.c | 629 ++++++++++++++++++++++++++
4 files changed, 643 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 51d5c62e3fdea..045a06d0bb216 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16263,6 +16263,7 @@ F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
F: Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml
F: drivers/media/platform/nxp/imx-mipi-csis.c
+F: drivers/media/platform/nxp/imx-parallel-cpi.c
F: drivers/media/platform/nxp/imx7-media-csi.c
F: drivers/media/platform/nxp/imx8mq-mipi-csi2.c
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 40e3436669e21..90f7c792003f2 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -39,6 +39,18 @@ config VIDEO_IMX_MIPI_CSIS
Video4Linux2 sub-device driver for the MIPI CSI-2 CSIS receiver
v3.3/v3.6.3 found on some i.MX7 and i.MX8 SoCs.
+config VIDEO_IMX_PARALLEL_CPI
+ tristate "NXP i.MX8/i.MX9 Parallel CPI Driver"
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select V4L2_1TO1
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Video4Linux2 sub-device driver for PARALLEL CPI receiver found
+ on some iMX8 and iMX9 SoCs.
+
source "drivers/media/platform/nxp/imx8-isi/Kconfig"
# mem2mem drivers
diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
index 4d90eb7136525..5346919d2f108 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -7,5 +7,6 @@ obj-y += imx8-isi/
obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
+obj-$(CONFIG_VIDEO_IMX_PARALLEL_CPI) += imx-parallel-cpi.o
obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
diff --git a/drivers/media/platform/nxp/imx-parallel-cpi.c b/drivers/media/platform/nxp/imx-parallel-cpi.c
new file mode 100644
index 0000000000000..0f74b51608715
--- /dev/null
+++ b/drivers/media/platform/nxp/imx-parallel-cpi.c
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i.MX Parallel CPI receiver driver.
+ *
+ * Copyright 2019-2025 NXP
+ *
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+
+/* CI_PI INTERFACE CONTROL */
+#define IF_CTRL_REG_PL_ENABLE BIT(0)
+#define IF_CTRL_REG_PL_VALID BIT(1)
+#define IF_CTRL_REG_DATA_TYPE_SEL BIT(8)
+#define IF_CTRL_REG_DATA_TYPE(x) FIELD_PREP(GENMASK(13, 9), (x))
+
+#define DATA_TYPE_OUT_NULL 0x00
+#define DATA_TYPE_OUT_RGB 0x04
+#define DATA_TYPE_OUT_YUV444 0x08
+#define DATA_TYPE_OUT_YYU420_ODD 0x10
+#define DATA_TYPE_OUT_YYU420_EVEN 0x12
+#define DATA_TYPE_OUT_YYY_ODD 0x18
+#define DATA_TYPE_OUT_UYVY_EVEN 0x1a
+#define DATA_TYPE_OUT_RAW 0x1c
+
+#define IF_CTRL_REG_IF_FORCE_HSYNV_OVERRIDE 0x4
+#define IF_CTRL_REG_IF_FORCE_VSYNV_OVERRIDE 0x2
+#define IF_CTRL_REG_IF_FORCE_DATA_ENABLE_OVERRIDE 0x1
+
+/* CPI INTERFACE CONTROL REG */
+#define CPI_CTRL_REG_CPI_EN BIT(0)
+#define CPI_CTRL_REG_PIXEL_CLK_POL BIT(1)
+#define CPI_CTRL_REG_HSYNC_POL BIT(2)
+#define CPI_CTRL_REG_VSYNC_POL BIT(3)
+#define CPI_CTRL_REG_DE_POL BIT(4)
+#define CPI_CTRL_REG_PIXEL_DATA_POL BIT(5)
+#define CPI_CTRL_REG_CCIR_EXT_VSYNC_EN BIT(6)
+#define CPI_CTRL_REG_CCIR_EN BIT(7)
+#define CPI_CTRL_REG_CCIR_VIDEO_MODE BIT(8)
+#define CPI_CTRL_REG_CCIR_NTSC_EN BIT(9)
+#define CPI_CTRL_REG_CCIR_VSYNC_RESET_EN BIT(10)
+#define CPI_CTRL_REG_CCIR_ECC_ERR_CORRECT_EN BIT(11)
+#define CPI_CTRL_REG_HSYNC_FORCE_EN BIT(12)
+#define CPI_CTRL_REG_VSYNC_FORCE_EN BIT(13)
+#define CPI_CTRL_REG_GCLK_MODE_EN BIT(14)
+#define CPI_CTRL_REG_VALID_SEL BIT(15)
+#define CPI_CTRL_REG_RAW_OUT_SEL BIT(16)
+#define CPI_CTRL_REG_HSYNC_OUT_SEL BIT(17)
+#define CPI_CTRL_REG_HSYNC_PULSE(x) FIELD_PREP(GENMASK(21, 19), (x))
+#define CPI_CTRL_REG_UV_SWAP_EN BIT(22)
+#define CPI_CTRL_REG_DATA_TYPE_IN(x) FIELD_PREP(GENMASK(26, 23), (x))
+#define CPI_CTRL_REG_MASK_VSYNC_COUNTER(x) FIELD_PREP(GENMASK(28, 27), (x))
+#define CPI_CTRL_REG_SOFTRST BIT(31)
+
+/* CPI INTERFACE STATUS */
+#define CPI_STATUS_FIELD_TOGGLE BIT(0)
+#define CPI_STATUS_ECC_ERROR BIT(1)
+
+/* CPI INTERFACE CONTROL REG1 */
+#define CPI_CTRL_REG1_PIXEL_WIDTH(v) FIELD_PREP(GENMASK(15, 0), (v))
+#define CPI_CTRL_REG1_VSYNC_PULSE(v) FIELD_PREP(GENMASK(31, 16), (v))
+
+#define CPI_CTRL_V2_REG1_PIXEL_WIDTH(v) FIELD_PREP(GENMASK(16, 0), (v))
+#define CPI_CTRL_V2_REG1_VSYNC_PULSE(v) FIELD_PREP(GENMASK(31, 16), (v))
+
+/* Need match field DATA_TYPE_IN definition at CPI CTRL register */
+enum cpi_in_data_type {
+ CPI_IN_DT_UYVY_BT656_8 = 0x0,
+ CPI_IN_DT_UYVY_BT656_10,
+ CPI_IN_DT_RGB_8,
+ CPI_IN_DT_BGR_8,
+ CPI_IN_DT_YVYU_8 = 0x5,
+ CPI_IN_DT_YUV_8,
+ CPI_IN_DT_RAW_8 = 0x9,
+ CPI_IN_DT_RAW_10,
+};
+
+enum {
+ PI_GATE_CLOCK_MODE,
+ PI_CCIR_MODE,
+};
+
+enum {
+ PI_V1,
+};
+
+struct imx_cpi_plat_data {
+ u32 version;
+ u32 if_ctrl_reg;
+ u32 interface_status;
+ u32 interface_ctrl_reg;
+ u32 interface_ctrl_reg1;
+};
+
+struct imx_cpi_device {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk_bulk_data *clks;
+ int num_clks;
+
+ struct v4l2_subdev sd;
+
+ const struct imx_cpi_plat_data *pdata;
+
+ u32 enabled_streams;
+ u8 mode;
+};
+
+struct imx_cpi_pix_format {
+ u32 code;
+ u32 output;
+ u32 data_type;
+ u8 width;
+};
+
+static const struct imx_cpi_pix_format imx_cpi_formats[] = {
+ /* YUV formats. */
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .output = MEDIA_BUS_FMT_UYVY8_1X16,
+ .data_type = CPI_IN_DT_UYVY_BT656_8,
+ .width = 16,
+ }, {
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .output = MEDIA_BUS_FMT_YUYV8_1X16,
+ .data_type = CPI_IN_DT_YVYU_8,
+ .width = 16,
+ },
+};
+
+static const struct imx_cpi_plat_data imx8qxp_pdata = {
+ .version = PI_V1,
+ .if_ctrl_reg = 0x0,
+ .interface_status = 0x20,
+ .interface_ctrl_reg = 0x10,
+ .interface_ctrl_reg1 = 0x30,
+};
+
+static const struct imx_cpi_pix_format *find_imx_cpi_format(u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx_cpi_formats); i++)
+ if (code == imx_cpi_formats[i].code)
+ return &imx_cpi_formats[i];
+
+ return NULL;
+}
+
+static void imx_cpi_sw_reset(struct imx_cpi_device *pcpidev)
+{
+ const struct imx_cpi_plat_data *pdata = pcpidev->pdata;
+ u32 val;
+
+ /* Softwaret Reset */
+ val = readl(pcpidev->regs + pdata->interface_ctrl_reg);
+ val |= CPI_CTRL_REG_SOFTRST;
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg);
+
+ fsleep(500);
+ val = readl(pcpidev->regs + pdata->interface_ctrl_reg);
+ val &= ~CPI_CTRL_REG_SOFTRST;
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg);
+}
+
+static void imx_cpi_hw_config(struct imx_cpi_device *pcpidev,
+ const struct imx_cpi_pix_format *pcpidev_fmt)
+{
+ u32 flags = pcpidev->sd.entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK].vep.bus.parallel.flags;
+ const struct imx_cpi_plat_data *pdata = pcpidev->pdata;
+ bool hsync_pol = flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+ bool vsync_pol = flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+ u32 val;
+
+ /* Software Reset */
+ imx_cpi_sw_reset(pcpidev);
+
+ /* Config PL Data Type */
+ val = IF_CTRL_REG_DATA_TYPE(DATA_TYPE_OUT_YUV444);
+ val |= IF_CTRL_REG_PL_ENABLE | IF_CTRL_REG_PL_VALID;
+ writel(val, pcpidev->regs + pdata->if_ctrl_reg);
+
+ /* Config CTRL REG */
+ val = CPI_CTRL_REG_HSYNC_FORCE_EN | CPI_CTRL_REG_VSYNC_FORCE_EN;
+
+ val |= CPI_CTRL_REG_DATA_TYPE_IN(pcpidev_fmt->data_type) |
+ FIELD_PREP(CPI_CTRL_REG_HSYNC_POL, hsync_pol) |
+ FIELD_PREP(CPI_CTRL_REG_VSYNC_POL, vsync_pol) |
+ FIELD_PREP(CPI_CTRL_REG_PIXEL_CLK_POL, 0) |
+ CPI_CTRL_REG_MASK_VSYNC_COUNTER(3) |
+ CPI_CTRL_REG_HSYNC_PULSE(2);
+
+ if (pcpidev_fmt->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+ pcpidev_fmt->code == MEDIA_BUS_FMT_UYVY8_2X8)
+ val |= CPI_CTRL_REG_UV_SWAP_EN;
+
+ if (pcpidev->mode == PI_GATE_CLOCK_MODE) {
+ val |= CPI_CTRL_REG_GCLK_MODE_EN;
+ } else if (pcpidev->mode == PI_CCIR_MODE) {
+ val |= (CPI_CTRL_REG_CCIR_EN |
+ CPI_CTRL_REG_CCIR_VSYNC_RESET_EN |
+ CPI_CTRL_REG_CCIR_EXT_VSYNC_EN |
+ CPI_CTRL_REG_CCIR_ECC_ERR_CORRECT_EN);
+ }
+
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg);
+}
+
+static void imx_cpi_config_ctrl_reg1(struct imx_cpi_device *pcpidev,
+ const struct v4l2_mbus_framefmt *format)
+{
+ const struct imx_cpi_plat_data *pdata = pcpidev->pdata;
+ u32 pixel_width;
+ u32 vsync_pulse;
+ u32 val;
+
+ pixel_width = format->width - 1;
+ vsync_pulse = format->width << 1;
+
+ val = CPI_CTRL_REG1_PIXEL_WIDTH(pixel_width) |
+ CPI_CTRL_REG1_VSYNC_PULSE(vsync_pulse);
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg1);
+}
+
+static void imx_cpi_enable(struct imx_cpi_device *pcpidev)
+{
+ const struct imx_cpi_plat_data *pdata = pcpidev->pdata;
+ u32 val;
+
+ /* Enable CPI */
+ val = readl(pcpidev->regs + pdata->interface_ctrl_reg);
+ val |= CPI_CTRL_REG_CPI_EN;
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg);
+
+ /* Disable SYNC Force */
+ val = readl(pcpidev->regs + pdata->interface_ctrl_reg);
+ val &= ~(CPI_CTRL_REG_HSYNC_FORCE_EN | CPI_CTRL_REG_VSYNC_FORCE_EN);
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg);
+}
+
+static void imx_cpi_disable(struct imx_cpi_device *pcpidev)
+{
+ const struct imx_cpi_plat_data *pdata = pcpidev->pdata;
+ u32 val;
+
+ /* Enable Sync Force */
+ val = readl(pcpidev->regs + pdata->interface_ctrl_reg);
+ val |= CPI_CTRL_REG_HSYNC_FORCE_EN | CPI_CTRL_REG_VSYNC_FORCE_EN;
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg);
+
+ /* Disable CPI */
+ val = readl(pcpidev->regs + pdata->interface_ctrl_reg);
+ val &= ~CPI_CTRL_REG_CPI_EN;
+ writel(val, pcpidev->regs + pdata->interface_ctrl_reg);
+
+ /* Disable Pixel Link */
+ val = readl(pcpidev->regs + pdata->if_ctrl_reg);
+ val &= ~(IF_CTRL_REG_PL_VALID | IF_CTRL_REG_PL_ENABLE);
+ writel(val, pcpidev->regs + pdata->if_ctrl_reg);
+}
+
+static struct imx_cpi_device *sd_to_imx_cpi_device(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct imx_cpi_device, sd);
+}
+
+static const struct media_entity_operations imx_cpi_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+ .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+};
+
+static int imx_cpi_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct imx_cpi_pix_format const *pcpidev_fmt;
+ struct v4l2_mbus_framefmt *fmt;
+
+ /*
+ * The Parallel cpi can't transcode in any way, the source format
+ * can't be modified.
+ */
+ if (sdformat->pad == V4L2_SUBDEV_1TO1_PADS_SOURCE)
+ return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
+
+ pcpidev_fmt = find_imx_cpi_format(sdformat->format.code);
+ if (!pcpidev_fmt)
+ pcpidev_fmt = &imx_cpi_formats[0];
+
+ fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
+
+ fmt->code = pcpidev_fmt->code;
+ fmt->width = sdformat->format.width;
+ fmt->height = sdformat->format.height;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = sdformat->format.colorspace;
+ fmt->quantization = sdformat->format.quantization;
+ fmt->xfer_func = sdformat->format.xfer_func;
+ fmt->ycbcr_enc = sdformat->format.ycbcr_enc;
+
+ sdformat->format = *fmt;
+
+ /* Propagate the format from sink to source. */
+ fmt = v4l2_subdev_state_get_format(sd_state, V4L2_SUBDEV_1TO1_PADS_SOURCE);
+ *fmt = sdformat->format;
+
+ /* The format on the source pad might change due to unpacking. */
+ fmt->code = pcpidev_fmt->output;
+
+ return 0;
+}
+
+static int imx_cpi_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = V4L2_SUBDEV_1TO1_PADS_SINK,
+ .sink_stream = 0,
+ .source_pad = V4L2_SUBDEV_1TO1_PADS_SOURCE,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ };
+ struct v4l2_subdev_krouting routing = {
+ .len_routes = ARRAY_SIZE(routes),
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_state_get_format(state, 0);
+
+ fmt->code = imx_cpi_formats[0].code;
+ fmt->width = 1920;
+ fmt->height = 1080;
+
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(false,
+ fmt->colorspace,
+ fmt->ycbcr_enc);
+
+ return v4l2_subdev_set_routing_with_fmt(sd, state, &routing, fmt);
+}
+
+static int imx_cpi_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct imx_cpi_device *pcpidev = sd_to_imx_cpi_device(sd);
+ struct media_pad *sink_pad, *remote_pad;
+ struct device *dev = pcpidev->dev;
+ struct v4l2_subdev *remote_sd;
+ u64 mask;
+ int ret;
+
+ sink_pad = &sd->entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
+ remote_pad = media_pad_remote_pad_first(sink_pad);
+ remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+ mask = v4l2_subdev_state_xlate_streams(state, V4L2_SUBDEV_1TO1_PADS_SINK,
+ V4L2_SUBDEV_1TO1_PADS_SOURCE,
+ &streams_mask);
+
+ ret = v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
+ if (ret)
+ dev_err(dev, "failed to disable streams on remote subdev: %d\n", ret);
+
+ pcpidev->enabled_streams &= ~streams_mask;
+
+ if (!pcpidev->enabled_streams) {
+ imx_cpi_disable(pcpidev);
+ pm_runtime_put_autosuspend(dev);
+ }
+
+ return 0;
+}
+
+static int imx_cpi_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct imx_cpi_device *pcpidev = sd_to_imx_cpi_device(sd);
+ const struct imx_cpi_pix_format *pcpidev_fmt;
+ const struct v4l2_mbus_framefmt *format;
+ struct media_pad *sink_pad, *remote_pad;
+ struct device *dev = pcpidev->dev;
+ struct v4l2_subdev *remote_sd;
+ u64 mask;
+ int ret;
+
+ sink_pad = &sd->entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
+ remote_pad = media_pad_remote_pad_first(sink_pad);
+ remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+ mask = v4l2_subdev_state_xlate_streams(state, V4L2_SUBDEV_1TO1_PADS_SINK,
+ V4L2_SUBDEV_1TO1_PADS_SOURCE,
+ &streams_mask);
+
+ format = v4l2_subdev_state_get_format(state, V4L2_SUBDEV_1TO1_PADS_SINK);
+ pcpidev_fmt = find_imx_cpi_format(format->code);
+
+ if (!pcpidev->enabled_streams) {
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ imx_cpi_hw_config(pcpidev, pcpidev_fmt);
+ imx_cpi_config_ctrl_reg1(pcpidev, format);
+ imx_cpi_enable(pcpidev);
+ }
+
+ ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, mask);
+ if (ret)
+ goto err_cpi_stop;
+
+ pcpidev->enabled_streams |= streams_mask;
+
+ return 0;
+
+err_cpi_stop:
+ /* Stop CSI hardware if no streams are enabled */
+ if (!pcpidev->enabled_streams)
+ imx_cpi_disable(pcpidev);
+
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
+static int imx_cpi_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ /*
+ * The PARALLEL CPI can't transcode in any way, the source format
+ * is identical to the sink format.
+ */
+ if (code->pad == V4L2_SUBDEV_1TO1_PADS_SOURCE) {
+ struct v4l2_mbus_framefmt *fmt;
+
+ if (code->index > 0)
+ return -EINVAL;
+
+ fmt = v4l2_subdev_state_get_format(sd_state, code->pad);
+ code->code = fmt->code;
+ return 0;
+ }
+
+ if (code->pad != V4L2_SUBDEV_1TO1_PADS_SINK)
+ return -EINVAL;
+
+ if (code->index >= ARRAY_SIZE(imx_cpi_formats))
+ return -EINVAL;
+
+ code->code = imx_cpi_formats[code->index].code;
+
+ return 0;
+}
+
+static int
+imx_cpi_set_pad_by_ep(struct v4l2_subdev *sd, struct media_pad *pad)
+{
+ struct v4l2_fwnode_endpoint *vep = &pad->vep;
+
+ if (vep->base.port == V4L2_SUBDEV_1TO1_PADS_SINK) {
+ /* Sink port */
+
+ if (vep->bus_type != V4L2_MBUS_PARALLEL)
+ return -EINVAL;
+
+ pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+
+ return 0;
+ }
+
+ if (vep->base.port == V4L2_SUBDEV_1TO1_PADS_SOURCE) {
+ /* Source port */
+ pad->flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static const struct v4l2_subdev_video_ops imx_cpi_video_ops = {
+ .s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops imx_cpi_pad_ops = {
+ .enum_mbus_code = imx_cpi_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = imx_cpi_set_fmt,
+ .get_frame_desc = v4l2_subdev_get_frame_desc_passthrough,
+ .enable_streams = imx_cpi_enable_streams,
+ .disable_streams = imx_cpi_disable_streams,
+};
+
+static const struct v4l2_subdev_ops imx_cpi_subdev_ops = {
+ .pad = &imx_cpi_pad_ops,
+ .video = &imx_cpi_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx_cpi_internal_ops = {
+ .init_state = imx_cpi_init_state,
+ .set_pad_by_ep = imx_cpi_set_pad_by_ep,
+};
+
+/* ----------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+static int imx_cpi_runtime_suspend(struct device *dev)
+{
+ struct imx_cpi_device *pcpidev = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(pcpidev->num_clks, pcpidev->clks);
+
+ return 0;
+}
+
+static int imx_cpi_runtime_resume(struct device *dev)
+{
+ struct imx_cpi_device *pcpidev = dev_get_drvdata(dev);
+
+ return clk_bulk_prepare_enable(pcpidev->num_clks, pcpidev->clks);
+}
+
+static const struct dev_pm_ops imx_cpi_pm_ops = {
+ RUNTIME_PM_OPS(imx_cpi_runtime_suspend, imx_cpi_runtime_resume, NULL)
+};
+
+static void imx_cpi_remove(struct platform_device *pdev)
+{
+ struct imx_cpi_device *pcpidev = platform_get_drvdata(pdev);
+
+ media_async_subdev_cleanup(&pcpidev->sd);
+}
+
+static int imx_cpi_probe(struct platform_device *pdev)
+{
+ struct imx_cpi_device *pcpidev;
+ struct device *dev = &pdev->dev;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ pcpidev = devm_kzalloc(dev, sizeof(*pcpidev), GFP_KERNEL);
+ if (!pcpidev)
+ return -ENOMEM;
+
+ pcpidev->dev = dev;
+ platform_set_drvdata(pdev, pcpidev);
+
+ pcpidev->pdata = of_device_get_match_data(dev);
+ pcpidev->mode = PI_GATE_CLOCK_MODE;
+
+ pcpidev->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pcpidev->regs))
+ return dev_err_probe(dev, PTR_ERR(pcpidev->regs),
+ "Failed to get regs\n");
+
+ pcpidev->num_clks = devm_clk_bulk_get_all(dev, &pcpidev->clks);
+ if (pcpidev->num_clks < 0)
+ return pcpidev->num_clks;
+
+ sd = &pcpidev->sd;
+
+ v4l2_subdev_init(sd, &imx_cpi_subdev_ops);
+
+ sd->internal_ops = &imx_cpi_internal_ops;
+ snprintf(sd->name, sizeof(sd->name), "parallel-%s",
+ dev_name(pcpidev->dev));
+
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ sd->entity.ops = &imx_cpi_entity_ops;
+
+ sd->dev = pcpidev->dev;
+
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ return media_async_register_subdev(sd);
+}
+
+static const struct of_device_id imx_cpi_of_match[] = {
+ { .compatible = "fsl,imx8qxp-pcif", .data = &imx8qxp_pdata },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, imx_cpi_of_match);
+
+static struct platform_driver imx_cpi_driver = {
+ .probe = imx_cpi_probe,
+ .remove = imx_cpi_remove,
+ .driver = {
+ .of_match_table = imx_cpi_of_match,
+ .name = "imx-parallel-cpi",
+ .pm = pm_ptr(&imx_cpi_pm_ops),
+ },
+};
+
+module_platform_driver(imx_cpi_driver);
+
+MODULE_DESCRIPTION("i.MX9 Parallel CPI receiver driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH v6 6/9] dt-bindings: media: add i.MX parallel CPI support
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel, Alice Yuan, Krzysztof Kozlowski
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Alice Yuan <alice.yuan@nxp.com>
Document the binding for parallel CPI controller found in i.MX8QXP, i.MX93
and i.MX91 SoCs.
Signed-off-by: Alice Yuan <alice.yuan@nxp.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Chagnes in v4
- add Laurent Pinchart's review by tag
- fix $ref: /schemas/graph.yaml#/$defs/port-base, original is
$ref: /schemas/graph.yaml#/properties/port-base
Change in v3:
- use enum at compatible string
- add ref to video-interfaces.yaml#
- use cpi as node name in examples.
- replace csi (Camera Serial Interface) with CPI (Camera Parallel Interface)
in commit message.
Change in v2:
- use pcif surfix as Laurent Pinchart's suggest.
- put power-domains into required list
---
.../devicetree/bindings/media/fsl,imx93-pcif.yaml | 126 +++++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 127 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/fsl,imx93-pcif.yaml b/Documentation/devicetree/bindings/media/fsl,imx93-pcif.yaml
new file mode 100644
index 0000000000000..9dd0331f6ef75
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/fsl,imx93-pcif.yaml
@@ -0,0 +1,126 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/fsl,imx93-pcif.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX8/9 Parallel Camera Interface
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+description: |
+ This is device node for the Parallel Camera Interface which enables the
+ chip to connect directly to external Parallel CMOS image sensors.
+ Supports up to 80MHz input clock from sensor.
+ Supports the following input data formats
+ - 8-bit/10-bit Camera Sensor Interface (CSI)
+ - 8-bit data port for RGB, YCbCr, and YUV data input
+ - 8-bit/10-bit data ports for Bayer data input
+ Parallel Camera Interface is hooked to the Imaging subsystem via the
+ Pixel Link.
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - fsl,imx8qxp-pcif
+ - fsl,imx93-pcif
+ - items:
+ - enum:
+ - fsl,imx91-pcif
+ - const: fsl,imx93-pcif
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 2
+
+ clock-names:
+ items:
+ - const: pixel
+ - const: ipg
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: Input port node.
+
+ properties:
+ endpoint:
+ $ref: video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ bus-type:
+ const: 5
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: Output port node.
+
+ properties:
+ endpoint:
+ $ref: video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ bus-type:
+ const: 5
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - power-domains
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx93-clock.h>
+ #include <dt-bindings/power/fsl,imx93-power.h>
+
+ cpi@4ac10070 {
+ compatible = "fsl,imx93-pcif";
+ reg = <0x4ac10070 0x10>;
+ clocks = <&clk IMX93_CLK_MIPI_CSI_GATE>,
+ <&clk IMX93_CLK_MEDIA_APB>;
+ clock-names = "pixel", "ipg";
+ assigned-clocks = <&clk IMX93_CLK_CAM_PIX>;
+ assigned-clock-parents = <&clk IMX93_CLK_VIDEO_PLL>;
+ assigned-clock-rates = <140000000>;
+ power-domains = <&media_blk_ctrl IMX93_MEDIABLK_PD_MIPI_CSI>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ endpoint {
+ remote-endpoint = <&mt9m114_ep>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ endpoint {
+ remote-endpoint = <&isi_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 895a87b571c35..51d5c62e3fdea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16258,6 +16258,7 @@ L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media.git
F: Documentation/admin-guide/media/imx7.rst
+F: Documentation/devicetree/bindings/media/fsl,imx93-pcif.yaml
F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
F: Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml
--
2.43.0
^ permalink raw reply related
* [PATCH v6 5/9] media: synopsys: Use media_async_register_subdev() to simplify code
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Use the media_async_register_subdev() to simplify the driver.
Replace the local subdev registration and media pad setup code with
media_async_register_subdev(). Reduce boilerplate code and aligns the
driver with the common pattern used by simple subdevices that each media
pad has one endpoint in fwnode.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- use media_async_register_subdev()
- remove sd_1to1.
change in v5
new patch
previous method:
https://lore.kernel.org/imx/20260226-v4l2_init_register-v2-2-902d7140f9fa@nxp.com/
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 178 +++++------------------
1 file changed, 40 insertions(+), 138 deletions(-)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index f51367409ff46..0fabc89a49b80 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -78,12 +78,6 @@ enum dw_mipi_csi2rx_regs_index {
DW_MIPI_CSI2RX_MAX,
};
-enum {
- DW_MIPI_CSI2RX_PAD_SINK,
- DW_MIPI_CSI2RX_PAD_SRC,
- DW_MIPI_CSI2RX_PAD_MAX,
-};
-
struct dw_mipi_csi2rx_device;
struct dw_mipi_csi2rx_drvdata {
@@ -112,12 +106,8 @@ struct dw_mipi_csi2rx_device {
const struct dw_mipi_csi2rx_format *formats;
unsigned int formats_num;
- struct media_pad pads[DW_MIPI_CSI2RX_PAD_MAX];
- struct v4l2_async_notifier notifier;
struct v4l2_subdev sd;
- enum v4l2_mbus_type bus_type;
- u32 lanes_num;
u64 enabled_streams;
const struct dw_mipi_csi2rx_drvdata *drvdata;
@@ -360,9 +350,10 @@ dw_mipi_csi2rx_find_format(struct dw_mipi_csi2rx_device *csi2, u32 mbus_code)
static int dw_mipi_csi2rx_start(struct dw_mipi_csi2rx_device *csi2)
{
+ struct media_pad *sink_pad = &csi2->sd.entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
+ u32 lanes = sink_pad->vep.bus.mipi_csi2.num_data_lanes;
struct media_pad *source_pad;
union phy_configure_opts opts;
- u32 lanes = csi2->lanes_num;
u32 control = 0;
s64 link_freq;
int ret;
@@ -370,8 +361,7 @@ static int dw_mipi_csi2rx_start(struct dw_mipi_csi2rx_device *csi2)
if (lanes < 1 || lanes > 4)
return -EINVAL;
- source_pad = media_pad_remote_pad_unique(
- &csi2->pads[DW_MIPI_CSI2RX_PAD_SINK]);
+ source_pad = media_pad_remote_pad_unique(sink_pad);
if (IS_ERR(source_pad))
return PTR_ERR(source_pad);
@@ -380,7 +370,7 @@ static int dw_mipi_csi2rx_start(struct dw_mipi_csi2rx_device *csi2)
if (link_freq < 0)
return link_freq;
- switch (csi2->bus_type) {
+ switch (sink_pad->vep.bus_type) {
case V4L2_MBUS_CSI2_DPHY:
ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq * 2,
lanes, &opts.mipi_dphy);
@@ -458,16 +448,16 @@ dw_mipi_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
struct dw_mipi_csi2rx_device *csi2 = to_csi2(sd);
switch (code->pad) {
- case DW_MIPI_CSI2RX_PAD_SRC:
+ case V4L2_SUBDEV_1TO1_PADS_SOURCE:
if (code->index)
return -EINVAL;
code->code =
v4l2_subdev_state_get_format(sd_state,
- DW_MIPI_CSI2RX_PAD_SINK)->code;
+ V4L2_SUBDEV_1TO1_PADS_SINK)->code;
return 0;
- case DW_MIPI_CSI2RX_PAD_SINK:
+ case V4L2_SUBDEV_1TO1_PADS_SINK:
if (code->index >= csi2->formats_num)
return -EINVAL;
@@ -487,7 +477,7 @@ static int dw_mipi_csi2rx_set_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *sink, *src;
/* the format on the source pad always matches the sink pad */
- if (format->pad == DW_MIPI_CSI2RX_PAD_SRC)
+ if (format->pad == V4L2_SUBDEV_1TO1_PADS_SOURCE)
return v4l2_subdev_get_fmt(sd, state, format);
sink = v4l2_subdev_state_get_format(state, format->pad, format->stream);
@@ -549,12 +539,12 @@ static int dw_mipi_csi2rx_enable_streams(struct v4l2_subdev *sd,
u64 mask;
int ret;
- sink_pad = &sd->entity.pads[DW_MIPI_CSI2RX_PAD_SINK];
+ sink_pad = &sd->entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
remote_pad = media_pad_remote_pad_first(sink_pad);
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- mask = v4l2_subdev_state_xlate_streams(state, DW_MIPI_CSI2RX_PAD_SINK,
- DW_MIPI_CSI2RX_PAD_SRC,
+ mask = v4l2_subdev_state_xlate_streams(state, V4L2_SUBDEV_1TO1_PADS_SINK,
+ V4L2_SUBDEV_1TO1_PADS_SOURCE,
&streams_mask);
if (!csi2->enabled_streams) {
@@ -608,12 +598,12 @@ static int dw_mipi_csi2rx_disable_streams(struct v4l2_subdev *sd,
u64 mask;
int ret;
- sink_pad = &sd->entity.pads[DW_MIPI_CSI2RX_PAD_SINK];
+ sink_pad = &sd->entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
remote_pad = media_pad_remote_pad_first(sink_pad);
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- mask = v4l2_subdev_state_xlate_streams(state, DW_MIPI_CSI2RX_PAD_SINK,
- DW_MIPI_CSI2RX_PAD_SRC,
+ mask = v4l2_subdev_state_xlate_streams(state, V4L2_SUBDEV_1TO1_PADS_SINK,
+ V4L2_SUBDEV_1TO1_PADS_SOURCE,
&streams_mask);
ret = v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
@@ -649,9 +639,9 @@ static int dw_mipi_csi2rx_init_state(struct v4l2_subdev *sd,
{
struct v4l2_subdev_route routes[] = {
{
- .sink_pad = DW_MIPI_CSI2RX_PAD_SINK,
+ .sink_pad = V4L2_SUBDEV_1TO1_PADS_SINK,
.sink_stream = 0,
- .source_pad = DW_MIPI_CSI2RX_PAD_SRC,
+ .source_pad = V4L2_SUBDEV_1TO1_PADS_SOURCE,
.source_stream = 0,
.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
},
@@ -666,95 +656,38 @@ static int dw_mipi_csi2rx_init_state(struct v4l2_subdev *sd,
&default_format);
}
-static const struct v4l2_subdev_internal_ops dw_mipi_csi2rx_internal_ops = {
- .init_state = dw_mipi_csi2rx_init_state,
-};
-
-static int dw_mipi_csi2rx_notifier_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_connection *asd)
+static int dw_mipi_set_pad_by_ep(struct v4l2_subdev *sd, struct media_pad *pad)
{
- struct dw_mipi_csi2rx_device *csi2 =
- container_of(notifier, struct dw_mipi_csi2rx_device, notifier);
- struct media_pad *sink_pad = &csi2->pads[DW_MIPI_CSI2RX_PAD_SINK];
- int ret;
-
- ret = v4l2_create_fwnode_links_to_pad(sd, sink_pad,
- MEDIA_LNK_FL_ENABLED);
- if (ret) {
- dev_err(csi2->dev, "failed to link source pad of %s\n",
- sd->name);
- return ret;
- }
-
- return 0;
-}
+ struct v4l2_fwnode_endpoint *vep = &pad->vep;
-static const struct v4l2_async_notifier_operations dw_mipi_csi2rx_notifier_ops = {
- .bound = dw_mipi_csi2rx_notifier_bound,
-};
-
-static int dw_mipi_csi2rx_register_notifier(struct dw_mipi_csi2rx_device *csi2)
-{
- struct v4l2_async_connection *asd;
- struct v4l2_async_notifier *ntf = &csi2->notifier;
- struct v4l2_fwnode_endpoint vep;
- struct v4l2_subdev *sd = &csi2->sd;
- struct device *dev = csi2->dev;
- int ret;
-
- struct fwnode_handle *ep __free(fwnode_handle) =
- fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
- if (!ep)
- return dev_err_probe(dev, -ENODEV, "failed to get endpoint\n");
-
- vep.bus_type = V4L2_MBUS_UNKNOWN;
- ret = v4l2_fwnode_endpoint_parse(ep, &vep);
- if (ret)
- return dev_err_probe(dev, ret, "failed to parse endpoint\n");
-
- if (vep.bus_type != V4L2_MBUS_CSI2_DPHY &&
- vep.bus_type != V4L2_MBUS_CSI2_CPHY)
- return dev_err_probe(dev, -EINVAL,
- "invalid bus type of endpoint\n");
-
- csi2->bus_type = vep.bus_type;
- csi2->lanes_num = vep.bus.mipi_csi2.num_data_lanes;
+ if (vep->base.port == V4L2_SUBDEV_1TO1_PADS_SINK) {
+ if (vep->bus_type != V4L2_MBUS_CSI2_DPHY &&
+ vep->bus_type != V4L2_MBUS_CSI2_CPHY)
+ return -EINVAL;
- v4l2_async_subdev_nf_init(ntf, sd);
- ntf->ops = &dw_mipi_csi2rx_notifier_ops;
+ pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
- asd = v4l2_async_nf_add_fwnode_remote(ntf, ep,
- struct v4l2_async_connection);
- if (IS_ERR(asd)) {
- ret = PTR_ERR(asd);
- goto err_nf_cleanup;
+ return 0;
}
- ret = v4l2_async_nf_register(ntf);
- if (ret) {
- ret = dev_err_probe(dev, ret, "failed to register notifier\n");
- goto err_nf_cleanup;
+ if (vep->base.port == V4L2_SUBDEV_1TO1_PADS_SOURCE) {
+ pad->flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+ return 0;
}
- return 0;
-
-err_nf_cleanup:
- v4l2_async_nf_cleanup(ntf);
-
- return ret;
+ return -EINVAL;
}
+static const struct v4l2_subdev_internal_ops dw_mipi_csi2rx_internal_ops = {
+ .init_state = dw_mipi_csi2rx_init_state,
+ .set_pad_by_ep = dw_mipi_set_pad_by_ep,
+};
+
static int dw_mipi_csi2rx_register(struct dw_mipi_csi2rx_device *csi2)
{
- struct media_pad *pads = csi2->pads;
struct v4l2_subdev *sd = &csi2->sd;
int ret;
- ret = dw_mipi_csi2rx_register_notifier(csi2);
- if (ret)
- goto err;
-
v4l2_subdev_init(sd, &dw_mipi_csi2rx_ops);
sd->dev = csi2->dev;
sd->entity.ops = &dw_mipi_csi2rx_media_ops;
@@ -764,45 +697,12 @@ static int dw_mipi_csi2rx_register(struct dw_mipi_csi2rx_device *csi2)
snprintf(sd->name, sizeof(sd->name), "dw-mipi-csi2rx %s",
dev_name(csi2->dev));
- pads[DW_MIPI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
- MEDIA_PAD_FL_MUST_CONNECT;
- pads[DW_MIPI_CSI2RX_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&sd->entity, DW_MIPI_CSI2RX_PAD_MAX, pads);
+ ret = media_async_register_subdev(&csi2->sd);
if (ret)
- goto err_notifier_unregister;
-
- ret = v4l2_subdev_init_finalize(sd);
- if (ret)
- goto err_entity_cleanup;
-
- ret = v4l2_async_register_subdev(sd);
- if (ret) {
- dev_err(sd->dev, "failed to register CSI-2 subdev\n");
- goto err_subdev_cleanup;
- }
+ return dev_err_probe(sd->dev, ret,
+ "failed to register CSI-2 subdev\n");
return 0;
-
-err_subdev_cleanup:
- v4l2_subdev_cleanup(sd);
-err_entity_cleanup:
- media_entity_cleanup(&sd->entity);
-err_notifier_unregister:
- v4l2_async_nf_unregister(&csi2->notifier);
- v4l2_async_nf_cleanup(&csi2->notifier);
-err:
- return ret;
-}
-
-static void dw_mipi_csi2rx_unregister(struct dw_mipi_csi2rx_device *csi2)
-{
- struct v4l2_subdev *sd = &csi2->sd;
-
- v4l2_async_unregister_subdev(sd);
- v4l2_subdev_cleanup(sd);
- media_entity_cleanup(&sd->entity);
- v4l2_async_nf_unregister(&csi2->notifier);
- v4l2_async_nf_cleanup(&csi2->notifier);
}
static void imx93_csi2rx_dphy_assert_reset(struct dw_mipi_csi2rx_device *csi2)
@@ -879,12 +779,14 @@ static void imx93_csi2rx_dphy_ipi_enable(struct dw_mipi_csi2rx_device *csi2)
static int imx93_csi2rx_wait_for_phy_stopstate(struct dw_mipi_csi2rx_device *csi2)
{
+ struct media_pad *sink_pad = &csi2->sd.entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
+ u32 num_lanes = sink_pad->vep.bus.mipi_csi2.num_data_lanes;
struct device *dev = csi2->dev;
u32 stopstate_mask;
u32 val;
int ret;
- stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(csi2->lanes_num - 1, 0);
+ stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(num_lanes - 1, 0);
ret = read_poll_timeout(dw_mipi_csi2rx_read, val,
(val & stopstate_mask) == stopstate_mask,
@@ -993,7 +895,7 @@ static void dw_mipi_csi2rx_remove(struct platform_device *pdev)
{
struct dw_mipi_csi2rx_device *csi2 = platform_get_drvdata(pdev);
- dw_mipi_csi2rx_unregister(csi2);
+ media_async_subdev_cleanup(&csi2->sd);
phy_exit(csi2->phy);
}
--
2.43.0
^ permalink raw reply related
* [PATCH v6 4/9] media: synopsys: Use v4l2_subdev_get_frame_desc_passthrough()
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Replace the local frame descriptor callback implementation with
v4l2_subdev_get_frame_desc_passthrough().
This helper provides the same functionality while avoiding duplicate
code and simplifying the driver implementation.
Reviewed-by: Guoniu Zhou <guoniu.zhou@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- collect gouniu's review by
change in v5
- new patch
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 22 +---------------------
1 file changed, 1 insertion(+), 21 deletions(-)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 41e48365167e5..f51367409ff46 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -630,31 +630,11 @@ static int dw_mipi_csi2rx_disable_streams(struct v4l2_subdev *sd,
return ret;
}
-static int
-dw_mipi_csi2rx_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
- struct v4l2_mbus_frame_desc *fd)
-{
- struct dw_mipi_csi2rx_device *csi2 = to_csi2(sd);
- struct v4l2_subdev *remote_sd;
- struct media_pad *remote_pad;
-
- remote_pad = media_pad_remote_pad_unique(&csi2->pads[DW_MIPI_CSI2RX_PAD_SINK]);
- if (IS_ERR(remote_pad)) {
- dev_err(csi2->dev, "can't get remote source pad\n");
- return PTR_ERR(remote_pad);
- }
-
- remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
-
- return v4l2_subdev_call(remote_sd, pad, get_frame_desc,
- remote_pad->index, fd);
-}
-
static const struct v4l2_subdev_pad_ops dw_mipi_csi2rx_pad_ops = {
.enum_mbus_code = dw_mipi_csi2rx_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = dw_mipi_csi2rx_set_fmt,
- .get_frame_desc = dw_mipi_csi2rx_get_frame_desc,
+ .get_frame_desc = v4l2_subdev_get_frame_desc_passthrough,
.set_routing = dw_mipi_csi2rx_set_routing,
.enable_streams = dw_mipi_csi2rx_enable_streams,
.disable_streams = dw_mipi_csi2rx_disable_streams,
--
2.43.0
^ permalink raw reply related
* [PATCH v6 3/9] media: subdev: Add media_async_register_subdev() helper
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Add media_async_register_subdev(), a helper to register a V4L2 sub-device
with the asynchronous sub-device framework.
The helper assumes a 1:1 mapping between firmware endpoints and media pads.
During registration it parses the firmware graph, creates media pads for
all endpoints, and registers common asynchronous notifiers for sink
endpoints. These notifiers automatically create media links when the
corresponding remote source devices become available.
The set_pad_by_ep() callback allows drivers to determine the media pad
associated with a firmware endpoint and identify whether the endpoint
represents a sink pad.
By centralizing firmware graph parsing, media pad creation, notifier
registration, and link creation, this helper reduces duplicated code and
simplifies error handling in V4L2 sub-device drivers.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- new patch
---
drivers/media/v4l2-core/v4l2-fwnode.c | 155 ++++++++++++++++++++++++++++++++++
include/media/v4l2-async.h | 39 +++++++++
2 files changed, 194 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 62a3a452f7884..169059654478f 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -26,6 +26,7 @@
#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
#include <media/v4l2-subdev.h>
#include "v4l2-subdev-priv.h"
@@ -1302,6 +1303,160 @@ int __v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *m
}
EXPORT_SYMBOL_GPL(__v4l2_async_register_subdev_sensor);
+static int v4l2_common_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_connection *asd)
+{
+ struct media_pad *pad = NULL;
+ int ret;
+
+ if (asd->match.type != V4L2_ASYNC_MATCH_TYPE_FWNODE)
+ return -EINVAL;
+
+ if (!asd->match.fwnode)
+ return -EINVAL;
+
+ struct fwnode_handle *remote __free(fwnode_handle) =
+ fwnode_graph_get_remote_endpoint(asd->match.fwnode);
+
+ for (int i = 0; i < notifier->sd->entity.num_pads; i++) {
+ if (notifier->sd->entity.pads[i].vep.base.local_fwnode == remote) {
+ pad = ¬ifier->sd->entity.pads[i];
+ break;
+ }
+ }
+
+ if (!pad) {
+ dev_err(notifier->sd->dev, "failed to find sink pad\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_create_fwnode_links_to_pad(sd, pad, MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ dev_err(sd->dev, "failed to link source pad\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations v4l2_common_notifier_ops = {
+ .bound = v4l2_common_notifier_bound,
+};
+
+static int
+v4l2_async_nf_parse_fwnode(struct device *dev, struct media_pad *pads,
+ struct v4l2_async_notifier *notifier)
+{
+ struct v4l2_subdev *sd = notifier->sd;
+ struct v4l2_async_connection *asd;
+ struct media_pad *pad;
+ int ret;
+
+ if (!sd->internal_ops->set_pad_by_ep)
+ return dev_err_probe(dev, -EINVAL,
+ "Missed valiate_endpoint() callback\n");
+ pad = pads;
+
+ fwnode_graph_for_each_endpoint_scoped(dev_fwnode(dev), ep) {
+ u32 flags;
+
+ ret = v4l2_fwnode_endpoint_parse(ep, &pad->vep);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to parse endpoint\n");
+
+ ret = sd->internal_ops->set_pad_by_ep(sd, pad);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Can support endponit\n");
+
+ flags = pad->flags;
+
+ pad++;
+
+ if (flags & MEDIA_PAD_FL_SOURCE)
+ continue; /* Bypass source port */
+
+ notifier->ops = &v4l2_common_notifier_ops;
+
+ asd = v4l2_async_nf_add_fwnode_remote(notifier, ep,
+ struct v4l2_async_connection);
+ if (IS_ERR(asd))
+ return dev_err_probe(dev, PTR_ERR(asd),
+ "failed to add notifier\n");
+ }
+
+ return 0;
+}
+
+void media_async_subdev_cleanup(struct v4l2_subdev *sd)
+{
+ v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_async_nf_unregister(sd->subdev_notifier);
+ v4l2_async_nf_cleanup(sd->subdev_notifier);
+ kfree(sd->entity.pads);
+}
+EXPORT_SYMBOL_GPL(media_async_subdev_cleanup);
+
+int __media_async_register_subdev(struct v4l2_subdev *sd, struct module *module)
+{
+ struct device *dev = sd->dev;
+ u32 ep_count;
+ int ret;
+
+ if (WARN_ON(!sd->dev))
+ return -ENODEV;
+
+ struct v4l2_async_notifier *notifier __free(kfree) = kzalloc_obj(*notifier);
+ if (!notifier)
+ return -ENOMEM;
+
+ v4l2_async_subdev_nf_init(notifier, sd);
+
+ ep_count = fwnode_graph_get_endpoint_count(dev_fwnode(dev), 0);
+ if (!ep_count)
+ return dev_err_probe(dev, -EINVAL, "No connected endpoints\n");
+
+ struct media_pad *pads __free(kfree) = kzalloc_objs(struct media_pad, ep_count);
+ if (!pads)
+ return -ENOMEM;
+
+ ret = v4l2_async_nf_parse_fwnode(dev, pads, notifier);
+ if (ret < 0)
+ return ret;
+
+ ret = media_entity_pads_init(&sd->entity, ep_count, pads);
+ if (ret)
+ goto out_cleanup;
+
+ ret = v4l2_async_nf_register(notifier);
+ if (ret < 0)
+ goto out_cleanup;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret)
+ goto out_unregister;
+
+ ret = __v4l2_async_register_subdev(sd, module);
+ if (ret < 0)
+ goto out_unregister;
+
+ sd->subdev_notifier = no_free_ptr(notifier);
+ retain_and_null_ptr(pads);
+
+ return 0;
+
+out_unregister:
+ v4l2_async_nf_unregister(notifier);
+
+out_cleanup:
+ v4l2_async_nf_cleanup(notifier);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__media_async_register_subdev);
+
MODULE_DESCRIPTION("V4L2 fwnode binding parsing library");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 54a2d9620ed5b..ca41820f776c5 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -345,4 +345,43 @@ __v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *modul
* @sd: pointer to &struct v4l2_subdev
*/
void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
+
+enum v4l2_subdev_1to1_pads {
+ V4L2_SUBDEV_1TO1_PADS_SINK,
+ V4L2_SUBDEV_1TO1_PADS_SOURCE,
+ V4L2_SUBDEV_1TO1_PADS_TOTAL,
+};
+
+/**
+ * media_async_register_subdev - registers a sub-device to the asynchronous
+ * sub-device framework and parse set up common
+ * related devices
+ *
+ * @sd: pointer to struct &v4l2_subdev
+ *
+ * Register a V4L2 sub-device with the asynchronous sub-device framework.
+ * In addition to v4l2_async_register_subdev(), this function parses the
+ * firmware graph, creates media pads for the endpoints, and registers common
+ * notifiers to create media links between connected devices.
+ *
+ * This function also init media_pads.
+ *
+ * The sub-device is unregistered and cleanup by media_async_subdev_cleanup()
+ *
+ * While registered, the subdev module is marked as in-use.
+ *
+ * An error is returned if the module is no longer loaded on any attempts
+ * to register it.
+ */
+#define media_async_register_subdev(sd_1to1) \
+ __media_async_register_subdev(sd_1to1, THIS_MODULE)
+
+int __media_async_register_subdev(struct v4l2_subdev *sd_1to1, struct module *module);
+
+/**
+ * media_async_subdev_cleanup - unregistered and cleanup subdev and media pads
+ * @sd_1to1: pointer to struct &v4l2_subdev_1to1
+ */
+void media_async_subdev_cleanup(struct v4l2_subdev *sd_1to1);
+
#endif
--
2.43.0
^ permalink raw reply related
* [PATCH v6 2/9] media: subdev: Add set_pad_by_ep() callback to internal ops
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Add a set_pad_by_ep() callback to struct v4l2_subdev_internal_ops. The
callback is invoked while parsing firmware node endpoints and allows
subdevice drivers to configure media pad properties based on endpoint
information.
Typical uses include setting media pad flags according to the endpoint's
port number or type, and validating that the endpoint configuration is
supported by the underlying hardware. This provides a common mechanism
for endpoint-aware pad initialization during graph construction.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- new patch
---
include/media/v4l2-subdev.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index d256b7ec8f848..eb652eb76d33f 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -935,6 +935,10 @@ struct v4l2_subdev_ops {
* the v4l2_subdev structure. It is almost certainly required for any
* sub-device that sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag.
*
+ * @set_pad_by_ep: Set pad informaiton by fwnode endpoint, parsed fwnode already
+ * saved into pad->vep. return < 0 means can't support this type
+ * endpoint. Set pad->flags according to pad->vep information.
+ *
* .. note::
* Never call this from drivers, only the v4l2 framework can call
* these ops.
@@ -947,6 +951,7 @@ struct v4l2_subdev_internal_ops {
int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
void (*release)(struct v4l2_subdev *sd);
+ int (*set_pad_by_ep)(struct v4l2_subdev *sd, struct media_pad *pad);
};
/* Set this flag if this subdev is a i2c device. */
--
2.43.0
^ permalink raw reply related
* [PATCH v6 1/9] media: mc-entity: Store parsed V4L2 fwnode endpoint in media_pad
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-0-4b3f45920d2f@nxp.com>
From: Frank Li <Frank.Li@nxp.com>
Each media pad is associated with a firmware node endpoint. Capture the
parsed V4L2 fwnode endpoint information in struct media_pad so it can be
reused by consumers.
This avoids reparsing firmware node endpoint data every time the endpoint
configuration is needed, reduces duplicate code, and provides a common
place to store endpoint properties associated with a pad.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Assume 1 to 1 map between dt's endpoint to medie pad.
Change in v6
- new patch
---
include/media/media-entity.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index d9b72cd87d524..4a3785cd9f370 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -20,6 +20,8 @@
#include <linux/minmax.h>
#include <linux/types.h>
+#include <media/v4l2-fwnode.h>
+
/* Enums used internally at the media controller to represent graphs */
/**
@@ -230,6 +232,7 @@ enum media_pad_signal_type {
* @flags: Pad flags, as defined in
* :ref:`include/uapi/linux/media.h <media_header>`
* (seek for ``MEDIA_PAD_FL_*``)
+ * @vep: associated fwnode endpoint information
* @pipe: Pipeline this pad belongs to. Use media_entity_pipeline() to
* access this field.
*/
@@ -240,7 +243,7 @@ struct media_pad {
u16 num_links;
enum media_pad_signal_type sig_type;
unsigned long flags;
-
+ struct v4l2_fwnode_endpoint vep;
/*
* The fields below are private, and should only be accessed via
* appropriate functions.
--
2.43.0
^ permalink raw reply related
* [PATCH v6 0/9] media: add new API simple 1to1 subdev register and add imx parallel camera support
From: Frank.Li @ 2026-06-24 20:37 UTC (permalink / raw)
To: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam
Cc: linux-media, linux-kernel, imx, Guoniu Zhou, devicetree,
linux-arm-kernel, Alice Yuan, Robert Chiras, Zhipeng Wang,
Krzysztof Kozlowski
Base on patches "media: add and use fwnode_graph_for_each_endpoint_scoped()"
https://lore.kernel.org/imx/20260624200237.GJ851255@killaraus.ideasonboard.com/T/#m7969735b6c236c6b3abc16b9f3f55ec0488dbe89
This patches base on previous' thread "media: imx8qxp: add parallel camera
support".
Add new API media_async_register_subdev_1to1() to simple 1to1 subdev
register.
Many V4L2 subdev drivers implement the same registration and media pads.
Assumes a 1:1 mapping between firmware endpoints and media pads.
During registration it parses the firmware graph, creates media pads for
all endpoints, and registers common asynchronous notifiers for sink
endpoints. These notifiers automatically create media links when the
corresponding remote source devices become available.
The set_pad_by_ep() callback allows drivers to determine the media pad
associated with a firmware endpoint and identify whether the endpoint
represents a sink pad.
By centralizing firmware graph parsing, media pad creation, notifier
registration, and link creation, this helper reduces duplicated code and
simplifies error handling in V4L2 sub-device drivers.
Add media_async_register_subdev(), a helper to register a V4L2 sub-device
with the asynchronous sub-device framework.
This reduces code duplication and simplifies the implementation of
simple bridge and converter drivers.
In subdev driver:
your_device_probe()
{
v4l2_subdev_init(sd, &dw_mipi_csi2rx_ops);
...
return media_async_register_subdev_1to1(sd);
}
...
your_device_remove()
{
media_async_subdev_cleanup(sd);
}
This API help reduce over line duplcated code in synopsys/dw-mipi-csi2rx.c.
And use this API at imx8's parallel CPI driver, which over 90% code now
hardware related.
And also benefit on going pix format patch
https://lore.kernel.org/imx/20260525-csi_formatter-v8-0-6b646231224b@oss.nxp.com/
It will also reduce missed media_entity_cleanup() problem at some error path
https://lore.kernel.org/linux-media/20260614202835.11977-15-birenpandya@gmail.com/
Previous do partial simpilfy at
https://lore.kernel.org/imx/aaisdJSsFE5-PLx1@lizhi-Precision-Tower-5810/
To: Sakari Ailus <sakari.ailus@linux.intel.com>
To: Mauro Carvalho Chehab <mchehab@kernel.org>
To: Michael Riesch <michael.riesch@collabora.com>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Frank Li <Frank.Li@nxp.com>
To: Martin Kepplinger-Novakovic <martink@posteo.de>
To: Rui Miguel Silva <rmfrfs@gmail.com>
To: Purism Kernel Team <kernel@puri.sm>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Sascha Hauer <s.hauer@pengutronix.de>
To: Pengutronix Kernel Team <kernel@pengutronix.de>
To: Fabio Estevam <festevam@gmail.com>
Cc: linux-media@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: imx@lists.linux.dev
Cc: Guoniu Zhou <guoniu.zhou@nxp.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Changes in v6:
- Change API to fix more width user case, assume a media pad have one endpoint
on dts.
- other detail change see each patch's change log
- Link to v5: https://patch.msgid.link/20260617-imx8qxp_pcam-v5-0-7fa6c8e7fba7@nxp.com
Changes in v5:
- Add media_async_register_subdev_1to1() to simple code.
- Link to v4: https://lore.kernel.org/r/20250729-imx8qxp_pcam-v4-0-4dfca4ed2f87@nxp.com
Changes in v4:
- remove imx93 driver support since have not camera sensor module to do test now.
Add it later
- Add new patch
media: v4l2-common: Add helper function v4l_get_required_align_by_bpp()
- See each patche's change log for detail.
- Link to v3: https://lore.kernel.org/r/20250708-imx8qxp_pcam-v3-0-c8533e405df1@nxp.com
Changes in v3:
- replace CSI with CPI.
- detail change see each patch's change logs
- Link to v2: https://lore.kernel.org/r/20250703-imx8qxp_pcam-v2-0-188be85f06f1@nxp.com
Changes in v2:
- remove patch media: nxp: isi: add support for UYVY8_2X8 and YUYV8_2X8 bus codes
because pcif controller convert 2x8 to 1x16 to match isi's input
- rename comaptible string to fsl,imx8qxp-pcif
- See each patches's change log for detail
- Link to v1: https://lore.kernel.org/r/20250630-imx8qxp_pcam-v1-0-eccd38d99201@nxp.com
---
Alice Yuan (2):
dt-bindings: media: add i.MX parallel CPI support
media: nxp: add V4L2 subdev driver for camera parallel interface (CPI)
Frank Li (7):
media: mc-entity: Store parsed V4L2 fwnode endpoint in media_pad
media: subdev: Add set_pad_by_ep() callback to internal ops
media: subdev: Add media_async_register_subdev() helper
media: synopsys: Use v4l2_subdev_get_frame_desc_passthrough()
media: synopsys: Use media_async_register_subdev() to simplify code
arm64: dts: imx8: add camera parallel interface (CPI) node
arm64: dts: imx8qxp-mek: add parallel ov5640 camera support
.../devicetree/bindings/media/fsl,imx93-pcif.yaml | 126 +++++
MAINTAINERS | 2 +
arch/arm64/boot/dts/freescale/Makefile | 3 +
arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi | 13 +
.../boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso | 83 +++
arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi | 27 +
drivers/media/platform/nxp/Kconfig | 12 +
drivers/media/platform/nxp/Makefile | 1 +
drivers/media/platform/nxp/imx-parallel-cpi.c | 629 +++++++++++++++++++++
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 200 ++-----
drivers/media/v4l2-core/v4l2-fwnode.c | 155 +++++
include/media/media-entity.h | 5 +-
include/media/v4l2-async.h | 39 ++
include/media/v4l2-subdev.h | 5 +
14 files changed, 1140 insertions(+), 160 deletions(-)
---
base-commit: c425f8be0326d40823cd93cbca633872d099df2a
change-id: 20250626-imx8qxp_pcam-d851238343c3
Best regards,
--
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply
* Re: [PATCH v2] ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema
From: Rhodes, David @ 2026-06-24 20:05 UTC (permalink / raw)
To: Rob Herring, David Heidelberg
Cc: David Rhodes, Richard Fitzgerald, Liam Girdwood, Mark Brown,
Krzysztof Kozlowski, Conor Dooley, patches, Bjorn Helgaas,
linux-sound, devicetree, linux-kernel, phone-devel
In-Reply-To: <20260624194541.GA672824-robh@kernel.org>
On 6/24/26 2:45 PM, Rob Herring wrote:
> On Wed, Jun 24, 2026 at 08:39:28PM +0200, David Heidelberg wrote:
>> On 24/06/2026 20:17, Rob Herring wrote:
>>> On Wed, Jun 24, 2026 at 11:02 AM David Heidelberg via B4 Relay
>>> <devnull+david.ixit.cz@kernel.org> wrote:
>>>>
>>>> From: David Heidelberg <david@ixit.cz>
>>>>
>>>> Convert CS35L36 Speaker Amplifier to yaml.
>>>>
>>>> Changes:
>>>> - maintainers email to the generic Cirrus email
>>>> - Both the codec and downstream worked just fine without
>>>> VP-supply provided. Align with datasheet for similar models.
>>>> - add dai-common.yaml to cover for '#sound-dai-cells',
>>>> 'sound-name-prefix'
>>>>
>>>> Reviewed-by: David Rhodes <David.Rhodes@cirrus.com>
>>>
>>> If you are going to take stuff I haven't fixed:
>>>
>>> Assisted-by: OpenAI:gpt-4
>>>
>>> (I don't remember the exact flavor I used)
>>>
>>>> Co-developed-by: Rob Herring (Arm) <robh@kernel.org>
>>>> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
>>>> Signed-off-by: David Heidelberg <david@ixit.cz>
>>>> ---
>>>> Relevant for Pixel 3 / 3XL / 4.
>>>> ---
>>>> Changes in v2:
>>>> - Rename the commit. (Mark)
>>>> - Link to v1: https://lore.kernel.org/r/20260618-dt-cirrus-cs35l36-v1-1-1a43515666ad@ixit.cz
>>>> ---
>>>> .../devicetree/bindings/sound/cirrus,cs35l36.yaml | 224 +++++++++++++++++++++
>>>> .../devicetree/bindings/sound/cs35l36.txt | 168 ----------------
>>>> 2 files changed, 224 insertions(+), 168 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
>>>> new file mode 100644
>>>> index 0000000000000..af0acaaefb68e
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
>>>> @@ -0,0 +1,224 @@
>>>> +# SPDX-License-Identifier: GPL-2.0-only
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/cirrus,cs35l36.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Cirrus Logic CS35L36 Speaker Amplifier
>>>> +
>>>> +maintainers:
>>>> + - patches@opensource.cirrus.com
>>>> + - Bjorn Helgaas <bhelgaas@google.com>
>>>
>>> Bjorn is not correct. Generally we want a person, not a company list.
>>
>> I'm adding back James, can I keep the patches at 2nd place?
>
> Yes.
Please put me down and the patches list as well. James will not respond
at that address any longer.
>
>>>> + cirrus,vpbr-thld:
>>>> + description: Initial VPBR threshold voltage
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
minimum: 2
maximum: 31
>>>> +
>>>> + cirrus,vpbr-atk-rate:
>>>> + description: Attenuation attack step rate
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
minimum: 0
maximum: 7
>>>> + cirrus,vpbr-atk-vol:
>>>> + description: VP brownout prevention step size
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
minimum: 0
maximum: 7
>>>> + cirrus,vpbr-max-attn:
>>>> + description: Maximum attenuation during VP brownout prevention
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
minimum: 0
maximum: 15
this is just an integer dB value
>>>> + cirrus,vpbr-wait:
>>>> + description: Delay between brownout clearance and attenuation release
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +enum:
- 0 # 10ms
- 1 # 100ms (Default)
- 2 # 250ms
- 3 # 500ms
>>>> + cirrus,vpbr-rel-rate:
>>>> + description: Attenuation release step rate
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
minimum: 0
maximum: 7
>>>> + cirrus,vpbr-mute-en:
>>>> + description: Mute audio if maximum attenuation reached
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>
minimum: 0
maximum: 1
>>> Constraints on any of these?
>>
>> Code just applies whatever is thrown at it, maybe David knows more?
>>
>> #nodatasheet (but would be lovely to have one)
>
> Unless the driver just takes these values and shoves them straight into
> a 32-bit register, the driver should give some clue about the size or
> possible values.
>
> Rob
>
Got some constraints for you.
Thanks,
David
^ permalink raw reply
* Re: [PATCH v2] ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema
From: David Heidelberg @ 2026-06-24 20:04 UTC (permalink / raw)
To: Rob Herring
Cc: David Rhodes, Richard Fitzgerald, Liam Girdwood, Mark Brown,
Krzysztof Kozlowski, Conor Dooley, patches, Bjorn Helgaas,
linux-sound, devicetree, linux-kernel, phone-devel
In-Reply-To: <20260624194541.GA672824-robh@kernel.org>
On 24/06/2026 21:45, Rob Herring wrote:
> On Wed, Jun 24, 2026 at 08:39:28PM +0200, David Heidelberg wrote:
>> On 24/06/2026 20:17, Rob Herring wrote:
>>> On Wed, Jun 24, 2026 at 11:02 AM David Heidelberg via B4 Relay
>>> <devnull+david.ixit.cz@kernel.org> wrote:
>>>>
>>>> From: David Heidelberg <david@ixit.cz>
>>>>
>>>> Convert CS35L36 Speaker Amplifier to yaml.
>>>>
>>>> Changes:
>>>> - maintainers email to the generic Cirrus email
>>>> - Both the codec and downstream worked just fine without
>>>> VP-supply provided. Align with datasheet for similar models.
>>>> - add dai-common.yaml to cover for '#sound-dai-cells',
>>>> 'sound-name-prefix'
>>>>
>>>> Reviewed-by: David Rhodes <David.Rhodes@cirrus.com>
>>>
>>> If you are going to take stuff I haven't fixed:
>>>
>>> Assisted-by: OpenAI:gpt-4
>>>
>>> (I don't remember the exact flavor I used)
>>>
>>>> Co-developed-by: Rob Herring (Arm) <robh@kernel.org>
>>>> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
>>>> Signed-off-by: David Heidelberg <david@ixit.cz>
>>>> ---
>>>> Relevant for Pixel 3 / 3XL / 4.
>>>> ---
>>>> Changes in v2:
>>>> - Rename the commit. (Mark)
>>>> - Link to v1: https://lore.kernel.org/r/20260618-dt-cirrus-cs35l36-v1-1-1a43515666ad@ixit.cz
>>>> ---
>>>> .../devicetree/bindings/sound/cirrus,cs35l36.yaml | 224 +++++++++++++++++++++
>>>> .../devicetree/bindings/sound/cs35l36.txt | 168 ----------------
>>>> 2 files changed, 224 insertions(+), 168 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
>>>> new file mode 100644
>>>> index 0000000000000..af0acaaefb68e
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
>>>> @@ -0,0 +1,224 @@
>>>> +# SPDX-License-Identifier: GPL-2.0-only
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/cirrus,cs35l36.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Cirrus Logic CS35L36 Speaker Amplifier
>>>> +
>>>> +maintainers:
>>>> + - patches@opensource.cirrus.com
>>>> + - Bjorn Helgaas <bhelgaas@google.com>
>>>
>>> Bjorn is not correct. Generally we want a person, not a company list.
>>
>> I'm adding back James, can I keep the patches at 2nd place?
>
> Yes.
>
>>>> + cirrus,vpbr-thld:
>>>> + description: Initial VPBR threshold voltage
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
>>>> + cirrus,vpbr-atk-rate:
>>>> + description: Attenuation attack step rate
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
>>>> + cirrus,vpbr-atk-vol:
>>>> + description: VP brownout prevention step size
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
>>>> + cirrus,vpbr-max-attn:
>>>> + description: Maximum attenuation during VP brownout prevention
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
>>>> + cirrus,vpbr-wait:
>>>> + description: Delay between brownout clearance and attenuation release
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
>>>> + cirrus,vpbr-rel-rate:
>>>> + description: Attenuation release step rate
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> +
>>>> + cirrus,vpbr-mute-en:
>>>> + description: Mute audio if maximum attenuation reached
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>
>>> Constraints on any of these?
>>
>> Code just applies whatever is thrown at it, maybe David knows more?
>>
>> #nodatasheet (but would be lovely to have one)
>
> Unless the driver just takes these values and shoves them straight into
> a 32-bit register, the driver should give some clue about the size or
> possible values.
Okay, that's me being too lazy. Fair enough, I'll fill the constraints :)
Thanks
David
>
> Rob
--
David Heidelberg
^ permalink raw reply
* Re: [PATCH RFC v4 10/12] reset: zte: Add a zx297520v3 reset driver
From: Stefan Dösinger @ 2026-06-24 20:00 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Brian Masney, Philipp Zabel
Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <90c4f50eb23dec06497d46f9c0f522a6b90a918b.camel@pengutronix.de>
[-- Attachment #1: Type: text/plain, Size: 1165 bytes --]
Hi Philipp,
Am Donnerstag, 18. Juni 2026, 12:24:26 Ostafrikanische Zeit schrieb Philipp
Zabel:
> > + [ZX297520V3_UART0_RESET] = { .reg = 0x78, .mask = BIT(6) |
BIT(7)
> > },
> Is this a single reset line controlled by two bits (do you know what
> they are)? Or might these actually be two different reset controls that
> are just always set together?
I suppose I could expose both bits as separate reset controls in the binding.
The lower bit is usually the one that actually resets the device, while the
higher one works similarly to PCLK - it disconnects the device from the bus,
if asserted. Depending on the device it may or may not leave any residual
effect behind after deassert.
The stumbling block is the dwc2 USB driver. It only takes one reset, so I'd
have to add another one (or abuse the dwc2-ecc reset) and presumably add a PHY
driver for the 3rd reset or add a dwc2-phy reset.
The AMBA bus already takes an array of resets, so the pl011 UARTs are fine
either way. For stmmac I need a glue driver for other reasons anyway. the
dwc,mmc2 controller on this board seems to have only one reset, so no need to
extend the driver here.
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 870 bytes --]
^ permalink raw reply
* Re: [PATCH v2] ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema
From: Rob Herring @ 2026-06-24 19:45 UTC (permalink / raw)
To: David Heidelberg
Cc: David Rhodes, Richard Fitzgerald, Liam Girdwood, Mark Brown,
Krzysztof Kozlowski, Conor Dooley, patches, Bjorn Helgaas,
linux-sound, devicetree, linux-kernel, phone-devel
In-Reply-To: <3873b111-36d5-442e-996c-31d05d23c8e8@ixit.cz>
On Wed, Jun 24, 2026 at 08:39:28PM +0200, David Heidelberg wrote:
> On 24/06/2026 20:17, Rob Herring wrote:
> > On Wed, Jun 24, 2026 at 11:02 AM David Heidelberg via B4 Relay
> > <devnull+david.ixit.cz@kernel.org> wrote:
> > >
> > > From: David Heidelberg <david@ixit.cz>
> > >
> > > Convert CS35L36 Speaker Amplifier to yaml.
> > >
> > > Changes:
> > > - maintainers email to the generic Cirrus email
> > > - Both the codec and downstream worked just fine without
> > > VP-supply provided. Align with datasheet for similar models.
> > > - add dai-common.yaml to cover for '#sound-dai-cells',
> > > 'sound-name-prefix'
> > >
> > > Reviewed-by: David Rhodes <David.Rhodes@cirrus.com>
> >
> > If you are going to take stuff I haven't fixed:
> >
> > Assisted-by: OpenAI:gpt-4
> >
> > (I don't remember the exact flavor I used)
> >
> > > Co-developed-by: Rob Herring (Arm) <robh@kernel.org>
> > > Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
> > > Signed-off-by: David Heidelberg <david@ixit.cz>
> > > ---
> > > Relevant for Pixel 3 / 3XL / 4.
> > > ---
> > > Changes in v2:
> > > - Rename the commit. (Mark)
> > > - Link to v1: https://lore.kernel.org/r/20260618-dt-cirrus-cs35l36-v1-1-1a43515666ad@ixit.cz
> > > ---
> > > .../devicetree/bindings/sound/cirrus,cs35l36.yaml | 224 +++++++++++++++++++++
> > > .../devicetree/bindings/sound/cs35l36.txt | 168 ----------------
> > > 2 files changed, 224 insertions(+), 168 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
> > > new file mode 100644
> > > index 0000000000000..af0acaaefb68e
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
> > > @@ -0,0 +1,224 @@
> > > +# SPDX-License-Identifier: GPL-2.0-only
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/cirrus,cs35l36.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Cirrus Logic CS35L36 Speaker Amplifier
> > > +
> > > +maintainers:
> > > + - patches@opensource.cirrus.com
> > > + - Bjorn Helgaas <bhelgaas@google.com>
> >
> > Bjorn is not correct. Generally we want a person, not a company list.
>
> I'm adding back James, can I keep the patches at 2nd place?
Yes.
> > > + cirrus,vpbr-thld:
> > > + description: Initial VPBR threshold voltage
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > +
> > > + cirrus,vpbr-atk-rate:
> > > + description: Attenuation attack step rate
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > +
> > > + cirrus,vpbr-atk-vol:
> > > + description: VP brownout prevention step size
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > +
> > > + cirrus,vpbr-max-attn:
> > > + description: Maximum attenuation during VP brownout prevention
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > +
> > > + cirrus,vpbr-wait:
> > > + description: Delay between brownout clearance and attenuation release
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > +
> > > + cirrus,vpbr-rel-rate:
> > > + description: Attenuation release step rate
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > +
> > > + cirrus,vpbr-mute-en:
> > > + description: Mute audio if maximum attenuation reached
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> >
> > Constraints on any of these?
>
> Code just applies whatever is thrown at it, maybe David knows more?
>
> #nodatasheet (but would be lovely to have one)
Unless the driver just takes these values and shoves them straight into
a 32-bit register, the driver should give some clue about the size or
possible values.
Rob
^ permalink raw reply
* [PATCH v2 0/2] rockchip: Fix devices suspend freeze on RK3568/RK3566
From: Jonas Karlman @ 2026-06-24 19:27 UTC (permalink / raw)
To: Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Diederik de Haas, Greg Kroah-Hartman, devicetree, linux-rockchip,
linux-usb, linux-arm-kernel, linux-kernel, Jonas Karlman
This series fixes a system freeze during suspend in ohci_suspend() due
to clk_usbphy1_480m not being enabled when EHCI/OHCI registers are
accessed on e.g. a Raxa ROCK 3C board.
Following pm_test modes work on my ROCK 3C with the missing usbphy clk
refs added:
echo N > /sys/module/printk/parameters/console_suspend
echo devices > /sys/power/pm_test
echo platform > /sys/power/pm_test
echo processors > /sys/power/pm_test
echo core > /sys/power/pm_test
echo mem > /sys/power/state
Changes in v2:
- Include rockchip,rk3588-ehci in the EHCI constraint
- Make clocks prop required for EHCI and OHCI
- Collect t-b tag
Jonas Karlman (2):
dt-bindings: usb: Add Rockchip RK3568 compatible for EHCI and OHCI
arm64: dts: rockchip: Fix devices suspend freeze on RK3568/RK3566
.../devicetree/bindings/usb/generic-ehci.yaml | 14 ++++++++++++++
.../devicetree/bindings/usb/generic-ohci.yaml | 7 ++++++-
arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 16 ++++++++--------
3 files changed, 28 insertions(+), 9 deletions(-)
--
2.54.0
^ permalink raw reply
* [PATCH v2 1/2] dt-bindings: usb: Add Rockchip RK3568 compatible for EHCI and OHCI
From: Jonas Karlman @ 2026-06-24 19:27 UTC (permalink / raw)
To: Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Greg Kroah-Hartman
Cc: Diederik de Haas, devicetree, linux-rockchip, linux-usb,
linux-arm-kernel, linux-kernel, Jonas Karlman
In-Reply-To: <20260624192726.781864-1-jonas@kwiboo.se>
The Rockchip RK3568 EHCI/OHCI controller depends on clk_usbphy1_480m
being enabled, or the system may freeze when registers are accessed.
Add Rockchip RK3568 EHCI and OHCI compatibles with a similar four-clock
constraint as RK3588, also extend the EHCI constraint to include RK3588
to match similar requirements of RK3588.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
Existing DTs for RK3568 use the plain generic-ehci/ohci compatible,
next patch make use of these new compatibles and adds the missing
clk_usbphy1_480m clock references.
Existing DTs for RK3588 have contained the required four clocks since
the initial addition of the EHCI/OHCI nodes.
Changes in v2:
- Include rockchip,rk3588-ehci in the EHCI constraint
- Make clocks prop required for EHCI and OHCI
---
.../devicetree/bindings/usb/generic-ehci.yaml | 14 ++++++++++++++
.../devicetree/bindings/usb/generic-ohci.yaml | 7 ++++++-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
index 55a5aa7d7a54..a39f01e740b1 100644
--- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
@@ -52,6 +52,7 @@ properties:
- ibm,476gtr-ehci
- nxp,lpc1850-ehci
- qca,ar7100-ehci
+ - rockchip,rk3568-ehci
- rockchip,rk3588-ehci
- snps,hsdk-v1.0-ehci
- socionext,uniphier-ehci
@@ -186,6 +187,19 @@ allOf:
required:
- clocks
- clock-names
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - rockchip,rk3568-ehci
+ - rockchip,rk3588-ehci
+ then:
+ properties:
+ clocks:
+ minItems: 4
+ required:
+ - clocks
unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
index d42f448fa204..19449a6b3033 100644
--- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
@@ -47,6 +47,7 @@ properties:
- hpe,gxp-ohci
- ibm,476gtr-ohci
- ingenic,jz4740-ohci
+ - rockchip,rk3568-ohci
- rockchip,rk3588-ohci
- snps,hsdk-v1.0-ohci
- const: generic-ohci
@@ -198,11 +199,15 @@ allOf:
properties:
compatible:
contains:
- const: rockchip,rk3588-ohci
+ enum:
+ - rockchip,rk3568-ohci
+ - rockchip,rk3588-ohci
then:
properties:
clocks:
minItems: 4
+ required:
+ - clocks
else:
properties:
clocks:
--
2.54.0
^ permalink raw reply related
* [PATCH v2 2/2] arm64: dts: rockchip: Fix devices suspend freeze on RK3568/RK3566
From: Jonas Karlman @ 2026-06-24 19:27 UTC (permalink / raw)
To: Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Peter Geis, Michael Riesch
Cc: Diederik de Haas, Greg Kroah-Hartman, devicetree, linux-rockchip,
linux-usb, linux-arm-kernel, linux-kernel, Jonas Karlman
In-Reply-To: <20260624192726.781864-1-jonas@kwiboo.se>
The EHCI/OHCI controller depends on clk_usbphy1_480m being enabled, or
the system may freeze when registers are accessed, i.e. during suspend
in ohci_suspend().
Add the missing clk_usbphy1_480m clocks reference to EHCI/OHCI
controllers to ensure the clock is enabled when ECHI/OHCI registers are
accessed to prevent a system freeze.
Fixes suspend pm_test issue with EHCI/OHCI devices due to the missing
clk_usbphy1_480m reference and makes following pm_test modes work:
echo N > /sys/module/printk/parameters/console_suspend
echo devices > /sys/power/pm_test
echo platform > /sys/power/pm_test
echo processors > /sys/power/pm_test
echo core > /sys/power/pm_test
echo mem > /sys/power/state
Fixes: 91c4c3e06a25 ("arm64: dts: rockchip: add usb2 nodes to rk3568 device tree")
Fixes: 78f7186095db ("arm64: dts: rockchip: rename and sort the rk356x usb2 phy handles")
Tested-by: Diederik de Haas <diederik@cknow-tech.com>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
v2: Collect t-b tag
---
arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index a5832895bd39..c930a6fd6ea0 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -321,44 +321,44 @@ its: msi-controller@fd440000 {
};
usb_host0_ehci: usb@fd800000 {
- compatible = "generic-ehci";
+ compatible = "rockchip,rk3568-ehci", "generic-ehci";
reg = <0x0 0xfd800000 0x0 0x40000>;
interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>,
- <&cru PCLK_USB>;
+ <&cru PCLK_USB>, <&usb2phy1>;
phys = <&usb2phy1_otg>;
phy-names = "usb";
status = "disabled";
};
usb_host0_ohci: usb@fd840000 {
- compatible = "generic-ohci";
+ compatible = "rockchip,rk3568-ohci", "generic-ohci";
reg = <0x0 0xfd840000 0x0 0x40000>;
interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>,
- <&cru PCLK_USB>;
+ <&cru PCLK_USB>, <&usb2phy1>;
phys = <&usb2phy1_otg>;
phy-names = "usb";
status = "disabled";
};
usb_host1_ehci: usb@fd880000 {
- compatible = "generic-ehci";
+ compatible = "rockchip,rk3568-ehci", "generic-ehci";
reg = <0x0 0xfd880000 0x0 0x40000>;
interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>,
- <&cru PCLK_USB>;
+ <&cru PCLK_USB>, <&usb2phy1>;
phys = <&usb2phy1_host>;
phy-names = "usb";
status = "disabled";
};
usb_host1_ohci: usb@fd8c0000 {
- compatible = "generic-ohci";
+ compatible = "rockchip,rk3568-ohci", "generic-ohci";
reg = <0x0 0xfd8c0000 0x0 0x40000>;
interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>,
- <&cru PCLK_USB>;
+ <&cru PCLK_USB>, <&usb2phy1>;
phys = <&usb2phy1_host>;
phy-names = "usb";
status = "disabled";
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v4 03/19] firmware: qcom: scm: Fix missing smp_load_acquire()
From: sashiko-bot @ 2026-06-24 19:24 UTC (permalink / raw)
To: Mukesh Ojha; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260624190830.3131112-4-mukesh.ojha@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The waitqueue interrupt is requested and enabled before the global __scm pointer is published, leading to a potential NULL pointer dereference in the IRQ handler path.
--
commit 181d68fe28239c2e3b0bbf1762f175bcdf577648
Author: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
firmware: qcom: scm: Fix missing smp_load_acquire()
This commit fixes a potential ordering violation in
qcom_scm_set_download_mode() by using smp_load_acquire() to safely read
the __scm pointer published by qcom_scm_probe().
> diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
> index 9b06a69d3a6d7..c8a84836887f0 100644
> --- a/drivers/firmware/qcom/qcom_scm.c
> +++ b/drivers/firmware/qcom/qcom_scm.c
[ ... ]
> @@ -2841,7 +2844,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
> * will cause the boot stages to enter download mode, unless
> * disabled below by a clean shutdown/reboot.
> */
> - qcom_scm_set_download_mode(download_mode);
> + qcom_scm_set_download_mode(scm, download_mode);
[Severity: High]
This is a pre-existing issue, but since we are looking at the initialization
ordering in qcom_scm_probe() in drivers/firmware/qcom/qcom_scm.c, could the
IRQ registration order cause a NULL pointer dereference?
Earlier in qcom_scm_probe(), the waitqueue interrupt is enabled before the
global __scm pointer is published:
ret = devm_request_threaded_irq(scm->dev, irq, NULL, qcom_scm_irq_handler,
IRQF_ONESHOT, "qcom-scm", scm);
...
smp_store_release(&__scm, scm);
If a pending hardware interrupt fires before __scm is published, the IRQ
handler will execute. The handler calls qcom_scm_waitq_wakeup(), which invokes
qcom_scm_get_completion().
Could qcom_scm_get_completion() crash here, since it ignores the valid scm
context passed via the IRQ data and unconditionally dereferences __scm?
drivers/firmware/qcom/qcom_scm.c:qcom_scm_get_completion() {
if (WARN_ON_ONCE(wq_ctx >= __scm->wq_cnt))
return ERR_PTR(-EINVAL);
...
}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624190830.3131112-1-mukesh.ojha@oss.qualcomm.com?part=3
^ permalink raw reply
* Re: [PATCH v4 04/19] firmware: qcom: scm: use dev_err_probe() for dload address failure
From: sashiko-bot @ 2026-06-24 19:22 UTC (permalink / raw)
To: Mukesh Ojha; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260624190830.3131112-5-mukesh.ojha@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] The global `qcom_tzmem_dev` pointer is set during `qcom_tzmem_enable()` but is never cleared on probe failure, causing subsequent probe retries to permanently fail with `-EBUSY`.
- [High] The probe function calls `of_reserved_mem_device_init()` but does not call `of_reserved_mem_device_release()` on subsequent error paths, leading to permanent probe failure or resource leaks upon probe retry.
--
commit 6dc15526252b78a9c217f06ed35ed4966a794450
Author: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
firmware: qcom: scm: use dev_err_probe() for dload address failure
Replace the bare return ret after qcom_scm_find_dload_address() with
dev_err_probe() to produce a consistent, deferred-probe-aware error
message when the download-mode address cannot be resolved.
> diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
> index c8a84836887f0..6cd4d9468456f 100644
> --- a/drivers/firmware/qcom/qcom_scm.c
> +++ b/drivers/firmware/qcom/qcom_scm.c
> @@ -2750,7 +2750,8 @@ static int qcom_scm_probe(struct platform_device *pdev)
> scm->dev = &pdev->dev;
> ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr);
> if (ret < 0)
> - return ret;
> + return dev_err_probe(&pdev->dev, ret,
> + "Failed to get download mode address\n");
>
> mutex_init(&scm->scm_bw_lock);
[Severity: High]
This is a pre-existing issue, but does qcom_scm_probe() properly release
resources on later probe failures?
Later in qcom_scm_probe(), of_reserved_mem_device_init() is called to setup
reserved memory:
drivers/firmware/qcom/qcom_scm.c:qcom_scm_probe() {
...
ret = of_reserved_mem_device_init(scm->dev);
if (ret && ret != -ENODEV)
return dev_err_probe(scm->dev, ret,
"Failed to setup the reserved memory region for TZ mem\n");
...
}
However, subsequent error paths, such as platform_get_irq_optional() returning
-EPROBE_DEFER, exit directly without calling of_reserved_mem_device_release().
If the probe is deferred, will this cause the next probe attempt to fail with
-EBUSY, or leak memory by duplicating the rmem_assigned_device list entry on
every retry?
[Severity: High]
This is a pre-existing issue, but does qcom_tzmem_enable() cause a permanent
probe failure if qcom_scm_probe() defers later in the function?
qcom_tzmem_enable() sets a static qcom_tzmem_dev pointer in qcom_tzmem.c:
drivers/firmware/qcom/qcom_tzmem.c:qcom_tzmem_enable() {
if (qcom_tzmem_dev)
return -EBUSY;
qcom_tzmem_dev = dev;
return qcom_tzmem_init();
}
Since qcom_scm_probe() does not clear this pointer if it defers after this
call, will subsequent probe retries permanently fail with -EBUSY when
qcom_tzmem_enable() checks the still-set pointer?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624190830.3131112-1-mukesh.ojha@oss.qualcomm.com?part=4
^ permalink raw reply
* Re: [PATCH v4 01/19] dt-bindings: firmware: qcom,scm: Add minidump SRAM property
From: sashiko-bot @ 2026-06-24 19:19 UTC (permalink / raw)
To: Mukesh Ojha; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260624190830.3131112-2-mukesh.ojha@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Missing property type reference (`$ref`) for the `sram` property in the dt-binding schema.
--
commit 6acd1cecaeb951d30398f9208dd4e87b7cfd156e
Author: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
dt-bindings: firmware: qcom,scm: Add minidump SRAM property
This commit adds a new 'sram' property to the Qualcomm SCM dt-binding. The
property is intended to contain a phandle to a region in always-on SRAM used
for minidump download destination configuration. This allows the OS to share
information with the boot firmware across warm resets.
> diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
> index 7918d31f58b4a..82c661db0b616 100644
> --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
> +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
> @@ -127,6 +127,13 @@ properties:
> - description: offset of the download mode control register
> description: TCSR hardware block
>
> + sram:
> + description:
> + Phandle to a region in always-on SRAM used to store the download
> + mode value for boot firmware to read before DDR is initialised on
> + the next warm reset.
> + maxItems: 1
[Severity: Low]
Does this property need an explicit type reference, such as
$ref: /schemas/types.yaml#/definitions/phandle?
Without a type definition, the dt-schema validator might infer the property
as an untyped array based on the presence of maxItems: 1. Could this allow
malformed device trees to pass validation silently since it won't enforce
that the provided value is actually a valid phandle?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624190830.3131112-1-mukesh.ojha@oss.qualcomm.com?part=1
^ permalink raw reply
* [PATCH v4 19/19] arm64: dts: qcom: sdm845: Add minidump SRAM config to SCM node
From: Mukesh Ojha @ 2026-06-24 19:08 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Robert Marko, Guru Das Srinagesh
Cc: cros-qcom-dts-watchers, linux-arm-msm, devicetree, linux-kernel,
Mukesh Ojha
In-Reply-To: <20260624190830.3131112-1-mukesh.ojha@oss.qualcomm.com>
Point the SCM node at the minidump config slot in the always-on SRAM.
Boot firmware reads this word before DDR is initialised on a warm reset
to decide where to deliver the minidump.
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/sdm845.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 4ae8627d6dbc..2179988dbaaf 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -363,6 +363,7 @@ cluster_sleep_0: cluster-sleep-0 {
firmware {
scm {
compatible = "qcom,scm-sdm845", "qcom,scm";
+ sram = <&minidump_config>;
};
};
@@ -5192,6 +5193,10 @@ sram@14680000 {
ranges = <0 0 0x14680000 0x40000>;
+ minidump_config: minidump-sram@1c {
+ reg = <0x1c 0x4>;
+ };
+
ipa_modem_tables: modem-tables@3d000 {
reg = <0x3d000 0x2000>;
};
--
2.53.0
^ permalink raw reply related
* [PATCH v4 18/19] arm64: dts: qcom: qcs615: Add minidump SRAM config to SCM node
From: Mukesh Ojha @ 2026-06-24 19:08 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Robert Marko, Guru Das Srinagesh
Cc: cros-qcom-dts-watchers, linux-arm-msm, devicetree, linux-kernel,
Mukesh Ojha, Konrad Dybcio
In-Reply-To: <20260624190830.3131112-1-mukesh.ojha@oss.qualcomm.com>
Point the SCM node at the minidump config slot in the always-on SRAM.
Boot firmware reads this word before DDR is initialised on a warm reset
to decide where to deliver the minidump.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/talos.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index fb1bbc51bb8a..a358d5441fa9 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -473,6 +473,7 @@ firmware {
scm {
compatible = "qcom,scm-qcs615", "qcom,scm";
qcom,dload-mode = <&tcsr 0x13000>;
+ sram = <&minidump_config>;
};
};
@@ -4654,6 +4655,10 @@ sram@14680000 {
#address-cells = <1>;
#size-cells = <1>;
+ minidump_config: minidump-sram@1c {
+ reg = <0x1c 0x4>;
+ };
+
pil-reloc@2a94c {
compatible = "qcom,pil-reloc-info";
reg = <0x2a94c 0xc8>;
--
2.53.0
^ permalink raw reply related
* [PATCH v4 17/19] arm64: dts: qcom: sm6375: Add minidump SRAM config to SCM node
From: Mukesh Ojha @ 2026-06-24 19:08 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Robert Marko, Guru Das Srinagesh
Cc: cros-qcom-dts-watchers, linux-arm-msm, devicetree, linux-kernel,
Mukesh Ojha, Konrad Dybcio
In-Reply-To: <20260624190830.3131112-1-mukesh.ojha@oss.qualcomm.com>
Point the SCM node at the minidump config slot in the always-on SRAM.
Boot firmware reads this word before DDR is initialised on a warm reset
to decide where to deliver the minidump.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/sm6375.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sm6375.dtsi b/arch/arm64/boot/dts/qcom/sm6375.dtsi
index ccf572bb1549..71a228597093 100644
--- a/arch/arm64/boot/dts/qcom/sm6375.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6375.dtsi
@@ -307,6 +307,7 @@ scm {
compatible = "qcom,scm-sm6375", "qcom,scm";
clocks = <&rpmcc RPM_SMD_CE1_CLK>;
clock-names = "core";
+ sram = <&minidump_config>;
#reset-cells = <1>;
};
};
@@ -1645,6 +1646,10 @@ sram@c125000 {
#address-cells = <1>;
#size-cells = <1>;
+ minidump_config: minidump-sram@1c {
+ reg = <0x1c 0x4>;
+ };
+
pil-reloc@94c {
compatible = "qcom,pil-reloc-info";
reg = <0x94c 0xc8>;
--
2.53.0
^ permalink raw reply related
* [PATCH v4 16/19] arm64: dts: qcom: sm6350: Add minidump SRAM config to SCM node
From: Mukesh Ojha @ 2026-06-24 19:08 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Robert Marko, Guru Das Srinagesh
Cc: cros-qcom-dts-watchers, linux-arm-msm, devicetree, linux-kernel,
Mukesh Ojha, Konrad Dybcio
In-Reply-To: <20260624190830.3131112-1-mukesh.ojha@oss.qualcomm.com>
Point the SCM node at the minidump config slot in the always-on SRAM.
Boot firmware reads this word before DDR is initialised on a warm reset
to decide where to deliver the minidump.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/sm6350.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi
index d6adf68563cb..06892ba22875 100644
--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi
@@ -363,6 +363,7 @@ big_cpu_sleep_1: cpu-sleep-1-1 {
firmware {
scm: scm {
compatible = "qcom,scm-sm6350", "qcom,scm";
+ sram = <&minidump_config>;
#reset-cells = <1>;
};
};
@@ -2808,6 +2809,10 @@ sram@14680000 {
ranges = <0 0 0x14680000 0x2e000>;
+ minidump_config: minidump-sram@1c {
+ reg = <0x1c 0x4>;
+ };
+
ipa_modem_tables: modem-tables@28000 {
reg = <0x28000 0x2000>;
};
--
2.53.0
^ permalink raw reply related
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