On Fri Aug 21 08:38:14 2026 +0200, Alain Volmat wrote:
> The dump pipe and pixel pipes capture part (tail of each pipe)
> is different in that pixel pipes have a pixel packer capable
> of generating various output format while the on dump pipe no
> such manipulation is possible.
> Still, all the buffer handling, format related manipulations
> are all same hence both dump and pixel pipe capture part are
> put together to avoid having large duplication of code.
> 
> This patch adds the pixel pipe capture within bytecap hence
> name isn't modified and a further commit should rename the
> file and probably function name to not only highlight byte
> capture (aka dump pipe).
> 
> Signed-off-by: Alain Volmat <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 .../st/stm32/stm32-dcmipp/dcmipp-bytecap.c         | 421 +++++++++++++++++----
 1 file changed, 355 insertions(+), 66 deletions(-)

---

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c 
b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index 53341b798457..4a8976da576a 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -25,27 +25,81 @@
 #define DCMIPP_CMIER_P0ALL     (DCMIPP_CMIER_P0VSYNCIE |\
                                 DCMIPP_CMIER_P0FRAMEIE |\
                                 DCMIPP_CMIER_P0OVRIE)
+#define DCMIPP_CMIER_P1FRAMEIE BIT(17)
+#define DCMIPP_CMIER_P1VSYNCIE BIT(18)
+#define DCMIPP_CMIER_P1OVRIE   BIT(23)
+#define DCMIPP_CMIER_P1ALL     (DCMIPP_CMIER_P1VSYNCIE |\
+                                DCMIPP_CMIER_P1FRAMEIE |\
+                                DCMIPP_CMIER_P1OVRIE)
+#define DCMIPP_CMIER_P2FRAMEIE BIT(25)
+#define DCMIPP_CMIER_P2VSYNCIE BIT(26)
+#define DCMIPP_CMIER_P2OVRIE   BIT(31)
+#define DCMIPP_CMIER_P2ALL     (DCMIPP_CMIER_P2VSYNCIE |\
+                                DCMIPP_CMIER_P2FRAMEIE |\
+                                DCMIPP_CMIER_P2OVRIE)
+#define DCMIPP_CMIER_PxALL(id) (((id) == 0) ? DCMIPP_CMIER_P0ALL :     \
+                                (((id) == 1) ? DCMIPP_CMIER_P1ALL :    \
+                                               DCMIPP_CMIER_P2ALL))
 #define DCMIPP_CMSR1           0x3f4
 #define DCMIPP_CMSR2           0x3f8
 #define DCMIPP_CMSR2_P0FRAMEF  BIT(9)
 #define DCMIPP_CMSR2_P0VSYNCF  BIT(10)
 #define DCMIPP_CMSR2_P0OVRF    BIT(15)
+#define DCMIPP_CMSR2_P1FRAMEF  BIT(17)
+#define DCMIPP_CMSR2_P1VSYNCF  BIT(18)
+#define DCMIPP_CMSR2_P1OVRF    BIT(23)
+#define DCMIPP_CMSR2_P2FRAMEF  BIT(25)
+#define DCMIPP_CMSR2_P2VSYNCF  BIT(26)
+#define DCMIPP_CMSR2_P2OVRF    BIT(31)
+#define DCMIPP_CMSR2_PxFRAMEF(id)      (((id) == 0) ? DCMIPP_CMSR2_P0FRAMEF :\
+                                        (((id) == 1) ? DCMIPP_CMSR2_P1FRAMEF :\
+                                                      DCMIPP_CMSR2_P2FRAMEF))
+#define DCMIPP_CMSR2_PxVSYNCF(id)      (((id) == 0) ? DCMIPP_CMSR2_P0VSYNCF :\
+                                        (((id) == 1) ? DCMIPP_CMSR2_P1VSYNCF :\
+                                                      DCMIPP_CMSR2_P2VSYNCF))
+#define DCMIPP_CMSR2_PxOVRF(id)        (((id) == 0) ? DCMIPP_CMSR2_P0OVRF :\
+                                (((id) == 1) ? DCMIPP_CMSR2_P1OVRF :\
+                                              DCMIPP_CMSR2_P2OVRF))
 #define DCMIPP_CMFCR           0x3fc
-#define DCMIPP_P0FSCR          0x404
-#define DCMIPP_P0FSCR_PIPEN    BIT(31)
-#define DCMIPP_P0FCTCR         0x500
-#define DCMIPP_P0FCTCR_CPTREQ  BIT(3)
+#define DCMIPP_PxFSCR(id)      (0x404 + ((id) * 0x400))
+#define DCMIPP_PxFSCR_PIPEN    BIT(31)
+#define DCMIPP_PxFCTCR(id)     (0x500 + ((id) * 0x400))
+#define DCMIPP_PxFCTCR_CPTREQ  BIT(3)
 #define DCMIPP_P0DCCNTR                0x5b0
 #define DCMIPP_P0DCLMTR                0x5b4
 #define DCMIPP_P0DCLMTR_ENABLE BIT(31)
 #define DCMIPP_P0DCLMTR_LIMIT_MASK     GENMASK(23, 0)
