Subject: Re: [PATCH v4 4/6] media: synopsys: Add PHY stopstate wait for i.MX93

From: Alexander Stein <[email-masked]>
Date: Thu, 21 May 2026 13:52:31 +0200

Hi,

thanks for the replay.

Am Donnerstag, 21. Mai 2026, 11:29:39 CEST schrieb G.N. Zhou (OSS):
> Hi Alexander,
> 
> > -----Original Message-----
> > From: Alexander Stein <[email-masked]>
> > Sent: Wednesday, May 20, 2026 7:12 PM
> > To: Michael Riesch <[email-masked]>; Mauro Carvalho Chehab
> > <[email-masked]>; Rob Herring <[email-masked]>; Krzysztof Kozlowski
> > <[email-masked]>; Conor Dooley <[email-masked]>; Heiko Stuebner
> > <[email-masked]>; Laurent Pinchart <[email-masked]>;
> > Frank Li <[email-masked]>; Sakari Ailus <[email-masked]>; Bryan
> > O'Donoghue <[email-masked]>; Mehdi Djait
> > <[email-masked]>; Hans Verkuil <[email-masked]>;
> > G.N. Zhou (OSS) <[email-masked]>
> > Cc: [email-masked]; [email-masked];
> > [email-masked]; [email-masked]; linux-arm-
> > [email-masked]; [email-masked]; G.N. Zhou (OSS)
> > <[email-masked]>
> > Subject: Re: [PATCH v4 4/6] media: synopsys: Add PHY stopstate wait for
> > i.MX93
> > 
> > Hi,
> > 
> > Am Dienstag, 19. Mai 2026, 04:07:41 CEST schrieb Guoniu Zhou:
> > > Implement waiting for D-PHY lanes to enter stop state on i.MX93. This
> > > ensures proper PHY initialization by verifying that the clock lane and
> > > all active data lanes have entered the stop state before proceeding
> > > with further operations.
> > >
> > > Reviewed-by: Frank Li <[email-masked]>
> > > Signed-off-by: Guoniu Zhou <[email-masked]>
> > > ---
> > > Changes in v2:
> > > - Removes redundant register availability check
> > > - Uses read_poll_timeout() with dw_mipi_csi2rx_read() instead of
> > >   readl_poll_timeout() with direct register address
> > > - Fixes stopstate condition logic
> > > - Check PHY stopstate after sensor enable instead of before to ensure
> > >   correct timing.
> > > - Optimize PHY stopstate polling parameters (1000us->10us, 2s->1ms) to
> > >   balance performance and responsiveness.
> > > ---
> > >  drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 36
> > > ++++++++++++++++++++++++
> > >  1 file changed, 36 insertions(+)
> > >
> > > diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > index 92178a3dec5d..8a34aec550ad 100644
> > > --- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > +++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > @@ -11,6 +11,7 @@
> > >  #include <linux/clk.h>
> > >  #include <linux/delay.h>
> > >  #include <linux/io.h>
> > > +#include <linux/iopoll.h>
> > >  #include <linux/module.h>
> > >  #include <linux/of.h>
> > >  #include <linux/phy/phy.h>
> > > @@ -35,6 +36,8 @@
> > >  #define DW_REG_EXIST		BIT(31)
> > >  #define DW_REG(x)		(DW_REG_EXIST | (x))
> > >
> > > +#define DPHY_STOPSTATE_CLK_LANE		BIT(16)
> > > +
> > >  #define DPHY_TEST_CTRL0_TEST_CLR	BIT(0)
> > >
> > >  #define IPI_VCID_VC(x)			FIELD_PREP(GENMASK(1, 0),
> > (x))
> > > @@ -65,6 +68,7 @@ enum dw_mipi_csi2rx_regs_index {
> > >  	DW_MIPI_CSI2RX_PHY_TST_CTRL0,
> > >  	DW_MIPI_CSI2RX_PHY_TST_CTRL1,
> > >  	DW_MIPI_CSI2RX_PHY_SHUTDOWNZ,
> > > +	DW_MIPI_CSI2RX_PHY_STOPSTATE,
> > >  	DW_MIPI_CSI2RX_IPI_DATATYPE,
> > >  	DW_MIPI_CSI2RX_IPI_MEM_FLUSH,
> > >  	DW_MIPI_CSI2RX_IPI_MODE,
> > > @@ -87,6 +91,7 @@ struct dw_mipi_csi2rx_drvdata {
> > >  	void (*dphy_assert_reset)(struct dw_mipi_csi2rx_device *csi2);
> > >  	void (*dphy_deassert_reset)(struct dw_mipi_csi2rx_device *csi2);
> > >  	void (*ipi_enable)(struct dw_mipi_csi2rx_device *csi2);
> > > +	int (*wait_for_phy_stopstate)(struct dw_mipi_csi2rx_device *csi2);
> > >  };
> > >
> > >  struct dw_mipi_csi2rx_format {
> > > @@ -139,6 +144,7 @@ static const u32 imx93_regs[DW_MIPI_CSI2RX_MAX]
> > = {
> > >  	[DW_MIPI_CSI2RX_PHY_SHUTDOWNZ] = DW_REG(0x40),
> > >  	[DW_MIPI_CSI2RX_DPHY_RSTZ] = DW_REG(0x44),
> > >  	[DW_MIPI_CSI2RX_PHY_STATE] = DW_REG(0x48),
> > > +	[DW_MIPI_CSI2RX_PHY_STOPSTATE] = DW_REG(0x4c),
> > >  	[DW_MIPI_CSI2RX_PHY_TST_CTRL0] = DW_REG(0x50),
> > >  	[DW_MIPI_CSI2RX_PHY_TST_CTRL1] = DW_REG(0x54),
> > >  	[DW_MIPI_CSI2RX_IPI_MODE] = DW_REG(0x80), @@ -556,10 +562,19
> > @@
> > > static int dw_mipi_csi2rx_enable_streams(struct v4l2_subdev *sd,
> > >  	if (ret)
> > >  		goto err_csi_stop;
> > >
> > > +	if (!csi2->enabled_streams &&
> > > +	    csi2->drvdata->wait_for_phy_stopstate) {
> > > +		ret = csi2->drvdata->wait_for_phy_stopstate(csi2);
> > > +		if (ret)
> > > +			goto err_disable_streams;
> > > +	}
> > > +
> > >  	csi2->enabled_streams |= streams_mask;
> > >
> > >  	return 0;
> > >
> > > +err_disable_streams:
> > > +	v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
> > >  err_csi_stop:
> > >  	/* Stop CSI hardware if no streams are enabled */
> > >  	if (!csi2->enabled_streams)
> > > @@ -871,11 +886,32 @@ static void imx93_csi2rx_dphy_ipi_enable(struct
> > dw_mipi_csi2rx_device *csi2)
> > >  	dw_mipi_csi2rx_write(csi2, DW_MIPI_CSI2RX_IPI_MODE, val);  }
> > >
> > > +static int imx93_csi2rx_wait_for_phy_stopstate(struct
> > > +dw_mipi_csi2rx_device *csi2) {
> > > +	struct device *dev = csi2->dev;
> > > +	u32 stopstate_mask;
> > > +	u32 val;
> > > +	int ret;
> > > +
> > > +	stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(csi2-
> > >lanes_num -
> > > +1, 0);
> > > +
> > > +	ret = read_poll_timeout(dw_mipi_csi2rx_read, val,
> > > +				(val & stopstate_mask) == stopstate_mask,
> > > +				 10, 1000, true,
> > > +				 csi2, DW_MIPI_CSI2RX_PHY_STOPSTATE);
> > > +	if (ret)
> > > +		dev_err(dev, "lanes are not in stop state: %#x,
> > expected %#x\n",
> > > +			val, stopstate_mask);
> > 
> > Did you actually test this on imx93? I'm trying to get my imx327 sensor to run,
> > but only run into this error message:
> > dw-mipi-csi2rx 4ae00000.mipi-csi: lanes are not in stop state: 0x0, expected
> > 0x10003
> 
> Thanks for testing. Regarding the lane stop state error on i.MX93 with imx327:
> 
> This error indicates the CSI-2 lanes are not in LP-11 (stop) state when 
> expected. Please check:
> 
> 1) Verify the sensor PHY is in LP-11 state before returning from the sensor's 
>    s_stream(1) call. The CSI-2 receiver expects lanes to be in stop state 
>    initially.

Well, this might be tricky as I don't have D-PHY capable scopes.
I can successfully use this sensor on a imx8mp, so I am expecting this to be
okay.

> 2) Check if the imx327 driver has a delay between starting the stream and 
>    returning from s_stream(). If the sensor transitions PHY out of LP-11 
>    state during this delay, the CSI driver's lane state check will fail 
>    when it runs later. The sensor should remain in LP-11 until the CSI 
>    controller completes its initialization.

In imx290_set_stream() and subsequently imx290_start_streaming() setting
IMX290_XMSTA starts the stream. I expect this is the point when the sensors
switches from LP-11 to HS. But again, I can't verify.

With enabling debug
> echo "module videodev +p" > /sys/kernel/debug/dynamic_debug/control
> echo 0xff > /sys/class/video4linux/video0/dev_debug

After I setup the media pipeline, running the command
> v4l2-ctl -z "platform:4ae40000.isi" -d "mxc_isi.0.capture" --stream-mmap --stream-count=1 --stream-to=imx93.raw
I get the following debug output:

--8<--
plane 0: bytesperline=3840 sizeimage=4147200
mxc-isi 4ae40000.isi: validating link "crossbar":2 -> "mxc_isi.0":0
mxc-isi 4ae40000.isi: validating stream "crossbar":2:0 -> "mxc_isi.0":0:0
mxc-isi 4ae40000.isi: validating link "dw-mipi-csi2rx 4ae00000.mipi-csi":1 -> "crossbar":0
mxc-isi 4ae40000.isi: validating stream "dw-mipi-csi2rx 4ae00000.mipi-csi":1:0 -> "crossbar":0:0
mxc-isi 4ae40000.isi: validating link "imx327 4-001a":0 -> "dw-mipi-csi2rx 4ae00000.mipi-csi":0
mxc-isi 4ae40000.isi: validating stream "imx327 4-001a":0:0 -> "dw-mipi-csi2rx 4ae00000.mipi-csi":0:0
mxc-isi 4ae40000.isi: enable streams "crossbar":2/0x1
mxc-isi 4ae40000.isi: collect_streams: "crossbar":2: found 0x1 enabled 0x0
imx290 4-001a: Frame descriptor on pad 0, type CSI-2
imx290 4-001a:   stream 0, code 0x300f, length 0, flags 0x0000, vc 0, dt 0x2b
dw-mipi-csi2rx 4ae00000.mipi-csi: Frame descriptor on pad 1, type CSI-2
dw-mipi-csi2rx 4ae00000.mipi-csi:        stream 0, code 0x300f, length 0, flags 0x0000, vc 0, dt 0x2b
mxc-isi 4ae40000.isi: enable streams "dw-mipi-csi2rx 4ae00000.mipi-csi":1/0x1
dw-mipi-csi2rx 4ae00000.mipi-csi: collect_streams: "dw-mipi-csi2rx 4ae00000.mipi-csi":1: found 0x1 enabled 0x0
mxc-isi 4ae40000.isi: enable streams "imx327 4-001a":0/0x1
imx290 4-001a: collect_streams: sub-device "imx327 4-001a" does not support streams
dw-mipi-csi2rx 4ae00000.mipi-csi: lanes are not in stop state: 0x0, expected 0x10003
mxc-isi 4ae40000.isi: disable streams "imx327 4-001a":0/0x1
imx290 4-001a: collect_streams: sub-device "imx327 4-001a" does not support streams
mxc-isi 4ae40000.isi: enable streams 1:0x1 failed: -110
mxc-isi 4ae40000.isi: failed to enable streams 0x1 on 'dw-mipi-csi2rx 4ae00000.mipi-csi':1: -110
mxc-isi 4ae40000.isi: enable streams 2:0x1 failed: -110
mxc-isi 4ae40000.isi: Failed to enable pipe 0
video0: VIDIOC_STREAMON: error -110: type=vid-cap-mplane
videodev: v4l2_release: video0: release
--8<--

For completeness this is my media device config
--8<--
# media-ctl  -p
Media controller API version 7.1.0

Media device information
------------------------
driver          mxc-isi
model           FSL Capture Media Device
serial          
bus info        platform:4ae40000.isi
hw revision     0x0
driver version  7.1.0

Device topology
- entity 1: crossbar (3 pads, 2 links, 1 route)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev0
        routes:
                0/0 -> 2/0 [ACTIVE]
        pad0: SINK,MUST_CONNECT
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw]
                <- "dw-mipi-csi2rx 4ae00000.mipi-cs":1 [ENABLED,IMMUTABLE]
        pad1: SINK,MUST_CONNECT
        pad2: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw]
                -> "mxc_isi.0":0 [ENABLED,IMMUTABLE]

