* [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* 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
* [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