[media] rockchip/rga: v4l2 m2m support

Rockchip RGA is a separate 2D raster graphic acceleration unit. It
accelerates 2D graphics operations, such as point/line drawing, image
scaling, rotation, BitBLT, alpha blending and image blur/sharpness

The driver supports various operations from the rendering pipeline.
 - copy
 - fast solid color fill
 - rotation
 - flip
 - alpha blending

The code in rga-hw.c is used to configure regs according to operations
The code in rga-buf.c is used to create private mmu table for RGA.

Signed-off-by: Jacob Chen <jacob-chen@iotwrt.com>
Signed-off-by: Hans Verkuil <hansverk@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
Jacob Chen 2017-10-11 00:29:35 -07:00 committed by Mauro Carvalho Chehab
parent 7ef3b44cea
commit f7e7b48e6d
8 changed files with 2169 additions and 0 deletions

View File

@ -458,6 +458,21 @@ config VIDEO_RENESAS_VSP1
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called vsp1. will be called vsp1.
config VIDEO_ROCKCHIP_RGA
tristate "Rockchip Raster 2d Graphic Acceleration Unit"
depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
depends on ARCH_ROCKCHIP || COMPILE_TEST
select VIDEOBUF2_DMA_SG
select V4L2_MEM2MEM_DEV
default n
---help---
This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator.
Rockchip RGA is a separate 2D raster graphic acceleration unit.
It accelerates 2D graphics operations, such as point/line drawing,
image scaling, rotation, BitBLT, alpha blending and image blur/sharpness.
To compile this driver as a module choose m here.
config VIDEO_TI_VPE config VIDEO_TI_VPE
tristate "TI VPE (Video Processing Engine) driver" tristate "TI VPE (Video Processing Engine) driver"
depends on VIDEO_DEV && VIDEO_V4L2 depends on VIDEO_DEV && VIDEO_V4L2

View File

@ -64,6 +64,8 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o
obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/
obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip/rga/
obj-y += omap/ obj-y += omap/
obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/

View File

@ -0,0 +1,3 @@
rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o

View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd
* Author: Jacob Chen <jacob-chen@iotwrt.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 <linux/pm_runtime.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-dma-sg.h>
#include <media/videobuf2-v4l2.h>
#include "rga-hw.h"
#include "rga.h"
static int
rga_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], struct device *alloc_devs[])
{
struct rga_ctx *ctx = vb2_get_drv_priv(vq);
struct rga_frame *f = rga_get_frame(ctx, vq->type);
if (IS_ERR(f))
return PTR_ERR(f);
if (*nplanes)
return sizes[0] < f->size ? -EINVAL : 0;
sizes[0] = f->size;
*nplanes = 1;
return 0;
}
static int rga_buf_prepare(struct vb2_buffer *vb)
{
struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
if (IS_ERR(f))
return PTR_ERR(f);
vb2_set_plane_payload(vb, 0, f->size);
return 0;
}
static void rga_buf_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct rga_ctx *ctx = vb2_get_drv_priv(q);
struct rockchip_rga *rga = ctx->rga;
int ret, i;
ret = pm_runtime_get_sync(rga->dev);
if (!ret)
return 0;
for (i = 0; i < q->num_buffers; ++i) {
if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]),
VB2_BUF_STATE_QUEUED);
}
}
return ret;
}
static void rga_buf_stop_streaming(struct vb2_queue *q)
{
struct rga_ctx *ctx = vb2_get_drv_priv(q);
struct rockchip_rga *rga = ctx->rga;
struct vb2_v4l2_buffer *vbuf;
for (;;) {
if (V4L2_TYPE_IS_OUTPUT(q->type))
vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
else
vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
if (!vbuf)
break;
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
}
pm_runtime_put(rga->dev);
}
const struct vb2_ops rga_qops = {
.queue_setup = rga_queue_setup,
.buf_prepare = rga_buf_prepare,
.buf_queue = rga_buf_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.start_streaming = rga_buf_start_streaming,
.stop_streaming = rga_buf_stop_streaming,
};
/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API.
* We use it more like a scatter-gather list.
*/
void rga_buf_map(struct vb2_buffer *vb)
{
struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct rockchip_rga *rga = ctx->rga;
struct sg_table *sgt;
struct scatterlist *sgl;
unsigned int *pages;
unsigned int address, len, i, p;
unsigned int mapped_size = 0;
if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
pages = rga->src_mmu_pages;
else
pages = rga->dst_mmu_pages;
/* Create local MMU table for RGA */
sgt = vb2_plane_cookie(vb, 0);
for_each_sg(sgt->sgl, sgl, sgt->nents, i) {
len = sg_dma_len(sgl) >> PAGE_SHIFT;
address = sg_phys(sgl);
for (p = 0; p < len; p++) {
dma_addr_t phys = address + (p << PAGE_SHIFT);
pages[mapped_size + p] = phys;
}
mapped_size += len;
}
/* sync local MMU table for RGA */
dma_sync_single_for_device(rga->dev, virt_to_phys(pages),
8 * PAGE_SIZE, DMA_BIDIRECTIONAL);
}

