1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1085 lines
29 KiB

/*
* Copyright (C) 2016 Fuzhou Rcockhip Electronics Co.Ltd
* Authors:
* Yakir Yang <ykk@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <android/log.h>
#include <sys/mman.h>
#include <linux/stddef.h>
#include <xf86drm.h>
#include "drm_fourcc.h"
//#include "libdrm_macros.h"
#include "rockchip_drm.h"
#include "rockchip_rga.h"
#include "rga_reg.h"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "libdrm", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "libdrm", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "libdrm", __VA_ARGS__)
enum rga_base_addr_reg {
rga_dst = 0,
rga_src
};
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 int rga_get_uv_factor(int drm_color_format)
{
int ydiv = 1;
switch (drm_color_format) {
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
ydiv = 2;
break;
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV12_10:
//case DRM_FORMAT_NV21_10:
ydiv = 4;
break;
default:
break;
}
return ydiv;
}
static int rga_get_ydiv(int drm_color_format)
{
int ydiv = 1;
switch (drm_color_format) {
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
ydiv = 1;
break;
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV12_10:
//case DRM_FORMAT_NV21_10:
ydiv = 2;
break;
default:
break;
}
return ydiv;
}
static int rga_get_xdiv(int drm_color_format)
{
int xdiv = 2;
switch (drm_color_format) {
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV12_10:
//case DRM_FORMAT_NV21_10:
xdiv = 1;
break;
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
xdiv = 2;
break;
default:
break;
}
return xdiv;
}
static int rga_get_color_swap(int drm_color_format)
{
unsigned int swap = 0;
switch (drm_color_format) {
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA5551:
case DRM_FORMAT_RGBA4444:
case DRM_FORMAT_RGB888:
case DRM_FORMAT_RGB565:
break;
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YUV420:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV12_10:
break;
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR1555:
case DRM_FORMAT_ABGR4444:
swap |= RGA_SRC_COLOR_ALPHA_SWAP;
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA5551:
case DRM_FORMAT_BGRA4444:
case DRM_FORMAT_BGR888:
case DRM_FORMAT_BGR565:
swap |= RGA_SRC_COLOR_RB_SWAP;
break;
case DRM_FORMAT_YVU422:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV61:
//case DRM_FORMAT_NV21_10:
swap |= RGA_SRC_COLOR_UV_SWAP;
break;
default:
printf("Unsupport input color format %d\n", drm_color_format);
break;
}
return swap;
}
static int rga_get_color_format(int drm_color_format)
{
switch (drm_color_format) {
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_RGBA8888:
return RGA_SRC_COLOR_FMT_ABGR8888;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_BGRX8888:
return RGA_SRC_COLOR_FMT_XBGR8888;
case DRM_FORMAT_RGB888:
case DRM_FORMAT_BGR888:
return RGA_SRC_COLOR_FMT_RGB888;
case DRM_FORMAT_RGB565:
case DRM_FORMAT_BGR565:
return RGA_SRC_COLOR_FMT_RGB565;
case DRM_FORMAT_ARGB1555:
case DRM_FORMAT_ABGR1555:
case DRM_FORMAT_RGBA5551:
case DRM_FORMAT_BGRA5551:
return RGA_SRC_COLOR_FMT_ARGB1555;
case DRM_FORMAT_ARGB4444:
case DRM_FORMAT_ABGR4444:
case DRM_FORMAT_RGBA4444:
case DRM_FORMAT_BGRA4444:
return RGA_SRC_COLOR_FMT_ARGB4444;
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
return RGA_SRC_COLOR_FMT_YUV422SP;
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
return RGA_SRC_COLOR_FMT_YUV422P;
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV12_10:
//case DRM_FORMAT_NV21_10:
return RGA_SRC_COLOR_FMT_YUV420SP;
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
return RGA_SRC_COLOR_FMT_YUV420P;
default:
return -EINVAL;
};
}
int get_string_of_cmd(int index,char *buf)
{
switch (index) {
case MODE_CTRL :strcpy(buf,"MODE_CTRL ");break;
case SRC_INFO :strcpy(buf,"SRC_INFO ");break;
case SRC_Y_RGB_BASE_ADDR:strcpy(buf,"SRC_Y_RGB_BASE_ADDR");break;
case SRC_CB_BASE_ADDR :strcpy(buf,"SRC_CB_BASE_ADDR ");break;
case SRC_CR_BASE_ADDR :strcpy(buf,"SRC_CR_BASE_ADDR ");break;
case SRC1_RGB_BASE_ADDR :strcpy(buf,"SRC1_RGB_BASE_ADDR ");break;
case SRC_VIR_INFO :strcpy(buf,"SRC_VIR_INFO ");break;
case SRC_ACT_INFO :strcpy(buf,"SRC_ACT_INFO ");break;
case SRC_X_FACTOR :strcpy(buf,"SRC_X_FACTOR ");break;
case SRC_Y_FACTOR :strcpy(buf,"SRC_Y_FACTOR ");break;
case SRC_BG_COLOR :strcpy(buf,"SRC_BG_COLOR ");break;
case SRC_FG_COLOR :strcpy(buf,"SRC_FG_COLOR ");break;
case SRC_TR_COLOR0 :strcpy(buf,"SRC_TR_COLOR0 ");break;
case SRC_TR_COLOR1 :strcpy(buf,"SRC_TR_COLOR1 ");break;
case DST_INFO :strcpy(buf,"DST_INFO ");break;
case DST_Y_RGB_BASE_ADDR:strcpy(buf,"DST_Y_RGB_BASE_ADDR");break;
case DST_CB_BASE_ADDR :strcpy(buf,"DST_CB_BASE_ADDR ");break;
case DST_CR_BASE_ADDR :strcpy(buf,"DST_CR_BASE_ADDR ");break;
case DST_VIR_INFO :strcpy(buf,"DST_VIR_INFO ");break;
case DST_ACT_INFO :strcpy(buf,"DST_ACT_INFO ");break;
case ALPHA_CTRL0 :strcpy(buf,"ALPHA_CTRL0 ");break;
case ALPHA_CTRL1 :strcpy(buf,"ALPHA_CTRL1 ");break;
case FADING_CTRL :strcpy(buf,"FADING_CTRL ");break;
case PAT_CON :strcpy(buf,"PAT_CON ");break;
case ROP_CON0 :strcpy(buf,"ROP_CON0 ");break;
case ROP_CON1 :strcpy(buf,"ROP_CON1 ");break;
case MASK_BASE :strcpy(buf,"MASK_BASE ");break;
case MMU_CTRL1 :strcpy(buf,"MMU_CTRL1 ");break;
case MMU_SRC_BASE :strcpy(buf,"MMU_SRC_BASE ");break;
case MMU_SRC1_BASE :strcpy(buf,"MMU_SRC1_BASE ");break;
case MMU_DST_BASE :strcpy(buf,"MMU_DST_BASE ");break;
case MMU_ELS_BASE :strcpy(buf,"MMU_ELS_BASE ");break;
case RGA_BUF_TYPE_GEMFD | SRC_Y_RGB_BASE_ADDR:
strcpy(buf,"SRC_Y_RGB_BASE_ADDR");break;
case RGA_BUF_TYPE_GEMFD | DST_Y_RGB_BASE_ADDR:
strcpy(buf,"DST_Y_RGB_BASE_ADDR");break;
default :strcpy(buf,"ERROR_OFFSET ");break;
}
return 0;
}
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_image *img, 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 = rga_get_xdiv(img->color_mode);
y_div = rga_get_ydiv(img->color_mode);
uv_factor = rga_get_uv_factor(img->color_mode);
uv_stride = img->stride / x_div;
pixel_width = img->stride / img->width;
lt->y_off = y * img->stride + x * pixel_width;
lt->u_off = img->stride * img->hstride + (y / y_div) * uv_stride + x / x_div;
lt->v_off = lt->u_off + img->width * img->hstride / uv_factor;
lb->y_off = lt->y_off + (h - 1) * img->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,
enum e_rga_src_rot_mode rotate_mode,
enum e_rga_src_mirr_mode 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 == NULL)
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;
}
/*
* rga_add_cmd - set given command and value to user side command buffer.
*
* @ctx: a pointer to rga_context structure.
* @cmd: command data.
* @value: value data.
*/
static int rga_add_cmd(struct rga_context *ctx, unsigned long cmd,
unsigned long value)
{
char buf[25];
const char *fmt;
if (ctx->log & 1) {
get_string_of_cmd(cmd, buf);
fprintf(stderr,"%s:0x%x:0x%x\n",buf,cmd,value);
LOGI("%s:%8x: 0x%x\n",buf,cmd,value);
}
switch (cmd & ~(RGA_IMGBUF_USERPTR)) {
case SRC_Y_RGB_BASE_ADDR:
case SRC_CB_BASE_ADDR:
case SRC_CR_BASE_ADDR:
case SRC1_RGB_BASE_ADDR:
case DST_Y_RGB_BASE_ADDR:
case DST_CB_BASE_ADDR:
case DST_CR_BASE_ADDR:
if (ctx->cmd_buf_nr >= RGA_MAX_GEM_CMD_NR) {
fprintf(stderr, "Overflow cmd_gem size.\n");
return -EINVAL;
}
ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd;
ctx->cmd_buf[ctx->cmd_buf_nr].data = value;
ctx->cmd_buf_nr++;
break;
default:
if (ctx->cmd_nr >= RGA_MAX_CMD_NR) {
fprintf(stderr, "Overflow cmd size.\n");
return -EINVAL;
}
ctx->cmd[ctx->cmd_nr].offset = cmd;
ctx->cmd[ctx->cmd_nr].data = value;
ctx->cmd_nr++;
break;
}
return 0;
}
int rga_dump_context(struct rga_context ctx)
{
int i = 0;
char buf[25];
fprintf(stderr,"********************frame start************************\n"
"fd=%d,major=%d,minor=%d\n"
"cmd_nr=%d,cmd=%p\n"
"cmd_buf_nr=%d,cmd_buf=%p\n"
"cmdlist_nr=%d\n",
ctx.fd,ctx.major,ctx.minor,ctx.cmd_nr,ctx.cmd,
ctx.cmd_buf_nr,ctx.cmd_buf,ctx.cmdlist_nr);
fprintf(stderr,"\n---------------cmd_nr=%d,cmd=%p:\n",ctx.cmd_nr,ctx.cmd);
for(i = 0; i < ctx.cmd_nr; i ++) {
get_string_of_cmd(ctx.cmd[i].offset,buf);
fprintf(stderr,"%s:0x%x:[0x%x]\n",
buf,ctx.cmd[i].offset,ctx.cmd[i].data);
}
fprintf(stderr,"\ncmd_buf_nr=%d,cmd_buf=%p\n",ctx.cmd_buf_nr,ctx.cmd_buf);
for(i = 0; i < ctx.cmd_buf_nr; i ++) {
get_string_of_cmd(ctx.cmd_buf[i].offset,buf);
fprintf(stderr,"%s:0x%x:[0x%x]\n",
buf,ctx.cmd_buf[i].offset,ctx.cmd_buf[i].data);
}
fprintf(stderr,"*******************frame end*************************\n");
return 0;
}
int rga_src_color_is_yuv(int format)
{
int ret = 0;
switch (format) {
case RGA_SRC_COLOR_FMT_YUV422SP:
case RGA_SRC_COLOR_FMT_YUV422P:
case RGA_SRC_COLOR_FMT_YUV420SP:
case RGA_SRC_COLOR_FMT_YUV420P:
ret = 1;
break;
default:
break;
}
return ret;
}
int rga_dst_color_is_yuv(int format)
{
int ret = 0;
switch (format) {
case RGA_DST_COLOR_FMT_YUV422SP:
case RGA_DST_COLOR_FMT_YUV422P:
case RGA_DST_COLOR_FMT_YUV420SP:
case RGA_DST_COLOR_FMT_YUV420P:
ret = 1;
break;
default:
break;
}
return ret;
}
/*
* rga_add_base_addr - helper function to set dst/src base address register.
*
* @ctx: a pointer to rga_context structure.
* @img: a pointer to the dst/src rga_image structure.
* @reg: the register that should be set.
*/
static void rga_add_base_addr(struct rga_context *ctx, struct rga_image *img,
enum rga_base_addr_reg reg)
{
const unsigned long cmd = (reg == rga_dst) ?
DST_Y_RGB_BASE_ADDR : SRC_Y_RGB_BASE_ADDR;
if (img->buf_type == RGA_IMGBUF_USERPTR) {
fprintf(stderr, "Can't support userptr now!\n");
return;
} else {
rga_add_cmd(ctx, cmd | RGA_BUF_TYPE_GEMFD, img->bo[0]);
}
}
/*
* rga_reset - reset rga hardware.
*
* @ctx: a pointer to rga_context structure.
*
*/
static void rga_reset(struct rga_context *ctx)
{
ctx->cmd_nr = 0;
ctx->cmd_buf_nr = 0;
}
/*
* rga_flush - submit all commands and values in user side command buffer
* to command queue aware of rga dma.
*
* @ctx: a pointer to rga_context structure.
*
* This function should be called after all commands and values to user
* side command buffer are set. It submits that buffer to the kernel side driver.
*/
static int rga_flush(struct rga_context *ctx)
{
int ret;
struct drm_rockchip_rga_set_cmdlist cmdlist = {0};
if (ctx->cmd_nr == 0 && ctx->cmd_buf_nr == 0)
return -1;
if (ctx->cmdlist_nr >= RGA_MAX_CMD_LIST_NR) {
fprintf(stderr, "Overflow cmdlist.\n");
return -EINVAL;
}
//rga_dump_context(*ctx);
cmdlist.cmd = (uint64_t)(uintptr_t)&ctx->cmd[0];
cmdlist.cmd_buf = (uint64_t)(uintptr_t)&ctx->cmd_buf[0];
cmdlist.cmd_nr = ctx->cmd_nr;
cmdlist.cmd_buf_nr = ctx->cmd_buf_nr;
ctx->cmd_nr = 0;
ctx->cmd_buf_nr = 0;
ret = drmIoctl(ctx->fd, DRM_IOCTL_ROCKCHIP_RGA_SET_CMDLIST, &cmdlist);
if (ret < 0) {
fprintf(stderr, "failed to set cmdlist.\n");
return ret;
}
ctx->cmdlist_nr++;
return ret;
}
/**
* rga_init - create a new rga context and get hardware version.
*
* fd: a file descriptor to an opened drm device.
*/
struct rga_context *rga_init(int fd)
{
struct drm_rockchip_rga_get_ver ver;
struct rga_context *ctx;
int ret;
ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
fprintf(stderr, "failed to allocate context.\n");
return NULL;
}
ctx->fd = fd;
ret = drmIoctl(fd, DRM_IOCTL_ROCKCHIP_RGA_GET_VER, &ver);
if (ret < 0) {
fprintf(stderr, "failed to get version.\n");
free(ctx);
return NULL;
}
ctx->major = ver.major;
ctx->minor = ver.minor;
return ctx;
}
void rga_fini(struct rga_context *ctx)
{
if (ctx)
free(ctx);
}
/**
* rga_exec - start the dma to process all commands summited by rga_flush().
*
* @ctx: a pointer to rga_context structure.
*/
int rga_exec(struct rga_context *ctx)
{
struct drm_rockchip_rga_exec exec;
int ret;
if (ctx->cmdlist_nr == 0)
return -EINVAL;
exec.async = 0;
ret = drmIoctl(ctx->fd, DRM_IOCTL_ROCKCHIP_RGA_EXEC, &exec);
if (ret < 0) {
fprintf(stderr, "failed to execute.\n");
return ret;
}
ctx->cmdlist_nr = 0;
return ret;
}
/**
* rga_solid_fill - fill given buffer with given color data.
*
* @ctx: a pointer to rga_context structure.
* @img: a pointer to rga_image structure including image and buffer
* information.
* @x: x start position to buffer filled with given color data.
* @y: y start position to buffer filled with given color data.
* @w: width value to buffer filled with given color data.
* @h: height value to buffer filled with given color data.
*/
int rga_solid_fill(struct rga_context *ctx, struct rga_image *img,
unsigned int x, unsigned int y, unsigned int w,
unsigned int h)
{
union rga_mode_ctrl mode;
union rga_dst_info dst_info;
union rga_dst_vir_info dst_vir_info;
union rga_dst_act_info dst_act_info;
struct rga_corners_addr_offset offsets;
if (x + w > img->width)
w = img->width - x;
if (y + h > img->height)
h = img->height - y;
/* Init the operation registers to zero */
mode.val = 0;
dst_info.val = 0;
dst_act_info.val = 0;
dst_vir_info.val = 0;
/*
* Configure the RGA operation mode registers:
* Bitblt Mode,
* SRC + DST=> DST,
* Solid color fill,
* Gradient status is not-clip,
*/
mode.data.gradient_sat = 1;
mode.data.render = RGA_MODE_RENDER_BITBLT;
mode.data.render = RGA_MODE_RENDER_RECTANGLE_FILL;
mode.data.cf_rop4_pat = RGA_MODE_CF_ROP4_SOLID,
mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;
rga_add_cmd(ctx, MODE_CTRL, mode.val);
/*
* Translate the DRM color format to RGA color format
*/
dst_info.data.format = rga_get_color_format(img->color_mode);
dst_info.data.swap = rga_get_color_swap(img->color_mode);
dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;
if (dst_info.data.format == RGA_DST_COLOR_FMT_YUV422SP ||
dst_info.data.format == RGA_DST_COLOR_FMT_YUV422P ||
dst_info.data.format == RGA_DST_COLOR_FMT_YUV420SP ||
dst_info.data.format == RGA_DST_COLOR_FMT_YUV420P)
dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;
rga_add_cmd(ctx, DST_INFO, dst_info.val);
/*
* Configure the target color to foreground color.
*/
rga_add_cmd(ctx, SRC_FG_COLOR, img->fill_color);
/*
* Cacluate the framebuffer virtual strides and active size,
* note that the step of vir_stride is 4 byte words
*/
dst_vir_info.data.vir_stride = img->stride >> 2;
dst_act_info.data.act_height = h - 1;
dst_act_info.data.act_width = w - 1;
rga_add_cmd(ctx, DST_VIR_INFO, dst_vir_info.val);
rga_add_cmd(ctx, DST_ACT_INFO, dst_act_info.val);
/*
* Configure the dest framebuffer base address with pixel offset.
*/
offsets = rga_get_addr_offset(img, x, y, w, h);
rga_add_cmd(ctx, DST_Y_RGB_BASE_ADDR, offsets.left_top.y_off);
rga_add_cmd(ctx, DST_CB_BASE_ADDR, offsets.left_top.u_off);
rga_add_cmd(ctx, DST_CR_BASE_ADDR, offsets.left_top.v_off);
rga_add_base_addr(ctx, img, rga_dst);
/* Start to flush RGA device */
rga_flush(ctx);
return 0;
}
int rga_multiple_transform(struct rga_context *ctx, struct rga_image *src,
struct rga_image *dst, unsigned int src_x,
unsigned int src_y, unsigned int src_w,
unsigned int src_h, unsigned int dst_x,
unsigned int dst_y, unsigned int dst_w,
unsigned int dst_h, unsigned int degree,
unsigned int x_mirr, unsigned int y_mirr)
{
union rga_mode_ctrl mode;
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;
unsigned int scale_dst_w, scale_dst_h;
if (degree != 0 && degree != 90 && degree != 180 && degree != 270) {
fprintf(stderr, "invalid rotate degree.\n");
rga_reset(ctx);
return -EINVAL;
}
if (src_w < 32 || src_h < 34 || dst_w < 32 || dst_h < 34) {
fprintf(stderr, "invalid src/dst width or height.\n");
rga_reset(ctx);
return -EINVAL;
}
if (src_x + src_w > src->width)
src_w = src->width - src_x;
if (src_y + src_h > src->height)
src_h = src->height - src_y;
if (dst_x + dst_w > dst->width)
dst_w = dst->width - dst_x;
if (dst_y + dst_h > dst->height)
dst_h = dst->height - dst_y;
if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) {
fprintf(stderr, "invalid width or height.\n");
rga_reset(ctx);
return -EINVAL;
}
/* Init RGA registers values to zero */
mode.val = 0;
x_factor.val = 0;
y_factor.val = 0;
src_info.val = 0;
dst_info.val = 0;
src_vir_info.val = 0;
dst_vir_info.val = 0;
src_act_info.val = 0;
dst_act_info.val = 0;
/*
* Configure the RGA operation mode registers:
* Bitblt Mode,
* SRC => DST,
* Gradient status is not-clip,
*/
mode.data.gradient_sat = 1;
mode.data.render = RGA_MODE_RENDER_BITBLT;
mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;
rga_add_cmd(ctx, MODE_CTRL, mode.val);
/*
* Translate the DRM color format to RGA color format, and
* configure the actual rotate / mirr mode.
*/
src_info.data.format = rga_get_color_format(src->color_mode);
dst_info.data.format = rga_get_color_format(dst->color_mode);
src_info.data.swap = rga_get_color_swap(src->color_mode);
dst_info.data.swap = rga_get_color_swap(dst->color_mode);
if (src->color_mode == DRM_FORMAT_NV12_10) {
src_info.data.yuv_ten_en = RGA_SRC_YUV_TEN_ENABLE;
src_info.data.yuv_ten_round_en = RGA_SRC_YUV_TEN_ROUND_ENABLE;
}
switch (degree) {
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;
}
if (x_mirr)
src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X;
if (y_mirr)
src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y;
/*
* 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 (ctx->major == 0 || ctx->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;
if (src->color_mode == DRM_FORMAT_NV12_10)
src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN | RGA_SRC_HSCL_MODE_UP;
} 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;
if (src->color_mode == DRM_FORMAT_NV12_10)
src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN | RGA_SRC_VSCL_MODE_UP;
} 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);
}
rga_add_cmd(ctx, SRC_X_FACTOR, x_factor.val);
rga_add_cmd(ctx, SRC_Y_FACTOR, y_factor.val);
if (rga_src_color_is_yuv(src_info.data.format)
&& rga_dst_color_is_yuv(dst_info.data.format)) {
src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R0;
dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R0;
}
if (rga_src_color_is_yuv(src_info.data.format)
&& !rga_dst_color_is_yuv(dst_info.data.format))
src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R1;
if (!rga_src_color_is_yuv(src_info.data.format)
&& rga_dst_color_is_yuv(dst_info.data.format))
dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R1;
rga_add_cmd(ctx, SRC_INFO, src_info.val);
rga_add_cmd(ctx, DST_INFO, dst_info.val);
/*
* 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 = 0x3ff;//src->stride >> 2;
src_vir_info.data.vir_width = src->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 = dst->stride >> 2;
dst_act_info.data.act_height = dst_h - 1;
dst_act_info.data.act_width = dst_w - 1;
rga_add_cmd(ctx, SRC_VIR_INFO, src_vir_info.val);
rga_add_cmd(ctx, SRC_ACT_INFO, src_act_info.val);
rga_add_cmd(ctx, DST_VIR_INFO, dst_vir_info.val);
rga_add_cmd(ctx, DST_ACT_INFO, dst_act_info.val);
/*
* Cacluate the source framebuffer base address with offset pixel.
*/
src_offsets = rga_get_addr_offset(src, src_x, src_y, src_w, src_h);
rga_add_cmd(ctx, SRC_Y_RGB_BASE_ADDR, src_offsets.left_top.y_off);
rga_add_cmd(ctx, SRC_CB_BASE_ADDR, src_offsets.left_top.u_off);
rga_add_cmd(ctx, SRC_CR_BASE_ADDR, src_offsets.left_top.v_off);
rga_add_base_addr(ctx, src, rga_src);
/*
* Configure the dest framebuffer base address with pixel offset.
*/
offsets = rga_get_addr_offset(dst, 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);
rga_add_cmd(ctx, DST_Y_RGB_BASE_ADDR, dst_offset->y_off);
rga_add_cmd(ctx, DST_CB_BASE_ADDR, dst_offset->u_off);
rga_add_cmd(ctx, DST_CR_BASE_ADDR, dst_offset->v_off);
rga_add_base_addr(ctx, dst, rga_dst);
/* Start to flush RGA device */
rga_flush(ctx);
return 0;
}
/**
* rga_copy_with_rorate - copy contents in source buffer to destination buffer
* rotate properly.
*
* @ctx: a pointer to rga_context structure.
* @src: a pointer to rga_image structure including image and buffer
* information to source.
* @dst: a pointer to rga_image structure including image and buffer
* information to destination.
* @src_x: x start position to source buffer.
* @src_y: y start position to source buffer.
* @src_w: width value to source buffer.
* @src_h: height value to source buffer.
* @dst_x: x start position to destination buffer.
* @dst_y: y start position to destination buffer.
* @dst_w: width value to destination buffer.
* @dst_h: height value to destination buffer.
* @degree: rotate degree (0, 90, 180, 270)
*/
int rga_copy_with_rotate(struct rga_context *ctx, struct rga_image *src,
struct rga_image *dst, unsigned int src_x,
unsigned int src_y, unsigned int src_w,
unsigned int src_h, unsigned int dst_x,
unsigned int dst_y, unsigned int dst_w,
unsigned int dst_h, unsigned int degree)
{
if (degree != 0 && degree != 90 && degree != 180 && degree != 270) {
fprintf(stderr, "invalid rotate degree %d.\n", degree);
return -EINVAL;
}
return rga_multiple_transform(ctx, src, dst, src_x, src_y, src_w,
src_h, dst_x, dst_y, dst_w, dst_h,
degree, 0, 0);
}
/**
* rga_copy_with_scale - copy contents in source buffer to destination buffer
* scaling up or down properly.
*
* @ctx: a pointer to rga_context structure.
* @src: a pointer to rga_image structure including image and buffer
* information to source.
* @dst: a pointer to rga_image structure including image and buffer
* information to destination.
* @src_x: x start position to source buffer.
* @src_y: y start position to source buffer.
* @src_w: width value to source buffer.
* @src_h: height value to source buffer.
* @dst_x: x start position to destination buffer.
* @dst_y: y start position to destination buffer.
* @dst_w: width value to destination buffer.
* @dst_h: height value to destination buffer.
*/
int rga_copy_with_scale(struct rga_context *ctx, struct rga_image *src,
struct rga_image *dst, unsigned int src_x,
unsigned int src_y, unsigned int src_w,
unsigned int src_h, unsigned int dst_x,
unsigned int dst_y, unsigned int dst_w,
unsigned int dst_h)
{
return rga_multiple_transform(ctx, src, dst, src_x, src_y, src_w,
src_h, dst_x, dst_y, dst_w, dst_h,
0, 0, 0);
}
/**
* rga_copy - copy contents in source buffer to destination buffer.
*
* @ctx: a pointer to rga_context structure.
* @src: a pointer to rga_image structure including image and buffer
* information to source.
* @dst: a pointer to rga_image structure including image and buffer
* information to destination.
* @src_x: x start position to source buffer.
* @src_y: y start position to source buffer.
* @dst_x: x start position to destination buffer.
* @dst_y: y start position to destination buffer.
* @w: width value to source and destination buffers.
* @h: height value to source and destination buffers.
*/
int rga_copy(struct rga_context *ctx, struct rga_image *src,
struct rga_image *dst, unsigned int src_x, unsigned int src_y,
unsigned int dst_x, unsigned dst_y, unsigned int w,
unsigned int h)
{
unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0;
src_w = w;
src_h = h;
if (src_x + src_w > src->width)
src_w = src->width - src_x;
if (src_y + src_h > src->height)
src_h = src->height - src_y;
dst_w = w;
dst_h = h;
if (dst_x + dst_w > dst->width)
dst_w = dst->width - dst_x;
if (dst_y + dst_h > dst->height)
dst_h = dst->height - dst_y;
w = (src_w < dst_w) ? src_w : dst_w;
h = (src_h < dst_h) ? src_h : dst_h;
if (w <= 0 || h <= 0) {
fprintf(stderr, "invalid width or height.\n");
rga_reset(ctx);
return -EINVAL;
}
return rga_multiple_transform(ctx, src, dst, src_x, src_y, src_w,
src_h, dst_x, dst_y, dst_w, dst_h,
0, 0, 0);
}