Linux-PHY Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack
@ 2026-10-17 17:13 Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 1/6] phy: core: Add MIPI C-PHY configurations Nihal Kumar Gupta
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Nihal Kumar Gupta @ 2026-10-17 17:13 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
	Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Bryan O'Donoghue
  Cc: Vikram Sharma, linux-phy, linux-kernel, linux-media,
	linux-arm-msm, Nihal Kumar Gupta

George posted a C-PHY series [1] which we are currently reviewing.
As discussed with Bryan, this series shares our independent
implementation so the approaches can be compared.

Two aspects covered here are not in [1]:

- Settle count calculation derived from sensor-reported T_PREPARE and
  T_PREAMBLE timing via get_mbus_config(). [1] left this as an open
  question.

- Data rate based register sequence selection using effective bit
  rate (link_freq * 32 / 7). [1] noted downstream does this but
  deferred it; this series implements it.

MIPI CSI-2 operates over two physical layer variants. D-PHY uses a
dedicated differential clock lane with up to four data lanes. C-PHY
encodes the clock within the data stream across up to three wire
trios, eliminating the dedicated clock lane.

Patch 1 extends the generic PHY framework with PHY_MODE_MIPI_CPHY
and struct phy_configure_opts_mipi_cphy.

Patch 2 adds t_prepare_ns and t_preamble_ns fields to the CSI-2
media bus configuration and extends CAMSS to forward them to the PHY
provider for settle count calculation. Sensor drivers must implement
get_mbus_config() and return non-zero values in nanoseconds; stream-on
returns -EINVAL otherwise. The strictness is deliberate: C-PHY settle
timing is symbol-rate-range specific and no safe value can be derived
from link frequency alone. A conservative fallback could be added if
reviewers prefer.

Patches 3-6 extend the Qualcomm CSIPHY driver: refactor D-PHY
register storage to accommodate C-PHY, accept C-PHY mode with
multiple data rate table selection, compute settle count, and add
lane power mask support for C-PHY trios.

C-PHY encodes 16 bits per 7 symbols, so the effective bit rate is:

  bit_rate = link_freq * 2 * 16 / 7 = link_freq * 32 / 7

where link_freq is symbol_rate / 2 as reported by the sensor via
get_mbus_config(). The rate-table entry whose bandwidth first meets
or exceeds bit_rate is selected.

The settle count defines how many timer clock cycles the CSIPHY
receiver waits before scanning for C-PHY sync. It is computed from
the sensor's T_PREPARE and T_PREAMBLE timing. The /3 factor reflects
that C-PHY distributes the preamble sequence across three trios:

  settle_cnt = (t_prepare_ns + t_preamble_ns / 3) * timer_clk_rate / 1e9

D-PHY settle count is unchanged from before this series.

[1] https://lore.kernel.org/all/20261016-x1e-cphy-rfc-v3-0-40a346a72153@gmail.com/

Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
Nihal Kumar Gupta (6):
      phy: core: Add MIPI C-PHY configurations
      media: qcom: camss: Add C-PHY timing fields and get config from sensor
      phy: qcom: mipi-csi2: Split D-PHY register settings
      phy: qcom: mipi-csi2: Accept C-PHY mode and add register sequence
      phy: qcom: mipi-csi2: Add C-PHY settle calculation
      phy: qcom: mipi-csi2: Add lane mask calculation for C-PHY

 drivers/media/platform/qcom/camss/camss-csiphy.c   |  90 +++++++++---
 drivers/media/platform/qcom/camss/camss-csiphy.h   |   2 +
 drivers/media/platform/qcom/camss/camss.c          |   8 +-
 drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 159 +++++++++++++++++----
 drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c     |  51 +++++--
 drivers/phy/qualcomm/phy-qcom-mipi-csi2.h          |  25 +++-
 include/linux/phy/phy.h                            |  47 ++++++
 include/media/v4l2-mediabus.h                      |   2 +
 8 files changed, 315 insertions(+), 69 deletions(-)
---
base-commit: 2efb7a11f1aa4d2dc285fe2680cca22cb9f72f64
change-id: 20261017-cphy_support-2ce4d656e631