View File

@ -0,0 +1,421 @@
/*
* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
* Author: Jacob Chen <jacob-chen@iotwrt.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 <linux/pm_runtime.h>
#include "rga-hw.h"
#include "rga.h"
enum e_rga_start_pos {
LT = 0,
LB = 1,
RT = 2,
RB = 3,
};
struct rga_addr_offset {
unsigned int y_off;
unsigned int u_off;
unsigned int v_off;
};
struct rga_corners_addr_offset {
struct rga_addr_offset left_top;
struct rga_addr_offset right_top;
struct rga_addr_offset left_bottom;
struct rga_addr_offset right_bottom;
};
static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
{
/*
* The rga hw scaling factor is a normalized inverse of the
* scaling factor.
* For example: When source width is 100 and destination width is 200
* (scaling of 2x), then the hw factor is NC * 100 / 200.
* The normalization factor (NC) is 2^16 = 0x10000.
*/
return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
}
static struct rga_corners_addr_offset
rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
unsigned int w, unsigned int h)
{
struct rga_corners_addr_offset offsets;
struct rga_addr_offset *lt, *lb, *rt, *rb;
unsigned int x_div = 0,
y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0;
lt = &offsets.left_top;
lb = &offsets.left_bottom;
rt = &offsets.right_top;
rb = &offsets.right_bottom;
x_div = frm->fmt->x_div;
y_div = frm->fmt->y_div;
uv_factor = frm->fmt->uv_factor;
uv_stride = frm->stride / x_div;
pixel_width = frm->stride / frm->width;
lt->y_off = y * frm->stride + x * pixel_width;
lt->u_off =
frm->width * frm->height + (y / y_div) * uv_stride + x / x_div;
lt->v_off = lt->u_off + frm->width * frm->height / uv_factor;
lb->y_off = lt->y_off + (h - 1) * frm->stride;
lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
rt->y_off = lt->y_off + (w - 1) * pixel_width;
rt->u_off = lt->u_off + w / x_div - 1;
rt->v_off = lt->v_off + w / x_div - 1;
rb->y_off = lb->y_off + (w - 1) * pixel_width;
rb->u_off = lb->u_off + w / x_div - 1;
rb->v_off = lb->v_off + w / x_div - 1;
return offsets;
}
static struct rga_addr_offset *rga_lookup_draw_pos(struct
rga_corners_addr_offset
* offsets, u32 rotate_mode,
u32 mirr_mode)
{
static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
{
LT, RT, LB, RB,
},
{
RT, LT, RB, LB,
},
{
RB, LB, RT, LT,
},
{
LB, RB, LT, RT,
},
};
if (!offsets)
return NULL;
switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
case LT:
return &offsets->left_top;
case LB:
return &offsets->left_bottom;
case RT:
return &offsets->right_top;
case RB:
return &offsets->right_bottom;
}
return NULL;
}
static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7;
}
static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7 << 4;
}
static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7 << 8;
}
static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int scale_dst_w, scale_dst_h;
unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y;
union rga_src_info src_info;
union rga_dst_info dst_info;
union rga_src_x_factor x_factor;
union rga_src_y_factor y_factor;
union rga_src_vir_info src_vir_info;
union rga_src_act_info src_act_info;
union rga_dst_vir_info dst_vir_info;
union rga_dst_act_info dst_act_info;
struct rga_addr_offset *dst_offset;
struct rga_corners_addr_offset offsets;
struct rga_corners_addr_offset src_offsets;
src_h = ctx->in.crop.height;
src_w = ctx->in.crop.width;
src_x = ctx->in.crop.left;
src_y = ctx->in.crop.top;
dst_h = ctx->out.crop.height;
dst_w = ctx->out.crop.width;
dst_x = ctx->out.crop.left;
dst_y = ctx->out.crop.top;
src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];
dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];
x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2];
y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2];
src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
src_info.data.format = ctx->in.fmt->hw_format;
src_info.data.swap = ctx->in.fmt->color_swap;
dst_info.data.format = ctx->out.fmt->hw_format;
dst_info.data.swap = ctx->out.fmt->color_swap;
if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) {
switch (ctx->in.colorspace) {
case V4L2_COLORSPACE_REC709:
src_info.data.csc_mode =
RGA_SRC_CSC_MODE_BT709_R0;
break;
default:
src_info.data.csc_mode =
RGA_SRC_CSC_MODE_BT601_R0;
break;
}
}
}
if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
switch (ctx->out.colorspace) {
case V4L2_COLORSPACE_REC709:
dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
break;
default:
dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;
break;
}
}
if (ctx->vflip)
src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X;
if (ctx->hflip)
src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y;
switch (ctx->rotate) {
case 90:
src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;
break;
case 180:
src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;
break;
case 270:
src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;
break;
default:
src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;
break;
}
/*
* Cacluate the up/down scaling mode/factor.
*
* RGA used to scale the picture first, and then rotate second,
* so we need to swap the w/h when rotate degree is 90/270.
*/
if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE ||
src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) {
if (rga->version.major == 0 || rga->version.minor == 0) {
if (dst_w == src_h)
src_h -= 8;
if (abs(src_w - dst_h) < 16)
src_w -= 16;
}
scale_dst_h = dst_w;
scale_dst_w = dst_h;
} else {
scale_dst_w = dst_w;
scale_dst_h = dst_h;
}
if (src_w == scale_dst_w) {
src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO;
x_factor.val = 0;
} else if (src_w > scale_dst_w) {
src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN;
x_factor.data.down_scale_factor =
rga_get_scaling(src_w, scale_dst_w) + 1;
} else {
src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP;
x_factor.data.up_scale_factor =
rga_get_scaling(src_w - 1, scale_dst_w - 1);
}
if (src_h == scale_dst_h) {
src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO;
y_factor.val = 0;
} else if (src_h > scale_dst_h) {
src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN;
y_factor.data.down_scale_factor =
rga_get_scaling(src_h, scale_dst_h) + 1;
} else {
src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP;
y_factor.data.up_scale_factor =
rga_get_scaling(src_h - 1, scale_dst_h - 1);
}
/*
* Cacluate the framebuffer virtual strides and active size,
* note that the step of vir_stride / vir_width is 4 byte words
*/
src_vir_info.data.vir_stride = ctx->in.stride >> 2;
src_vir_info.data.vir_width = ctx->in.stride >> 2;
src_act_info.data.act_height = src_h - 1;
src_act_info.data.act_width = src_w - 1;
dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
dst_act_info.data.act_height = dst_h - 1;
dst_act_info.data.act_width = dst_w - 1;
/*
* Cacluate the source framebuffer base address with offset pixel.
*/
src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y,
src_w, src_h);
/*
* Configure the dest framebuffer base address with pixel offset.
*/
offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h);
dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode,
src_info.data.mir_mode);
dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
src_offsets.left_top.y_off;
dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
src_offsets.left_top.u_off;
dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
src_offsets.left_top.v_off;
dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
dst_offset->y_off;
dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
dst_offset->u_off;
dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
dst_offset->v_off;
dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
}
static void rga_cmd_set_mode(struct rga_ctx *ctx)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
union rga_mode_ctrl mode;
union rga_alpha_ctrl0 alpha_ctrl0;
union rga_alpha_ctrl1 alpha_ctrl1;
mode.val = 0;
alpha_ctrl0.val = 0;
alpha_ctrl1.val = 0;
mode.data.gradient_sat = 1;
mode.data.render = RGA_MODE_RENDER_BITBLT;
mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;
/* disable alpha blending */
dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val;
dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val;
dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
}
void rga_cmd_set(struct rga_ctx *ctx)
{
struct rockchip_rga *rga = ctx->rga;
memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
rga_cmd_set_src_addr(ctx, rga->src_mmu_pages);
/*
* Due to hardware bug,
* src1 mmu also should be configured when using alpha blending.
*/
rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages);
rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages);
rga_cmd_set_mode(ctx);
rga_cmd_set_trans_info(ctx);
rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
/* sync CMD buf for RGA */
dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
PAGE_SIZE, DMA_BIDIRECTIONAL);
}
void rga_hw_start(struct rockchip_rga *rga)
{
struct rga_ctx *ctx = rga->curr;
rga_cmd_set(ctx);
rga_write(rga, RGA_SYS_CTRL, 0x00);
rga_write(rga, RGA_SYS_CTRL, 0x22);
rga_write(rga, RGA_INT, 0x600);
rga_write(rga, RGA_CMD_CTRL, 0x1);
}

