root/drivers/staging/media/meson/vdec/vdec_helpers.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. amvdec_read_dos
  2. amvdec_write_dos
  3. amvdec_write_dos_bits
  4. amvdec_clear_dos_bits
  5. amvdec_read_parser
  6. amvdec_write_parser
  7. canvas_alloc
  8. set_canvas_yuv420m
  9. set_canvas_nv12m
  10. amvdec_set_canvases
  11. amvdec_add_ts_reorder
  12. amvdec_remove_ts
  13. dst_buf_done
  14. amvdec_dst_buf_done
  15. amvdec_dst_buf_done_offset
  16. amvdec_dst_buf_done_idx
  17. amvdec_set_par_from_dar
  18. amvdec_src_change
  19. amvdec_abort

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright (C) 2018 BayLibre, SAS
   4  * Author: Maxime Jourdan <mjourdan@baylibre.com>
   5  */
   6 
   7 #include <linux/gcd.h>
   8 #include <media/v4l2-mem2mem.h>
   9 #include <media/v4l2-event.h>
  10 #include <media/videobuf2-dma-contig.h>
  11 
  12 #include "vdec_helpers.h"
  13 
  14 #define NUM_CANVAS_NV12 2
  15 #define NUM_CANVAS_YUV420 3
  16 
  17 u32 amvdec_read_dos(struct amvdec_core *core, u32 reg)
  18 {
  19         return readl_relaxed(core->dos_base + reg);
  20 }
  21 EXPORT_SYMBOL_GPL(amvdec_read_dos);
  22 
  23 void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val)
  24 {
  25         writel_relaxed(val, core->dos_base + reg);
  26 }
  27 EXPORT_SYMBOL_GPL(amvdec_write_dos);
  28 
  29 void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
  30 {
  31         amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) | val);
  32 }
  33 EXPORT_SYMBOL_GPL(amvdec_write_dos_bits);
  34 
  35 void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
  36 {
  37         amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) & ~val);
  38 }
  39 EXPORT_SYMBOL_GPL(amvdec_clear_dos_bits);
  40 
  41 u32 amvdec_read_parser(struct amvdec_core *core, u32 reg)
  42 {
  43         return readl_relaxed(core->esparser_base + reg);
  44 }
  45 EXPORT_SYMBOL_GPL(amvdec_read_parser);
  46 
  47 void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val)
  48 {
  49         writel_relaxed(val, core->esparser_base + reg);
  50 }
  51 EXPORT_SYMBOL_GPL(amvdec_write_parser);
  52 
  53 static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
  54 {
  55         int ret;
  56 
  57         if (sess->canvas_num >= MAX_CANVAS) {
  58                 dev_err(sess->core->dev, "Reached max number of canvas\n");
  59                 return -ENOMEM;
  60         }
  61 
  62         ret = meson_canvas_alloc(sess->core->canvas, canvas_id);
  63         if (ret)
  64                 return ret;
  65 
  66         sess->canvas_alloc[sess->canvas_num++] = *canvas_id;
  67         return 0;
  68 }
  69 
  70 static int set_canvas_yuv420m(struct amvdec_session *sess,
  71                               struct vb2_buffer *vb, u32 width,
  72                               u32 height, u32 reg)
  73 {
  74         struct amvdec_core *core = sess->core;
  75         u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */
  76         dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */
  77         int ret, i;
  78 
  79         for (i = 0; i < NUM_CANVAS_YUV420; ++i) {
  80                 ret = canvas_alloc(sess, &canvas_id[i]);
  81                 if (ret)
  82                         return ret;
  83 
  84                 buf_paddr[i] =
  85                     vb2_dma_contig_plane_dma_addr(vb, i);
  86         }
  87 
  88         /* Y plane */
  89         meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
  90                             width, height, MESON_CANVAS_WRAP_NONE,
  91                             MESON_CANVAS_BLKMODE_LINEAR,
  92                             MESON_CANVAS_ENDIAN_SWAP64);
  93 
  94         /* U plane */
  95         meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
  96                             width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
  97                             MESON_CANVAS_BLKMODE_LINEAR,
  98                             MESON_CANVAS_ENDIAN_SWAP64);
  99 
 100         /* V plane */
 101         meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2],
 102                             width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
 103                             MESON_CANVAS_BLKMODE_LINEAR,
 104                             MESON_CANVAS_ENDIAN_SWAP64);
 105 
 106         amvdec_write_dos(core, reg,
 107                          ((canvas_id[2]) << 16) |
 108                          ((canvas_id[1]) << 8)  |
 109                          (canvas_id[0]));
 110 
 111         return 0;
 112 }
 113 
 114 static int set_canvas_nv12m(struct amvdec_session *sess,
 115                             struct vb2_buffer *vb, u32 width,
 116                             u32 height, u32 reg)
 117 {
 118         struct amvdec_core *core = sess->core;
 119         u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */
 120         dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */
 121         int ret, i;
 122 
 123         for (i = 0; i < NUM_CANVAS_NV12; ++i) {
 124                 ret = canvas_alloc(sess, &canvas_id[i]);
 125                 if (ret)
 126                         return ret;
 127 
 128                 buf_paddr[i] =
 129                     vb2_dma_contig_plane_dma_addr(vb, i);
 130         }
 131 
 132         /* Y plane */
 133         meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
 134                             width, height, MESON_CANVAS_WRAP_NONE,
 135                             MESON_CANVAS_BLKMODE_LINEAR,
 136                             MESON_CANVAS_ENDIAN_SWAP64);
 137 
 138         /* U/V plane */
 139         meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
 140                             width, height / 2, MESON_CANVAS_WRAP_NONE,
 141                             MESON_CANVAS_BLKMODE_LINEAR,
 142                             MESON_CANVAS_ENDIAN_SWAP64);
 143 
 144         amvdec_write_dos(core, reg,
 145                          ((canvas_id[1]) << 16) |
 146                          ((canvas_id[1]) << 8)  |
 147                          (canvas_id[0]));
 148 
 149         return 0;
 150 }
 151 
 152 int amvdec_set_canvases(struct amvdec_session *sess,
 153                         u32 reg_base[], u32 reg_num[])
 154 {
 155         struct v4l2_m2m_buffer *buf;
 156         u32 pixfmt = sess->pixfmt_cap;
 157         u32 width = ALIGN(sess->width, 64);
 158         u32 height = ALIGN(sess->height, 64);
 159         u32 reg_cur = reg_base[0];
 160         u32 reg_num_cur = 0;
 161         u32 reg_base_cur = 0;
 162         int i = 0;
 163         int ret;
 164 
 165         v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
 166                 if (!reg_base[reg_base_cur])
 167                         return -EINVAL;
 168 
 169                 reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4;
 170 
 171                 switch (pixfmt) {
 172                 case V4L2_PIX_FMT_NV12M:
 173                         ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width,
 174                                                height, reg_cur);
 175                         if (ret)
 176                                 return ret;
 177                         break;
 178                 case V4L2_PIX_FMT_YUV420M:
 179                         ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width,
 180                                                  height, reg_cur);
 181                         if (ret)
 182                                 return ret;
 183                         break;
 184                 default:
 185                         dev_err(sess->core->dev, "Unsupported pixfmt %08X\n",
 186                                 pixfmt);
 187                         return -EINVAL;
 188                 }
 189 
 190                 reg_num_cur++;
 191                 if (reg_num_cur >= reg_num[reg_base_cur]) {
 192                         reg_base_cur++;
 193                         reg_num_cur = 0;
 194                 }
 195 
 196                 sess->fw_idx_to_vb2_idx[i++] = buf->vb.vb2_buf.index;
 197         }
 198 
 199         return 0;
 200 }
 201 EXPORT_SYMBOL_GPL(amvdec_set_canvases);
 202 
 203 void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset)
 204 {
 205         struct amvdec_timestamp *new_ts, *tmp;
 206         unsigned long flags;
 207 
 208         new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL);
 209         new_ts->ts = ts;
 210         new_ts->offset = offset;
 211 
 212         spin_lock_irqsave(&sess->ts_spinlock, flags);
 213 
 214         if (list_empty(&sess->timestamps))
 215                 goto add_tail;
 216 
 217         list_for_each_entry(tmp, &sess->timestamps, list) {
 218                 if (ts <= tmp->ts) {
 219                         list_add_tail(&new_ts->list, &tmp->list);
 220                         goto unlock;
 221                 }
 222         }
 223 
 224 add_tail:
 225         list_add_tail(&new_ts->list, &sess->timestamps);
 226 unlock:
 227         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 228 }
 229 EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder);
 230 
 231 void amvdec_remove_ts(struct amvdec_session *sess, u64 ts)
 232 {
 233         struct amvdec_timestamp *tmp;
 234         unsigned long flags;
 235 
 236         spin_lock_irqsave(&sess->ts_spinlock, flags);
 237         list_for_each_entry(tmp, &sess->timestamps, list) {
 238                 if (tmp->ts == ts) {
 239                         list_del(&tmp->list);
 240                         kfree(tmp);
 241                         goto unlock;
 242                 }
 243         }
 244         dev_warn(sess->core->dev_dec,
 245                  "Couldn't remove buffer with timestamp %llu from list\n", ts);
 246 
 247 unlock:
 248         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 249 }
 250 EXPORT_SYMBOL_GPL(amvdec_remove_ts);
 251 
 252 static void dst_buf_done(struct amvdec_session *sess,
 253                          struct vb2_v4l2_buffer *vbuf,
 254                          u32 field,
 255                          u64 timestamp)
 256 {
 257         struct device *dev = sess->core->dev_dec;
 258         u32 output_size = amvdec_get_output_size(sess);
 259 
 260         switch (sess->pixfmt_cap) {
 261         case V4L2_PIX_FMT_NV12M:
 262                 vbuf->vb2_buf.planes[0].bytesused = output_size;
 263                 vbuf->vb2_buf.planes[1].bytesused = output_size / 2;
 264                 break;
 265         case V4L2_PIX_FMT_YUV420M:
 266                 vbuf->vb2_buf.planes[0].bytesused = output_size;
 267                 vbuf->vb2_buf.planes[1].bytesused = output_size / 4;
 268                 vbuf->vb2_buf.planes[2].bytesused = output_size / 4;
 269                 break;
 270         }
 271 
 272         vbuf->vb2_buf.timestamp = timestamp;
 273         vbuf->sequence = sess->sequence_cap++;
 274 
 275         if (sess->should_stop &&
 276             atomic_read(&sess->esparser_queued_bufs) <= 2) {
 277                 const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
 278 
 279                 dev_dbg(dev, "Signaling EOS\n");
 280                 v4l2_event_queue_fh(&sess->fh, &ev);
 281                 vbuf->flags |= V4L2_BUF_FLAG_LAST;
 282         } else if (sess->should_stop)
 283                 dev_dbg(dev, "should_stop, %u bufs remain\n",
 284                         atomic_read(&sess->esparser_queued_bufs));
 285 
 286         dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index);
 287         vbuf->field = field;
 288         v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
 289 
 290         /* Buffer done probably means the vififo got freed */
 291         schedule_work(&sess->esparser_queue_work);
 292 }
 293 
 294 void amvdec_dst_buf_done(struct amvdec_session *sess,
 295                          struct vb2_v4l2_buffer *vbuf, u32 field)
 296 {
 297         struct device *dev = sess->core->dev_dec;
 298         struct amvdec_timestamp *tmp;
 299         struct list_head *timestamps = &sess->timestamps;
 300         u64 timestamp;
 301         unsigned long flags;
 302 
 303         spin_lock_irqsave(&sess->ts_spinlock, flags);
 304         if (list_empty(timestamps)) {
 305                 dev_err(dev, "Buffer %u done but list is empty\n",
 306                         vbuf->vb2_buf.index);
 307 
 308                 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
 309                 spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 310                 return;
 311         }
 312 
 313         tmp = list_first_entry(timestamps, struct amvdec_timestamp, list);
 314         timestamp = tmp->ts;
 315         list_del(&tmp->list);
 316         kfree(tmp);
 317         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 318 
 319         dst_buf_done(sess, vbuf, field, timestamp);
 320         atomic_dec(&sess->esparser_queued_bufs);
 321 }
 322 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done);
 323 
 324 void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
 325                                 struct vb2_v4l2_buffer *vbuf,
 326                                 u32 offset, u32 field, bool allow_drop)
 327 {
 328         struct device *dev = sess->core->dev_dec;
 329         struct amvdec_timestamp *match = NULL;
 330         struct amvdec_timestamp *tmp, *n;
 331         u64 timestamp = 0;
 332         unsigned long flags;
 333 
 334         spin_lock_irqsave(&sess->ts_spinlock, flags);
 335 
 336         /* Look for our vififo offset to get the corresponding timestamp. */
 337         list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
 338                 s64 delta = (s64)offset - tmp->offset;
 339 
 340                 /* Offsets reported by codecs usually differ slightly,
 341                  * so we need some wiggle room.
 342                  * 4KiB being the minimum packet size, there is no risk here.
 343                  */
 344                 if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) {
 345                         match = tmp;
 346                         break;
 347                 }
 348 
 349                 if (!allow_drop)
 350                         continue;
 351 
 352                 /* Delete any timestamp entry that appears before our target
 353                  * (not all src packets/timestamps lead to a frame)
 354                  */
 355                 if (delta > 0 || delta < -1 * (s32)sess->vififo_size) {
 356                         atomic_dec(&sess->esparser_queued_bufs);
 357                         list_del(&tmp->list);
 358                         kfree(tmp);
 359                 }
 360         }
 361 
 362         if (!match) {
 363                 dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n",
 364                         vbuf->vb2_buf.index, offset);
 365         } else {
 366                 timestamp = match->ts;
 367                 list_del(&match->list);
 368                 kfree(match);
 369         }
 370         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 371 
 372         dst_buf_done(sess, vbuf, field, timestamp);
 373         if (match)
 374                 atomic_dec(&sess->esparser_queued_bufs);
 375 }
 376 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_offset);
 377 
 378 void amvdec_dst_buf_done_idx(struct amvdec_session *sess,
 379                              u32 buf_idx, u32 offset, u32 field)
 380 {
 381         struct vb2_v4l2_buffer *vbuf;
 382         struct device *dev = sess->core->dev_dec;
 383 
 384         vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx,
 385                                               sess->fw_idx_to_vb2_idx[buf_idx]);
 386 
 387         if (!vbuf) {
 388                 dev_err(dev,
 389                         "Buffer %u done but it doesn't exist in m2m_ctx\n",
 390                         buf_idx);
 391                 return;
 392         }
 393 
 394         if (offset != -1)
 395                 amvdec_dst_buf_done_offset(sess, vbuf, offset, field, true);
 396         else
 397                 amvdec_dst_buf_done(sess, vbuf, field);
 398 }
 399 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx);
 400 
 401 void amvdec_set_par_from_dar(struct amvdec_session *sess,
 402                              u32 dar_num, u32 dar_den)
 403 {
 404         u32 div;
 405 
 406         sess->pixelaspect.numerator = sess->height * dar_num;
 407         sess->pixelaspect.denominator = sess->width * dar_den;
 408         div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator);
 409         sess->pixelaspect.numerator /= div;
 410         sess->pixelaspect.denominator /= div;
 411 }
 412 EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar);
 413 
 414 void amvdec_src_change(struct amvdec_session *sess, u32 width,
 415                        u32 height, u32 dpb_size)
 416 {
 417         static const struct v4l2_event ev = {
 418                 .type = V4L2_EVENT_SOURCE_CHANGE,
 419                 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
 420 
 421         v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, dpb_size);
 422 
 423         /* Check if the capture queue is already configured well for our
 424          * usecase. If so, keep decoding with it and do not send the event
 425          */
 426         if (sess->width == width &&
 427             sess->height == height &&
 428             dpb_size <= sess->num_dst_bufs) {
 429                 sess->fmt_out->codec_ops->resume(sess);
 430                 return;
 431         }
 432 
 433         sess->width = width;
 434         sess->height = height;
 435         sess->status = STATUS_NEEDS_RESUME;
 436 
 437         dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n",
 438                 width, height, dpb_size);
 439         v4l2_event_queue_fh(&sess->fh, &ev);
 440 }
 441 EXPORT_SYMBOL_GPL(amvdec_src_change);
 442 
 443 void amvdec_abort(struct amvdec_session *sess)
 444 {
 445         dev_info(sess->core->dev, "Aborting decoding session!\n");
 446         vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q);
 447         vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q);
 448 }
 449 EXPORT_SYMBOL_GPL(amvdec_abort);

/* [<][>][^][v][top][bottom][index][help] */