// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
* Tiffany Lin <tiffany.lin@mediatek.com>
*/
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-dma-contig.h>
#include "mtk_vcodec_dec_drv.h"
#include "mtk_vcodec_dec.h"
#include "vdec_drv_if.h"
#include "mtk_vcodec_dec_pm.h"
#define DFT_CFG_WIDTH MTK_VDEC_MIN_W
#define DFT_CFG_HEIGHT MTK_VDEC_MIN_H
static const struct mtk_video_fmt *
mtk_vdec_find_format(struct v4l2_format *f,
const struct mtk_vcodec_dec_pdata *dec_pdata)
{
const struct mtk_video_fmt *fmt;
unsigned int k;
for (k = 0; k < *dec_pdata->num_formats; k++) {
fmt = &dec_pdata->vdec_formats[k];
if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
return fmt;
}
return NULL;
}
static bool mtk_vdec_get_cap_fmt(struct mtk_vcodec_dec_ctx *ctx, int format_index)
{
const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
const struct mtk_video_fmt *fmt;
struct mtk_q_data *q_data;
int num_frame_count = 0, i;
bool ret = false;
fmt = &dec_pdata->vdec_formats[format_index];
for (i = 0; i < *dec_pdata->num_formats; i++) {
if (dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME)
continue;
num_frame_count++;
}
if (num_frame_count == 1 || (!ctx->is_10bit_bitstream && fmt->fourcc == V4L2_PIX_FMT_MM21))
return true;
q_data = &ctx->q_data[MTK_Q_DATA_SRC];
switch (q_data->fmt->fourcc) {
case V4L2_PIX_FMT_H264_SLICE:
if (ctx->is_10bit_bitstream && fmt->fourcc == V4L2_PIX_FMT_MT2110R)
ret = true;
break;
case V4L2_PIX_FMT_VP9_FRAME:
case V4L2_PIX_FMT_AV1_FRAME:
case V4L2_PIX_FMT_HEVC_SLICE:
if (ctx->is_10bit_bitstream && fmt->fourcc == V4L2_PIX_FMT_MT2110T)
ret = true;
break;
default:
break;
}
return ret;
}
static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_dec_ctx *ctx,
enum v4l2_buf_type type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
return &ctx->q_data[MTK_Q_DATA_SRC];
return &ctx->q_data[MTK_Q_DATA_DST];
}
static int stateful_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
{
return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd);
}
static int stateful_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
{
struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
struct vb2_queue *src_vq, *dst_vq;
int ret;
ret = stateful_try_decoder_cmd(file, priv, cmd);
if (ret)
return ret;
mtk_v4l2_vdec_dbg(1, ctx, "decoder cmd=%u", cmd->cmd);
dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
switch (cmd->cmd) {
case V4L2_DEC_CMD_STOP:
src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (!vb2_is_streaming(src_vq)) {
mtk_v4l2_vdec_dbg(1, ctx, "Output stream is off. No need to flush.");
return 0;
}
if (!vb2_is_streaming(dst_vq)) {
mtk_v4l2_vdec_dbg(1, ctx, "Capture stream is off. No need to flush.");
return 0;
}
v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf.vb);
v4l2_m2m_try_schedule(ctx->m2m_ctx);
break;
case V4L2_DEC_CMD_START:
vb2_clear_last_buffer_dequeued(dst_vq);
break;
default:
return -EINVAL;
}
return 0;
}
static int stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
{
return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd);
}
static int stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
{
struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
int ret;
ret = v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd);
if (ret)
return ret;
mtk_v4l2_vdec_dbg(3, ctx, "decoder cmd=%u", cmd->cmd);
switch (cmd->cmd) {
case V4L2_DEC_CMD_FLUSH:
/*
* If the flag of the output buffer is equals V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF,
* this command will prevent dequeueing the capture buffer containing the last
* decoded frame. Or do nothing
*/
break;
default:
mtk_v4l2_vdec_err(ctx, "invalid stateless decoder cmd=%u", cmd->cmd);
return -EINVAL;
}
return 0;
}
static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
{
struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
if (ctx->dev->vdec_pdata->uses_stateless_api)
return stateless_try_decoder_cmd(file