media: qcom: camss: Add link support for TPG

TPG is connected to the csid as an entity, the link
needs to be adapted.

Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # Dell Inpsiron14p
Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
This commit is contained in:
Wenmeng Liu 2026-03-17 18:05:46 +08:00 committed by Bryan O'Donoghue
parent 70b193987c
commit 4b14db418b
5 changed files with 90 additions and 14 deletions

View File

@ -35,6 +35,8 @@
#define HW_VERSION_REVISION 16
#define HW_VERSION_GENERATION 28
#define LANE_CFG_BITWIDTH 4
#define MSM_CSID_NAME "msm_csid"
const char * const csid_testgen_modes[] = {
@ -1215,18 +1217,22 @@ void msm_csid_get_csid_id(struct media_entity *entity, u8 *id)
}
/*
* csid_get_lane_assign - Calculate CSI2 lane assign configuration parameter
* @lane_cfg - CSI2 lane configuration
* csid_get_lane_assign - Calculate lane assign by csiphy/tpg lane num
* @lane_cfg: CSI2 lane configuration
* @num_lanes: lane num
*
* Return lane assign
*/
static u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg)
static u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg, int num_lanes)
{
u32 lane_assign = 0;
int pos;
int i;
for (i = 0; i < lane_cfg->num_data; i++)
lane_assign |= lane_cfg->data[i].pos << (i * 4);
for (i = 0; i < num_lanes; i++) {
pos = lane_cfg ? lane_cfg->data[i].pos : i;
lane_assign |= pos << (i * LANE_CFG_BITWIDTH);
}
return lane_assign;
}
@ -1251,6 +1257,7 @@ static int csid_link_setup(struct media_entity *entity,
if ((local->flags & MEDIA_PAD_FL_SINK) &&
(flags & MEDIA_LNK_FL_ENABLED)) {
struct v4l2_subdev *sd;
struct tpg_device *tpg;
struct csid_device *csid;
struct csiphy_device *csiphy;
struct csiphy_lanes_cfg *lane_cfg;
@ -1265,18 +1272,28 @@ static int csid_link_setup(struct media_entity *entity,
return -EBUSY;
sd = media_entity_to_v4l2_subdev(remote->entity);
csiphy = v4l2_get_subdevdata(sd);
if (sd->grp_id == TPG_GRP_ID) {
tpg = v4l2_get_subdevdata(sd);
/* If a sensor is not linked to CSIPHY */
/* do no allow a link from CSIPHY to CSID */
if (!csiphy->cfg.csi2)
return -EPERM;
csid->phy.lane_cnt = tpg->res->lane_cnt;
csid->phy.csiphy_id = tpg->id;
csid->phy.lane_assign = csid_get_lane_assign(NULL, csid->phy.lane_cnt);
csid->tpg_linked = true;
} else {
csiphy = v4l2_get_subdevdata(sd);
csid->phy.csiphy_id = csiphy->id;
/* If a sensor is not linked to CSIPHY */
/* do no allow a link from CSIPHY to CSID */
if (!csiphy->cfg.csi2)
return -EPERM;
lane_cfg = &csiphy->cfg.csi2->lane_cfg;
csid->phy.lane_cnt = lane_cfg->num_data;
csid->phy.lane_assign = csid_get_lane_assign(lane_cfg);
csid->phy.csiphy_id = csiphy->id;
lane_cfg = &csiphy->cfg.csi2->lane_cfg;
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;
}
}
/* Decide which virtual channels to enable based on which source pads are enabled */
if (local->flags & MEDIA_PAD_FL_SOURCE) {

View File

@ -161,6 +161,7 @@ struct csid_device {
int num_supplies;
struct completion reset_complete;
struct csid_testgen_config testgen;
bool tpg_linked;
struct csid_phy_config phy;
struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM];
struct v4l2_ctrl_handler ctrls;

View File

@ -793,6 +793,7 @@ int msm_csiphy_register_entity(struct csiphy_device *csiphy,
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
MSM_CSIPHY_NAME, csiphy->id);
sd->grp_id = CSIPHY_GRP_ID;
v4l2_set_subdevdata(sd, csiphy);
ret = csiphy_init_formats(sd, NULL);

View File

@ -21,6 +21,8 @@
#define MSM_CSIPHY_PAD_SRC 1
#define MSM_CSIPHY_PADS_NUM 2
#define CSIPHY_GRP_ID 1
struct csiphy_lane {
u8 pos;
u8 pol;

View File

@ -4748,6 +4748,19 @@ static int camss_init_subdevices(struct camss *camss)
}
}
if (camss->tpg) {
for (i = 0; i < camss->res->tpg_num; i++) {
ret = msm_tpg_subdev_init(camss, &camss->tpg[i],
&res->tpg_res[i], i);
if (ret < 0) {
dev_err(camss->dev,
"Failed to init tpg%d sub-device: %d\n",
i, ret);
return ret;
}
}
}
/* note: SM8250 requires VFE to be initialized before CSID */
for (i = 0; i < camss->res->vfe_num; i++) {
ret = msm_vfe_subdev_init(camss, &camss->vfe[i],
@ -4836,6 +4849,23 @@ static int camss_link_entities(struct camss *camss)
}
}
for (i = 0; i < camss->res->tpg_num; i++) {
for (j = 0; j < camss->res->csid_num; j++) {
ret = media_create_pad_link(&camss->tpg[i].subdev.entity,
MSM_TPG_PAD_SRC,
&camss->csid[j].subdev.entity,
MSM_CSID_PAD_SINK,
0);
if (ret < 0) {
camss_link_err(camss,
camss->tpg[i].subdev.entity.name,
camss->csid[j].subdev.entity.name,
ret);
return ret;
}
}
}
if (camss->ispif) {
for (i = 0; i < camss->res->csid_num; i++) {
for (j = 0; j < camss->ispif->line_num; j++) {
@ -4940,6 +4970,19 @@ static int camss_register_entities(struct camss *camss)
}
}
if (camss->tpg) {
for (i = 0; i < camss->res->tpg_num; i++) {
ret = msm_tpg_register_entity(&camss->tpg[i],
&camss->v4l2_dev);
if (ret < 0) {
dev_err(camss->dev,
"Failed to register tpg%d entity: %d\n",
i, ret);
goto err_reg_tpg;
}
}
}
for (i = 0; i < camss->res->csid_num; i++) {
ret = msm_csid_register_entity(&camss->csid[i],
&camss->v4l2_dev);
@ -4983,6 +5026,13 @@ static int camss_register_entities(struct camss *camss)
for (i--; i >= 0; i--)
msm_csid_unregister_entity(&camss->csid[i]);
i = camss->res->tpg_num;
err_reg_tpg:
if (camss->tpg) {
for (i--; i >= 0; i--)
msm_tpg_unregister_entity(&camss->tpg[i]);
}
i = camss->res->csiphy_num;
err_reg_csiphy:
for (i--; i >= 0; i--)
@ -5004,6 +5054,11 @@ static void camss_unregister_entities(struct camss *camss)
for (i = 0; i < camss->res->csiphy_num; i++)
msm_csiphy_unregister_entity(&camss->csiphy[i]);
if (camss->tpg) {
for (i = 0; i < camss->res->tpg_num; i++)
msm_tpg_unregister_entity(&camss->tpg[i]);
}
for (i = 0; i < camss->res->csid_num; i++)
msm_csid_unregister_entity(&camss->csid[i]);