-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
media: add Rockchip VPU JPEG encoder driver
Add a mem2mem driver for the VPU available on Rockchip SoCs. Currently only JPEG encoding is supported, for RK3399 and RK3288 platforms. Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> [hverkuil-cisco@xs4all.nl: fix checkpatch.pl alignment warning] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
- Loading branch information
Ezequiel Garcia
authored and
Mauro Carvalho Chehab
committed
Dec 5, 2018
1 parent
7f22507
commit 775fec6
Showing
19 changed files
with
3,454 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
config VIDEO_ROCKCHIP_VPU | ||
tristate "Rockchip VPU driver" | ||
depends on ARCH_ROCKCHIP || COMPILE_TEST | ||
depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER | ||
select VIDEOBUF2_DMA_CONTIG | ||
select VIDEOBUF2_VMALLOC | ||
select V4L2_MEM2MEM_DEV | ||
default n | ||
help | ||
Support for the Video Processing Unit present on Rockchip SoC, | ||
which accelerates video and image encoding and decoding. | ||
To compile this driver as a module, choose M here: the module | ||
will be called rockchip-vpu. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu.o | ||
|
||
rockchip-vpu-y += \ | ||
rockchip_vpu_drv.o \ | ||
rockchip_vpu_enc.o \ | ||
rk3288_vpu_hw.o \ | ||
rk3288_vpu_hw_jpeg_enc.o \ | ||
rk3399_vpu_hw.o \ | ||
rk3399_vpu_hw_jpeg_enc.o \ | ||
rockchip_vpu_jpeg.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
* Support for VP8, VP9 and H264 is planned for this driver. | ||
|
||
Given the V4L controls for those CODECs will be part of | ||
the uABI, it will be required to have the driver in staging. | ||
|
||
For this reason, we are keeping this driver in staging for now. | ||
|
||
* Add support for the S_SELECTION API. | ||
See the comment for VEPU_REG_ENC_OVER_FILL_STRM_OFFSET. | ||
|
||
* Instead of having a DMA bounce buffer, it could be possible to use a | ||
normal buffer and memmove() the payload to make space for the header. | ||
This might need to use extra JPEG markers for padding reasons. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// 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 "rockchip_vpu_jpeg.h" | ||
#include "rk3288_vpu_regs.h" | ||
|
||
#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) | ||
|
||
/* | ||
* Supported formats. | ||
*/ | ||
|
||
static const struct rockchip_vpu_fmt rk3288_vpu_enc_fmts[] = { | ||
{ | ||
.fourcc = V4L2_PIX_FMT_YUV420M, | ||
.codec_mode = RK_VPU_MODE_NONE, | ||
.enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, | ||
}, | ||
{ | ||
.fourcc = V4L2_PIX_FMT_NV12M, | ||
.codec_mode = RK_VPU_MODE_NONE, | ||
.enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, | ||
}, | ||
{ | ||
.fourcc = V4L2_PIX_FMT_YUYV, | ||
.codec_mode = RK_VPU_MODE_NONE, | ||
.enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, | ||
}, | ||
{ | ||
.fourcc = V4L2_PIX_FMT_UYVY, | ||
.codec_mode = RK_VPU_MODE_NONE, | ||
.enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, | ||
}, | ||
{ | ||
.fourcc = V4L2_PIX_FMT_JPEG, | ||
.codec_mode = RK_VPU_MODE_JPEG_ENC, | ||
.max_depth = 2, | ||
.header_size = JPEG_HEADER_SIZE, | ||
.frmsize = { | ||
.min_width = 96, | ||
.max_width = 8192, | ||
.step_width = JPEG_MB_DIM, | ||
.min_height = 32, | ||
.max_height = 8192, | ||
.step_height = JPEG_MB_DIM, | ||
}, | ||
}, | ||
}; | ||
|
||
static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) | ||
{ | ||
struct rockchip_vpu_dev *vpu = dev_id; | ||
enum vb2_buffer_state state; | ||
u32 status, bytesused; | ||
|
||
status = vepu_read(vpu, VEPU_REG_INTERRUPT); | ||
bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; | ||
state = (status & VEPU_REG_INTERRUPT_FRAME_RDY) ? | ||
VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; | ||
|
||
vepu_write(vpu, 0, VEPU_REG_INTERRUPT); | ||
vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); | ||
|
||
rockchip_vpu_irq_done(vpu, bytesused, state); | ||
|
||
return IRQ_HANDLED; | ||
} | ||
|
||
static int rk3288_vpu_hw_init(struct rockchip_vpu_dev *vpu) | ||
{ | ||
/* Bump ACLK to max. possible freq. to improve performance. */ | ||
clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); | ||
return 0; | ||
} | ||
|
||
static 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); | ||
} | ||
|
||
/* | ||
* Supported codec ops. | ||
*/ | ||
|
||
static const struct rockchip_vpu_codec_ops rk3288_vpu_codec_ops[] = { | ||
[RK_VPU_MODE_JPEG_ENC] = { | ||
.run = rk3288_vpu_jpeg_enc_run, | ||
.reset = rk3288_vpu_enc_reset, | ||
}, | ||
}; | ||
|
||
/* | ||
* VPU variant. | ||
*/ | ||
|
||
const struct rockchip_vpu_variant rk3288_vpu_variant = { | ||
.enc_offset = 0x0, | ||
.enc_fmts = rk3288_vpu_enc_fmts, | ||
.num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), | ||
.codec_ops = rk3288_vpu_codec_ops, | ||
.codec = RK_VPU_CODEC_JPEG, | ||
.vepu_irq = rk3288_vepu_irq, | ||
.init = rk3288_vpu_hw_init, | ||
.clk_names = {"aclk", "hclk"}, | ||
.num_clocks = 2 | ||
}; |
130 changes: 130 additions & 0 deletions
130
drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Rockchip VPU codec driver | ||
* | ||
* Copyright (C) 2018 Rockchip Electronics Co., Ltd. | ||
*/ | ||
|
||
#include <asm/unaligned.h> | ||
#include <media/v4l2-mem2mem.h> | ||
#include "rockchip_vpu_jpeg.h" | ||
#include "rockchip_vpu.h" | ||
#include "rockchip_vpu_common.h" | ||
#include "rockchip_vpu_hw.h" | ||
#include "rk3288_vpu_regs.h" | ||
|
||
#define VEPU_JPEG_QUANT_TABLE_COUNT 16 | ||
|
||
static void rk3288_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, | ||
struct rockchip_vpu_ctx *ctx) | ||
{ | ||
struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; | ||
u32 reg; | ||
|
||
reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) | ||
| VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) | ||
| VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(0) | ||
| VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); | ||
vepu_write_relaxed(vpu, reg, VEPU_REG_IN_IMG_CTRL); | ||
} | ||
|
||
static void rk3288_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, | ||
struct rockchip_vpu_ctx *ctx, | ||
struct vb2_buffer *src_buf) | ||
{ | ||
struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; | ||
dma_addr_t src[3]; | ||
|
||
WARN_ON(pix_fmt->num_planes > 3); | ||
|
||
vepu_write_relaxed(vpu, ctx->bounce_dma_addr, | ||
VEPU_REG_ADDR_OUTPUT_STREAM); | ||
vepu_write_relaxed(vpu, ctx->bounce_size, | ||
VEPU_REG_STR_BUF_LIMIT); | ||
|
||
if (pix_fmt->num_planes == 1) { | ||
src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); | ||
/* single plane formats we supported are all interlaced */ | ||
vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); | ||
} else if (pix_fmt->num_planes == 2) { | ||
src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); | ||
src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); | ||
vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); | ||
vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); | ||
} else { | ||
src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); | ||
src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); | ||
src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); | ||
vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); | ||
vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); | ||
vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2); | ||
} | ||
} | ||
|
||
static void | ||
rk3288_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu, | ||
unsigned char *luma_qtable, | ||
unsigned char *chroma_qtable) | ||
{ | ||
__be32 *luma_qtable_p; | ||
__be32 *chroma_qtable_p; | ||
u32 reg, i; | ||
|
||
luma_qtable_p = (__be32 *)luma_qtable; | ||
chroma_qtable_p = (__be32 *)chroma_qtable; | ||
|
||
for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { | ||
reg = get_unaligned_be32(&luma_qtable[i]); | ||
vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i)); | ||
|
||
reg = get_unaligned_be32(&chroma_qtable[i]); | ||
vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i)); | ||
} | ||
} | ||
|
||
void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) | ||
{ | ||
struct rockchip_vpu_dev *vpu = ctx->dev; | ||
struct vb2_buffer *src_buf, *dst_buf; | ||
struct rockchip_vpu_jpeg_ctx jpeg_ctx; | ||
u32 reg; | ||
|
||
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | ||
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | ||
|
||
memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); | ||
jpeg_ctx.buffer = vb2_plane_vaddr(dst_buf, 0); | ||
jpeg_ctx.width = ctx->dst_fmt.width; | ||
jpeg_ctx.height = ctx->dst_fmt.height; | ||
jpeg_ctx.quality = ctx->jpeg_quality; | ||
rockchip_vpu_jpeg_header_assemble(&jpeg_ctx); | ||
|
||
/* Switch to JPEG encoder mode before writing registers */ | ||
vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_JPEG, | ||
VEPU_REG_ENC_CTRL); | ||
|
||
rk3288_vpu_set_src_img_ctrl(vpu, ctx); | ||
rk3288_vpu_jpeg_enc_set_buffers(vpu, ctx, src_buf); | ||
rk3288_vpu_jpeg_enc_set_qtable(vpu, | ||
rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0), | ||
rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1)); | ||
|
||
reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 | ||
| VEPU_REG_AXI_CTRL_INPUT_SWAP16 | ||
| VEPU_REG_AXI_CTRL_BURST_LEN(16) | ||
| VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 | ||
| VEPU_REG_AXI_CTRL_INPUT_SWAP32 | ||
| VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 | ||
| VEPU_REG_AXI_CTRL_INPUT_SWAP8; | ||
/* Make sure that all registers are written at this point. */ | ||
vepu_write(vpu, reg, VEPU_REG_AXI_CTRL); | ||
|
||
reg = VEPU_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) | ||
| VEPU_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) | ||
| VEPU_REG_ENC_CTRL_ENC_MODE_JPEG | ||
| VEPU_REG_ENC_PIC_INTRA | ||
| VEPU_REG_ENC_CTRL_EN_BIT; | ||
/* Kick the watchdog and start encoding */ | ||
schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); | ||
vepu_write(vpu, reg, VEPU_REG_ENC_CTRL); | ||
} |
Oops, something went wrong.