[PATCH 06/13] media: stm32: dcmipp: configure csi input of all pipes on stm32mp25
From: Alain Volmat <alain.volmat@foss.st.com>
Date: 2026-02-02 13:58:12
Also in:
linux-devicetree, linux-media, lkml
Subsystem:
media drivers for stm32 - dcmi / dcmipp, media input infrastructure (v4l/dvb), the rest · Maintainers:
Hugues Fruchet, Alain Volmat, Mauro Carvalho Chehab, Linus Torvalds
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@foss.st.com> --- .../platform/st/stm32/stm32-dcmipp/dcmipp-input.c | 75 +++++++++++++++------- 1 file changed, 51 insertions(+), 24 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 bed79a813def..82427c5d126e 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))
@@ -383,7 +389,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;
@@ -399,22 +406,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 +445,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 +483,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 +554,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 +566,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