[PATCH v3 06/13] media: stm32: dcmipp: configure csi input of all pipes on stm32mp25
From: Alain Volmat
Date: Fri Jul 24 2026 - 12:33:01 EST
The STM32MP25 has CSI input and 2 additional pixel pipes in addition
to the byte pipe. Each pipe can select which data to receive based
on CSI VC/DT selection.
The multi-stream support of DCMIPP will be added in a future commit,
however, to start putting proper control method, the input subset
has now 3 SRC pads, one per pipe available.
Currently, and until multi-stream support is added, same data is
sent to all pipes.
Signed-off-by: Alain Volmat <alain.volmat@xxxxxxxxxxx>
---
.../platform/st/stm32/stm32-dcmipp/dcmipp-input.c | 86 +++++++++++++++-------
1 file changed, 58 insertions(+), 28 deletions(-)
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
index 75421035cfad5..220e03ea38aae 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
@@ -43,12 +43,18 @@
#define DCMIPP_CMCR_INSEL BIT(0)
#define DCMIPP_P0FSCR 0x404
-#define DCMIPP_P0FSCR_DTMODE_MASK GENMASK(17, 16)
-#define DCMIPP_P0FSCR_DTMODE_SHIFT 16
-#define DCMIPP_P0FSCR_DTMODE_DTIDA 0x00
+#define DCMIPP_P1FSCR 0x804
+#define DCMIPP_P2FSCR 0xC04
+#define DCMIPP_PXFSCR_DTMODE_MASK GENMASK(17, 16)
+#define DCMIPP_PXFSCR_DTMODE_SHIFT 16
+#define DCMIPP_PXFSCR_DTMODE_DTIDA 0x00
#define DCMIPP_P0FSCR_DTMODE_ALLDT 0x03
-#define DCMIPP_P0FSCR_DTIDA_MASK GENMASK(5, 0)
-#define DCMIPP_P0FSCR_DTIDA_SHIFT 0
+#define DCMIPP_PXFSCR_DTIDA_MASK GENMASK(5, 0)
+#define DCMIPP_PXFSCR_DTIDA_SHIFT 0
+
+#define DCMIPP_PXFSCR(a) (((a) == 0) ? DCMIPP_P0FSCR :\
+ ((a) == 1) ? DCMIPP_P1FSCR :\
+ DCMIPP_P2FSCR)
#define IS_SINK(pad) (!(pad))
#define IS_SRC(pad) ((pad))
@@ -274,6 +280,7 @@ static int dcmipp_inp_set_fmt(struct v4l2_subdev *sd,
{
struct dcmipp_inp_device *inp = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
+ int pad;
if (v4l2_subdev_is_streaming(sd))
return -EBUSY;
@@ -298,9 +305,11 @@ static int dcmipp_inp_set_fmt(struct v4l2_subdev *sd,
/* When setting the sink format, report that format on the src pad */
if (IS_SINK(fmt->pad)) {
- mf = v4l2_subdev_state_get_format(sd_state, 1);
- *mf = fmt->format;
- dcmipp_inp_adjust_fmt(inp, mf, 1);
+ for (pad = 1; pad < sd->entity.num_pads; pad++) {
+ mf = v4l2_subdev_state_get_format(sd_state, pad);
+ *mf = fmt->format;
+ dcmipp_inp_adjust_fmt(inp, mf, pad);
+ }
}
return 0;
@@ -383,7 +392,8 @@ static int dcmipp_inp_configure_parallel(struct dcmipp_inp_device *inp,
}
static int dcmipp_inp_configure_csi(struct dcmipp_inp_device *inp,
- struct v4l2_subdev_state *state)
+ struct v4l2_subdev_state *state,
+ u32 pad)
{
const struct dcmipp_inp_pix_map *vpix;
struct v4l2_mbus_framefmt *sink_fmt;
@@ -391,7 +401,7 @@ static int dcmipp_inp_configure_csi(struct dcmipp_inp_device *inp,
/* Get format information */
sink_fmt = v4l2_subdev_state_get_format(state, 0);
- src_fmt = v4l2_subdev_state_get_format(state, 1);
+ src_fmt = v4l2_subdev_state_get_format(state, pad);
vpix = dcmipp_inp_pix_map_by_code(sink_fmt->code, src_fmt->code);
if (!vpix) {
@@ -399,22 +409,28 @@ static int dcmipp_inp_configure_csi(struct dcmipp_inp_device *inp,
return -EINVAL;
}
- /* Apply configuration on each input pipe */
- reg_clear(inp, DCMIPP_P0FSCR,
- DCMIPP_P0FSCR_DTMODE_MASK | DCMIPP_P0FSCR_DTIDA_MASK);
+ /* Perform the configuration on the related pad/pipe */
+ reg_clear(inp, DCMIPP_PXFSCR(pad - 1),
+ DCMIPP_PXFSCR_DTMODE_MASK | DCMIPP_PXFSCR_DTIDA_MASK);
/* In case of JPEG we don't know the DT so we allow all data */
/*
* TODO - check instead dt == 0 for the time being to allow other
* unknown data-type
*/
- if (!vpix->dt)
- reg_set(inp, DCMIPP_P0FSCR,
- DCMIPP_P0FSCR_DTMODE_ALLDT << DCMIPP_P0FSCR_DTMODE_SHIFT);
- else
+ if (!vpix->dt) {
+ if (pad != 1) {
+ dev_err(inp->dev, "JPEG only available on pipe 0\n");
+ return -EINVAL;
+ }
+ /* Only available on Pipe #0 */
reg_set(inp, DCMIPP_P0FSCR,
- vpix->dt << DCMIPP_P0FSCR_DTIDA_SHIFT |
- DCMIPP_P0FSCR_DTMODE_DTIDA);
+ DCMIPP_P0FSCR_DTMODE_ALLDT << DCMIPP_PXFSCR_DTMODE_SHIFT);
+ } else {
+ reg_set(inp, DCMIPP_PXFSCR(pad - 1),
+ vpix->dt << DCMIPP_PXFSCR_DTIDA_SHIFT |
+ DCMIPP_PXFSCR_DTMODE_DTIDA);
+ }
/* Select the DCMIPP CSI interface */
reg_write(inp, DCMIPP_CMCR, DCMIPP_CMCR_INSEL);
@@ -432,20 +448,24 @@ static int dcmipp_inp_enable_streams(struct v4l2_subdev *sd,
struct media_pad *s_pad;
int ret = 0;
- /* Get source subdev */
- s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
- if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
- return -EINVAL;
- s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
-
if (inp->ved.bus_type == V4L2_MBUS_PARALLEL ||
inp->ved.bus_type == V4L2_MBUS_BT656)
ret = dcmipp_inp_configure_parallel(inp, state);
else if (inp->ved.bus_type == V4L2_MBUS_CSI2_DPHY)
- ret = dcmipp_inp_configure_csi(inp, state);
+ ret = dcmipp_inp_configure_csi(inp, state, pad);
if (ret)
return ret;
+ /* If there where no other pad enabled, then enable the source subdev */
+ if (sd->enabled_pads)
+ return 0;
+
+ /* Get source subdev */
+ s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
+ if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
+ return -EINVAL;
+ s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
+
ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0));
if (ret < 0) {
dev_err(inp->dev,
@@ -466,6 +486,10 @@ static int dcmipp_inp_disable_streams(struct v4l2_subdev *sd,
struct media_pad *s_pad;
int ret;
+ /* Don't do anything if there are still other pads enabled */
+ if ((sd->enabled_pads & ~BIT(pad)))
+ return 0;
+
/* Get source subdev */
s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
@@ -533,8 +557,10 @@ struct dcmipp_ent_device *dcmipp_inp_ent_init(const char *entity_name,
struct dcmipp_inp_device *inp;
const unsigned long pads_flag[] = {
MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
+ MEDIA_PAD_FL_SOURCE, MEDIA_PAD_FL_SOURCE,
};
struct device *dev = dcmipp->dev;
+ u16 num_pads = ARRAY_SIZE(pads_flag);
int ret;
/* Allocate the inp struct */
@@ -543,18 +569,22 @@ struct dcmipp_ent_device *dcmipp_inp_ent_init(const char *entity_name,
return ERR_PTR(-ENOMEM);
inp->regs = dcmipp->regs;
+ inp->ved.dcmipp = dcmipp;
+
+ /* For DCMIPP without CSI2, there is only a single pipe hence 2 pads */
+ if (!inp->ved.dcmipp->pipe_cfg->has_csi2)
+ num_pads = 2;
/* Initialize ved and sd */
ret = dcmipp_ent_sd_register(&inp->ved, &inp->sd, &dcmipp->v4l2_dev,
entity_name, MEDIA_ENT_F_VID_IF_BRIDGE,
- ARRAY_SIZE(pads_flag), pads_flag,
+ num_pads, pads_flag,
&dcmipp_inp_int_ops, &dcmipp_inp_ops,
NULL, NULL);
if (ret) {
kfree(inp);
return ERR_PTR(ret);
}
- inp->ved.dcmipp = dcmipp;
inp->dev = dev;
--
2.34.1