media: ti: cal: use CSI-2 frame number for seq number
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Tue, 26 Apr 2022 07:06:16 +0000 (09:06 +0200)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Tue, 30 Aug 2022 05:43:39 +0000 (07:43 +0200)
The userspace needs a way to match received metadata buffers to pixel
data buffers. The obvious way to do this is to use the CSI-2 frame
number, as both the metadata and the pixel data have the same frame
number as they come from the same frame.

However, we don't have means to convey the frame number to userspace. We
do have the 'sequence' field, which with a few tricks can be used for
this purpose.

To achieve this, track the frame number for each virtual channel and
increase the sequence for each virtual channel by frame-number -
previous-frame-number, also taking into account the eventual wrap of the
CSI-2 frame number. If the CSI-2 peripheral does not support frame
numbers, CAL increases the frame number register by one each frame.

This way we get a monotonically increasing sequence number which is
common to all streams using the same virtual channel.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/media/platform/ti/cal/cal-camerarx.c
drivers/media/platform/ti/cal/cal.c
drivers/media/platform/ti/cal/cal.h

index a5d9189ae6e3c010a94fd27b6c53b15f46e96a1d..16ae52879a79bf5d53e28e1062e1409875cb4ad7 100644 (file)
@@ -871,6 +871,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
        phy->cal = cal;
        phy->instance = instance;
 
+       spin_lock_init(&phy->vc_lock);
        mutex_init(&phy->mutex);
 
        phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
index 425b4f4b7ed7e1d40a148be6acd97af8c4e57700..afba0b72a68c209c52f637a5fa4006a86d8a04e7 100644 (file)
@@ -543,7 +543,22 @@ void cal_ctx_unprepare(struct cal_ctx *ctx)
 
 void cal_ctx_start(struct cal_ctx *ctx)
 {
-       ctx->sequence = 0;
+       struct cal_camerarx *phy = ctx->phy;
+
+       /*
+        * Reset the frame number & sequence number, but only if the
+        * virtual channel is not already in use.
+        */
+
+       spin_lock(&phy->vc_lock);
+
+       if (phy->vc_enable_count[ctx->vc]++ == 0) {
+               phy->vc_frame_number[ctx->vc] = 0;
+               phy->vc_sequence[ctx->vc] = 0;
+       }
+
+       spin_unlock(&phy->vc_lock);
+
        ctx->dma.state = CAL_DMA_RUNNING;
 
        /* Configure the CSI-2, pixel processing and write DMA contexts. */
@@ -563,8 +578,15 @@ void cal_ctx_start(struct cal_ctx *ctx)
 
 void cal_ctx_stop(struct cal_ctx *ctx)
 {
+       struct cal_camerarx *phy = ctx->phy;
        long timeout;
 
+       WARN_ON(phy->vc_enable_count[ctx->vc] == 0);
+
+       spin_lock(&phy->vc_lock);
+       phy->vc_enable_count[ctx->vc]--;
+       spin_unlock(&phy->vc_lock);
+
        /*
         * Request DMA stop and wait until it completes. If completion times
         * out, forcefully disable the DMA.
@@ -601,6 +623,34 @@ void cal_ctx_stop(struct cal_ctx *ctx)
  * ------------------------------------------------------------------
  */
 
+/*
+ * Track a sequence number for each virtual channel, which is shared by
+ * all contexts using the same virtual channel. This is done using the
+ * CSI-2 frame number as a base.
+ */
+static void cal_update_seq_number(struct cal_ctx *ctx)
+{
+       struct cal_dev *cal = ctx->cal;
+       struct cal_camerarx *phy = ctx->phy;
+       u16 prev_frame_num, frame_num;
+       u8 vc = ctx->vc;
+
+       frame_num =
+               cal_read(cal, CAL_CSI2_STATUS(phy->instance, ctx->csi2_ctx)) &
+               0xffff;
+
+       if (phy->vc_frame_number[vc] != frame_num) {
+               prev_frame_num = phy->vc_frame_number[vc];
+
+               if (prev_frame_num >= frame_num)
+                       phy->vc_sequence[vc] += 1;
+               else
+                       phy->vc_sequence[vc] += frame_num - prev_frame_num;
+
+               phy->vc_frame_number[vc] = frame_num;
+       }
+}
+
 static inline void cal_irq_wdma_start(struct cal_ctx *ctx)
 {
        spin_lock(&ctx->dma.lock);
@@ -631,6 +681,8 @@ static inline void cal_irq_wdma_start(struct cal_ctx *ctx)
        }
 
        spin_unlock(&ctx->dma.lock);
+
+       cal_update_seq_number(ctx);
 }
 
 static inline void cal_irq_wdma_end(struct cal_ctx *ctx)
@@ -657,7 +709,8 @@ static inline void cal_irq_wdma_end(struct cal_ctx *ctx)
        if (buf) {
                buf->vb.vb2_buf.timestamp = ktime_get_ns();
                buf->vb.field = ctx->v_fmt.fmt.pix.field;
-               buf->vb.sequence = ctx->sequence++;
+               buf->vb.sequence = ctx->phy->vc_sequence[ctx->vc];
+
                vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
        }
 }
index 61409ddced98b0d3c85ee67b36cd261189a2d4aa..80f2c9c73c719cba4af0440c92b3ff4622cb99f7 100644 (file)
@@ -180,6 +180,12 @@ struct cal_camerarx {
        struct media_pad        pads[CAL_CAMERARX_NUM_PADS];
        struct v4l2_mbus_framefmt       formats[CAL_CAMERARX_NUM_PADS];
 
+       /* protects the vc_* fields below */
+       spinlock_t              vc_lock;
+       u8                      vc_enable_count[4];
+       u16                     vc_frame_number[4];
+       u32                     vc_sequence[4];
+
        /*
         * Lock for camerarx ops. Protects:
         * - formats
@@ -242,7 +248,6 @@ struct cal_ctx {
        const struct cal_format_info    **active_fmt;
        unsigned int            num_active_fmt;
 
-       unsigned int            sequence;
        struct vb2_queue        vb_vidq;
        u8                      dma_ctx;
        u8                      cport;