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