View File

@ -0,0 +1,437 @@
/*
* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
* Author: Jacob Chen <jacob-chen@iotwrt.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.
*/
#ifndef __RGA_HW_H__
#define __RGA_HW_H__
#define RGA_CMDBUF_SIZE 0x20
/* Hardware limits */
#define MAX_WIDTH 8192
#define MAX_HEIGHT 8192
#define MIN_WIDTH 34
#define MIN_HEIGHT 34
#define DEFAULT_WIDTH 100
#define DEFAULT_HEIGHT 100
#define RGA_TIMEOUT 500
/* Registers address */
#define RGA_SYS_CTRL 0x0000
#define RGA_CMD_CTRL 0x0004
#define RGA_CMD_BASE 0x0008
#define RGA_INT 0x0010
#define RGA_MMU_CTRL0 0x0014
#define RGA_VERSION_INFO 0x0028
#define RGA_MODE_BASE_REG 0x0100
#define RGA_MODE_MAX_REG 0x017C
#define RGA_MODE_CTRL 0x0100
#define RGA_SRC_INFO 0x0104
#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108
#define RGA_SRC_CB_BASE_ADDR 0x010c
#define RGA_SRC_CR_BASE_ADDR 0x0110
#define RGA_SRC1_RGB_BASE_ADDR 0x0114
#define RGA_SRC_VIR_INFO 0x0118
#define RGA_SRC_ACT_INFO 0x011c
#define RGA_SRC_X_FACTOR 0x0120
#define RGA_SRC_Y_FACTOR 0x0124
#define RGA_SRC_BG_COLOR 0x0128
#define RGA_SRC_FG_COLOR 0x012c
#define RGA_SRC_TR_COLOR0 0x0130
#define RGA_SRC_TR_COLOR1 0x0134
#define RGA_DST_INFO 0x0138
#define RGA_DST_Y_RGB_BASE_ADDR 0x013c
#define RGA_DST_CB_BASE_ADDR 0x0140
#define RGA_DST_CR_BASE_ADDR 0x0144
#define RGA_DST_VIR_INFO 0x0148
#define RGA_DST_ACT_INFO 0x014c
#define RGA_ALPHA_CTRL0 0x0150
#define RGA_ALPHA_CTRL1 0x0154
#define RGA_FADING_CTRL 0x0158
#define RGA_PAT_CON 0x015c
#define RGA_ROP_CON0 0x0160
#define RGA_ROP_CON1 0x0164
#define RGA_MASK_BASE 0x0168
#define RGA_MMU_CTRL1 0x016C
#define RGA_MMU_SRC_BASE 0x0170
#define RGA_MMU_SRC1_BASE 0x0174
#define RGA_MMU_DST_BASE 0x0178
/* Registers value */
#define RGA_MODE_RENDER_BITBLT 0
#define RGA_MODE_RENDER_COLOR_PALETTE 1
#define RGA_MODE_RENDER_RECTANGLE_FILL 2
#define RGA_MODE_RENDER_UPDATE_PALETTE_LUT_RAM 3
#define RGA_MODE_BITBLT_MODE_SRC_TO_DST 0
#define RGA_MODE_BITBLT_MODE_SRC_SRC1_TO_DST 1
#define RGA_MODE_CF_ROP4_SOLID 0
#define RGA_MODE_CF_ROP4_PATTERN 1
#define RGA_COLOR_FMT_ABGR8888 0
#define RGA_COLOR_FMT_XBGR8888 1
#define RGA_COLOR_FMT_RGB888 2
#define RGA_COLOR_FMT_BGR565 4
#define RGA_COLOR_FMT_ABGR1555 5
#define RGA_COLOR_FMT_ABGR4444 6
#define RGA_COLOR_FMT_YUV422SP 8
#define RGA_COLOR_FMT_YUV422P 9
#define RGA_COLOR_FMT_YUV420SP 10
#define RGA_COLOR_FMT_YUV420P 11
/* SRC_COLOR Palette */
#define RGA_COLOR_FMT_CP_1BPP 12
#define RGA_COLOR_FMT_CP_2BPP 13
#define RGA_COLOR_FMT_CP_4BPP 14
#define RGA_COLOR_FMT_CP_8BPP 15
#define RGA_COLOR_FMT_MASK 15
#define RGA_COLOR_NONE_SWAP 0
#define RGA_COLOR_RB_SWAP 1
#define RGA_COLOR_ALPHA_SWAP 2
#define RGA_COLOR_UV_SWAP 4
#define RGA_SRC_CSC_MODE_BYPASS 0
#define RGA_SRC_CSC_MODE_BT601_R0 1
#define RGA_SRC_CSC_MODE_BT601_R1 2
#define RGA_SRC_CSC_MODE_BT709_R0 3
#define RGA_SRC_CSC_MODE_BT709_R1 4
#define RGA_SRC_ROT_MODE_0_DEGREE 0
#define RGA_SRC_ROT_MODE_90_DEGREE 1
#define RGA_SRC_ROT_MODE_180_DEGREE 2
#define RGA_SRC_ROT_MODE_270_DEGREE 3
#define RGA_SRC_MIRR_MODE_NO 0
#define RGA_SRC_MIRR_MODE_X 1
#define RGA_SRC_MIRR_MODE_Y 2
#define RGA_SRC_MIRR_MODE_X_Y 3
#define RGA_SRC_HSCL_MODE_NO 0
#define RGA_SRC_HSCL_MODE_DOWN 1
#define RGA_SRC_HSCL_MODE_UP 2
#define RGA_SRC_VSCL_MODE_NO 0
#define RGA_SRC_VSCL_MODE_DOWN 1
#define RGA_SRC_VSCL_MODE_UP 2
#define RGA_SRC_TRANS_ENABLE_R 1
#define RGA_SRC_TRANS_ENABLE_G 2
#define RGA_SRC_TRANS_ENABLE_B 4
#define RGA_SRC_TRANS_ENABLE_A 8
#define RGA_SRC_BIC_COE_SELEC_CATROM 0
#define RGA_SRC_BIC_COE_SELEC_MITCHELL 1
#define RGA_SRC_BIC_COE_SELEC_HERMITE 2
#define RGA_SRC_BIC_COE_SELEC_BSPLINE 3
#define RGA_DST_DITHER_MODE_888_TO_666 0
#define RGA_DST_DITHER_MODE_888_TO_565 1
#define RGA_DST_DITHER_MODE_888_TO_555 2
#define RGA_DST_DITHER_MODE_888_TO_444 3
#define RGA_DST_CSC_MODE_BYPASS 0
#define RGA_DST_CSC_MODE_BT601_R0 1
#define RGA_DST_CSC_MODE_BT601_R1 2
#define RGA_DST_CSC_MODE_BT709_R0 3
#define RGA_ALPHA_ROP_MODE_2 0
#define RGA_ALPHA_ROP_MODE_3 1
#define RGA_ALPHA_ROP_MODE_4 2
#define RGA_ALPHA_SELECT_ALPHA 0
#define RGA_ALPHA_SELECT_ROP 1
#define RGA_ALPHA_MASK_BIG_ENDIAN 0
#define RGA_ALPHA_MASK_LITTLE_ENDIAN 1
#define RGA_ALPHA_NORMAL 0
#define RGA_ALPHA_REVERSE 1
#define RGA_ALPHA_BLEND_GLOBAL 0
#define RGA_ALPHA_BLEND_NORMAL 1
#define RGA_ALPHA_BLEND_MULTIPLY 2
#define RGA_ALPHA_CAL_CUT 0
#define RGA_ALPHA_CAL_NORMAL 1
#define RGA_ALPHA_FACTOR_ZERO 0
#define RGA_ALPHA_FACTOR_ONE 1
#define RGA_ALPHA_FACTOR_OTHER 2
#define RGA_ALPHA_FACTOR_OTHER_REVERSE 3
#define RGA_ALPHA_FACTOR_SELF 4
#define RGA_ALPHA_COLOR_NORMAL 0
#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
/* Registers union */
union rga_mode_ctrl {
unsigned int val;
struct {
/* [0:2] */
unsigned int render:3;
/* [3:6] */
unsigned int bitblt:1;
unsigned int cf_rop4_pat:1;
unsigned int alpha_zero_key:1;
unsigned int gradient_sat:1;
/* [7:31] */
unsigned int reserved:25;
} data;
};
union rga_src_info {
unsigned int val;
struct {
/* [0:3] */
unsigned int format:4;
/* [4:7] */
unsigned int swap:3;
unsigned int cp_endian:1;
/* [8:17] */
unsigned int csc_mode:2;
unsigned int rot_mode:2;
unsigned int mir_mode:2;
unsigned int hscl_mode:2;
unsigned int vscl_mode:2;
/* [18:22] */
unsigned int trans_mode:1;
unsigned int trans_enable:4;
/* [23:25] */
unsigned int dither_up_en:1;
unsigned int bic_coe_sel:2;
/* [26:31] */
unsigned int reserved:6;
} data;
};
union rga_src_vir_info {
unsigned int val;
struct {
/* [0:15] */
unsigned int vir_width:15;
unsigned int reserved:1;
/* [16:25] */
unsigned int vir_stride:10;
/* [26:31] */
unsigned int reserved1:6;
} data;
};
union rga_src_act_info {
unsigned int val;
struct {
/* [0:15] */
unsigned int act_width:13;
unsigned int reserved:3;
/* [16:31] */
unsigned int act_height:13;
unsigned int reserved1:3;
} data;
};
union rga_src_x_factor {
unsigned int val;
struct {
/* [0:15] */
unsigned int down_scale_factor:16;
/* [16:31] */
unsigned int up_scale_factor:16;
} data;
};
union rga_src_y_factor {
unsigned int val;
struct {
/* [0:15] */
unsigned int down_scale_factor:16;
/* [16:31] */
unsigned int up_scale_factor:16;
} data;
};
/* Alpha / Red / Green / Blue */
union rga_src_cp_gr_color {
unsigned int val;
struct {
/* [0:15] */
unsigned int gradient_x:16;
/* [16:31] */
unsigned int gradient_y:16;
} data;
};
union rga_src_transparency_color0 {
unsigned int val;
struct {
/* [0:7] */
unsigned int trans_rmin:8;
/* [8:15] */
unsigned int trans_gmin:8;
/* [16:23] */
unsigned int trans_bmin:8;
/* [24:31] */
unsigned int trans_amin:8;
} data;
};
union rga_src_transparency_color1 {
unsigned int val;
struct {
/* [0:7] */
unsigned int trans_rmax:8;
/* [8:15] */
unsigned int trans_gmax:8;
/* [16:23] */
unsigned int trans_bmax:8;
/* [24:31] */
unsigned int trans_amax:8;
} data;
};
union rga_dst_info {
unsigned int val;
struct {
/* [0:3] */
unsigned int format:4;
/* [4:6] */
unsigned int swap:3;
/* [7:9] */
unsigned int src1_format:3;
/* [10:11] */
unsigned int src1_swap:2;
/* [12:15] */
unsigned int dither_up_en:1;
unsigned int dither_down_en:1;
unsigned int dither_down_mode:2;
/* [16:18] */
unsigned int csc_mode:2;
unsigned int csc_clip:1;
/* [19:31] */
unsigned int reserved:13;
} data;
};
union rga_dst_vir_info {
unsigned int val;
struct {
/* [0:15] */
unsigned int vir_stride:15;
unsigned int reserved:1;
/* [16:31] */
unsigned int src1_vir_stride:15;
unsigned int reserved1:1;
} data;
};
union rga_dst_act_info {
unsigned int val;
struct {
/* [0:15] */
unsigned int act_width:12;
unsigned int reserved:4;
/* [16:31] */
unsigned int act_height:12;
unsigned int reserved1:4;
} data;
};
union rga_alpha_ctrl0 {
unsigned int val;
struct {
/* [0:3] */
unsigned int rop_en:1;
unsigned int rop_select:1;
unsigned int rop_mode:2;
/* [4:11] */
unsigned int src_fading_val:8;
/* [12:20] */
unsigned int dst_fading_val:8;
unsigned int mask_endian:1;
/* [21:31] */
unsigned int reserved:11;
} data;
};
union rga_alpha_ctrl1 {
unsigned int val;
struct {
/* [0:1] */
unsigned int dst_color_m0:1;
unsigned int src_color_m0:1;
/* [2:7] */
unsigned int dst_factor_m0:3;
unsigned int src_factor_m0:3;
/* [8:9] */
unsigned int dst_alpha_cal_m0:1;
unsigned int src_alpha_cal_m0:1;
/* [10:13] */
unsigned int dst_blend_m0:2;
unsigned int src_blend_m0:2;
/* [14:15] */
unsigned int dst_alpha_m0:1;
unsigned int src_alpha_m0:1;
/* [16:21] */
unsigned int dst_factor_m1:3;
unsigned int src_factor_m1:3;
/* [22:23] */
unsigned int dst_alpha_cal_m1:1;
unsigned int src_alpha_cal_m1:1;
/* [24:27] */
unsigned int dst_blend_m1:2;
unsigned int src_blend_m1:2;
/* [28:29] */
unsigned int dst_alpha_m1:1;
unsigned int src_alpha_m1:1;
/* [30:31] */
unsigned int reserved:2;
} data;
};
union rga_fading_ctrl {
unsigned int val;
struct {
/* [0:7] */
unsigned int fading_offset_r:8;
/* [8:15] */
unsigned int fading_offset_g:8;
/* [16:23] */
unsigned int fading_offset_b:8;
/* [24:31] */
unsigned int fading_en:1;
unsigned int reserved:7;
} data;
};
union rga_pat_con {
unsigned int val;
struct {
/* [0:7] */
unsigned int width:8;
/* [8:15] */
unsigned int height:8;
/* [16:23] */
unsigned int offset_x:8;
/* [24:31] */
unsigned int offset_y:8;
} data;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,125 @@
/*
* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
* Author: Jacob Chen <jacob-chen@iotwrt.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.
*/
#ifndef __RGA_H__
#define __RGA_H__
#include <linux/platform_device.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#define RGA_NAME "rockchip-rga"
struct rga_fmt {
u32 fourcc;
int depth;
u8 uv_factor;
u8 y_div;
u8 x_div;
u8 color_swap;
u8 hw_format;
};
struct rga_frame {
/* Original dimensions */
u32 width;
u32 height;
u32 colorspace;
/* Crop */
struct v4l2_rect crop;
/* Image format */
struct rga_fmt *fmt;
/* Variables that can calculated once and reused */
u32 stride;
u32 size;
};
struct rockchip_rga_version {
u32 major;
u32 minor;
};
struct rga_ctx {
struct v4l2_fh fh;
struct rockchip_rga *rga;
struct rga_frame in;
struct rga_frame out;
struct v4l2_ctrl_handler ctrl_handler;
/* Control values */
u32 op;
u32 hflip;
u32 vflip;
u32 rotate;
u32 fill_color;
};
struct rockchip_rga {
struct v4l2_device v4l2_dev;
struct v4l2_m2m_dev *m2m_dev;
struct video_device *vfd;
struct device *dev;
struct regmap *grf;
void __iomem *regs;
struct clk *sclk;
struct clk *aclk;
struct clk *hclk;
struct rockchip_rga_version version;
/* vfd lock */
struct mutex mutex;
/* ctrl parm lock */
spinlock_t ctrl_lock;
wait_queue_head_t irq_queue;
struct rga_ctx *curr;
dma_addr_t cmdbuf_phy;
void *cmdbuf_virt;
unsigned int *src_mmu_pages;
unsigned int *dst_mmu_pages;
};
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
/* RGA Buffers Manage */
extern const struct vb2_ops rga_qops;
void rga_buf_map(struct vb2_buffer *vb);
/* RGA Hardware */
static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
{
writel(value, rga->regs + reg);
};
static inline u32 rga_read(struct rockchip_rga *rga, u32 reg)
{
return readl(rga->regs + reg);
};
static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
{
u32 temp = rga_read(rga, reg) & ~(mask);
temp |= val & mask;
rga_write(rga, reg, temp);
};
void rga_hw_start(struct rockchip_rga *rga);
#endif