// SPDX-License-Identifier: GPL-2.0
/*
* Rockchip Video Decoder driver
*
* Copyright (C) 2019 Collabora, Ltd.
*
* Based on rkvdec driver by Google LLC. (Tomasz Figa <tfiga@chromium.org>)
* Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-vmalloc.h>
#include "rkvdec.h"
#include "rkvdec-regs.h"
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) {
const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
/*
* TODO: The hardware supports 10-bit and 4:2:2 profiles,
* but it's currently broken in the driver.
* Reject them for now, until it's fixed.
*/
if (sps->chroma_format_idc > 1)
/* Only 4:0:0 and 4:2:0 are supported */
return -EINVAL;
if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
/* Luma and chroma bit depth mismatch */
return -EINVAL;
if (sps->bit_depth_luma_minus8 != 0)
/* Only 8-bit is supported */
return -EINVAL;
}
return 0;
}
static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = {
.try_ctrl = rkvdec_try_ctrl,
};
static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
{
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
},
{
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_SPS,
.cfg.ops = &rkvdec_ctrl_ops,
},
{
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS,
},
{
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
},
{
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE,
.cfg.min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
.cfg.max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
.cfg.def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
},
{
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_START_CODE,
.cfg.min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
.cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
.cfg.max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
},
};
static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
.ctrls = rkvdec_h264_ctrl_descs,
.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
};
static const u32 rkvdec_h264_decoded_fmts[] = {
V4L2_PIX_FMT_NV12,
};
static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_H264_SLICE,
.frmsize = {
.min_width = 48,
.max_width = 4096,
.step_width = 16,
.min_height = 48,
.max_height = 2304,
.step_height = 16,
},
.ctrls = &rkvdec_h264_ctrls,
.ops = &rkvdec_h264_fmt_ops,
.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
.decoded_fmts = rkvdec_h264_decoded_fmts,
}
};
static const struct rkvdec_coded_fmt_desc *
rkvdec_find_coded_fmt_desc(u32 fourcc)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
if (rkvdec_coded_fmts[i].fourcc == fourcc)
return &rkvdec_coded_fmts[i];
}