File Index
Files and directories
Sign in
FILE

vdec.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/meson/vdec/vdec.c 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.