From c87ad497eca4d5162853c6dbdc101cfda0ca9937 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 01/15] FROMLIST: media: qcom: camss: csiphy: Introduce PHY configuration Read PHY configuration from the device-tree bus-type and save it into the csiphy structure for later use. For C-PHY, skip clock line configuration, as there is none. Link: https://lore.kernel.org/all/20260301-qcom-cphy-v4-1-e53316d2cc65@ixit.cz/ Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- .../media/platform/qcom/camss/camss-csiphy.h | 2 ++ drivers/media/platform/qcom/camss/camss.c | 18 +++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 1879826034aac..e8a7445f146db 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -31,11 +31,13 @@ struct csiphy_lane { /** * struct csiphy_lanes_cfg - CSIPHY lanes configuration + * @phy_cfg: interface selection (C-PHY or D-PHY) * @num_data: number of data lanes * @data: data lanes configuration * @clk: clock lane configuration (only for D-PHY) */ struct csiphy_lanes_cfg { + enum v4l2_mbus_type phy_cfg; int num_data; struct csiphy_lane *data; struct csiphy_lane clk; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index cab82648134c5..776214ba92692 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -4564,11 +4564,11 @@ 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) { + switch (vep.bus_type) { + case V4L2_MBUS_CSI2_CPHY: + case V4L2_MBUS_CSI2_DPHY: + break; + default: dev_err(dev, "Unsupported bus type %d\n", vep.bus_type); return -EINVAL; } @@ -4576,9 +4576,13 @@ static int camss_parse_endpoint_node(struct device *dev, csd->interface.csiphy_id = vep.base.port; mipi_csi2 = &vep.bus.mipi_csi2; - lncfg->clk.pos = mipi_csi2->clock_lane; - lncfg->clk.pol = mipi_csi2->lane_polarities[0]; lncfg->num_data = mipi_csi2->num_data_lanes; + lncfg->phy_cfg = vep.bus_type; + + if (lncfg->phy_cfg != V4L2_MBUS_CSI2_CPHY) { + lncfg->clk.pos = mipi_csi2->clock_lane; + lncfg->clk.pol = mipi_csi2->lane_polarities[0]; + } lncfg->data = devm_kcalloc(dev, lncfg->num_data, sizeof(*lncfg->data), From 43456bef431fa0dc3400765e7ff60ec700551971 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 02/15] FROMLIST: media: qcom: camss: csiphy-3ph: Use odd bits for configuring C-PHY lanes So far, only D-PHY mode was supported, which uses even bits when enabling or masking lanes. For C-PHY configuration, the hardware instead requires using the odd bits. Since there can be unrecognized configuration allow returning failure. Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-2-e53316d2cc65@ixit.cz/ Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- .../qcom/camss/camss-csiphy-2ph-1-0.c | 8 +-- .../qcom/camss/camss-csiphy-3ph-1-0.c | 49 ++++++++++++++----- .../media/platform/qcom/camss/camss-csiphy.c | 5 +- .../media/platform/qcom/camss/camss-csiphy.h | 6 +-- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c index 9d67e7fa6366a..bb4b91f69616b 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c @@ -94,9 +94,9 @@ static u8 csiphy_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate) return settle_cnt; } -static void csiphy_lanes_enable(struct csiphy_device *csiphy, - struct csiphy_config *cfg, - s64 link_freq, u8 lane_mask) +static int csiphy_lanes_enable(struct csiphy_device *csiphy, + struct csiphy_config *cfg, + s64 link_freq, u8 lane_mask) { struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; u8 settle_cnt; @@ -132,6 +132,8 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, writel_relaxed(0x3f, csiphy->base + CAMSS_CSI_PHY_INTERRUPT_CLEARn(l)); } + + return 0; } static void csiphy_lanes_disable(struct csiphy_device *csiphy, diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index d37f71de0f42c..1516024702e23 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -14,6 +14,7 @@ #include #include #include +#include #define CSIPHY_3PH_LNn_CFG1(n) (0x000 + 0x100 * (n)) #define CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG (BIT(7) | BIT(6)) @@ -993,13 +994,22 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, static u8 csiphy_get_lane_mask(struct csiphy_lanes_cfg *lane_cfg) { - u8 lane_mask; - int i; + u8 lane_mask = 0; - lane_mask = CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE; + switch (lane_cfg->phy_cfg) { + case V4L2_MBUS_CSI2_CPHY: + for (int i = 0; i < lane_cfg->num_data; i++) + lane_mask |= BIT(lane_cfg->data[i].pos + 1); + break; + case V4L2_MBUS_CSI2_DPHY: + lane_mask = CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE; - for (i = 0; i < lane_cfg->num_data; i++) - lane_mask |= 1 << lane_cfg->data[i].pos; + for (int i = 0; i < lane_cfg->num_data; i++) + lane_mask |= BIT(lane_cfg->data[i].pos); + break; + default: + break; + } return lane_mask; } @@ -1028,10 +1038,11 @@ static bool csiphy_is_gen2(u32 version) return ret; } -static void csiphy_lanes_enable(struct csiphy_device *csiphy, - struct csiphy_config *cfg, - s64 link_freq, u8 lane_mask) +static int csiphy_lanes_enable(struct csiphy_device *csiphy, + struct csiphy_config *cfg, + s64 link_freq, u8 lane_mask) { + struct device *dev = csiphy->camss->dev; struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; struct csiphy_device_regs *regs = csiphy->regs; u8 settle_cnt; @@ -1040,9 +1051,23 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); - val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE; - for (i = 0; i < c->num_data; i++) - val |= BIT(c->data[i].pos * 2); + val = 0; + + switch (c->phy_cfg) { + case V4L2_MBUS_CSI2_CPHY: + for (i = 0; i < c->num_data; i++) + val |= BIT((c->data[i].pos * 2) + 1); + break; + case V4L2_MBUS_CSI2_DPHY: + val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE; + + for (i = 0; i < c->num_data; i++) + val |= BIT(c->data[i].pos * 2); + break; + default: + dev_err(dev, "Unsupported bus type %d\n", c->phy_cfg); + return -EINVAL; + } writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 5)); @@ -1069,6 +1094,8 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, writel_relaxed(0, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, i)); } + + return 0; } static void csiphy_lanes_disable(struct csiphy_device *csiphy, diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index b9f7d6573a0f0..a67924787b7d3 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -267,6 +267,7 @@ static int csiphy_set_power_legacy(struct v4l2_subdev *sd, int on) static int csiphy_stream_on_legacy(struct csiphy_device *csiphy) { struct csiphy_config *cfg = &csiphy->cfg; + const struct csiphy_hw_ops *ops = csiphy->res->hw_ops; s64 link_freq; u8 lane_mask = csiphy->res->hw_ops->get_lane_mask(&cfg->csi2->lane_cfg); u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats, @@ -297,9 +298,7 @@ static int csiphy_stream_on_legacy(struct csiphy_device *csiphy) wmb(); } - csiphy->res->hw_ops->lanes_enable(csiphy, cfg, link_freq, lane_mask); - - return 0; + return ops->lanes_enable(csiphy, cfg, link_freq, lane_mask); } /* diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index e8a7445f146db..8643ab57c3786 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -76,9 +76,9 @@ struct csiphy_hw_ops { void (*hw_version_read)(struct csiphy_device *csiphy, struct device *dev); void (*reset)(struct csiphy_device *csiphy); - void (*lanes_enable)(struct csiphy_device *csiphy, - struct csiphy_config *cfg, - s64 link_freq, u8 lane_mask); + int (*lanes_enable)(struct csiphy_device *csiphy, + struct csiphy_config *cfg, + s64 link_freq, u8 lane_mask); void (*lanes_disable)(struct csiphy_device *csiphy, struct csiphy_config *cfg); irqreturn_t (*isr)(int irq, void *dev); From 18f128c3c80d169fcfe370c8223b429c4d3860f0 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 03/15] FROMLIST: media: qcom: camss: Prepare CSID for C-PHY support Inherit C-PHY information from CSIPHY, so we can configure CSID properly. CSI2_RX_CFG0_PHY_TYPE_SEL must be set to 1, when C-PHY mode is used. Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-3-e53316d2cc65@ixit.cz Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- drivers/media/platform/qcom/camss/camss-csid-gen2.c | 1 + drivers/media/platform/qcom/camss/camss-csid.c | 1 + drivers/media/platform/qcom/camss/camss-csid.h | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c index 2a1746dcc1c5b..033036ae28a4f 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c @@ -183,6 +183,7 @@ static void __csid_configure_rx(struct csid_device *csid, val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; val |= phy->csiphy_id << CSI2_RX_CFG0_PHY_NUM_SEL; + val |= csid->phy.cphy << CSI2_RX_CFG0_PHY_TYPE_SEL; writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 48459b46a981b..71f2bb75c3bdd 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -1290,6 +1290,7 @@ static int csid_link_setup(struct media_entity *entity, csid->phy.csiphy_id = csiphy->id; lane_cfg = &csiphy->cfg.csi2->lane_cfg; + csid->phy.cphy = (lane_cfg->phy_cfg == V4L2_MBUS_CSI2_CPHY); csid->phy.lane_cnt = lane_cfg->num_data; csid->phy.lane_assign = csid_get_lane_assign(lane_cfg, lane_cfg->num_data); csid->tpg_linked = false; diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index 5296b10f6bac8..00e2669db64c9 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -70,6 +70,7 @@ struct csid_phy_config { u32 lane_assign; u32 en_vc; u8 need_vc_update; + bool cphy; }; struct csid_device; From 46a3f630834cabd274e1fa81de66fe01578b1c7a Mon Sep 17 00:00:00 2001 From: Petr Hodina Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 04/15] FROMLIST: media: qcom: camss: Initialize lanes after lane configuration is available The lanes must not be initialized before the driver has access to the lane configuration, as it depends on whether D-PHY or C-PHY mode is in use. Move the lane initialization to a later stage where the configuration structures are available. Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-4-e53316d2cc65@ixit.cz Signed-off-by: Petr Hodina Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 92 ++++++++++++------- 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 1516024702e23..6acdbafaecb29 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -1049,6 +1049,63 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, u8 val; int i; + switch (csiphy->camss->res->version) { + case CAMSS_845: + { + regs->lane_regs = &lane_regs_sdm845[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sdm845); + } + break; + case CAMSS_2290: + case CAMSS_6150: + { + regs->lane_regs = &lane_regs_qcm2290[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_qcm2290); + } + break; + case CAMSS_7280: + case CAMSS_8250: + { + regs->lane_regs = &lane_regs_sm8250[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8250); + } + break; + case CAMSS_8280XP: + { + regs->lane_regs = &lane_regs_sc8280xp[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sc8280xp); + } + break; + case CAMSS_X1E80100: + case CAMSS_X1P42100: + { + regs->lane_regs = &lane_regs_x1e80100[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_x1e80100); + } + break; + case CAMSS_8550: + { + regs->lane_regs = &lane_regs_sm8550[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8550); + } + break; + case CAMSS_8650: + { + regs->lane_regs = &lane_regs_sm8650[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8650); + } + break; + case CAMSS_8300: + case CAMSS_8775P: + { + regs->lane_regs = &lane_regs_sa8775p[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p); + } + break; + default: + break; + } + settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); val = 0; @@ -1120,50 +1177,17 @@ static int csiphy_init(struct csiphy_device *csiphy) return -ENOMEM; csiphy->regs = regs; - regs->offset = 0x800; regs->common_status_offset = 0xb0; switch (csiphy->camss->res->version) { - case CAMSS_845: - regs->lane_regs = &lane_regs_sdm845[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_sdm845); - break; - case CAMSS_2290: - case CAMSS_6150: - regs->lane_regs = &lane_regs_qcm2290[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_qcm2290); - break; - case CAMSS_7280: - case CAMSS_8250: - regs->lane_regs = &lane_regs_sm8250[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8250); - break; - case CAMSS_8280XP: - regs->lane_regs = &lane_regs_sc8280xp[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_sc8280xp); - break; case CAMSS_X1E80100: case CAMSS_X1P42100: - regs->lane_regs = &lane_regs_x1e80100[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_x1e80100); - regs->offset = 0x1000; - break; case CAMSS_8550: - regs->lane_regs = &lane_regs_sm8550[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8550); - regs->offset = 0x1000; - break; case CAMSS_8650: - regs->lane_regs = &lane_regs_sm8650[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8650); regs->offset = 0x1000; break; - case CAMSS_8300: - case CAMSS_8775P: - regs->lane_regs = &lane_regs_sa8775p[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p); - break; default: + regs->offset = 0x800; break; } From e6d93b3585068e1033779201f541442bd93b378f Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 05/15] FROMLIST: media: qcom: camss: csiphy-3ph: Add Gen2 v1.1 MIPI CSI-2 CPHY init Add a PHY configuration sequence for the sdm845 which uses a Qualcomm Gen 2 version 1.1 CSI-2 PHY. The PHY can be configured as two phase or three phase in C-PHY or D-PHY mode. This configuration supports three-phase C-PHY mode. Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-5-e53316d2cc65@ixit.cz/ Signed-off-by: Casey Connolly Reviewed-by: Vladimir Zapolskiy Reviewed-by: Bryan O'Donoghue Co-developed-by: David Heidelberg Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 6acdbafaecb29..7462a40b14dd7 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -146,6 +146,7 @@ csiphy_lane_regs lane_regs_sa8775p[] = { }; /* GEN2 1.0 2PH */ +/* 5 entries: clock + 4 lanes */ static const struct csiphy_lane_regs lane_regs_sdm845[] = { {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -220,6 +221,71 @@ csiphy_lane_regs lane_regs_sdm845[] = { {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +/* GEN2 1.0 3PH */ +/* 3 entries: 3 lanes (C-PHY) */ +static const struct +csiphy_lane_regs lane_regs_sdm845_3ph[] = { + {0x015c, 0x43, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016c, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011c, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012c, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01cc, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01dc, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x035c, 0x43, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036c, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031c, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032c, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03cc, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03dc, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x055c, 0x43, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056c, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051c, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052c, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05cc, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05dc, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + /* GEN2 1.1 2PH */ static const struct csiphy_lane_regs lane_regs_sc8280xp[] = { @@ -1051,7 +1117,11 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, switch (csiphy->camss->res->version) { case CAMSS_845: - { + if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { + regs->lane_regs = &lane_regs_sdm845_3ph[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sdm845_3ph); + + } else { regs->lane_regs = &lane_regs_sdm845[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sdm845); } From a99f587492f4e9412f7017aa185ebc2f82c66da5 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 06/15] FROMLIST: media: qcom: camss: csiphy-3ph: Update Gen2 v1.1 MIPI CSI-2 CPHY init These values should improve C-PHY behaviour. Should match most recent Qualcomm code. Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-6-e53316d2cc65@ixit.cz/ Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- .../platform/qcom/camss/camss-csiphy-3ph-1-0.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 7462a40b14dd7..82d66b7cb2c9d 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -225,9 +225,9 @@ csiphy_lane_regs lane_regs_sdm845[] = { /* 3 entries: 3 lanes (C-PHY) */ static const struct csiphy_lane_regs lane_regs_sdm845_3ph[] = { - {0x015c, 0x43, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0168, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x016c, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015c, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xac, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016c, 0xa5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x010c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, @@ -245,9 +245,9 @@ csiphy_lane_regs lane_regs_sdm845_3ph[] = { {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01dc, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x035c, 0x43, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0368, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x036c, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035c, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xac, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036c, 0xa5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x030c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, @@ -265,9 +265,9 @@ csiphy_lane_regs lane_regs_sdm845_3ph[] = { {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03dc, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x055c, 0x43, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0568, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x056c, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055c, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xac, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056c, 0xa5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x050c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, From c2d53a366b503ddcf06816bd9004707d68c6fe95 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 07/15] FROMLIST: media: qcom: camss: csiphy-3ph: Add Gen2 v1.2.1 MIPI CSI-2 C-PHY init Add a PHY configuration sequence for the sm8250 which uses a Qualcomm Gen 2 version 1.2.1 CSI-2 PHY. The PHY can be configured as two phase or three phase in C-PHY or D-PHY mode. This configuration supports three-phase C-PHY mode. Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-7-e53316d2cc65@ixit.cz/ Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 112 +++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 82d66b7cb2c9d..d2f8cc0a6981d 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -550,6 +550,113 @@ csiphy_lane_regs lane_regs_qcm2290[] = { {0x0664, 0x3f, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +/* GEN2 1.2.1 3PH */ +/* 3 entries: 3 lanes (C-PHY) */ +static const struct +csiphy_lane_regs lane_regs_sm8250_3ph[] = { + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x1a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098c, 0xaf, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x015c, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018c, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011c, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012c, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01cc, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01dc, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09ac, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09b0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0a90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a98, 0x1a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a8c, 0xaf, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x035c, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038c, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031c, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032c, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03cc, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03dc, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0a80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0aac, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0ab0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0b90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b98, 0x1a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b8c, 0xaf, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x055c, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xa0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050c, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058c, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051c, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052c, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05cc, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05dc, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0b80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0bac, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0bb0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + /* GEN2 2.1.2 2PH DPHY mode */ static const struct csiphy_lane_regs lane_regs_sm8550[] = { @@ -1135,7 +1242,10 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, break; case CAMSS_7280: case CAMSS_8250: - { + if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { + regs->lane_regs = &lane_regs_sm8250_3ph[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8250_3ph); + } else { regs->lane_regs = &lane_regs_sm8250[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8250); } From 08a8545dd4f44a93233c40a5ed90bd7e098a5a21 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 08/15] FROMLIST: media: qcom: camss: csiphy-3ph: C-PHY needs own lane configuration Catch when C-PHY configuration gets used on SoC with CAMSS missing C-PHY configuration lane registers. Hopefully this check will disappear as these lane regs gets populated. -- @bod Proliferating special cases in switch statements on a per-SoC basis is verboten. Please find another way to do this, you already have a bool to indicate cphy in struct csid_phy_config {} so at some level CAMSS already has a bool to indicate what to do. Please make that logic accessible to logical consumers throughout, in this case the CPHY code. -- Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-8-e53316d2cc65@ixit.cz Signed-off-by: David Heidelberg Signed-off-by: Anusha Arun Nandi --- .../platform/qcom/camss/camss-csiphy-3ph-1-0.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index d2f8cc0a6981d..b8fb315c741d5 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -1222,6 +1222,22 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, u8 val; int i; + if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { + switch (csiphy->camss->res->version) { + case CAMSS_2290: + case CAMSS_8280XP: + case CAMSS_X1E80100: + case CAMSS_8550: + case CAMSS_8650: + case CAMSS_8300: + case CAMSS_8775P: + dev_err(csiphy->camss->dev, "Missing lane_regs definition for C-PHY\n"); + return -EINVAL; + default: + break; + } + } + switch (csiphy->camss->res->version) { case CAMSS_845: if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { From 8f4d8afaf4c4a3b7c669faa451a489a3b7acca02 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 09/15] FROMLIST: media: qcom: camss: Account for C-PHY when calculating link frequency Ensure that the link frequency divider correctly accounts for C-PHY operation. The divider differs between D-PHY and C-PHY, as described in the MIPI CSI-2 specification. For more details, see: https://docs.kernel.org/driver-api/media/tx-rx.html#pixel-rate Link: https://lore.kernel.org/r/20260301-qcom-cphy-v4-9-e53316d2cc65@ixit.cz Suggested-by: Sakari Ailus Signed-off-by: David Heidelberg Signed-off-by: Jigarkumar Zala Signed-off-by: Anusha Arun Nandi --- drivers/media/platform/qcom/camss/camss-csid.c | 9 +++++---- drivers/media/platform/qcom/camss/camss-csiphy.c | 8 +++----- drivers/media/platform/qcom/camss/camss.c | 16 ++++++++++++++-- drivers/media/platform/qcom/camss/camss.h | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 71f2bb75c3bdd..16ce2d29d78e1 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -536,9 +536,11 @@ const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info * csid_set_clock_rates - Calculate and set clock rates on CSID module * @csiphy: CSID device */ -static int csid_set_clock_rates(struct csid_device *csid) +static int csid_set_clock_rates(struct v4l2_subdev *sd, struct csid_device *csid) { struct device *dev = csid->camss->dev; + struct csiphy_device *csiphy = &csid->camss->csiphy[csid->phy.csiphy_id]; + struct csiphy_lanes_cfg *lane_cfg = &csiphy->cfg.csi2->lane_cfg; const struct csid_format_info *fmt; s64 link_freq; int i, j; @@ -546,8 +548,7 @@ static int csid_set_clock_rates(struct csid_device *csid) fmt = csid_get_fmt_entry(csid->res->formats->formats, csid->res->formats->nformats, csid->fmt[MSM_CSIPHY_PAD_SINK].code); - link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, - csid->phy.lane_cnt); + link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, lane_cfg); if (link_freq < 0) link_freq = 0; @@ -705,7 +706,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) return ret; } - ret = csid_set_clock_rates(csid); + ret = csid_set_clock_rates(sd, csid); if (ret < 0) { regulator_bulk_disable(csid->num_supplies, csid->supplies); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index a67924787b7d3..0903d16d4e26c 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -145,9 +145,8 @@ static int csiphy_set_clock_rates_legacy(struct csiphy_device *csiphy) u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats, csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); - u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; - link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes); + link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, &csiphy->cfg.csi2->lane_cfg); if (link_freq < 0) link_freq = 0; @@ -272,10 +271,9 @@ static int csiphy_stream_on_legacy(struct csiphy_device *csiphy) u8 lane_mask = csiphy->res->hw_ops->get_lane_mask(&cfg->csi2->lane_cfg); u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats, csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); - u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; u8 val; - link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes); + link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, &csiphy->cfg.csi2->lane_cfg); if (link_freq < 0) { dev_err(csiphy->camss->dev, @@ -336,7 +334,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy) dphy_cfg = &dphy_opts.mipi_dphy; - link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes); + link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, &csiphy->cfg.csi2->lane_cfg); if (link_freq < 0) { dev_err(dev, diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 776214ba92692..212914d84a0b3 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -33,6 +33,14 @@ #define CAMSS_CLOCK_MARGIN_NUMERATOR 105 #define CAMSS_CLOCK_MARGIN_DENOMINATOR 100 +/* + * C-PHY encodes data by 16/7 ~ 2.28 bits/symbol + * D-PHY doesn't encode data, thus 16/16 = 1 b/s + */ +#define CAMSS_COMMON_PHY_DIVIDENT 16 +#define CAMSS_CPHY_DIVISOR 7 +#define CAMSS_DPHY_DIVISOR 16 + static const struct parent_dev_ops vfe_parent_dev_ops; static const struct camss_subdev_resources csiphy_res_8x16[] = { @@ -4438,15 +4446,19 @@ struct media_pad *camss_find_sensor_pad(struct media_entity *entity) * Return link frequency on success or a negative error code otherwise */ s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, - unsigned int lanes) + struct csiphy_lanes_cfg *lane_cfg) { struct media_pad *sensor_pad; + u8 num_lanes = lane_cfg->num_data; + bool cphy = lane_cfg->phy_cfg == V4L2_MBUS_CSI2_CPHY; + unsigned int div = num_lanes * 2 * (cphy ? CAMSS_CPHY_DIVISOR : + CAMSS_DPHY_DIVISOR); sensor_pad = camss_find_sensor_pad(entity); if (!sensor_pad) return -ENODEV; - return v4l2_get_link_freq(sensor_pad, bpp, 2 * lanes); + return v4l2_get_link_freq(sensor_pad, CAMSS_COMMON_PHY_DIVIDENT * bpp, div); } /* diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 541b5c8bf1926..731c8cf542cac 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -170,7 +170,7 @@ int camss_enable_clocks(int nclocks, struct camss_clock *clock, void camss_disable_clocks(int nclocks, struct camss_clock *clock); struct media_pad *camss_find_sensor_pad(struct media_entity *entity); s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, - unsigned int lanes); + struct csiphy_lanes_cfg *lane_cfg); int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock); int camss_pm_domain_on(struct camss *camss, int id); void camss_pm_domain_off(struct camss *camss, int id); From ff0dc302fb47d46c5dec9657d2b4c99c4664d5fb Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 10/15] PENDING: media: qcom: camss: Program common control register Use these switch cases to add the sa8775p (CAMSS_8775P) 3-phase 1.5 Gsps settings, programming the appropriate common-control register 5/6/7 and reset-release values for C-PHY and D-PHY. CRs-Fixed: 4571838 Signed-off-by: Jigarkumar Zala Signed-off-by: Anusha Arun Nandi --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index b8fb315c741d5..617d5139d6620 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -1011,8 +1011,6 @@ static void csiphy_reset(struct csiphy_device *csiphy) writel_relaxed(0x1, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 0)); usleep_range(5000, 8000); - writel_relaxed(0x0, csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 0)); } static irqreturn_t csiphy_isr(int irq, void *dev) @@ -1329,9 +1327,37 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 6)); - val = 0x02; - writel_relaxed(val, csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 7)); + switch (platform_version) { + case CAMSS_8300: + case CAMSS_8775P: + if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { + val = 0x5A; + writel_relaxed(val, csiphy->base + + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 7)); + val = 0xE; + writel_relaxed(val, csiphy->base + + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 0)); + } else { + val = 0x02; + writel_relaxed(val, csiphy->base + + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 7)); + writel_relaxed(val, csiphy->base + + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 0)); + } + break; + case CAMSS_7280: + case CAMSS_8250: + case CAMSS_8280XP: + case CAMSS_845: + default: + val = 0x02; + writel_relaxed(val, csiphy->base + + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 7)); + val = 0x0; + writel_relaxed(val, csiphy->base + + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 0)); + break; + } val = 0x00; writel_relaxed(val, csiphy->base + From 59c31cc0ea69a08251362ee44709313c2747308b Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 9 Jun 2026 14:47:15 -0700 Subject: [PATCH 11/15] PENDING: media: qcom: camss: Prepare CSID for C-PHY support in gen3 Add the CSI2 RX PHY type select bitfield and program it from the configured PHY type so that the CSID RX path is told whether the incoming data is C-PHY or D-PHY. CRs-Fixed: 4571838 Signed-off-by: Jigarkumar Zala Signed-off-by: Anusha Arun Nandi --- drivers/media/platform/qcom/camss/camss-csid-gen3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c index 222765fe7914d..310933cf19da2 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c @@ -66,6 +66,7 @@ #define CSI2_RX_CFG0_VC_MODE 3 #define CSI2_RX_CFG0_DL0_INPUT_SEL 4 #define CSI2_RX_CFG0_PHY_NUM_SEL 20 +#define CSI2_RX_CFG0_PHY_TYPE_SEL 24 #define CSI2_RX_CFG0_TPG_MUX_EN BIT(27) #define CSI2_RX_CFG0_TPG_MUX_SEL GENMASK(29, 28) @@ -115,6 +116,7 @@ static void __csid_configure_rx(struct csid_device *csid, camss = csid->camss; val = (phy->lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; + val |= phy->cphy << CSI2_RX_CFG0_PHY_TYPE_SEL; val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; if (camss->tpg && csid->tpg_linked && From 120b36ae807b1c806dea5b799baf247eb4ff2bb9 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 9 Jun 2026 14:47:15 -0700 Subject: [PATCH 12/15] PENDING: media: qcom: camss: Add sa8775p C-PHY 3ph lane config Add the lane_regs_sa8775p_3ph[] register table for the sa8775p Gen3 CSIPHY at 1.5 Gsps, and select it in csiphy_lanes_enable() for CAMSS_8775P when the endpoint is configured for C-PHY, falling back to the existing sa8775p D-PHY table otherwise. CRs-Fixed: 4571838 Signed-off-by: Jigarkumar Zala Signed-off-by: Anusha Arun Nandi --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 106 +++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 617d5139d6620..1d6887092a8fa 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -145,6 +145,101 @@ csiphy_lane_regs lane_regs_sa8775p[] = { {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +/* GEN3 3PH sa8775p 1.5Gsps */ +/* 3 entries: 3 lanes (C-PHY) */ +static const struct +csiphy_lane_regs lane_regs_sa8775p_3ph[] = { + {0x0168, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0xC8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0xC8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0xC8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x61, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x61, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x61, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x24, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x24, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x24, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x09B4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + /* GEN2 1.0 2PH */ /* 5 entries: clock + 4 lanes */ static const struct @@ -1228,7 +1323,6 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, case CAMSS_8550: case CAMSS_8650: case CAMSS_8300: - case CAMSS_8775P: dev_err(csiphy->camss->dev, "Missing lane_regs definition for C-PHY\n"); return -EINVAL; default: @@ -1290,12 +1384,20 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, } break; case CAMSS_8300: - case CAMSS_8775P: { regs->lane_regs = &lane_regs_sa8775p[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p); } break; + case CAMSS_8775P: + if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { + regs->lane_regs = &lane_regs_sa8775p_3ph[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p_3ph); + } else { + regs->lane_regs = &lane_regs_sa8775p[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p); + } + break; default: break; } From 3c9956e8d1d8ea1ce3ba22156dfafac4f38b585e Mon Sep 17 00:00:00 2001 From: Anusha Arun Nandi Date: Tue, 9 Jun 2026 14:47:15 -0700 Subject: [PATCH 13/15] PENDING: media: qcom: camss: Add CAMSS_8300 C-PHY support Share the C-PHY/D-PHY lane_regs selection for CAMSS_8300 so the sa8300 platform uses the same 3ph handling as CAMSS_8775P. Also drop CAMSS_8300 from the missing-C-PHY-table guard now that a C-PHY table is provided. CRs-Fixed: 4571838 Signed-off-by: Jigarkumar Zala Signed-off-by: Anusha Arun Nandi --- drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 1d6887092a8fa..698d059eb1c7b 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -1322,7 +1322,6 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, case CAMSS_X1E80100: case CAMSS_8550: case CAMSS_8650: - case CAMSS_8300: dev_err(csiphy->camss->dev, "Missing lane_regs definition for C-PHY\n"); return -EINVAL; default: @@ -1384,11 +1383,6 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, } break; case CAMSS_8300: - { - regs->lane_regs = &lane_regs_sa8775p[0]; - regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p); - } - break; case CAMSS_8775P: if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { regs->lane_regs = &lane_regs_sa8775p_3ph[0]; From 0f4181f02b59039a6692ad35fa6c9be60cf52179 Mon Sep 17 00:00:00 2001 From: Anusha Arun Nandi Date: Tue, 9 Jun 2026 14:47:14 -0700 Subject: [PATCH 14/15] PENDING: media: qcom: camss: Dynamic data-rate specific C-PHY register settings The C-PHY PHY register configuration needs to vary with the link (symbol) data rate. Until now only a single base lane_regs table was applied per platform, regardless of the negotiated rate. Introduce a data-rate selection mechanism for C-PHY: - Add struct data_rate_reg_info describing a per-bandwidth register override table. - Add csiphy_cphy_data_rate_config(), which selects the first table entry whose bandwidth satisfies the required PHY data rate (derived from the resolved link frequency) and writes those overrides on top of the base lane_regs configuration. The settle-count parameter types are handled specially. When the link frequency cannot be resolved, it falls back to the lowest supported rate. - Add per-data-rate register tables and data_rate_settings tables for sa8775p and 8300(1.5/1.7/2.5/3.5/4.5 GSpS) and sm8250 (2.5/3.5/4.5 GSpS). - Select the appropriate data-rate settings table in csiphy_lanes_enable() for both platforms when the endpoint is configured for C-PHY. CRs-Fixed: 4571838 Co-developed-by: Jigarkumar Zala Signed-off-by: Jigarkumar Zala Signed-off-by: Anusha Arun Nandi --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 251 ++++++++++++++++++ .../media/platform/qcom/camss/camss-csiphy.h | 6 + 2 files changed, 257 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 698d059eb1c7b..113168f8751bc 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -59,6 +59,8 @@ #define CSIPHY_3PH_REGS 6 #define CSIPHY_SKEW_CAL 7 +#define CSIPHY_CPHY_DATA_RATE_DEFAULT_IDX 0 + struct csiphy_lane_regs { s32 reg_addr; s32 reg_data; @@ -223,6 +225,9 @@ csiphy_lane_regs lane_regs_sa8775p_3ph[] = { {0x0B80, 0x61, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_lane_regs datarate_sa8775p_3ph_1p5Gsps[] = { {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0168, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -240,6 +245,183 @@ csiphy_lane_regs lane_regs_sa8775p_3ph[] = { {0x0BB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +struct csiphy_lane_regs datarate_sa8775p_3ph_1p7Gsps[] = { + {0x015C, 0x56, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x65, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x035C, 0x56, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x65, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x055C, 0x56, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x65, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x09B4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_lane_regs datarate_sa8775p_3ph_2p5Gsps[] = { + {0x0168, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0xC8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0368, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0xC8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0568, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0xC8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x09B4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_lane_regs datarate_sa8775p_3ph_3p5Gsps[] = { + {0x0168, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0368, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0568, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x09B4, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_lane_regs datarate_sa8775p_3ph_4p5Gsps[] = { + {0x0168, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0368, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0568, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x08, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x09B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +static struct data_rate_reg_info data_rate_settings_sa8775p_3ph[] = { + { + /* 1.5 GSpS */ + .bandwidth = 1500000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sa8775p_3ph_1p5Gsps), + .data_rate_reg_array = datarate_sa8775p_3ph_1p5Gsps, + }, + { + /* 1.7 GSpS */ + .bandwidth = 1700000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sa8775p_3ph_1p7Gsps), + .data_rate_reg_array = datarate_sa8775p_3ph_1p7Gsps, + }, + { + /* 2.5 GSpS */ + .bandwidth = 2500000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sa8775p_3ph_2p5Gsps), + .data_rate_reg_array = datarate_sa8775p_3ph_2p5Gsps, + }, + { + /* 3.5 GSpS */ + .bandwidth = 3500000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sa8775p_3ph_3p5Gsps), + .data_rate_reg_array = datarate_sa8775p_3ph_3p5Gsps, + }, + { + /* 4.5 GSpS */ + .bandwidth = 4500000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sa8775p_3ph_4p5Gsps), + .data_rate_reg_array = datarate_sa8775p_3ph_4p5Gsps, + }, +}; + +struct csiphy_lane_regs datarate_sm8250_3ph_2p5Gsps[] = { + {0x144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_lane_regs datarate_sm8250_3ph_3p5Gsps[] = { + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_lane_regs datarate_sm8250_3ph_4p5Gsps[] = { + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x02, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x01, CSIPHY_DEFAULT_PARAMS}, +}; + +static struct data_rate_reg_info data_rate_settings_sm8250_3ph[] = { + { + /* 2.5 GSpS */ + .bandwidth = 2500000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sm8250_3ph_2p5Gsps), + .data_rate_reg_array = datarate_sm8250_3ph_2p5Gsps, + }, + { + /* 3.5 GSpS */ + .bandwidth = 3500000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sm8250_3ph_3p5Gsps), + .data_rate_reg_array = datarate_sm8250_3ph_3p5Gsps, + }, + { + /* 4.5 GSpS */ + .bandwidth = 4500000000, + .data_rate_reg_array_size = ARRAY_SIZE(datarate_sm8250_3ph_4p5Gsps), + .data_rate_reg_array = datarate_sm8250_3ph_4p5Gsps, + }, +}; + /* GEN2 1.0 2PH */ /* 5 entries: clock + 4 lanes */ static const struct @@ -1231,6 +1413,60 @@ static void csiphy_gen1_config_lanes(struct csiphy_device *csiphy, writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_MISC1(l)); } +/* + * csiphy_cphy_data_rate_config - Apply data-rate specific C-PHY overrides + * + * Applied on top of the base lane_regs. Selects the first table entry whose + * bandwidth >= the data rate derived from @link_freq (highest entry if none + * qualifies, default entry if @link_freq is unknown) and writes its overrides. + */ +static void csiphy_cphy_data_rate_config(struct csiphy_device *csiphy, + struct data_rate_reg_info *settings, + size_t num_settings, + s64 link_freq, u8 settle_cnt) +{ + struct device *dev = csiphy->camss->dev; + const struct csiphy_lane_regs *r; + size_t idx, i; + u32 val; + + if (!settings || !num_settings) + return; + + if (!link_freq) { + /* Link frequency unknown; use the default (lowest) entry. */ + idx = CSIPHY_CPHY_DATA_RATE_DEFAULT_IDX; + } else { + /* First entry that satisfies the rate, else the highest. */ + for (idx = 0; idx < num_settings; idx++) { + if (settings[idx].bandwidth >= link_freq) + break; + } + } + + dev_dbg(dev, + "CSIPHY using specific bandwidth %llu bits/s (entry %zu) for link_freq %lld\n", + settings[idx].bandwidth, idx, link_freq); + + r = settings[idx].data_rate_reg_array; + for (i = 0; i < settings[idx].data_rate_reg_array_size; i++, r++) { + switch (r->csiphy_param_type) { + case CSIPHY_SETTLE_CNT_LOWER_BYTE: + val = settle_cnt & 0xff; + break; + case CSIPHY_SETTLE_CNT_HIGHER_BYTE: + val = (settle_cnt >> 8) & 0xff; + break; + default: + val = r->reg_data; + break; + } + writel_relaxed(val, csiphy->base + r->reg_addr); + if (r->delay_us) + udelay(r->delay_us); + } +} + static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, u8 settle_cnt) { @@ -1311,6 +1547,8 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, struct device *dev = csiphy->camss->dev; struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; struct csiphy_device_regs *regs = csiphy->regs; + struct data_rate_reg_info *data_rate_settings = NULL; + size_t num_data_rate_settings = 0; u8 settle_cnt; u8 val; int i; @@ -1352,6 +1590,8 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { regs->lane_regs = &lane_regs_sm8250_3ph[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8250_3ph); + data_rate_settings = data_rate_settings_sm8250_3ph; + num_data_rate_settings = ARRAY_SIZE(data_rate_settings_sm8250_3ph); } else { regs->lane_regs = &lane_regs_sm8250[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8250); @@ -1387,6 +1627,8 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY) { regs->lane_regs = &lane_regs_sa8775p_3ph[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p_3ph); + data_rate_settings = data_rate_settings_sa8775p_3ph; + num_data_rate_settings = ARRAY_SIZE(data_rate_settings_sa8775p_3ph); } else { regs->lane_regs = &lane_regs_sa8775p[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p); @@ -1464,6 +1706,15 @@ static int csiphy_lanes_enable(struct csiphy_device *csiphy, else csiphy_gen1_config_lanes(csiphy, cfg, settle_cnt); + /* + * For C-PHY platforms with a data-rate settings table, apply the + * data-rate specific overrides on top of the base lane_regs config. + */ + if (c->phy_cfg == V4L2_MBUS_CSI2_CPHY && data_rate_settings) + csiphy_cphy_data_rate_config(csiphy, data_rate_settings, + num_data_rate_settings, + link_freq, settle_cnt); + /* IRQ_MASK registers - disable all interrupts */ for (i = 11; i < 22; i++) { writel_relaxed(0, csiphy->base + diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 8643ab57c3786..c1232986a2598 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -63,6 +63,12 @@ struct csiphy_formats { const struct csiphy_format_info *formats; }; +struct data_rate_reg_info { + u64 bandwidth; + ssize_t data_rate_reg_array_size; + struct csiphy_lane_regs *data_rate_reg_array; +}; + struct csiphy_device; struct csiphy_hw_ops { From adb6a916c055c31c4f7f65eb4df231fb7fd70afd Mon Sep 17 00:00:00 2001 From: Anusha Arun Nandi Date: Tue, 23 Jun 2026 02:13:41 +0000 Subject: [PATCH 15/15] PENDING: media: qcom: camss: validate local/remote endpoint bus-type Parse the remote (sensor) endpoint in camss_parse_endpoint_node() and compare its bus-type against the local (CSIPHY) endpoint. Reject the link with -EINVAL if the two ends disagree, so CPHY/DPHY mismatches are caught early during probe. CRs-Fixed: 4571838 Co-developed-by: Jigarkumar Zala Signed-off-by: Jigarkumar Zala Signed-off-by: Anusha Arun Nandi --- drivers/media/platform/qcom/camss/camss.c | 28 ++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 212914d84a0b3..fd231f3ea4b88 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -4568,7 +4568,9 @@ static int camss_parse_endpoint_node(struct device *dev, { struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg; struct v4l2_mbus_config_mipi_csi2 *mipi_csi2; - struct v4l2_fwnode_endpoint vep = { { 0 } }; + struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_UNKNOWN }; + struct v4l2_fwnode_endpoint remote_vep = { .bus_type = V4L2_MBUS_UNKNOWN }; + struct fwnode_handle *remote_ep; unsigned int i; int ret; @@ -4585,6 +4587,30 @@ static int camss_parse_endpoint_node(struct device *dev, return -EINVAL; } + /* Get the remote (sensor) endpoint handle, e.g. imx686_ep1 */ + remote_ep = fwnode_graph_get_remote_endpoint(ep); + if (!remote_ep) { + dev_dbg(dev, "No remote endpoint found for %pfw\n", ep); + return -ENODEV; + } + + /* Parse the remote bus type and release the handle */ + ret = v4l2_fwnode_endpoint_parse(remote_ep, &remote_vep); + fwnode_handle_put(remote_ep); + if (ret) { + dev_dbg(dev, "Failed to parse remote endpoint\n"); + return ret; + } + + /* The local (CSIPHY) and remote (sensor) ends must agree */ + if (vep.bus_type != remote_vep.bus_type) { + dev_dbg(dev, "Bus type mismatch! Local (CSI-PHY): %u, Remote (Sensor): %u\n", + vep.bus_type, remote_vep.bus_type); + return -EINVAL; + } + + dev_dbg(dev, "Verified link: both ends use bus-type %u\n", vep.bus_type); + csd->interface.csiphy_id = vep.base.port; mipi_csi2 = &vep.bus.mipi_csi2;