-#define DCMIPP_P0PPM0AR1       0x5c4
-#define DCMIPP_P0SR            0x5f8
-#define DCMIPP_P0SR_CPTACT     BIT(23)
+
+#define DCMIPP_PxPPM0AR1(id)   (0x5c4 + ((id) * 0x400))
+#define DCMIPP_PxPPM0PR(id)    (0x9cc + (((id) - 1) * 0x400))
+#define DCMIPP_P1PPM1AR1       0x9d4
+#define DCMIPP_P1PPM1PR                0x9dc
+#define DCMIPP_P1PPM2AR1       0x9e4
+
+#define DCMIPP_PxSR(id)                (0x5f8 + ((id) * 0x400))
+#define DCMIPP_PxSR_CPTACT     BIT(23)
+
+#define DCMIPP_PxPPCR(id)      (0x9c0 + (((id) - 1) * 0x400))
+#define DCMIPP_PxPPCR_FORMAT_RGB888    0x0
+#define DCMIPP_PxPPCR_FORMAT_RGB565    0x1
+#define DCMIPP_PxPPCR_FORMAT_ARGB8888  0x2
+#define DCMIPP_PxPPCR_FORMAT_RGBA8888  0x3
+#define DCMIPP_PxPPCR_FORMAT_Y8                0x4
+#define DCMIPP_PxPPCR_FORMAT_YUV444    0x5
+#define DCMIPP_PxPPCR_FORMAT_YUYV      0x6
+#define DCMIPP_P1PPCR_FORMAT_NV61      0x7
+#define DCMIPP_P1PPCR_FORMAT_NV21      0x8
+#define DCMIPP_P1PPCR_FORMAT_YV12      0x9
+#define DCMIPP_PxPPCR_FORMAT_UYVY      0xa
+
+#define DCMIPP_PxPPCR_SWAPRB           BIT(4)
 
 struct dcmipp_bytecap_pix_map {
        unsigned int code;
        u32 pixelformat;
+       u32 plane_nb;
+       unsigned int ppcr_fmt;
+       unsigned int swap_uv;
 };
 
 #define PIXMAP_MBUS_PFMT(mbus, fmt)                    \
@@ -54,7 +108,7 @@ struct dcmipp_bytecap_pix_map {
                .pixelformat = V4L2_PIX_FMT_##fmt       \
        }
 
