FILE
vdec.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/media/meson/vdec/vdec.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/of.h> 8#include <linux/clk.h> 9#include <linux/io.h> 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <linux/mfd/syscon.h> 13#include <linux/slab.h> 14#include <linux/interrupt.h> 15#include <linux/kthread.h> 16#include <media/v4l2-ioctl.h> 17#include <media/v4l2-event.h> 18#include <media/v4l2-ctrls.h> 19#include <media/v4l2-mem2mem.h> 20#include <media/v4l2-dev.h> 21#include <media/videobuf2-dma-contig.h> 22 23#include "vdec.h" 24#include "esparser.h" 25#include "vdec_helpers.h" 26 27struct dummy_buf { 28 struct vb2_v4l2_buffer vb; 29 struct list_head list; 30}; 31 32/* 16 MiB for parsed bitstream swap exchange */ 33#define SIZE_VIFIFO SZ_16M 34 35static u32 get_output_size(u32 width, u32 height) 36{ 37 return ALIGN(width * height, SZ_64K); 38} 39 40u32 amvdec_get_output_size(struct amvdec_session *sess) 41{ 42 return get_output_size(sess->width, sess->height); 43} 44EXPORT_SYMBOL_GPL(amvdec_get_output_size); 45 46static int vdec_codec_needs_recycle(struct amvdec_session *sess) 47{ 48 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 49 50 return codec_ops->can_recycle && codec_ops->recycle; 51} 52 53static int vdec_recycle_thread(void *data) 54{ 55 struct amvdec_session *sess = data; 56 struct amvdec_core *core = sess->core; 57 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 58 struct amvdec_buffer *tmp, *n; 59 60 while (!kthread_should_stop()) { 61 mutex_lock(&sess->bufs_recycle_lock); 62 list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { 63 if (!codec_ops->can_recycle(core)) 64 break; 65 66 codec_ops->recycle(core, tmp->vb->index); 67 list_del(&tmp->list); 68 kfree(tmp); 69 } 70 mutex_unlock(&sess->bufs_recycle_lock); 71 72 usleep_range(5000, 10000); 73 } 74 75 return 0; 76} 77 78static int vdec_poweron(struct amvdec_session *sess) 79{ 80 int ret; 81 struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; 82 83 ret = clk_prepare_enable(sess->core->dos_parser_clk); 84 if (ret) 85 return ret; 86 87 ret = clk_prepare_enable(sess->core->dos_clk); 88 if (ret) 89 goto disable_dos_parser; 90 91 ret = vdec_ops->start(sess); 92 if (ret) 93 goto disable_dos; 94 95 esparser_power_up(sess); 96 97 return 0; 98 99disable_dos: 100 clk_disable_unprepare(sess->core->dos_clk); 101disable_dos_parser: 102 clk_disable_unprepare(sess->core->dos_parser_clk); 103 104 return ret; 105} 106 107static void vdec_wait_inactive(struct amvdec_session *sess) 108{ 109 /* We consider 50ms with no IRQ to be inactive. */ 110 while (time_is_after_jiffies64(sess->last_irq_jiffies + 111 msecs_to_jiffies(50))) 112 msleep(25); 113} 114 115static void vdec_poweroff(struct amvdec_session *sess) 116{ 117 struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; 118 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 119 120 sess->should_stop = 1; 121 vdec_wait_inactive(sess); 122 if (codec_ops->drain) 123 codec_ops->drain(sess); 124 125 vdec_ops->stop(sess); 126 clk_disable_unprepare(sess->core->dos_clk); 127 clk_disable_unprepare(sess->core->dos_parser_clk); 128} 129 130static void 131vdec_queue_recycle(struct amvdec_session *sess, struct vb2_buffer *vb) 132{ 133 struct amvdec_buffer *new_buf; 134 135 new_buf = kmalloc(sizeof(*new_buf), GFP_KERNEL); 136 if (!new_buf) 137 return; 138 new_buf->vb = vb; 139 140 mutex_lock(&sess->bufs_recycle_lock); 141 list_add_tail(&new_buf->list, &sess->bufs_recycle); 142 mutex_unlock(&sess->bufs_recycle_lock); 143} 144 145static void vdec_m2m_device_run(void *priv) 146{ 147 struct amvdec_session *sess = priv; 148 149 schedule_work(&sess->esparser_queue_work); 150} 151 152static void vdec_m2m_job_abort(void *priv) 153{ 154 struct amvdec_session *sess = priv; 155 156 v4l2_m2m_job_finish(sess->m2m_dev, sess->m2m_ctx); 157} 158 159static const struct v4l2_m2m_ops vdec_m2m_ops = { 160 .device_run = vdec_m2m_device_run, 161 .job_abort = vdec_m2m_job_abort, 162}; 163 164static void process_num_buffers(struct vb2_queue *q, 165 struct amvdec_session *sess, 166 unsigned int *num_buffers, 167 bool is_reqbufs) 168{ 169 const struct amvdec_format *fmt_out = sess->fmt_out; 170 unsigned int q_num_bufs = vb2_get_num_buffers(q); 171 unsigned int buffers_total = q_num_bufs + *num_buffers; 172 u32 min_buf_capture = v4l2_ctrl_g_ctrl(sess->ctrl_min_buf_capture); 173 174 if (q_num_bufs + *num_buffers < min_buf_capture) 175 *num_buffers = min_buf_capture - q_num_bufs; 176 if (is_reqbufs && buffers_total < fmt_out->min_buffers) 177 *num_buffers = fmt_out->min_buffers - q_num_bufs; 178 if (buffers_total > fmt_out->max_buffers) 179 *num_buffers = fmt_out->max_buffers - q_num_bufs; 180 181 /* We need to program the complete CAPTURE buffer list 182 * in registers during start_streaming, and the firmwares 183 * are free to choose any of them to write frames to. As such, 184 * we need all of them to be queued into the driver 185 */ 186 sess->num_dst_bufs = q_num_bufs + *num_buffers; 187 q->min_queued_buffers = max(fmt_out->min_buffers, sess->num_dst_bufs); 188} 189 190static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, 191 unsigned int *num_planes, unsigned int sizes[], 192 struct device *alloc_devs[]) 193{ 194 struct amvdec_session *sess = vb2_get_drv_priv(q); 195 u32 output_size = amvdec_get_output_size(sess); 196 197 if (*num_planes) { 198 switch (q->type) { 199 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 200 if (*num_planes != 1 || 201 sizes[0] < sess->src_buffer_size) 202 return -EINVAL; 203 break; 204 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 205 switch (sess->pixfmt_cap) { 206 case V4L2_PIX_FMT_NV12M: 207 if (*num_planes != 2 || 208 sizes[0] < output_size || 209 sizes[1] < output_size / 2) 210 return -EINVAL; 211 break; 212 case V4L2_PIX_FMT_YUV420M: 213 if (*num_planes != 3 || 214 sizes[0] < output_size || 215 sizes[1] < output_size / 4 || 216 sizes[2] < output_size / 4) 217 return -EINVAL; 218 break; 219 default: 220 return -EINVAL; 221 } 222 223 process_num_buffers(q, sess, num_buffers, false); 224 break; 225 } 226 227 return 0; 228 } 229 230 switch (q->type) { 231 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 232 sizes[0] = sess->src_buffer_size; 233 *num_planes = 1; 234 break; 235 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 236 switch (sess->pixfmt_cap) { 237 case V4L2_PIX_FMT_NV12M: 238 sizes[0] = output_size; 239 sizes[1] = output_size / 2; 240 *num_planes = 2; 241 break; 242 case V4L2_PIX_FMT_YUV420M: 243 sizes[0] = output_size; 244 sizes[1] = output_size / 4; 245 sizes[2] = output_size / 4; 246 *num_planes = 3; 247 break; 248 default: 249 return -EINVAL; 250 } 251 252 process_num_buffers(q, sess, num_buffers, true); 253 break; 254 default: 255 return -EINVAL; 256 } 257 258 sess->changed_format = 1; 259 return 0; 260} 261 262static void vdec_vb2_buf_queue(struct vb2_buffer *vb) 263{ 264 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 265 struct amvdec_session *sess = vb2_get_drv_priv(vb->vb2_queue); 266 struct v4l2_m2m_ctx *m2m_ctx = sess->m2m_ctx; 267 268 v4l2_m2m_buf_queue(m2m_ctx, vbuf); 269 270 if (!sess->streamon_out) 271 return; 272 273 if (sess->streamon_cap && 274 vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 275 vdec_codec_needs_recycle(sess)) 276 vdec_queue_recycle(sess, vb); 277 278 schedule_work(&sess->esparser_queue_work); 279} 280 281static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) 282{ 283 struct amvdec_session *sess = vb2_get_drv_priv(q); 284 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 285 struct amvdec_core *core = sess->core; 286 struct vb2_v4l2_buffer *buf; 287 int ret; 288 289 if (core->cur_sess && core->cur_sess != sess) { 290 ret = -EBUSY; 291 goto bufs_done; 292 } 293 294 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 295 sess->streamon_out = 1; 296 else 297 sess->streamon_cap = 1; 298 299 if (!sess->streamon_out) 300 return 0; 301 302 if (sess->status == STATUS_NEEDS_RESUME && 303 q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 304 sess->changed_format) { 305 codec_ops->resume(sess); 306 sess->status = STATUS_RUNNING; 307 return 0; 308 } 309 310 if (sess->status == STATUS_RUNNING || 311 sess->status == STATUS_NEEDS_RESUME || 312 sess->status == STATUS_INIT) 313 return 0; 314 315 sess->vififo_size = SIZE_VIFIFO; 316 sess->vififo_vaddr = 317 dma_alloc_coherent(sess->core->dev, sess->vififo_size, 318 &sess->vififo_paddr, GFP_KERNEL); 319 if (!sess->vififo_vaddr) { 320 dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n"); 321 ret = -ENOMEM; 322 goto bufs_done; 323 } 324 325 sess->should_stop = 0; 326 sess->keyframe_found = 0; 327 sess->last_offset = 0; 328 sess->wrap_count = 0; 329 sess->pixelaspect.numerator = 1; 330 sess->pixelaspect.denominator = 1; 331 atomic_set(&sess->esparser_queued_bufs, 0); 332 v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, 1); 333 334 ret = vdec_poweron(sess); 335 if (ret) 336 goto vififo_free; 337 338 sess->sequence_cap = 0; 339 sess->sequence_out = 0; 340 if (vdec_codec_needs_recycle(sess)) 341 sess->recycle_thread = kthread_run(vdec_recycle_thread, sess, 342 "vdec_recycle"); 343 344 sess->status = STATUS_INIT; 345 core->cur_sess = sess; 346 schedule_work(&sess->esparser_queue_work); 347 return 0; 348 349vififo_free: 350 dma_free_coherent(sess->core->dev, sess->vififo_size, 351 sess->vififo_vaddr, sess->vififo_paddr); 352bufs_done: 353 while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) 354 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); 355 while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) 356 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); 357 358 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 359 sess->streamon_out = 0; 360 else 361 sess->streamon_cap = 0; 362 363 return ret; 364} 365 366static void vdec_free_canvas(struct amvdec_session *sess) 367{ 368 int i; 369 370 for (i = 0; i < sess->canvas_num; ++i) 371 meson_canvas_free(sess->core->canvas, sess->canvas_alloc[i]); 372 373 sess->canvas_num = 0; 374} 375 376static void vdec_reset_timestamps(struct amvdec_session *sess) 377{ 378 struct amvdec_timestamp *tmp, *n; 379 380 list_for_each_entry_safe(tmp, n, &sess->timestamps, list) { 381 list_del(&tmp->list); 382 kfree(tmp); 383 } 384} 385 386static void vdec_reset_bufs_recycle(struct amvdec_session *sess) 387{ 388 struct amvdec_buffer *tmp, *n; 389 390 list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { 391 list_del(&tmp->list); 392 kfree(tmp); 393 } 394} 395 396static void vdec_stop_streaming(struct vb2_queue *q) 397{ 398 struct amvdec_session *sess = vb2_get_drv_priv(q); 399 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 400 struct amvdec_core *core = sess->core; 401 struct vb2_v4l2_buffer *buf; 402 403 if (sess->status == STATUS_RUNNING || 404 sess->status == STATUS_INIT || 405 (sess->status == STATUS_NEEDS_RESUME && 406 (!sess->streamon_out || !sess->streamon_cap))) { 407 if (vdec_codec_needs_recycle(sess)) 408 kthread_stop(sess->recycle_thread); 409 410 vdec_poweroff(sess); 411 vdec_free_canvas(sess); 412 dma_free_coherent(sess->core->dev, sess->vififo_size, 413 sess->vififo_vaddr, sess->vififo_paddr); 414 vdec_reset_timestamps(sess); 415 vdec_reset_bufs_recycle(sess); 416 kfree(sess->priv); 417 sess->priv = NULL; 418 core->cur_sess = NULL; 419 sess->status = STATUS_STOPPED; 420 } 421 422 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 423 while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) 424 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); 425 426 sess->streamon_out = 0; 427 } else { 428 /* Drain remaining refs if was still running */ 429 if (sess->status >= STATUS_RUNNING && codec_ops->drain) 430 codec_ops->drain(sess); 431 432 while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) 433 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); 434 435 sess->streamon_cap = 0; 436 } 437} 438 439static int vdec_vb2_buf_prepare(struct vb2_buffer *vb) 440{ 441 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 442 443 vbuf->field = V4L2_FIELD_NONE; 444 return 0; 445} 446 447static const struct vb2_ops vdec_vb2_ops = { 448 .queue_setup = vdec_queue_setup, 449 .start_streaming = vdec_start_streaming, 450 .stop_streaming = vdec_stop_streaming, 451 .buf_queue = vdec_vb2_buf_queue, 452 .buf_prepare = vdec_vb2_buf_prepare, 453}; 454 455static int 456vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) 457{ 458 strscpy(cap->driver, "meson-vdec", sizeof(cap->driver)); 459 strscpy(cap->card, "Amlogic Video Decoder", sizeof(cap->card)); 460 strscpy(cap->bus_info, "platform:meson-vdec", sizeof(cap->bus_info)); 461 462 return 0; 463} 464 465static const struct amvdec_format * 466find_format(const struct amvdec_format *fmts, u32 size, u32 pixfmt) 467{ 468 unsigned int i; 469 470 for (i = 0; i < size; i++) { 471 if (fmts[i].pixfmt == pixfmt) 472 return &fmts[i]; 473 } 474 475 return NULL; 476} 477 478static unsigned int 479vdec_supports_pixfmt_cap(const struct amvdec_format *fmt_out, u32 pixfmt_cap) 480{ 481 int i; 482 483 for (i = 0; fmt_out->pixfmts_cap[i]; i++) 484 if (fmt_out->pixfmts_cap[i] == pixfmt_cap) 485 return 1; 486 487 return 0; 488} 489 490static const struct amvdec_format * 491vdec_try_fmt_common(struct amvdec_session *sess, u32 size, 492 struct v4l2_format *f) 493{ 494 struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 495 struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; 496 const struct amvdec_format *fmts = sess->core->platform->formats; 497 const struct amvdec_format *fmt_out = NULL; 498 u32 output_size = 0; 499 500 memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); 501 memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); 502 503 switch (f->type) { 504 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 505 fmt_out = find_format(fmts, size, pixmp->pixelformat); 506 if (!fmt_out) { 507 pixmp->pixelformat = V4L2_PIX_FMT_MPEG2; 508 fmt_out = find_format(fmts, size, pixmp->pixelformat); 509 } 510 break; 511 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 512 fmt_out = sess->fmt_out; 513 break; 514 default: 515 return NULL; 516 } 517 518 pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width); 519 pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height); 520 output_size = get_output_size(pixmp->width, pixmp->height); 521 522 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 523 if (!pfmt[0].sizeimage) 524 pfmt[0].sizeimage = sess->src_buffer_size; 525 pfmt[0].bytesperline = 0; 526 pixmp->num_planes = 1; 527 } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 528 fmt_out = sess->fmt_out; 529 if (!vdec_supports_pixfmt_cap(fmt_out, pixmp->pixelformat)) 530 pixmp->pixelformat = fmt_out->pixfmts_cap[0]; 531 532 memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved)); 533 if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) { 534 pfmt[0].sizeimage = output_size; 535 pfmt[0].bytesperline = ALIGN(pixmp->width, 32); 536 537 pfmt[1].sizeimage = output_size / 2; 538 pfmt[1].bytesperline = ALIGN(pixmp->width, 32); 539 pixmp->num_planes = 2; 540 } else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) { 541 pfmt[0].sizeimage = output_size; 542 pfmt[0].bytesperline = ALIGN(pixmp->width, 32); 543 544 pfmt[1].sizeimage = output_size / 4; 545 pfmt[1].bytesperline = ALIGN(pixmp->width, 32) / 2; 546 547 pfmt[2].sizeimage = output_size / 2; 548 pfmt[2].bytesperline = ALIGN(pixmp->width, 32) / 2; 549 pixmp->num_planes = 3; 550 } 551 } 552 553 if (pixmp->field == V4L2_FIELD_ANY) 554 pixmp->field = V4L2_FIELD_NONE; 555 556 return fmt_out; 557} 558 559static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) 560{ 561 struct amvdec_session *sess = file_to_amvdec_session(file); 562 563 vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); 564 565 return 0; 566} 567 568static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) 569{ 570 struct amvdec_session *sess = file_to_amvdec_session(file); 571 struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 572 573 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 574 pixmp->pixelformat = sess->pixfmt_cap; 575 else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 576 pixmp->pixelformat = sess->fmt_out->pixfmt; 577 578 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 579 pixmp->width = sess->width; 580 pixmp->height = sess->height; 581 pixmp->colorspace = sess->colorspace; 582 pixmp->ycbcr_enc = sess->ycbcr_enc; 583 pixmp->quantization = sess->quantization; 584 pixmp->xfer_func = sess->xfer_func; 585 } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 586 pixmp->width = sess->width; 587 pixmp->height = sess->height; 588 } 589 590 vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); 591 592 return 0; 593} 594 595static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) 596{ 597 struct amvdec_session *sess = file_to_amvdec_session(file); 598 struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 599 u32 num_formats = sess->core->platform->num_formats; 600 const struct amvdec_format *fmt_out; 601 struct v4l2_pix_format_mplane orig_pixmp; 602 struct v4l2_format format; 603 u32 pixfmt_out = 0, pixfmt_cap = 0; 604 605 orig_pixmp = *pixmp; 606 607 fmt_out = vdec_try_fmt_common(sess, num_formats, f); 608 if (!fmt_out) 609 return -EINVAL; 610 611 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 612 pixfmt_out = pixmp->pixelformat; 613 pixfmt_cap = sess->pixfmt_cap; 614 } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 615 pixfmt_cap = pixmp->pixelformat; 616 pixfmt_out = sess->fmt_out->pixfmt; 617 } 618 619 memset(&format, 0, sizeof(format)); 620 621 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 622 format.fmt.pix_mp.pixelformat = pixfmt_out; 623 format.fmt.pix_mp.width = orig_pixmp.width; 624 format.fmt.pix_mp.height = orig_pixmp.height; 625 vdec_try_fmt_common(sess, num_formats, &format); 626 627 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 628 sess->width = format.fmt.pix_mp.width; 629 sess->height = format.fmt.pix_mp.height; 630 sess->colorspace = pixmp->colorspace; 631 sess->ycbcr_enc = pixmp->ycbcr_enc; 632 sess->quantization = pixmp->quantization; 633 sess->xfer_func = pixmp->xfer_func; 634 sess->src_buffer_size = pixmp->plane_fmt[0].sizeimage; 635 } 636 637 memset(&format, 0, sizeof(format)); 638 639 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 640 format.fmt.pix_mp.pixelformat = pixfmt_cap; 641 format.fmt.pix_mp.width = orig_pixmp.width; 642 format.fmt.pix_mp.height = orig_pixmp.height; 643 vdec_try_fmt_common(sess, num_formats, &format); 644 645 sess->width = format.fmt.pix_mp.width; 646 sess->height = format.fmt.pix_mp.height; 647 648 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 649 sess->fmt_out = fmt_out; 650 else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 651 sess->pixfmt_cap = format.fmt.pix_mp.pixelformat; 652 653 return 0; 654} 655 656static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) 657{ 658 struct amvdec_session *sess = file_to_amvdec_session(file); 659 const struct vdec_platform *platform = sess->core->platform; 660 const struct amvdec_format *fmt_out; 661 662 memset(f->reserved, 0, sizeof(f->reserved)); 663 664 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 665 if (f->index >= platform->num_formats) 666 return -EINVAL; 667 668 fmt_out = &platform->formats[f->index]; 669 f->pixelformat = fmt_out->pixfmt; 670 f->flags = fmt_out->flags; 671 } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 672 fmt_out = sess->fmt_out; 673 if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index]) 674 return -EINVAL; 675 676 f->pixelformat = fmt_out->pixfmts_cap[f->index]; 677 } else { 678 return -EINVAL; 679 } 680 681 return 0; 682} 683 684static int vdec_enum_framesizes(struct file *file, void *fh, 685 struct v4l2_frmsizeenum *fsize) 686{ 687 struct amvdec_session *sess = file_to_amvdec_session(file); 688 const struct amvdec_format *formats = sess->core->platform->formats; 689 const struct amvdec_format *fmt; 690 u32 num_formats = sess->core->platform->num_formats; 691 692 fmt = find_format(formats, num_formats, fsize->pixel_format); 693 if (!fmt || fsize->index) 694 return -EINVAL; 695 696 fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; 697 698 fsize->stepwise.min_width = 256; 699 fsize->stepwise.max_width = fmt->max_width; 700 fsize->stepwise.step_width = 1; 701 fsize->stepwise.min_height = 144; 702 fsize->stepwise.max_height = fmt->max_height; 703 fsize->stepwise.step_height = 1; 704 705 return 0; 706} 707 708static int 709vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) 710{ 711 struct amvdec_session *sess = file_to_amvdec_session(file); 712 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 713 struct device *dev = sess->core->dev; 714 int ret; 715 716 ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); 717 if (ret) 718 return ret; 719 720 if (!(sess->streamon_out & sess->streamon_cap)) 721 return 0; 722 723 if (cmd->cmd == V4L2_DEC_CMD_START) { 724 v4l2_m2m_clear_state(sess->m2m_ctx); 725 sess->should_stop = 0; 726 return 0; 727 } 728 729 /* Should not happen */ 730 if (cmd->cmd != V4L2_DEC_CMD_STOP) 731 return -EINVAL; 732 733 dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n"); 734 735 sess->should_stop = 1; 736 737 v4l2_m2m_mark_stopped(sess->m2m_ctx); 738 739 if (codec_ops->drain) { 740 vdec_wait_inactive(sess); 741 codec_ops->drain(sess); 742 } else if (codec_ops->eos_sequence) { 743 u32 len; 744 const u8 *data = codec_ops->eos_sequence(&len); 745 746 esparser_queue_eos(sess->core, data, len); 747 vdec_wait_inactive(sess); 748 } 749 750 return ret; 751} 752 753static int vdec_subscribe_event(struct v4l2_fh *fh, 754 const struct v4l2_event_subscription *sub) 755{ 756 switch (sub->type) { 757 case V4L2_EVENT_EOS: 758 case V4L2_EVENT_SOURCE_CHANGE: 759 return v4l2_event_subscribe(fh, sub, 0, NULL); 760 case V4L2_EVENT_CTRL: 761 return v4l2_ctrl_subscribe_event(fh, sub); 762 default: 763 return -EINVAL; 764 } 765} 766 767static int vdec_g_pixelaspect(struct file *file, void *fh, int type, 768 struct v4l2_fract *f) 769{ 770 struct amvdec_session *sess = file_to_amvdec_session(file); 771 772 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 773 return -EINVAL; 774 775 *f = sess->pixelaspect; 776 return 0; 777} 778 779static const struct v4l2_ioctl_ops vdec_ioctl_ops = { 780 .vidioc_querycap = vdec_querycap, 781 .vidioc_enum_fmt_vid_cap = vdec_enum_fmt, 782 .vidioc_enum_fmt_vid_out = vdec_enum_fmt, 783 .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt, 784 .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt, 785 .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, 786 .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt, 787 .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt, 788 .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt, 789 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 790 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 791 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 792 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 793 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 794 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 795 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 796 .vidioc_streamon = v4l2_m2m_ioctl_streamon, 797 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 798 .vidioc_enum_framesizes = vdec_enum_framesizes, 799 .vidioc_subscribe_event = vdec_subscribe_event, 800 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 801 .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, 802 .vidioc_decoder_cmd = vdec_decoder_cmd, 803 .vidioc_g_pixelaspect = vdec_g_pixelaspect, 804}; 805 806static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, 807 struct vb2_queue *dst_vq) 808{ 809 struct amvdec_session *sess = priv; 810 int ret; 811 812 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 813 src_vq->io_modes = VB2_MMAP | VB2_DMABUF; 814 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 815 src_vq->ops = &vdec_vb2_ops; 816 src_vq->mem_ops = &vb2_dma_contig_memops; 817 src_vq->drv_priv = sess; 818 src_vq->buf_struct_size = sizeof(struct dummy_buf); 819 src_vq->min_queued_buffers = 1; 820 src_vq->dev = sess->core->dev; 821 src_vq->lock = &sess->lock; 822 ret = vb2_queue_init(src_vq); 823 if (ret) 824 return ret; 825 826 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 827 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; 828 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 829 dst_vq->ops = &vdec_vb2_ops; 830 dst_vq->mem_ops = &vb2_dma_contig_memops; 831 dst_vq->drv_priv = sess; 832 dst_vq->buf_struct_size = sizeof(struct dummy_buf); 833 dst_vq->min_queued_buffers = 1; 834 dst_vq->dev = sess->core->dev; 835 dst_vq->lock = &sess->lock; 836 return vb2_queue_init(dst_vq); 837} 838 839static int vdec_init_ctrls(struct amvdec_session *sess) 840{ 841 struct v4l2_ctrl_handler *ctrl_handler = &sess->ctrl_handler; 842 int ret; 843 844 ret = v4l2_ctrl_handler_init(ctrl_handler, 1); 845 if (ret) 846 return ret; 847 848 sess->ctrl_min_buf_capture = 849 v4l2_ctrl_new_std(ctrl_handler, NULL, 850 V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 851 1); 852 853 ret = ctrl_handler->error; 854 if (ret) { 855 v4l2_ctrl_handler_free(ctrl_handler); 856 return ret; 857 } 858 859 return 0; 860} 861 862static int vdec_open(struct file *file) 863{ 864 struct amvdec_core *core = video_drvdata(file); 865 struct device *dev = core->dev; 866 const struct amvdec_format *formats = core->platform->formats; 867 struct amvdec_session *sess; 868 int ret; 869 870 sess = kzalloc(sizeof(*sess), GFP_KERNEL); 871 if (!sess) 872 return -ENOMEM; 873 874 sess->core = core; 875 876 sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops); 877 if (IS_ERR(sess->m2m_dev)) { 878 dev_err(dev, "Fail to v4l2_m2m_init\n"); 879 ret = PTR_ERR(sess->m2m_dev); 880 goto err_free_sess; 881 } 882 883 sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init); 884 if (IS_ERR(sess->m2m_ctx)) { 885 dev_err(dev, "Fail to v4l2_m2m_ctx_init\n"); 886 ret = PTR_ERR(sess->m2m_ctx); 887 goto err_m2m_release; 888 } 889 890 ret = vdec_init_ctrls(sess); 891 if (ret) 892 goto err_m2m_release; 893 894 sess->pixfmt_cap = formats[0].pixfmts_cap[0]; 895 sess->fmt_out = &formats[0]; 896 sess->width = 1280; 897 sess->height = 720; 898 sess->pixelaspect.numerator = 1; 899 sess->pixelaspect.denominator = 1; 900 sess->src_buffer_size = SZ_1M; 901 902 INIT_LIST_HEAD(&sess->timestamps); 903 INIT_LIST_HEAD(&sess->bufs_recycle); 904 INIT_WORK(&sess->esparser_queue_work, esparser_queue_all_src); 905 mutex_init(&sess->lock); 906 mutex_init(&sess->bufs_recycle_lock); 907 spin_lock_init(&sess->ts_spinlock); 908 909 v4l2_fh_init(&sess->fh, core->vdev_dec); 910 sess->fh.ctrl_handler = &sess->ctrl_handler; 911 v4l2_fh_add(&sess->fh, file); 912 sess->fh.m2m_ctx = sess->m2m_ctx; 913 914 return 0; 915 916err_m2m_release: 917 v4l2_m2m_release(sess->m2m_dev); 918err_free_sess: 919 kfree(sess); 920 return ret; 921} 922 923static int vdec_close(struct file *file) 924{ 925 struct amvdec_session *sess = file_to_amvdec_session(file); 926 927 v4l2_m2m_ctx_release(sess->m2m_ctx); 928 v4l2_m2m_release(sess->m2m_dev); 929 v4l2_fh_del(&sess->fh, file); 930 v4l2_fh_exit(&sess->fh); 931 932 mutex_destroy(&sess->lock); 933 mutex_destroy(&sess->bufs_recycle_lock); 934 935 kfree(sess); 936 937 return 0; 938} 939 940static const struct v4l2_file_operations vdec_fops = { 941 .owner = THIS_MODULE, 942 .open = vdec_open, 943 .release = vdec_close, 944 .unlocked_ioctl = video_ioctl2, 945 .poll = v4l2_m2m_fop_poll, 946 .mmap = v4l2_m2m_fop_mmap, 947}; 948 949static irqreturn_t vdec_isr(int irq, void *data) 950{ 951 struct amvdec_core *core = data; 952 struct amvdec_session *sess = core->cur_sess; 953 954 sess->last_irq_jiffies = get_jiffies_64(); 955 956 return sess->fmt_out->codec_ops->isr(sess); 957} 958 959static irqreturn_t vdec_threaded_isr(int irq, void *data) 960{ 961 struct amvdec_core *core = data; 962 struct amvdec_session *sess = core->cur_sess; 963 964 return sess->fmt_out->codec_ops->threaded_isr(sess); 965} 966 967static const struct of_device_id vdec_dt_match[] = { 968 { .compatible = "amlogic,gxbb-vdec", 969 .data = &vdec_platform_gxbb }, 970 { .compatible = "amlogic,gxm-vdec", 971 .data = &vdec_platform_gxm }, 972 { .compatible = "amlogic,gxl-vdec", 973 .data = &vdec_platform_gxl }, 974 { .compatible = "amlogic,gxlx-vdec", 975 .data = &vdec_platform_gxlx }, 976 { .compatible = "amlogic,g12a-vdec", 977 .data = &vdec_platform_g12a }, 978 { .compatible = "amlogic,sm1-vdec", 979 .data = &vdec_platform_sm1 }, 980 {} 981}; 982MODULE_DEVICE_TABLE(of, vdec_dt_match); 983 984static int vdec_probe(struct platform_device *pdev) 985{ 986 struct device *dev = &pdev->dev; 987 struct video_device *vdev; 988 struct amvdec_core *core; 989 const struct of_device_id *of_id; 990 int irq; 991 int ret; 992 993 core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); 994 if (!core) 995 return -ENOMEM; 996 997 core->dev = dev; 998 platform_set_drvdata(pdev, core); 999 1000 core->dos_base = devm_platform_ioremap_resource_byname(pdev, "dos"); 1001 if (IS_ERR(core->dos_base)) 1002 return PTR_ERR(core->dos_base); 1003 1004 core->esparser_base = devm_platform_ioremap_resource_byname(pdev, "esparser"); 1005 if (IS_ERR(core->esparser_base)) 1006 return PTR_ERR(core->esparser_base); 1007 1008 core->regmap_ao = 1009 syscon_regmap_lookup_by_phandle(dev->of_node, 1010 "amlogic,ao-sysctrl"); 1011 if (IS_ERR(core->regmap_ao)) { 1012 dev_err(dev, "Couldn't regmap AO sysctrl\n"); 1013 return PTR_ERR(core->regmap_ao); 1014 } 1015 1016 core->canvas = meson_canvas_get(dev); 1017 if (IS_ERR(core->canvas)) 1018 return PTR_ERR(core->canvas); 1019 1020 of_id = of_match_node(vdec_dt_match, dev->of_node); 1021 core->platform = of_id->data; 1022 1023 if (core->platform->revision == VDEC_REVISION_G12A || 1024 core->platform->revision == VDEC_REVISION_SM1) { 1025 core->vdec_hevcf_clk = devm_clk_get(dev, "vdec_hevcf"); 1026 if (IS_ERR(core->vdec_hevcf_clk)) 1027 return -EPROBE_DEFER; 1028 } 1029 1030 core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); 1031 if (IS_ERR(core->dos_parser_clk)) 1032 return -EPROBE_DEFER; 1033 1034 core->dos_clk = devm_clk_get(dev, "dos"); 1035 if (IS_ERR(core->dos_clk)) 1036 return -EPROBE_DEFER; 1037 1038 core->vdec_1_clk = devm_clk_get(dev, "vdec_1"); 1039 if (IS_ERR(core->vdec_1_clk)) 1040 return -EPROBE_DEFER; 1041 1042 core->vdec_hevc_clk = devm_clk_get(dev, "vdec_hevc"); 1043 if (IS_ERR(core->vdec_hevc_clk)) 1044 return -EPROBE_DEFER; 1045 1046 irq = platform_get_irq_byname(pdev, "vdec"); 1047 if (irq < 0) 1048 return irq; 1049 1050 ret = devm_request_threaded_irq(core->dev, irq, vdec_isr, 1051 vdec_threaded_isr, IRQF_ONESHOT, 1052 "vdec", core); 1053 if (ret) 1054 return ret; 1055 1056 ret = esparser_init(pdev, core); 1057 if (ret) 1058 return ret; 1059 1060 ret = v4l2_device_register(dev, &core->v4l2_dev); 1061 if (ret) { 1062 dev_err(dev, "Couldn't register v4l2 device\n"); 1063 return -ENOMEM; 1064 } 1065 1066 vdev = video_device_alloc(); 1067 if (!vdev) { 1068 ret = -ENOMEM; 1069 goto err_vdev_release; 1070 } 1071 1072 core->vdev_dec = vdev; 1073 core->dev_dec = dev; 1074 mutex_init(&core->lock); 1075 1076 strscpy(vdev->name, "meson-video-decoder", sizeof(vdev->name)); 1077 vdev->release = video_device_release; 1078 vdev->fops = &vdec_fops; 1079 vdev->ioctl_ops = &vdec_ioctl_ops; 1080 vdev->vfl_dir = VFL_DIR_M2M; 1081 vdev->v4l2_dev = &core->v4l2_dev; 1082 vdev->lock = &core->lock; 1083 vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; 1084 1085 video_set_drvdata(vdev, core); 1086 1087 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 1088 if (ret) { 1089 dev_err(dev, "Failed registering video device\n"); 1090 goto err_vdev_release; 1091 } 1092 1093 return 0; 1094 1095err_vdev_release: 1096 video_device_release(vdev); 1097 v4l2_device_unregister(&core->v4l2_dev); 1098 return ret; 1099} 1100 1101static void vdec_remove(struct platform_device *pdev) 1102{ 1103 struct amvdec_core *core = platform_get_drvdata(pdev); 1104 1105 video_unregister_device(core->vdev_dec); 1106 v4l2_device_unregister(&core->v4l2_dev); 1107} 1108 1109static struct platform_driver meson_vdec_driver = { 1110 .probe = vdec_probe, 1111 .remove = vdec_remove, 1112 .driver = { 1113 .name = "meson-vdec", 1114 .of_match_table = vdec_dt_match, 1115 }, 1116}; 1117module_platform_driver(meson_vdec_driver); 1118 1119MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM/G12/SM1"); 1120MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>"); 1121MODULE_LICENSE("GPL");
~/
Read-only file preview.