Best regards,
-- 
Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH RFC 1/6] phy: core: Add MIPI C-PHY configurations
  2026-10-17 17:13 [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack Nihal Kumar Gupta
@ 2026-10-17 17:13 ` Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 2/6] media: qcom: camss: Add C-PHY timing fields and get config from sensor Nihal Kumar Gupta
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Nihal Kumar Gupta @ 2026-10-17 17:13 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
	Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Bryan O'Donoghue
  Cc: Vikram Sharma, linux-phy, linux-kernel, linux-media,
	linux-arm-msm, Nihal Kumar Gupta

MIPI CSI-2 receivers can be connected through C-PHY as well as D-PHY.
C-PHY uses trios instead of lanes and needs mode-specific timings passed
to the PHY provider.

Add PHY_MODE_MIPI_CPHY and C-PHY configure option carrying the link rate,
trio count and C-PHY prepare/preamble timing.

Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
 include/linux/phy/phy.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index c480d6cb42c500a295eef3bdf42fbc6d36f54bf8..c3784b679f3a26686324286d407cfa9d258579f1 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -47,6 +47,7 @@ enum phy_mode {
 	PHY_MODE_DP,
 	PHY_MODE_HDMI,
 	PHY_MODE_TBT,
+	PHY_MODE_MIPI_CPHY,
 };
 
 enum phy_media {
@@ -64,11 +65,56 @@ union phy_notify {
 	enum phy_ufs_state ufs_state;
 };
 
+/**
+ * struct phy_configure_opts_mipi_cphy - MIPI C-PHY configuration set
+ *
+ * This structure is used to represent the configuration state of a
+ * MIPI C-PHY phy.
+ */
+struct phy_configure_opts_mipi_cphy {
+	/**
+	 * @symbol_rate:
+	 *
+	 * Symbol rate per trio, in symbols per second.
+	 */
+	u64 symbol_rate;
+
+	/**
+	 * @trios:
+	 *
+	 * Number of active C-PHY trios.
+	 *
+	 * Minimum value: 1
+	 * Maximum value: 3
+	 */
+	unsigned int trios;
+
+	/**
+	 * @t_prepare_ns:
+	 *
+	 * C-PHY T_PREPARE timing value, in nanoseconds.
+	 * Time the transmitter drives the LP-00 state before
+	 * starting the HS preamble sequence.
+	 */
+	u32 t_prepare_ns;
+
+	/**
+	 * @t_preamble_ns:
+	 *
+	 * C-PHY T_PREAMBLE timing value, in nanoseconds.
+	 * Duration of the HS preamble sequence transmitted
+	 * before the first payload symbol.
+	 */
+	u32 t_preamble_ns;
+};
+
 /**
  * union phy_configure_opts - Opaque generic phy configuration
  *
  * @mipi_dphy:	Configuration set applicable for phys supporting
  *		the MIPI_DPHY phy mode.
+ * @mipi_cphy:	Configuration set applicable for phys supporting
+ *		the MIPI_CPHY phy mode.
  * @dp:		Configuration set applicable for phys supporting
  *		the DisplayPort protocol.
  * @lvds:	Configuration set applicable for phys supporting
@@ -78,6 +124,7 @@ union phy_notify {
  */
 union phy_configure_opts {
 	struct phy_configure_opts_mipi_dphy	mipi_dphy;
+	struct phy_configure_opts_mipi_cphy	mipi_cphy;
 	struct phy_configure_opts_dp		dp;
 	struct phy_configure_opts_lvds		lvds;
 	struct phy_configure_opts_hdmi		hdmi;

-- 
2.34.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RFC 2/6] media: qcom: camss: Add C-PHY timing fields and get config from sensor
  2026-10-17 17:13 [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 1/6] phy: core: Add MIPI C-PHY configurations Nihal Kumar Gupta
@ 2026-10-17 17:13 ` Nihal Kumar Gupta
  2026-10-17 17:34   ` sashiko-bot
  2026-10-17 17:13 ` [PATCH RFC 3/6] phy: qcom: mipi-csi2: Split D-PHY register settings Nihal Kumar Gupta
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 8+ messages in thread
From: Nihal Kumar Gupta @ 2026-10-17 17:13 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
	Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Bryan O'Donoghue
  Cc: Vikram Sharma, linux-phy, linux-kernel, linux-media,
	linux-arm-msm, Nihal Kumar Gupta

C-PHY settle count is derived from the T_PREPARE and T_PREAMBLE link
timing parameters reported by the transmitter. Add C-PHY prepare and
preamble timing fields to the CSI-2 media bus configuration.

The endpoint bus type already describes whether the connected CSI-2 link
uses D-PHY or C-PHY.

Accept C-PHY endpoints, store the parsed CSI-2 PHY type and query the
remote sensor media bus configuration for C-PHY links. Pass the reported
link frequency and timing to the generic PHY while keeping the existing
D-PHY fallback path.

Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
 drivers/media/platform/qcom/camss/camss-csiphy.c | 90 +++++++++++++++++++-----
 drivers/media/platform/qcom/camss/camss-csiphy.h |  2 +
 drivers/media/platform/qcom/camss/camss.c        |  8 +--
 include/media/v4l2-mediabus.h                    |  2 +
 4 files changed, 79 insertions(+), 23 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index f99eea2ef2289cbee404808348c06968350dc4ac..ed2318d76987d6a9ae7e185d00e258d49d0c79a4 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -313,6 +313,29 @@ static void csiphy_stream_off_legacy(struct csiphy_device *csiphy)
 	csiphy->res->hw_ops->lanes_disable(csiphy, &csiphy->cfg);
 }
 