-static const struct dcmipp_bytecap_pix_map dcmipp_bytecap_pix_map_list[] = {
+static const struct dcmipp_bytecap_pix_map dcmipp_bytecap_dump_pix_map_list[] 
= {
        PIXMAP_MBUS_PFMT(RGB565_2X8_LE, RGB565),
        PIXMAP_MBUS_PFMT(RGB565_1X16, RGB565),
        PIXMAP_MBUS_PFMT(RGB888_1X24, RGB24),
@@ -89,24 +143,47 @@ static const struct dcmipp_bytecap_pix_map 
dcmipp_bytecap_pix_map_list[] = {
        PIXMAP_MBUS_PFMT(JPEG_1X8, JPEG),
 };
 
-static const struct dcmipp_bytecap_pix_map *
-dcmipp_bytecap_pix_map_by_pixelformat(u32 pixelformat)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(dcmipp_bytecap_pix_map_list); i++) {
-               if (dcmipp_bytecap_pix_map_list[i].pixelformat == pixelformat)
-                       return &dcmipp_bytecap_pix_map_list[i];
+#define PIXMAP_MBUS_PIXEL_PFMT(mbus, fmt, nb_plane, pp_code, swap)             
\
+       {                                               \
+               .code = MEDIA_BUS_FMT_##mbus,           \
+               .pixelformat = V4L2_PIX_FMT_##fmt,      \
+               .plane_nb = nb_plane,                   \
+               .ppcr_fmt = pp_code,                    \
+               .swap_uv = swap,                        \
        }
 
-       return NULL;
-}
+static const struct dcmipp_bytecap_pix_map dcmipp_bytecap_pixel_pix_map_list[] 
= {
+       /* Coplanar formats are supported on main & aux pipe */
+       PIXMAP_MBUS_PIXEL_PFMT(RGB888_1X24, RGB565, 1, 
DCMIPP_PxPPCR_FORMAT_RGB565, 0),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, YUYV, 1, DCMIPP_PxPPCR_FORMAT_YUYV, 
0),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, YVYU, 1, DCMIPP_PxPPCR_FORMAT_YUYV, 
1),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, UYVY, 1, DCMIPP_PxPPCR_FORMAT_UYVY, 
0),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, VYUY, 1, DCMIPP_PxPPCR_FORMAT_UYVY, 
1),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, GREY, 1, DCMIPP_PxPPCR_FORMAT_Y8, 0),
+       PIXMAP_MBUS_PIXEL_PFMT(RGB888_1X24, RGB24, 1, 
DCMIPP_PxPPCR_FORMAT_RGB888, 1),
+       PIXMAP_MBUS_PIXEL_PFMT(RGB888_1X24, BGR24, 1, 
DCMIPP_PxPPCR_FORMAT_RGB888, 0),
+       PIXMAP_MBUS_PIXEL_PFMT(RGB888_1X24, ARGB32, 1, 
DCMIPP_PxPPCR_FORMAT_RGBA8888, 1),
+       PIXMAP_MBUS_PIXEL_PFMT(RGB888_1X24, ABGR32, 1, 
DCMIPP_PxPPCR_FORMAT_ARGB8888, 0),
+       PIXMAP_MBUS_PIXEL_PFMT(RGB888_1X24, RGBA32, 1, 
DCMIPP_PxPPCR_FORMAT_ARGB8888, 1),
+       PIXMAP_MBUS_PIXEL_PFMT(RGB888_1X24, BGRA32, 1, 
DCMIPP_PxPPCR_FORMAT_RGBA8888, 0),
+
+       /* Semiplanar & planar formats (plane_nb > 1) are only supported on 
main pipe */
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, NV12, 2, DCMIPP_P1PPCR_FORMAT_NV21, 
0),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, NV21, 2, DCMIPP_P1PPCR_FORMAT_NV21, 
1),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, NV16, 2, DCMIPP_P1PPCR_FORMAT_NV61, 
0),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, NV61, 2, DCMIPP_P1PPCR_FORMAT_NV61, 
1),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, YUV420, 3, DCMIPP_P1PPCR_FORMAT_YV12, 
0),
+       PIXMAP_MBUS_PIXEL_PFMT(YUV8_1X24, YVU420, 3, DCMIPP_P1PPCR_FORMAT_YV12, 
1),
+};
 
 struct dcmipp_buf {
        struct vb2_v4l2_buffer  vb;
        bool                    prepared;
        dma_addr_t              addr;
        size_t                  size;
+       dma_addr_t              addrs[3];
+       u32                     strides[3];
+       u64                     sizes[3];
        struct list_head        list;
 };
 
