Commit 9e5d1581 authored by AngeloGioacchino Del Regno's avatar AngeloGioacchino Del Regno Committed by Mauro Carvalho Chehab

media: camss: Add support for SDM630/636/660 camera subsystem

Add support for the Qualcomm SDM630/636/660 and SDA variants' camera
subsystem. These SoCs are equipped with:
- 3x CSI PHY 3-Phase v1.0 (downstream csiphy-v3.5)
- 4x CSID v5.0
- 2x ISPIF v3.0
- 2x VFE 4.8
As a note, this camera subsystem is very similar to the one that
is found in the MSM8998/APQ8098 SoCs.
Signed-off-by: default avatarAngeloGioacchino Del Regno <kholk11@gmail.com>
Reviewed-by: default avatarRobert Foss <robert.foss@linaro.org>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 3cba9d22
......@@ -383,7 +383,8 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
return 0;
return sink_code;
} else if (csid->camss->version == CAMSS_8x96) {
} else if (csid->camss->version == CAMSS_8x96 ||
csid->camss->version == CAMSS_660) {
switch (sink_code) {
case MEDIA_BUS_FMT_SBGGR10_1X10:
{
......@@ -718,7 +719,8 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
if (csid->camss->version == CAMSS_8x96) {
if (csid->camss->version == CAMSS_8x96 ||
csid->camss->version == CAMSS_660) {
u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
......@@ -1098,7 +1100,8 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
csid->formats = csid_formats_8x16;
csid->nformats =
ARRAY_SIZE(csid_formats_8x16);
} else if (camss->version == CAMSS_8x96) {
} else if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
csid->formats = csid_formats_8x96;
csid->nformats =
ARRAY_SIZE(csid_formats_8x96);
......
......@@ -554,7 +554,8 @@ int msm_csiphy_subdev_init(struct camss *camss,
csiphy->ops = &csiphy_ops_2ph_1_0;
csiphy->formats = csiphy_formats_8x16;
csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16);
} else if (camss->version == CAMSS_8x96) {
} else if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
csiphy->ops = &csiphy_ops_3ph_1_0;
csiphy->formats = csiphy_formats_8x96;
csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96);
......
......@@ -825,7 +825,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
ispif_select_csid(ispif, intf, csid, vfe, 1);
ispif_select_cid(ispif, intf, cid, vfe, 1);
ispif_config_irq(ispif, intf, vfe, 1);
if (to_camss(ispif)->version == CAMSS_8x96)
if (to_camss(ispif)->version == CAMSS_8x96 ||
to_camss(ispif)->version == CAMSS_660)
ispif_config_pack(ispif,
line->fmt[MSM_ISPIF_PAD_SINK].code,
intf, cid, vfe, 1);
......@@ -842,7 +843,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
mutex_lock(&ispif->config_lock);
if (to_camss(ispif)->version == CAMSS_8x96)
if (to_camss(ispif)->version == CAMSS_8x96 ||
to_camss(ispif)->version == CAMSS_660)
ispif_config_pack(ispif,
line->fmt[MSM_ISPIF_PAD_SINK].code,
intf, cid, vfe, 0);
......@@ -1098,7 +1100,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
/* Number of ISPIF lines - same as number of CSID hardware modules */
if (to_camss(ispif)->version == CAMSS_8x16)
ispif->line_num = 2;
else if (to_camss(ispif)->version == CAMSS_8x96)
else if (to_camss(ispif)->version == CAMSS_8x96 ||
to_camss(ispif)->version == CAMSS_660)
ispif->line_num = 4;
else
return -EINVAL;
......@@ -1116,7 +1119,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
ispif->line[i].formats = ispif_formats_8x16;
ispif->line[i].nformats =
ARRAY_SIZE(ispif_formats_8x16);
} else if (to_camss(ispif)->version == CAMSS_8x96) {
} else if (to_camss(ispif)->version == CAMSS_8x96 ||
to_camss(ispif)->version == CAMSS_660) {
ispif->line[i].formats = ispif_formats_8x96;
ispif->line[i].nformats =
ARRAY_SIZE(ispif_formats_8x96);
......@@ -1156,7 +1160,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
if (to_camss(ispif)->version == CAMSS_8x16)
ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
else if (to_camss(ispif)->version == CAMSS_8x96)
else if (to_camss(ispif)->version == CAMSS_8x96 ||
to_camss(ispif)->version == CAMSS_660)
ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
else
......
......@@ -205,7 +205,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
return sink_code;
}
else if (vfe->camss->version == CAMSS_8x96)
else if (vfe->camss->version == CAMSS_8x96 ||
vfe->camss->version == CAMSS_660)
switch (sink_code) {
case MEDIA_BUS_FMT_YUYV8_2X8:
{
......@@ -1991,12 +1992,19 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
vfe->isr_ops.comp_done = vfe_isr_comp_done;
vfe->isr_ops.wm_done = vfe_isr_wm_done;
if (camss->version == CAMSS_8x16)
switch (camss->version) {
case CAMSS_8x16:
vfe->ops = &vfe_ops_4_1;
else if (camss->version == CAMSS_8x96)
break;
case CAMSS_8x96:
vfe->ops = &vfe_ops_4_7;
else
break;
case CAMSS_660:
vfe->ops = &vfe_ops_4_8;
break;
default:
return -EINVAL;
}
/* Memory */
......@@ -2095,7 +2103,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
l->formats = formats_rdi_8x16;
l->nformats = ARRAY_SIZE(formats_rdi_8x16);
}
} else if (camss->version == CAMSS_8x96) {
} else if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
if (i == VFE_LINE_PIX) {
l->formats = formats_pix_8x96;
l->nformats = ARRAY_SIZE(formats_pix_8x96);
......
......@@ -970,7 +970,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
video->formats = formats_rdi_8x16;
video->nformats = ARRAY_SIZE(formats_rdi_8x16);
}
} else if (video->camss->version == CAMSS_8x96) {
} else if (video->camss->version == CAMSS_8x96 ||
video->camss->version == CAMSS_660) {
if (is_pix) {
video->formats = formats_pix_8x96;
video->nformats = ARRAY_SIZE(formats_pix_8x96);
......
......@@ -283,6 +283,188 @@ static const struct resources vfe_res_8x96[] = {
}
};
static const struct resources csiphy_res_660[] = {
/* CSIPHY0 */
{
.regulator = { NULL },
.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer",
"csi0_phy", "csiphy_ahb2crif" },
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 100000000, 200000000, 269333333 },
{ 0 } },
.reg = { "csiphy0", "csiphy0_clk_mux" },
.interrupt = { "csiphy0" }
},
/* CSIPHY1 */
{
.regulator = { NULL },
.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer",
"csi1_phy", "csiphy_ahb2crif" },
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 100000000, 200000000, 269333333 },
{ 0 } },
.reg = { "csiphy1", "csiphy1_clk_mux" },
.interrupt = { "csiphy1" }
},
/* CSIPHY2 */
{
.regulator = { NULL },
.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer",
"csi2_phy", "csiphy_ahb2crif" },
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 100000000, 200000000, 269333333 },
{ 0 } },
.reg = { "csiphy2", "csiphy2_clk_mux" },
.interrupt = { "csiphy2" }
}
};
static const struct resources csid_res_660[] = {
/* CSID0 */
{
.regulator = { "vdda", "vdd_sec" },
.clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
"csi0", "csi0_phy", "csi0_pix", "csi0_rdi",
"cphy_csid0" },
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 0 },
{ 100000000, 200000000, 310000000,
404000000, 465000000 },
{ 0 },
{ 0 },
{ 0 },
{ 0 } },
.reg = { "csid0" },
.interrupt = { "csid0" }
},
/* CSID1 */
{
.regulator = { "vdda", "vdd_sec" },
.clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
"csi1", "csi1_phy", "csi1_pix", "csi1_rdi",
"cphy_csid1" },
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 0 },
{ 100000000, 200000000, 310000000,
404000000, 465000000 },
{ 0 },
{ 0 },
{ 0 },
{ 0 } },
.reg = { "csid1" },
.interrupt = { "csid1" }
},
/* CSID2 */
{
.regulator = { "vdda", "vdd_sec" },
.clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb",
"csi2", "csi2_phy", "csi2_pix", "csi2_rdi",
"cphy_csid2" },
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 0 },
{ 100000000, 200000000, 310000000,
404000000, 465000000 },
{ 0 },
{ 0 },
{ 0 },
{ 0 } },
.reg = { "csid2" },
.interrupt = { "csid2" }
},
/* CSID3 */
{
.regulator = { "vdda", "vdd_sec" },
.clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb",
"csi3", "csi3_phy", "csi3_pix", "csi3_rdi",
"cphy_csid3" },
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 0 },
{ 100000000, 200000000, 310000000,
404000000, 465000000 },
{ 0 },
{ 0 },
{ 0 },
{ 0 } },
.reg = { "csid3" },
.interrupt = { "csid3" }
}
};
static const struct resources_ispif ispif_res_660 = {
/* ISPIF */
.clock = { "top_ahb", "ahb", "ispif_ahb",
"csi0", "csi0_pix", "csi0_rdi",
"csi1", "csi1_pix", "csi1_rdi",
"csi2", "csi2_pix", "csi2_rdi",
"csi3", "csi3_pix", "csi3_rdi" },
.clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
.reg = { "ispif", "csi_clk_mux" },
.interrupt = "ispif"
};
static const struct resources vfe_res_660[] = {
/* VFE0 */
{
.regulator = { NULL },
.clock = { "throttle_axi", "top_ahb", "ahb", "vfe0",
"csi_vfe0", "vfe_ahb", "vfe0_ahb", "vfe_axi",
"vfe0_stream"},
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 120000000, 200000000, 256000000,
300000000, 404000000, 480000000,
540000000, 576000000 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 } },
.reg = { "vfe0" },
.interrupt = { "vfe0" }
},
/* VFE1 */
{
.regulator = { NULL },
.clock = { "throttle_axi", "top_ahb", "ahb", "vfe1",
"csi_vfe1", "vfe_ahb", "vfe1_ahb", "vfe_axi",
"vfe1_stream"},
.clock_rate = { { 0 },
{ 0 },
{ 0 },
{ 120000000, 200000000, 256000000,
300000000, 404000000, 480000000,
540000000, 576000000 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 } },
.reg = { "vfe1" },
.interrupt = { "vfe1" }
}
};
/*
* camss_add_clock_margin - Add margin to clock frequency rate
* @rate: Clock frequency rate
......@@ -397,7 +579,8 @@ int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock)
int camss_pm_domain_on(struct camss *camss, int id)
{
if (camss->version == CAMSS_8x96) {
if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
camss->genpd_link[id] = device_link_add(camss->dev,
camss->genpd[id], DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
......@@ -411,7 +594,8 @@ int camss_pm_domain_on(struct camss *camss, int id)
void camss_pm_domain_off(struct camss *camss, int id)
{
if (camss->version == CAMSS_8x96)
if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660)
device_link_del(camss->genpd_link[id]);
}
......@@ -533,6 +717,11 @@ static int camss_init_subdevices(struct camss *camss)
csid_res = csid_res_8x96;
ispif_res = &ispif_res_8x96;
vfe_res = vfe_res_8x96;
} else if (camss->version == CAMSS_660) {
csiphy_res = csiphy_res_660;
csid_res = csid_res_660;
ispif_res = &ispif_res_660;
vfe_res = vfe_res_660;
} else {
return -EINVAL;
}
......@@ -833,6 +1022,12 @@ static int camss_probe(struct platform_device *pdev)
camss->csiphy_num = 3;
camss->csid_num = 4;
camss->vfe_num = 2;
} else if (of_device_is_compatible(dev->of_node,
"qcom,sdm660-camss")) {
camss->version = CAMSS_660;
camss->csiphy_num = 3;
camss->csid_num = 4;
camss->vfe_num = 2;
} else {
ret = -EINVAL;
goto err_free;
......@@ -919,7 +1114,8 @@ static int camss_probe(struct platform_device *pdev)
}
}
if (camss->version == CAMSS_8x96) {
if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id(
camss->dev, PM_DOMAIN_VFE0);
if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0]))
......@@ -958,7 +1154,8 @@ void camss_delete(struct camss *camss)
pm_runtime_disable(camss->dev);
if (camss->version == CAMSS_8x96) {
if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true);
dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true);
}
......@@ -989,6 +1186,7 @@ static int camss_remove(struct platform_device *pdev)
static const struct of_device_id camss_dt_match[] = {
{ .compatible = "qcom,msm8916-camss" },
{ .compatible = "qcom,msm8996-camss" },
{ .compatible = "qcom,sdm660-camss" },
{ }
};
......
......@@ -65,6 +65,7 @@ enum pm_domain {
enum camss_version {
CAMSS_8x16,
CAMSS_8x96,
CAMSS_660,
};
struct camss {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment