Merge branch 'next' into for-linus
[sfrench/cifs-2.6.git] / drivers / staging / media / meson / vdec / vdec_helpers.c
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 /* 4 KiB per 64x32 block */
54 u32 amvdec_am21c_body_size(u32 width, u32 height)
55 {
56         u32 width_64 = ALIGN(width, 64) / 64;
57         u32 height_32 = ALIGN(height, 32) / 32;
58
59         return SZ_4K * width_64 * height_32;
60 }
61 EXPORT_SYMBOL_GPL(amvdec_am21c_body_size);
62
63 /* 32 bytes per 128x64 block */
64 u32 amvdec_am21c_head_size(u32 width, u32 height)
65 {
66         u32 width_128 = ALIGN(width, 128) / 128;
67         u32 height_64 = ALIGN(height, 64) / 64;
68
69         return 32 * width_128 * height_64;
70 }
71 EXPORT_SYMBOL_GPL(amvdec_am21c_head_size);
72
73 u32 amvdec_am21c_size(u32 width, u32 height)
74 {
75         return ALIGN(amvdec_am21c_body_size(width, height) +
76                      amvdec_am21c_head_size(width, height), SZ_64K);
77 }
78 EXPORT_SYMBOL_GPL(amvdec_am21c_size);
79
80 static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
81 {
82         int ret;
83
84         if (sess->canvas_num >= MAX_CANVAS) {
85                 dev_err(sess->core->dev, "Reached max number of canvas\n");
86                 return -ENOMEM;
87         }
88
89         ret = meson_canvas_alloc(sess->core->canvas, canvas_id);
90         if (ret)
91                 return ret;
92
93         sess->canvas_alloc[sess->canvas_num++] = *canvas_id;
94         return 0;
95 }
96
97 static int set_canvas_yuv420m(struct amvdec_session *sess,
98                               struct vb2_buffer *vb, u32 width,
99                               u32 height, u32 reg)
100 {
101         struct amvdec_core *core = sess->core;
102         u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */
103         dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */
104         int ret, i;
105
106         for (i = 0; i < NUM_CANVAS_YUV420; ++i) {
107                 ret = canvas_alloc(sess, &canvas_id[i]);
108                 if (ret)
109                         return ret;
110
111                 buf_paddr[i] =
112                     vb2_dma_contig_plane_dma_addr(vb, i);
113         }
114
115         /* Y plane */
116         meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
117                             width, height, MESON_CANVAS_WRAP_NONE,
118                             MESON_CANVAS_BLKMODE_LINEAR,
119                             MESON_CANVAS_ENDIAN_SWAP64);
120
121         /* U plane */
122         meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
123                             width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
124                             MESON_CANVAS_BLKMODE_LINEAR,
125                             MESON_CANVAS_ENDIAN_SWAP64);
126
127         /* V plane */
128         meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2],
129                             width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
130                             MESON_CANVAS_BLKMODE_LINEAR,
131                             MESON_CANVAS_ENDIAN_SWAP64);
132
133         amvdec_write_dos(core, reg,
134                          ((canvas_id[2]) << 16) |
135                          ((canvas_id[1]) << 8)  |
136                          (canvas_id[0]));
137
138         return 0;
139 }
140
141 static int set_canvas_nv12m(struct amvdec_session *sess,
142                             struct vb2_buffer *vb, u32 width,
143                             u32 height, u32 reg)
144 {
145         struct amvdec_core *core = sess->core;
146         u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */
147         dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */
148         int ret, i;
149
150         for (i = 0; i < NUM_CANVAS_NV12; ++i) {
151                 ret = canvas_alloc(sess, &canvas_id[i]);
152                 if (ret)
153                         return ret;
154
155                 buf_paddr[i] =
156                     vb2_dma_contig_plane_dma_addr(vb, i);
157         }
158
159         /* Y plane */
160         meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
161                             width, height, MESON_CANVAS_WRAP_NONE,
162                             MESON_CANVAS_BLKMODE_LINEAR,
163                             MESON_CANVAS_ENDIAN_SWAP64);
164
165         /* U/V plane */
166         meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
167                             width, height / 2, MESON_CANVAS_WRAP_NONE,
168                             MESON_CANVAS_BLKMODE_LINEAR,
169                             MESON_CANVAS_ENDIAN_SWAP64);
170
171         amvdec_write_dos(core, reg,
172                          ((canvas_id[1]) << 16) |
173                          ((canvas_id[1]) << 8)  |
174                          (canvas_id[0]));
175
176         return 0;
177 }
178
179 int amvdec_set_canvases(struct amvdec_session *sess,
180                         u32 reg_base[], u32 reg_num[])
181 {
182         struct v4l2_m2m_buffer *buf;
183         u32 pixfmt = sess->pixfmt_cap;
184         u32 width = ALIGN(sess->width, 32);
185         u32 height = ALIGN(sess->height, 32);
186         u32 reg_cur = reg_base[0];
187         u32 reg_num_cur = 0;
188         u32 reg_base_cur = 0;
189         int i = 0;
190         int ret;
191
192         v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
193                 if (!reg_base[reg_base_cur])
194                         return -EINVAL;
195
196                 reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4;
197
198                 switch (pixfmt) {
199                 case V4L2_PIX_FMT_NV12M:
200                         ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width,
201                                                height, reg_cur);
202                         if (ret)
203                                 return ret;
204                         break;
205                 case V4L2_PIX_FMT_YUV420M:
206                         ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width,
207                                                  height, reg_cur);
208                         if (ret)
209                                 return ret;
210                         break;
211                 default:
212                         dev_err(sess->core->dev, "Unsupported pixfmt %08X\n",
213                                 pixfmt);
214                         return -EINVAL;
215                 }
216
217                 reg_num_cur++;
218                 if (reg_num_cur >= reg_num[reg_base_cur]) {
219                         reg_base_cur++;
220                         reg_num_cur = 0;
221                 }
222
223                 sess->fw_idx_to_vb2_idx[i++] = buf->vb.vb2_buf.index;
224         }
225
226         return 0;
227 }
228 EXPORT_SYMBOL_GPL(amvdec_set_canvases);
229
230 void amvdec_add_ts(struct amvdec_session *sess, u64 ts,
231                    struct v4l2_timecode tc, u32 offset, u32 vbuf_flags)
232 {
233         struct amvdec_timestamp *new_ts;
234         unsigned long flags;
235
236         new_ts = kzalloc(sizeof(*new_ts), GFP_KERNEL);
237         new_ts->ts = ts;
238         new_ts->tc = tc;
239         new_ts->offset = offset;
240         new_ts->flags = vbuf_flags;
241
242         spin_lock_irqsave(&sess->ts_spinlock, flags);
243         list_add_tail(&new_ts->list, &sess->timestamps);
244         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
245 }
246 EXPORT_SYMBOL_GPL(amvdec_add_ts);
247
248 void amvdec_remove_ts(struct amvdec_session *sess, u64 ts)
249 {
250         struct amvdec_timestamp *tmp;
251         unsigned long flags;
252
253         spin_lock_irqsave(&sess->ts_spinlock, flags);
254         list_for_each_entry(tmp, &sess->timestamps, list) {
255                 if (tmp->ts == ts) {
256                         list_del(&tmp->list);
257                         kfree(tmp);
258                         goto unlock;
259                 }
260         }
261         dev_warn(sess->core->dev_dec,
262                  "Couldn't remove buffer with timestamp %llu from list\n", ts);
263
264 unlock:
265         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
266 }
267 EXPORT_SYMBOL_GPL(amvdec_remove_ts);
268
269 static void dst_buf_done(struct amvdec_session *sess,
270                          struct vb2_v4l2_buffer *vbuf,
271                          u32 field, u64 timestamp,
272                          struct v4l2_timecode timecode, u32 flags)
273 {
274         struct device *dev = sess->core->dev_dec;
275         u32 output_size = amvdec_get_output_size(sess);
276
277         switch (sess->pixfmt_cap) {
278         case V4L2_PIX_FMT_NV12M:
279                 vbuf->vb2_buf.planes[0].bytesused = output_size;
280                 vbuf->vb2_buf.planes[1].bytesused = output_size / 2;
281                 break;
282         case V4L2_PIX_FMT_YUV420M:
283                 vbuf->vb2_buf.planes[0].bytesused = output_size;
284                 vbuf->vb2_buf.planes[1].bytesused = output_size / 4;
285                 vbuf->vb2_buf.planes[2].bytesused = output_size / 4;
286                 break;
287         }
288
289         vbuf->vb2_buf.timestamp = timestamp;
290         vbuf->sequence = sess->sequence_cap++;
291         vbuf->flags = flags;
292         vbuf->timecode = timecode;
293
294         if (sess->should_stop &&
295             atomic_read(&sess->esparser_queued_bufs) <= 1) {
296                 const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
297
298                 dev_dbg(dev, "Signaling EOS, sequence_cap = %u\n",
299                         sess->sequence_cap - 1);
300                 v4l2_event_queue_fh(&sess->fh, &ev);
301                 vbuf->flags |= V4L2_BUF_FLAG_LAST;
302         } else if (sess->status == STATUS_NEEDS_RESUME) {
303                 /* Mark LAST for drained show frames during a source change */
304                 vbuf->flags |= V4L2_BUF_FLAG_LAST;
305                 sess->sequence_cap = 0;
306         } else if (sess->should_stop)
307                 dev_dbg(dev, "should_stop, %u bufs remain\n",
308                         atomic_read(&sess->esparser_queued_bufs));
309
310         dev_dbg(dev, "Buffer %u done, ts = %llu, flags = %08X\n",
311                 vbuf->vb2_buf.index, timestamp, flags);
312         vbuf->field = field;
313         v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
314
315         /* Buffer done probably means the vififo got freed */
316         schedule_work(&sess->esparser_queue_work);
317 }
318
319 void amvdec_dst_buf_done(struct amvdec_session *sess,
320                          struct vb2_v4l2_buffer *vbuf, u32 field)
321 {
322         struct device *dev = sess->core->dev_dec;
323         struct amvdec_timestamp *tmp;
324         struct list_head *timestamps = &sess->timestamps;
325         struct v4l2_timecode timecode;
326         u64 timestamp;
327         u32 vbuf_flags;
328         unsigned long flags;
329
330         spin_lock_irqsave(&sess->ts_spinlock, flags);
331         if (list_empty(timestamps)) {
332                 dev_err(dev, "Buffer %u done but list is empty\n",
333                         vbuf->vb2_buf.index);
334
335                 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
336                 spin_unlock_irqrestore(&sess->ts_spinlock, flags);
337                 return;
338         }
339
340         tmp = list_first_entry(timestamps, struct amvdec_timestamp, list);
341         timestamp = tmp->ts;
342         timecode = tmp->tc;
343         vbuf_flags = tmp->flags;
344         list_del(&tmp->list);
345         kfree(tmp);
346         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
347
348         dst_buf_done(sess, vbuf, field, timestamp, timecode, vbuf_flags);
349         atomic_dec(&sess->esparser_queued_bufs);
350 }
351 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done);
352
353 void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
354                                 struct vb2_v4l2_buffer *vbuf,
355                                 u32 offset, u32 field, bool allow_drop)
356 {
357         struct device *dev = sess->core->dev_dec;
358         struct amvdec_timestamp *match = NULL;
359         struct amvdec_timestamp *tmp, *n;
360         struct v4l2_timecode timecode = { 0 };
361         u64 timestamp = 0;
362         u32 vbuf_flags = 0;
363         unsigned long flags;
364
365         spin_lock_irqsave(&sess->ts_spinlock, flags);
366
367         /* Look for our vififo offset to get the corresponding timestamp. */
368         list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
369                 if (tmp->offset > offset) {
370                         /*
371                          * Delete any record that remained unused for 32 match
372                          * checks
373                          */
374                         if (tmp->used_count++ >= 32) {
375                                 list_del(&tmp->list);
376                                 kfree(tmp);
377                         }
378                         break;
379                 }
380
381                 match = tmp;
382         }
383
384         if (!match) {
385                 dev_err(dev, "Buffer %u done but can't match offset (%08X)\n",
386                         vbuf->vb2_buf.index, offset);
387         } else {
388                 timestamp = match->ts;
389                 timecode = match->tc;
390                 vbuf_flags = match->flags;
391                 list_del(&match->list);
392                 kfree(match);
393         }
394         spin_unlock_irqrestore(&sess->ts_spinlock, flags);
395
396         dst_buf_done(sess, vbuf, field, timestamp, timecode, vbuf_flags);
397         if (match)
398                 atomic_dec(&sess->esparser_queued_bufs);
399 }
400 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_offset);
401
402 void amvdec_dst_buf_done_idx(struct amvdec_session *sess,
403                              u32 buf_idx, u32 offset, u32 field)
404 {
405         struct vb2_v4l2_buffer *vbuf;
406         struct device *dev = sess->core->dev_dec;
407
408         vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx,
409                                               sess->fw_idx_to_vb2_idx[buf_idx]);
410
411         if (!vbuf) {
412                 dev_err(dev,
413                         "Buffer %u done but it doesn't exist in m2m_ctx\n",
414                         buf_idx);
415                 return;
416         }
417
418         if (offset != -1)
419                 amvdec_dst_buf_done_offset(sess, vbuf, offset, field, true);
420         else
421                 amvdec_dst_buf_done(sess, vbuf, field);
422 }
423 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx);
424
425 void amvdec_set_par_from_dar(struct amvdec_session *sess,
426                              u32 dar_num, u32 dar_den)
427 {
428         u32 div;
429
430         sess->pixelaspect.numerator = sess->height * dar_num;
431         sess->pixelaspect.denominator = sess->width * dar_den;
432         div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator);
433         sess->pixelaspect.numerator /= div;
434         sess->pixelaspect.denominator /= div;
435 }
436 EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar);
437
438 void amvdec_src_change(struct amvdec_session *sess, u32 width,
439                        u32 height, u32 dpb_size)
440 {
441         static const struct v4l2_event ev = {
442                 .type = V4L2_EVENT_SOURCE_CHANGE,
443                 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
444
445         v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, dpb_size);
446
447         /*
448          * Check if the capture queue is already configured well for our
449          * usecase. If so, keep decoding with it and do not send the event
450          */
451         if (sess->streamon_cap &&
452             sess->width == width &&
453             sess->height == height &&
454             dpb_size <= sess->num_dst_bufs) {
455                 sess->fmt_out->codec_ops->resume(sess);
456                 return;
457         }
458
459         sess->changed_format = 0;
460         sess->width = width;
461         sess->height = height;
462         sess->status = STATUS_NEEDS_RESUME;
463
464         dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n",
465                 width, height, dpb_size);
466         v4l2_event_queue_fh(&sess->fh, &ev);
467 }
468 EXPORT_SYMBOL_GPL(amvdec_src_change);
469
470 void amvdec_abort(struct amvdec_session *sess)
471 {
472         dev_info(sess->core->dev, "Aborting decoding session!\n");
473         vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q);
474         vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q);
475 }
476 EXPORT_SYMBOL_GPL(amvdec_abort);