Commit 9047c326 authored by Ezequiel Garcia's avatar Ezequiel Garcia

rockchip/vpu: Add H264 decoder

Signed-off-by: Ezequiel Garcia's avatarEzequiel Garcia <ezequiel@collabora.com>
parent cf93368f
......@@ -9,4 +9,6 @@ rockchip-vpu-y += \
rk3399_vpu_hw.o \
rk3399_vpu_hw_jpeg_enc.o \
rk3399_vpu_hw_vp8_dec.o \
rk3399_vdec_hw.o \
rk3399_vdec_hw_h264.o \
rockchip_vpu_jpeg.o
// SPDX-License-Identifier: GPL-2.0
/*
* Rockchip VPU codec driver
*
* Copyright (C) 2018 Rockchip Electronics Co., Ltd.
* Jeffy Chen <jeffy.chen@rock-chips.com>
*/
#include <linux/clk.h>
#include "rockchip_vpu.h"
#include "rk3399_vdec_regs.h"
#define RK3399_ACLK_MAX_FREQ (500 * 1000 * 1000)
/*
* Supported formats.
*/
static const struct rockchip_vpu_fmt rk3399_vdec_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_NV12,
.codec_mode = RK_VPU_MODE_NONE,
},
{
.fourcc = V4L2_PIX_FMT_H264_SLICE,
.codec_mode = RK_VPU_MODE_H264_DEC,
.max_depth = 2,
.frmsize = {
.min_width = 48,
.max_width = 3840,
.step_width = H264_MB_DIM,
.min_height = 48,
.max_height = 2160,
.step_height = H264_MB_DIM,
},
},
};
static irqreturn_t rk3399_vdec_irq(int irq, void *dev_id)
{
struct rockchip_vpu_dev *vpu = dev_id;
u32 status = vdpu_read(vpu, RKVDEC_REG_INTERRUPT);
vdpu_write(vpu, 0, RKVDEC_REG_INTERRUPT);
rockchip_vpu_irq_done(vpu,
0,
status & RKVDEC_RDY_STA ?
VB2_BUF_STATE_DONE :
VB2_BUF_STATE_ERROR);
return IRQ_HANDLED;
}
static int rk3399_vdec_hw_init(struct rockchip_vpu_dev *vpu)
{
/* Bump ACLK to max. possible freq. to improve performance. */
clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ);
return 0;
}
static void rk3399_vdec_reset(struct rockchip_vpu_ctx *ctx)
{
struct rockchip_vpu_dev *vpu = ctx->dev;
vdpu_write(vpu, RKVDEC_IRQ_DIS, RKVDEC_REG_INTERRUPT);
vdpu_write(vpu, 0, RKVDEC_REG_SYSCTRL);
}
/*
* Supported codec ops.
*/
static const struct rockchip_vpu_codec_ops rk3399_vdec_codec_ops[] = {
[RK_VPU_MODE_H264_DEC] = {
.start = rk3399_vdec_h264_start,
.stop = rk3399_vdec_h264_stop,
.run = rk3399_vdec_h264_run,
.reset = rk3399_vdec_reset,
},
};
const struct rockchip_vpu_variant rk3399_vdec_variant = {
.dec_offset = 0x0,
.dec_fmts = rk3399_vdec_fmts,
.num_dec_fmts = ARRAY_SIZE(rk3399_vdec_fmts),
.codec = RK_VPU_CODEC_H264,
.codec_ops = rk3399_vdec_codec_ops,
.vdpu_irq = rk3399_vdec_irq,
.init = rk3399_vdec_hw_init,
.clk_names = {"aclk", "hclk", "sclk_cabac", "sclk_core"},
.num_clocks = 4
};
This diff is collapsed.
This diff is collapsed.
......@@ -758,11 +758,16 @@ void rk3399_vpu_vp8_dec_run(struct rockchip_vpu_ctx *ctx)
struct rockchip_vpu_run run = { NULL };
size_t height = ctx->dst_fmt.height;
size_t width = ctx->dst_fmt.width;
struct media_request *src_req;
u32 mb_width, mb_height;
u32 reg;
run.src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
run.dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
src_req = run.src_buf->req_obj.req;
v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler);
run.vp8_dec.frame_header = rockchip_vpu_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HDR);
if (!run.vp8_dec.frame_header) {
vpu_err("failed to find vp8 frame header control\n");
......@@ -831,6 +836,8 @@ void rk3399_vpu_vp8_dec_run(struct rockchip_vpu_ctx *ctx)
rk3399_vp8_dec_cfg_ref(ctx, &run);
rk3399_vp8_dec_cfg_buffers(ctx, &run);
v4l2_ctrl_request_complete(src_req, &ctx->ctrl_handler);
/* Kick the watchdog and start decoding */
schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
......
......@@ -28,6 +28,9 @@
#define ROCKCHIP_VPU_MAX_CTRLS 32
#define ROCKCHIP_VPU_MAX_CLOCKS 4
#define H264_MB_DIM 16
#define H264_MB_WIDTH(w) DIV_ROUND_UP(w, H264_MB_DIM)
#define H264_MB_HEIGHT(h) DIV_ROUND_UP(h, H264_MB_DIM)
#define VP8_MB_DIM 16
#define VP8_MB_WIDTH(w) DIV_ROUND_UP(w, VP8_MB_DIM)
#define VP8_MB_HEIGHT(h) DIV_ROUND_UP(h, VP8_MB_DIM)
......@@ -40,6 +43,7 @@ struct rockchip_vpu_codec_ops;
#define RK_VPU_CODEC_JPEG BIT(0)
#define RK_VPU_CODEC_VP8 BIT(1)
#define RK_VPU_CODEC_H264 BIT(2)
/**
* struct rockchip_vpu_variant - information about VPU hardware variant
......@@ -84,6 +88,7 @@ enum rockchip_vpu_codec_mode {
RK_VPU_MODE_NONE = -1,
RK_VPU_MODE_JPEG_ENC,
RK_VPU_MODE_VP8_DEC,
RK_VPU_MODE_H264_DEC,
};
/*
......@@ -216,6 +221,7 @@ struct rockchip_vpu_ctx {
/* Specific for particular codec modes. */
union {
struct rockchip_vpu_vp8_dec_hw_ctx vp8_dec_ctx;
struct rockchip_vpu_h264_dec_hw_ctx h264_dec_ctx;
};
};
......
......@@ -305,6 +305,41 @@ static struct rockchip_vpu_ctrl controls[] = {
.elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header),
},
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
.codec = RK_VPU_CODEC_H264,
.cfg = {
.elem_size = sizeof(struct v4l2_ctrl_h264_decode_param),
},
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
.codec = RK_VPU_CODEC_H264,
.cfg = {
.elem_size = sizeof(struct v4l2_ctrl_h264_slice_param),
},
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_SPS,
.codec = RK_VPU_CODEC_H264,
.cfg = {
.elem_size = sizeof(struct v4l2_ctrl_h264_sps),
},
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_PPS,
.codec = RK_VPU_CODEC_H264,
.cfg = {
.elem_size = sizeof(struct v4l2_ctrl_h264_pps),
},
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
.codec = RK_VPU_CODEC_H264,
.cfg = {
.elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix),
},
},
};
static int rockchip_vpu_ctrls_setup(struct rockchip_vpu_dev *vpu,
......@@ -442,6 +477,7 @@ static const struct v4l2_file_operations rockchip_vpu_fops = {
static const struct of_device_id of_rockchip_vpu_match[] = {
{ .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
{ .compatible = "rockchip,rk3399-vdec", .data = &rk3399_vdec_variant, },
{ .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
{ /* sentinel */ }
};
......
......@@ -39,6 +39,15 @@ struct rockchip_vpu_vp8_dec_hw_ctx {
struct rockchip_vpu_aux_buf prob_table;
};
/**
* struct rockchip_vpu_h264_dec_hw_ctx - Per context data specific to H264
* decoding.
* @priv_tbl: Private auxiliary buffer for hardware.
*/
struct rockchip_vpu_h264_dec_hw_ctx {
struct rockchip_vpu_aux_buf priv;
};
/**
* struct rockchip_vpu_codec_ops - codec mode specific operations
*
......@@ -68,6 +77,7 @@ enum rockchip_vpu_enc_fmt {
};
extern const struct rockchip_vpu_variant rk3399_vpu_variant;
extern const struct rockchip_vpu_variant rk3399_vdec_variant;
extern const struct rockchip_vpu_variant rk3288_vpu_variant;
void rockchip_vpu_watchdog(struct work_struct *work);
......@@ -83,4 +93,8 @@ int rk3399_vpu_vp8_dec_start(struct rockchip_vpu_ctx *ctx);
void rk3399_vpu_vp8_dec_stop(struct rockchip_vpu_ctx *ctx);
void rk3399_vpu_vp8_dec_run(struct rockchip_vpu_ctx *ctx);
int rk3399_vdec_h264_start(struct rockchip_vpu_ctx *ctx);
void rk3399_vdec_h264_stop(struct rockchip_vpu_ctx *ctx);
void rk3399_vdec_h264_run(struct rockchip_vpu_ctx *ctx);
#endif /* ROCKCHIP_VPU_HW_H_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment