mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
CHROMIUM: [media] rockchip-vpu: reconstructs hw codes for futher chips
Change-Id: I3ad3a5220d5dc5b952d9e0e11f7142bc30a144f9 Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> Signed-off-by: Yakir Yang <ykk@rock-chips.com>
This commit is contained in:
@@ -5,6 +5,7 @@ rockchip-vpu-y += rockchip_vpu.o \
|
||||
rockchip_vpu_dec.o \
|
||||
rockchip_vpu_enc.o \
|
||||
rockchip_vpu_hw.o \
|
||||
rk3288_vpu_hw.o \
|
||||
rk3288_vpu_hw_h264d.o \
|
||||
rk3288_vpu_hw_vp8d.o \
|
||||
rk3288_vpu_hw_vp8e.o
|
||||
|
||||
74
drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.c
Normal file
74
drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Rockchip VPU codec driver
|
||||
*
|
||||
* Copyright (C) 2016 Rockchip Electronics Co., Ltd.
|
||||
* Jeffy Chen <jeffy.chen@rock-chips.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "rockchip_vpu_common.h"
|
||||
|
||||
#include "rk3288_vpu_regs.h"
|
||||
|
||||
/*
|
||||
* Interrupt handlers.
|
||||
*/
|
||||
|
||||
int rk3288_vpu_enc_irq(int irq, struct rockchip_vpu_dev *vpu)
|
||||
{
|
||||
u32 status = vepu_read(vpu, VEPU_REG_INTERRUPT);
|
||||
|
||||
vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
|
||||
|
||||
if (status & VEPU_REG_INTERRUPT_BIT) {
|
||||
vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rk3288_vpu_dec_irq(int irq, struct rockchip_vpu_dev *vpu)
|
||||
{
|
||||
u32 status = vdpu_read(vpu, VDPU_REG_INTERRUPT);
|
||||
|
||||
vdpu_write(vpu, 0, VDPU_REG_INTERRUPT);
|
||||
|
||||
vpu_debug(3, "vdpu_irq status: %08x\n", status);
|
||||
|
||||
if (status & VDPU_REG_INTERRUPT_DEC_IRQ) {
|
||||
vdpu_write(vpu, 0, VDPU_REG_CONFIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialization/clean-up.
|
||||
*/
|
||||
|
||||
void rk3288_vpu_enc_reset(struct rockchip_vpu_ctx *ctx)
|
||||
{
|
||||
struct rockchip_vpu_dev *vpu = ctx->dev;
|
||||
|
||||
vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
|
||||
vepu_write(vpu, 0, VEPU_REG_ENC_CTRL);
|
||||
vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
|
||||
}
|
||||
|
||||
void rk3288_vpu_dec_reset(struct rockchip_vpu_ctx *ctx)
|
||||
{
|
||||
struct rockchip_vpu_dev *vpu = ctx->dev;
|
||||
|
||||
vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT);
|
||||
vdpu_write(vpu, 0, VDPU_REG_CONFIG);
|
||||
}
|
||||
@@ -30,13 +30,6 @@
|
||||
#define VP8_CABAC_CTX_OFFSET 192
|
||||
#define VP8_CABAC_CTX_SIZE ((55 + 96) << 3)
|
||||
|
||||
#define VP8_KEY_FRAME_HDR_SIZE 10
|
||||
#define VP8_INTER_FRAME_HDR_SIZE 3
|
||||
|
||||
#define VP8_FRAME_TAG_KEY_FRAME_BIT BIT(0)
|
||||
#define VP8_FRAME_TAG_LENGTH_SHIFT 5
|
||||
#define VP8_FRAME_TAG_LENGTH_MASK (0x7ffff << 5)
|
||||
|
||||
/**
|
||||
* struct rk3288_vpu_vp8e_ctrl_buf - hardware control buffer layout
|
||||
* @ext_hdr_size: Ext header size in bytes (written by hardware).
|
||||
@@ -49,59 +42,6 @@ struct rk3288_vpu_vp8e_ctrl_buf {
|
||||
u8 rsvd[1016];
|
||||
};
|
||||
|
||||
/*
|
||||
* The hardware takes care only of ext hdr and dct partition. The software
|
||||
* must take care of frame header.
|
||||
*
|
||||
* Buffer layout as received from hardware:
|
||||
* |<--gap-->|<--ext hdr-->|<-gap->|<---dct part---
|
||||
* |<-------dct part offset------->|
|
||||
*
|
||||
* Required buffer layout:
|
||||
* |<--hdr-->|<--ext hdr-->|<---dct part---
|
||||
*/
|
||||
void rk3288_vpu_vp8e_assemble_bitstream(struct rockchip_vpu_ctx *ctx,
|
||||
struct rockchip_vpu_buf *dst_buf)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vb2_dst = to_vb2_v4l2_buffer(&dst_buf->vb.vb2_buf);
|
||||
size_t ext_hdr_size = dst_buf->vp8e.ext_hdr_size;
|
||||
size_t dct_size = dst_buf->vp8e.dct_size;
|
||||
size_t hdr_size = dst_buf->vp8e.hdr_size;
|
||||
size_t dst_size;
|
||||
size_t tag_size;
|
||||
void *dst;
|
||||
u32 *tag;
|
||||
|
||||
dst_size = vb2_plane_size(&dst_buf->vb.vb2_buf, 0);
|
||||
dst = vb2_plane_vaddr(&dst_buf->vb.vb2_buf, 0);
|
||||
tag = dst; /* To access frame tag words. */
|
||||
|
||||
if (WARN_ON(hdr_size + ext_hdr_size + dct_size > dst_size))
|
||||
return;
|
||||
if (WARN_ON(dst_buf->vp8e.dct_offset + dct_size > dst_size))
|
||||
return;
|
||||
|
||||
memmove(dst + hdr_size + ext_hdr_size,
|
||||
dst + dst_buf->vp8e.dct_offset, dct_size);
|
||||
memcpy(dst, dst_buf->vp8e.header, hdr_size);
|
||||
|
||||
/* Patch frame tag at first 32-bit word of the frame. */
|
||||
if (vb2_dst->flags & V4L2_BUF_FLAG_KEYFRAME) {
|
||||
tag_size = VP8_KEY_FRAME_HDR_SIZE;
|
||||
tag[0] &= ~VP8_FRAME_TAG_KEY_FRAME_BIT;
|
||||
} else {
|
||||
tag_size = VP8_INTER_FRAME_HDR_SIZE;
|
||||
tag[0] |= VP8_FRAME_TAG_KEY_FRAME_BIT;
|
||||
}
|
||||
|
||||
tag[0] &= ~VP8_FRAME_TAG_LENGTH_MASK;
|
||||
tag[0] |= (hdr_size + ext_hdr_size - tag_size)
|
||||
<< VP8_FRAME_TAG_LENGTH_SHIFT;
|
||||
|
||||
vb2_set_plane_payload(&dst_buf->vb.vb2_buf, 0,
|
||||
hdr_size + ext_hdr_size + dct_size);
|
||||
}
|
||||
|
||||
static inline unsigned int ref_luma_size(unsigned int w, unsigned int h)
|
||||
{
|
||||
return round_up(w, MB_DIM) * round_up(h, MB_DIM);
|
||||
|
||||
@@ -1162,7 +1162,7 @@ static void rockchip_vpu_buf_finish(struct vb2_buffer *vb)
|
||||
struct rockchip_vpu_buf *buf;
|
||||
|
||||
buf = vb_to_buf(vb);
|
||||
rk3288_vpu_vp8e_assemble_bitstream(ctx, buf);
|
||||
rockchip_vpu_vp8e_assemble_bitstream(ctx, buf);
|
||||
}
|
||||
|
||||
vpu_debug_leave();
|
||||
|
||||
@@ -30,7 +30,13 @@
|
||||
|
||||
#include <linux/dma-iommu.h>
|
||||
|
||||
#include "rk3288_vpu_regs.h"
|
||||
/* Various parameters specific to VP8 encoder. */
|
||||
#define VP8_KEY_FRAME_HDR_SIZE 10
|
||||
#define VP8_INTER_FRAME_HDR_SIZE 3
|
||||
|
||||
#define VP8_FRAME_TAG_KEY_FRAME_BIT BIT(0)
|
||||
#define VP8_FRAME_TAG_LENGTH_SHIFT 5
|
||||
#define VP8_FRAME_TAG_LENGTH_MASK (0x7ffff << 5)
|
||||
|
||||
/**
|
||||
* struct rockchip_vpu_variant - information about VPU hardware variant
|
||||
@@ -68,6 +74,7 @@ static const struct rockchip_vpu_variant rockchip_vpu_variants[] = {
|
||||
* @exit: Clean-up after streaming. Called from VB2 .stop_streaming()
|
||||
* when streaming from first of both enabled queues is being
|
||||
* disabled.
|
||||
* @irq: Handle {en,de}code irq. Check and clear interrupt.
|
||||
* @run: Start single {en,de)coding run. Called from non-atomic context
|
||||
* to indicate that a pair of buffers is ready and the hardware
|
||||
* should be programmed and started.
|
||||
@@ -78,6 +85,7 @@ struct rockchip_vpu_codec_ops {
|
||||
int (*init)(struct rockchip_vpu_ctx *);
|
||||
void (*exit)(struct rockchip_vpu_ctx *);
|
||||
|
||||
int (*irq)(int, struct rockchip_vpu_dev *);
|
||||
void (*run)(struct rockchip_vpu_ctx *);
|
||||
void (*done)(struct rockchip_vpu_ctx *, enum vb2_buffer_state);
|
||||
void (*reset)(struct rockchip_vpu_ctx *);
|
||||
@@ -136,14 +144,9 @@ static void rockchip_vpu_power_off(struct rockchip_vpu_dev *vpu)
|
||||
static irqreturn_t vepu_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_vpu_dev *vpu = dev_id;
|
||||
u32 status = vepu_read(vpu, VEPU_REG_INTERRUPT);
|
||||
struct rockchip_vpu_ctx *ctx = vpu->current_ctx;
|
||||
|
||||
vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
|
||||
|
||||
if (status & VEPU_REG_INTERRUPT_BIT) {
|
||||
struct rockchip_vpu_ctx *ctx = vpu->current_ctx;
|
||||
|
||||
vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
|
||||
if (!ctx->hw.codec_ops->irq(irq, vpu)) {
|
||||
rockchip_vpu_power_off(vpu);
|
||||
cancel_delayed_work(&vpu->watchdog_work);
|
||||
|
||||
@@ -156,16 +159,9 @@ static irqreturn_t vepu_irq(int irq, void *dev_id)
|
||||
static irqreturn_t vdpu_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_vpu_dev *vpu = dev_id;
|
||||
u32 status = vdpu_read(vpu, VDPU_REG_INTERRUPT);
|
||||
struct rockchip_vpu_ctx *ctx = vpu->current_ctx;
|
||||
|
||||
vdpu_write(vpu, 0, VDPU_REG_INTERRUPT);
|
||||
|
||||
vpu_debug(3, "vdpu_irq status: %08x\n", status);
|
||||
|
||||
if (status & VDPU_REG_INTERRUPT_DEC_IRQ) {
|
||||
struct rockchip_vpu_ctx *ctx = vpu->current_ctx;
|
||||
|
||||
vdpu_write(vpu, 0, VDPU_REG_CONFIG);
|
||||
if (!ctx->hw.codec_ops->irq(irq, vpu)) {
|
||||
rockchip_vpu_power_off(vpu);
|
||||
cancel_delayed_work(&vpu->watchdog_work);
|
||||
|
||||
@@ -364,44 +360,30 @@ void rockchip_vpu_hw_remove(struct rockchip_vpu_dev *vpu)
|
||||
clk_disable_unprepare(vpu->aclk_vcodec);
|
||||
}
|
||||
|
||||
static void rockchip_vpu_enc_reset(struct rockchip_vpu_ctx *ctx)
|
||||
{
|
||||
struct rockchip_vpu_dev *vpu = ctx->dev;
|
||||
|
||||
vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
|
||||
vepu_write(vpu, 0, VEPU_REG_ENC_CTRL);
|
||||
vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
|
||||
}
|
||||
|
||||
static void rockchip_vpu_dec_reset(struct rockchip_vpu_ctx *ctx)
|
||||
{
|
||||
struct rockchip_vpu_dev *vpu = ctx->dev;
|
||||
|
||||
vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT);
|
||||
vdpu_write(vpu, 0, VDPU_REG_CONFIG);
|
||||
}
|
||||
|
||||
static const struct rockchip_vpu_codec_ops mode_ops[] = {
|
||||
[RK3288_VPU_CODEC_VP8E] = {
|
||||
.init = rk3288_vpu_vp8e_init,
|
||||
.exit = rk3288_vpu_vp8e_exit,
|
||||
.irq = rk3288_vpu_enc_irq,
|
||||
.run = rk3288_vpu_vp8e_run,
|
||||
.done = rk3288_vpu_vp8e_done,
|
||||
.reset = rockchip_vpu_enc_reset,
|
||||
.reset = rk3288_vpu_enc_reset,
|
||||
},
|
||||
[RK3288_VPU_CODEC_VP8D] = {
|
||||
.init = rk3288_vpu_vp8d_init,
|
||||
.exit = rk3288_vpu_vp8d_exit,
|
||||
.irq = rk3288_vpu_dec_irq,
|
||||
.run = rk3288_vpu_vp8d_run,
|
||||
.done = rockchip_vpu_run_done,
|
||||
.reset = rockchip_vpu_dec_reset,
|
||||
.reset = rk3288_vpu_dec_reset,
|
||||
},
|
||||
[RK3288_VPU_CODEC_H264D] = {
|
||||
.init = rk3288_vpu_h264d_init,
|
||||
.exit = rk3288_vpu_h264d_exit,
|
||||
.irq = rk3288_vpu_dec_irq,
|
||||
.run = rk3288_vpu_h264d_run,
|
||||
.done = rockchip_vpu_run_done,
|
||||
.reset = rockchip_vpu_dec_reset,
|
||||
.reset = rk3288_vpu_dec_reset,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -428,3 +410,59 @@ void rockchip_vpu_deinit(struct rockchip_vpu_ctx *ctx)
|
||||
{
|
||||
ctx->hw.codec_ops->exit(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The hardware takes care only of ext hdr and dct partition. The software
|
||||
* must take care of frame header.
|
||||
*
|
||||
* Buffer layout as received from hardware:
|
||||
* |<--gap-->|<--ext hdr-->|<-gap->|<---dct part---
|
||||
* |<-------dct part offset------->|
|
||||
*
|
||||
* Required buffer layout:
|
||||
* |<--hdr-->|<--ext hdr-->|<---dct part---
|
||||
*/
|
||||
void rockchip_vpu_vp8e_assemble_bitstream(struct rockchip_vpu_ctx *ctx,
|
||||
struct rockchip_vpu_buf *dst_buf)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vb2_dst = to_vb2_v4l2_buffer(&dst_buf->vb.vb2_buf);
|
||||
size_t ext_hdr_size = dst_buf->vp8e.ext_hdr_size;
|
||||
size_t dct_size = dst_buf->vp8e.dct_size;
|
||||
size_t hdr_size = dst_buf->vp8e.hdr_size;
|
||||
size_t dst_size;
|
||||
size_t tag_size;
|
||||
void *dst;
|
||||
u32 *tag;
|
||||
|
||||
dst_size = vb2_plane_size(&dst_buf->vb.vb2_buf, 0);
|
||||
dst = vb2_plane_vaddr(&dst_buf->vb.vb2_buf, 0);
|
||||
tag = dst; /* To access frame tag words. */
|
||||
|
||||
if (WARN_ON(hdr_size + ext_hdr_size + dct_size > dst_size))
|
||||
return;
|
||||
if (WARN_ON(dst_buf->vp8e.dct_offset + dct_size > dst_size))
|
||||
return;
|
||||
|
||||
vpu_debug(1, "%s: hdr_size = %d, ext_hdr_size = %d, dct_size = %d\n",
|
||||
__func__, hdr_size, ext_hdr_size, dct_size);
|
||||
|
||||
memmove(dst + hdr_size + ext_hdr_size,
|
||||
dst + dst_buf->vp8e.dct_offset, dct_size);
|
||||
memcpy(dst, dst_buf->vp8e.header, hdr_size);
|
||||
|
||||
/* Patch frame tag at first 32-bit word of the frame. */
|
||||
if (vb2_dst->flags & V4L2_BUF_FLAG_KEYFRAME) {
|
||||
tag_size = VP8_KEY_FRAME_HDR_SIZE;
|
||||
tag[0] &= ~VP8_FRAME_TAG_KEY_FRAME_BIT;
|
||||
} else {
|
||||
tag_size = VP8_INTER_FRAME_HDR_SIZE;
|
||||
tag[0] |= VP8_FRAME_TAG_KEY_FRAME_BIT;
|
||||
}
|
||||
|
||||
tag[0] &= ~VP8_FRAME_TAG_LENGTH_MASK;
|
||||
tag[0] |= (hdr_size + ext_hdr_size - tag_size)
|
||||
<< VP8_FRAME_TAG_LENGTH_SHIFT;
|
||||
|
||||
vb2_set_plane_payload(&dst_buf->vb.vb2_buf, 0,
|
||||
hdr_size + ext_hdr_size + dct_size);
|
||||
}
|
||||
|
||||
@@ -164,6 +164,12 @@ void rockchip_vpu_deinit(struct rockchip_vpu_ctx *ctx);
|
||||
|
||||
void rockchip_vpu_run(struct rockchip_vpu_ctx *ctx);
|
||||
|
||||
/* Ops for rk3288 vpu */
|
||||
int rk3288_vpu_enc_irq(int irq, struct rockchip_vpu_dev *vpu);
|
||||
int rk3288_vpu_dec_irq(int irq, struct rockchip_vpu_dev *vpu);
|
||||
void rk3288_vpu_enc_reset(struct rockchip_vpu_ctx *ctx);
|
||||
void rk3288_vpu_dec_reset(struct rockchip_vpu_ctx *ctx);
|
||||
|
||||
/* Run ops for rk3288 H264 decoder */
|
||||
int rk3288_vpu_h264d_init(struct rockchip_vpu_ctx *ctx);
|
||||
void rk3288_vpu_h264d_exit(struct rockchip_vpu_ctx *ctx);
|
||||
@@ -182,7 +188,7 @@ void rk3288_vpu_vp8e_done(struct rockchip_vpu_ctx *ctx,
|
||||
enum vb2_buffer_state result);
|
||||
const struct rockchip_reg_params *rk3288_vpu_vp8e_get_dummy_params(void);
|
||||
|
||||
void rk3288_vpu_vp8e_assemble_bitstream(struct rockchip_vpu_ctx *ctx,
|
||||
void rockchip_vpu_vp8e_assemble_bitstream(struct rockchip_vpu_ctx *ctx,
|
||||
struct rockchip_vpu_buf *dst_buf);
|
||||
|
||||
#endif /* ROCKCHIP_VPU_HW_H_ */
|
||||
|
||||
Reference in New Issue
Block a user