18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2015
48c2ecf20Sopenharmony_ci * Authors: Hugues Fruchet <hugues.fruchet@st.com>
58c2ecf20Sopenharmony_ci *          Jean-Christophe Trotin <jean-christophe.trotin@st.com>
68c2ecf20Sopenharmony_ci *          for STMicroelectronics.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h>
168c2ecf20Sopenharmony_ci#include <media/v4l2-event.h>
178c2ecf20Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "delta.h"
208c2ecf20Sopenharmony_ci#include "delta-debug.h"
218c2ecf20Sopenharmony_ci#include "delta-ipc.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define DELTA_NAME	"st-delta"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define DELTA_PREFIX "[---:----]"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define to_ctx(__fh) container_of(__fh, struct delta_ctx, fh)
288c2ecf20Sopenharmony_ci#define to_au(__vbuf) container_of(__vbuf, struct delta_au, vbuf)
298c2ecf20Sopenharmony_ci#define to_frame(__vbuf) container_of(__vbuf, struct delta_frame, vbuf)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define call_dec_op(dec, op, args...)\
328c2ecf20Sopenharmony_ci		((dec && (dec)->op) ? (dec)->op(args) : 0)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* registry of available decoders */
358c2ecf20Sopenharmony_cistatic const struct delta_dec *delta_decoders[] = {
368c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_STI_DELTA_MJPEG
378c2ecf20Sopenharmony_ci	&mjpegdec,
388c2ecf20Sopenharmony_ci#endif
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic inline int frame_size(u32 w, u32 h, u32 fmt)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	switch (fmt) {
448c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
458c2ecf20Sopenharmony_ci		return (w * h * 3) / 2;
468c2ecf20Sopenharmony_ci	default:
478c2ecf20Sopenharmony_ci		return 0;
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic inline int frame_stride(u32 w, u32 fmt)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	switch (fmt) {
548c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
558c2ecf20Sopenharmony_ci		return w;
568c2ecf20Sopenharmony_ci	default:
578c2ecf20Sopenharmony_ci		return 0;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic void dump_au(struct delta_ctx *ctx, struct delta_au *au)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
648c2ecf20Sopenharmony_ci	u32 size = 10;	/* dump first & last 10 bytes */
658c2ecf20Sopenharmony_ci	u8 *data = (u8 *)(au->vaddr);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (au->size <= (size * 2))
688c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s dump au[%d] dts=%lld size=%d data=%*ph\n",
698c2ecf20Sopenharmony_ci			ctx->name, au->vbuf.vb2_buf.index, au->dts, au->size,
708c2ecf20Sopenharmony_ci			au->size, data);
718c2ecf20Sopenharmony_ci	else
728c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s dump au[%d] dts=%lld size=%d data=%*ph..%*ph\n",
738c2ecf20Sopenharmony_ci			ctx->name, au->vbuf.vb2_buf.index, au->dts, au->size,
748c2ecf20Sopenharmony_ci			size, data, size, data + au->size - size);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void dump_frame(struct delta_ctx *ctx, struct delta_frame *frame)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
808c2ecf20Sopenharmony_ci	u32 size = 10;	/* dump first 10 bytes */
818c2ecf20Sopenharmony_ci	u8 *data = (u8 *)(frame->vaddr);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s dump frame[%d] dts=%lld type=%s field=%s data=%*ph\n",
848c2ecf20Sopenharmony_ci		ctx->name, frame->index, frame->dts,
858c2ecf20Sopenharmony_ci		frame_type_str(frame->flags),
868c2ecf20Sopenharmony_ci		frame_field_str(frame->field),
878c2ecf20Sopenharmony_ci		size, data);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic void delta_au_done(struct delta_ctx *ctx, struct delta_au *au, int err)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	vbuf = &au->vbuf;
958c2ecf20Sopenharmony_ci	vbuf->sequence = ctx->au_num++;
968c2ecf20Sopenharmony_ci	v4l2_m2m_buf_done(vbuf, err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void delta_frame_done(struct delta_ctx *ctx, struct delta_frame *frame,
1008c2ecf20Sopenharmony_ci			     int err)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	dump_frame(ctx, frame);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* decoded frame is now output to user */
1078c2ecf20Sopenharmony_ci	frame->state |= DELTA_FRAME_OUT;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	vbuf = &frame->vbuf;
1108c2ecf20Sopenharmony_ci	vbuf->sequence = ctx->frame_num++;
1118c2ecf20Sopenharmony_ci	v4l2_m2m_buf_done(vbuf, err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (frame->info.size) /* ignore EOS */
1148c2ecf20Sopenharmony_ci		ctx->output_frames++;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void requeue_free_frames(struct delta_ctx *ctx)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
1208c2ecf20Sopenharmony_ci	struct delta_frame *frame;
1218c2ecf20Sopenharmony_ci	unsigned int i;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* requeue all free frames */
1248c2ecf20Sopenharmony_ci	for (i = 0; i < ctx->nb_of_frames; i++) {
1258c2ecf20Sopenharmony_ci		frame = ctx->frames[i];
1268c2ecf20Sopenharmony_ci		if (frame->state == DELTA_FRAME_FREE) {
1278c2ecf20Sopenharmony_ci			vbuf = &frame->vbuf;
1288c2ecf20Sopenharmony_ci			v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1298c2ecf20Sopenharmony_ci			frame->state = DELTA_FRAME_M2M;
1308c2ecf20Sopenharmony_ci		}
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int delta_recycle(struct delta_ctx *ctx, struct delta_frame *frame)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* recycle frame on decoder side */
1398c2ecf20Sopenharmony_ci	call_dec_op(dec, recycle, ctx, frame);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* this frame is no more output */
1428c2ecf20Sopenharmony_ci	frame->state &= ~DELTA_FRAME_OUT;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* requeue free frame */
1458c2ecf20Sopenharmony_ci	if (frame->state == DELTA_FRAME_FREE) {
1468c2ecf20Sopenharmony_ci		struct vb2_v4l2_buffer *vbuf = &frame->vbuf;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1498c2ecf20Sopenharmony_ci		frame->state = DELTA_FRAME_M2M;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* reset other frame fields */
1538c2ecf20Sopenharmony_ci	frame->flags = 0;
1548c2ecf20Sopenharmony_ci	frame->dts = 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return 0;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic void delta_push_dts(struct delta_ctx *ctx, u64 val)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct delta_dts *dts;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	dts = kzalloc(sizeof(*dts), GFP_KERNEL);
1648c2ecf20Sopenharmony_ci	if (!dts)
1658c2ecf20Sopenharmony_ci		return;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dts->list);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/*
1708c2ecf20Sopenharmony_ci	 * protected by global lock acquired
1718c2ecf20Sopenharmony_ci	 * by V4L2 when calling delta_vb2_au_queue
1728c2ecf20Sopenharmony_ci	 */
1738c2ecf20Sopenharmony_ci	dts->val = val;
1748c2ecf20Sopenharmony_ci	list_add_tail(&dts->list, &ctx->dts);
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic void delta_pop_dts(struct delta_ctx *ctx, u64 *val)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
1808c2ecf20Sopenharmony_ci	struct delta_dts *dts;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/*
1838c2ecf20Sopenharmony_ci	 * protected by global lock acquired
1848c2ecf20Sopenharmony_ci	 * by V4L2 when calling delta_vb2_au_queue
1858c2ecf20Sopenharmony_ci	 */
1868c2ecf20Sopenharmony_ci	if (list_empty(&ctx->dts)) {
1878c2ecf20Sopenharmony_ci		dev_warn(delta->dev, "%s no dts to pop ... output dts = 0\n",
1888c2ecf20Sopenharmony_ci			 ctx->name);
1898c2ecf20Sopenharmony_ci		*val = 0;
1908c2ecf20Sopenharmony_ci		return;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	dts = list_first_entry(&ctx->dts, struct delta_dts, list);
1948c2ecf20Sopenharmony_ci	list_del(&dts->list);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	*val = dts->val;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	kfree(dts);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void delta_flush_dts(struct delta_ctx *ctx)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct delta_dts *dts;
2048c2ecf20Sopenharmony_ci	struct delta_dts *next;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/*
2078c2ecf20Sopenharmony_ci	 * protected by global lock acquired
2088c2ecf20Sopenharmony_ci	 * by V4L2 when calling delta_vb2_au_queue
2098c2ecf20Sopenharmony_ci	 */
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* free all pending dts */
2128c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dts, next, &ctx->dts, list)
2138c2ecf20Sopenharmony_ci		kfree(dts);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* reset list */
2168c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->dts);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic inline int frame_alignment(u32 fmt)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	switch (fmt) {
2228c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
2238c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV21:
2248c2ecf20Sopenharmony_ci		/* multiple of 2 */
2258c2ecf20Sopenharmony_ci		return 2;
2268c2ecf20Sopenharmony_ci	default:
2278c2ecf20Sopenharmony_ci		return 1;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic inline int estimated_au_size(u32 w, u32 h)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	/*
2348c2ecf20Sopenharmony_ci	 * for a MJPEG stream encoded from YUV422 pixel format,
2358c2ecf20Sopenharmony_ci	 * assuming a compression ratio of 2, the maximum size
2368c2ecf20Sopenharmony_ci	 * of an access unit is (width x height x 2) / 2,
2378c2ecf20Sopenharmony_ci	 * so (width x height)
2388c2ecf20Sopenharmony_ci	 */
2398c2ecf20Sopenharmony_ci	return (w * h);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic void set_default_params(struct delta_ctx *ctx)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct delta_frameinfo *frameinfo = &ctx->frameinfo;
2458c2ecf20Sopenharmony_ci	struct delta_streaminfo *streaminfo = &ctx->streaminfo;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	memset(frameinfo, 0, sizeof(*frameinfo));
2488c2ecf20Sopenharmony_ci	frameinfo->pixelformat = V4L2_PIX_FMT_NV12;
2498c2ecf20Sopenharmony_ci	frameinfo->width = DELTA_DEFAULT_WIDTH;
2508c2ecf20Sopenharmony_ci	frameinfo->height = DELTA_DEFAULT_HEIGHT;
2518c2ecf20Sopenharmony_ci	frameinfo->aligned_width = ALIGN(frameinfo->width,
2528c2ecf20Sopenharmony_ci					 DELTA_WIDTH_ALIGNMENT);
2538c2ecf20Sopenharmony_ci	frameinfo->aligned_height = ALIGN(frameinfo->height,
2548c2ecf20Sopenharmony_ci					  DELTA_HEIGHT_ALIGNMENT);
2558c2ecf20Sopenharmony_ci	frameinfo->size = frame_size(frameinfo->aligned_width,
2568c2ecf20Sopenharmony_ci				     frameinfo->aligned_height,
2578c2ecf20Sopenharmony_ci				     frameinfo->pixelformat);
2588c2ecf20Sopenharmony_ci	frameinfo->field = V4L2_FIELD_NONE;
2598c2ecf20Sopenharmony_ci	frameinfo->colorspace = V4L2_COLORSPACE_REC709;
2608c2ecf20Sopenharmony_ci	frameinfo->xfer_func = V4L2_XFER_FUNC_DEFAULT;
2618c2ecf20Sopenharmony_ci	frameinfo->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
2628c2ecf20Sopenharmony_ci	frameinfo->quantization = V4L2_QUANTIZATION_DEFAULT;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	memset(streaminfo, 0, sizeof(*streaminfo));
2658c2ecf20Sopenharmony_ci	streaminfo->streamformat = DELTA_DEFAULT_STREAMFORMAT;
2668c2ecf20Sopenharmony_ci	streaminfo->width = DELTA_DEFAULT_WIDTH;
2678c2ecf20Sopenharmony_ci	streaminfo->height = DELTA_DEFAULT_HEIGHT;
2688c2ecf20Sopenharmony_ci	streaminfo->field = V4L2_FIELD_NONE;
2698c2ecf20Sopenharmony_ci	streaminfo->colorspace = V4L2_COLORSPACE_REC709;
2708c2ecf20Sopenharmony_ci	streaminfo->xfer_func = V4L2_XFER_FUNC_DEFAULT;
2718c2ecf20Sopenharmony_ci	streaminfo->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
2728c2ecf20Sopenharmony_ci	streaminfo->quantization = V4L2_QUANTIZATION_DEFAULT;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ctx->max_au_size = estimated_au_size(streaminfo->width,
2758c2ecf20Sopenharmony_ci					     streaminfo->height);
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic const struct delta_dec *delta_find_decoder(struct delta_ctx *ctx,
2798c2ecf20Sopenharmony_ci						  u32 streamformat,
2808c2ecf20Sopenharmony_ci						  u32 pixelformat)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
2838c2ecf20Sopenharmony_ci	const struct delta_dec *dec;
2848c2ecf20Sopenharmony_ci	unsigned int i;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	for (i = 0; i < delta->nb_of_decoders; i++) {
2878c2ecf20Sopenharmony_ci		dec = delta->decoders[i];
2888c2ecf20Sopenharmony_ci		if ((dec->pixelformat == pixelformat) &&
2898c2ecf20Sopenharmony_ci		    (dec->streamformat == streamformat))
2908c2ecf20Sopenharmony_ci			return dec;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	return NULL;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic void register_format(u32 format, u32 formats[], u32 *nb_of_formats)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	u32 i;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	for (i = 0; i < *nb_of_formats; i++) {
3018c2ecf20Sopenharmony_ci		if (format == formats[i])
3028c2ecf20Sopenharmony_ci			return;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	formats[(*nb_of_formats)++] = format;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic void register_formats(struct delta_dev *delta)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	unsigned int i;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	for (i = 0; i < delta->nb_of_decoders; i++) {
3138c2ecf20Sopenharmony_ci		register_format(delta->decoders[i]->pixelformat,
3148c2ecf20Sopenharmony_ci				delta->pixelformats,
3158c2ecf20Sopenharmony_ci				&delta->nb_of_pixelformats);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		register_format(delta->decoders[i]->streamformat,
3188c2ecf20Sopenharmony_ci				delta->streamformats,
3198c2ecf20Sopenharmony_ci				&delta->nb_of_streamformats);
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic void register_decoders(struct delta_dev *delta)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	unsigned int i;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(delta_decoders); i++) {
3288c2ecf20Sopenharmony_ci		if (delta->nb_of_decoders >= DELTA_MAX_DECODERS) {
3298c2ecf20Sopenharmony_ci			dev_dbg(delta->dev,
3308c2ecf20Sopenharmony_ci				"%s failed to register %s decoder (%d maximum reached)\n",
3318c2ecf20Sopenharmony_ci				DELTA_PREFIX, delta_decoders[i]->name,
3328c2ecf20Sopenharmony_ci				DELTA_MAX_DECODERS);
3338c2ecf20Sopenharmony_ci			return;
3348c2ecf20Sopenharmony_ci		}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		delta->decoders[delta->nb_of_decoders++] = delta_decoders[i];
3378c2ecf20Sopenharmony_ci		dev_info(delta->dev, "%s %s decoder registered\n",
3388c2ecf20Sopenharmony_ci			 DELTA_PREFIX, delta_decoders[i]->name);
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic int delta_open_decoder(struct delta_ctx *ctx, u32 streamformat,
3438c2ecf20Sopenharmony_ci			      u32 pixelformat, const struct delta_dec **pdec)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
3468c2ecf20Sopenharmony_ci	const struct delta_dec *dec;
3478c2ecf20Sopenharmony_ci	int ret;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	dec = delta_find_decoder(ctx, streamformat, ctx->frameinfo.pixelformat);
3508c2ecf20Sopenharmony_ci	if (!dec) {
3518c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s no decoder found matching %4.4s => %4.4s\n",
3528c2ecf20Sopenharmony_ci			ctx->name, (char *)&streamformat, (char *)&pixelformat);
3538c2ecf20Sopenharmony_ci		return -EINVAL;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s one decoder matching %4.4s => %4.4s\n",
3578c2ecf20Sopenharmony_ci		ctx->name, (char *)&streamformat, (char *)&pixelformat);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* update instance name */
3608c2ecf20Sopenharmony_ci	snprintf(ctx->name, sizeof(ctx->name), "[%3d:%4.4s]",
3618c2ecf20Sopenharmony_ci		 delta->instance_id, (char *)&streamformat);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* open decoder instance */
3648c2ecf20Sopenharmony_ci	ret = call_dec_op(dec, open, ctx);
3658c2ecf20Sopenharmony_ci	if (ret) {
3668c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to open decoder instance (%d)\n",
3678c2ecf20Sopenharmony_ci			ctx->name, ret);
3688c2ecf20Sopenharmony_ci		return ret;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s %s decoder opened\n", ctx->name, dec->name);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	*pdec = dec;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return ret;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci/*
3798c2ecf20Sopenharmony_ci * V4L2 ioctl operations
3808c2ecf20Sopenharmony_ci */
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic int delta_querycap(struct file *file, void *priv,
3838c2ecf20Sopenharmony_ci			  struct v4l2_capability *cap)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
3868c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	strscpy(cap->driver, DELTA_NAME, sizeof(cap->driver));
3898c2ecf20Sopenharmony_ci	strscpy(cap->card, delta->vdev->name, sizeof(cap->card));
3908c2ecf20Sopenharmony_ci	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
3918c2ecf20Sopenharmony_ci		 delta->pdev->name);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic int delta_enum_fmt_stream(struct file *file, void *priv,
3978c2ecf20Sopenharmony_ci				 struct v4l2_fmtdesc *f)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
4008c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (unlikely(f->index >= delta->nb_of_streamformats))
4038c2ecf20Sopenharmony_ci		return -EINVAL;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	f->pixelformat = delta->streamformats[f->index];
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	return 0;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic int delta_enum_fmt_frame(struct file *file, void *priv,
4118c2ecf20Sopenharmony_ci				struct v4l2_fmtdesc *f)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
4148c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (unlikely(f->index >= delta->nb_of_pixelformats))
4178c2ecf20Sopenharmony_ci		return -EINVAL;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	f->pixelformat = delta->pixelformats[f->index];
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return 0;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic int delta_g_fmt_stream(struct file *file, void *fh,
4258c2ecf20Sopenharmony_ci			      struct v4l2_format *f)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
4288c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
4298c2ecf20Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
4308c2ecf20Sopenharmony_ci	struct delta_streaminfo *streaminfo = &ctx->streaminfo;
4318c2ecf20Sopenharmony_ci	unsigned char str[100] = "";
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (!(ctx->flags & DELTA_FLAG_STREAMINFO))
4348c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
4358c2ecf20Sopenharmony_ci			"%s V4L2 GET_FMT (OUTPUT): no stream information available, default to %s\n",
4368c2ecf20Sopenharmony_ci			ctx->name,
4378c2ecf20Sopenharmony_ci			delta_streaminfo_str(streaminfo, str, sizeof(str)));
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	pix->pixelformat = streaminfo->streamformat;
4408c2ecf20Sopenharmony_ci	pix->width = streaminfo->width;
4418c2ecf20Sopenharmony_ci	pix->height = streaminfo->height;
4428c2ecf20Sopenharmony_ci	pix->field = streaminfo->field;
4438c2ecf20Sopenharmony_ci	pix->bytesperline = 0;
4448c2ecf20Sopenharmony_ci	pix->sizeimage = ctx->max_au_size;
4458c2ecf20Sopenharmony_ci	pix->colorspace = streaminfo->colorspace;
4468c2ecf20Sopenharmony_ci	pix->xfer_func = streaminfo->xfer_func;
4478c2ecf20Sopenharmony_ci	pix->ycbcr_enc = streaminfo->ycbcr_enc;
4488c2ecf20Sopenharmony_ci	pix->quantization = streaminfo->quantization;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic int delta_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
4568c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
4578c2ecf20Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
4588c2ecf20Sopenharmony_ci	struct delta_frameinfo *frameinfo = &ctx->frameinfo;
4598c2ecf20Sopenharmony_ci	struct delta_streaminfo *streaminfo = &ctx->streaminfo;
4608c2ecf20Sopenharmony_ci	unsigned char str[100] = "";
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (!(ctx->flags & DELTA_FLAG_FRAMEINFO))
4638c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
4648c2ecf20Sopenharmony_ci			"%s V4L2 GET_FMT (CAPTURE): no frame information available, default to %s\n",
4658c2ecf20Sopenharmony_ci			ctx->name,
4668c2ecf20Sopenharmony_ci			delta_frameinfo_str(frameinfo, str, sizeof(str)));
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	pix->pixelformat = frameinfo->pixelformat;
4698c2ecf20Sopenharmony_ci	pix->width = frameinfo->aligned_width;
4708c2ecf20Sopenharmony_ci	pix->height = frameinfo->aligned_height;
4718c2ecf20Sopenharmony_ci	pix->field = frameinfo->field;
4728c2ecf20Sopenharmony_ci	pix->bytesperline = frame_stride(frameinfo->aligned_width,
4738c2ecf20Sopenharmony_ci					       frameinfo->pixelformat);
4748c2ecf20Sopenharmony_ci	pix->sizeimage = frameinfo->size;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (ctx->flags & DELTA_FLAG_STREAMINFO) {
4778c2ecf20Sopenharmony_ci		/* align colorspace & friends on stream ones if any set */
4788c2ecf20Sopenharmony_ci		frameinfo->colorspace = streaminfo->colorspace;
4798c2ecf20Sopenharmony_ci		frameinfo->xfer_func = streaminfo->xfer_func;
4808c2ecf20Sopenharmony_ci		frameinfo->ycbcr_enc = streaminfo->ycbcr_enc;
4818c2ecf20Sopenharmony_ci		frameinfo->quantization = streaminfo->quantization;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci	pix->colorspace = frameinfo->colorspace;
4848c2ecf20Sopenharmony_ci	pix->xfer_func = frameinfo->xfer_func;
4858c2ecf20Sopenharmony_ci	pix->ycbcr_enc = frameinfo->ycbcr_enc;
4868c2ecf20Sopenharmony_ci	pix->quantization = frameinfo->quantization;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return 0;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic int delta_try_fmt_stream(struct file *file, void *priv,
4928c2ecf20Sopenharmony_ci				struct v4l2_format *f)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
4958c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
4968c2ecf20Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
4978c2ecf20Sopenharmony_ci	u32 streamformat = pix->pixelformat;
4988c2ecf20Sopenharmony_ci	const struct delta_dec *dec;
4998c2ecf20Sopenharmony_ci	u32 width, height;
5008c2ecf20Sopenharmony_ci	u32 au_size;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	dec = delta_find_decoder(ctx, streamformat, ctx->frameinfo.pixelformat);
5038c2ecf20Sopenharmony_ci	if (!dec) {
5048c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
5058c2ecf20Sopenharmony_ci			"%s V4L2 TRY_FMT (OUTPUT): unsupported format %4.4s\n",
5068c2ecf20Sopenharmony_ci			ctx->name, (char *)&pix->pixelformat);
5078c2ecf20Sopenharmony_ci		return -EINVAL;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* adjust width & height */
5118c2ecf20Sopenharmony_ci	width = pix->width;
5128c2ecf20Sopenharmony_ci	height = pix->height;
5138c2ecf20Sopenharmony_ci	v4l_bound_align_image
5148c2ecf20Sopenharmony_ci		(&pix->width,
5158c2ecf20Sopenharmony_ci		 DELTA_MIN_WIDTH,
5168c2ecf20Sopenharmony_ci		 dec->max_width ? dec->max_width : DELTA_MAX_WIDTH,
5178c2ecf20Sopenharmony_ci		 0,
5188c2ecf20Sopenharmony_ci		 &pix->height,
5198c2ecf20Sopenharmony_ci		 DELTA_MIN_HEIGHT,
5208c2ecf20Sopenharmony_ci		 dec->max_height ? dec->max_height : DELTA_MAX_HEIGHT,
5218c2ecf20Sopenharmony_ci		 0, 0);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if ((pix->width != width) || (pix->height != height))
5248c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
5258c2ecf20Sopenharmony_ci			"%s V4L2 TRY_FMT (OUTPUT): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n",
5268c2ecf20Sopenharmony_ci			ctx->name, width, height,
5278c2ecf20Sopenharmony_ci			pix->width, pix->height);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	au_size = estimated_au_size(pix->width, pix->height);
5308c2ecf20Sopenharmony_ci	if (pix->sizeimage < au_size) {
5318c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
5328c2ecf20Sopenharmony_ci			"%s V4L2 TRY_FMT (OUTPUT): size updated %d -> %d to fit estimated size\n",
5338c2ecf20Sopenharmony_ci			ctx->name, pix->sizeimage, au_size);
5348c2ecf20Sopenharmony_ci		pix->sizeimage = au_size;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	pix->bytesperline = 0;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if (pix->field == V4L2_FIELD_ANY)
5408c2ecf20Sopenharmony_ci		pix->field = V4L2_FIELD_NONE;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return 0;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic int delta_try_fmt_frame(struct file *file, void *priv,
5468c2ecf20Sopenharmony_ci			       struct v4l2_format *f)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
5498c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
5508c2ecf20Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
5518c2ecf20Sopenharmony_ci	u32 pixelformat = pix->pixelformat;
5528c2ecf20Sopenharmony_ci	const struct delta_dec *dec;
5538c2ecf20Sopenharmony_ci	u32 width, height;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	dec = delta_find_decoder(ctx, ctx->streaminfo.streamformat,
5568c2ecf20Sopenharmony_ci				 pixelformat);
5578c2ecf20Sopenharmony_ci	if (!dec) {
5588c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
5598c2ecf20Sopenharmony_ci			"%s V4L2 TRY_FMT (CAPTURE): unsupported format %4.4s\n",
5608c2ecf20Sopenharmony_ci			ctx->name, (char *)&pixelformat);
5618c2ecf20Sopenharmony_ci		return -EINVAL;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	/* adjust width & height */
5658c2ecf20Sopenharmony_ci	width = pix->width;
5668c2ecf20Sopenharmony_ci	height = pix->height;
5678c2ecf20Sopenharmony_ci	v4l_bound_align_image(&pix->width,
5688c2ecf20Sopenharmony_ci			      DELTA_MIN_WIDTH, DELTA_MAX_WIDTH,
5698c2ecf20Sopenharmony_ci			      frame_alignment(pixelformat) - 1,
5708c2ecf20Sopenharmony_ci			      &pix->height,
5718c2ecf20Sopenharmony_ci			      DELTA_MIN_HEIGHT, DELTA_MAX_HEIGHT,
5728c2ecf20Sopenharmony_ci			      frame_alignment(pixelformat) - 1, 0);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	if ((pix->width != width) || (pix->height != height))
5758c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
5768c2ecf20Sopenharmony_ci			"%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n",
5778c2ecf20Sopenharmony_ci			ctx->name, width, height, pix->width, pix->height);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* default decoder alignment constraint */
5808c2ecf20Sopenharmony_ci	width = ALIGN(pix->width, DELTA_WIDTH_ALIGNMENT);
5818c2ecf20Sopenharmony_ci	height = ALIGN(pix->height, DELTA_HEIGHT_ALIGNMENT);
5828c2ecf20Sopenharmony_ci	if ((pix->width != width) || (pix->height != height))
5838c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
5848c2ecf20Sopenharmony_ci			"%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit decoder alignment\n",
5858c2ecf20Sopenharmony_ci			ctx->name, width, height, pix->width, pix->height);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	if (!pix->colorspace) {
5888c2ecf20Sopenharmony_ci		pix->colorspace = V4L2_COLORSPACE_REC709;
5898c2ecf20Sopenharmony_ci		pix->xfer_func = V4L2_XFER_FUNC_DEFAULT;
5908c2ecf20Sopenharmony_ci		pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
5918c2ecf20Sopenharmony_ci		pix->quantization = V4L2_QUANTIZATION_DEFAULT;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	pix->width = width;
5958c2ecf20Sopenharmony_ci	pix->height = height;
5968c2ecf20Sopenharmony_ci	pix->bytesperline = frame_stride(pix->width, pixelformat);
5978c2ecf20Sopenharmony_ci	pix->sizeimage = frame_size(pix->width, pix->height, pixelformat);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if (pix->field == V4L2_FIELD_ANY)
6008c2ecf20Sopenharmony_ci		pix->field = V4L2_FIELD_NONE;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	return 0;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic int delta_s_fmt_stream(struct file *file, void *fh,
6068c2ecf20Sopenharmony_ci			      struct v4l2_format *f)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
6098c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
6108c2ecf20Sopenharmony_ci	struct vb2_queue *vq;
6118c2ecf20Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
6128c2ecf20Sopenharmony_ci	int ret;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	ret = delta_try_fmt_stream(file, fh, f);
6158c2ecf20Sopenharmony_ci	if (ret) {
6168c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
6178c2ecf20Sopenharmony_ci			"%s V4L2 S_FMT (OUTPUT): unsupported format %4.4s\n",
6188c2ecf20Sopenharmony_ci			ctx->name, (char *)&pix->pixelformat);
6198c2ecf20Sopenharmony_ci		return ret;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
6238c2ecf20Sopenharmony_ci	if (vb2_is_streaming(vq)) {
6248c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s V4L2 S_FMT (OUTPUT): queue busy\n",
6258c2ecf20Sopenharmony_ci			ctx->name);
6268c2ecf20Sopenharmony_ci		return -EBUSY;
6278c2ecf20Sopenharmony_ci	}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	ctx->max_au_size = pix->sizeimage;
6308c2ecf20Sopenharmony_ci	ctx->streaminfo.width = pix->width;
6318c2ecf20Sopenharmony_ci	ctx->streaminfo.height = pix->height;
6328c2ecf20Sopenharmony_ci	ctx->streaminfo.streamformat = pix->pixelformat;
6338c2ecf20Sopenharmony_ci	ctx->streaminfo.colorspace = pix->colorspace;
6348c2ecf20Sopenharmony_ci	ctx->streaminfo.xfer_func = pix->xfer_func;
6358c2ecf20Sopenharmony_ci	ctx->streaminfo.ycbcr_enc = pix->ycbcr_enc;
6368c2ecf20Sopenharmony_ci	ctx->streaminfo.quantization = pix->quantization;
6378c2ecf20Sopenharmony_ci	ctx->flags |= DELTA_FLAG_STREAMINFO;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	return 0;
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int delta_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
6458c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
6468c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
6478c2ecf20Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
6488c2ecf20Sopenharmony_ci	struct delta_frameinfo frameinfo;
6498c2ecf20Sopenharmony_ci	unsigned char str[100] = "";
6508c2ecf20Sopenharmony_ci	struct vb2_queue *vq;
6518c2ecf20Sopenharmony_ci	int ret;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
6548c2ecf20Sopenharmony_ci	if (vb2_is_streaming(vq)) {
6558c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s V4L2 S_FMT (CAPTURE): queue busy\n",
6568c2ecf20Sopenharmony_ci			ctx->name);
6578c2ecf20Sopenharmony_ci		return -EBUSY;
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if (ctx->state < DELTA_STATE_READY) {
6618c2ecf20Sopenharmony_ci		/*
6628c2ecf20Sopenharmony_ci		 * decoder not yet opened and valid stream header not found,
6638c2ecf20Sopenharmony_ci		 * could not negotiate format with decoder, check at least
6648c2ecf20Sopenharmony_ci		 * pixel format & negotiate resolution boundaries
6658c2ecf20Sopenharmony_ci		 * and alignment...
6668c2ecf20Sopenharmony_ci		 */
6678c2ecf20Sopenharmony_ci		ret = delta_try_fmt_frame(file, fh, f);
6688c2ecf20Sopenharmony_ci		if (ret) {
6698c2ecf20Sopenharmony_ci			dev_dbg(delta->dev,
6708c2ecf20Sopenharmony_ci				"%s V4L2 S_FMT (CAPTURE): unsupported format %4.4s\n",
6718c2ecf20Sopenharmony_ci				ctx->name, (char *)&pix->pixelformat);
6728c2ecf20Sopenharmony_ci			return ret;
6738c2ecf20Sopenharmony_ci		}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		return 0;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	/* set frame information to decoder */
6798c2ecf20Sopenharmony_ci	memset(&frameinfo, 0, sizeof(frameinfo));
6808c2ecf20Sopenharmony_ci	frameinfo.pixelformat = pix->pixelformat;
6818c2ecf20Sopenharmony_ci	frameinfo.width = pix->width;
6828c2ecf20Sopenharmony_ci	frameinfo.height = pix->height;
6838c2ecf20Sopenharmony_ci	frameinfo.aligned_width = pix->width;
6848c2ecf20Sopenharmony_ci	frameinfo.aligned_height = pix->height;
6858c2ecf20Sopenharmony_ci	frameinfo.size = pix->sizeimage;
6868c2ecf20Sopenharmony_ci	frameinfo.field = pix->field;
6878c2ecf20Sopenharmony_ci	frameinfo.colorspace = pix->colorspace;
6888c2ecf20Sopenharmony_ci	frameinfo.xfer_func = pix->xfer_func;
6898c2ecf20Sopenharmony_ci	frameinfo.ycbcr_enc = pix->ycbcr_enc;
6908c2ecf20Sopenharmony_ci	frameinfo.quantization = pix->quantization;
6918c2ecf20Sopenharmony_ci	ret = call_dec_op(dec, set_frameinfo, ctx, &frameinfo);
6928c2ecf20Sopenharmony_ci	if (ret)
6938c2ecf20Sopenharmony_ci		return ret;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	/* then get what decoder can really do */
6968c2ecf20Sopenharmony_ci	ret = call_dec_op(dec, get_frameinfo, ctx, &frameinfo);
6978c2ecf20Sopenharmony_ci	if (ret)
6988c2ecf20Sopenharmony_ci		return ret;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	ctx->flags |= DELTA_FLAG_FRAMEINFO;
7018c2ecf20Sopenharmony_ci	ctx->frameinfo = frameinfo;
7028c2ecf20Sopenharmony_ci	dev_dbg(delta->dev,
7038c2ecf20Sopenharmony_ci		"%s V4L2 SET_FMT (CAPTURE): frameinfo updated to %s\n",
7048c2ecf20Sopenharmony_ci		ctx->name,
7058c2ecf20Sopenharmony_ci		delta_frameinfo_str(&frameinfo, str, sizeof(str)));
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	pix->pixelformat = frameinfo.pixelformat;
7088c2ecf20Sopenharmony_ci	pix->width = frameinfo.aligned_width;
7098c2ecf20Sopenharmony_ci	pix->height = frameinfo.aligned_height;
7108c2ecf20Sopenharmony_ci	pix->bytesperline = frame_stride(pix->width, pix->pixelformat);
7118c2ecf20Sopenharmony_ci	pix->sizeimage = frameinfo.size;
7128c2ecf20Sopenharmony_ci	pix->field = frameinfo.field;
7138c2ecf20Sopenharmony_ci	pix->colorspace = frameinfo.colorspace;
7148c2ecf20Sopenharmony_ci	pix->xfer_func = frameinfo.xfer_func;
7158c2ecf20Sopenharmony_ci	pix->ycbcr_enc = frameinfo.ycbcr_enc;
7168c2ecf20Sopenharmony_ci	pix->quantization = frameinfo.quantization;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	return 0;
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic int delta_g_selection(struct file *file, void *fh,
7228c2ecf20Sopenharmony_ci			     struct v4l2_selection *s)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(fh);
7258c2ecf20Sopenharmony_ci	struct delta_frameinfo *frameinfo = &ctx->frameinfo;
7268c2ecf20Sopenharmony_ci	struct v4l2_rect crop;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
7298c2ecf20Sopenharmony_ci		return -EINVAL;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if ((ctx->flags & DELTA_FLAG_FRAMEINFO) &&
7328c2ecf20Sopenharmony_ci	    (frameinfo->flags & DELTA_FRAMEINFO_FLAG_CROP)) {
7338c2ecf20Sopenharmony_ci		crop = frameinfo->crop;
7348c2ecf20Sopenharmony_ci	} else {
7358c2ecf20Sopenharmony_ci		/* default to video dimensions */
7368c2ecf20Sopenharmony_ci		crop.left = 0;
7378c2ecf20Sopenharmony_ci		crop.top = 0;
7388c2ecf20Sopenharmony_ci		crop.width = frameinfo->width;
7398c2ecf20Sopenharmony_ci		crop.height = frameinfo->height;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	switch (s->target) {
7438c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE:
7448c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
7458c2ecf20Sopenharmony_ci		/* visible area inside video */
7468c2ecf20Sopenharmony_ci		s->r = crop;
7478c2ecf20Sopenharmony_ci		break;
7488c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE_PADDED:
7498c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
7508c2ecf20Sopenharmony_ci		/* up to aligned dimensions */
7518c2ecf20Sopenharmony_ci		s->r.left = 0;
7528c2ecf20Sopenharmony_ci		s->r.top = 0;
7538c2ecf20Sopenharmony_ci		s->r.width = frameinfo->aligned_width;
7548c2ecf20Sopenharmony_ci		s->r.height = frameinfo->aligned_height;
7558c2ecf20Sopenharmony_ci		break;
7568c2ecf20Sopenharmony_ci	default:
7578c2ecf20Sopenharmony_ci		return -EINVAL;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	return 0;
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic void delta_complete_eos(struct delta_ctx *ctx,
7648c2ecf20Sopenharmony_ci			       struct delta_frame *frame)
7658c2ecf20Sopenharmony_ci{
7668c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
7678c2ecf20Sopenharmony_ci	const struct v4l2_event ev = {.type = V4L2_EVENT_EOS};
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	/*
7708c2ecf20Sopenharmony_ci	 * Send EOS to user:
7718c2ecf20Sopenharmony_ci	 * - by returning an empty frame flagged to V4L2_BUF_FLAG_LAST
7728c2ecf20Sopenharmony_ci	 * - and then send EOS event
7738c2ecf20Sopenharmony_ci	 */
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	/* empty frame */
7768c2ecf20Sopenharmony_ci	frame->info.size = 0;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/* set the last buffer flag */
7798c2ecf20Sopenharmony_ci	frame->flags |= V4L2_BUF_FLAG_LAST;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/* release frame to user */
7828c2ecf20Sopenharmony_ci	delta_frame_done(ctx, frame, 0);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	/* send EOS event */
7858c2ecf20Sopenharmony_ci	v4l2_event_queue_fh(&ctx->fh, &ev);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s EOS completed\n", ctx->name);
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cistatic int delta_try_decoder_cmd(struct file *file, void *fh,
7918c2ecf20Sopenharmony_ci				 struct v4l2_decoder_cmd *cmd)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	if (cmd->cmd != V4L2_DEC_CMD_STOP)
7948c2ecf20Sopenharmony_ci		return -EINVAL;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
7978c2ecf20Sopenharmony_ci		return -EINVAL;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (!(cmd->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) &&
8008c2ecf20Sopenharmony_ci	    (cmd->stop.pts != 0))
8018c2ecf20Sopenharmony_ci		return -EINVAL;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	return 0;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic int delta_decoder_stop_cmd(struct delta_ctx *ctx, void *fh)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
8098c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
8108c2ecf20Sopenharmony_ci	struct delta_frame *frame = NULL;
8118c2ecf20Sopenharmony_ci	int ret = 0;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s EOS received\n", ctx->name);
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (ctx->state != DELTA_STATE_READY)
8168c2ecf20Sopenharmony_ci		return 0;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	/* drain the decoder */
8198c2ecf20Sopenharmony_ci	call_dec_op(dec, drain, ctx);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	/* release to user drained frames */
8228c2ecf20Sopenharmony_ci	while (1) {
8238c2ecf20Sopenharmony_ci		frame = NULL;
8248c2ecf20Sopenharmony_ci		ret = call_dec_op(dec, get_frame, ctx, &frame);
8258c2ecf20Sopenharmony_ci		if (ret == -ENODATA) {
8268c2ecf20Sopenharmony_ci			/* no more decoded frames */
8278c2ecf20Sopenharmony_ci			break;
8288c2ecf20Sopenharmony_ci		}
8298c2ecf20Sopenharmony_ci		if (frame) {
8308c2ecf20Sopenharmony_ci			dev_dbg(delta->dev, "%s drain frame[%d]\n",
8318c2ecf20Sopenharmony_ci				ctx->name, frame->index);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci			/* pop timestamp and mark frame with it */
8348c2ecf20Sopenharmony_ci			delta_pop_dts(ctx, &frame->dts);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci			/* release decoded frame to user */
8378c2ecf20Sopenharmony_ci			delta_frame_done(ctx, frame, 0);
8388c2ecf20Sopenharmony_ci		}
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/* try to complete EOS */
8428c2ecf20Sopenharmony_ci	ret = delta_get_free_frame(ctx, &frame);
8438c2ecf20Sopenharmony_ci	if (ret)
8448c2ecf20Sopenharmony_ci		goto delay_eos;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	/* new frame available, EOS can now be completed */
8478c2ecf20Sopenharmony_ci	delta_complete_eos(ctx, frame);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	ctx->state = DELTA_STATE_EOS;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	return 0;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cidelay_eos:
8548c2ecf20Sopenharmony_ci	/*
8558c2ecf20Sopenharmony_ci	 * EOS completion from driver is delayed because
8568c2ecf20Sopenharmony_ci	 * we don't have a free empty frame available.
8578c2ecf20Sopenharmony_ci	 * EOS completion is so delayed till next frame_queue() call
8588c2ecf20Sopenharmony_ci	 * to be sure to have a free empty frame available.
8598c2ecf20Sopenharmony_ci	 */
8608c2ecf20Sopenharmony_ci	ctx->state = DELTA_STATE_WF_EOS;
8618c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s EOS delayed\n", ctx->name);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	return 0;
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic int delta_decoder_cmd(struct file *file, void *fh,
8678c2ecf20Sopenharmony_ci			     struct v4l2_decoder_cmd *cmd)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(fh);
8708c2ecf20Sopenharmony_ci	int ret = 0;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	ret = delta_try_decoder_cmd(file, fh, cmd);
8738c2ecf20Sopenharmony_ci	if (ret)
8748c2ecf20Sopenharmony_ci		return ret;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	return delta_decoder_stop_cmd(ctx, fh);
8778c2ecf20Sopenharmony_ci}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistatic int delta_subscribe_event(struct v4l2_fh *fh,
8808c2ecf20Sopenharmony_ci				 const struct v4l2_event_subscription *sub)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	switch (sub->type) {
8838c2ecf20Sopenharmony_ci	case V4L2_EVENT_EOS:
8848c2ecf20Sopenharmony_ci		return v4l2_event_subscribe(fh, sub, 2, NULL);
8858c2ecf20Sopenharmony_ci	default:
8868c2ecf20Sopenharmony_ci		return -EINVAL;
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	return 0;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci/* v4l2 ioctl ops */
8938c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops delta_ioctl_ops = {
8948c2ecf20Sopenharmony_ci	.vidioc_querycap = delta_querycap,
8958c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_cap = delta_enum_fmt_frame,
8968c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_cap = delta_g_fmt_frame,
8978c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_cap = delta_try_fmt_frame,
8988c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_cap = delta_s_fmt_frame,
8998c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_out = delta_enum_fmt_stream,
9008c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_out = delta_g_fmt_stream,
9018c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_out = delta_try_fmt_stream,
9028c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_out = delta_s_fmt_stream,
9038c2ecf20Sopenharmony_ci	.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
9048c2ecf20Sopenharmony_ci	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
9058c2ecf20Sopenharmony_ci	.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
9068c2ecf20Sopenharmony_ci	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
9078c2ecf20Sopenharmony_ci	.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
9088c2ecf20Sopenharmony_ci	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
9098c2ecf20Sopenharmony_ci	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
9108c2ecf20Sopenharmony_ci	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
9118c2ecf20Sopenharmony_ci	.vidioc_g_selection = delta_g_selection,
9128c2ecf20Sopenharmony_ci	.vidioc_try_decoder_cmd = delta_try_decoder_cmd,
9138c2ecf20Sopenharmony_ci	.vidioc_decoder_cmd = delta_decoder_cmd,
9148c2ecf20Sopenharmony_ci	.vidioc_subscribe_event = delta_subscribe_event,
9158c2ecf20Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
9168c2ecf20Sopenharmony_ci};
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci/*
9198c2ecf20Sopenharmony_ci * mem-to-mem operations
9208c2ecf20Sopenharmony_ci */
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_cistatic void delta_run_work(struct work_struct *work)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = container_of(work, struct delta_ctx, run_work);
9258c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
9268c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
9278c2ecf20Sopenharmony_ci	struct delta_au *au;
9288c2ecf20Sopenharmony_ci	struct delta_frame *frame = NULL;
9298c2ecf20Sopenharmony_ci	int ret = 0;
9308c2ecf20Sopenharmony_ci	bool discard = false;
9318c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	if (!dec) {
9348c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s no decoder opened yet\n", ctx->name);
9358c2ecf20Sopenharmony_ci		return;
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	/* protect instance against reentrancy */
9398c2ecf20Sopenharmony_ci	mutex_lock(&ctx->lock);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
9428c2ecf20Sopenharmony_ci	if (!vbuf) {
9438c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s no buffer to decode\n", ctx->name);
9448c2ecf20Sopenharmony_ci		mutex_unlock(&ctx->lock);
9458c2ecf20Sopenharmony_ci		return;
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci	au = to_au(vbuf);
9488c2ecf20Sopenharmony_ci	au->size = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
9498c2ecf20Sopenharmony_ci	au->dts = vbuf->vb2_buf.timestamp;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	/* dump access unit */
9528c2ecf20Sopenharmony_ci	dump_au(ctx, au);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	/* enable the hardware */
9558c2ecf20Sopenharmony_ci	if (!dec->pm) {
9568c2ecf20Sopenharmony_ci		ret = delta_get_sync(ctx);
9578c2ecf20Sopenharmony_ci		if (ret) {
9588c2ecf20Sopenharmony_ci			delta_put_autosuspend(ctx);
9598c2ecf20Sopenharmony_ci			goto err;
9608c2ecf20Sopenharmony_ci		}
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	/* decode this access unit */
9648c2ecf20Sopenharmony_ci	ret = call_dec_op(dec, decode, ctx, au);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/*
9678c2ecf20Sopenharmony_ci	 * if the (-ENODATA) value is returned, it refers to the interlaced
9688c2ecf20Sopenharmony_ci	 * stream case for which 2 access units are needed to get 1 frame.
9698c2ecf20Sopenharmony_ci	 * So, this returned value doesn't mean that the decoding fails, but
9708c2ecf20Sopenharmony_ci	 * indicates that the timestamp information of the access unit shall
9718c2ecf20Sopenharmony_ci	 * not be taken into account, and that the V4L2 buffer associated with
9728c2ecf20Sopenharmony_ci	 * the access unit shall be flagged with V4L2_BUF_FLAG_ERROR to inform
9738c2ecf20Sopenharmony_ci	 * the user of this situation
9748c2ecf20Sopenharmony_ci	 */
9758c2ecf20Sopenharmony_ci	if (ret == -ENODATA) {
9768c2ecf20Sopenharmony_ci		discard = true;
9778c2ecf20Sopenharmony_ci	} else if (ret) {
9788c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s decoding failed (%d)\n",
9798c2ecf20Sopenharmony_ci			ctx->name, ret);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		/* disable the hardware */
9828c2ecf20Sopenharmony_ci		if (!dec->pm)
9838c2ecf20Sopenharmony_ci			delta_put_autosuspend(ctx);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci		goto err;
9868c2ecf20Sopenharmony_ci	}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	/* disable the hardware */
9898c2ecf20Sopenharmony_ci	if (!dec->pm)
9908c2ecf20Sopenharmony_ci		delta_put_autosuspend(ctx);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	/* push au timestamp in FIFO */
9938c2ecf20Sopenharmony_ci	if (!discard)
9948c2ecf20Sopenharmony_ci		delta_push_dts(ctx, au->dts);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	/* get available decoded frames */
9978c2ecf20Sopenharmony_ci	while (1) {
9988c2ecf20Sopenharmony_ci		ret = call_dec_op(dec, get_frame, ctx, &frame);
9998c2ecf20Sopenharmony_ci		if (ret == -ENODATA) {
10008c2ecf20Sopenharmony_ci			/* no more decoded frames */
10018c2ecf20Sopenharmony_ci			goto out;
10028c2ecf20Sopenharmony_ci		}
10038c2ecf20Sopenharmony_ci		if (ret) {
10048c2ecf20Sopenharmony_ci			dev_err(delta->dev, "%s  cannot get decoded frame (%d)\n",
10058c2ecf20Sopenharmony_ci				ctx->name, ret);
10068c2ecf20Sopenharmony_ci			goto out;
10078c2ecf20Sopenharmony_ci		}
10088c2ecf20Sopenharmony_ci		if (!frame) {
10098c2ecf20Sopenharmony_ci			dev_err(delta->dev,
10108c2ecf20Sopenharmony_ci				"%s  NULL decoded frame\n",
10118c2ecf20Sopenharmony_ci				ctx->name);
10128c2ecf20Sopenharmony_ci			ret = -EIO;
10138c2ecf20Sopenharmony_ci			goto out;
10148c2ecf20Sopenharmony_ci		}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci		/* pop timestamp and mark frame with it */
10178c2ecf20Sopenharmony_ci		delta_pop_dts(ctx, &frame->dts);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		/* release decoded frame to user */
10208c2ecf20Sopenharmony_ci		delta_frame_done(ctx, frame, 0);
10218c2ecf20Sopenharmony_ci	}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ciout:
10248c2ecf20Sopenharmony_ci	requeue_free_frames(ctx);
10258c2ecf20Sopenharmony_ci	delta_au_done(ctx, au, (discard ? -ENODATA : 0));
10268c2ecf20Sopenharmony_ci	mutex_unlock(&ctx->lock);
10278c2ecf20Sopenharmony_ci	v4l2_m2m_job_finish(delta->m2m_dev, ctx->fh.m2m_ctx);
10288c2ecf20Sopenharmony_ci	return;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_cierr:
10318c2ecf20Sopenharmony_ci	requeue_free_frames(ctx);
10328c2ecf20Sopenharmony_ci	delta_au_done(ctx, au, ret);
10338c2ecf20Sopenharmony_ci	mutex_unlock(&ctx->lock);
10348c2ecf20Sopenharmony_ci	v4l2_m2m_job_finish(delta->m2m_dev, ctx->fh.m2m_ctx);
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic void delta_device_run(void *priv)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = priv;
10408c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	queue_work(delta->work_queue, &ctx->run_work);
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic void delta_job_abort(void *priv)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = priv;
10488c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s aborting job\n", ctx->name);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	ctx->aborting = true;
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic int delta_job_ready(void *priv)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = priv;
10588c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
10598c2ecf20Sopenharmony_ci	int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (!src_bufs) {
10628c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s not ready: not enough video buffers.\n",
10638c2ecf20Sopenharmony_ci			ctx->name);
10648c2ecf20Sopenharmony_ci		return 0;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
10688c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s not ready: not enough video capture buffers.\n",
10698c2ecf20Sopenharmony_ci			ctx->name);
10708c2ecf20Sopenharmony_ci		return 0;
10718c2ecf20Sopenharmony_ci	}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	if (ctx->aborting) {
10748c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s job not ready: aborting\n", ctx->name);
10758c2ecf20Sopenharmony_ci		return 0;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s job ready\n", ctx->name);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	return 1;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci/* mem-to-mem ops */
10848c2ecf20Sopenharmony_cistatic const struct v4l2_m2m_ops delta_m2m_ops = {
10858c2ecf20Sopenharmony_ci	.device_run     = delta_device_run,
10868c2ecf20Sopenharmony_ci	.job_ready	= delta_job_ready,
10878c2ecf20Sopenharmony_ci	.job_abort      = delta_job_abort,
10888c2ecf20Sopenharmony_ci};
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci/*
10918c2ecf20Sopenharmony_ci * VB2 queue operations
10928c2ecf20Sopenharmony_ci */
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_cistatic int delta_vb2_au_queue_setup(struct vb2_queue *vq,
10958c2ecf20Sopenharmony_ci				    unsigned int *num_buffers,
10968c2ecf20Sopenharmony_ci				    unsigned int *num_planes,
10978c2ecf20Sopenharmony_ci				    unsigned int sizes[],
10988c2ecf20Sopenharmony_ci				    struct device *alloc_devs[])
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(vq);
11018c2ecf20Sopenharmony_ci	unsigned int size = ctx->max_au_size;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	if (*num_planes)
11048c2ecf20Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	*num_planes = 1;
11078c2ecf20Sopenharmony_ci	if (*num_buffers < 1)
11088c2ecf20Sopenharmony_ci		*num_buffers = 1;
11098c2ecf20Sopenharmony_ci	if (*num_buffers > DELTA_MAX_AUS)
11108c2ecf20Sopenharmony_ci		*num_buffers = DELTA_MAX_AUS;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	sizes[0] = size;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	return 0;
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic int delta_vb2_au_prepare(struct vb2_buffer *vb)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	struct vb2_queue *q = vb->vb2_queue;
11208c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(q);
11218c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
11228c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
11238c2ecf20Sopenharmony_ci	struct delta_au *au = to_au(vbuf);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	if (!au->prepared) {
11268c2ecf20Sopenharmony_ci		/* get memory addresses */
11278c2ecf20Sopenharmony_ci		au->vaddr = vb2_plane_vaddr(&au->vbuf.vb2_buf, 0);
11288c2ecf20Sopenharmony_ci		au->paddr = vb2_dma_contig_plane_dma_addr
11298c2ecf20Sopenharmony_ci				(&au->vbuf.vb2_buf, 0);
11308c2ecf20Sopenharmony_ci		au->prepared = true;
11318c2ecf20Sopenharmony_ci		dev_dbg(delta->dev, "%s au[%d] prepared; virt=0x%p, phy=0x%pad\n",
11328c2ecf20Sopenharmony_ci			ctx->name, vb->index, au->vaddr, &au->paddr);
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (vbuf->field == V4L2_FIELD_ANY)
11368c2ecf20Sopenharmony_ci		vbuf->field = V4L2_FIELD_NONE;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	return 0;
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_cistatic int delta_setup_frame(struct delta_ctx *ctx,
11428c2ecf20Sopenharmony_ci			     struct delta_frame *frame)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
11458c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (frame->index >= DELTA_MAX_FRAMES) {
11488c2ecf20Sopenharmony_ci		dev_err(delta->dev,
11498c2ecf20Sopenharmony_ci			"%s frame index=%d exceeds output frame count (%d)\n",
11508c2ecf20Sopenharmony_ci			ctx->name, frame->index, DELTA_MAX_FRAMES);
11518c2ecf20Sopenharmony_ci		return -EINVAL;
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	if (ctx->nb_of_frames >= DELTA_MAX_FRAMES) {
11558c2ecf20Sopenharmony_ci		dev_err(delta->dev,
11568c2ecf20Sopenharmony_ci			"%s number of frames exceeds output frame count (%d > %d)\n",
11578c2ecf20Sopenharmony_ci			ctx->name, ctx->nb_of_frames, DELTA_MAX_FRAMES);
11588c2ecf20Sopenharmony_ci		return -EINVAL;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	if (frame->index != ctx->nb_of_frames) {
11628c2ecf20Sopenharmony_ci		dev_warn(delta->dev,
11638c2ecf20Sopenharmony_ci			 "%s frame index discontinuity detected, expected %d, got %d\n",
11648c2ecf20Sopenharmony_ci			 ctx->name, ctx->nb_of_frames, frame->index);
11658c2ecf20Sopenharmony_ci	}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	frame->state = DELTA_FRAME_FREE;
11688c2ecf20Sopenharmony_ci	ctx->frames[ctx->nb_of_frames] = frame;
11698c2ecf20Sopenharmony_ci	ctx->nb_of_frames++;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	/* setup frame on decoder side */
11728c2ecf20Sopenharmony_ci	return call_dec_op(dec, setup_frame, ctx, frame);
11738c2ecf20Sopenharmony_ci}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci/*
11768c2ecf20Sopenharmony_ci * default implementation of get_frameinfo decoder ops
11778c2ecf20Sopenharmony_ci * matching frame information from stream information
11788c2ecf20Sopenharmony_ci * & with default pixel format & default alignment.
11798c2ecf20Sopenharmony_ci */
11808c2ecf20Sopenharmony_ciint delta_get_frameinfo_default(struct delta_ctx *ctx,
11818c2ecf20Sopenharmony_ci				struct delta_frameinfo *frameinfo)
11828c2ecf20Sopenharmony_ci{
11838c2ecf20Sopenharmony_ci	struct delta_streaminfo *streaminfo = &ctx->streaminfo;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	memset(frameinfo, 0, sizeof(*frameinfo));
11868c2ecf20Sopenharmony_ci	frameinfo->pixelformat = V4L2_PIX_FMT_NV12;
11878c2ecf20Sopenharmony_ci	frameinfo->width = streaminfo->width;
11888c2ecf20Sopenharmony_ci	frameinfo->height = streaminfo->height;
11898c2ecf20Sopenharmony_ci	frameinfo->aligned_width = ALIGN(streaminfo->width,
11908c2ecf20Sopenharmony_ci					 DELTA_WIDTH_ALIGNMENT);
11918c2ecf20Sopenharmony_ci	frameinfo->aligned_height = ALIGN(streaminfo->height,
11928c2ecf20Sopenharmony_ci					  DELTA_HEIGHT_ALIGNMENT);
11938c2ecf20Sopenharmony_ci	frameinfo->size = frame_size(frameinfo->aligned_width,
11948c2ecf20Sopenharmony_ci				     frameinfo->aligned_height,
11958c2ecf20Sopenharmony_ci				     frameinfo->pixelformat);
11968c2ecf20Sopenharmony_ci	if (streaminfo->flags & DELTA_STREAMINFO_FLAG_CROP) {
11978c2ecf20Sopenharmony_ci		frameinfo->flags |= DELTA_FRAMEINFO_FLAG_CROP;
11988c2ecf20Sopenharmony_ci		frameinfo->crop = streaminfo->crop;
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci	if (streaminfo->flags & DELTA_STREAMINFO_FLAG_PIXELASPECT) {
12018c2ecf20Sopenharmony_ci		frameinfo->flags |= DELTA_FRAMEINFO_FLAG_PIXELASPECT;
12028c2ecf20Sopenharmony_ci		frameinfo->pixelaspect = streaminfo->pixelaspect;
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci	frameinfo->field = streaminfo->field;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	return 0;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci/*
12108c2ecf20Sopenharmony_ci * default implementation of recycle decoder ops
12118c2ecf20Sopenharmony_ci * consisting to relax the "decoded" frame state
12128c2ecf20Sopenharmony_ci */
12138c2ecf20Sopenharmony_ciint delta_recycle_default(struct delta_ctx *pctx,
12148c2ecf20Sopenharmony_ci			  struct delta_frame *frame)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	frame->state &= ~DELTA_FRAME_DEC;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	return 0;
12198c2ecf20Sopenharmony_ci}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_cistatic void dump_frames_status(struct delta_ctx *ctx)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
12248c2ecf20Sopenharmony_ci	unsigned int i;
12258c2ecf20Sopenharmony_ci	struct delta_frame *frame;
12268c2ecf20Sopenharmony_ci	unsigned char str[100] = "";
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	dev_info(delta->dev,
12298c2ecf20Sopenharmony_ci		 "%s dumping frames status...\n", ctx->name);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	for (i = 0; i < ctx->nb_of_frames; i++) {
12328c2ecf20Sopenharmony_ci		frame = ctx->frames[i];
12338c2ecf20Sopenharmony_ci		dev_info(delta->dev,
12348c2ecf20Sopenharmony_ci			 "%s frame[%d] %s\n",
12358c2ecf20Sopenharmony_ci			 ctx->name, frame->index,
12368c2ecf20Sopenharmony_ci			 frame_state_str(frame->state,
12378c2ecf20Sopenharmony_ci					 str, sizeof(str)));
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci}
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ciint delta_get_free_frame(struct delta_ctx *ctx,
12428c2ecf20Sopenharmony_ci			 struct delta_frame **pframe)
12438c2ecf20Sopenharmony_ci{
12448c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
12458c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
12468c2ecf20Sopenharmony_ci	struct delta_frame *frame;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	*pframe = NULL;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
12518c2ecf20Sopenharmony_ci	if (!vbuf) {
12528c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s no frame available",
12538c2ecf20Sopenharmony_ci			ctx->name);
12548c2ecf20Sopenharmony_ci		return -EIO;
12558c2ecf20Sopenharmony_ci	}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	frame = to_frame(vbuf);
12588c2ecf20Sopenharmony_ci	frame->state &= ~DELTA_FRAME_M2M;
12598c2ecf20Sopenharmony_ci	if (frame->state != DELTA_FRAME_FREE) {
12608c2ecf20Sopenharmony_ci		dev_err(delta->dev,
12618c2ecf20Sopenharmony_ci			"%s frame[%d] is not free\n",
12628c2ecf20Sopenharmony_ci			ctx->name, frame->index);
12638c2ecf20Sopenharmony_ci		dump_frames_status(ctx);
12648c2ecf20Sopenharmony_ci		return -ENODATA;
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	dev_dbg(delta->dev,
12688c2ecf20Sopenharmony_ci		"%s get free frame[%d]\n", ctx->name, frame->index);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	*pframe = frame;
12718c2ecf20Sopenharmony_ci	return 0;
12728c2ecf20Sopenharmony_ci}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ciint delta_get_sync(struct delta_ctx *ctx)
12758c2ecf20Sopenharmony_ci{
12768c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
12778c2ecf20Sopenharmony_ci	int ret = 0;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	/* enable the hardware */
12808c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(delta->dev);
12818c2ecf20Sopenharmony_ci	if (ret < 0) {
12828c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s pm_runtime_get_sync failed (%d)\n",
12838c2ecf20Sopenharmony_ci			__func__, ret);
12848c2ecf20Sopenharmony_ci		return ret;
12858c2ecf20Sopenharmony_ci	}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	return 0;
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_civoid delta_put_autosuspend(struct delta_ctx *ctx)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(delta->dev);
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_cistatic void delta_vb2_au_queue(struct vb2_buffer *vb)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	struct vb2_queue *q = vb->vb2_queue;
13008c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(q);
13018c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_cistatic int delta_vb2_au_start_streaming(struct vb2_queue *q,
13078c2ecf20Sopenharmony_ci					unsigned int count)
13088c2ecf20Sopenharmony_ci{
13098c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(q);
13108c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
13118c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
13128c2ecf20Sopenharmony_ci	struct delta_au *au;
13138c2ecf20Sopenharmony_ci	int ret = 0;
13148c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = NULL;
13158c2ecf20Sopenharmony_ci	struct delta_streaminfo *streaminfo = &ctx->streaminfo;
13168c2ecf20Sopenharmony_ci	struct delta_frameinfo *frameinfo = &ctx->frameinfo;
13178c2ecf20Sopenharmony_ci	unsigned char str1[100] = "";
13188c2ecf20Sopenharmony_ci	unsigned char str2[100] = "";
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	if ((ctx->state != DELTA_STATE_WF_FORMAT) &&
13218c2ecf20Sopenharmony_ci	    (ctx->state != DELTA_STATE_WF_STREAMINFO))
13228c2ecf20Sopenharmony_ci		return 0;
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	if (ctx->state == DELTA_STATE_WF_FORMAT) {
13258c2ecf20Sopenharmony_ci		/* open decoder if not yet done */
13268c2ecf20Sopenharmony_ci		ret = delta_open_decoder(ctx,
13278c2ecf20Sopenharmony_ci					 ctx->streaminfo.streamformat,
13288c2ecf20Sopenharmony_ci					 ctx->frameinfo.pixelformat, &dec);
13298c2ecf20Sopenharmony_ci		if (ret)
13308c2ecf20Sopenharmony_ci			goto err;
13318c2ecf20Sopenharmony_ci		ctx->dec = dec;
13328c2ecf20Sopenharmony_ci		ctx->state = DELTA_STATE_WF_STREAMINFO;
13338c2ecf20Sopenharmony_ci	}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	/*
13368c2ecf20Sopenharmony_ci	 * first buffer should contain stream header,
13378c2ecf20Sopenharmony_ci	 * decode it to get the infos related to stream
13388c2ecf20Sopenharmony_ci	 * such as width, height, dpb, ...
13398c2ecf20Sopenharmony_ci	 */
13408c2ecf20Sopenharmony_ci	vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
13418c2ecf20Sopenharmony_ci	if (!vbuf) {
13428c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to start streaming, no stream header buffer enqueued\n",
13438c2ecf20Sopenharmony_ci			ctx->name);
13448c2ecf20Sopenharmony_ci		ret = -EINVAL;
13458c2ecf20Sopenharmony_ci		goto err;
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci	au = to_au(vbuf);
13488c2ecf20Sopenharmony_ci	au->size = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
13498c2ecf20Sopenharmony_ci	au->dts = vbuf->vb2_buf.timestamp;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	delta_push_dts(ctx, au->dts);
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	/* dump access unit */
13548c2ecf20Sopenharmony_ci	dump_au(ctx, au);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	/* decode this access unit */
13578c2ecf20Sopenharmony_ci	ret = call_dec_op(dec, decode, ctx, au);
13588c2ecf20Sopenharmony_ci	if (ret) {
13598c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to start streaming, header decoding failed (%d)\n",
13608c2ecf20Sopenharmony_ci			ctx->name, ret);
13618c2ecf20Sopenharmony_ci		goto err;
13628c2ecf20Sopenharmony_ci	}
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	ret = call_dec_op(dec, get_streaminfo, ctx, streaminfo);
13658c2ecf20Sopenharmony_ci	if (ret) {
13668c2ecf20Sopenharmony_ci		dev_dbg_ratelimited(delta->dev,
13678c2ecf20Sopenharmony_ci				    "%s failed to start streaming, valid stream header not yet decoded\n",
13688c2ecf20Sopenharmony_ci				    ctx->name);
13698c2ecf20Sopenharmony_ci		goto err;
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci	ctx->flags |= DELTA_FLAG_STREAMINFO;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	ret = call_dec_op(dec, get_frameinfo, ctx, frameinfo);
13748c2ecf20Sopenharmony_ci	if (ret)
13758c2ecf20Sopenharmony_ci		goto err;
13768c2ecf20Sopenharmony_ci	ctx->flags |= DELTA_FLAG_FRAMEINFO;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	ctx->state = DELTA_STATE_READY;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s %s => %s\n", ctx->name,
13818c2ecf20Sopenharmony_ci		delta_streaminfo_str(streaminfo, str1, sizeof(str1)),
13828c2ecf20Sopenharmony_ci		delta_frameinfo_str(frameinfo, str2, sizeof(str2)));
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	delta_au_done(ctx, au, ret);
13858c2ecf20Sopenharmony_ci	return 0;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cierr:
13888c2ecf20Sopenharmony_ci	/*
13898c2ecf20Sopenharmony_ci	 * return all buffers to vb2 in QUEUED state.
13908c2ecf20Sopenharmony_ci	 * This will give ownership back to userspace
13918c2ecf20Sopenharmony_ci	 */
13928c2ecf20Sopenharmony_ci	if (vbuf)
13938c2ecf20Sopenharmony_ci		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
13968c2ecf20Sopenharmony_ci		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED);
13978c2ecf20Sopenharmony_ci	return ret;
13988c2ecf20Sopenharmony_ci}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_cistatic void delta_vb2_au_stop_streaming(struct vb2_queue *q)
14018c2ecf20Sopenharmony_ci{
14028c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(q);
14038c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	delta_flush_dts(ctx);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	/* return all buffers to vb2 in ERROR state */
14088c2ecf20Sopenharmony_ci	while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
14098c2ecf20Sopenharmony_ci		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	ctx->au_num = 0;
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	ctx->aborting = false;
14148c2ecf20Sopenharmony_ci}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_cistatic int delta_vb2_frame_queue_setup(struct vb2_queue *vq,
14178c2ecf20Sopenharmony_ci				       unsigned int *num_buffers,
14188c2ecf20Sopenharmony_ci				       unsigned int *num_planes,
14198c2ecf20Sopenharmony_ci				       unsigned int sizes[],
14208c2ecf20Sopenharmony_ci				       struct device *alloc_devs[])
14218c2ecf20Sopenharmony_ci{
14228c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(vq);
14238c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
14248c2ecf20Sopenharmony_ci	struct delta_streaminfo *streaminfo = &ctx->streaminfo;
14258c2ecf20Sopenharmony_ci	struct delta_frameinfo *frameinfo = &ctx->frameinfo;
14268c2ecf20Sopenharmony_ci	unsigned int size = frameinfo->size;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	/*
14298c2ecf20Sopenharmony_ci	 * the number of output buffers needed for decoding =
14308c2ecf20Sopenharmony_ci	 * user need (*num_buffers given, usually for display pipeline) +
14318c2ecf20Sopenharmony_ci	 * stream need (streaminfo->dpb) +
14328c2ecf20Sopenharmony_ci	 * decoding peak smoothing (depends on DELTA IP perf)
14338c2ecf20Sopenharmony_ci	 */
14348c2ecf20Sopenharmony_ci	if (*num_buffers < DELTA_MIN_FRAME_USER) {
14358c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
14368c2ecf20Sopenharmony_ci			"%s num_buffers too low (%d), increasing to %d\n",
14378c2ecf20Sopenharmony_ci			ctx->name, *num_buffers, DELTA_MIN_FRAME_USER);
14388c2ecf20Sopenharmony_ci		*num_buffers = DELTA_MIN_FRAME_USER;
14398c2ecf20Sopenharmony_ci	}
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	*num_buffers += streaminfo->dpb + DELTA_PEAK_FRAME_SMOOTHING;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	if (*num_buffers > DELTA_MAX_FRAMES) {
14448c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
14458c2ecf20Sopenharmony_ci			"%s output frame count too high (%d), cut to %d\n",
14468c2ecf20Sopenharmony_ci			ctx->name, *num_buffers, DELTA_MAX_FRAMES);
14478c2ecf20Sopenharmony_ci		*num_buffers = DELTA_MAX_FRAMES;
14488c2ecf20Sopenharmony_ci	}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	if (*num_planes)
14518c2ecf20Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	/* single plane for Y and CbCr */
14548c2ecf20Sopenharmony_ci	*num_planes = 1;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	sizes[0] = size;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	ctx->nb_of_frames = 0;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	return 0;
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic int delta_vb2_frame_prepare(struct vb2_buffer *vb)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	struct vb2_queue *q = vb->vb2_queue;
14668c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(q);
14678c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
14688c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
14698c2ecf20Sopenharmony_ci	struct delta_frame *frame = to_frame(vbuf);
14708c2ecf20Sopenharmony_ci	int ret = 0;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	if (!frame->prepared) {
14738c2ecf20Sopenharmony_ci		frame->index = vbuf->vb2_buf.index;
14748c2ecf20Sopenharmony_ci		frame->vaddr = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
14758c2ecf20Sopenharmony_ci		frame->paddr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
14768c2ecf20Sopenharmony_ci		frame->info = ctx->frameinfo;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci		ret = delta_setup_frame(ctx, frame);
14798c2ecf20Sopenharmony_ci		if (ret) {
14808c2ecf20Sopenharmony_ci			dev_err(delta->dev,
14818c2ecf20Sopenharmony_ci				"%s setup_frame() failed (%d)\n",
14828c2ecf20Sopenharmony_ci				ctx->name, ret);
14838c2ecf20Sopenharmony_ci			return ret;
14848c2ecf20Sopenharmony_ci		}
14858c2ecf20Sopenharmony_ci		frame->prepared = true;
14868c2ecf20Sopenharmony_ci		dev_dbg(delta->dev,
14878c2ecf20Sopenharmony_ci			"%s frame[%d] prepared; virt=0x%p, phy=0x%pad\n",
14888c2ecf20Sopenharmony_ci			ctx->name, vb->index, frame->vaddr,
14898c2ecf20Sopenharmony_ci			&frame->paddr);
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	frame->flags = vbuf->flags;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	return 0;
14958c2ecf20Sopenharmony_ci}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_cistatic void delta_vb2_frame_finish(struct vb2_buffer *vb)
14988c2ecf20Sopenharmony_ci{
14998c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
15008c2ecf20Sopenharmony_ci	struct delta_frame *frame = to_frame(vbuf);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	/* update V4L2 fields for user */
15038c2ecf20Sopenharmony_ci	vb2_set_plane_payload(&vbuf->vb2_buf, 0, frame->info.size);
15048c2ecf20Sopenharmony_ci	vb->timestamp = frame->dts;
15058c2ecf20Sopenharmony_ci	vbuf->field = frame->field;
15068c2ecf20Sopenharmony_ci	vbuf->flags = frame->flags;
15078c2ecf20Sopenharmony_ci}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_cistatic void delta_vb2_frame_queue(struct vb2_buffer *vb)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	struct vb2_queue *q = vb->vb2_queue;
15128c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(q);
15138c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
15148c2ecf20Sopenharmony_ci	struct delta_frame *frame = to_frame(vbuf);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if (ctx->state == DELTA_STATE_WF_EOS) {
15178c2ecf20Sopenharmony_ci		/* new frame available, EOS can now be completed */
15188c2ecf20Sopenharmony_ci		delta_complete_eos(ctx, frame);
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci		ctx->state = DELTA_STATE_EOS;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci		/* return, no need to recycle this buffer to decoder */
15238c2ecf20Sopenharmony_ci		return;
15248c2ecf20Sopenharmony_ci	}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	/* recycle this frame */
15278c2ecf20Sopenharmony_ci	delta_recycle(ctx, frame);
15288c2ecf20Sopenharmony_ci}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_cistatic void delta_vb2_frame_stop_streaming(struct vb2_queue *q)
15318c2ecf20Sopenharmony_ci{
15328c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = vb2_get_drv_priv(q);
15338c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
15348c2ecf20Sopenharmony_ci	struct delta_frame *frame;
15358c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
15368c2ecf20Sopenharmony_ci	unsigned int i;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	delta_flush_dts(ctx);
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	call_dec_op(dec, flush, ctx);
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	/*
15438c2ecf20Sopenharmony_ci	 * return all buffers to vb2 in ERROR state
15448c2ecf20Sopenharmony_ci	 * & reset each frame state to OUT
15458c2ecf20Sopenharmony_ci	 */
15468c2ecf20Sopenharmony_ci	for (i = 0; i < ctx->nb_of_frames; i++) {
15478c2ecf20Sopenharmony_ci		frame = ctx->frames[i];
15488c2ecf20Sopenharmony_ci		if (!(frame->state & DELTA_FRAME_OUT)) {
15498c2ecf20Sopenharmony_ci			vbuf = &frame->vbuf;
15508c2ecf20Sopenharmony_ci			v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
15518c2ecf20Sopenharmony_ci		}
15528c2ecf20Sopenharmony_ci		frame->state = DELTA_FRAME_OUT;
15538c2ecf20Sopenharmony_ci	}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	ctx->frame_num = 0;
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	ctx->aborting = false;
15588c2ecf20Sopenharmony_ci}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci/* VB2 queue ops */
15618c2ecf20Sopenharmony_cistatic const struct vb2_ops delta_vb2_au_ops = {
15628c2ecf20Sopenharmony_ci	.queue_setup = delta_vb2_au_queue_setup,
15638c2ecf20Sopenharmony_ci	.buf_prepare = delta_vb2_au_prepare,
15648c2ecf20Sopenharmony_ci	.buf_queue = delta_vb2_au_queue,
15658c2ecf20Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
15668c2ecf20Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
15678c2ecf20Sopenharmony_ci	.start_streaming = delta_vb2_au_start_streaming,
15688c2ecf20Sopenharmony_ci	.stop_streaming = delta_vb2_au_stop_streaming,
15698c2ecf20Sopenharmony_ci};
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_cistatic const struct vb2_ops delta_vb2_frame_ops = {
15728c2ecf20Sopenharmony_ci	.queue_setup = delta_vb2_frame_queue_setup,
15738c2ecf20Sopenharmony_ci	.buf_prepare = delta_vb2_frame_prepare,
15748c2ecf20Sopenharmony_ci	.buf_finish = delta_vb2_frame_finish,
15758c2ecf20Sopenharmony_ci	.buf_queue = delta_vb2_frame_queue,
15768c2ecf20Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
15778c2ecf20Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
15788c2ecf20Sopenharmony_ci	.stop_streaming = delta_vb2_frame_stop_streaming,
15798c2ecf20Sopenharmony_ci};
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci/*
15828c2ecf20Sopenharmony_ci * V4L2 file operations
15838c2ecf20Sopenharmony_ci */
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_cistatic int queue_init(void *priv,
15868c2ecf20Sopenharmony_ci		      struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
15878c2ecf20Sopenharmony_ci{
15888c2ecf20Sopenharmony_ci	struct vb2_queue *q;
15898c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = priv;
15908c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
15918c2ecf20Sopenharmony_ci	int ret;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	/* setup vb2 queue for stream input */
15948c2ecf20Sopenharmony_ci	q = src_vq;
15958c2ecf20Sopenharmony_ci	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
15968c2ecf20Sopenharmony_ci	q->io_modes = VB2_MMAP | VB2_DMABUF;
15978c2ecf20Sopenharmony_ci	q->drv_priv = ctx;
15988c2ecf20Sopenharmony_ci	/* overload vb2 buf with private au struct */
15998c2ecf20Sopenharmony_ci	q->buf_struct_size = sizeof(struct delta_au);
16008c2ecf20Sopenharmony_ci	q->ops = &delta_vb2_au_ops;
16018c2ecf20Sopenharmony_ci	q->mem_ops = &vb2_dma_contig_memops;
16028c2ecf20Sopenharmony_ci	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
16038c2ecf20Sopenharmony_ci	q->lock = &delta->lock;
16048c2ecf20Sopenharmony_ci	q->dev = delta->dev;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	ret = vb2_queue_init(q);
16078c2ecf20Sopenharmony_ci	if (ret)
16088c2ecf20Sopenharmony_ci		return ret;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	/* setup vb2 queue for frame output */
16118c2ecf20Sopenharmony_ci	q = dst_vq;
16128c2ecf20Sopenharmony_ci	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
16138c2ecf20Sopenharmony_ci	q->io_modes = VB2_MMAP | VB2_DMABUF;
16148c2ecf20Sopenharmony_ci	q->drv_priv = ctx;
16158c2ecf20Sopenharmony_ci	/* overload vb2 buf with private frame struct */
16168c2ecf20Sopenharmony_ci	q->buf_struct_size = sizeof(struct delta_frame)
16178c2ecf20Sopenharmony_ci			     + DELTA_MAX_FRAME_PRIV_SIZE;
16188c2ecf20Sopenharmony_ci	q->ops = &delta_vb2_frame_ops;
16198c2ecf20Sopenharmony_ci	q->mem_ops = &vb2_dma_contig_memops;
16208c2ecf20Sopenharmony_ci	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
16218c2ecf20Sopenharmony_ci	q->lock = &delta->lock;
16228c2ecf20Sopenharmony_ci	q->dev = delta->dev;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	return vb2_queue_init(q);
16258c2ecf20Sopenharmony_ci}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_cistatic int delta_open(struct file *file)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	struct delta_dev *delta = video_drvdata(file);
16308c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = NULL;
16318c2ecf20Sopenharmony_ci	int ret = 0;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	mutex_lock(&delta->lock);
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
16368c2ecf20Sopenharmony_ci	if (!ctx) {
16378c2ecf20Sopenharmony_ci		ret = -ENOMEM;
16388c2ecf20Sopenharmony_ci		goto err;
16398c2ecf20Sopenharmony_ci	}
16408c2ecf20Sopenharmony_ci	ctx->dev = delta;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	v4l2_fh_init(&ctx->fh, video_devdata(file));
16438c2ecf20Sopenharmony_ci	file->private_data = &ctx->fh;
16448c2ecf20Sopenharmony_ci	v4l2_fh_add(&ctx->fh);
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	INIT_WORK(&ctx->run_work, delta_run_work);
16478c2ecf20Sopenharmony_ci	mutex_init(&ctx->lock);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(delta->m2m_dev, ctx,
16508c2ecf20Sopenharmony_ci					    queue_init);
16518c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->fh.m2m_ctx)) {
16528c2ecf20Sopenharmony_ci		ret = PTR_ERR(ctx->fh.m2m_ctx);
16538c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to initialize m2m context (%d)\n",
16548c2ecf20Sopenharmony_ci			DELTA_PREFIX, ret);
16558c2ecf20Sopenharmony_ci		goto err_fh_del;
16568c2ecf20Sopenharmony_ci	}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	/*
16598c2ecf20Sopenharmony_ci	 * wait stream format to determine which
16608c2ecf20Sopenharmony_ci	 * decoder to open
16618c2ecf20Sopenharmony_ci	 */
16628c2ecf20Sopenharmony_ci	ctx->state = DELTA_STATE_WF_FORMAT;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->dts);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	/* set the instance name */
16678c2ecf20Sopenharmony_ci	delta->instance_id++;
16688c2ecf20Sopenharmony_ci	snprintf(ctx->name, sizeof(ctx->name), "[%3d:----]",
16698c2ecf20Sopenharmony_ci		 delta->instance_id);
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	/* default parameters for frame and stream */
16728c2ecf20Sopenharmony_ci	set_default_params(ctx);
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	/* enable ST231 clocks */
16758c2ecf20Sopenharmony_ci	if (delta->clk_st231)
16768c2ecf20Sopenharmony_ci		if (clk_prepare_enable(delta->clk_st231))
16778c2ecf20Sopenharmony_ci			dev_warn(delta->dev, "failed to enable st231 clk\n");
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	/* enable FLASH_PROMIP clock */
16808c2ecf20Sopenharmony_ci	if (delta->clk_flash_promip)
16818c2ecf20Sopenharmony_ci		if (clk_prepare_enable(delta->clk_flash_promip))
16828c2ecf20Sopenharmony_ci			dev_warn(delta->dev, "failed to enable delta promip clk\n");
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	mutex_unlock(&delta->lock);
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s decoder instance created\n", ctx->name);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	return 0;
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_cierr_fh_del:
16918c2ecf20Sopenharmony_ci	v4l2_fh_del(&ctx->fh);
16928c2ecf20Sopenharmony_ci	v4l2_fh_exit(&ctx->fh);
16938c2ecf20Sopenharmony_ci	kfree(ctx);
16948c2ecf20Sopenharmony_cierr:
16958c2ecf20Sopenharmony_ci	mutex_unlock(&delta->lock);
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	return ret;
16988c2ecf20Sopenharmony_ci}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_cistatic int delta_release(struct file *file)
17018c2ecf20Sopenharmony_ci{
17028c2ecf20Sopenharmony_ci	struct delta_ctx *ctx = to_ctx(file->private_data);
17038c2ecf20Sopenharmony_ci	struct delta_dev *delta = ctx->dev;
17048c2ecf20Sopenharmony_ci	const struct delta_dec *dec = ctx->dec;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	mutex_lock(&delta->lock);
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	/* close decoder */
17098c2ecf20Sopenharmony_ci	call_dec_op(dec, close, ctx);
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	/*
17128c2ecf20Sopenharmony_ci	 * trace a summary of instance
17138c2ecf20Sopenharmony_ci	 * before closing (debug purpose)
17148c2ecf20Sopenharmony_ci	 */
17158c2ecf20Sopenharmony_ci	delta_trace_summary(ctx);
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	v4l2_fh_del(&ctx->fh);
17208c2ecf20Sopenharmony_ci	v4l2_fh_exit(&ctx->fh);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	/* disable ST231 clocks */
17238c2ecf20Sopenharmony_ci	if (delta->clk_st231)
17248c2ecf20Sopenharmony_ci		clk_disable_unprepare(delta->clk_st231);
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	/* disable FLASH_PROMIP clock */
17278c2ecf20Sopenharmony_ci	if (delta->clk_flash_promip)
17288c2ecf20Sopenharmony_ci		clk_disable_unprepare(delta->clk_flash_promip);
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	dev_dbg(delta->dev, "%s decoder instance released\n", ctx->name);
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	kfree(ctx);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	mutex_unlock(&delta->lock);
17358c2ecf20Sopenharmony_ci	return 0;
17368c2ecf20Sopenharmony_ci}
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci/* V4L2 file ops */
17398c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations delta_fops = {
17408c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
17418c2ecf20Sopenharmony_ci	.open = delta_open,
17428c2ecf20Sopenharmony_ci	.release = delta_release,
17438c2ecf20Sopenharmony_ci	.unlocked_ioctl = video_ioctl2,
17448c2ecf20Sopenharmony_ci	.mmap = v4l2_m2m_fop_mmap,
17458c2ecf20Sopenharmony_ci	.poll = v4l2_m2m_fop_poll,
17468c2ecf20Sopenharmony_ci};
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci/*
17498c2ecf20Sopenharmony_ci * Platform device operations
17508c2ecf20Sopenharmony_ci */
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_cistatic int delta_register_device(struct delta_dev *delta)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	int ret;
17558c2ecf20Sopenharmony_ci	struct video_device *vdev;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	if (!delta)
17588c2ecf20Sopenharmony_ci		return -ENODEV;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	delta->m2m_dev = v4l2_m2m_init(&delta_m2m_ops);
17618c2ecf20Sopenharmony_ci	if (IS_ERR(delta->m2m_dev)) {
17628c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to initialize v4l2-m2m device\n",
17638c2ecf20Sopenharmony_ci			DELTA_PREFIX);
17648c2ecf20Sopenharmony_ci		ret = PTR_ERR(delta->m2m_dev);
17658c2ecf20Sopenharmony_ci		goto err;
17668c2ecf20Sopenharmony_ci	}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	vdev = video_device_alloc();
17698c2ecf20Sopenharmony_ci	if (!vdev) {
17708c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to allocate video device\n",
17718c2ecf20Sopenharmony_ci			DELTA_PREFIX);
17728c2ecf20Sopenharmony_ci		ret = -ENOMEM;
17738c2ecf20Sopenharmony_ci		goto err_m2m_release;
17748c2ecf20Sopenharmony_ci	}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	vdev->fops = &delta_fops;
17778c2ecf20Sopenharmony_ci	vdev->ioctl_ops = &delta_ioctl_ops;
17788c2ecf20Sopenharmony_ci	vdev->release = video_device_release;
17798c2ecf20Sopenharmony_ci	vdev->lock = &delta->lock;
17808c2ecf20Sopenharmony_ci	vdev->vfl_dir = VFL_DIR_M2M;
17818c2ecf20Sopenharmony_ci	vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
17828c2ecf20Sopenharmony_ci	vdev->v4l2_dev = &delta->v4l2_dev;
17838c2ecf20Sopenharmony_ci	snprintf(vdev->name, sizeof(vdev->name), "%s-%s",
17848c2ecf20Sopenharmony_ci		 DELTA_NAME, DELTA_FW_VERSION);
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
17878c2ecf20Sopenharmony_ci	if (ret) {
17888c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to register video device\n",
17898c2ecf20Sopenharmony_ci			DELTA_PREFIX);
17908c2ecf20Sopenharmony_ci		goto err_vdev_release;
17918c2ecf20Sopenharmony_ci	}
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	delta->vdev = vdev;
17948c2ecf20Sopenharmony_ci	video_set_drvdata(vdev, delta);
17958c2ecf20Sopenharmony_ci	return 0;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_cierr_vdev_release:
17988c2ecf20Sopenharmony_ci	video_device_release(vdev);
17998c2ecf20Sopenharmony_cierr_m2m_release:
18008c2ecf20Sopenharmony_ci	v4l2_m2m_release(delta->m2m_dev);
18018c2ecf20Sopenharmony_cierr:
18028c2ecf20Sopenharmony_ci	return ret;
18038c2ecf20Sopenharmony_ci}
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_cistatic void delta_unregister_device(struct delta_dev *delta)
18068c2ecf20Sopenharmony_ci{
18078c2ecf20Sopenharmony_ci	if (!delta)
18088c2ecf20Sopenharmony_ci		return;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	if (delta->m2m_dev)
18118c2ecf20Sopenharmony_ci		v4l2_m2m_release(delta->m2m_dev);
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	video_unregister_device(delta->vdev);
18148c2ecf20Sopenharmony_ci}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_cistatic int delta_probe(struct platform_device *pdev)
18178c2ecf20Sopenharmony_ci{
18188c2ecf20Sopenharmony_ci	struct delta_dev *delta;
18198c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
18208c2ecf20Sopenharmony_ci	int ret;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	delta = devm_kzalloc(dev, sizeof(*delta), GFP_KERNEL);
18238c2ecf20Sopenharmony_ci	if (!delta) {
18248c2ecf20Sopenharmony_ci		ret = -ENOMEM;
18258c2ecf20Sopenharmony_ci		goto err;
18268c2ecf20Sopenharmony_ci	}
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	delta->dev = dev;
18298c2ecf20Sopenharmony_ci	delta->pdev = pdev;
18308c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, delta);
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	mutex_init(&delta->lock);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	/* get clock resources */
18358c2ecf20Sopenharmony_ci	delta->clk_delta = devm_clk_get(dev, "delta");
18368c2ecf20Sopenharmony_ci	if (IS_ERR(delta->clk_delta)) {
18378c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s can't get delta clock\n", DELTA_PREFIX);
18388c2ecf20Sopenharmony_ci		delta->clk_delta = NULL;
18398c2ecf20Sopenharmony_ci	}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	delta->clk_st231 = devm_clk_get(dev, "delta-st231");
18428c2ecf20Sopenharmony_ci	if (IS_ERR(delta->clk_st231)) {
18438c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s can't get delta-st231 clock\n", DELTA_PREFIX);
18448c2ecf20Sopenharmony_ci		delta->clk_st231 = NULL;
18458c2ecf20Sopenharmony_ci	}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	delta->clk_flash_promip = devm_clk_get(dev, "delta-flash-promip");
18488c2ecf20Sopenharmony_ci	if (IS_ERR(delta->clk_flash_promip)) {
18498c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s can't get delta-flash-promip clock\n",
18508c2ecf20Sopenharmony_ci			DELTA_PREFIX);
18518c2ecf20Sopenharmony_ci		delta->clk_flash_promip = NULL;
18528c2ecf20Sopenharmony_ci	}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	/* init pm_runtime used for power management */
18558c2ecf20Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, DELTA_HW_AUTOSUSPEND_DELAY_MS);
18568c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
18578c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(dev);
18588c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	/* init firmware ipc channel */
18618c2ecf20Sopenharmony_ci	ret = delta_ipc_init(delta);
18628c2ecf20Sopenharmony_ci	if (ret) {
18638c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to initialize firmware ipc channel\n",
18648c2ecf20Sopenharmony_ci			DELTA_PREFIX);
18658c2ecf20Sopenharmony_ci		goto err_pm_disable;
18668c2ecf20Sopenharmony_ci	}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	/* register all available decoders */
18698c2ecf20Sopenharmony_ci	register_decoders(delta);
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	/* register all supported formats */
18728c2ecf20Sopenharmony_ci	register_formats(delta);
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	/* register on V4L2 */
18758c2ecf20Sopenharmony_ci	ret = v4l2_device_register(dev, &delta->v4l2_dev);
18768c2ecf20Sopenharmony_ci	if (ret) {
18778c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to register V4L2 device\n",
18788c2ecf20Sopenharmony_ci			DELTA_PREFIX);
18798c2ecf20Sopenharmony_ci		goto err_pm_disable;
18808c2ecf20Sopenharmony_ci	}
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	delta->work_queue = create_workqueue(DELTA_NAME);
18838c2ecf20Sopenharmony_ci	if (!delta->work_queue) {
18848c2ecf20Sopenharmony_ci		dev_err(delta->dev, "%s failed to allocate work queue\n",
18858c2ecf20Sopenharmony_ci			DELTA_PREFIX);
18868c2ecf20Sopenharmony_ci		ret = -ENOMEM;
18878c2ecf20Sopenharmony_ci		goto err_v4l2;
18888c2ecf20Sopenharmony_ci	}
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	/* register device */
18918c2ecf20Sopenharmony_ci	ret = delta_register_device(delta);
18928c2ecf20Sopenharmony_ci	if (ret)
18938c2ecf20Sopenharmony_ci		goto err_work_queue;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	dev_info(dev, "%s %s registered as /dev/video%d\n",
18968c2ecf20Sopenharmony_ci		 DELTA_PREFIX, delta->vdev->name, delta->vdev->num);
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	return 0;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_cierr_work_queue:
19018c2ecf20Sopenharmony_ci	destroy_workqueue(delta->work_queue);
19028c2ecf20Sopenharmony_cierr_v4l2:
19038c2ecf20Sopenharmony_ci	v4l2_device_unregister(&delta->v4l2_dev);
19048c2ecf20Sopenharmony_cierr_pm_disable:
19058c2ecf20Sopenharmony_ci	pm_runtime_disable(dev);
19068c2ecf20Sopenharmony_cierr:
19078c2ecf20Sopenharmony_ci	return ret;
19088c2ecf20Sopenharmony_ci}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_cistatic int delta_remove(struct platform_device *pdev)
19118c2ecf20Sopenharmony_ci{
19128c2ecf20Sopenharmony_ci	struct delta_dev *delta = platform_get_drvdata(pdev);
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	delta_ipc_exit(delta);
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	delta_unregister_device(delta);
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	destroy_workqueue(delta->work_queue);
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(delta->dev);
19218c2ecf20Sopenharmony_ci	pm_runtime_disable(delta->dev);
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	v4l2_device_unregister(&delta->v4l2_dev);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	return 0;
19268c2ecf20Sopenharmony_ci}
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_cistatic int delta_runtime_suspend(struct device *dev)
19298c2ecf20Sopenharmony_ci{
19308c2ecf20Sopenharmony_ci	struct delta_dev *delta = dev_get_drvdata(dev);
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	if (delta->clk_delta)
19338c2ecf20Sopenharmony_ci		clk_disable_unprepare(delta->clk_delta);
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	return 0;
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_cistatic int delta_runtime_resume(struct device *dev)
19398c2ecf20Sopenharmony_ci{
19408c2ecf20Sopenharmony_ci	struct delta_dev *delta = dev_get_drvdata(dev);
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	if (delta->clk_delta)
19438c2ecf20Sopenharmony_ci		if (clk_prepare_enable(delta->clk_delta))
19448c2ecf20Sopenharmony_ci			dev_warn(dev, "failed to prepare/enable delta clk\n");
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	return 0;
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci/* PM ops */
19508c2ecf20Sopenharmony_cistatic const struct dev_pm_ops delta_pm_ops = {
19518c2ecf20Sopenharmony_ci	.runtime_suspend = delta_runtime_suspend,
19528c2ecf20Sopenharmony_ci	.runtime_resume = delta_runtime_resume,
19538c2ecf20Sopenharmony_ci};
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_cistatic const struct of_device_id delta_match_types[] = {
19568c2ecf20Sopenharmony_ci	{
19578c2ecf20Sopenharmony_ci	 .compatible = "st,st-delta",
19588c2ecf20Sopenharmony_ci	},
19598c2ecf20Sopenharmony_ci	{
19608c2ecf20Sopenharmony_ci	 /* end node */
19618c2ecf20Sopenharmony_ci	}
19628c2ecf20Sopenharmony_ci};
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, delta_match_types);
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_cistatic struct platform_driver delta_driver = {
19678c2ecf20Sopenharmony_ci	.probe = delta_probe,
19688c2ecf20Sopenharmony_ci	.remove = delta_remove,
19698c2ecf20Sopenharmony_ci	.driver = {
19708c2ecf20Sopenharmony_ci		   .name = DELTA_NAME,
19718c2ecf20Sopenharmony_ci		   .of_match_table = delta_match_types,
19728c2ecf20Sopenharmony_ci		   .pm = &delta_pm_ops},
19738c2ecf20Sopenharmony_ci};
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_cimodule_platform_driver(delta_driver);
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
19788c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hugues Fruchet <hugues.fruchet@st.com>");
19798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics DELTA video decoder V4L2 driver");
1980