// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Rockchip Electronics Co., Ltd. * * Author: Huang Lee */ #include "rga3_reg_info.h" #include "rga_dma_buf.h" #include "rga_iommu.h" #include "rga_common.h" #include "rga_debugger.h" #include "rga_hw_config.h" #define FACTOR_MAX ((int)(2 << 15)) static void RGA3_set_reg_win0_info(u8 *base, struct rga3_req *msg) { u32 *bRGA3_WIN0_RD_CTRL; u32 *bRGA3_WIN0_Y_BASE, *bRGA3_WIN0_U_BASE, *bRGA3_WIN0_V_BASE; u32 *bRGA3_WIN0_VIR_STRIDE; u32 *bRGA3_WIN0_UV_VIR_STRIDE; u32 *bRGA3_WIN0_SRC_SIZE; u32 *bRGA3_WIN0_ACT_OFF; u32 *bRGA3_WIN0_ACT_SIZE; u32 *bRGA3_WIN0_DST_SIZE; u32 *bRGA3_WIN0_SCL_FAC; /* Not used yet. */ // u32 *bRGA3_WIN0_FBC_OFF; u32 sw = 0, sh = 0; u32 dw = 0, dh = 0; u32 param_x = 0, param_y = 0; u8 x_up = 0, y_up = 0, x_by = 0, y_by = 0; u32 reg = 0; u8 win_format = 0; u8 win_yc_swp = 0; /* rb swap on RGB, uv swap on YUV */ u8 win_pix_swp = 0; /* * 1: Semi planar, for yuv 4:2:x * 2: Interleaved (yuyv), for yuv422 8bit only ,RGB */ u8 win_interleaved = 1; /* enable r2y or y2r */ u8 win_r2y = 0; u8 win_y2r = 0; u8 rotate_mode = 0; u8 xmirror = 0; u8 ymirror = 0; u8 pixel_width = 1; u8 yuv10 = 0; u32 stride = 0; u32 uv_stride = 0; bRGA3_WIN0_RD_CTRL = (u32 *) (base + RGA3_WIN0_RD_CTRL_OFFSET); bRGA3_WIN0_Y_BASE = (u32 *) (base + RGA3_WIN0_Y_BASE_OFFSET); bRGA3_WIN0_U_BASE = (u32 *) (base + RGA3_WIN0_U_BASE_OFFSET); bRGA3_WIN0_V_BASE = (u32 *) (base + RGA3_WIN0_V_BASE_OFFSET); bRGA3_WIN0_VIR_STRIDE = (u32 *) (base + RGA3_WIN0_VIR_STRIDE_OFFSET); bRGA3_WIN0_UV_VIR_STRIDE = (u32 *) (base + RGA3_WIN0_UV_VIR_STRIDE_OFFSET); /* Not used yet. */ // bRGA3_WIN0_FBC_OFF = (u32 *) (base + RGA3_WIN0_FBC_OFF_OFFSET); bRGA3_WIN0_ACT_OFF = (u32 *) (base + RGA3_WIN0_ACT_OFF_OFFSET); bRGA3_WIN0_SRC_SIZE = (u32 *) (base + RGA3_WIN0_SRC_SIZE_OFFSET); bRGA3_WIN0_ACT_SIZE = (u32 *) (base + RGA3_WIN0_ACT_SIZE_OFFSET); bRGA3_WIN0_DST_SIZE = (u32 *) (base + RGA3_WIN0_DST_SIZE_OFFSET); bRGA3_WIN0_SCL_FAC = (u32 *) (base + RGA3_WIN0_SCL_FAC_OFFSET); if (msg->win0.rotate_mode != 0) { rotate_mode = msg->rotate_mode & RGA3_ROT_BIT_ROT_90 ? 1 : 0; xmirror = msg->rotate_mode & RGA3_ROT_BIT_X_MIRROR ? 1 : 0; ymirror = msg->rotate_mode & RGA3_ROT_BIT_Y_MIRROR ? 1 : 0; } /* scale */ dw = msg->win0.dst_act_w; dh = msg->win0.dst_act_h; if (rotate_mode) { sh = msg->win0.src_act_w; sw = msg->win0.src_act_h; } else { sw = msg->win0.src_act_w; sh = msg->win0.src_act_h; } if (sw > dw) { x_up = 0; x_by = 0; } else if (sw < dw) { x_up = 1; x_by = 0; } else { x_up = 0; x_by = 1; } if (sh > dh) { y_up = 0; y_by = 0; } else if (sh < dh) { y_up = 1; y_by = 0; } else { y_up = 0; y_by = 1; } if (x_by == 1 && x_up == 0) param_x = 0; else if (x_up == 1 && x_by == 0) { param_x = FACTOR_MAX * (sw - 1) / (dw - 1); /* even multiples of 128 require a scaling factor -1 */ if ((FACTOR_MAX * (sw - 1)) % (dw - 1) == 0) param_x = param_x - 1; } else param_x = FACTOR_MAX * (dw - 1) / (sw - 1) + 1; if (y_by == 1 && y_up == 0) param_y = 0; else if (y_up == 1 && y_by == 0) { param_y = FACTOR_MAX * (sh - 1) / (dh - 1); /* even multiples of 128 require a scaling factor -1 */ if ((FACTOR_MAX * (sh - 1)) % (dh - 1) == 0) param_y = param_y - 1; } else param_y = FACTOR_MAX * (dh - 1) / (sh - 1) + 1; switch (msg->win0.format) { case RGA_FORMAT_RGBA_8888: win_format = 0x8; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_BGRA_8888: win_format = 0x6; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_ARGB_8888: win_format = 0x9; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_ABGR_8888: win_format = 0x7; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_RGB_888: win_format = 0x5; pixel_width = 3; win_interleaved = 2; win_pix_swp = 1; break; case RGA_FORMAT_BGR_888: win_format = 0x5; pixel_width = 3; win_interleaved = 2; break; case RGA_FORMAT_RGB_565: win_format = 0x4; pixel_width = 2; win_interleaved = 2; win_pix_swp = 1; break; case RGA_FORMAT_BGR_565: win_format = 0x4; pixel_width = 2; win_interleaved = 2; break; case RGA_FORMAT_YVYU_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 1; win_yc_swp = 1; win_interleaved = 2; break; case RGA_FORMAT_VYUY_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 1; win_yc_swp = 0; win_interleaved = 2; break; case RGA_FORMAT_YUYV_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 0; win_yc_swp = 1; win_interleaved = 2; break; case RGA_FORMAT_UYVY_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 0; win_yc_swp = 0; win_interleaved = 2; break; case RGA_FORMAT_YCbCr_422_SP: win_format = 0x1; break; case RGA_FORMAT_YCbCr_420_SP: win_format = 0x0; break; case RGA_FORMAT_YCrCb_422_SP: win_format = 0x1; win_pix_swp = 1; break; case RGA_FORMAT_YCrCb_420_SP: win_format = 0x0; win_pix_swp = 1; break; case RGA_FORMAT_YCbCr_420_SP_10B: win_format = 0x2; yuv10 = 1; break; case RGA_FORMAT_YCrCb_420_SP_10B: win_format = 0x2; yuv10 = 1; win_pix_swp = 1; break; case RGA_FORMAT_YCbCr_422_SP_10B: win_format = 0x3; yuv10 = 1; break; case RGA_FORMAT_YCrCb_422_SP_10B: win_format = 0x3; yuv10 = 1; win_pix_swp = 1; break; }; if (rga_is_rgb_format(msg->win0.format) && rga_is_yuv_format(msg->wr.format)) win_r2y = 1; if (rga_is_yuv_format(msg->win0.format) && rga_is_rgb_format(msg->wr.format)) win_y2r = 1; reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN(win_r2y))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN(win_y2r))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT(win_format))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP(win_pix_swp))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP(win_yc_swp))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT(win_interleaved))); if (win_r2y == 1) { reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win0.r2y_mode))); } else if (win_y2r == 1) { reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win0.y2r_mode))); } /* rotate & mirror */ if (msg->win0.rotate_mode == 1) { reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT(rotate_mode))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR(xmirror))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR(ymirror))); } /* scale */ *bRGA3_WIN0_SCL_FAC = param_x | param_y << 16; reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY(x_by))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP(x_up))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY(y_by))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP(y_up))); /* rd_mode */ reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE(msg->win0.rd_mode))); /* win0 enable */ reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE(msg->win0.enable))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT(1))); /* Only on raster mode, yuv 10bit can change to compact or set endian */ if (msg->win0.rd_mode == 0 && yuv10 == 1) { reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT (msg->win0.is_10b_compact))); reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE (msg->win0.is_10b_endian))); } *bRGA3_WIN0_RD_CTRL = reg; switch (msg->win0.rd_mode) { case 0: /* raster */ stride = (((msg->win0.vir_w * pixel_width) + 15) & ~15) >> 2; if (rga_is_yuv420_semi_planar_format(msg->win0.format)) uv_stride = ((msg->win0.vir_w + 15) & ~15) >> 2; else uv_stride = stride; break; case 1: /* fbc */ stride = ((msg->win0.vir_w + 15) & ~15) >> 2; if (rga_is_yuv420_semi_planar_format(msg->win0.format)) uv_stride = ((msg->win0.vir_w + 15) & ~15) >> 2; else uv_stride = stride; break; case 2: /* tile 8*8 */ /* * tile 8*8 mode 8 lines of data are read/written at one time, * so stride needs * 8. YUV420 only has 4 lines of UV data, so * it needs to >>1. */ stride = (((msg->win0.vir_w * pixel_width * 8) + 15) & ~15) >> 2; if (rga_is_yuv420_semi_planar_format(msg->win0.format)) uv_stride = ((((msg->win0.vir_w * 8) + 15) & ~15) >> 1) >> 2; else uv_stride = stride; break; } *bRGA3_WIN0_Y_BASE = (u32) msg->win0.yrgb_addr; *bRGA3_WIN0_U_BASE = (u32) msg->win0.uv_addr; *bRGA3_WIN0_V_BASE = (u32) msg->win0.v_addr; *bRGA3_WIN0_VIR_STRIDE = stride; *bRGA3_WIN0_UV_VIR_STRIDE = uv_stride; *bRGA3_WIN0_ACT_OFF = msg->win0.x_offset | (msg->win0.y_offset << 16); /* fbcd offset */ /* * *bRGA3_WIN0_FBC_OFF = msg->win0.fbc_x_offset | * (msg->win0.fbc_y_offset << 16); */ /* do not use win0 src size except fbcd */ /* in FBCD, src_width needs to be aligned at 16 */ *bRGA3_WIN0_SRC_SIZE = ALIGN(msg->win0.src_act_w + msg->win0.x_offset, 16) | (ALIGN(msg->win0.y_offset + msg->win0.src_act_h, 16) << 16); *bRGA3_WIN0_ACT_SIZE = msg->win0.src_act_w | (msg->win0.src_act_h << 16); *bRGA3_WIN0_DST_SIZE = msg->win0.dst_act_w | (msg->win0.dst_act_h << 16); } static void RGA3_set_reg_win1_info(u8 *base, struct rga3_req *msg) { u32 *bRGA3_WIN1_RD_CTRL; u32 *bRGA3_WIN1_Y_BASE, *bRGA3_WIN1_U_BASE, *bRGA3_WIN1_V_BASE; u32 *bRGA3_WIN1_VIR_STRIDE; u32 *bRGA3_WIN1_UV_VIR_STRIDE; u32 *bRGA3_WIN1_SRC_SIZE; u32 *bRGA3_WIN1_ACT_OFF; u32 *bRGA3_WIN1_ACT_SIZE; u32 *bRGA3_WIN1_DST_SIZE; u32 *bRGA3_WIN1_SCL_FAC; /* Not used yet. */ // u32 *bRGA3_WIN1_FBC_OFF; u32 sw = 0, sh = 0; u32 dw = 0, dh = 0; u32 param_x = 0, param_y = 0; u8 x_up = 0, y_up = 0, x_by = 0, y_by = 0; u32 reg = 0; u8 win_format = 0; u8 win_yc_swp = 0; /* rb swap on RGB, uv swap on YUV */ u8 win_pix_swp = 0; /* * 1: Semi planar, for yuv 4:2:x * 2: Interleaved (yuyv), for yuv422 8bit only ,RGB */ u8 win_interleaved = 1; u8 pixel_width = 1; u8 yuv10 = 0; /* enable r2y or y2r */ u8 win_r2y = 0; u8 win_y2r = 0; u8 rotate_mode = 0; u8 xmirror = 0; u8 ymirror = 0; u32 stride = 0; u32 uv_stride = 0; bRGA3_WIN1_RD_CTRL = (u32 *) (base + RGA3_WIN1_RD_CTRL_OFFSET); bRGA3_WIN1_Y_BASE = (u32 *) (base + RGA3_WIN1_Y_BASE_OFFSET); bRGA3_WIN1_U_BASE = (u32 *) (base + RGA3_WIN1_U_BASE_OFFSET); bRGA3_WIN1_V_BASE = (u32 *) (base + RGA3_WIN1_V_BASE_OFFSET); bRGA3_WIN1_VIR_STRIDE = (u32 *) (base + RGA3_WIN1_VIR_STRIDE_OFFSET); bRGA3_WIN1_UV_VIR_STRIDE = (u32 *) (base + RGA3_WIN1_UV_VIR_STRIDE_OFFSET); /* Not used yet. */ // bRGA3_WIN1_FBC_OFF = (u32 *) (base + RGA3_WIN1_FBC_OFF_OFFSET); bRGA3_WIN1_ACT_OFF = (u32 *) (base + RGA3_WIN1_ACT_OFF_OFFSET); bRGA3_WIN1_SRC_SIZE = (u32 *) (base + RGA3_WIN1_SRC_SIZE_OFFSET); bRGA3_WIN1_ACT_SIZE = (u32 *) (base + RGA3_WIN1_ACT_SIZE_OFFSET); bRGA3_WIN1_DST_SIZE = (u32 *) (base + RGA3_WIN1_DST_SIZE_OFFSET); bRGA3_WIN1_SCL_FAC = (u32 *) (base + RGA3_WIN1_SCL_FAC_OFFSET); if (msg->win1.rotate_mode != 0) { rotate_mode = msg->rotate_mode & RGA3_ROT_BIT_ROT_90 ? 1 : 0; xmirror = msg->rotate_mode & RGA3_ROT_BIT_X_MIRROR ? 1 : 0; ymirror = msg->rotate_mode & RGA3_ROT_BIT_Y_MIRROR ? 1 : 0; } /* scale */ dw = msg->win1.dst_act_w; dh = msg->win1.dst_act_h; if (rotate_mode) { sh = msg->win1.src_act_w; sw = msg->win1.src_act_h; } else { sw = msg->win1.src_act_w; sh = msg->win1.src_act_h; } if (sw > dw) { x_up = 0; x_by = 0; } else if (sw < dw) { x_up = 1; x_by = 0; } else { x_up = 0; x_by = 1; } if (sh > dh) { y_up = 0; y_by = 0; } else if (sh < dh) { y_up = 1; y_by = 0; } else { y_up = 0; y_by = 1; } if (x_by == 1) param_x = 0; else if (x_up == 1) { param_x = (FACTOR_MAX * (sw - 1)) / (dw - 1); /* even multiples of 128 require a scaling factor -1 */ if ((FACTOR_MAX * (sw - 1)) % (dw - 1) == 0) param_x = param_x - 1; } else param_x = (FACTOR_MAX * (dw - 1)) / (sw - 1) + 1; if (y_by == 1) param_y = 0; else if (y_up == 1) { param_y = (FACTOR_MAX * (sh - 1)) / (dh - 1); /* even multiples of 128 require a scaling factor -1 */ if ((FACTOR_MAX * (sh - 1)) % (dh - 1) == 0) param_y = param_y - 1; } else param_y = (FACTOR_MAX * (dh - 1)) / (sh - 1) + 1; switch (msg->win1.format) { case RGA_FORMAT_RGBA_8888: win_format = 0x8; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_BGRA_8888: win_format = 0x6; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_ARGB_8888: win_format = 0x9; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_ABGR_8888: win_format = 0x7; pixel_width = 4; win_interleaved = 2; break; case RGA_FORMAT_RGB_888: win_format = 0x5; pixel_width = 3; win_interleaved = 2; win_pix_swp = 1; break; case RGA_FORMAT_BGR_888: win_format = 0x5; pixel_width = 3; win_interleaved = 2; break; case RGA_FORMAT_RGB_565: win_format = 0x4; pixel_width = 2; win_interleaved = 2; win_pix_swp = 1; break; case RGA_FORMAT_BGR_565: win_format = 0x4; pixel_width = 2; win_interleaved = 2; break; case RGA_FORMAT_YVYU_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 1; win_yc_swp = 1; win_interleaved = 2; break; case RGA_FORMAT_VYUY_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 1; win_yc_swp = 0; win_interleaved = 2; break; case RGA_FORMAT_YUYV_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 0; win_yc_swp = 1; win_interleaved = 2; break; case RGA_FORMAT_UYVY_422: win_format = 0x1; pixel_width = 2; win_pix_swp = 0; win_yc_swp = 0; win_interleaved = 2; break; case RGA_FORMAT_YCbCr_422_SP: win_format = 0x1; break; case RGA_FORMAT_YCbCr_420_SP: win_format = 0x0; break; case RGA_FORMAT_YCrCb_422_SP: win_format = 0x1; win_pix_swp = 1; break; case RGA_FORMAT_YCrCb_420_SP: win_format = 0x0; win_pix_swp = 1; break; case RGA_FORMAT_YCbCr_420_SP_10B: win_format = 0x2; yuv10 = 1; break; case RGA_FORMAT_YCrCb_420_SP_10B: win_format = 0x2; win_pix_swp = 1; yuv10 = 1; break; case RGA_FORMAT_YCbCr_422_SP_10B: win_format = 0x3; yuv10 = 1; break; case RGA_FORMAT_YCrCb_422_SP_10B: win_format = 0x3; win_pix_swp = 1; yuv10 = 1; break; }; if (rga_is_rgb_format(msg->win1.format) && rga_is_yuv_format(msg->wr.format)) win_r2y = 1; if (rga_is_yuv_format(msg->win1.format) && rga_is_rgb_format(msg->wr.format)) win_y2r = 1; reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN(win_r2y))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN(win_y2r))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT(win_format))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP(win_pix_swp))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP(win_yc_swp))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT(win_interleaved))); if (win_r2y == 1) { reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win1.r2y_mode))); } else if (win_y2r == 1) { reg = ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win1.y2r_mode))); } /* rotate & mirror */ reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT(rotate_mode))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR(xmirror))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR(ymirror))); //warning: TRM not complete /* scale */ *bRGA3_WIN1_SCL_FAC = param_x | param_y << 16; reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY(x_by))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP(x_up))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY(y_by))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP(y_up))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT(1))); /* Only on roster mode, yuv 10bit can change to compact or set endian */ if (msg->win1.rd_mode == 0 && yuv10 == 1) { reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT (msg->win1.is_10b_compact))); reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE (msg->win1.is_10b_endian))); } /* rd_mode */ reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE(msg->win1.rd_mode))); /* win1 enable */ reg = ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE)) | (s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE(msg->win1.enable))); *bRGA3_WIN1_RD_CTRL = reg; switch (msg->win1.rd_mode) { case 0: /* raster */ stride = (((msg->win1.vir_w * pixel_width) + 15) & ~15) >> 2; if (rga_is_yuv420_semi_planar_format(msg->win1.format)) uv_stride = ((msg->win1.vir_w + 15) & ~15) >> 2; else uv_stride = stride; break; case 1: /* fbc */ stride = ((msg->win1.vir_w + 15) & ~15) >> 2; if (rga_is_yuv420_semi_planar_format(msg->win1.format)) uv_stride = ((msg->win1.vir_w + 15) & ~15) >> 2; else uv_stride = stride; break; case 2: /* tile 8*8 */ stride = (((msg->win1.vir_w * pixel_width * 8) + 15) & ~15) >> 2; if (rga_is_yuv420_semi_planar_format(msg->win1.format)) uv_stride = ((((msg->win1.vir_w * 8) + 15) & ~15) >> 1) >> 2; else uv_stride = stride; break; } *bRGA3_WIN1_Y_BASE = (u32) msg->win1.yrgb_addr; *bRGA3_WIN1_U_BASE = (u32) msg->win1.uv_addr; *bRGA3_WIN1_V_BASE = (u32) msg->win1.v_addr; *bRGA3_WIN1_VIR_STRIDE = stride; *bRGA3_WIN1_UV_VIR_STRIDE = uv_stride; *bRGA3_WIN1_ACT_OFF = msg->win1.x_offset | (msg->win1.y_offset << 16); /* fbcd offset */ /* * *bRGA3_WIN1_FBC_OFF = msg->win1.fbc_x_offset | * (msg->win1.fbc_y_offset << 16); */ /* do not use win1 src size except fbcd */ *bRGA3_WIN1_SRC_SIZE = (msg->win1.src_act_w + msg->win1.x_offset) | ((msg->win1.src_act_h + msg->win1.y_offset) << 16); *bRGA3_WIN1_ACT_SIZE = msg->win1.src_act_w | (msg->win1.src_act_h << 16); *bRGA3_WIN1_DST_SIZE = msg->win1.dst_act_w | (msg->win1.dst_act_h << 16); } static void RGA3_set_reg_wr_info(u8 *base, struct rga3_req *msg) { u32 *bRGA3_WR_RD_CTRL; u32 *bRGA3_WR_Y_BASE, *bRGA3_WR_U_BASE, *bRGA3_WR_V_BASE; u32 *bRGA3_WR_VIR_STRIDE; u32 *bRGA3_WR_PL_VIR_STRIDE; u32 *bRGA3_WR_FBCD_CTRL; u32 reg = 0; u32 fbcd_reg = 0; u8 wr_format = 0; u8 wr_yc_swp = 0; /* rb swap on RGB, uv swap on YUV */ u8 wr_pix_swp = 0; u8 pixel_width = 1; u8 yuv10 = 0; /* * 1: Semi planar, for yuv 4:2:x * 2: Interleaved (yuyv), for yuv422 8bit only ,RGB */ u8 wr_interleaved = 1; u32 stride = 0; u32 uv_stride = 0; u32 vir_h = 0; bRGA3_WR_RD_CTRL = (u32 *) (base + RGA3_WR_CTRL_OFFSET); bRGA3_WR_FBCD_CTRL = (u32 *) (base + RGA3_WR_FBCE_CTRL_OFFSET); bRGA3_WR_Y_BASE = (u32 *) (base + RGA3_WR_Y_BASE_OFFSET); bRGA3_WR_U_BASE = (u32 *) (base + RGA3_WR_U_BASE_OFFSET); bRGA3_WR_V_BASE = (u32 *) (base + RGA3_WR_V_BASE_OFFSET); bRGA3_WR_VIR_STRIDE = (u32 *) (base + RGA3_WR_VIR_STRIDE_OFFSET); bRGA3_WR_PL_VIR_STRIDE = (u32 *) (base + RGA3_WR_PL_VIR_STRIDE_OFFSET); switch (msg->wr.format) { case RGA_FORMAT_RGBA_8888: wr_format = 0x6; pixel_width = 4; wr_interleaved = 2; wr_pix_swp = 1; break; case RGA_FORMAT_BGRA_8888: wr_format = 0x6; pixel_width = 4; wr_interleaved = 2; break; case RGA_FORMAT_RGB_888: wr_format = 0x5; pixel_width = 3; wr_interleaved = 2; wr_pix_swp = 1; break; case RGA_FORMAT_BGR_888: wr_format = 0x5; pixel_width = 3; wr_interleaved = 2; break; case RGA_FORMAT_RGB_565: wr_format = 0x4; pixel_width = 2; wr_interleaved = 2; wr_pix_swp = 1; break; case RGA_FORMAT_BGR_565: wr_format = 0x4; pixel_width = 2; wr_interleaved = 2; break; case RGA_FORMAT_YVYU_422: wr_format = 0x1; pixel_width = 2; wr_pix_swp = 1; wr_yc_swp = 1; wr_interleaved = 2; break; case RGA_FORMAT_VYUY_422: wr_format = 0x1; pixel_width = 2; wr_pix_swp = 1; wr_yc_swp = 0; wr_interleaved = 2; break; case RGA_FORMAT_YUYV_422: wr_format = 0x1; pixel_width = 2; wr_pix_swp = 0; wr_yc_swp = 1; wr_interleaved = 2; break; case RGA_FORMAT_UYVY_422: wr_format = 0x1; pixel_width = 2; wr_pix_swp = 0; wr_yc_swp = 0; wr_interleaved = 2; break; case RGA_FORMAT_YCbCr_422_SP: wr_format = 0x1; break; case RGA_FORMAT_YCbCr_420_SP: wr_format = 0x0; break; case RGA_FORMAT_YCrCb_422_SP: wr_format = 0x1; wr_pix_swp = 1; break; case RGA_FORMAT_YCrCb_420_SP: wr_format = 0x0; wr_pix_swp = 1; break; case RGA_FORMAT_YCbCr_420_SP_10B: wr_format = 0x2; yuv10 = 1; break; case RGA_FORMAT_YCrCb_420_SP_10B: wr_format = 0x2; wr_pix_swp = 1; yuv10 = 1; break; case RGA_FORMAT_YCbCr_422_SP_10B: wr_format = 0x3; yuv10 = 1; break; case RGA_FORMAT_YCrCb_422_SP_10B: wr_format = 0x3; wr_pix_swp = 1; yuv10 = 1; break; }; reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_PIC_FORMAT)) | (s_RGA3_WR_CTRL_SW_WR_PIC_FORMAT(wr_format))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_PIX_SWAP)) | (s_RGA3_WR_CTRL_SW_WR_PIX_SWAP(wr_pix_swp))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_YC_SWAP)) | (s_RGA3_WR_CTRL_SW_WR_YC_SWAP(wr_yc_swp))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_FORMAT)) | (s_RGA3_WR_CTRL_SW_WR_FORMAT(wr_interleaved))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN)) | (s_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN(1))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_OUTSTANDING_MAX)) | (s_RGA3_WR_CTRL_SW_OUTSTANDING_MAX(0xf))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT)) | (s_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT(1))); /* Only on roster mode, yuv 10bit can change to compact or set endian */ if (msg->wr.rd_mode == 0 && yuv10 == 1) { reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT)) | (s_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT (msg->wr.is_10b_compact))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE)) | (s_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE (msg->wr.is_10b_endian))); } /* rd_mode */ reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_MODE)) | (s_RGA3_WR_CTRL_SW_WR_MODE(msg->wr.rd_mode))); fbcd_reg = ((fbcd_reg & (~m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS)) | (s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS(0))); *bRGA3_WR_RD_CTRL = reg; *bRGA3_WR_FBCD_CTRL = fbcd_reg; switch (msg->wr.rd_mode) { case 0: /* raster */ stride = (((msg->wr.vir_w * pixel_width) + 15) & ~15) >> 2; uv_stride = ((msg->wr.vir_w + 15) & ~15) >> 2; *bRGA3_WR_U_BASE = (u32) msg->wr.uv_addr; break; case 1: /* fbc */ stride = ((msg->wr.vir_w + 15) & ~15) >> 2; /* need to calculate fbcd header size */ vir_h = ((msg->wr.vir_h + 15) & ~15); /* RGBA8888 */ if (wr_format == 0x6) uv_stride = ((msg->wr.vir_w + 15) & ~15); /* RGB888 */ else if (wr_format == 0x5) uv_stride = (((msg->wr.vir_w + 15) & ~15) >> 2) * 3; /* RGB565, yuv422 8bit, yuv420 10bit */ else if (wr_format == 0x4 || wr_format == 0x1 || wr_format == 0x2) uv_stride = ((msg->wr.vir_w + 15) & ~15) >> 1; /* yuv420 8bit */ else if (wr_format == 0x0) uv_stride = (((msg->wr.vir_w + 15) & ~15) >> 3) * 3; /* yuv422 10bit */ else if (wr_format == 0x3) uv_stride = (((msg->wr.vir_w + 15) & ~15) >> 3) * 5; *bRGA3_WR_U_BASE = (u32) (msg->wr.uv_addr + ((stride * vir_h)>>2)); break; case 2: /* tile 8*8 */ stride = (((msg->wr.vir_w * pixel_width * 8) + 15) & ~15) >> 2; if (rga_is_yuv420_semi_planar_format(msg->win0.format)) uv_stride = ((((msg->wr.vir_w * 8) + 15) & ~15) >> 1) >> 2; else uv_stride = stride; *bRGA3_WR_U_BASE = (u32) msg->wr.uv_addr; break; } *bRGA3_WR_Y_BASE = (u32) msg->wr.yrgb_addr; *bRGA3_WR_V_BASE = (u32) msg->wr.v_addr; *bRGA3_WR_VIR_STRIDE = stride; *bRGA3_WR_PL_VIR_STRIDE = uv_stride; } static void RGA3_set_reg_overlap_info(u8 *base, struct rga3_req *msg) { u32 *bRGA_OVERLAP_TOP_CTRL; u32 *bRGA_OVERLAP_BOT_CTRL; u32 *bRGA_OVERLAP_TOP_ALPHA; u32 *bRGA_OVERLAP_BOT_ALPHA; u32 *bRGA_OVERLAP_TOP_KEY_MIN; u32 *bRGA_OVERLAP_TOP_KEY_MAX; u32 *bRGA_OVERLAP_CTRL; u32 *bRGA3_OVLP_OFF; u32 reg; union rga3_color_ctrl top_color_ctrl, bottom_color_ctrl; union rga3_alpha_ctrl top_alpha_ctrl, bottom_alpha_ctrl; struct rga_alpha_config *config; bRGA_OVERLAP_TOP_CTRL = (u32 *) (base + RGA3_OVLP_TOP_CTRL_OFFSET); bRGA_OVERLAP_BOT_CTRL = (u32 *) (base + RGA3_OVLP_BOT_CTRL_OFFSET); bRGA_OVERLAP_TOP_ALPHA = (u32 *) (base + RGA3_OVLP_TOP_ALPHA_OFFSET); bRGA_OVERLAP_BOT_ALPHA = (u32 *) (base + RGA3_OVLP_BOT_ALPHA_OFFSET); bRGA_OVERLAP_CTRL = (u32 *) (base + RGA3_OVLP_CTRL_OFFSET); bRGA3_OVLP_OFF = (u32 *) (base + RGA3_OVLP_OFF_OFFSET); /* Alpha blend */ /*bot -> win0(dst), top -> win1(src). */ top_color_ctrl.value = 0; bottom_color_ctrl.value = 0; top_alpha_ctrl.value = 0; bottom_alpha_ctrl.value = 0; config = &msg->alpha_config; if (config->fg_pixel_alpha_en) top_color_ctrl.bits.blend_mode = config->fg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL : RGA_ALPHA_PER_PIXEL; else top_color_ctrl.bits.blend_mode = RGA_ALPHA_GLOBAL; if (config->bg_pixel_alpha_en) bottom_color_ctrl.bits.blend_mode = config->bg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL : RGA_ALPHA_PER_PIXEL; else bottom_color_ctrl.bits.blend_mode = RGA_ALPHA_GLOBAL; /* * Since the hardware uses 256 as 1, the original alpha value needs to * be + (alpha >> 7). */ top_color_ctrl.bits.alpha_cal_mode = RGA_ALPHA_SATURATION; bottom_color_ctrl.bits.alpha_cal_mode = RGA_ALPHA_SATURATION; top_color_ctrl.bits.global_alpha = config->fg_global_alpha_value; bottom_color_ctrl.bits.global_alpha = config->bg_global_alpha_value; /* porter duff alpha enable */ switch (config->mode) { case RGA_ALPHA_BLEND_SRC: /* * SRC mode: * Sf = 1, Df = 0; * [Rc,Ra] = [Sc,Sa]; */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; break; case RGA_ALPHA_BLEND_DST: /* * SRC mode: * Sf = 0, Df = 1; * [Rc,Ra] = [Dc,Da]; */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; break; case RGA_ALPHA_BLEND_SRC_OVER: /* * SRC-OVER mode: * Sf = 1, Df = (1 - Sa) * [Rc,Ra] = [ Sc + (1 - Sa) * Dc, Sa + (1 - Sa) * Da ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; break; case RGA_ALPHA_BLEND_DST_OVER: /* * DST-OVER mode: * Sf = (1 - Da) , Df = 1 * [Rc,Ra] = [ Sc * (1 - Da) + Dc, Sa * (1 - Da) + Da ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; break; case RGA_ALPHA_BLEND_SRC_IN: /* * SRC-IN mode: * Sf = Da , Df = 0 * [Rc,Ra] = [ Sc * Da, Sa * Da ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; break; case RGA_ALPHA_BLEND_DST_IN: /* * DST-IN mode: * Sf = 0 , Df = Sa * [Rc,Ra] = [ Dc * Sa, Da * Sa ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; break; case RGA_ALPHA_BLEND_SRC_OUT: /* * SRC-OUT mode: * Sf = (1 - Da) , Df = 0 * [Rc,Ra] = [ Sc * (1 - Da), Sa * (1 - Da) ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; break; case RGA_ALPHA_BLEND_DST_OUT: /* * DST-OUT mode: * Sf = 0 , Df = (1 - Sa) * [Rc,Ra] = [ Dc * (1 - Sa), Da * (1 - Sa) ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; break; case RGA_ALPHA_BLEND_SRC_ATOP: /* * SRC-ATOP mode: * Sf = Da , Df = (1 - Sa) * [Rc,Ra] = [ Sc * Da + Dc * (1 - Sa), Sa * Da + Da * (1 - Sa) ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; break; case RGA_ALPHA_BLEND_DST_ATOP: /* * DST-ATOP mode: * Sf = (1 - Da) , Df = Sa * [Rc,Ra] = [ Sc * (1 - Da) + Dc * Sa, Sa * (1 - Da) + Da * Sa ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; break; case RGA_ALPHA_BLEND_XOR: /* * DST-XOR mode: * Sf = (1 - Da) , Df = (1 - Sa) * [Rc,Ra] = [ Sc * (1 - Da) + Dc * (1 - Sa), Sa * (1 - Da) + Da * (1 - Sa) ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; break; case RGA_ALPHA_BLEND_CLEAR: /* * DST-CLEAR mode: * Sf = 0 , Df = 0 * [Rc,Ra] = [ 0, 0 ] */ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; break; default: break; } if (!config->enable && msg->abb_alpha_pass) { /* * enabled by default bot_blend_m1 && bot_alpha_cal_m1 for src channel(win0) * In ABB mode, the number will be fetched according to 16*16, so it needs to * be enabled top_blend_m1 && top_alpha_cal_m1 for dst channel(wr). */ top_color_ctrl.bits.color_mode = RGA_ALPHA_PRE_MULTIPLIED; top_alpha_ctrl.bits.blend_mode = RGA_ALPHA_PER_PIXEL; top_alpha_ctrl.bits.alpha_cal_mode = RGA_ALPHA_NO_SATURATION; bottom_color_ctrl.bits.color_mode = RGA_ALPHA_PRE_MULTIPLIED; bottom_alpha_ctrl.bits.blend_mode = RGA_ALPHA_PER_PIXEL; bottom_alpha_ctrl.bits.alpha_cal_mode = RGA_ALPHA_NO_SATURATION; } else { top_color_ctrl.bits.color_mode = config->fg_pre_multiplied ? RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED; top_alpha_ctrl.bits.blend_mode = top_color_ctrl.bits.blend_mode; top_alpha_ctrl.bits.alpha_cal_mode = top_color_ctrl.bits.alpha_cal_mode; top_alpha_ctrl.bits.alpha_mode = top_color_ctrl.bits.alpha_mode; top_alpha_ctrl.bits.factor_mode = top_color_ctrl.bits.factor_mode; bottom_color_ctrl.bits.color_mode = config->bg_pre_multiplied ? RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED; bottom_alpha_ctrl.bits.blend_mode = bottom_color_ctrl.bits.blend_mode; bottom_alpha_ctrl.bits.alpha_cal_mode = bottom_color_ctrl.bits.alpha_cal_mode; bottom_alpha_ctrl.bits.alpha_mode = bottom_color_ctrl.bits.alpha_mode; bottom_alpha_ctrl.bits.factor_mode = bottom_color_ctrl.bits.factor_mode; } *bRGA_OVERLAP_TOP_CTRL = top_color_ctrl.value; *bRGA_OVERLAP_BOT_CTRL = bottom_color_ctrl.value; *bRGA_OVERLAP_TOP_ALPHA = top_alpha_ctrl.value; *bRGA_OVERLAP_BOT_ALPHA = bottom_alpha_ctrl.value; /* set RGA_OVERLAP_CTRL */ reg = 0; /* color key */ bRGA_OVERLAP_TOP_KEY_MIN = (u32 *) (base + RGA3_OVLP_TOP_KEY_MIN_OFFSET); bRGA_OVERLAP_TOP_KEY_MAX = (u32 *) (base + RGA3_OVLP_TOP_KEY_MAX_OFFSET); /* * YG : value (0:9) * UB : value >> 10 (10:19) * VG : value >> 20 (20:29) */ if (msg->color_key_min > 0 || msg->color_key_max > 0) { *bRGA_OVERLAP_TOP_KEY_MIN = msg->color_key_min; *bRGA_OVERLAP_TOP_KEY_MAX = msg->color_key_max; reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_TOP_KEY_EN)) | (s_RGA3_OVLP_CTRL_SW_TOP_KEY_EN(1))); } /* 1: ABB mode, 0: ABC mode, ABB cannot support fbc in&out */ if (msg->win0.yrgb_addr == msg->wr.yrgb_addr) reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_OVLP_MODE)) | (s_RGA3_OVLP_CTRL_SW_OVLP_MODE(1))); /* 1: yuv field, 0: rgb field */ if (rga_is_yuv_format(msg->wr.format)) reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_OVLP_FIELD)) | (s_RGA3_OVLP_CTRL_SW_OVLP_FIELD(1))); /* * warning: if m1 & m0 need config split,need to redesign * this judge, which consider RGBA8888 format */ reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN)) | (s_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN(config->enable))); *bRGA_OVERLAP_CTRL = reg; *bRGA3_OVLP_OFF = msg->wr.x_offset | (msg->wr.y_offset << 16); } static int rga3_gen_reg_info(u8 *base, struct rga3_req *msg) { switch (msg->render_mode) { case BITBLT_MODE: RGA3_set_reg_win0_info(base, msg); RGA3_set_reg_win1_info(base, msg); RGA3_set_reg_overlap_info(base, msg); RGA3_set_reg_wr_info(base, msg); break; default: rga_err("error msg render mode %d\n", msg->render_mode); break; } return 0; } static void addr_copy(struct rga_win_info_t *win, struct rga_img_info_t *img) { win->yrgb_addr = img->yrgb_addr; win->uv_addr = img->uv_addr; win->v_addr = img->v_addr; win->enable = 1; } static void set_win_info(struct rga_win_info_t *win, struct rga_img_info_t *img) { win->x_offset = img->x_offset; win->y_offset = img->y_offset; win->src_act_w = img->act_w; win->src_act_h = img->act_h; win->vir_w = img->vir_w; win->vir_h = img->vir_h; if (img->rd_mode == RGA_RASTER_MODE) win->rd_mode = 0; else if (img->rd_mode == RGA_FBC_MODE) win->rd_mode = 1; else if (img->rd_mode == RGA_TILE_MODE) win->rd_mode = 2; switch (img->compact_mode) { case RGA_10BIT_INCOMPACT: win->is_10b_compact = 0; break; case RGA_10BIT_COMPACT: default: win->is_10b_compact = 1; break; } win->is_10b_endian = img->is_10b_endian; } static void set_wr_info(struct rga_req *req_rga, struct rga3_req *req) { /* The output w/h are bound to the dst_act_w/h of win0. */ req->wr.dst_act_w = req->win0.dst_act_w; req->wr.dst_act_h = req->win0.dst_act_h; /* Some configurations need to be all equal to the output w/h. */ req->wr.vir_w = req_rga->dst.vir_w; req->wr.vir_h = req_rga->dst.vir_h; if (req_rga->dst.rd_mode == RGA_RASTER_MODE) req->wr.rd_mode = 0; else if (req_rga->dst.rd_mode == RGA_FBC_MODE) req->wr.rd_mode = 1; else if (req_rga->dst.rd_mode == RGA_TILE_MODE) req->wr.rd_mode = 2; switch (req_rga->dst.compact_mode) { case RGA_10BIT_INCOMPACT: req->wr.is_10b_compact = 0; break; case RGA_10BIT_COMPACT: default: req->wr.is_10b_compact = 1; break; } req->wr.is_10b_endian = req_rga->dst.is_10b_endian; } /* TODO: common part */ static void rga_cmd_to_rga3_cmd(struct rga_req *req_rga, struct rga3_req *req) { struct rga_img_info_t tmp; req->render_mode = BITBLT_MODE; /* rotate & mirror */ switch (req_rga->rotate_mode & 0x0f) { case 0x1: if (req_rga->sina == 65536 && req_rga->cosa == 0) { /* rot-90 */ req->rotate_mode = RGA3_ROT_BIT_ROT_90; } else if (req_rga->sina == 0 && req_rga->cosa == -65536) { /* rot-180 = X-mirror + Y-mirror */ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR; } else if (req_rga->sina == -65536 && req_rga->cosa == 0) { /* rot-270 or -90 = rot-90 + X-mirror + Y-mirror */ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR | RGA3_ROT_BIT_ROT_90; } else if (req_rga->sina == 0 && req_rga->cosa == 65536) { /* bypass */ req->rotate_mode = 0; } break; case 0x2: /* X-mirror */ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR; break; case 0x3: /* Y-mirror */ req->rotate_mode = RGA3_ROT_BIT_Y_MIRROR; break; case 0x4: /* X-mirror + Y-mirror */ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR; break; default: req->rotate_mode = 0; break; } /* The upper four bits are only allowed to configure the mirror. */ switch ((req_rga->rotate_mode & 0xf0) >> 4) { case 2: /* X-mirror */ req->rotate_mode ^= RGA3_ROT_BIT_X_MIRROR; break; case 3: /* Y-mirror */ req->rotate_mode ^= RGA3_ROT_BIT_Y_MIRROR; break; case 0x4: /* X-mirror + Y-mirror */ req->rotate_mode ^= RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR; break; } req->win0_a_global_val = req_rga->alpha_global_value; req->win1_a_global_val = req_rga->alpha_global_value; /* fixup yuv/rgb convert to rgba missing alpha channel */ if (!(req_rga->alpha_rop_flag & 1)) { if (!rga_is_alpha_format(req_rga->src.format) && rga_is_alpha_format(req_rga->dst.format)) { req->alpha_config.fg_global_alpha_value = 0xff; req->alpha_config.bg_global_alpha_value = 0xff; } } /* simple win can not support dst offset */ if ((!((req_rga->alpha_rop_flag) & 1)) && (req_rga->dst.x_offset == 0 && req_rga->dst.y_offset == 0) && (req_rga->src.yrgb_addr != req_rga->dst.yrgb_addr)) { /* * ABB mode Layer binding: * src => win0 * dst => wr */ /* * enabled by default bot_blend_m1 && bot_alpha_cal_m1 for src channel(win0) * In ABB mode, the number will be fetched according to 16*16, so it needs to * be enabled top_blend_m1 && top_alpha_cal_m1 for dst channel(wr). */ if (rga_is_alpha_format(req_rga->src.format)) req->abb_alpha_pass = true; set_win_info(&req->win0, &req_rga->src); /* enable win0 rotate */ req->win0.rotate_mode = 1; /* set win dst size */ req->win0.dst_act_w = req_rga->dst.act_w; req->win0.dst_act_h = req_rga->dst.act_h; addr_copy(&req->win0, &req_rga->src); addr_copy(&req->wr, &req_rga->dst); req->win0.format = req_rga->src.format; req->wr.format = req_rga->dst.format; } else { /* * ABC mode Layer binding: * src => win1 * src1/dst => win0 * dst => wr */ /* * enabled by default top_blend_m1 && top_alpha_cal_m1 for src channel(win1) * In ABB mode, the number will be fetched according to 16*16, so it needs to * be enabled bot_blend_m1 && bot_alpha_cal_m1 for src1/dst channel(win0). */ if (rga_is_alpha_format(req_rga->src.format)) req->abb_alpha_pass = true; if (req_rga->pat.yrgb_addr != 0) { if (req_rga->src.yrgb_addr == req_rga->dst.yrgb_addr) { /* Convert ABC mode to ABB mode. */ memcpy(&req_rga->src, &req_rga->pat, sizeof(req_rga->src)); memset(&req_rga->pat, 0x0, sizeof(req_rga->pat)); req_rga->bsfilter_flag = 0; rga_swap_pd_mode(req_rga); } else if ((req_rga->dst.x_offset + req_rga->src.act_w > req_rga->pat.act_w) || (req_rga->dst.y_offset + req_rga->src.act_h > req_rga->pat.act_h)) { /* wr_offset + win1.act_size need > win0.act_size */ memcpy(&tmp, &req_rga->src, sizeof(tmp)); memcpy(&req_rga->src, &req_rga->pat, sizeof(req_rga->src)); memcpy(&req_rga->pat, &tmp, sizeof(req_rga->pat)); rga_swap_pd_mode(req_rga); } } set_win_info(&req->win1, &req_rga->src); /* enable win1 rotate */ req->win1.rotate_mode = 1; addr_copy(&req->win1, &req_rga->src); addr_copy(&req->wr, &req_rga->dst); req->win1.format = req_rga->src.format; req->wr.format = req_rga->dst.format; if (req_rga->pat.yrgb_addr != 0) { /* A+B->C mode */ set_win_info(&req->win0, &req_rga->pat); addr_copy(&req->win0, &req_rga->pat); req->win0.format = req_rga->pat.format; /* set win0 dst size */ if (req->win0.x_offset || req->win0.y_offset) { req->win0.src_act_w = req->win0.src_act_w + req->win0.x_offset; req->win0.src_act_h = req->win0.src_act_h + req->win0.y_offset; req->win0.dst_act_w = req_rga->dst.act_w + req->win0.x_offset; req->win0.dst_act_h = req_rga->dst.act_h + req->win0.y_offset; req->win0.x_offset = 0; req->win0.y_offset = 0; } else { req->win0.dst_act_w = req_rga->dst.act_w; req->win0.dst_act_h = req_rga->dst.act_h; } /* set win1 dst size */ req->win1.dst_act_w = req_rga->dst.act_w; req->win1.dst_act_h = req_rga->dst.act_h; } else { /* A+B->B mode */ set_win_info(&req->win0, &req_rga->dst); addr_copy(&req->win0, &req_rga->dst); req->win0.format = req_rga->dst.format; /* only win1 && wr support fbcd, win0 default raster */ req->win0.rd_mode = 0; /* set win0 dst size */ req->win0.dst_act_w = req_rga->dst.act_w; req->win0.dst_act_h = req_rga->dst.act_h; /* set win1 dst size */ req->win1.dst_act_w = req_rga->dst.act_w; req->win1.dst_act_h = req_rga->dst.act_h; } /* dst offset need to config overlap offset */ req->wr.x_offset = req_rga->dst.x_offset; req->wr.y_offset = req_rga->dst.y_offset; } set_wr_info(req_rga, req); if (req->rotate_mode & RGA3_ROT_BIT_ROT_90) { if (req->win1.yrgb_addr != 0) { /* ABB */ if (req->win0.yrgb_addr == req->wr.yrgb_addr) { req->win1.dst_act_w = req_rga->dst.act_h; req->win1.dst_act_h = req_rga->dst.act_w; /* win0 do not need rotate, but net equal to wr */ req->win0.dst_act_w = req_rga->dst.act_h; req->win0.dst_act_h = req_rga->dst.act_w; req->win0.src_act_w = req_rga->dst.act_h; req->win0.src_act_h = req_rga->dst.act_w; } } else { req->win0.rotate_mode = 1; req->win0.dst_act_w = req_rga->dst.act_h; req->win0.dst_act_h = req_rga->dst.act_w; } } /* overlap */ /* Alpha blend mode */ if (((req_rga->alpha_rop_flag) & 1)) { if ((req_rga->alpha_rop_flag >> 3) & 1) { req->alpha_config.enable = true; if ((req_rga->alpha_rop_flag >> 9) & 1) { req->alpha_config.fg_pre_multiplied = false; req->alpha_config.bg_pre_multiplied = false; } else { req->alpha_config.fg_pre_multiplied = true; req->alpha_config.bg_pre_multiplied = true; } req->alpha_config.fg_pixel_alpha_en = rga_is_alpha_format(req->win1.format); req->alpha_config.bg_pixel_alpha_en = rga_is_alpha_format(req->win0.format); if (req_rga->feature.global_alpha_en) { if (req_rga->fg_global_alpha < 0xff) { req->alpha_config.fg_global_alpha_en = true; req->alpha_config.fg_global_alpha_value = req_rga->fg_global_alpha; } else if (!req->alpha_config.fg_pixel_alpha_en) { req->alpha_config.fg_global_alpha_en = true; req->alpha_config.fg_global_alpha_value = 0xff; } if (req_rga->bg_global_alpha < 0xff) { req->alpha_config.bg_global_alpha_en = true; req->alpha_config.bg_global_alpha_value = req_rga->bg_global_alpha; } else if (!req->alpha_config.bg_pixel_alpha_en) { req->alpha_config.bg_global_alpha_en = true; req->alpha_config.bg_global_alpha_value = 0xff; } } else { req->alpha_config.fg_global_alpha_value = 0xff; req->alpha_config.bg_global_alpha_value = 0xff; } req->alpha_config.mode = req_rga->PD_mode; } } /* yuv to rgb */ /* 601 limit */ if (req_rga->yuv2rgb_mode == 1) { req->win0.y2r_mode = 0; req->win1.y2r_mode = 0; /* 601 full */ } else if (req_rga->yuv2rgb_mode == 2) { req->win0.y2r_mode = 2; req->win1.y2r_mode = 2; /* 709 limit */ } else if (req_rga->yuv2rgb_mode == 3) { req->win0.y2r_mode = 1; req->win1.y2r_mode = 1; } /* rgb to yuv */ /* 601 limit */ if ((req_rga->yuv2rgb_mode >> 2) == 2) { req->win0.r2y_mode = 0; req->win1.r2y_mode = 0; /* 601 full */ } else if ((req_rga->yuv2rgb_mode >> 2) == 1) { req->win0.r2y_mode = 2; req->win1.r2y_mode = 2; /* 709 limit */ } else if ((req_rga->yuv2rgb_mode >> 2) == 3) { req->win0.r2y_mode = 1; req->win1.r2y_mode = 1; } /* color key: 8bit->10bit */ req->color_key_min = (req_rga->color_key_min & 0xff) << 22 | ((req_rga->color_key_min >> 8) & 0xff) << 2 | ((req_rga->color_key_min >> 16) & 0xff) << 12; req->color_key_max = (req_rga->color_key_max & 0xff) << 22 | ((req_rga->color_key_max >> 8) & 0xff) << 2 | ((req_rga->color_key_max >> 16) & 0xff) << 12; if (req_rga->mmu_info.mmu_en && (req_rga->mmu_info.mmu_flag & 1) == 1) { req->mmu_info.src0_mmu_flag = 1; req->mmu_info.src1_mmu_flag = 1; req->mmu_info.dst_mmu_flag = 1; } } static void rga3_soft_reset(struct rga_scheduler_t *scheduler) { u32 i; u32 iommu_dte_addr = 0; if (scheduler->data->mmu == RGA_IOMMU) iommu_dte_addr = rga_read(RGA_IOMMU_DTE_ADDR, scheduler); rga_write(s_RGA3_SYS_CTRL_CCLK_SRESET(1) | s_RGA3_SYS_CTRL_ACLK_SRESET(1), RGA3_SYS_CTRL, scheduler); for (i = 0; i < RGA_RESET_TIMEOUT; i++) { if (rga_read(RGA3_RO_SRST, scheduler) & m_RGA3_RO_SRST_RO_RST_DONE) break; udelay(1); } rga_write(s_RGA3_SYS_CTRL_CCLK_SRESET(0) | s_RGA3_SYS_CTRL_ACLK_SRESET(0), RGA3_SYS_CTRL, scheduler); if (scheduler->data->mmu == RGA_IOMMU) { rga_write(iommu_dte_addr, RGA_IOMMU_DTE_ADDR, scheduler); /* enable iommu */ rga_write(RGA_IOMMU_CMD_ENABLE_PAGING, RGA_IOMMU_COMMAND, scheduler); } if (i == RGA_RESET_TIMEOUT) rga_err("%s[%#x] soft reset timeout. SYS_CTRL[0x%x], RO_SRST[0x%x]\n", rga_get_core_name(scheduler->core), scheduler->core, rga_read(RGA3_SYS_CTRL, scheduler), rga_read(RGA3_RO_SRST, scheduler)); else rga_log("%s[%#x] soft reset complete.\n", rga_get_core_name(scheduler->core), scheduler->core); } static int rga3_scale_check(struct rga_job *job, const struct rga3_req *req) { u32 win0_saw, win0_sah, win0_daw, win0_dah; u32 win1_saw, win1_sah, win1_daw, win1_dah; if (req->rotate_mode & RGA3_ROT_BIT_ROT_90) { if (req->win1.yrgb_addr != 0) { /* ABB */ if (req->win0.yrgb_addr == req->wr.yrgb_addr) { /* win0 do not need rotate, but net equal to wr */ win0_saw = req->win0.src_act_h; win0_sah = req->win0.src_act_w; win0_daw = req->win0.dst_act_h; win0_dah = req->win0.dst_act_w; win1_saw = req->win1.dst_act_w; win1_sah = req->win1.dst_act_h; win1_daw = req->win1.dst_act_h; win1_dah = req->win1.dst_act_w; } else { win0_saw = req->win0.src_act_w; win0_sah = req->win0.src_act_h; win0_daw = req->win0.dst_act_w; win0_dah = req->win0.dst_act_h; win1_saw = req->win1.src_act_w; win1_sah = req->win1.src_act_h; win1_daw = req->win1.dst_act_w; win1_dah = req->win1.dst_act_h; } } else { win0_saw = req->win0.src_act_w; win0_sah = req->win0.src_act_h; win0_daw = req->win0.dst_act_h; win0_dah = req->win0.dst_act_w; } } else { win0_saw = req->win0.src_act_w; win0_sah = req->win0.src_act_h; win0_daw = req->win0.dst_act_w; win0_dah = req->win0.dst_act_h; if (req->win1.yrgb_addr != 0) { win1_saw = req->win1.src_act_w; win1_sah = req->win1.src_act_h; win1_daw = req->win1.dst_act_w; win1_dah = req->win1.dst_act_h; } } if (((win0_saw >> 3) > win0_daw) || ((win0_sah >> 3) > win0_dah)) { rga_job_log(job, "win0 unsupported to scaling less than 1/8 times. src[%d, %d], dst[%d, %d]\n", win0_saw, win0_sah, win0_daw, win0_dah); return -EINVAL; } if (((win0_daw >> 3) > win0_saw) || ((win0_dah >> 3) > win0_sah)) { rga_job_log(job, "win0 unsupported to scaling more than 8 times. src[%d, %d], dst[%d, %d]\n", win0_saw, win0_sah, win0_daw, win0_dah); return -EINVAL; } if (req->win1.yrgb_addr != 0) { if (((win1_saw >> 3) > win1_daw) || ((win1_sah >> 3) > win1_dah)) { rga_job_log(job, "win1 unsupported to scaling less than 1/8 times. src[%d, %d], dst[%d, %d]\n", win1_saw, win1_sah, win1_daw, win1_dah); return -EINVAL; } if (((win1_daw >> 3) > win1_saw) || ((win1_dah >> 3) > win1_sah)) { rga_job_log(job, "win1 unsupported to scaling more than 8 times. src[%d, %d], dst[%d, %d]\n", win1_saw, win1_sah, win1_daw, win1_dah); return -EINVAL; } } return 0; } static int rga3_check_param(struct rga_job *job, const struct rga_hw_data *data, const struct rga3_req *req) { if (unlikely(rga_hw_out_of_range(&(data->input_range), req->win0.src_act_w, req->win0.src_act_h) || rga_hw_out_of_range(&(data->input_range), req->win0.dst_act_w, req->win0.dst_act_h) || rga_hw_out_of_range(&(data->input_range), req->win0.src_act_w + req->win0.x_offset, req->win0.src_act_h + req->win0.y_offset))) { rga_job_err(job, "invalid win0, src[w,h] = [%d, %d], dst[w,h] = [%d, %d], off[x,y] = [%d,%d]\n", req->win0.src_act_w, req->win0.src_act_h, req->win0.dst_act_w, req->win0.dst_act_h, req->win0.x_offset, req->win0.y_offset); return -EINVAL; } if (unlikely(req->win0.vir_w * rga_get_pixel_stride_from_format(req->win0.format) > data->max_byte_stride * 8)) { rga_job_err(job, "invalid win0 stride, stride = %d, pixel_stride = %d, max_byte_stride = %d\n", req->win0.vir_w, rga_get_pixel_stride_from_format(req->win0.format), data->max_byte_stride); return -EINVAL; } if (unlikely(rga_hw_out_of_range(&(data->output_range), req->wr.dst_act_w, req->wr.dst_act_h))) { rga_job_err(job, "invalid wr, [w,h] = [%d, %d]\n", req->wr.dst_act_w, req->wr.dst_act_h); return -EINVAL; } if (unlikely(req->wr.vir_w * rga_get_pixel_stride_from_format(req->wr.format) > data->max_byte_stride * 8)) { rga_job_err(job, "invalid wr stride, stride = %d, pixel_stride = %d, max_byte_stride = %d\n", req->wr.vir_w, rga_get_pixel_stride_from_format(req->wr.format), data->max_byte_stride); return -EINVAL; } if (req->win1.yrgb_addr != 0) { if (unlikely(rga_hw_out_of_range(&(data->input_range), req->win1.src_act_w, req->win1.src_act_h) || rga_hw_out_of_range(&(data->input_range), req->win1.dst_act_w, req->win1.dst_act_h) || rga_hw_out_of_range(&(data->input_range), req->win1.src_act_w + req->win1.x_offset, req->win1.src_act_h + req->win1.y_offset))) { rga_job_err(job, "invalid win1, src[w,h] = [%d, %d], dst[w,h] = [%d, %d], off[x,y] = [%d,%d]\n", req->win1.src_act_w, req->win1.src_act_h, req->win1.dst_act_w, req->win1.dst_act_h, req->win1.x_offset, req->win1.y_offset); return -EINVAL; } if (unlikely(req->win1.vir_w * rga_get_pixel_stride_from_format(req->win1.format) > data->max_byte_stride * 8)) { rga_job_err(job, "invalid win1 stride, stride = %d, pixel_stride = %d, max_byte_stride = %d\n", req->win1.vir_w, rga_get_pixel_stride_from_format(req->win1.format), data->max_byte_stride); return -EINVAL; } /* warning: rotate mode skip this judge */ if (req->rotate_mode == 0) { /* check win0 dst size > win1 dst size */ if (unlikely((req->win1.dst_act_w > req->win0.dst_act_w) || (req->win1.dst_act_h > req->win0.dst_act_h))) { rga_job_err(job, "invalid output param win0[w,h] = [%d, %d], win1[w,h] = [%d, %d]\n", req->win0.dst_act_w, req->win0.dst_act_h, req->win1.dst_act_w, req->win1.dst_act_h); return -EINVAL; } } } if (rga3_scale_check(job, req) < 0) return -EINVAL; return 0; } static void print_debug_info(struct rga_job *job, struct rga3_req *req) { rga_job_log(job, "render_mode:%s, bitblit_mode=%d, rotate_mode:%x\n", rga_get_render_mode_str(req->render_mode), req->bitblt_mode, req->rotate_mode); rga_job_log(job, "win0: y = %lx uv = %lx v = %lx src_w = %d src_h = %d\n", req->win0.yrgb_addr, req->win0.uv_addr, req->win0.v_addr, req->win0.src_act_w, req->win0.src_act_h); rga_job_log(job, "win0: vw = %d vh = %d xoff = %d yoff = %d format = %s\n", req->win0.vir_w, req->win0.vir_h, req->win0.x_offset, req->win0.y_offset, rga_get_format_name(req->win0.format)); rga_job_log(job, "win0: dst_w = %d, dst_h = %d, rd_mode = %d\n", req->win0.dst_act_w, req->win0.dst_act_h, req->win0.rd_mode); rga_job_log(job, "win0: rot_mode = %d, en = %d, compact = %d, endian = %d\n", req->win0.rotate_mode, req->win0.enable, req->win0.is_10b_compact, req->win0.is_10b_endian); if (req->win1.yrgb_addr != 0 || req->win1.uv_addr != 0 || req->win1.v_addr != 0) { rga_job_log(job, "win1: y = %lx uv = %lx v = %lx src_w = %d src_h = %d\n", req->win1.yrgb_addr, req->win1.uv_addr, req->win1.v_addr, req->win1.src_act_w, req->win1.src_act_h); rga_job_log(job, "win1: vw = %d vh = %d xoff = %d yoff = %d format = %s\n", req->win1.vir_w, req->win1.vir_h, req->win1.x_offset, req->win1.y_offset, rga_get_format_name(req->win1.format)); rga_job_log(job, "win1: dst_w = %d, dst_h = %d, rd_mode = %d\n", req->win1.dst_act_w, req->win1.dst_act_h, req->win1.rd_mode); rga_job_log(job, "win1: rot_mode = %d, en = %d, compact = %d, endian = %d\n", req->win1.rotate_mode, req->win1.enable, req->win1.is_10b_compact, req->win1.is_10b_endian); } rga_job_log(job, "wr: y = %lx uv = %lx v = %lx vw = %d vh = %d\n", req->wr.yrgb_addr, req->wr.uv_addr, req->wr.v_addr, req->wr.vir_w, req->wr.vir_h); rga_job_log(job, "wr: ovlp_xoff = %d ovlp_yoff = %d format = %s rdmode = %d\n", req->wr.x_offset, req->wr.y_offset, rga_get_format_name(req->wr.format), req->wr.rd_mode); rga_job_log(job, "mmu: win0 = %.2x win1 = %.2x wr = %.2x\n", req->mmu_info.src0_mmu_flag, req->mmu_info.src1_mmu_flag, req->mmu_info.dst_mmu_flag); rga_job_log(job, "alpha: flag %x mode=%s\n", req->alpha_rop_flag, rga_get_blend_mode_str(req->alpha_config.mode)); rga_job_log(job, "alpha: pre_multi=[%d,%d] pixl=[%d,%d] glb=[%d,%d]\n", req->alpha_config.fg_pre_multiplied, req->alpha_config.bg_pre_multiplied, req->alpha_config.fg_pixel_alpha_en, req->alpha_config.bg_pixel_alpha_en, req->alpha_config.fg_global_alpha_en, req->alpha_config.bg_global_alpha_en); rga_job_log(job, "alpha: fg_global_alpha=%x bg_global_alpha=%x\n", req->alpha_config.fg_global_alpha_value, req->alpha_config.bg_global_alpha_value); rga_job_log(job, "yuv2rgb mode is %x\n", req->yuv2rgb_mode); } static int rga3_align_check(struct rga_job *job, struct rga3_req *req) { if (rga_is_yuv10bit_format(req->win0.format)) if ((req->win0.vir_w % 64) || (req->win0.x_offset % 4) || (req->win0.src_act_w % 4) || (req->win0.y_offset % 4) || (req->win0.src_act_h % 4) || (req->win0.vir_h % 2)) rga_job_log(job, "yuv10bit err win0 wstride is not align\n"); if (rga_is_yuv10bit_format(req->win1.format)) if ((req->win1.vir_w % 64) || (req->win1.x_offset % 4) || (req->win1.src_act_w % 4) || (req->win1.y_offset % 4) || (req->win1.src_act_h % 4) || (req->win1.vir_h % 2)) rga_job_log(job, "yuv10bit err win1 wstride is not align\n"); if (rga_is_yuv8bit_format(req->win0.format)) if ((req->win0.vir_w % 16) || (req->win0.x_offset % 2) || (req->win0.src_act_w % 2) || (req->win0.y_offset % 2) || (req->win0.src_act_h % 2) || (req->win0.vir_h % 2)) rga_job_log(job, "yuv8bit err win0 wstride is not align\n"); if (rga_is_yuv8bit_format(req->win1.format)) if ((req->win1.vir_w % 16) || (req->win1.x_offset % 2) || (req->win1.src_act_w % 2) || (req->win1.y_offset % 2) || (req->win1.src_act_h % 2) || (req->win1.vir_h % 2)) rga_job_log(job, "yuv8bit err win1 wstride is not align\n"); return 0; } static int rga3_init_reg(struct rga_job *job) { struct rga3_req req; int ret = 0; struct rga_scheduler_t *scheduler = NULL; ktime_t timestamp = ktime_get(); scheduler = job->scheduler; if (unlikely(scheduler == NULL)) { rga_job_err(job, "failed to get scheduler, %s(%d)\n", __func__, __LINE__); return -EINVAL; } memset(&req, 0x0, sizeof(req)); rga_cmd_to_rga3_cmd(&job->rga_command_base, &req); /* check value if legal */ ret = rga3_check_param(job, scheduler->data, &req); if (ret == -EINVAL) { rga_job_err(job, "req argument is inval\n"); return ret; } rga3_align_check(job, &req); /* for debug */ if (DEBUGGER_EN(MSG)) print_debug_info(job, &req); if (rga3_gen_reg_info((uint8_t *) job->cmd_buf->vaddr, &req) == -1) { rga_job_err(job, "RKA: gen reg info error\n"); return -EINVAL; } if (DEBUGGER_EN(TIME)) rga_job_log(job, "generate register cost time %lld us\n", ktime_us_delta(ktime_get(), timestamp)); return ret; } static void rga3_dump_read_back_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) { int i; unsigned long flags; uint32_t cmd_reg[48] = {0}; spin_lock_irqsave(&scheduler->irq_lock, flags); for (i = 0; i < 48; i++) cmd_reg[i] = rga_read(0x100 + i * 4, scheduler); spin_unlock_irqrestore(&scheduler->irq_lock, flags); rga_job_log(job, "CMD_READ_BACK_REG\n"); for (i = 0; i < 12; i++) rga_job_log(job, "i = %x : %.8x %.8x %.8x %.8x\n", i, cmd_reg[0 + i * 4], cmd_reg[1 + i * 4], cmd_reg[2 + i * 4], cmd_reg[3 + i * 4]); } static int rga3_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) { int i; bool master_mode_en; uint32_t sys_ctrl; uint32_t *cmd; ktime_t now = ktime_get(); cmd = job->cmd_buf->vaddr; /* * Currently there is no iova allocated for storing cmd for the IOMMU device, * so the iommu device needs to use the slave mode. */ if (scheduler->data->mmu != RGA_IOMMU) master_mode_en = true; else master_mode_en = false; if (DEBUGGER_EN(REG)) { rga_job_log(job, "CMD_REG\n"); for (i = 0; i < 12; i++) rga_job_log(job, "i = %x : %.8x %.8x %.8x %.8x\n", i, cmd[0 + i * 4], cmd[1 + i * 4], cmd[2 + i * 4], cmd[3 + i * 4]); } /* All CMD finish int */ rga_write(m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH | m_RGA3_INT_ERROR_MASK, RGA3_INT_EN, scheduler); if (master_mode_en) { /* master mode */ sys_ctrl = s_RGA3_SYS_CTRL_CMD_MODE(1); rga_write(job->cmd_buf->dma_addr, RGA3_CMD_ADDR, scheduler); rga_write(sys_ctrl, RGA3_SYS_CTRL, scheduler); rga_write(m_RGA3_CMD_CTRL_CMD_LINE_ST_P, RGA3_CMD_CTRL, scheduler); } else { /* slave mode */ sys_ctrl = s_RGA3_SYS_CTRL_CMD_MODE(0) | m_RGA3_SYS_CTRL_RGA_SART; for (i = 0; i <= 50; i++) rga_write(cmd[i], 0x100 + i * 4, scheduler); rga_write(sys_ctrl, RGA3_SYS_CTRL, scheduler); } if (DEBUGGER_EN(REG)) { rga_job_log(job, "sys_ctrl = 0x%x, int_en = 0x%x, int_raw = 0x%x\n", rga_read(RGA3_SYS_CTRL, scheduler), rga_read(RGA3_INT_EN, scheduler), rga_read(RGA3_INT_RAW, scheduler)); rga_job_log(job, "hw_status = 0x%x, cmd_status = 0x%x\n", rga_read(RGA3_STATUS0, scheduler), rga_read(RGA3_CMD_STATE, scheduler)); } if (DEBUGGER_EN(TIME)) rga_job_log(job, "set register cost time %lld us\n", ktime_us_delta(ktime_get(), now)); job->timestamp.hw_execute = now; job->timestamp.hw_recode = now; job->session->last_active = now; if (DEBUGGER_EN(REG)) rga3_dump_read_back_reg(job, scheduler); return 0; } static int rga3_get_version(struct rga_scheduler_t *scheduler) { u32 major_version, minor_version, svn_version; u32 reg_version; if (!scheduler) { rga_err("scheduler is null\n"); return -EINVAL; } reg_version = rga_read(RGA3_VERSION_NUM, scheduler); major_version = (reg_version & RGA3_MAJOR_VERSION_MASK) >> 28; minor_version = (reg_version & RGA3_MINOR_VERSION_MASK) >> 20; svn_version = (reg_version & RGA3_SVN_VERSION_MASK); snprintf(scheduler->version.str, 10, "%x.%01x.%05x", major_version, minor_version, svn_version); scheduler->version.major = major_version; scheduler->version.minor = minor_version; scheduler->version.revision = svn_version; return 0; } static int rga3_read_status(struct rga_job *job, struct rga_scheduler_t *scheduler) { job->intr_status = rga_read(RGA3_INT_RAW, scheduler); job->hw_status = rga_read(RGA3_STATUS0, scheduler); job->cmd_status = rga_read(RGA3_CMD_STATE, scheduler); job->work_cycle = 0; return 0; } static void rga3_clear_intr(struct rga_scheduler_t *scheduler) { rga_write(m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH | m_RGA3_INT_ERROR_MASK, RGA3_INT_CLR, scheduler); } static int rga3_irq(struct rga_scheduler_t *scheduler) { struct rga_job *job = scheduler->running_job; if (job == NULL) { rga3_clear_intr(scheduler); rga_err("core[%d], invalid job, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", scheduler->core, rga_read(RGA3_INT_RAW, scheduler), rga_read(RGA3_STATUS0, scheduler), rga_read(RGA3_CMD_STATE, scheduler)); return IRQ_HANDLED; } if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) { rga3_clear_intr(scheduler); return IRQ_WAKE_THREAD; } scheduler->ops->read_status(job, scheduler); if (DEBUGGER_EN(INT_FLAG)) rga_job_log(job, "irq handler, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", job->intr_status, job->hw_status, job->cmd_status); if (job->intr_status & (m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH)) { set_bit(RGA_JOB_STATE_FINISH, &job->state); } else if (job->intr_status & m_RGA3_INT_ERROR_MASK) { set_bit(RGA_JOB_STATE_INTR_ERR, &job->state); rga_job_err(job, "irq handler err! INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", job->intr_status, job->hw_status, job->cmd_status); scheduler->ops->soft_reset(scheduler); } rga3_clear_intr(scheduler); return IRQ_WAKE_THREAD; } static int rga3_isr_thread(struct rga_job *job, struct rga_scheduler_t *scheduler) { if (DEBUGGER_EN(INT_FLAG)) rga_job_log(job, "isr thread, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", rga_read(RGA3_INT_RAW, scheduler), rga_read(RGA3_STATUS0, scheduler), rga_read(RGA3_CMD_STATE, scheduler)); if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) { if (job->intr_status & m_RGA3_INT_RAG_MI_RD_BUS_ERR) { rga_job_err(job, "DMA read bus error, please check size of the input_buffer or whether the buffer has been freed.\n"); job->ret = -EFAULT; } else if (job->intr_status & m_RGA3_INT_WIN0_FBCD_DEC_ERR) { rga_job_err(job, "win0 FBC decoder error, please check the fbc image of the source.\n"); job->ret = -EFAULT; } else if (job->intr_status & m_RGA3_INT_WIN1_FBCD_DEC_ERR) { rga_job_err(job, "win1 FBC decoder error, please check the fbc image of the source.\n"); job->ret = -EFAULT; } else if (job->intr_status & m_RGA3_INT_RGA_MI_WR_BUS_ERR) { rga_job_err(job, "wr buss error, please check size of the output_buffer or whether the buffer has been freed.\n"); job->ret = -EFAULT; } if (job->ret == 0) { rga_job_err(job, "rga intr error[0x%x]!\n", job->intr_status); job->ret = -EFAULT; } } return IRQ_HANDLED; } const struct rga_backend_ops rga3_ops = { .get_version = rga3_get_version, .set_reg = rga3_set_reg, .init_reg = rga3_init_reg, .soft_reset = rga3_soft_reset, .read_back_reg = NULL, .read_status = rga3_read_status, .irq = rga3_irq, .isr_thread = rga3_isr_thread, };