@@ -140,6 +217,11 @@ struct dcmipp_bytecap_device {
 
        void __iomem *regs;
 
+       int pipe_id;
+
+       const struct dcmipp_bytecap_pix_map *pix_map;
+       unsigned int pix_map_array_size;
+
        u32 cmsr2;
 
        struct {
@@ -155,6 +237,30 @@ struct dcmipp_bytecap_device {
        } count;
 };
 
+static const struct dcmipp_bytecap_pix_map *
+dcmipp_bytecap_pix_map_by_pixelformat(struct dcmipp_bytecap_device *vcap,
+                                     u32 pixelformat)
+{
+       for (unsigned int i = 0; i < vcap->pix_map_array_size; i++) {
+               if (vcap->pix_map[i].pixelformat == pixelformat)
+                       return &vcap->pix_map[i];
+       }
+
+       return NULL;
+}
+
+static bool dcmipp_bytecap_is_format_valid(struct dcmipp_bytecap_device *vcap,
+                                          unsigned int pixelformat)
+{
+       const struct dcmipp_bytecap_pix_map *vpix =
+               dcmipp_bytecap_pix_map_by_pixelformat(vcap, pixelformat);
+
+       if (!vpix || (vpix->plane_nb > 1 && vcap->pipe_id != 1))
+               return false;
+
+       return true;
+}
+
 static const struct v4l2_pix_format fmt_default = {
        .width = DCMIPP_FMT_WIDTH_DEFAULT,
        .height = DCMIPP_FMT_HEIGHT_DEFAULT,
@@ -168,6 +274,73 @@ static const struct v4l2_pix_format fmt_default = {
        .xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
 };
 
+static inline int hdw_pixel_alignment(u32 format)
+{
+       /* 16 bytes alignment required by hardware */
+       switch (format) {
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_GREY:
+               return 4;/* 2^4 = 16 pixels = 16 bytes */
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
+               return 3;/* 2^3  = 8 pixels = 16 bytes */
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+               return 4;/* 2^4 = 16 pixels = 48 bytes */
+       case V4L2_PIX_FMT_ARGB32:
+       case V4L2_PIX_FMT_ABGR32:
+       case V4L2_PIX_FMT_RGBA32:
+       case V4L2_PIX_FMT_BGRA32:
+               return 2;/* 2^2  = 4 pixels = 16 bytes */
+       default:
+               return 0;
+       }
+}
+
+static inline int frame_planes(dma_addr_t base_addr, dma_addr_t addrs[],
+                              u32 strides[], u64 sizes[],
+                              u32 width, u32 height, u32 format)
+{
+       const struct v4l2_format_info *info;
+
+       /* Only used by dump pipe hence addrs[0] is enough */
+       if (format == V4L2_PIX_FMT_JPEG) {
+               addrs[0] = base_addr;
+               return 0;
+       }
+
+       info = v4l2_format_info(format);
+       if (!info)
+               return -EINVAL;
+
+       /* Fill-in each plane information */
+       addrs[0] = base_addr;
+       strides[0] = width * info->bpp[0];
+       sizes[0] = strides[0] * height;
+
+       if (info->comp_planes > 1) {
+               addrs[1] = addrs[0] + sizes[0];
+               strides[1] = width * info->bpp[1] / info->hdiv;
+               sizes[1] = strides[1] * height / info->vdiv;
+       }
+
+       if (info->comp_planes > 2) {
+               addrs[2] = addrs[1] + sizes[1];
+               strides[2] = width * info->bpp[2] / info->hdiv;
+               sizes[2] = strides[2] * height / info->vdiv;
+       }
+
+       return 0;
+}
+
 static int dcmipp_bytecap_querycap(struct file *file, void *priv,
                                   struct v4l2_capability *cap)
 {
@@ -192,21 +365,24 @@ static int dcmipp_bytecap_try_fmt_vid_cap(struct file 
*file, void *priv,
 {
        struct dcmipp_bytecap_device *vcap = video_drvdata(file);
        struct v4l2_pix_format *format = &f->fmt.pix;
-       const struct dcmipp_bytecap_pix_map *vpix;
        u32 in_w, in_h;
 
        /* Don't accept a pixelformat that is not on the table */
-       vpix = dcmipp_bytecap_pix_map_by_pixelformat(format->pixelformat);
-       if (!vpix)
+       if (!dcmipp_bytecap_is_format_valid(vcap, format->pixelformat))
                format->pixelformat = fmt_default.pixelformat;
 
        /* Adjust width & height */
        in_w = format->width;
        in_h = format->height;
-       v4l_bound_align_image(&format->width, DCMIPP_FRAME_MIN_WIDTH,
-                             DCMIPP_FRAME_MAX_WIDTH, 0, &format->height,
-                             DCMIPP_FRAME_MIN_HEIGHT, DCMIPP_FRAME_MAX_HEIGHT,
-                             0, 0);
+       format->width = clamp_t(u32, format->width, DCMIPP_FRAME_MIN_WIDTH,
+                               vcap->pipe_id != 0 ?
+                               DCMIPP_FRAME_MAX_WIDTH : 
DCMIPP_FRAME_MAX_WIDTH);
+       if (vcap->pipe_id != 0)
+               format->width = round_up(format->width,
+                                        1 << 
hdw_pixel_alignment(format->pixelformat));
+       format->height = clamp_t(u32, format->height, DCMIPP_FRAME_MIN_HEIGHT,
+                                vcap->pipe_id != 0 ?
+                                DCMIPP_FRAME_MAX_HEIGHT : 
DCMIPP_FRAME_MAX_HEIGHT);
        if (format->width != in_w || format->height != in_h)
                dev_dbg(vcap->dev, "resolution updated: %dx%d -> %dx%d\n",
                        in_w, in_h, format->width, format->height);
@@ -262,7 +438,7 @@ static int dcmipp_bytecap_s_fmt_vid_cap(struct file *file, 
void *priv,
 static int dcmipp_bytecap_enum_fmt_vid_cap(struct file *file, void *priv,
                                           struct v4l2_fmtdesc *f)
 {
-       const struct dcmipp_bytecap_pix_map *vpix;
+       struct dcmipp_bytecap_device *vcap = video_drvdata(file);
        unsigned int index = f->index;
        unsigned int i, prev_pixelformat = 0;
 
@@ -271,17 +447,20 @@ static int dcmipp_bytecap_enum_fmt_vid_cap(struct file 
*file, void *priv,
         * care of removing duplicated entries (due to support of both
         * parallel & csi 16 bits formats
         */
-       for (i = 0; i < ARRAY_SIZE(dcmipp_bytecap_pix_map_list); i++) {
-               vpix = &dcmipp_bytecap_pix_map_list[i];
+       for (i = 0; i < vcap->pix_map_array_size; i++) {
+               /* Only main pipe supports (Semi)-planar formats */
+               if (vcap->pipe_id != 1 && vcap->pix_map[i].plane_nb > 1)
+                       continue;
+
                /* Skip formats not matching requested mbus code */
-               if (f->mbus_code && vpix->code != f->mbus_code)
+               if (f->mbus_code && vcap->pix_map[i].code != f->mbus_code)
                        continue;
 
                /* Skip duplicated pixelformat */
-               if (vpix->pixelformat == prev_pixelformat)
+               if (vcap->pix_map[i].pixelformat == prev_pixelformat)
                        continue;
 
-               prev_pixelformat = vpix->pixelformat;
+               prev_pixelformat = vcap->pix_map[i].pixelformat;
 
                if (index == 0)
                        break;
@@ -289,10 +468,10 @@ static int dcmipp_bytecap_enum_fmt_vid_cap(struct file 
*file, void *priv,
                index--;
        }
 
-       if (i == ARRAY_SIZE(dcmipp_bytecap_pix_map_list))
+       if (i == vcap->pix_map_array_size)
                return -EINVAL;
 
-       f->pixelformat = vpix->pixelformat;
+       f->pixelformat = vcap->pix_map[i].pixelformat;
 
        return 0;
 }
@@ -300,14 +479,14 @@ static int dcmipp_bytecap_enum_fmt_vid_cap(struct file 
*file, void *priv,
 static int dcmipp_bytecap_enum_framesizes(struct file *file, void *fh,
                                          struct v4l2_frmsizeenum *fsize)
 {
-       const struct dcmipp_bytecap_pix_map *vpix;
+       struct dcmipp_bytecap_device *vcap = video_drvdata(file);
+
 
        if (fsize->index)
                return -EINVAL;
 
        /* Only accept code in the pix map table */
-       vpix = dcmipp_bytecap_pix_map_by_pixelformat(fsize->pixel_format);
-       if (!vpix)
+       if (!dcmipp_bytecap_is_format_valid(vcap, fsize->pixel_format))
                return -EINVAL;
 
        fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
@@ -355,14 +534,27 @@ static void dcmipp_start_capture(struct 
dcmipp_bytecap_device *vcap,
                                 struct dcmipp_buf *buf)
 {
        /* Set buffer address */
-       reg_write(vcap, DCMIPP_P0PPM0AR1, buf->addr);
+       reg_write(vcap, DCMIPP_PxPPM0AR1(vcap->pipe_id), buf->addrs[0]);
 
-       /* Set buffer size */
-       reg_write(vcap, DCMIPP_P0DCLMTR, DCMIPP_P0DCLMTR_ENABLE |
-                 ((buf->size / 4) & DCMIPP_P0DCLMTR_LIMIT_MASK));
+       if (vcap->pipe_id == 0) {
+               /* Set buffer size */
+               reg_write(vcap, DCMIPP_P0DCLMTR, DCMIPP_P0DCLMTR_ENABLE |
+                         ((buf->size / 4) & DCMIPP_P0DCLMTR_LIMIT_MASK));
+       } else {
+               reg_write(vcap, DCMIPP_PxPPM0PR(vcap->pipe_id),
+                         buf->strides[0]);
+
+               if (buf->addrs[1]) {
+                       reg_write(vcap, DCMIPP_P1PPM1AR1, buf->addrs[1]);
+                       reg_write(vcap, DCMIPP_P1PPM1PR, buf->strides[1]);
+               }
+
+               if (buf->addrs[2])
+                       reg_write(vcap, DCMIPP_P1PPM2AR1, buf->addrs[2]);
+       }
 
        /* Capture request */
-       reg_set(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
+       reg_set(vcap, DCMIPP_PxFCTCR(vcap->pipe_id), DCMIPP_PxFCTCR_CPTREQ);
 }
 
 static void dcmipp_bytecap_all_buffers_done(struct dcmipp_bytecap_device *vcap,
@@ -423,8 +615,25 @@ static int dcmipp_bytecap_start_streaming(struct vb2_queue 
*vq,
 
        spin_lock_irq(&vcap->irqlock);
 
+       if (vcap->pipe_id != 0) {
+               const struct dcmipp_bytecap_pix_map *vpix =
+                       dcmipp_bytecap_pix_map_by_pixelformat(vcap, 
vcap->format.pixelformat);
+               unsigned int ppcr = 0;
+
+               /*
+                * Configure the Pixel Packer
+                * vpix is guaranteed to be valid since pixelformat is validated
+                * in dcmipp_pixelcap_s_fmt_vid_cap function before
+                */
+               ppcr = vpix->ppcr_fmt;
+               if (vpix->swap_uv)
+                       ppcr |= DCMIPP_PxPPCR_SWAPRB;
+
+               reg_write(vcap, DCMIPP_PxPPCR(vcap->pipe_id), ppcr);
+       }
+
        /* Enable pipe at the end of programming */
-       reg_set(vcap, DCMIPP_P0FSCR, DCMIPP_P0FSCR_PIPEN);
+       reg_set(vcap, DCMIPP_PxFSCR(vcap->pipe_id), DCMIPP_PxFSCR_PIPEN);
 
        /*
         * vb2 framework guarantee that we have at least 'min_queued_buffers'
@@ -438,7 +647,7 @@ static int dcmipp_bytecap_start_streaming(struct vb2_queue 
*vq,
 
        /* Enable interruptions */
        spin_lock(&vcap->vdev.v4l2_dev->lock);
-       reg_set(vcap, DCMIPP_CMIER, DCMIPP_CMIER_P0ALL);
+       reg_set(vcap, DCMIPP_CMIER, DCMIPP_CMIER_PxALL(vcap->pipe_id));
        spin_unlock(&vcap->vdev.v4l2_dev->lock);
 
        vcap->state = DCMIPP_RUNNING;
@@ -469,7 +678,7 @@ static void dcmipp_dump_status(struct dcmipp_bytecap_device 
*vcap)
        struct device *dev = vcap->dev;
 
        dev_dbg(dev, "[DCMIPP_PRSR]  =%#10.8x\n", reg_read(vcap, DCMIPP_PRSR));
-       dev_dbg(dev, "[DCMIPP_P0SR] =%#10.8x\n", reg_read(vcap, DCMIPP_P0SR));
+       dev_dbg(dev, "[DCMIPP_P0SR] =%#10.8x\n", reg_read(vcap, 
DCMIPP_PxSR(0)));
        dev_dbg(dev, "[DCMIPP_P0DCCNTR]=%#10.8x\n",
                reg_read(vcap, DCMIPP_P0DCCNTR));
        dev_dbg(dev, "[DCMIPP_CMSR1] =%#10.8x\n", reg_read(vcap, DCMIPP_CMSR1));
@@ -496,25 +705,26 @@ static void dcmipp_bytecap_stop_streaming(struct 
vb2_queue *vq)
 
        /* Disable interruptions */
        spin_lock(&vcap->vdev.v4l2_dev->lock);
-       reg_clear(vcap, DCMIPP_CMIER, DCMIPP_CMIER_P0ALL);
+       reg_clear(vcap, DCMIPP_CMIER, DCMIPP_CMIER_PxALL(vcap->pipe_id));
        spin_unlock(&vcap->vdev.v4l2_dev->lock);
 
        /* Stop capture */
-       reg_clear(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
+       reg_clear(vcap, DCMIPP_PxFCTCR(vcap->pipe_id), DCMIPP_PxFCTCR_CPTREQ);
 
        /* Wait until CPTACT become 0 */
-       ret = readl_relaxed_poll_timeout(vcap->regs + DCMIPP_P0SR, status,
-                                        !(status & DCMIPP_P0SR_CPTACT),
+       ret = readl_relaxed_poll_timeout(vcap->regs + 
DCMIPP_PxSR(vcap->pipe_id),
+                                        status,
+                                        !(status & DCMIPP_PxSR_CPTACT),
                                         20 * USEC_PER_MSEC,
                                         1000 * USEC_PER_MSEC);
        if (ret)
                dev_warn(vcap->dev, "Timeout when stopping\n");
 
        /* Disable pipe */
-       reg_clear(vcap, DCMIPP_P0FSCR, DCMIPP_P0FSCR_PIPEN);
+       reg_clear(vcap, DCMIPP_PxFSCR(vcap->pipe_id), DCMIPP_PxFSCR_PIPEN);
 
        /* Clear any pending interrupts */
-       reg_write(vcap, DCMIPP_CMFCR, DCMIPP_CMIER_P0ALL);
+       reg_write(vcap, DCMIPP_CMFCR, DCMIPP_CMIER_PxALL(vcap->pipe_id));
 
        spin_lock_irq(&vcap->irqlock);
 
@@ -527,7 +737,8 @@ static void dcmipp_bytecap_stop_streaming(struct vb2_queue 
*vq)
 
        spin_unlock_irq(&vcap->irqlock);
 
-       dcmipp_dump_status(vcap);
+       if (vcap->pipe_id == 0)
+               dcmipp_dump_status(vcap);
 
        pm_runtime_put(vcap->dev);
 
@@ -543,7 +754,9 @@ static int dcmipp_bytecap_buf_prepare(struct vb2_buffer *vb)
        struct dcmipp_bytecap_device *vcap =  vb2_get_drv_priv(vb->vb2_queue);
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct dcmipp_buf *buf = container_of(vbuf, struct dcmipp_buf, vb);
+       struct v4l2_pix_format *format = &vcap->format;
        unsigned long size;
+       int ret;
 
        size = vcap->format.sizeimage;
 
@@ -559,6 +772,26 @@ static int dcmipp_bytecap_buf_prepare(struct vb2_buffer 
*vb)
                /* Get memory addresses */
                buf->addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
                buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+
+               ret = frame_planes(buf->addr,
+                                  buf->addrs, buf->strides, buf->sizes,
+                                  format->width, format->height,
+                                  format->pixelformat);
+               if (ret) {
+                       dev_err(vcap->dev, "%s: Unsupported pixel format 
(%x)\n",
+                               __func__, format->pixelformat);
+                       return ret;
+               }
+
+               /* Check for 16 bytes alignment required by hardware */
+               WARN_ON(buf->addrs[0] & 15);
+               if (vcap->pipe_id != 0) {
+                       WARN_ON(buf->strides[0] & 15);
+                       WARN_ON(buf->addrs[1] & 15);
+                       WARN_ON(buf->strides[1] & 15);
+                       WARN_ON(buf->addrs[2] & 15);
+               }
+
                buf->prepared = true;
 
                vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
@@ -692,7 +925,7 @@ dcmipp_bytecap_set_next_frame_or_stop(struct 
dcmipp_bytecap_device *vcap)
                 * for next frame). On-going frame capture will continue until
                 * FRAME END but no further capture will be done.
                 */
-               reg_clear(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
+               reg_clear(vcap, DCMIPP_PxFCTCR(vcap->pipe_id), 
DCMIPP_PxFCTCR_CPTREQ);
 
                dev_dbg(vcap->dev, "Capture restart is deferred to next buffer 
queueing\n");
                vcap->next = NULL;
@@ -709,7 +942,13 @@ dcmipp_bytecap_set_next_frame_or_stop(struct 
dcmipp_bytecap_device *vcap)
         * This register is shadowed and will be taken into
         * account on next VSYNC (start of next frame)
         */
-       reg_write(vcap, DCMIPP_P0PPM0AR1, vcap->next->addr);
+       reg_write(vcap, DCMIPP_PxPPM0AR1(vcap->pipe_id), vcap->next->addrs[0]);
+       if (vcap->pipe_id == 1) {
+               if (vcap->next->addrs[1])
+                       reg_write(vcap, DCMIPP_P1PPM1AR1, vcap->next->addrs[1]);
+               if (vcap->next->addrs[2])
+                       reg_write(vcap, DCMIPP_P1PPM2AR1, vcap->next->addrs[2]);
+       }
        dev_dbg(vcap->dev, "Write [%d] %p phy=%pad\n",
                vcap->next->vb.vb2_buf.index, vcap->next, &vcap->next->addr);
 }
@@ -745,29 +984,39 @@ static irqreturn_t dcmipp_bytecap_irq_thread(int irq, 
void *arg)
 {
        struct dcmipp_bytecap_device *vcap =
                        container_of(arg, struct dcmipp_bytecap_device, ved);
+       u32 cmsr2_pxframef;
+       u32 cmsr2_pxvsyncf;
+       u32 cmsr2_pxovrf;
        size_t bytesused = 0;
 
        spin_lock_irq(&vcap->irqlock);
 
+       cmsr2_pxovrf = DCMIPP_CMSR2_PxOVRF(vcap->pipe_id);
+       cmsr2_pxvsyncf = DCMIPP_CMSR2_PxVSYNCF(vcap->pipe_id);
+       cmsr2_pxframef = DCMIPP_CMSR2_PxFRAMEF(vcap->pipe_id);
+
        /*
         * If we have an overrun, a frame-end will probably not be generated,
         * in that case the active buffer will be recycled as next buffer by
         * the VSYNC handler
         */
-       if (vcap->cmsr2 & DCMIPP_CMSR2_P0OVRF) {
+       if (vcap->cmsr2 & cmsr2_pxovrf) {
                vcap->count.errors++;
                vcap->count.overrun++;
        }
 
-       if (vcap->cmsr2 & DCMIPP_CMSR2_P0FRAMEF) {
+       if (vcap->cmsr2 & cmsr2_pxframef) {
                vcap->count.frame++;
 
                /* Read captured buffer size */
-               bytesused = reg_read(vcap, DCMIPP_P0DCCNTR);
+               if (vcap->pipe_id == 0)
+                       bytesused = reg_read(vcap, DCMIPP_P0DCCNTR);
+               else
+                       bytesused = vcap->format.sizeimage;
                dcmipp_bytecap_process_frame(vcap, bytesused);
        }
 
-       if (vcap->cmsr2 & DCMIPP_CMSR2_P0VSYNCF) {
+       if (vcap->cmsr2 & cmsr2_pxvsyncf) {
                vcap->count.vsync++;
                if (vcap->state == DCMIPP_WAIT_FOR_BUFFER) {
                        vcap->count.underrun++;
@@ -799,7 +1048,7 @@ static irqreturn_t dcmipp_bytecap_irq_callback(int irq, 
void *arg)
        struct dcmipp_ent_device *ved = arg;
 
        /* Store interrupt status register */
-       vcap->cmsr2 = ved->cmsr2 & DCMIPP_CMIER_P0ALL;
+       vcap->cmsr2 = ved->cmsr2 & DCMIPP_CMIER_PxALL(vcap->pipe_id);
        if (!vcap->cmsr2)
                return IRQ_HANDLED;
        vcap->count.it++;
@@ -822,29 +1071,40 @@ static int dcmipp_bytecap_link_validate(struct 
media_link *link)
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
                .pad = link->source->index,
        };
+       u32 width_aligned;
        int ret, i;
 
        ret = v4l2_subdev_call(source_sd, pad, get_fmt, NULL, &source_fmt);
        if (ret < 0)
                return 0;
 
-       if (source_fmt.format.width != vcap->format.width ||
+       width_aligned = source_fmt.format.width;
+
+       /*
+        * On pixel pipes there can be alignment constraints.
+        * Depending on the format & pixelpacker constraints, vcap width is
+        * different from mbus width.  Compute expected vcap width based on
+        * mbus width
+        */
+       if (vcap->pipe_id != 0)
+               width_aligned = round_up(source_fmt.format.width,
+                                        1 << 
hdw_pixel_alignment(vcap->format.pixelformat));
+
+       if (width_aligned != vcap->format.width ||
            source_fmt.format.height != vcap->format.height) {
                dev_err(vcap->dev, "Wrong width or height %ux%u (%ux%u 
expected)\n",
                        vcap->format.width, vcap->format.height,
-                       source_fmt.format.width, source_fmt.format.height);
+                       width_aligned, source_fmt.format.height);
                return -EINVAL;
        }
 
-       for (i = 0; i < ARRAY_SIZE(dcmipp_bytecap_pix_map_list); i++) {
-               if (dcmipp_bytecap_pix_map_list[i].pixelformat ==
-                       vcap->format.pixelformat &&
-                   dcmipp_bytecap_pix_map_list[i].code ==
-                       source_fmt.format.code)
+       for (i = 0; i < vcap->pix_map_array_size; i++) {
+               if (vcap->pix_map[i].pixelformat == vcap->format.pixelformat &&
+                   vcap->pix_map[i].code == source_fmt.format.code)
                        break;
        }
 
-       if (i == ARRAY_SIZE(dcmipp_bytecap_pix_map_list)) {
+       if (i == vcap->pix_map_array_size) {
                dev_err(vcap->dev, "mbus code 0x%x do not match capture device 
format (0x%x)\n",
                        vcap->format.pixelformat, source_fmt.format.code);
                return -EINVAL;
@@ -857,6 +1117,18 @@ static const struct media_entity_operations 
dcmipp_bytecap_entity_ops = {
        .link_validate = dcmipp_bytecap_link_validate,
 };
 
+static int dcmipp_name_to_pipe_id(const char *name)
+{
+       if (strstr(name, "dump"))
+               return 0;
+       else if (strstr(name, "main"))
+               return 1;
+       else if (strstr(name, "aux"))
+               return 2;
+       else
+               return -EINVAL;
+}
+
 struct dcmipp_ent_device *dcmipp_bytecap_ent_init(const char *entity_name,
                                                  struct dcmipp_device *dcmipp)
 {
@@ -872,6 +1144,23 @@ struct dcmipp_ent_device *dcmipp_bytecap_ent_init(const 
char *entity_name,
        if (!vcap)
                return ERR_PTR(-ENOMEM);
 
+       /* Retrieve the pipe_id */
+       vcap->pipe_id = dcmipp_name_to_pipe_id(entity_name);
+       if (vcap->pipe_id < 0) {
+               ret = -EIO;
+               dev_err(dev, "failed to retrieve pipe_id\n");
+               goto err_free_vcap;
+       }
+
+       /* Initialize supported format table format */
+       if (vcap->pipe_id == 0) {
+               vcap->pix_map = dcmipp_bytecap_dump_pix_map_list;
+               vcap->pix_map_array_size = 
ARRAY_SIZE(dcmipp_bytecap_dump_pix_map_list);
+       } else {
+               vcap->pix_map = dcmipp_bytecap_pixel_pix_map_list;
+               vcap->pix_map_array_size = 
ARRAY_SIZE(dcmipp_bytecap_pixel_pix_map_list);
+       }
+
        /* Allocate the pads */
        vcap->ved.pads = dcmipp_pads_init(1, &pad_flag);
        if (IS_ERR(vcap->ved.pads)) {
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to