- entity 5: mxc_isi.0 (2 pads, 2 links, 0 routes)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
        pad0: SINK
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw
                 compose.bounds:(0,0)/1920x1080
                 compose:(0,0)/1920x1080]
                <- "crossbar":2 [ENABLED,IMMUTABLE]
        pad1: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:jpeg xfer:srgb ycbcr:601 quantization:full-range
                 crop.bounds:(0,0)/1920x1080
                 crop:(0,0)/1920x1080]
                -> "mxc_isi.0.capture":0 [ENABLED,IMMUTABLE]

- entity 8: mxc_isi.0.capture (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
        pad0: SINK
                <- "mxc_isi.0":1 [ENABLED,IMMUTABLE]

- entity 16: dw-mipi-csi2rx 4ae00000.mipi-cs (2 pads, 2 links, 1 route)
             type V4L2 subdev subtype Unknown flags 0
             device node name /dev/v4l-subdev2
        routes:
                0/0 -> 1/0 [ACTIVE]
        pad0: SINK,MUST_CONNECT
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]
                <- "imx327 4-001a":0 [ENABLED]
        pad1: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]
                -> "crossbar":0 [ENABLED,IMMUTABLE]

- entity 21: imx327 4-001a (1 pad, 1 link, 0 routes)
             type V4L2 subdev subtype Sensor flags 0
             device node name /dev/v4l-subdev3
        pad0: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range
                 crop.bounds:(0,0)/1945x1097
                 crop:(12,8)/1920x1080]
                -> "dw-mipi-csi2rx 4ae00000.mipi-cs":0 [ENABLED]
