From: Bryan O'Donoghue <bod@kernel.org>
To: geocausa@gmail.com, Sergey Lebedev <lsa.uz@pm.me>,
Andre Gilerson <andre.gilerson@gmail.com>
Cc: Sakari Ailus <sakari.ailus@linux.intel.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
German Pablo Lindo <germanpapulindez@gmail.com>,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH RFC 2/2] media: i2c: imx681: Add C-PHY support
Date: Fri, 16 Oct 2026 16:54:53 +0100 [thread overview]
Message-ID: <11f1a19d-7d57-497f-826e-901f9f88b99b@kernel.org> (raw)
In-Reply-To: <20261015-imx681-x1e-v1-2-fd22f5f3b0c5@gmail.com>
On 15/10/2026 22:25, George Neacsu via B4 Relay wrote:
> From: George Neacsu <geocausa@gmail.com>
>
> The IMX681 also drives MIPI C-PHY. On the Surface Pro 11 with a
> Snapdragon X Elite it reaches the CAMSS CSIPHY over one C-PHY trio,
> which Windows runs at 2.4 Gsym/s.
How do we know that ?
> Only the signalling, the lane count and the output PLL differ from the
> two-lane D-PHY set-up of the Intel model. The read-out window and the
> pixel array PLL stay as they are, and so does the pixel rate: Windows on
> the Snapdragon model programs the same video timing PLL, and its line and
> frame lengths give 720 MHz at 30 fps too.
How do we know what windows does on the Snapdragon ? Has the file been
analysed ?
Are we inferring what Windows does or asserting what it does ?
Describe each bus by those
> three values and its link frequency, pick the one the endpoint asks for,
> and write them after the register list:
>
> - CSI_SIGNALING_MODE: 2 for D-PHY, 3 for C-PHY, as CCS numbers them;
> - CSI_LANE_MODE: the number of lanes or trios, minus one;
> - OP_PLL_MULTIPLIER: 303 for D-PHY as before, 375 for C-PHY, so
> 19.2 MHz / 3 * 375 = 2400 Msym/s, a 1.2 GHz link frequency by the V4L2
> convention for C-PHY (half the symbol rate).
>
> CSI_LANE_MODE was not written before. It is now written for D-PHY too,
> with the value two lanes need.
>
> Tested on the Surface Pro 11 (X1E80100), with the endpoint on one C-PHY
> trio at 1.2 GHz and CAMSS capturing raw frames over CSIPHY2, CSID1 and an
> RDI interface: 3844x2640 at 29.99 fps, the colour-bar test pattern
> arrives intact, a scene captures, and VBLANK still sets the frame rate
> (8.19 fps at 9000 lines). The D-PHY path is not tested here.
>
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: George Neacsu <geocausa@gmail.com>
> ---
> drivers/media/i2c/imx681.c | 95 +++++++++++++++++++++++++++++++++-------------
> 1 file changed, 69 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/media/i2c/imx681.c b/drivers/media/i2c/imx681.c
> index 6c8e4b3..c660f06 100644
> --- a/drivers/media/i2c/imx681.c
> +++ b/drivers/media/i2c/imx681.c
> @@ -77,6 +77,9 @@
> #define IMX681_REG_LINE_LENGTH CCI_REG16(0x0342)
> #define IMX681_REG_ORIENTATION CCI_REG8(0x0101)
> #define IMX681_REG_CSI_SIGNALING_MODE CCI_REG8(0x0111)
> +#define IMX681_CSI_SIGNALING_DPHY 0x02
> +#define IMX681_CSI_SIGNALING_CPHY 0x03
How do we know 0x03 means CPHY ? Could it bit 0x01 for example ?
The commit log needs to elucidate that information - I guess, I tested,
the LLM told me so, reverse engineered the windows driver binaries -
whatever.
I'm not concerned about the provenance of the information more its
correctness.
> +#define IMX681_REG_CSI_LANE_MODE CCI_REG8(0x0114)
Same here. I _suspect_ the answer is opening the sensor init files on
the windows partition, matching the patterns and inferring the missing
register but, lets document that process somewhere.
> #define IMX681_REG_EXTCLK_FREQ_MHZ CCI_REG16(0x0136)
> #define IMX681_REG_PLL_MULTIPLIER CCI_REG16(0x0306)
> #define IMX681_REG_OP_PRE_PLL_CLK_DIV CCI_REG16(0x030c)
> @@ -93,7 +96,6 @@
> /* PLL, as the Windows traces configure it and the part reads back. */
> #define IMX681_PLL_MULTIPLIER 225
> #define IMX681_OP_PRE_PLL_CLK_DIV 3
> -#define IMX681_OP_PLL_MULTIPLIER 303
>
> /*
> * Where the read-out window sits in the pixel array, and how much array
> @@ -119,16 +121,44 @@
> #define IMX681_FRAME_LENGTH_LINES 3177 /* 0x0C69 */
> #define IMX681_FRAME_LENGTH_MAX 0xFFFF /* 24-bit reg, limit to 16-bit */
>
> -/* MIPI lanes */
> -#define IMX681_NUM_LANES 2
> -
> /*
> - * Link frequency derived from PLL settings in Windows trace:
> - * EXCK=19.2MHz, PLL2_MUL=303, PLL2_PRE_DIV=3
> - * OP output = 19.2 * 303 / 3 = 1939.2 MHz (MIPI bit rate)
> - * Link freq = 1939.2 / 2 (DDR) = 969.6 MHz
> + * The part drives either bus. Only the signalling, the lane count and the
> + * output PLL differ between them: the pixel array, its PLL and the read-out
> + * window stay as they are, so the pixel rate below holds for both.
> */
> -#define IMX681_LINK_FREQ 969600000LL
> +struct imx681_bus {
> + enum v4l2_mbus_type type;
> + unsigned int lanes;
> + u8 signaling_mode;
> + u16 op_pll_multiplier;
> + s64 link_freq;
> +};
> +
> +static const struct imx681_bus imx681_buses[] = {
> + /*
> + * D-PHY, two lanes, as on the Surface Pro 11 for Business (Intel):
> + * 19.2 MHz / 3 * 303 = 1939.2 Mbps per lane, so a 969.6 MHz link.
> + */
> + {
> + .type = V4L2_MBUS_CSI2_DPHY,
> + .lanes = 2,
> + .signaling_mode = IMX681_CSI_SIGNALING_DPHY,
> + .op_pll_multiplier = 303,
> + .link_freq = 969600000,
> + },
> + /*
> + * C-PHY, one trio, as on the Surface Pro 11 (Snapdragon X Elite):
> + * 19.2 MHz / 3 * 375 = 2400 Msym/s, and a C-PHY link frequency is half
> + * the symbol rate.
> + */
> + {
> + .type = V4L2_MBUS_CSI2_CPHY,
> + .lanes = 1,
> + .signaling_mode = IMX681_CSI_SIGNALING_CPHY,
> + .op_pll_multiplier = 375,
> + .link_freq = 1200000000,
> + },
> +};
>
> /*
> * The pixel rate cannot be derived from the CSI-2 link: this part runs two
> @@ -154,21 +184,15 @@
>
> #define IMAGE_PAD 0
>
> -static const s64 imx681_link_frequencies[] = {
> - IMX681_LINK_FREQ,
> -};
> -
> /*
> * Sensor init register sequence, captured from Windows I2C traces.
> * This configures the sensor for 3844x2640 RAW10 output at ~30fps
> - * with 2-lane MIPI CSI-2, 19.2MHz input clock.
> + * from a 19.2MHz input clock; imx681_start_streaming() adds the bus.
> */
> static const struct cci_reg_sequence imx681_init_regs[] = {
> { IMX681_REG_EXTCLK_FREQ_MHZ, IMX681_XCLK_FREQ_ENC },
> /* Vendor specific configuration */
> { CCI_REG16(0x002C), 0x0505 },
> - /* 0x02 is D-PHY, which is the only mode this part offers. */
> - { IMX681_REG_CSI_SIGNALING_MODE, 0x02 },
> /* Vendor access unlock sequence */
> { CCI_REG8(0x30EB), 0x05 },
> { CCI_REG8(0x30EB), 0x0C },
> @@ -197,11 +221,10 @@ static const struct cci_reg_sequence imx681_init_regs[] = {
> * low byte of PLL_MULTIPLIER and 0x030d the low byte of
> * OP_PRE_PLL_CLK_DIV, and each was right only while its high byte
> * held the reset value. Written whole, and the part reads back
> - * 225, 3 and 303 at the operating point either way.
> + * 225 and 3 at the operating point either way.
> */
> { IMX681_REG_PLL_MULTIPLIER, IMX681_PLL_MULTIPLIER },
> { IMX681_REG_OP_PRE_PLL_CLK_DIV, IMX681_OP_PRE_PLL_CLK_DIV },
> - { IMX681_REG_OP_PLL_MULTIPLIER, IMX681_OP_PLL_MULTIPLIER },
> /* Vendor specific registers */
> { CCI_REG8(0x7E9B), 0x02 },
> { CCI_REG8(0x0368), 0x00 },
> @@ -259,6 +282,7 @@ struct imx681 {
> struct v4l2_ctrl *hflip;
> struct v4l2_ctrl *vflip;
>
> + const struct imx681_bus *bus;
> unsigned long link_freq_bitmap;
> };
>
> @@ -508,6 +532,17 @@ static int imx681_start_streaming(struct imx681 *imx681)
> return ret;
> }
>
> + cci_write(imx681->cci, IMX681_REG_CSI_SIGNALING_MODE,
> + imx681->bus->signaling_mode, &ret);
> + cci_write(imx681->cci, IMX681_REG_CSI_LANE_MODE,
> + imx681->bus->lanes - 1, &ret);
> + cci_write(imx681->cci, IMX681_REG_OP_PLL_MULTIPLIER,
> + imx681->bus->op_pll_multiplier, &ret);
> + if (ret) {
> + dev_err(imx681->dev, "failed to configure the bus: %d\n", ret);
> + return ret;
> + }
> +
> /* Wait for sensor to stabilise after configuration */
> usleep_range(IMX681_INIT_DELAY_US, IMX681_INIT_DELAY_US + 1000);
>
> @@ -711,7 +746,7 @@ static int imx681_init_controls(struct imx681 *imx681)
> V4L2_CID_LINK_FREQ,
> __fls(imx681->link_freq_bitmap),
> __ffs(imx681->link_freq_bitmap),
> - imx681_link_frequencies);
> + &imx681->bus->link_freq);
> if (link_freq)
> link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
> @@ -814,9 +849,10 @@ static int imx681_parse_endpoint(struct imx681 *imx681)
> {
> struct fwnode_handle *fwnode = dev_fwnode(imx681->dev);
> struct v4l2_fwnode_endpoint bus_cfg = {
> - .bus_type = V4L2_MBUS_CSI2_DPHY,
> + .bus_type = V4L2_MBUS_UNKNOWN,
> };
> struct fwnode_handle *ep;
> + unsigned int lanes;
> int ret;
>
> ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
> @@ -827,19 +863,26 @@ static int imx681_parse_endpoint(struct imx681 *imx681)
> return dev_err_probe(imx681->dev, ret,
> "failed to parse endpoint\n");
>
> - if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX681_NUM_LANES) {
> + /* Without a bus-type, an endpoint with data-lanes parses as D-PHY. */
> + lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
> + for (unsigned int i = 0; i < ARRAY_SIZE(imx681_buses); i++) {
> + if (imx681_buses[i].type == bus_cfg.bus_type &&
> + imx681_buses[i].lanes == lanes)
> + imx681->bus = &imx681_buses[i];
> + }
> +
> + if (!imx681->bus) {
> ret = dev_err_probe(imx681->dev, -EINVAL,
> - "expected %d data lanes, got %d\n",
> - IMX681_NUM_LANES,
> - bus_cfg.bus.mipi_csi2.num_data_lanes);
> + "unsupported bus: %s with %u lanes\n",
> + bus_cfg.bus_type == V4L2_MBUS_CSI2_CPHY ?
> + "C-PHY" : "D-PHY", lanes);
> goto done;
> }
>
> ret = v4l2_link_freq_to_bitmap(imx681->dev,
> bus_cfg.link_frequencies,
> bus_cfg.nr_of_link_frequencies,
> - imx681_link_frequencies,
> - ARRAY_SIZE(imx681_link_frequencies),
> + &imx681->bus->link_freq, 1,
> &imx681->link_freq_bitmap);
> if (ret)
> ret = dev_err_probe(imx681->dev, ret,
>
> --
> 2.53.0
next prev parent reply other threads:[~2026-10-16 15:54 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-15 21:25 [PATCH RFC 0/2] media: imx681: C-PHY for the Surface Pro 11 (Snapdragon) George Neacsu via B4 Relay
2026-10-15 21:25 ` [PATCH RFC 1/2] dt-bindings: media: sony,imx681: Allow a C-PHY bus George Neacsu via B4 Relay
2026-10-16 15:59 ` Bryan O'Donoghue
2026-10-16 16:08 ` George Neacsu
2026-10-15 21:25 ` [PATCH RFC 2/2] media: i2c: imx681: Add C-PHY support George Neacsu via B4 Relay
2026-10-16 15:54 ` Bryan O'Donoghue [this message]
2026-10-16 16:08 ` George Neacsu
2026-10-16 7:00 ` [PATCH RFC 0/2] media: imx681: C-PHY for the Surface Pro 11 (Snapdragon) Sergey Lebedev
2026-10-16 14:55 ` George Neacsu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11f1a19d-7d57-497f-826e-901f9f88b99b@kernel.org \
--to=bod@kernel.org \
--cc=andre.gilerson@gmail.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=geocausa@gmail.com \
--cc=germanpapulindez@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=lsa.uz@pm.me \
--cc=mchehab@kernel.org \
--cc=robh@kernel.org \
--cc=sakari.ailus@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox