[PATCH v4 4/6] media: synopsys: Add PHY stopstate wait for i.MX93
G.N. Zhou (OSS)
guoniu.zhou at oss.nxp.com
Thu May 21 18:58:56 PDT 2026
Hi Alexander,
> -----Original Message-----
> From: Alexander Stein <alexander.stein at ew.tq-group.com>
> Sent: Thursday, May 21, 2026 7:53 PM
> To: Michael Riesch <michael.riesch at collabora.com>; Mauro Carvalho Chehab
> <mchehab at kernel.org>; Rob Herring <robh at kernel.org>; Krzysztof Kozlowski
> <krzk+dt at kernel.org>; Conor Dooley <conor+dt at kernel.org>; Heiko Stuebner
> <heiko at sntech.de>; Laurent Pinchart <laurent.pinchart at ideasonboard.com>;
> Frank Li <frank.li at nxp.com>; Sakari Ailus <sakari.ailus at linux.intel.com>; Bryan
> O'Donoghue <bryan.odonoghue at linaro.org>; Mehdi Djait
> <mehdi.djait at linux.intel.com>; Hans Verkuil <hverkuil+cisco at kernel.org>;
> G.N. Zhou (OSS) <guoniu.zhou at oss.nxp.com>; G.N. Zhou (OSS)
> <guoniu.zhou at oss.nxp.com>
> Cc: linux-media at vger.kernel.org; linux-kernel at vger.kernel.org;
> devicetree at vger.kernel.org; imx at lists.linux.dev; linux-arm-
> kernel at lists.infradead.org; linux-rockchip at lists.infradead.org; G.N. Zhou (OSS)
> <guoniu.zhou at oss.nxp.com>
> Subject: Re: [PATCH v4 4/6] media: synopsys: Add PHY stopstate wait for
> i.MX93
>
> 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 <alexander.stein at ew.tq-group.com>
> > > Sent: Wednesday, May 20, 2026 7:12 PM
> > > To: Michael Riesch <michael.riesch at collabora.com>; Mauro Carvalho
> > > Chehab <mchehab at kernel.org>; Rob Herring <robh at kernel.org>;
> > > Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley
> > > <conor+dt at kernel.org>; Heiko Stuebner <heiko at sntech.de>; Laurent
> > > Pinchart <laurent.pinchart at ideasonboard.com>;
> > > Frank Li <frank.li at nxp.com>; Sakari Ailus
> > > <sakari.ailus at linux.intel.com>; Bryan O'Donoghue
> > > <bryan.odonoghue at linaro.org>; Mehdi Djait
> > > <mehdi.djait at linux.intel.com>; Hans Verkuil
> > > <hverkuil+cisco at kernel.org>; G.N. Zhou (OSS)
> > > <guoniu.zhou at oss.nxp.com>
> > > Cc: linux-media at vger.kernel.org; linux-kernel at vger.kernel.org;
> > > devicetree at vger.kernel.org; imx at lists.linux.dev; linux-arm-
> > > kernel at lists.infradead.org; linux-rockchip at lists.infradead.org; G.N.
> > > Zhou (OSS) <guoniu.zhou at oss.nxp.com>
> > > 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 <Frank.Li at nxp.com>
> > > > Signed-off-by: Guoniu Zhou <guoniu.zhou at oss.nxp.com>
> > > > ---
> > > > 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.
As mentioned in #2, I reviewed drivers/media/i2c/imx290.c and identified a 30ms
delay that appears to be the root cause of this issue.
The problem occurs because:
The sensor exits LP-11 state and transitions to HS mode after IMX290_XMSTA is written
The 30ms delay in s_stream() causes the function to return late
By the time the CSI controller performs its lane state check, the sensor has already switched
from LP-11 to HS mode, causing the check to fail。
Proposed fix:
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 21cbc81cb2ed..519aa336249a 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -1059,7 +1059,6 @@ static int imx290_start_streaming(struct imx290 *imx290,
cci_write(imx290->regmap, IMX290_STANDBY, 0x00, &ret);
- msleep(30);
/* Start streaming */
return cci_write(imx290->regmap, IMX290_XMSTA, 0x00, &ret);
Removing this delay allows s_stream() to return immediately, giving the CSI controller
time to complete its initialization before the sensor transitions PHY state.
Could you test this patch and confirm if it resolves the lane state check failure?
Best Regards
G.N Zhou
>
> 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/20250701-95_cam-v1-2-
> c5172bab387b at nxp.com/
> 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/
>
More information about the linux-arm-kernel
mailing list