--8<--

Anything odd here?

> You may need to remove any delays in the imx327 s_stream implementation, or 
> ensure the sensor stays in LP-11 state until the CSI receiver is ready.
> 
> If possible, could you share the imx327 driver code or check its s_stream implementation?

It's essentially upstream in drivers/media/i2c/imx290.c.
I only have a dummy implementation for get_frame_desc and a small adjustement
for my camera module regarding i2c access.

--8<--
static int imx290_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
				 struct v4l2_mbus_frame_desc *fd)
{
	const struct v4l2_mbus_framefmt *format;
	struct v4l2_subdev_state *state;

	state = v4l2_subdev_lock_and_get_active_state(sd);
	format = v4l2_subdev_state_get_format(state, pad);
	v4l2_subdev_unlock_state(state);

	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
	fd->num_entries = 1;
	fd->entry[0].pixelcode = format->code;
	fd->entry[0].stream = 0;
	fd->entry[0].bus.csi2.vc = 0;
	fd->entry[0].bus.csi2.dt = MIPI_CSI2_DT_RAW10; //TODO: get_data_type_by_code(format->code);

	return 0;
}
--8<--

Another thing. I use https://lore.kernel.org/imx/[email-masked]/
for the D-PHY. Is there any update/progress on that driver?

Best regards,
Alexander
-- 
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/