+static int csiphy_get_remote_mbus_config(struct csiphy_device *csiphy,
+					 struct v4l2_mbus_config *cfg)
+{
+	struct media_pad *remote;
+	struct v4l2_subdev *remote_sd;
+	int ret;
+
+	remote = media_pad_remote_pad_first(&csiphy->pads[MSM_CSIPHY_PAD_SINK]);
+	if (!remote)
+		return -ENOLINK;
+
+	remote_sd = media_entity_to_v4l2_subdev(remote->entity);
+	if (!remote_sd)
+		return -EINVAL;
+
+	memset(cfg, 0, sizeof(*cfg));
+	ret = v4l2_subdev_call(remote_sd, pad, get_mbus_config,
+			      remote->index, cfg);
+	if (ret == -ENOIOCTLCMD)
+		return -EOPNOTSUPP;
+
+	return ret;
+}
 /*
  * csiphy_stream_on - Enable streaming on CSIPHY module
  * @csiphy: CSIPHY device
@@ -324,43 +347,74 @@ static void csiphy_stream_off_legacy(struct csiphy_device *csiphy)
  */
 static int csiphy_stream_on(struct csiphy_device *csiphy)
 {
+	struct v4l2_mbus_config mbus_cfg = { };
 	u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
 				csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
 	struct csiphy_lanes_cfg *lncfg = &csiphy->cfg.csi2->lane_cfg;
-	struct phy_configure_opts_mipi_dphy *dphy_cfg;
-	union phy_configure_opts dphy_opts = { 0 };
+	union phy_configure_opts opts = { 0 };
+	enum phy_mode mode = PHY_MODE_INVALID;
 	struct device *dev = csiphy->camss->dev;
 	u8 num_lanes = lncfg->num_data;
 	s64 link_freq;
 	int ret;
 
-	dphy_cfg = &dphy_opts.mipi_dphy;
-
-	link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
+	ret = csiphy_get_remote_mbus_config(csiphy, &mbus_cfg);
+	if (ret && ret != -EOPNOTSUPP)
+		return ret;
 
-	if (link_freq <= 0) {
-		dev_err(dev,
-			"Cannot get CSI2 transmitter's link frequency\n");
-		return -EINVAL;
+	if (ret == -EOPNOTSUPP && lncfg->phy_type == V4L2_MBUS_CSI2_CPHY) {
+		dev_err(dev, "C-PHY transmitter does not report media bus configuration\n");
+		return ret;
 	}
 
-	ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq, num_lanes,
-							 dphy_cfg);
-	if (ret < 0) {
-		dev_err(dev, "Invalid config for link frequency %lld\n",
-			link_freq);
-		return ret;
+	if (!ret && mbus_cfg.type == V4L2_MBUS_CSI2_CPHY) {
+		struct phy_configure_opts_mipi_cphy *cphy = &opts.mipi_cphy;
+
+		link_freq = mbus_cfg.link_freq;
+		if (link_freq <= 0) {
+			dev_err(dev,
+				"Cannot get CSI2 transmitter's link frequency\n");
+			return -EINVAL;
+		}
+
+		cphy->symbol_rate = link_freq * 2;
+		cphy->trios = num_lanes;
+		cphy->t_prepare_ns = mbus_cfg.bus.mipi_csi2.t_prepare_ns;
+		cphy->t_preamble_ns = mbus_cfg.bus.mipi_csi2.t_preamble_ns;
+
+		mode = PHY_MODE_MIPI_CPHY;
+	} else if (ret || mbus_cfg.type == V4L2_MBUS_CSI2_DPHY) {
+		struct phy_configure_opts_mipi_dphy *dphy = &opts.mipi_dphy;
+
+		link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
+		if (link_freq <= 0) {
+			dev_err(dev,
+				"Cannot get CSI2 transmitter's link frequency\n");
+			return -EINVAL;
+		}
+
+		ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq, num_lanes,
+								dphy);
+		if (ret < 0) {
+			dev_err(dev, "Invalid config for link frequency %lld\n",
+				link_freq);
+			return ret;
+		}
+		mode = PHY_MODE_MIPI_DPHY;
+	} else {
+		dev_err(dev, "Unsupported mbus type %u\n", mbus_cfg.type);
+		return -EINVAL;
 	}
 
-	ret = phy_set_mode(csiphy->phy, PHY_MODE_MIPI_DPHY);
+	ret = phy_set_mode(csiphy->phy, mode);
 	if (ret) {
 		dev_err(dev, "Failed to set phy mode\n");
 		return ret;
 	}
 
-	ret = phy_configure(csiphy->phy, &dphy_opts);
+	ret = phy_configure(csiphy->phy, &opts);
 	if (ret) {
-		dev_err(dev, "failed to configure MIPI D-PHY\n");
+		dev_err(dev, "failed to configure MIPI CSI-2 PHY\n");
 		goto error;
 	}
 
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h
index 8c3319f2ca1cfdef4c0185deed2805854ac81703..a13cfaf3796106d421c8d711308d3fb3fb9259a8 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.h
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.h
@@ -35,11 +35,13 @@ struct csiphy_lane {
  * @num_data: number of data lanes
  * @data:     data lanes configuration
  * @clk:      clock lane configuration (only for D-PHY)
+ * @phy_type: CSI-2 PHY bus type
  */
 struct csiphy_lanes_cfg {
 	int num_data;
 	struct csiphy_lane *data;
 	struct csiphy_lane clk;
+	enum v4l2_mbus_type phy_type;
 };
 
 struct csiphy_csi2_cfg {
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index c54185c93a8a98fc6a20fdb8e0f9f8e61bc41058..f61a9c242ef46f968ecc22dddd16a2e96465ca65 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -4694,11 +4694,8 @@ static int camss_parse_endpoint_node(struct device *dev,
 	if (ret)
 		return ret;
 
-	/*
-	 * Most SoCs support both D-PHY and C-PHY standards, but currently only
-	 * D-PHY is supported in the driver.
-	 */
-	if (vep.bus_type != V4L2_MBUS_CSI2_DPHY) {
+	if (vep.bus_type != V4L2_MBUS_CSI2_DPHY &&
+	    vep.bus_type != V4L2_MBUS_CSI2_CPHY) {
 		dev_err(dev, "Unsupported bus type %d\n", vep.bus_type);
 		return -EINVAL;
 	}
@@ -4706,6 +4703,7 @@ static int camss_parse_endpoint_node(struct device *dev,
 	csd->interface.csiphy_id = vep.base.port;
 
 	mipi_csi2 = &vep.bus.mipi_csi2;
+	lncfg->phy_type = vep.bus_type;
 	lncfg->clk.pos = mipi_csi2->clock_lane;
 	lncfg->clk.pol = mipi_csi2->lane_polarities[0];
 	lncfg->num_data = mipi_csi2->num_data_lanes;
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 24c738cd78940fa7f6118d78595fe221689a39e7..42543ec98a839567c21485d3e97f875b8a081100 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -109,6 +109,8 @@ struct v4l2_mbus_config_mipi_csi2 {
 	unsigned char num_data_lanes;
 	bool lane_polarities[1 + V4L2_MBUS_CSI2_MAX_DATA_LANES];
 	enum v4l2_mbus_csi2_cphy_line_orders_type line_orders[V4L2_MBUS_CSI2_MAX_DATA_LANES];
+	u32 t_prepare_ns;
+	u32 t_preamble_ns;
 };
 
 /**

-- 
2.34.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RFC 3/6] phy: qcom: mipi-csi2: Split D-PHY register settings
  2026-10-17 17:13 [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 1/6] phy: core: Add MIPI C-PHY configurations Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 2/6] media: qcom: camss: Add C-PHY timing fields and get config from sensor Nihal Kumar Gupta
@ 2026-10-17 17:13 ` Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 4/6] phy: qcom: mipi-csi2: Accept C-PHY mode and add register sequence Nihal Kumar Gupta
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Nihal Kumar Gupta @ 2026-10-17 17:13 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
	Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Bryan O'Donoghue
  Cc: Vikram Sharma, linux-phy, linux-kernel, linux-media,
	linux-arm-msm, Nihal Kumar Gupta

The register sequence storage is tied to a single init table. C-PHY
support needs separate D-PHY and C-PHY sequence selection without
changing the existing D-PHY programming.

Wrap the existing D-PHY table in a D-PHY settings structure and route
lane programming through a common register write helper.

Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 28 +++++++++++++++-------
 drivers/phy/qualcomm/phy-qcom-mipi-csi2.h          |  8 +++++--
 2 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
index 966d79c98f9b21e1a235b8397c4c84b25d869427..79c7fa57d059b29f2f72a0c1208e07115b3fb049 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
@@ -241,14 +241,12 @@ static u8 phy_qcom_mipi_csi2_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate)
 	return settle_cnt;
 }
 
-static void
-phy_qcom_mipi_csi2_gen2_config_lanes(struct mipi_csi2phy_device *csi2phy,
-				     u8 settle_cnt)
+static void phy_qcom_mipi_csi2_write_regs(struct mipi_csi2phy_device *csi2phy,
+					  const struct mipi_csi2phy_lane_regs *r,
+					  unsigned int array_size, u8 settle_cnt)
 {
-	const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
-	const struct mipi_csi2phy_lane_regs *r = regs->init_seq;
-	int i, array_size = regs->lane_array_size;
 	u32 val;
+	int i;
 
 	for (i = 0; i < array_size; i++, r++) {
 		switch (r->param_type) {
@@ -268,6 +266,16 @@ phy_qcom_mipi_csi2_gen2_config_lanes(struct mipi_csi2phy_device *csi2phy,
 	}
 }
 
+static void
+phy_qcom_mipi_csi2_gen2_config_lanes(struct mipi_csi2phy_device *csi2phy,
+				     u8 settle_cnt)
+{
+	const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
+
+	phy_qcom_mipi_csi2_write_regs(csi2phy, regs->dphy->dphy_init_seq,
+					 regs->dphy->num_regs, settle_cnt);
+}
+
 static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
 					   struct mipi_csi2phy_stream_cfg *cfg)
 {
@@ -369,11 +377,15 @@ static struct mipi_csi2_genpd x1e_genpds[] = {
 	{ .name = "mx", .scaled = true },
 };
 
+static const struct mipi_csi2phy_dphy_rate_settings x1e80100_dphy_settings = {
+	.dphy_init_seq = lane_regs_x1e80100,
+	.num_regs = ARRAY_SIZE(lane_regs_x1e80100),
+};
+
 const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_4nm_x1e = {
 	.ops = &phy_qcom_mipi_csi2_ops_3ph_1_0,
 	.reg_info = {
-		.init_seq = lane_regs_x1e80100,
-		.lane_array_size = ARRAY_SIZE(lane_regs_x1e80100),
+		.dphy = &x1e80100_dphy_settings,
 		.common_regs_offset = 0x1000,
 	},
 	.supply_names = (const char **)x1e_supplies,
diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
index 7e55ae00737047f2d0384728a9c98780851eec05..528e80109c2f96b8c66d989ac834e30e7b38c732 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
@@ -47,9 +47,13 @@ struct mipi_csi2phy_lane_regs {
 	const u32 param_type;
 };
 
+struct mipi_csi2phy_dphy_rate_settings {
+	const struct mipi_csi2phy_lane_regs *dphy_init_seq;
+	unsigned int num_regs;
+};
+
 struct mipi_csi2phy_device_regs {
-	const struct mipi_csi2phy_lane_regs *init_seq;
-	const int lane_array_size;
+	const struct mipi_csi2phy_dphy_rate_settings *dphy;
 	const u32 common_regs_offset;
 };
 

-- 
2.34.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RFC 4/6] phy: qcom: mipi-csi2: Accept C-PHY mode and add register sequence
  2026-10-17 17:13 [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack Nihal Kumar Gupta
                   ` (2 preceding siblings ...)
  2026-10-17 17:13 ` [PATCH RFC 3/6] phy: qcom: mipi-csi2: Split D-PHY register settings Nihal Kumar Gupta
@ 2026-10-17 17:13 ` Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 5/6] phy: qcom: mipi-csi2: Add C-PHY settle calculation Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 6/6] phy: qcom: mipi-csi2: Add lane mask calculation for C-PHY Nihal Kumar Gupta
  5 siblings, 0 replies; 8+ messages in thread
From: Nihal Kumar Gupta @ 2026-10-17 17:13 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
	Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Bryan O'Donoghue
  Cc: Vikram Sharma, linux-phy, linux-kernel, linux-media,
	linux-arm-msm, Nihal Kumar Gupta

The CSI-2 PHY core rejects all modes except D-PHY, so CAMSS cannot pass
C-PHY stream configuration to the PHY provider. Accept PHY_MODE_MIPI_CPHY
in set_mode() and configure(). Validate the trio count and store the C-PHY
link frequency and timing in the stream configuration.

C-PHY programming needs a common base sequence and a data-rate specific
sequence, while D-PHY keeps using its existing sequence. Add
mipi_csi2phy_cphy_rate_settings descriptor and select the register
sequence from the configured PHY mode. Leave SoC-specific C-PHY register
data to separate patches.

Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 51 +++++++++++++++++-----
 drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c     | 51 ++++++++++++++++------
 drivers/phy/qualcomm/phy-qcom-mipi-csi2.h          | 17 ++++++++
 3 files changed, 96 insertions(+), 23 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
index 79c7fa57d059b29f2f72a0c1208e07115b3fb049..30f7f39ba855a0a2921189050f0084dead207fbd 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
@@ -266,14 +266,48 @@ static void phy_qcom_mipi_csi2_write_regs(struct mipi_csi2phy_device *csi2phy,
 	}
 }
 
-static void
+static int
 phy_qcom_mipi_csi2_gen2_config_lanes(struct mipi_csi2phy_device *csi2phy,
 				     u8 settle_cnt)
 {
 	const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
+	u64 bit_rate;
+	int i;
+
+	switch (csi2phy->phy_mode) {
+	case PHY_MODE_MIPI_CPHY:
+		if (!regs->cphy || !regs->num_cphy)
+			return -EINVAL;
+
+		/*
+		 * link_freq = symbol_rate / 2; convert to effective bit rate
+		 * (bits/s) for comparison against the bandwidth table:
+		 * bit_rate = link_freq * 2 * 16 / 7 = link_freq * 32 / 7
+		 */
+		bit_rate = div_u64((u64)csi2phy->stream_cfg.link_freq * 32, 7);
+
+		for (i = 0; i < regs->num_cphy; i++) {
+			if (regs->cphy[i].bandwidth >= bit_rate)
+				break;
+		}
+
+		if (i == regs->num_cphy)
+			i = regs->num_cphy - 1;
+
+		phy_qcom_mipi_csi2_write_regs(csi2phy, regs->cphy[i].cphy_init_seq,
+						 regs->cphy[i].num_regs,
+						 settle_cnt);
+		break;
+	case PHY_MODE_MIPI_DPHY:
+		phy_qcom_mipi_csi2_write_regs(csi2phy, regs->dphy->dphy_init_seq,
+						 regs->dphy->num_regs,
+						 settle_cnt);
+		break;
+	default:
+		return -EINVAL;
+	}
 
-	phy_qcom_mipi_csi2_write_regs(csi2phy, regs->dphy->dphy_init_seq,
-					 regs->dphy->num_regs, settle_cnt);
+	return 0;
 }
 
 static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
@@ -283,12 +317,7 @@ static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
 	struct mipi_csi2phy_lanes_cfg *lane_cfg = &cfg->lane_cfg;
 	u8 settle_cnt;
 	u8 val;
-	int i;
-
-	if (cfg->link_freq <= 0)
-		return -EINVAL;
-
-	settle_cnt = phy_qcom_mipi_csi2_settle_cnt_calc(cfg->link_freq, csi2phy->timer_clk_rate);
+	int i, ret;
 	if (!settle_cnt)
 		return -ENODEV;
 
@@ -329,7 +358,9 @@ static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
 	writel(val, csi2phy->base +
 	       CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 0));
 
-	phy_qcom_mipi_csi2_gen2_config_lanes(csi2phy, settle_cnt);
+	ret = phy_qcom_mipi_csi2_gen2_config_lanes(csi2phy, settle_cnt);
+	if (ret)
+		return ret;
 
 	/* IRQ_MASK registers - disable all interrupts */
 	for (i = CSI_COMMON_STATUS_NUM; i < CSI_CTRL_STATUS_INDEX; i++) {
diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
index c0a4fa20eaf0c87f6c18b35e625f5ba1769c94e7..56b8830d69ee34280119d8b813ede643252e3606 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
@@ -100,23 +100,46 @@ static int phy_qcom_mipi_csi2_configure(struct phy *phy,
 					union phy_configure_opts *opts)
 {
 	struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
-	struct phy_configure_opts_mipi_dphy *dphy_cfg = &opts->mipi_dphy;
 	struct mipi_csi2phy_stream_cfg *stream_cfg = &csi2phy->stream_cfg;
-	int ret;
+	int ret = 0;
 
-	ret = phy_mipi_dphy_config_validate(dphy_cfg);
-	if (ret)
-		return ret;
+	if (csi2phy->phy_mode == PHY_MODE_MIPI_DPHY) {
+		struct phy_configure_opts_mipi_dphy *dphy_cfg = &opts->mipi_dphy;
 
-	if (dphy_cfg->lanes < 1 || dphy_cfg->lanes > CSI2_MAX_DATA_LANES)
-		return -EINVAL;
+		ret = phy_mipi_dphy_config_validate(dphy_cfg);
+		if (ret)
+			return ret;
 
-	if (dphy_cfg->lanes != stream_cfg->num_data_lanes)
-		return -EINVAL;
+		if (dphy_cfg->lanes < 1 || dphy_cfg->lanes > CSI2_MAX_DATA_LANES)
+			return -EINVAL;
 
-	stream_cfg->link_freq = dphy_cfg->hs_clk_rate;
+		if (dphy_cfg->lanes != stream_cfg->num_data_lanes)
+			return -EINVAL;
 
-	return 0;
+		stream_cfg->link_freq = dphy_cfg->hs_clk_rate;
+		stream_cfg->num_data_lanes = dphy_cfg->lanes;
+	} else if (csi2phy->phy_mode == PHY_MODE_MIPI_CPHY) {
+		struct phy_configure_opts_mipi_cphy *cphy_cfg = &opts->mipi_cphy;
+
+		if (cphy_cfg->trios < 1 || cphy_cfg->trios > CSI2_MAX_DATA_TRIOS)
+			return -EINVAL;
+
+		if (!cphy_cfg->t_prepare_ns || !cphy_cfg->t_preamble_ns) {
+			dev_err(csi2phy->dev,
+				"Invalid C-PHY timing: t_prepare_ns=%u t_preamble_ns=%u\n",
+				cphy_cfg->t_prepare_ns, cphy_cfg->t_preamble_ns);
+			return -EINVAL;
+		}
+
+		stream_cfg->link_freq = cphy_cfg->symbol_rate / 2;
+		stream_cfg->num_data_lanes = cphy_cfg->trios;
+		stream_cfg->t_prepare_ns = cphy_cfg->t_prepare_ns;
+		stream_cfg->t_preamble_ns = cphy_cfg->t_preamble_ns;
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
 }
 
 static int phy_qcom_mipi_csi2_set_mode(struct phy *phy,
@@ -124,7 +147,8 @@ static int phy_qcom_mipi_csi2_set_mode(struct phy *phy,
 {
 	struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
 
-	if (mode != PHY_MODE_MIPI_DPHY)
+	if (mode != PHY_MODE_MIPI_DPHY &&
+	    mode != PHY_MODE_MIPI_CPHY)
 		return -EOPNOTSUPP;
 
 	csi2phy->phy_mode = mode;
@@ -278,7 +302,8 @@ static int phy_qcom_mipi_csi2_parse_routing(struct mipi_csi2phy_device *csi2phy)
 	bus_type = MEDIA_BUS_TYPE_CSI2_DPHY;
 	fwnode_property_read_u32(ep, "bus-type", &bus_type);
 
-	if (bus_type != MEDIA_BUS_TYPE_CSI2_DPHY) {
+	if (bus_type != MEDIA_BUS_TYPE_CSI2_DPHY &&
+	    bus_type != MEDIA_BUS_TYPE_CSI2_CPHY) {
 		ret = -EOPNOTSUPP;
 		dev_err(dev, "Unsupported bus-type %u\n", bus_type);
 		goto out_put;
diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
index 528e80109c2f96b8c66d989ac834e30e7b38c732..31103546e4874ffd519fe7f386d779f17325cb30 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
@@ -11,6 +11,7 @@
 #include <linux/phy/phy.h>
 
 #define CSI2_MAX_DATA_LANES	4
+#define CSI2_MAX_DATA_TRIOS	3
 #define CSI2_DEFAULT_CLK_LANE	7
 
 struct mipi_csi2phy_lane {
@@ -26,6 +27,8 @@ struct mipi_csi2phy_lanes_cfg {
 struct mipi_csi2phy_stream_cfg {
 	s64 link_freq;
 	u8 num_data_lanes;
+	u32 t_prepare_ns;
+	u32 t_preamble_ns;
 	struct mipi_csi2phy_lanes_cfg lane_cfg;
 };
 
@@ -52,8 +55,22 @@ struct mipi_csi2phy_dphy_rate_settings {
 	unsigned int num_regs;
 };
 
+struct mipi_csi2phy_cphy_rate_settings {
+	/**
+	 * @bandwidth: Maximum effective data rate for this register sequence,
+	 * in bits/s (= symbol_rate * 16 / 7). The first entry whose bandwidth
+	 * is >= the configured link bit rate is selected; the last entry is
+	 * a fallback.
+	 */
+	u64 bandwidth;
+	const struct mipi_csi2phy_lane_regs *cphy_init_seq;
+	unsigned int num_regs;
+};
+
 struct mipi_csi2phy_device_regs {
 	const struct mipi_csi2phy_dphy_rate_settings *dphy;
+	const struct mipi_csi2phy_cphy_rate_settings *cphy;
+	unsigned int num_cphy;
 	const u32 common_regs_offset;
 };
 

-- 
2.34.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RFC 5/6] phy: qcom: mipi-csi2: Add C-PHY settle calculation
  2026-10-17 17:13 [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack Nihal Kumar Gupta
                   ` (3 preceding siblings ...)
  2026-10-17 17:13 ` [PATCH RFC 4/6] phy: qcom: mipi-csi2: Accept C-PHY mode and add register sequence Nihal Kumar Gupta
@ 2026-10-17 17:13 ` Nihal Kumar Gupta
  2026-10-17 17:13 ` [PATCH RFC 6/6] phy: qcom: mipi-csi2: Add lane mask calculation for C-PHY Nihal Kumar Gupta
  5 siblings, 0 replies; 8+ messages in thread
From: Nihal Kumar Gupta @ 2026-10-17 17:13 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
	Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Bryan O'Donoghue
  Cc: Vikram Sharma, linux-phy, linux-kernel, linux-media,
	linux-arm-msm, Nihal Kumar Gupta

C-PHY settle timing is provided by the sensor and does not use the D-PHY
T_hs_settle calculation. Add a C-PHY settle count helper and select the
settle calculation from the configured PHY mode.

Use the sensor-provided t_prepare_ns and t_preamble_ns values to derive
the C-PHY settle count:

  settle_cnt = (t_prepare_ns + t_preamble_ns / 3) * timer_clk_rate
               / NSEC_PER_SEC

Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 54 ++++++++++++++++++----
 1 file changed, 44 insertions(+), 10 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
index 30f7f39ba855a0a2921189050f0084dead207fbd..d93fd9845b50bd7e5623013aecd6db42dd491dca 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
@@ -210,7 +210,7 @@ static void phy_qcom_mipi_csi2_reset(struct mipi_csi2phy_device *csi2phy)
 }
 
 /*
- * phy_qcom_mipi_csi2_settle_cnt_calc - Calculate settle count value
+ * phy_qcom_dphy_settle_cnt - Calculate settle count value
  *
  * Helper function to calculate settle count value. This is
  * based on the CSI2 T_hs_settle parameter which in turn
@@ -218,7 +218,7 @@ static void phy_qcom_mipi_csi2_reset(struct mipi_csi2phy_device *csi2phy)
  *
  * Return settle count.
  */
-static u8 phy_qcom_mipi_csi2_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate)
+static u8 phy_qcom_dphy_settle_cnt(s64 link_freq, u32 timer_clk_rate)
 {
 	u32 t_hs_prepare_max_ps;
 	u32 timer_period_ps;
@@ -310,14 +310,44 @@ phy_qcom_mipi_csi2_gen2_config_lanes(struct mipi_csi2phy_device *csi2phy,
 	return 0;
 }
 
+static u8 phy_qcom_cphy_settle_cnt(struct mipi_csi2phy_stream_cfg *cfg,
+				   u32 timer_clk_rate)
+{
+	u64 settle_cnt;
+
+	settle_cnt = ((u64)cfg->t_prepare_ns +
+		      DIV_ROUND_CLOSEST(cfg->t_preamble_ns, 3)) * timer_clk_rate;
+	do_div(settle_cnt, NSEC_PER_SEC);
+
+	return settle_cnt;
+}
+
 static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
 					   struct mipi_csi2phy_stream_cfg *cfg)
 {
+	struct device *dev = csi2phy->dev;
 	const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
 	struct mipi_csi2phy_lanes_cfg *lane_cfg = &cfg->lane_cfg;
 	u8 settle_cnt;
 	u8 val;
 	int i, ret;
+
+	if (cfg->link_freq <= 0)
+		return -EINVAL;
+
+	switch (csi2phy->phy_mode) {
+	case PHY_MODE_MIPI_CPHY:
+		settle_cnt = phy_qcom_cphy_settle_cnt(cfg,
+						 csi2phy->timer_clk_rate);
+		break;
+	case PHY_MODE_MIPI_DPHY:
+		settle_cnt = phy_qcom_dphy_settle_cnt(cfg->link_freq,
+						 csi2phy->timer_clk_rate);
+		break;
+	default:
+		dev_err(dev, "Unsupported PHY mode %u\n", csi2phy->phy_mode);
+		return -EINVAL;
+	}
 	if (!settle_cnt)
 		return -ENODEV;
 
@@ -334,17 +364,21 @@ static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
 	writel(val, csi2phy->base +
 	       CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 5));
 
-	/* Lane configuration for polarity @ CSIPHY-base + CTRL9 */
-	for (i = 0; i < cfg->num_data_lanes; i++) {
-		if (lane_cfg->data[i].pol) {
-			u8 pos = lane_cfg->data[i].pos;
+	if (csi2phy->phy_mode == PHY_MODE_MIPI_DPHY) {
+		/* Lane configuration for polarity @ CSIPHY-base + CTRL9 */
+		for (i = 0; i < cfg->num_data_lanes; i++) {
+			if (lane_cfg->data[i].pol) {
+				u8 pos = lane_cfg->data[i].pos;
 
-			writel(BIT(2), csi2phy->base + CSIPHY_2PH_LN_CSI_2PHASE_CTRL9n(pos * 2));
+				writel(BIT(2), csi2phy->base +
+				       CSIPHY_2PH_LN_CSI_2PHASE_CTRL9n(pos * 2));
+			}
 		}
-	}
 
-	if (lane_cfg->clk.pol)
-		writel(BIT(2), csi2phy->base + CSIPHY_2PH_LN_CSI_2PHASE_CTRL9n(lane_cfg->clk.pos));
+		if (lane_cfg->clk.pol)
+			writel(BIT(2), csi2phy->base +
+			       CSIPHY_2PH_LN_CSI_2PHASE_CTRL9n(lane_cfg->clk.pos));
+	}
 
 	val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B;
 	writel(val, csi2phy->base +

-- 
2.34.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RFC 6/6] phy: qcom: mipi-csi2: Add lane mask calculation for C-PHY
  2026-10-17 17:13 [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack Nihal Kumar Gupta
                   ` (4 preceding siblings ...)
  2026-10-17 17:13 ` [PATCH RFC 5/6] phy: qcom: mipi-csi2: Add C-PHY settle calculation Nihal Kumar Gupta
@ 2026-10-17 17:13 ` Nihal Kumar Gupta
  5 siblings, 0 replies; 8+ messages in thread
From: Nihal Kumar Gupta @ 2026-10-17 17:13 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
	Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Bryan O'Donoghue
  Cc: Vikram Sharma, linux-phy, linux-kernel, linux-media,
	linux-arm-msm, Nihal Kumar Gupta

C-PHY uses trio lanes instead of D-PHY data+clock lanes. The existing
lane power-up mask hard-codes D-PHY bit positions and cannot represent
C-PHY trios.

Extract csiphy_get_lane_mask() and select the correct bit pattern based
on the configured PHY mode. For C-PHY, data lane bits are shifted by one
to target trio positions [1,3,5]; for D-PHY, the clock lane bit and
even-numbered data bits [0,2,4,6] are set as before.

Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 40 ++++++++++++++++------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
index d93fd9845b50bd7e5623013aecd6db42dd491dca..5e7036cb7205d75c988a281eced60658b45c73c3 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
@@ -322,6 +322,35 @@ static u8 phy_qcom_cphy_settle_cnt(struct mipi_csi2phy_stream_cfg *cfg,
 	return settle_cnt;
 }
 
+static u8 csiphy_get_lane_mask(struct mipi_csi2phy_lanes_cfg *lane_cfg,
+			       enum phy_mode mode, u8 num_data)
+{
+	u8 lane_mask = 0;
+	u8 offset = 0;
+
+	switch (mode) {
+	case PHY_MODE_MIPI_CPHY:
+		offset = 1;
+		break;
+	case PHY_MODE_MIPI_DPHY:
+		lane_mask = BIT(lane_cfg->clk.pos);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * CSI_COMMON_CTRL5 is a physical lane power-up bitmap:
+	 * - Bits [0,2,4,6] → D-PHY data lanes(LN0, LN2, LN4, LN6)
+	 * - Bits [1,3,5] → C-PHY trio lanes(LN1, LN3, LN5)
+	 * - Bit [7] → D-PHY clock lane(LNCK) dedicated clock enable
+	 */
+	for (int i = 0; i < num_data; i++)
+		lane_mask |= BIT((lane_cfg->data[i].pos * 2) + offset);
+
+	return lane_mask;
+}
+
 static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
 					   struct mipi_csi2phy_stream_cfg *cfg)
 {
@@ -351,16 +380,7 @@ static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
 	if (!settle_cnt)
 		return -ENODEV;
 
-	/*
-	 * CSI_COMMON_CTRL5 is a physical lane power-up bitmap:
-	 * - Bits [0,2,4,6] → D-PHY data lanes(LN0, LN2, LN4, LN6)
-	 * - Bits [1,3,5] → C-PHY trio lanes(LN1, LN3, LN5)
-	 * - Bit [7] → D-PHY clock lane(LNCK) dedicated clock enable
-	 */
-	val = BIT(lane_cfg->clk.pos);
-	for (i = 0; i < cfg->num_data_lanes; i++)
-		val |= BIT(lane_cfg->data[i].pos * 2);
-
+	val = csiphy_get_lane_mask(lane_cfg, csi2phy->phy_mode, cfg->num_data_lanes);
 	writel(val, csi2phy->base +
 	       CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 5));
 

-- 
2.34.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH RFC 2/6] media: qcom: camss: Add C-PHY timing fields and get config from sensor
  2026-10-17 17:13 ` [PATCH RFC 2/6] media: qcom: camss: Add C-PHY timing fields and get config from sensor Nihal Kumar Gupta
@ 2026-10-17 17:34   ` sashiko-bot
  0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-10-17 17:34 UTC (permalink / raw)
  To: Nihal Kumar Gupta; +Cc: linux-phy, media-ci, vkoul, neil.armstrong, olteanv

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] media: qcom: camss: missing V4L2_CID_LINK_FREQ fallback in csiphy_stream_on()
- [Low] media: v4l2-mediabus: missing kernel-doc for C-PHY timing fields
--

commit 0e2de1c89a699407d4b177bc0d1a72cd888312a3
Author: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>

media: qcom: camss: Add C-PHY timing fields and get config from sensor

This commit adds t_prepare_ns and t_preamble_ns timing fields to struct
v4l2_mbus_config_mipi_csi2 and updates the CAMSS CSIPHY driver to accept
C-PHY endpoints, query the remote transmitter media bus configuration,
and pass C-PHY link frequency and timings to the generic PHY.

> diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
> index f99eea2ef2289..ed2318d76987d 100644
> --- a/drivers/media/platform/qcom/camss/camss-csiphy.c
> +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
> @@ -313,6 +313,29 @@ static void csiphy_stream_off_legacy(struct csiphy_device *csiphy)
>  	csiphy->res->hw_ops->lanes_disable(csiphy, &csiphy->cfg);
>  }
>  
> +static int csiphy_get_remote_mbus_config(struct csiphy_device *csiphy,
> +					 struct v4l2_mbus_config *cfg)
> +{
> +	struct media_pad *remote;
> +	struct v4l2_subdev *remote_sd;
> +	int ret;
> +
> +	remote = media_pad_remote_pad_first(&csiphy->pads[MSM_CSIPHY_PAD_SINK]);
> +	if (!remote)
> +		return -ENOLINK;
> +
> +	remote_sd = media_entity_to_v4l2_subdev(remote->entity);
> +	if (!remote_sd)
> +		return -EINVAL;
> +
> +	memset(cfg, 0, sizeof(*cfg));
> +	ret = v4l2_subdev_call(remote_sd, pad, get_mbus_config,
> +			      remote->index, cfg);
> +	if (ret == -ENOIOCTLCMD)
> +		return -EOPNOTSUPP;
> +
> +	return ret;
> +}
>  /*
>   * csiphy_stream_on - Enable streaming on CSIPHY module
>   * @csiphy: CSIPHY device
> @@ -324,43 +347,74 @@ static void csiphy_stream_off_legacy(struct csiphy_device *csiphy)
>   */
>  static int csiphy_stream_on(struct csiphy_device *csiphy)
>  {
> +	struct v4l2_mbus_config mbus_cfg = { };
>  	u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
>  				csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
>  	struct csiphy_lanes_cfg *lncfg = &csiphy->cfg.csi2->lane_cfg;
> -	struct phy_configure_opts_mipi_dphy *dphy_cfg;
> -	union phy_configure_opts dphy_opts = { 0 };
> +	union phy_configure_opts opts = { 0 };
> +	enum phy_mode mode = PHY_MODE_INVALID;
>  	struct device *dev = csiphy->camss->dev;
>  	u8 num_lanes = lncfg->num_data;
>  	s64 link_freq;
>  	int ret;
>  
> -	dphy_cfg = &dphy_opts.mipi_dphy;
> -
> -	link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
> +	ret = csiphy_get_remote_mbus_config(csiphy, &mbus_cfg);
> +	if (ret && ret != -EOPNOTSUPP)
> +		return ret;
>  
> -	if (link_freq <= 0) {
> -		dev_err(dev,
> -			"Cannot get CSI2 transmitter's link frequency\n");
> -		return -EINVAL;
> +	if (ret == -EOPNOTSUPP && lncfg->phy_type == V4L2_MBUS_CSI2_CPHY) {
> +		dev_err(dev, "C-PHY transmitter does not report media bus configuration\n");
> +		return ret;
>  	}
>  
> -	ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq, num_lanes,
> -							 dphy_cfg);
> -	if (ret < 0) {
> -		dev_err(dev, "Invalid config for link frequency %lld\n",
> -			link_freq);
> -		return ret;
> +	if (!ret && mbus_cfg.type == V4L2_MBUS_CSI2_CPHY) {
> +		struct phy_configure_opts_mipi_cphy *cphy = &opts.mipi_cphy;
> +
> +		link_freq = mbus_cfg.link_freq;
> +		if (link_freq <= 0) {
> +			dev_err(dev,
> +				"Cannot get CSI2 transmitter's link frequency\n");
> +			return -EINVAL;
> +		}

[Severity: Medium]
What happens in csiphy_stream_on() if a C-PHY sensor or bridge implements
get_mbus_config() to report V4L2_MBUS_CSI2_CPHY and C-PHY timings, but
exposes its link frequency through V4L2_CID_LINK_FREQ rather than setting
mbus_cfg.link_freq?

Per Documentation/driver-api/media/tx-rx.rst and include/media/v4l2-common.h,
transmitters with configurable link frequencies use V4L2_CID_LINK_FREQ
and leave v4l2_mbus_config::link_freq unset, while receivers are expected
to query the frequency via v4l2_get_link_freq() (which checks
mbus_config.link_freq first and falls back to V4L2_CID_LINK_FREQ).

In CAMSS, both csid_set_clock_rates() in
drivers/media/platform/qcom/camss/camss-csid.c:

	link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp,
					csid->phy.lane_cnt);

and the D-PHY branch below call camss_get_link_freq() -> v4l2_get_link_freq().
Should the C-PHY branch also fall back to camss_get_link_freq() when
mbus_cfg.link_freq is not populated (which would also make use of bpp
computed at the top of csiphy_stream_on())?

[ ... ]

> diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
> index 24c738cd78940..42543ec98a839 100644
> --- a/include/media/v4l2-mediabus.h
> +++ b/include/media/v4l2-mediabus.h
> @@ -109,6 +109,8 @@ struct v4l2_mbus_config_mipi_csi2 {
>  	unsigned char num_data_lanes;
>  	bool lane_polarities[1 + V4L2_MBUS_CSI2_MAX_DATA_LANES];
>  	enum v4l2_mbus_csi2_cphy_line_orders_type line_orders[V4L2_MBUS_CSI2_MAX_DATA_LANES];
> +	u32 t_prepare_ns;
> +	u32 t_preamble_ns;
>  };

[Severity: Low]
struct v4l2_mbus_config_mipi_csi2 has a kernel-doc comment block right above
it, and include/media/v4l2-mediabus.h is included by
Documentation/driver-api/media/v4l2-mediabus.rst. Should @t_prepare_ns and
@t_preamble_ns be added to the kernel-doc comment to avoid kernel-doc build
warnings?

>  
>  /**

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261017-cphy_support-v1-0-8b0e1237ce95@oss.qualcomm.com?part=2

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-17 17:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17 17:13 [PATCH RFC 0/6] phy/media: Add generic MIPI C-PHY support to CSI-2 stack Nihal Kumar Gupta
2026-10-17 17:13 ` [PATCH RFC 1/6] phy: core: Add MIPI C-PHY configurations Nihal Kumar Gupta
2026-10-17 17:13 ` [PATCH RFC 2/6] media: qcom: camss: Add C-PHY timing fields and get config from sensor Nihal Kumar Gupta
2026-10-17 17:34   ` sashiko-bot
2026-10-17 17:13 ` [PATCH RFC 3/6] phy: qcom: mipi-csi2: Split D-PHY register settings Nihal Kumar Gupta
2026-10-17 17:13 ` [PATCH RFC 4/6] phy: qcom: mipi-csi2: Accept C-PHY mode and add register sequence Nihal Kumar Gupta
2026-10-17 17:13 ` [PATCH RFC 5/6] phy: qcom: mipi-csi2: Add C-PHY settle calculation Nihal Kumar Gupta
2026-10-17 17:13 ` [PATCH RFC 6/6] phy: qcom: mipi-csi2: Add lane mask calculation for C-PHY Nihal Kumar Gupta

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox