455 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd4 * Author: Jacob Chen <jacob-chen@iotwrt.com>5 */6 7#include <linux/pm_runtime.h>8 9#include "rga-hw.h"10#include "rga.h"11 12enum e_rga_start_pos {13 LT = 0,14 LB = 1,15 RT = 2,16 RB = 3,17};18 19struct rga_corners_addr_offset {20 struct rga_addr_offset left_top;21 struct rga_addr_offset right_top;22 struct rga_addr_offset left_bottom;23 struct rga_addr_offset right_bottom;24};25 26static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)27{28 /*29 * The rga hw scaling factor is a normalized inverse of the30 * scaling factor.31 * For example: When source width is 100 and destination width is 20032 * (scaling of 2x), then the hw factor is NC * 100 / 200.33 * The normalization factor (NC) is 2^16 = 0x10000.34 */35 36 return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);37}38 39static struct rga_corners_addr_offset40rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,41 unsigned int x, unsigned int y, unsigned int w, unsigned int h)42{43 struct rga_corners_addr_offset offsets;44 struct rga_addr_offset *lt, *lb, *rt, *rb;45 unsigned int x_div = 0,46 y_div = 0, uv_stride = 0, pixel_width = 0;47 48 lt = &offsets.left_top;49 lb = &offsets.left_bottom;50 rt = &offsets.right_top;51 rb = &offsets.right_bottom;52 53 x_div = frm->fmt->x_div;54 y_div = frm->fmt->y_div;55 uv_stride = frm->stride / x_div;56 pixel_width = frm->stride / frm->width;57 58 lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;59 lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;60 lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div;61 62 lb->y_off = lt->y_off + (h - 1) * frm->stride;63 lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;64 lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;65 66 rt->y_off = lt->y_off + (w - 1) * pixel_width;67 rt->u_off = lt->u_off + w / x_div - 1;68 rt->v_off = lt->v_off + w / x_div - 1;69 70 rb->y_off = lb->y_off + (w - 1) * pixel_width;71 rb->u_off = lb->u_off + w / x_div - 1;72 rb->v_off = lb->v_off + w / x_div - 1;73 74 return offsets;75}76 77static struct rga_addr_offset *rga_lookup_draw_pos(struct78 rga_corners_addr_offset79 * offsets, u32 rotate_mode,80 u32 mirr_mode)81{82 static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {83 {84 LT, RT, LB, RB,85 },86 {87 RT, LT, RB, LB,88 },89 {90 RB, LB, RT, LT,91 },92 {93 LB, RB, LT, RT,94 },95 };96 97 if (!offsets)98 return NULL;99 100 switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {101 case LT:102 return &offsets->left_top;103 case LB:104 return &offsets->left_bottom;105 case RT:106 return &offsets->right_top;107 case RB:108 return &offsets->right_bottom;109 }110 111 return NULL;112}113 114static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)115{116 struct rockchip_rga *rga = ctx->rga;117 u32 *dest = rga->cmdbuf_virt;118 unsigned int reg;119 120 reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;121 dest[reg >> 2] = dma_addr >> 4;122 123 reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;124 dest[reg >> 2] |= 0x7;125}126 127static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)128{129 struct rockchip_rga *rga = ctx->rga;130 u32 *dest = rga->cmdbuf_virt;131 unsigned int reg;132 133 reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;134 dest[reg >> 2] = dma_addr >> 4;135 136 reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;137 dest[reg >> 2] |= 0x7 << 4;138}139 140static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)141{142 struct rockchip_rga *rga = ctx->rga;143 u32 *dest = rga->cmdbuf_virt;144 unsigned int reg;145 146 reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;147 dest[reg >> 2] = dma_addr >> 4;148 149 reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;150 dest[reg >> 2] |= 0x7 << 8;151}152 153static void rga_cmd_set_trans_info(struct rga_ctx *ctx)154{155 struct rockchip_rga *rga = ctx->rga;156 u32 *dest = rga->cmdbuf_virt;157 unsigned int scale_dst_w, scale_dst_h;158 unsigned int src_h, src_w, dst_h, dst_w;159 union rga_src_info src_info;160 union rga_dst_info dst_info;161 union rga_src_x_factor x_factor;162 union rga_src_y_factor y_factor;163 union rga_src_vir_info src_vir_info;164 union rga_src_act_info src_act_info;165 union rga_dst_vir_info dst_vir_info;166 union rga_dst_act_info dst_act_info;167 168 src_h = ctx->in.crop.height;169 src_w = ctx->in.crop.width;170 dst_h = ctx->out.crop.height;171 dst_w = ctx->out.crop.width;172 173 src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];174 dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];175 x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2];176 y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2];177 src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2];178 src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2];179 dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];180 dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];181 182 src_info.data.format = ctx->in.fmt->hw_format;183 src_info.data.swap = ctx->in.fmt->color_swap;184 dst_info.data.format = ctx->out.fmt->hw_format;185 dst_info.data.swap = ctx->out.fmt->color_swap;186 187 /*188 * CSC mode must only be set when the colorspace families differ between189 * input and output. It must remain unset (zeroed) if both are the same.190 */191 192 if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&193 RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {194 switch (ctx->in.colorspace) {195 case V4L2_COLORSPACE_REC709:196 src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;197 break;198 default:199 src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R0;200 break;201 }202 }203 204 if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&205 RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {206 switch (ctx->out.colorspace) {207 case V4L2_COLORSPACE_REC709:208 dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;209 break;210 default:211 dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;212 break;213 }214 }215 216 if (ctx->vflip)217 src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X;218 219 if (ctx->hflip)220 src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y;221 222 switch (ctx->rotate) {223 case 90:224 src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;225 break;226 case 180:227 src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;228 break;229 case 270:230 src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;231 break;232 default:233 src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;234 break;235 }236 237 /*238 * Calculate the up/down scaling mode/factor.239 *240 * RGA used to scale the picture first, and then rotate second,241 * so we need to swap the w/h when rotate degree is 90/270.242 */243 if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE ||244 src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) {245 if (rga->version.major == 0 || rga->version.minor == 0) {246 if (dst_w == src_h)247 src_h -= 8;248 if (abs(src_w - dst_h) < 16)249 src_w -= 16;250 }251 252 scale_dst_h = dst_w;253 scale_dst_w = dst_h;254 } else {255 scale_dst_w = dst_w;256 scale_dst_h = dst_h;257 }258 259 if (src_w == scale_dst_w) {260 src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO;261 x_factor.val = 0;262 } else if (src_w > scale_dst_w) {263 src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN;264 x_factor.data.down_scale_factor =265 rga_get_scaling(src_w, scale_dst_w) + 1;266 } else {267 src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP;268 x_factor.data.up_scale_factor =269 rga_get_scaling(src_w - 1, scale_dst_w - 1);270 }271 272 if (src_h == scale_dst_h) {273 src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO;274 y_factor.val = 0;275 } else if (src_h > scale_dst_h) {276 src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN;277 y_factor.data.down_scale_factor =278 rga_get_scaling(src_h, scale_dst_h) + 1;279 } else {280 src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP;281 y_factor.data.up_scale_factor =282 rga_get_scaling(src_h - 1, scale_dst_h - 1);283 }284 285 /*286 * Calculate the framebuffer virtual strides and active size,287 * note that the step of vir_stride / vir_width is 4 byte words288 */289 src_vir_info.data.vir_stride = ctx->in.stride >> 2;290 src_vir_info.data.vir_width = ctx->in.stride >> 2;291 292 src_act_info.data.act_height = src_h - 1;293 src_act_info.data.act_width = src_w - 1;294 295 dst_vir_info.data.vir_stride = ctx->out.stride >> 2;296 dst_act_info.data.act_height = dst_h - 1;297 dst_act_info.data.act_width = dst_w - 1;298 299 dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;300 dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;301 dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;302 dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;303 304 dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;305 306 dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;307 dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;308 309 dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;310}311 312static void rga_cmd_set_src_info(struct rga_ctx *ctx,313 struct rga_addr_offset *offset)314{315 struct rga_corners_addr_offset src_offsets;316 struct rockchip_rga *rga = ctx->rga;317 u32 *dest = rga->cmdbuf_virt;318 unsigned int src_h, src_w, src_x, src_y;319 320 src_h = ctx->in.crop.height;321 src_w = ctx->in.crop.width;322 src_x = ctx->in.crop.left;323 src_y = ctx->in.crop.top;324 325 /*326 * Calculate the source framebuffer base address with offset pixel.327 */328 src_offsets = rga_get_addr_offset(&ctx->in, offset,329 src_x, src_y, src_w, src_h);330 331 dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =332 src_offsets.left_top.y_off;333 dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =334 src_offsets.left_top.u_off;335 dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =336 src_offsets.left_top.v_off;337}338 339static void rga_cmd_set_dst_info(struct rga_ctx *ctx,340 struct rga_addr_offset *offset)341{342 struct rga_addr_offset *dst_offset;343 struct rga_corners_addr_offset offsets;344 struct rockchip_rga *rga = ctx->rga;345 u32 *dest = rga->cmdbuf_virt;346 unsigned int dst_h, dst_w, dst_x, dst_y;347 unsigned int mir_mode = 0;348 unsigned int rot_mode = 0;349 350 dst_h = ctx->out.crop.height;351 dst_w = ctx->out.crop.width;352 dst_x = ctx->out.crop.left;353 dst_y = ctx->out.crop.top;354 355 if (ctx->vflip)356 mir_mode |= RGA_SRC_MIRR_MODE_X;357 if (ctx->hflip)358 mir_mode |= RGA_SRC_MIRR_MODE_Y;359 360 switch (ctx->rotate) {361 case 90:362 rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;363 break;364 case 180:365 rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;366 break;367 case 270:368 rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;369 break;370 default:371 rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;372 break;373 }374 375 /*376 * Configure the dest framebuffer base address with pixel offset.377 */378 offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w, dst_h);379 dst_offset = rga_lookup_draw_pos(&offsets, mir_mode, rot_mode);380 381 dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =382 dst_offset->y_off;383 dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =384 dst_offset->u_off;385 dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =386 dst_offset->v_off;387}388 389static void rga_cmd_set_mode(struct rga_ctx *ctx)390{391 struct rockchip_rga *rga = ctx->rga;392 u32 *dest = rga->cmdbuf_virt;393 union rga_mode_ctrl mode;394 union rga_alpha_ctrl0 alpha_ctrl0;395 union rga_alpha_ctrl1 alpha_ctrl1;396 397 mode.val = 0;398 alpha_ctrl0.val = 0;399 alpha_ctrl1.val = 0;400 401 mode.data.gradient_sat = 1;402 mode.data.render = RGA_MODE_RENDER_BITBLT;403 mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;404 405 /* disable alpha blending */406 dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val;407 dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val;408 409 dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;410}411 412static void rga_cmd_set(struct rga_ctx *ctx,413 struct rga_vb_buffer *src, struct rga_vb_buffer *dst)414{415 struct rockchip_rga *rga = ctx->rga;416 417 memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);418 419 rga_cmd_set_src_addr(ctx, src->dma_desc_pa);420 /*421 * Due to hardware bug,422 * src1 mmu also should be configured when using alpha blending.423 */424 rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);425 426 rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);427 rga_cmd_set_mode(ctx);428 429 rga_cmd_set_src_info(ctx, &src->offset);430 rga_cmd_set_dst_info(ctx, &dst->offset);431 rga_cmd_set_trans_info(ctx);432 433 rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);434 435 /* sync CMD buf for RGA */436 dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,437 PAGE_SIZE, DMA_BIDIRECTIONAL);438}439 440void rga_hw_start(struct rockchip_rga *rga,441 struct rga_vb_buffer *src, struct rga_vb_buffer *dst)442{443 struct rga_ctx *ctx = rga->curr;444 445 rga_cmd_set(ctx, src, dst);446 447 rga_write(rga, RGA_SYS_CTRL, 0x00);448 449 rga_write(rga, RGA_SYS_CTRL, 0x22);450 451 rga_write(rga, RGA_INT, 0x600);452 453 rga_write(rga, RGA_CMD_CTRL, 0x1);454}455