162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 462306a36Sopenharmony_ci * Author: Jacob Chen <jacob-chen@iotwrt.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "rga-hw.h" 1062306a36Sopenharmony_ci#include "rga.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cienum e_rga_start_pos { 1362306a36Sopenharmony_ci LT = 0, 1462306a36Sopenharmony_ci LB = 1, 1562306a36Sopenharmony_ci RT = 2, 1662306a36Sopenharmony_ci RB = 3, 1762306a36Sopenharmony_ci}; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct rga_addr_offset { 2062306a36Sopenharmony_ci unsigned int y_off; 2162306a36Sopenharmony_ci unsigned int u_off; 2262306a36Sopenharmony_ci unsigned int v_off; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct rga_corners_addr_offset { 2662306a36Sopenharmony_ci struct rga_addr_offset left_top; 2762306a36Sopenharmony_ci struct rga_addr_offset right_top; 2862306a36Sopenharmony_ci struct rga_addr_offset left_bottom; 2962306a36Sopenharmony_ci struct rga_addr_offset right_bottom; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic unsigned int rga_get_scaling(unsigned int src, unsigned int dst) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci /* 3562306a36Sopenharmony_ci * The rga hw scaling factor is a normalized inverse of the 3662306a36Sopenharmony_ci * scaling factor. 3762306a36Sopenharmony_ci * For example: When source width is 100 and destination width is 200 3862306a36Sopenharmony_ci * (scaling of 2x), then the hw factor is NC * 100 / 200. 3962306a36Sopenharmony_ci * The normalization factor (NC) is 2^16 = 0x10000. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct rga_corners_addr_offset 4662306a36Sopenharmony_cirga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y, 4762306a36Sopenharmony_ci unsigned int w, unsigned int h) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct rga_corners_addr_offset offsets; 5062306a36Sopenharmony_ci struct rga_addr_offset *lt, *lb, *rt, *rb; 5162306a36Sopenharmony_ci unsigned int x_div = 0, 5262306a36Sopenharmony_ci y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci lt = &offsets.left_top; 5562306a36Sopenharmony_ci lb = &offsets.left_bottom; 5662306a36Sopenharmony_ci rt = &offsets.right_top; 5762306a36Sopenharmony_ci rb = &offsets.right_bottom; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci x_div = frm->fmt->x_div; 6062306a36Sopenharmony_ci y_div = frm->fmt->y_div; 6162306a36Sopenharmony_ci uv_factor = frm->fmt->uv_factor; 6262306a36Sopenharmony_ci uv_stride = frm->stride / x_div; 6362306a36Sopenharmony_ci pixel_width = frm->stride / frm->width; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci lt->y_off = y * frm->stride + x * pixel_width; 6662306a36Sopenharmony_ci lt->u_off = 6762306a36Sopenharmony_ci frm->width * frm->height + (y / y_div) * uv_stride + x / x_div; 6862306a36Sopenharmony_ci lt->v_off = lt->u_off + frm->width * frm->height / uv_factor; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci lb->y_off = lt->y_off + (h - 1) * frm->stride; 7162306a36Sopenharmony_ci lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride; 7262306a36Sopenharmony_ci lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci rt->y_off = lt->y_off + (w - 1) * pixel_width; 7562306a36Sopenharmony_ci rt->u_off = lt->u_off + w / x_div - 1; 7662306a36Sopenharmony_ci rt->v_off = lt->v_off + w / x_div - 1; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci rb->y_off = lb->y_off + (w - 1) * pixel_width; 7962306a36Sopenharmony_ci rb->u_off = lb->u_off + w / x_div - 1; 8062306a36Sopenharmony_ci rb->v_off = lb->v_off + w / x_div - 1; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return offsets; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic struct rga_addr_offset *rga_lookup_draw_pos(struct 8662306a36Sopenharmony_ci rga_corners_addr_offset 8762306a36Sopenharmony_ci * offsets, u32 rotate_mode, 8862306a36Sopenharmony_ci u32 mirr_mode) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci static enum e_rga_start_pos rot_mir_point_matrix[4][4] = { 9162306a36Sopenharmony_ci { 9262306a36Sopenharmony_ci LT, RT, LB, RB, 9362306a36Sopenharmony_ci }, 9462306a36Sopenharmony_ci { 9562306a36Sopenharmony_ci RT, LT, RB, LB, 9662306a36Sopenharmony_ci }, 9762306a36Sopenharmony_ci { 9862306a36Sopenharmony_ci RB, LB, RT, LT, 9962306a36Sopenharmony_ci }, 10062306a36Sopenharmony_ci { 10162306a36Sopenharmony_ci LB, RB, LT, RT, 10262306a36Sopenharmony_ci }, 10362306a36Sopenharmony_ci }; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (!offsets) 10662306a36Sopenharmony_ci return NULL; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) { 10962306a36Sopenharmony_ci case LT: 11062306a36Sopenharmony_ci return &offsets->left_top; 11162306a36Sopenharmony_ci case LB: 11262306a36Sopenharmony_ci return &offsets->left_bottom; 11362306a36Sopenharmony_ci case RT: 11462306a36Sopenharmony_ci return &offsets->right_top; 11562306a36Sopenharmony_ci case RB: 11662306a36Sopenharmony_ci return &offsets->right_bottom; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return NULL; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct rockchip_rga *rga = ctx->rga; 12562306a36Sopenharmony_ci u32 *dest = rga->cmdbuf_virt; 12662306a36Sopenharmony_ci unsigned int reg; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG; 12962306a36Sopenharmony_ci dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; 13262306a36Sopenharmony_ci dest[reg >> 2] |= 0x7; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct rockchip_rga *rga = ctx->rga; 13862306a36Sopenharmony_ci u32 *dest = rga->cmdbuf_virt; 13962306a36Sopenharmony_ci unsigned int reg; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG; 14262306a36Sopenharmony_ci dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; 14562306a36Sopenharmony_ci dest[reg >> 2] |= 0x7 << 4; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct rockchip_rga *rga = ctx->rga; 15162306a36Sopenharmony_ci u32 *dest = rga->cmdbuf_virt; 15262306a36Sopenharmony_ci unsigned int reg; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG; 15562306a36Sopenharmony_ci dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; 15862306a36Sopenharmony_ci dest[reg >> 2] |= 0x7 << 8; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void rga_cmd_set_trans_info(struct rga_ctx *ctx) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct rockchip_rga *rga = ctx->rga; 16462306a36Sopenharmony_ci u32 *dest = rga->cmdbuf_virt; 16562306a36Sopenharmony_ci unsigned int scale_dst_w, scale_dst_h; 16662306a36Sopenharmony_ci unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y; 16762306a36Sopenharmony_ci union rga_src_info src_info; 16862306a36Sopenharmony_ci union rga_dst_info dst_info; 16962306a36Sopenharmony_ci union rga_src_x_factor x_factor; 17062306a36Sopenharmony_ci union rga_src_y_factor y_factor; 17162306a36Sopenharmony_ci union rga_src_vir_info src_vir_info; 17262306a36Sopenharmony_ci union rga_src_act_info src_act_info; 17362306a36Sopenharmony_ci union rga_dst_vir_info dst_vir_info; 17462306a36Sopenharmony_ci union rga_dst_act_info dst_act_info; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci struct rga_addr_offset *dst_offset; 17762306a36Sopenharmony_ci struct rga_corners_addr_offset offsets; 17862306a36Sopenharmony_ci struct rga_corners_addr_offset src_offsets; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci src_h = ctx->in.crop.height; 18162306a36Sopenharmony_ci src_w = ctx->in.crop.width; 18262306a36Sopenharmony_ci src_x = ctx->in.crop.left; 18362306a36Sopenharmony_ci src_y = ctx->in.crop.top; 18462306a36Sopenharmony_ci dst_h = ctx->out.crop.height; 18562306a36Sopenharmony_ci dst_w = ctx->out.crop.width; 18662306a36Sopenharmony_ci dst_x = ctx->out.crop.left; 18762306a36Sopenharmony_ci dst_y = ctx->out.crop.top; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2]; 19062306a36Sopenharmony_ci dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2]; 19162306a36Sopenharmony_ci x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2]; 19262306a36Sopenharmony_ci y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2]; 19362306a36Sopenharmony_ci src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2]; 19462306a36Sopenharmony_ci src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2]; 19562306a36Sopenharmony_ci dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2]; 19662306a36Sopenharmony_ci dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2]; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci src_info.data.format = ctx->in.fmt->hw_format; 19962306a36Sopenharmony_ci src_info.data.swap = ctx->in.fmt->color_swap; 20062306a36Sopenharmony_ci dst_info.data.format = ctx->out.fmt->hw_format; 20162306a36Sopenharmony_ci dst_info.data.swap = ctx->out.fmt->color_swap; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * CSC mode must only be set when the colorspace families differ between 20562306a36Sopenharmony_ci * input and output. It must remain unset (zeroed) if both are the same. 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) && 20962306a36Sopenharmony_ci RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) { 21062306a36Sopenharmony_ci switch (ctx->in.colorspace) { 21162306a36Sopenharmony_ci case V4L2_COLORSPACE_REC709: 21262306a36Sopenharmony_ci src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0; 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci default: 21562306a36Sopenharmony_ci src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R0; 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) && 22162306a36Sopenharmony_ci RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) { 22262306a36Sopenharmony_ci switch (ctx->out.colorspace) { 22362306a36Sopenharmony_ci case V4L2_COLORSPACE_REC709: 22462306a36Sopenharmony_ci dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci default: 22762306a36Sopenharmony_ci dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0; 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (ctx->vflip) 23362306a36Sopenharmony_ci src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (ctx->hflip) 23662306a36Sopenharmony_ci src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci switch (ctx->rotate) { 23962306a36Sopenharmony_ci case 90: 24062306a36Sopenharmony_ci src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE; 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci case 180: 24362306a36Sopenharmony_ci src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci case 270: 24662306a36Sopenharmony_ci src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci default: 24962306a36Sopenharmony_ci src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * Calculate the up/down scaling mode/factor. 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * RGA used to scale the picture first, and then rotate second, 25762306a36Sopenharmony_ci * so we need to swap the w/h when rotate degree is 90/270. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE || 26062306a36Sopenharmony_ci src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) { 26162306a36Sopenharmony_ci if (rga->version.major == 0 || rga->version.minor == 0) { 26262306a36Sopenharmony_ci if (dst_w == src_h) 26362306a36Sopenharmony_ci src_h -= 8; 26462306a36Sopenharmony_ci if (abs(src_w - dst_h) < 16) 26562306a36Sopenharmony_ci src_w -= 16; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci scale_dst_h = dst_w; 26962306a36Sopenharmony_ci scale_dst_w = dst_h; 27062306a36Sopenharmony_ci } else { 27162306a36Sopenharmony_ci scale_dst_w = dst_w; 27262306a36Sopenharmony_ci scale_dst_h = dst_h; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (src_w == scale_dst_w) { 27662306a36Sopenharmony_ci src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO; 27762306a36Sopenharmony_ci x_factor.val = 0; 27862306a36Sopenharmony_ci } else if (src_w > scale_dst_w) { 27962306a36Sopenharmony_ci src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN; 28062306a36Sopenharmony_ci x_factor.data.down_scale_factor = 28162306a36Sopenharmony_ci rga_get_scaling(src_w, scale_dst_w) + 1; 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP; 28462306a36Sopenharmony_ci x_factor.data.up_scale_factor = 28562306a36Sopenharmony_ci rga_get_scaling(src_w - 1, scale_dst_w - 1); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (src_h == scale_dst_h) { 28962306a36Sopenharmony_ci src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO; 29062306a36Sopenharmony_ci y_factor.val = 0; 29162306a36Sopenharmony_ci } else if (src_h > scale_dst_h) { 29262306a36Sopenharmony_ci src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN; 29362306a36Sopenharmony_ci y_factor.data.down_scale_factor = 29462306a36Sopenharmony_ci rga_get_scaling(src_h, scale_dst_h) + 1; 29562306a36Sopenharmony_ci } else { 29662306a36Sopenharmony_ci src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP; 29762306a36Sopenharmony_ci y_factor.data.up_scale_factor = 29862306a36Sopenharmony_ci rga_get_scaling(src_h - 1, scale_dst_h - 1); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * Calculate the framebuffer virtual strides and active size, 30362306a36Sopenharmony_ci * note that the step of vir_stride / vir_width is 4 byte words 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci src_vir_info.data.vir_stride = ctx->in.stride >> 2; 30662306a36Sopenharmony_ci src_vir_info.data.vir_width = ctx->in.stride >> 2; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci src_act_info.data.act_height = src_h - 1; 30962306a36Sopenharmony_ci src_act_info.data.act_width = src_w - 1; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci dst_vir_info.data.vir_stride = ctx->out.stride >> 2; 31262306a36Sopenharmony_ci dst_act_info.data.act_height = dst_h - 1; 31362306a36Sopenharmony_ci dst_act_info.data.act_width = dst_w - 1; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * Calculate the source framebuffer base address with offset pixel. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y, 31962306a36Sopenharmony_ci src_w, src_h); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * Configure the dest framebuffer base address with pixel offset. 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ci offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h); 32562306a36Sopenharmony_ci dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode, 32662306a36Sopenharmony_ci src_info.data.mir_mode); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = 32962306a36Sopenharmony_ci src_offsets.left_top.y_off; 33062306a36Sopenharmony_ci dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = 33162306a36Sopenharmony_ci src_offsets.left_top.u_off; 33262306a36Sopenharmony_ci dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = 33362306a36Sopenharmony_ci src_offsets.left_top.v_off; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val; 33662306a36Sopenharmony_ci dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val; 33762306a36Sopenharmony_ci dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val; 33862306a36Sopenharmony_ci dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = 34362306a36Sopenharmony_ci dst_offset->y_off; 34462306a36Sopenharmony_ci dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = 34562306a36Sopenharmony_ci dst_offset->u_off; 34662306a36Sopenharmony_ci dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = 34762306a36Sopenharmony_ci dst_offset->v_off; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val; 35062306a36Sopenharmony_ci dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void rga_cmd_set_mode(struct rga_ctx *ctx) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct rockchip_rga *rga = ctx->rga; 35862306a36Sopenharmony_ci u32 *dest = rga->cmdbuf_virt; 35962306a36Sopenharmony_ci union rga_mode_ctrl mode; 36062306a36Sopenharmony_ci union rga_alpha_ctrl0 alpha_ctrl0; 36162306a36Sopenharmony_ci union rga_alpha_ctrl1 alpha_ctrl1; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci mode.val = 0; 36462306a36Sopenharmony_ci alpha_ctrl0.val = 0; 36562306a36Sopenharmony_ci alpha_ctrl1.val = 0; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci mode.data.gradient_sat = 1; 36862306a36Sopenharmony_ci mode.data.render = RGA_MODE_RENDER_BITBLT; 36962306a36Sopenharmony_ci mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* disable alpha blending */ 37262306a36Sopenharmony_ci dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val; 37362306a36Sopenharmony_ci dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void rga_cmd_set(struct rga_ctx *ctx) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct rockchip_rga *rga = ctx->rga; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci rga_cmd_set_src_addr(ctx, rga->src_mmu_pages); 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * Due to hardware bug, 38762306a36Sopenharmony_ci * src1 mmu also should be configured when using alpha blending. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages); 39262306a36Sopenharmony_ci rga_cmd_set_mode(ctx); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci rga_cmd_set_trans_info(ctx); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* sync CMD buf for RGA */ 39962306a36Sopenharmony_ci dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy, 40062306a36Sopenharmony_ci PAGE_SIZE, DMA_BIDIRECTIONAL); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_civoid rga_hw_start(struct rockchip_rga *rga) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct rga_ctx *ctx = rga->curr; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci rga_cmd_set(ctx); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci rga_write(rga, RGA_SYS_CTRL, 0x00); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci rga_write(rga, RGA_SYS_CTRL, 0x22); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci rga_write(rga, RGA_INT, 0x600); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci rga_write(rga, RGA_CMD_CTRL, 0x1); 41662306a36Sopenharmony_ci} 417