From 971dce993d3075b927b6ca393d0c9dcb9532c62f Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Thu, 5 Dec 2024 11:39:16 +0800 Subject: [PATCH] video: rockchip: rga3: fix bi-linear scaled down causing timeout Adjust config based on RGA2 limit. Update driver version to 1.3.7 Signed-off-by: Yu Qiaowei Change-Id: I2954dbb36a1698e34da14fff33fb9d97792478da --- .../rockchip/rga3/include/rga2_reg_info.h | 13 ++- drivers/video/rockchip/rga3/include/rga_drv.h | 2 +- drivers/video/rockchip/rga3/rga2_reg_info.c | 79 ++++++++++++++++--- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/drivers/video/rockchip/rga3/include/rga2_reg_info.h b/drivers/video/rockchip/rga3/include/rga2_reg_info.h index cca8a20b16b2..4afac19b0a16 100644 --- a/drivers/video/rockchip/rga3/include/rga2_reg_info.h +++ b/drivers/video/rockchip/rga3/include/rga2_reg_info.h @@ -292,11 +292,15 @@ /* RGA_SRC_ACT_INFO */ -#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH (0x1fff << 0) -#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT (0x1fff << 16) +#define m_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_YOFF (0x3 << 30) +#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT (0x7ff << 16) +#define m_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_XOFF (0x3 << 14) +#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH (0x7ff << 0) -#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH(x) ((x & 0x1fff) << 0) -#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT(x) ((x & 0x1fff) << 16) +#define s_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_YOFF(x) ((x & 0x3) << 30) +#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT(x) ((x & 0x7ff) << 16) +#define s_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_XOFF(x) ((x & 0x3) << 14) +#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH(x) ((x & 0x7ff) << 0) /* RGA2_OSD_CTRL0 */ #define m_RGA2_OSD_CTRL0_SW_OSD_MODE (0x3 << 0) @@ -480,6 +484,7 @@ #define s_RGA2_MMU_CTRL1_SW_ELS_MMU_FLUSH(x) ((x & 0x1) << 13) #define RGA2_VSP_BICUBIC_LIMIT 1996 +#define RGA2_BILINEAR_PREC 12 union rga2_color_ctrl { uint32_t value; diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h index 9c5688107542..e0c34bb4aa7e 100644 --- a/drivers/video/rockchip/rga3/include/rga_drv.h +++ b/drivers/video/rockchip/rga3/include/rga_drv.h @@ -88,7 +88,7 @@ #define DRIVER_MAJOR_VERISON 1 #define DRIVER_MINOR_VERSION 3 -#define DRIVER_REVISION_VERSION 6 +#define DRIVER_REVISION_VERSION 7 #define DRIVER_PATCH_VERSION #define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \ diff --git a/drivers/video/rockchip/rga3/rga2_reg_info.c b/drivers/video/rockchip/rga3/rga2_reg_info.c index 49523d5d7e95..aa918ac5b92f 100644 --- a/drivers/video/rockchip/rga3/rga2_reg_info.c +++ b/drivers/video/rockchip/rga3/rga2_reg_info.c @@ -101,17 +101,52 @@ unsigned int rga2_rop_code[256] = { 0x00000051, 0x008004d4, 0x00800451, 0x00800007,//f }; +static void rga2_scale_down_bilinear_protect(u32 *param_fix, u32 *src_fix, + u32 param, u32 offset, u32 src, u32 dst) +{ + int final_coor, final_diff, final_steps; + + while (1) { + final_coor = offset + param * (dst - 1); + final_diff = (src - 1) * (1 << RGA2_BILINEAR_PREC) - final_coor; + + /* + * The hardware requires that the last point of the dst map on + * src must not exceed the range of src. + */ + if (final_diff <= 0) + param = param - 1; + else + break; + } + + /* + * The hardware requires that the last point of dst mapping on + * src be between the last two points of each row/column, so + * actual width/height needs to be modified. + */ + final_steps = (final_coor & ((1 << RGA2_BILINEAR_PREC) - 1)) ? + ((final_coor >> RGA2_BILINEAR_PREC) + 1) : + (final_coor >> RGA2_BILINEAR_PREC); + + *param_fix = param; + *src_fix = final_steps + 1; +} + static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg) { u32 *bRGA_SRC_X_FACTOR; u32 *bRGA_SRC_Y_FACTOR; + u32 *bRGA_SRC_ACT_INFO; u32 sw, sh; u32 dw, dh; u32 param_x, param_y; u32 scale_x_offset, scale_y_offset; + u32 src_fix, param_fix; bRGA_SRC_X_FACTOR = (u32 *) (base + RGA2_SRC_X_FACTOR_OFFSET); bRGA_SRC_Y_FACTOR = (u32 *) (base + RGA2_SRC_Y_FACTOR_OFFSET); + bRGA_SRC_ACT_INFO = (u32 *) (base + RGA2_SRC_ACT_INFO_OFFSET); if (((msg->rotate_mode & 0x3) == 1) || ((msg->rotate_mode & 0x3) == 3)) { @@ -128,10 +163,24 @@ static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg) if (sw > dw) { if (msg->interp.horiz == RGA_INTERP_LINEAR) { /* default to half_pixel mode. */ - param_x = (sw << 12) / dw; - scale_x_offset = 0x1ff; + param_x = (sw << RGA2_BILINEAR_PREC) / dw; + scale_x_offset = (1 << RGA2_BILINEAR_PREC) >> 1; - *bRGA_SRC_X_FACTOR = ((param_x & 0xffff) | ((scale_x_offset) << 16)); + rga2_scale_down_bilinear_protect(¶m_fix, &src_fix, + param_x, scale_x_offset, sw, dw); + if (DEBUGGER_EN(MSG)) { + if (param_x != param_fix) + rga_log("scale: Bi-linear horiz factor %#x fix to %#x\n", + param_x, param_fix); + if (sw != src_fix) + rga_log("scale: Bi-linear src_width %d -> %d\n", + sw, src_fix); + } + + *bRGA_SRC_X_FACTOR = ((param_fix & 0xffff) | ((scale_x_offset) << 16)); + *bRGA_SRC_ACT_INFO = + ((*bRGA_SRC_ACT_INFO & (~m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH)) | + s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH((src_fix - 1))); } else { param_x = ((dw << 16) + (sw / 2)) / sw; @@ -151,10 +200,24 @@ static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg) if (sh > dh) { if (msg->interp.verti == RGA_INTERP_LINEAR) { /* default to half_pixel mode. */ - param_y = (sh << 12) / dh; - scale_y_offset = 0x1ff; + param_y = (sh << RGA2_BILINEAR_PREC) / dh; + scale_y_offset = (1 << RGA2_BILINEAR_PREC) >> 1; - *bRGA_SRC_Y_FACTOR = ((param_y & 0xffff) | ((scale_y_offset) << 16)); + rga2_scale_down_bilinear_protect(¶m_fix, &src_fix, + param_y, scale_y_offset, sh, dh); + if (DEBUGGER_EN(MSG)) { + if (param_y != param_fix) + rga_log("scale: Bi-linear verti factor %#x fix to %#x\n", + param_y, param_fix); + if (sh != src_fix) + rga_log("scale: Bi-linear src_height %d fix to %d\n", + sh, src_fix); + } + + *bRGA_SRC_Y_FACTOR = ((param_fix & 0xffff) | ((scale_y_offset) << 16)); + *bRGA_SRC_ACT_INFO = + ((*bRGA_SRC_ACT_INFO & (~m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT)) | + s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT((src_fix - 1))); } else { param_y = ((dh << 16) + (sh / 2)) / sh; @@ -363,10 +426,6 @@ static void RGA2_set_reg_src_info(u8 *base, struct rga2_req *msg) vsd_scale_mode = 0; break; case RGA_INTERP_LINEAR: - if (sh > 4096) - /* force select average */ - vsd_scale_mode = 0; - else vsd_scale_mode = 1; break;