Files
bfe-core1106-sdk/patches/50-rga.patch
BFE EngineeringandClaude Opus 4.8 f2a9c0a32c kernel: RV1106 6.18.46 patch series + hermetic build wrapper (P1)
- patches/: the pristine-6.18.46 -> WardenOS delta as a 13-patch, subsystem-split
  series (223 files, ~136K lines: clk, pinctrl, DTs/mach, usb-phy, VOP/panel/rgb,
  mailbox, pvtm, rknpu, rga, aic8800 wifi, audio codec, thermal/rtc/adc/gmac/touch).
  Verified: every patch applies cleanly onto pristine (git apply --check), the full
  series reproduces the hardware-verified tree, and the applied source configures +
  builds the warden dtb + rockchip DRM drivers (rc=0).
- build/build-kernel.sh: fetch+verify pristine (sha256-pinned) -> apply series ->
  warden_defconfig -> zImage + rv1106-warden.dtb. build/warden_defconfig captured.
- CI: `patches-apply` (GitHub-hosted, cached tarball) enforces the series applies;
  `kernel-build` (self-hosted warden-sdk runner, dispatch-gated until registered)
  runs the full build and uploads the image.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017wB8KB3MMQztRDXCMCkPrf
2026-08-25 14:26:04 -06:00

17109 lines
465 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0adb1e2fa..954f3de7d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -46,6 +46,7 @@ source "drivers/gpu/drm/Kconfig"
menu "Frame buffer Devices"
source "drivers/video/fbdev/Kconfig"
+source "drivers/video/rockchip/Kconfig"
endmenu
source "drivers/video/backlight/Kconfig"
@@ -90,4 +91,5 @@ endif
source "drivers/gpu/trace/Kconfig"
+source "drivers/video/rockchip/Kconfig"
endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ffbac4387..bd44d988c 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
ifeq ($(CONFIG_OF),y)
obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
endif
+obj-y += rockchip/
diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig
new file mode 100644
index 000000000..39e01f133
--- /dev/null
+++ b/drivers/video/rockchip/Kconfig
@@ -0,0 +1 @@
+source "drivers/video/rockchip/rga3/Kconfig"
diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile
new file mode 100644
index 000000000..53958b85c
--- /dev/null
+++ b/drivers/video/rockchip/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ROCKCHIP_MULTI_RGA) += rga3/
diff --git a/drivers/video/rockchip/rga3/Kconfig b/drivers/video/rockchip/rga3/Kconfig
new file mode 100644
index 000000000..c8c96b2d6
--- /dev/null
+++ b/drivers/video/rockchip/rga3/Kconfig
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0
+menuconfig ROCKCHIP_MULTI_RGA
+ tristate "MULTI_RGA"
+ depends on ARCH_ROCKCHIP
+ help
+ multi_rga module.
+
+if ROCKCHIP_MULTI_RGA
+
+config ROCKCHIP_RGA_ASYNC
+ bool "Enable async mode"
+ depends on SYNC_FILE
+ default y
+ help
+ Asynchronous calls will be supported.
+
+config ROCKCHIP_RGA_PROC_FS
+ bool "Enable RGA procfs"
+ select ROCKCHIP_RGA_DEBUGGER
+ depends on PROC_FS
+ help
+ Enable procfs to debug multi RGA driver.
+
+config ROCKCHIP_RGA_DEBUG_FS
+ bool "Enable RGA debugfs"
+ select ROCKCHIP_RGA_DEBUGGER
+ depends on DEBUG_FS
+ default y
+ help
+ Enable debugfs to debug multi RGA driver.
+
+config ROCKCHIP_RGA_DEBUGGER
+ bool
+ help
+ Enabling the debugger of multi RGA, you can use procfs and debugfs for debugging.
+
+endif
diff --git a/drivers/video/rockchip/rga3/Makefile b/drivers/video/rockchip/rga3/Makefile
new file mode 100644
index 000000000..11f401de2
--- /dev/null
+++ b/drivers/video/rockchip/rga3/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-y += -I$(srctree)/$(src)/include
+
+rga3-y := rga_drv.o rga_common.o rga3_reg_info.o rga_iommu.o rga_dma_buf.o rga_job.o rga_hw_config.o rga2_reg_info.o rga_policy.o rga_mm.o
+rga3-$(CONFIG_ROCKCHIP_RGA_ASYNC) += rga_fence.o
+rga3-$(CONFIG_ROCKCHIP_RGA_DEBUGGER) += rga_debugger.o
+
+obj-$(CONFIG_ROCKCHIP_MULTI_RGA) += rga3.o
diff --git a/drivers/video/rockchip/rga3/include/rga.h b/drivers/video/rockchip/rga3/include/rga.h
new file mode 100644
index 000000000..2a60a1ae7
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga.h
@@ -0,0 +1,944 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RGA_DRIVER_H_
+#define _RGA_DRIVER_H_
+
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+
+/* Use 'r' as magic number */
+#define RGA_IOC_MAGIC 'r'
+#define RGA_IOW(nr, type) _IOW(RGA_IOC_MAGIC, nr, type)
+#define RGA_IOR(nr, type) _IOR(RGA_IOC_MAGIC, nr, type)
+#define RGA_IOWR(nr, type) _IOWR(RGA_IOC_MAGIC, nr, type)
+
+#define RGA_IOC_GET_DRVIER_VERSION RGA_IOR(0x1, struct rga_version_t)
+#define RGA_IOC_GET_HW_VERSION RGA_IOR(0x2, struct rga_hw_versions_t)
+#define RGA_IOC_IMPORT_BUFFER RGA_IOWR(0x3, struct rga_buffer_pool)
+#define RGA_IOC_RELEASE_BUFFER RGA_IOW(0x4, struct rga_buffer_pool)
+#define RGA_IOC_REQUEST_CREATE RGA_IOR(0x5, uint32_t)
+#define RGA_IOC_REQUEST_SUBMIT RGA_IOWR(0x6, struct rga_user_request)
+#define RGA_IOC_REQUEST_CONFIG RGA_IOWR(0x7, struct rga_user_request)
+#define RGA_IOC_REQUEST_CANCEL RGA_IOWR(0x8, uint32_t)
+
+#define RGA_BLIT_SYNC 0x5017
+#define RGA_BLIT_ASYNC 0x5018
+#define RGA_FLUSH 0x5019
+#define RGA_GET_RESULT 0x501a
+#define RGA_GET_VERSION 0x501b
+#define RGA_CACHE_FLUSH 0x501c
+
+#define RGA2_GET_VERSION 0x601b
+#define RGA_IMPORT_DMA 0x601d
+#define RGA_RELEASE_DMA 0x601e
+
+#define RGA_TASK_NUM_MAX 50
+
+#define RGA_OUT_OF_RESOURCES -10
+#define RGA_MALLOC_ERROR -11
+
+#define SCALE_DOWN_LARGE 1
+#define SCALE_UP_LARGE 1
+
+#define RGA_BUFFER_POOL_SIZE_MAX 40
+
+#define RGA3_MAJOR_VERSION_MASK (0xF0000000)
+#define RGA3_MINOR_VERSION_MASK (0x0FF00000)
+#define RGA3_SVN_VERSION_MASK (0x000FFFFF)
+
+#define RGA2_MAJOR_VERSION_MASK (0xFF000000)
+#define RGA2_MINOR_VERSION_MASK (0x00F00000)
+#define RGA2_SVN_VERSION_MASK (0x000FFFFF)
+
+#define RGA_MODE_ROTATE_0 (1<<0)
+#define RGA_MODE_ROTATE_90 (1<<1)
+#define RGA_MODE_ROTATE_180 (1<<2)
+#define RGA_MODE_ROTATE_270 (1<<3)
+#define RGA_MODE_X_MIRROR (1<<4)
+#define RGA_MODE_Y_MIRROR (1<<5)
+
+#define RGA_MODE_CSC_BT601L (1<<0)
+#define RGA_MODE_CSC_BT601F (1<<1)
+#define RGA_MODE_CSC_BT709 (1<<2)
+#define RGA_MODE_CSC_BT2020 (1<<3)
+
+#define RGA_MODE_ROTATE_MASK (\
+ RGA_MODE_ROTATE_0 | \
+ RGA_MODE_ROTATE_90 | \
+ RGA_MODE_ROTATE_180 | \
+ RGA_MODE_ROTATE_270 | \
+ RGA_MODE_X_MIRROR | \
+ RGA_MODE_Y_MIRROR)
+
+enum rga_memory_type {
+ RGA_DMA_BUFFER = 0,
+ RGA_VIRTUAL_ADDRESS,
+ RGA_PHYSICAL_ADDRESS,
+ RGA_DMA_BUFFER_PTR,
+};
+
+enum rga_scale_up_mode {
+ RGA_SCALE_UP_NONE = 0x0,
+ RGA_SCALE_UP_BIC = 0x1,
+};
+
+enum rga_scale_down_mode {
+ RGA_SCALE_DOWN_NONE = 0x0,
+ RGA_SCALE_DOWN_AVG = 0x1,
+};
+
+enum RGA_SCHEDULER_CORE {
+ RGA_SCHEDULER_RGA3_CORE0 = 1 << 0,
+ RGA_SCHEDULER_RGA3_CORE1 = 1 << 1,
+ RGA_SCHEDULER_RGA2_CORE0 = 1 << 2,
+};
+
+/* RGA process mode enum */
+enum {
+ BITBLT_MODE = 0x0,
+ COLOR_PALETTE_MODE = 0x1,
+ COLOR_FILL_MODE = 0x2,
+ /* used by rga2 */
+ UPDATE_PALETTE_TABLE_MODE = 0x6,
+ UPDATE_PATTEN_BUF_MODE = 0x7,
+}; /*render mode*/
+
+/* RGA rd_mode */
+enum {
+ RGA_RASTER_MODE = 0x1 << 0,
+ RGA_FBC_MODE = 0x1 << 1,
+ RGA_TILE_MODE = 0x1 << 2,
+};
+
+enum {
+ RGA_10BIT_COMPACT = 0x0,
+ RGA_10BIT_INCOMPACT = 0x1,
+};
+
+enum {
+ RGA_CONTEXT_NONE = 0x0,
+ RGA_CONTEXT_SRC_FIX_ENABLE = 0x1 << 0,
+ RGA_CONTEXT_SRC_CACHE_INFO = 0x1 << 1,
+ RGA_CONTEXT_SRC_MASK = RGA_CONTEXT_SRC_FIX_ENABLE |
+ RGA_CONTEXT_SRC_CACHE_INFO,
+ RGA_CONTEXT_PAT_FIX_ENABLE = 0x1 << 2,
+ RGA_CONTEXT_PAT_CACHE_INFO = 0x1 << 3,
+ RGA_CONTEXT_PAT_MASK = RGA_CONTEXT_PAT_FIX_ENABLE |
+ RGA_CONTEXT_PAT_CACHE_INFO,
+ RGA_CONTEXT_DST_FIX_ENABLE = 0x1 << 4,
+ RGA_CONTEXT_DST_CACHE_INFO = 0x1 << 5,
+ RGA_CONTEXT_DST_MASK = RGA_CONTEXT_DST_FIX_ENABLE |
+ RGA_CONTEXT_DST_CACHE_INFO,
+};
+
+/* RGA feature */
+enum {
+ RGA_COLOR_FILL = 0x1 << 0,
+ RGA_COLOR_PALETTE = 0x1 << 1,
+ RGA_COLOR_KEY = 0x1 << 2,
+ RGA_ROP_CALCULATE = 0x1 << 3,
+ RGA_NN_QUANTIZE = 0x1 << 4,
+ RGA_OSD_BLEND = 0x1 << 5,
+ RGA_DITHER = 0x1 << 6,
+ RGA_MOSAIC = 0x1 << 7,
+ RGA_YIN_YOUT = 0x1 << 8,
+ RGA_YUV_HDS = 0x1 << 9,
+ RGA_YUV_VDS = 0x1 << 10,
+ RGA_OSD = 0x1 << 11,
+ RGA_PRE_INTR = 0x1 << 12,
+ RGA_FULL_CSC = 0x1 << 13,
+};
+
+enum rga_surf_format {
+ RGA_FORMAT_RGBA_8888 = 0x0,
+ RGA_FORMAT_RGBX_8888 = 0x1,
+ RGA_FORMAT_RGB_888 = 0x2,
+ RGA_FORMAT_BGRA_8888 = 0x3,
+ RGA_FORMAT_RGB_565 = 0x4,
+ RGA_FORMAT_RGBA_5551 = 0x5,
+ RGA_FORMAT_RGBA_4444 = 0x6,
+ RGA_FORMAT_BGR_888 = 0x7,
+
+ RGA_FORMAT_YCbCr_422_SP = 0x8,
+ RGA_FORMAT_YCbCr_422_P = 0x9,
+ RGA_FORMAT_YCbCr_420_SP = 0xa,
+ RGA_FORMAT_YCbCr_420_P = 0xb,
+
+ RGA_FORMAT_YCrCb_422_SP = 0xc,
+ RGA_FORMAT_YCrCb_422_P = 0xd,
+ RGA_FORMAT_YCrCb_420_SP = 0xe,
+ RGA_FORMAT_YCrCb_420_P = 0xf,
+
+ RGA_FORMAT_BPP1 = 0x10,
+ RGA_FORMAT_BPP2 = 0x11,
+ RGA_FORMAT_BPP4 = 0x12,
+ RGA_FORMAT_BPP8 = 0x13,
+
+ RGA_FORMAT_Y4 = 0x14,
+ RGA_FORMAT_YCbCr_400 = 0x15,
+
+ RGA_FORMAT_BGRX_8888 = 0x16,
+
+ RGA_FORMAT_YVYU_422 = 0x18,
+ RGA_FORMAT_YVYU_420 = 0x19,
+ RGA_FORMAT_VYUY_422 = 0x1a,
+ RGA_FORMAT_VYUY_420 = 0x1b,
+ RGA_FORMAT_YUYV_422 = 0x1c,
+ RGA_FORMAT_YUYV_420 = 0x1d,
+ RGA_FORMAT_UYVY_422 = 0x1e,
+ RGA_FORMAT_UYVY_420 = 0x1f,
+
+ RGA_FORMAT_YCbCr_420_SP_10B = 0x20,
+ RGA_FORMAT_YCrCb_420_SP_10B = 0x21,
+ RGA_FORMAT_YCbCr_422_SP_10B = 0x22,
+ RGA_FORMAT_YCrCb_422_SP_10B = 0x23,
+
+ RGA_FORMAT_BGR_565 = 0x24,
+ RGA_FORMAT_BGRA_5551 = 0x25,
+ RGA_FORMAT_BGRA_4444 = 0x26,
+
+ RGA_FORMAT_ARGB_8888 = 0x28,
+ RGA_FORMAT_XRGB_8888 = 0x29,
+ RGA_FORMAT_ARGB_5551 = 0x2a,
+ RGA_FORMAT_ARGB_4444 = 0x2b,
+ RGA_FORMAT_ABGR_8888 = 0x2c,
+ RGA_FORMAT_XBGR_8888 = 0x2d,
+ RGA_FORMAT_ABGR_5551 = 0x2e,
+ RGA_FORMAT_ABGR_4444 = 0x2f,
+
+ RGA_FORMAT_RGBA_2BPP = 0x30,
+
+ RGA_FORMAT_UNKNOWN = 0x100,
+};
+
+enum rga_alpha_mode {
+ RGA_ALPHA_STRAIGHT = 0,
+ RGA_ALPHA_INVERSE = 1,
+};
+
+enum rga_global_blend_mode {
+ RGA_ALPHA_GLOBAL = 0,
+ RGA_ALPHA_PER_PIXEL = 1,
+ RGA_ALPHA_PER_PIXEL_GLOBAL = 2,
+};
+
+enum rga_alpha_cal_mode {
+ RGA_ALPHA_SATURATION = 0,
+ RGA_ALPHA_NO_SATURATION = 1,
+};
+
+enum rga_factor_mode {
+ RGA_ALPHA_ZERO = 0,
+ RGA_ALPHA_ONE = 1,
+ /*
+ * When used as a factor for the SRC channel, it indicates
+ * the use of the DST channel's alpha value, and vice versa.
+ */
+ RGA_ALPHA_OPPOSITE = 2,
+ RGA_ALPHA_OPPOSITE_INVERSE = 3,
+ RGA_ALPHA_OWN = 4,
+};
+
+enum rga_color_mode {
+ RGA_ALPHA_PRE_MULTIPLIED = 0,
+ RGA_ALPHA_NO_PRE_MULTIPLIED = 1,
+};
+
+enum rga_alpha_blend_mode {
+ RGA_ALPHA_NONE = 0,
+ RGA_ALPHA_BLEND_SRC,
+ RGA_ALPHA_BLEND_DST,
+ RGA_ALPHA_BLEND_SRC_OVER,
+ RGA_ALPHA_BLEND_DST_OVER,
+ RGA_ALPHA_BLEND_SRC_IN,
+ RGA_ALPHA_BLEND_DST_IN,
+ RGA_ALPHA_BLEND_SRC_OUT,
+ RGA_ALPHA_BLEND_DST_OUT,
+ RGA_ALPHA_BLEND_SRC_ATOP,
+ RGA_ALPHA_BLEND_DST_ATOP,
+ RGA_ALPHA_BLEND_XOR,
+ RGA_ALPHA_BLEND_CLEAR,
+};
+
+#define RGA_SCHED_PRIORITY_DEFAULT 0
+#define RGA_SCHED_PRIORITY_MAX 6
+
+#define RGA_VERSION_SIZE 16
+#define RGA_HW_SIZE 5
+
+struct rga_version_t {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t revision;
+ uint8_t str[RGA_VERSION_SIZE];
+};
+
+struct rga_hw_versions_t {
+ struct rga_version_t version[RGA_HW_SIZE];
+ uint32_t size;
+};
+
+struct rga_memory_parm {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+
+ uint32_t size;
+};
+
+struct rga_external_buffer {
+ uint64_t memory;
+ uint32_t type;
+
+ uint32_t handle;
+ struct rga_memory_parm memory_parm;
+
+ uint8_t reserve[252];
+};
+
+struct rga_buffer_pool {
+ uint64_t buffers_ptr;
+ uint32_t size;
+};
+
+struct rga_mmu_info_t {
+ unsigned long src0_base_addr;
+ unsigned long src1_base_addr;
+ unsigned long dst_base_addr;
+ unsigned long els_base_addr;
+
+ /* [0] mmu enable [1] flush [2] prefetch_en [3] prefetch dir */
+ u8 src0_mmu_flag;
+ u8 src1_mmu_flag;
+ u8 dst_mmu_flag;
+ u8 els_mmu_flag;
+};
+
+struct rga_color_fill_t {
+ int16_t gr_x_a;
+ int16_t gr_y_a;
+ int16_t gr_x_b;
+ int16_t gr_y_b;
+ int16_t gr_x_g;
+ int16_t gr_y_g;
+ int16_t gr_x_r;
+ int16_t gr_y_r;
+};
+
+/***************************************/
+/* porting from rga.h for msg convert */
+/***************************************/
+
+struct rga_fading_t {
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+ uint8_t res;
+};
+
+struct rga_mmu_t {
+ uint8_t mmu_en;
+ uint64_t base_addr;
+ /*
+ * [0] mmu enable [1] src_flush [2] dst_flush
+ * [3] CMD_flush [4~5] page size
+ */
+ uint32_t mmu_flag;
+};
+
+struct rga_rect_t {
+ uint16_t xmin;
+ /* width - 1 */
+ uint16_t xmax;
+ uint16_t ymin;
+ /* height - 1 */
+ uint16_t ymax;
+};
+
+struct rga_point_t {
+ uint16_t x;
+ uint16_t y;
+};
+
+struct rga_line_draw_t {
+ /* LineDraw_start_point */
+ struct rga_point_t start_point;
+ /* LineDraw_end_point */
+ struct rga_point_t end_point;
+ /* LineDraw_color */
+ uint32_t color;
+ /* (enum) LineDrawing mode sel */
+ uint32_t flag;
+ /* range 1~16 */
+ uint32_t line_width;
+};
+
+/* color space convert coefficient. */
+struct rga_csc_coe {
+ int16_t r_v;
+ int16_t g_y;
+ int16_t b_u;
+ int32_t off;
+};
+
+struct rga_full_csc {
+ uint8_t flag;
+ struct rga_csc_coe coe_y;
+ struct rga_csc_coe coe_u;
+ struct rga_csc_coe coe_v;
+};
+
+struct rga_csc_range {
+ uint16_t max;
+ uint16_t min;
+};
+
+struct rga_csc_clip {
+ struct rga_csc_range y;
+ struct rga_csc_range uv;
+};
+
+struct rga_mosaic_info {
+ uint8_t enable;
+ uint8_t mode;
+};
+
+/* MAX(min, (max - channel_value)) */
+struct rga_osd_invert_factor {
+ uint8_t alpha_max;
+ uint8_t alpha_min;
+ uint8_t yg_max;
+ uint8_t yg_min;
+ uint8_t crb_max;
+ uint8_t crb_min;
+};
+
+struct rga_color {
+ union {
+ struct {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+ uint8_t alpha;
+ };
+ uint32_t value;
+ };
+};
+
+struct rga_osd_bpp2 {
+ uint8_t ac_swap; // ac swap flag
+ // 0: CA
+ // 1: AC
+ uint8_t endian_swap; // rgba2bpp endian swap
+ // 0: Big endian
+ // 1: Little endian
+ struct rga_color color0;
+ struct rga_color color1;
+};
+
+struct rga_osd_mode_ctrl {
+ uint8_t mode; // OSD cal mode:
+ // 0b'1: statistics mode
+ // 1b'1: auto inversion overlap mode
+ uint8_t direction_mode; // horizontal or vertical
+ // 0: horizontal
+ // 1: vertical
+ uint8_t width_mode; // using @fix_width or LUT width
+ // 0: fix width
+ // 1: LUT width
+ uint16_t block_fix_width; // OSD block fixed width
+ // real width = (fix_width + 1) * 2
+ uint8_t block_num; // OSD block num
+ uint16_t flags_index; // auto invert flags index
+
+ /* invertion config */
+ uint8_t color_mode; // selete color
+ // 0: src1 color
+ // 1: config data color
+ uint8_t invert_flags_mode; // invert flag selete
+ // 0: use RAM flag
+ // 1: usr last result
+ uint8_t default_color_sel; // default color mode
+ // 0: default is bright
+ // 1: default is dark
+ uint8_t invert_enable; // invert channel enable
+ // 1 << 0: alpha enable
+ // 1 << 1: Y/G disable
+ // 1 << 3: C/RB disable
+ uint8_t invert_mode; // invert cal mode
+ // 0: normal(max-data)
+ // 1: swap
+ uint8_t invert_thresh; // if luma > thresh, osd_flag to be 1
+ uint8_t unfix_index; // OSD width config index
+};
+
+struct rga_osd_info {
+ uint8_t enable;
+
+ struct rga_osd_mode_ctrl mode_ctrl;
+ struct rga_osd_invert_factor cal_factor;
+ struct rga_osd_bpp2 bpp2_info;
+
+ union {
+ struct {
+ uint32_t last_flags0;
+ uint32_t last_flags1;
+ };
+ uint64_t last_flags;
+ };
+
+ union {
+ struct {
+ uint32_t cur_flags0;
+ uint32_t cur_flags1;
+ };
+ uint64_t cur_flags;
+ };
+};
+
+struct rga_pre_intr_info {
+ uint8_t enable;
+
+ uint8_t read_intr_en;
+ uint8_t write_intr_en;
+ uint8_t read_hold_en;
+ uint32_t read_threshold;
+ uint32_t write_start;
+ uint32_t write_step;
+};
+
+struct rga_win_info_t {
+ /* yrgb mem addr */
+ unsigned long yrgb_addr;
+ /* cb/cr mem addr */
+ unsigned long uv_addr;
+ /* cr mem addr */
+ unsigned long v_addr;
+ /* definition by RK_FORMAT */
+ unsigned int format;
+
+ unsigned short src_act_w;
+ unsigned short src_act_h;
+
+ unsigned short dst_act_w;
+ unsigned short dst_act_h;
+
+ unsigned short x_offset;
+ unsigned short y_offset;
+
+ unsigned short vir_w;
+ unsigned short vir_h;
+
+ unsigned short y2r_mode;
+ unsigned short r2y_mode;
+
+ unsigned short rotate_mode;
+ /* RASTER or FBCD or TILE */
+ unsigned short rd_mode;
+
+ unsigned short is_10b_compact;
+ unsigned short is_10b_endian;
+
+ unsigned short enable;
+};
+
+struct rga_img_info_t {
+ /* yrgb mem addr */
+ uint64_t yrgb_addr;
+ /* cb/cr mem addr */
+ uint64_t uv_addr;
+ /* cr mem addr */
+ uint64_t v_addr;
+ /* definition by RK_FORMAT */
+ uint32_t format;
+
+ uint16_t act_w;
+ uint16_t act_h;
+ uint16_t x_offset;
+ uint16_t y_offset;
+
+ uint16_t vir_w;
+ uint16_t vir_h;
+
+ uint16_t endian_mode;
+ /* useless */
+ uint16_t alpha_swap;
+
+ /* used by RGA3 */
+ uint16_t rotate_mode;
+ uint16_t rd_mode;
+
+ uint16_t compact_mode;
+ uint16_t is_10b_endian;
+
+ uint16_t enable;
+};
+
+struct rga_feature {
+ uint32_t global_alpha_en:1;
+ uint32_t full_csc_clip_en:1;
+ uint32_t user_close_fence:1;
+};
+
+struct rga_req {
+ /* (enum) process mode sel */
+ uint8_t render_mode;
+
+ struct rga_img_info_t src;
+ struct rga_img_info_t dst;
+ struct rga_img_info_t pat;
+
+ /* rop4 mask addr */
+ uint64_t rop_mask_addr;
+ /* LUT addr */
+ uint64_t LUT_addr;
+
+ /* dst clip window default value is dst_vir */
+ /* value from [0, w-1] / [0, h-1]*/
+ struct rga_rect_t clip;
+
+ /* dst angle default value 0 16.16 scan from table */
+ int32_t sina;
+ /* dst angle default value 0 16.16 scan from table */
+ int32_t cosa;
+
+ /* alpha rop process flag */
+ /* ([0] = 1 alpha_rop_enable) */
+ /* ([1] = 1 rop enable) */
+ /* ([2] = 1 fading_enable) */
+ /* ([3] = 1 PD_enable) */
+ /* ([4] = 1 alpha cal_mode_sel) */
+ /* ([5] = 1 dither_enable) */
+ /* ([6] = 1 gradient fill mode sel) */
+ /* ([7] = 1 AA_enable) */
+ uint16_t alpha_rop_flag;
+
+ /* 0 nearst / 1 bilnear / 2 bicubic */
+ uint8_t scale_mode;
+
+ /* color key max */
+ uint32_t color_key_max;
+ /* color key min */
+ uint32_t color_key_min;
+
+ /* foreground color */
+ uint32_t fg_color;
+ /* background color */
+ uint32_t bg_color;
+
+ /* color fill use gradient */
+ struct rga_color_fill_t gr_color;
+
+ struct rga_line_draw_t line_draw_info;
+
+ struct rga_fading_t fading;
+
+ /* porter duff alpha mode sel */
+ uint8_t PD_mode;
+
+ /* legacy: global alpha value */
+ uint8_t alpha_global_value;
+
+ /* rop2/3/4 code scan from rop code table*/
+ uint16_t rop_code;
+
+ /* [2] 0 blur 1 sharp / [1:0] filter_type*/
+ uint8_t bsfilter_flag;
+
+ /* (enum) color palette 0/1bpp, 1/2bpp 2/4bpp 3/8bpp*/
+ uint8_t palette_mode;
+
+ /* (enum) BT.601 MPEG / BT.601 JPEG / BT.709 */
+ uint8_t yuv2rgb_mode;
+
+ /* 0/big endian 1/little endian*/
+ uint8_t endian_mode;
+
+ /* (enum) rotate mode */
+ /* 0x0, no rotate */
+ /* 0x1, rotate */
+ /* 0x2, x_mirror */
+ /* 0x3, y_mirror */
+ uint8_t rotate_mode;
+
+ /* 0 solid color / 1 pattern color */
+ uint8_t color_fill_mode;
+
+ /* mmu information */
+ struct rga_mmu_t mmu_info;
+
+ /* ([0~1] alpha mode) */
+ /* ([2~3] rop mode) */
+ /* ([4] zero mode en) */
+ /* ([5] dst alpha mode) */
+ /* ([6] alpha output mode sel) 0 src / 1 dst*/
+ uint8_t alpha_rop_mode;
+
+ uint8_t src_trans_mode;
+
+ uint8_t dither_mode;
+
+ /* full color space convert */
+ struct rga_full_csc full_csc;
+
+ int32_t in_fence_fd;
+ uint8_t core;
+ uint8_t priority;
+ int32_t out_fence_fd;
+
+ uint8_t handle_flag;
+
+ /* RGA2 1106 add */
+ struct rga_mosaic_info mosaic_info;
+
+ uint8_t uvhds_mode;
+ uint8_t uvvds_mode;
+
+ struct rga_osd_info osd_info;
+
+ struct rga_pre_intr_info pre_intr_info;
+
+ /* global alpha */
+ uint8_t fg_global_alpha;
+ uint8_t bg_global_alpha;
+
+ struct rga_feature feature;
+
+ struct rga_csc_clip full_csc_clip;
+
+ uint8_t reservr[43];
+};
+
+struct rga_alpha_config {
+ bool enable;
+ bool fg_pre_multiplied;
+ bool bg_pre_multiplied;
+ bool fg_pixel_alpha_en;
+ bool bg_pixel_alpha_en;
+ bool fg_global_alpha_en;
+ bool bg_global_alpha_en;
+ uint16_t fg_global_alpha_value;
+ uint16_t bg_global_alpha_value;
+ enum rga_alpha_blend_mode mode;
+};
+
+struct rga2_req {
+ /* (enum) process mode sel */
+ u8 render_mode;
+
+ /* active window */
+ struct rga_img_info_t src;
+ struct rga_img_info_t src1;
+ struct rga_img_info_t dst;
+ struct rga_img_info_t pat;
+
+ /* rop4 mask addr */
+ unsigned long rop_mask_addr;
+ /* LUT addr */
+ unsigned long LUT_addr;
+
+ u32 rop_mask_stride;
+
+ /* 0: SRC + DST => DST */
+ /* 1: SRC + SRC1 => DST */
+ u8 bitblt_mode;
+
+ /* [1:0] */
+ /* 0 degree 0x0 */
+ /* 90 degree 0x1 */
+ /* 180 degree 0x2 */
+ /* 270 degree 0x3 */
+ /* [5:4] */
+ /* none 0x0 */
+ /* x_mirror 0x1 */
+ /* y_mirror 0x2 */
+ /* x_mirror + y_mirror 0x3 */
+ u8 rotate_mode;
+
+ /* alpha rop process flag */
+ /* ([0] = 1 alpha_rop_enable) */
+ /* ([1] = 1 rop enable) */
+ /* ([2] = 1 fading_enable) */
+ /* ([3] = 1 alpha cal_mode_sel) */
+ /* ([4] = 1 src_dither_up_enable) */
+ /* ([5] = 1 dst_dither_up_enable) */
+ /* ([6] = 1 dither_down_enable) */
+ /* ([7] = 1 gradient fill mode sel) */
+ u16 alpha_rop_flag;
+
+ struct rga_alpha_config alpha_config;
+
+ /* 0 1 2 3 */
+ u8 scale_bicu_mode;
+
+ u32 color_key_max;
+ u32 color_key_min;
+
+ /* foreground color */
+ u32 fg_color;
+ /* background color */
+ u32 bg_color;
+
+ u8 color_fill_mode;
+ /* color fill use gradient */
+ struct rga_color_fill_t gr_color;
+
+ /* Fading value */
+ u8 fading_alpha_value;
+ u8 fading_r_value;
+ u8 fading_g_value;
+ u8 fading_b_value;
+
+ /* src global alpha value */
+ u8 src_a_global_val;
+ /* dst global alpha value */
+ u8 dst_a_global_val;
+
+ /* rop mode select 0 : rop2 1 : rop3 2 : rop4 */
+ u8 rop_mode;
+ /* rop2/3/4 code */
+ u16 rop_code;
+
+ /* (enum) color palette 0/1bpp, 1/2bpp 2/4bpp 3/8bpp*/
+ u8 palette_mode;
+
+ /* (enum) BT.601 MPEG / BT.601 JPEG / BT.709 */
+ u8 yuv2rgb_mode;
+
+ u8 full_csc_en;
+
+ /* 0/little endian 1/big endian */
+ u8 endian_mode;
+
+ u8 CMD_fin_int_enable;
+
+ /* mmu information */
+ struct rga_mmu_info_t mmu_info;
+
+ u8 alpha_zero_key;
+ u8 src_trans_mode;
+
+ /* useless */
+ u8 alpha_swp;
+ u8 dither_mode;
+
+ u8 rgb2yuv_mode;
+
+ /* RGA2 1106 add */
+ struct rga_mosaic_info mosaic_info;
+
+ uint8_t yin_yout_en;
+
+ uint8_t uvhds_mode;
+ uint8_t uvvds_mode;
+
+ struct rga_osd_info osd_info;
+};
+
+struct rga3_req {
+ /* (enum) process mode sel */
+ u8 render_mode;
+
+ struct rga_win_info_t win0;
+ struct rga_win_info_t wr;
+ struct rga_win_info_t win1;
+
+ /* rop4 mask addr */
+ unsigned long rop_mask_addr;
+ unsigned long LUT_addr;
+
+ u32 rop_mask_stride;
+
+ u8 bitblt_mode;
+ u8 rotate_mode;
+
+ u16 alpha_rop_flag;
+
+ struct rga_alpha_config alpha_config;
+
+ /* for abb mode presever alpha. */
+ bool abb_alpha_pass;
+
+ u8 scale_bicu_mode;
+
+ u32 color_key_max;
+ u32 color_key_min;
+
+ u32 fg_color;
+ u32 bg_color;
+
+ u8 color_fill_mode;
+ struct rga_color_fill_t gr_color;
+
+ u8 fading_alpha_value;
+ u8 fading_r_value;
+ u8 fading_g_value;
+ u8 fading_b_value;
+
+ /* win0 global alpha value */
+ u8 win0_a_global_val;
+ /* win1 global alpha value */
+ u8 win1_a_global_val;
+
+ u8 rop_mode;
+ u16 rop_code;
+
+ u8 palette_mode;
+
+ u8 yuv2rgb_mode;
+
+ u8 endian_mode;
+
+ u8 CMD_fin_int_enable;
+
+ struct rga_mmu_info_t mmu_info;
+
+ u8 alpha_zero_key;
+ u8 src_trans_mode;
+
+ u8 alpha_swp;
+ u8 dither_mode;
+
+ u8 rgb2yuv_mode;
+};
+
+struct rga_video_frame_info {
+ uint32_t x_offset;
+ uint32_t y_offset;
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t vir_w;
+ uint32_t vir_h;
+ uint32_t rd_mode;
+};
+
+struct rga_mpi_job_t {
+ struct dma_buf *dma_buf_src0;
+ struct dma_buf *dma_buf_src1;
+ struct dma_buf *dma_buf_dst;
+
+ struct rga_video_frame_info *src;
+ struct rga_video_frame_info *pat;
+ struct rga_video_frame_info *dst;
+ struct rga_video_frame_info *output;
+
+ int ctx_id;
+};
+
+struct rga_user_request {
+ uint64_t task_ptr;
+ uint32_t task_num;
+ uint32_t id;
+ uint32_t sync_mode;
+ uint32_t release_fence_fd;
+
+ uint32_t mpi_config_flags;
+
+ uint32_t acquire_fence_fd;
+
+ uint8_t reservr[120];
+};
+
+int rga_mpi_commit(struct rga_mpi_job_t *mpi_job);
+
+#endif /*_RGA_DRIVER_H_*/
diff --git a/drivers/video/rockchip/rga3/include/rga2_reg_info.h b/drivers/video/rockchip/rga3/include/rga2_reg_info.h
new file mode 100644
index 000000000..add2f41bd
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga2_reg_info.h
@@ -0,0 +1,477 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __REG2_INFO_H__
+#define __REG2_INFO_H__
+
+#include "rga_drv.h"
+
+#define RGA2_SYS_REG_BASE 0x000
+#define RGA2_CSC_REG_BASE 0x060
+#define RGA2_CMD_REG_BASE 0x100
+
+/* sys reg */
+#define RGA2_SYS_CTRL 0x000
+#define RGA2_CMD_CTRL 0x004
+#define RGA2_CMD_BASE 0x008
+#define RGA2_STATUS1 0x00c
+#define RGA2_INT 0x010
+#define RGA2_MMU_CTRL0 0x014
+#define RGA2_MMU_CMD_BASE 0x018
+#define RGA2_STATUS2 0x01c
+#define RGA2_VERSION_NUM 0x028
+#define RGA2_READ_LINE_CNT 0x030
+#define RGA2_WRITE_LINE_CNT 0x034
+#define RGA2_LINE_CNT 0x038
+#define RGA2_PERF_CTRL0 0x040
+
+/* full csc reg */
+#define RGA2_DST_CSC_00 0x060
+#define RGA2_DST_CSC_01 0x064
+#define RGA2_DST_CSC_02 0x068
+#define RGA2_DST_CSC_OFF0 0x06c
+#define RGA2_DST_CSC_10 0x070
+#define RGA2_DST_CSC_11 0x074
+#define RGA2_DST_CSC_12 0x078
+#define RGA2_DST_CSC_OFF1 0x07c
+#define RGA2_DST_CSC_20 0x080
+#define RGA2_DST_CSC_21 0x084
+#define RGA2_DST_CSC_22 0x088
+#define RGA2_DST_CSC_OFF2 0x08c
+
+/* osd read-back reg */
+#define RGA2_OSD_CUR_FLAGS0 0x090
+#define RGA2_OSD_CUR_FLAGS1 0x09c
+
+/* mode ctrl */
+#define RGA2_MODE_CTRL_OFFSET 0x000
+#define RGA2_SRC_INFO_OFFSET 0x004
+#define RGA2_SRC_BASE0_OFFSET 0x008
+#define RGA2_SRC_BASE1_OFFSET 0x00c
+#define RGA2_SRC_BASE2_OFFSET 0x010
+#define RGA2_SRC_BASE3_OFFSET 0x014
+#define RGA2_SRC_VIR_INFO_OFFSET 0x018
+#define RGA2_SRC_ACT_INFO_OFFSET 0x01c
+#define RGA2_SRC_X_FACTOR_OFFSET 0x020
+#define RGA2_OSD_CTRL0_OFFSET 0x020 // repeat
+#define RGA2_SRC_Y_FACTOR_OFFSET 0x024
+#define RGA2_OSD_CTRL1_OFFSET 0x024 // repeat
+#define RGA2_SRC_BG_COLOR_OFFSET 0x028
+#define RGA2_OSD_COLOR0_OFFSET 0x028 // repeat
+#define RGA2_SRC_FG_COLOR_OFFSET 0x02c
+#define RGA2_OSD_COLOR1_OFFSET 0x02c // repeat
+#define RGA2_SRC_TR_COLOR0_OFFSET 0x030
+#define RGA2_CF_GR_A_OFFSET 0x030 // repeat
+#define RGA2_OSD_LAST_FLAGS0_OFFSET 0x030 // repeat
+#define RGA2_MOSAIC_MODE_OFFSET 0x030 // repeat
+#define RGA2_SRC_TR_COLOR1_OFFSET 0x034
+#define RGA2_CF_GR_B_OFFSET 0x034 // repeat
+#define RGA2_OSD_LAST_FLAGS1_OFFSET 0x034 // repeat
+#define RGA2_DST_INFO_OFFSET 0x038
+#define RGA2_DST_BASE0_OFFSET 0x03c
+#define RGA2_DST_BASE1_OFFSET 0x040
+#define RGA2_DST_BASE2_OFFSET 0x044
+#define RGA2_DST_VIR_INFO_OFFSET 0x048
+#define RGA2_DST_ACT_INFO_OFFSET 0x04c
+#define RGA2_ALPHA_CTRL0_OFFSET 0x050
+#define RGA2_ALPHA_CTRL1_OFFSET 0x054
+#define RGA2_FADING_CTRL_OFFSET 0x058
+#define RGA2_PAT_CON_OFFSET 0x05c
+#define RGA2_ROP_CTRL0_OFFSET 0x060
+#define RGA2_CF_GR_G_OFFSET 0x060 // repeat
+#define RGA2_DST_Y4MAP_LUT0_OFFSET 0x060 // repeat
+#define RGA2_DST_QUANTIZE_SCALE_OFFSET 0x060 // repeat
+#define RGA2_OSD_INVERTSION_CAL0_OFFSET 0x060 // repeat
+#define RGA2_ROP_CTRL1_OFFSET 0x064
+#define RGA2_CF_GR_R_OFFSET 0x064 // repeat
+#define RGA2_DST_Y4MAP_LUT1_OFFSET 0x064 // repeat
+#define RGA2_DST_QUANTIZE_OFFSET_OFFSET 0x064 // repeat
+#define RGA2_OSD_INVERTSION_CAL1_OFFSET 0x064 // repeat
+#define RGA2_MASK_BASE_OFFSET 0x068
+#define RGA2_MMU_CTRL1_OFFSET 0x06c
+#define RGA2_MMU_SRC_BASE_OFFSET 0x070
+#define RGA2_MMU_SRC1_BASE_OFFSET 0x074
+#define RGA2_MMU_DST_BASE_OFFSET 0x078
+#define RGA2_MMU_ELS_BASE_OFFSET 0x07c
+
+/*RGA_SYS*/
+#define m_RGA2_SYS_CTRL_SRC0YUV420SP_RD_OPT_DIS (0x1 << 12)
+#define m_RGA2_SYS_CTRL_DST_WR_OPT_DIS (0x1 << 11)
+#define m_RGA2_SYS_CTRL_CMD_CONTINUE_P (0x1 << 10)
+#define m_RGA2_SYS_CTRL_HOLD_MODE_EN (0x1 << 9)
+#define m_RGA2_SYS_CTRL_RST_HANDSAVE_P (0x1 << 7)
+#define m_RGA2_SYS_CTRL_RST_PROTECT_P (0x1 << 6)
+#define m_RGA2_SYS_CTRL_AUTO_RST (0x1 << 5)
+#define m_RGA2_SYS_CTRL_CCLK_SRESET_P (0x1 << 4)
+#define m_RGA2_SYS_CTRL_ACLK_SRESET_P (0x1 << 3)
+#define m_RGA2_SYS_CTRL_AUTO_CKG (0x1 << 2)
+#define m_RGA2_SYS_CTRL_CMD_MODE (0x1 << 1)
+#define m_RGA2_SYS_CTRL_CMD_OP_ST_P (0x1 << 0)
+
+#define s_RGA2_SYS_CTRL_CMD_CONTINUE(x) ((x & 0x1) << 10)
+#define s_RGA2_SYS_CTRL_HOLD_MODE_EN(x) ((x & 0x1) << 9)
+#define s_RGA2_SYS_CTRL_CMD_MODE(x) ((x & 0x1) << 1)
+
+/* RGA_CMD_CTRL */
+#define m_RGA2_CMD_CTRL_INCR_NUM (0x3ff << 3)
+#define m_RGA2_CMD_CTRL_STOP (0x1 << 2)
+#define m_RGA2_CMD_CTRL_INCR_VALID_P (0x1 << 1)
+#define m_RGA2_CMD_CTRL_CMD_LINE_ST_P (0x1 << 0)
+
+/* RGA_STATUS1 */
+#define m_RGA2_STATUS1_SW_CMD_TOTAL_NUM (0xfff << 8)
+#define m_RGA2_STATUS1_SW_CMD_CUR_NUM (0xfff << 8)
+#define m_RGA2_STATUS1_SW_RGA_STA (0x1 << 0)
+
+/*RGA_INT*/
+#define m_RGA2_INT_LINE_WR_CLEAR (1 << 16)
+#define m_RGA2_INT_LINE_RD_CLEAR (1 << 15)
+#define m_RGA2_INT_LINE_WR_EN (1 << 14)
+#define m_RGA2_INT_LINE_RD_EN (1 << 13)
+#define m_RGA2_INT_WRITE_CNT_FLAG (1 << 12)
+#define m_RGA2_INT_READ_CNT_FLAG (1 << 11)
+#define m_RGA2_INT_ALL_CMD_DONE_INT_EN (1 << 10)
+#define m_RGA2_INT_MMU_INT_EN (1 << 9)
+#define m_RGA2_INT_ERROR_INT_EN (1 << 8)
+#define m_RGA2_INT_NOW_CMD_DONE_INT_CLEAR (1 << 7)
+#define m_RGA2_INT_ALL_CMD_DONE_INT_CLEAR (1 << 6)
+#define m_RGA2_INT_MMU_INT_CLEAR (1 << 5)
+#define m_RGA2_INT_ERROR_INT_CLEAR (1 << 4)
+#define m_RGA2_INT_CUR_CMD_DONE_INT_FLAG (1 << 3)
+#define m_RGA2_INT_ALL_CMD_DONE_INT_FLAG (1 << 2)
+#define m_RGA2_INT_MMU_INT_FLAG (1 << 1)
+#define m_RGA2_INT_ERROR_INT_FLAG (1 << 0)
+
+#define m_RGA2_INT_ERROR_FLAG_MASK \
+ ( \
+ m_RGA2_INT_MMU_INT_FLAG | \
+ m_RGA2_INT_ERROR_INT_FLAG \
+ )
+#define m_RGA2_INT_ERROR_CLEAR_MASK \
+ ( \
+ m_RGA2_INT_MMU_INT_CLEAR | \
+ m_RGA2_INT_ERROR_INT_CLEAR \
+)
+#define m_RGA2_INT_ERROR_ENABLE_MASK \
+ ( \
+ m_RGA2_INT_MMU_INT_EN | \
+ m_RGA2_INT_ERROR_INT_EN \
+ )
+
+#define s_RGA2_INT_LINE_WR_CLEAR(x) ((x & 0x1) << 16)
+#define s_RGA2_INT_LINE_RD_CLEAR(x) ((x & 0x1) << 15)
+#define s_RGA2_INT_LINE_WR_EN(x) ((x & 0x1) << 14)
+#define s_RGA2_INT_LINE_RD_EN(x) ((x & 0x1) << 13)
+#define s_RGA2_INT_ALL_CMD_DONE_INT_EN(x) ((x & 0x1) << 10)
+#define s_RGA2_INT_MMU_INT_EN(x) ((x & 0x1) << 9)
+#define s_RGA2_INT_ERROR_INT_EN(x) ((x & 0x1) << 8)
+#define s_RGA2_INT_NOW_CMD_DONE_INT_CLEAR(x) ((x & 0x1) << 7)
+#define s_RGA2_INT_ALL_CMD_DONE_INT_CLEAR(x) ((x & 0x1) << 6)
+#define s_RGA2_INT_MMU_INT_CLEAR(x) ((x & 0x1) << 5)
+#define s_RGA2_INT_ERROR_INT_CLEAR(x) ((x & 0x1) << 4)
+
+/* RGA_STATUS2 hardware status */
+#define m_RGA2_STATUS2_RPP_MKRAM_RREADY (0x2 << 11)
+#define m_RGA2_STATUS2_DSTRPP_OUTBUF_RREADY (0x1f << 6)
+#define m_RGA2_STATUS2_SRCRPP_OUTBUF_RREADY (0xf << 2)
+#define m_RGA2_STATUS2_BUS_ERROR (0x1 << 1)
+#define m_RGA2_STATUS2_RPP_ERROR (0x1 << 0)
+
+/* RGA_READ_LINE_CNT_TH */
+#define m_RGA2_READ_LINE_SW_INTR_LINE_RD_TH (0x1fff << 0)
+
+#define s_RGA2_READ_LINE_SW_INTR_LINE_RD_TH(x) ((x & 0x1fff) << 0)
+
+/* RGA_WRITE_LINE_CNT_TN */
+#define m_RGA2_WRITE_LINE_SW_INTR_LINE_WR_START (0x1fff << 0)
+#define m_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP (0x1fff << 16)
+
+#define s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_START(x) ((x & 0x1fff) << 0)
+#define s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP(x) ((x & 0x1fff) << 16)
+
+/* RGA_MODE_CTRL */
+#define m_RGA2_MODE_CTRL_SW_RENDER_MODE (0x7 << 0)
+#define m_RGA2_MODE_CTRL_SW_BITBLT_MODE (0x1 << 3)
+#define m_RGA2_MODE_CTRL_SW_CF_ROP4_PAT (0x1 << 4)
+#define m_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET (0x1 << 5)
+#define m_RGA2_MODE_CTRL_SW_GRADIENT_SAT (0x1 << 6)
+#define m_RGA2_MODE_CTRL_SW_INTR_CF_E (0x1 << 7)
+#define m_RGA2_MODE_CTRL_SW_OSD_E (0x1<<8)
+#define m_RGA2_MODE_CTRL_SW_MOSAIC_EN (0x1<<9)
+#define m_RGA2_MODE_CTRL_SW_YIN_YOUT_EN (0x1<<10)
+
+#define s_RGA2_MODE_CTRL_SW_RENDER_MODE(x) ((x & 0x7) << 0)
+#define s_RGA2_MODE_CTRL_SW_BITBLT_MODE(x) ((x & 0x1) << 3)
+#define s_RGA2_MODE_CTRL_SW_CF_ROP4_PAT(x) ((x & 0x1) << 4)
+#define s_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET(x) ((x & 0x1) << 5)
+#define s_RGA2_MODE_CTRL_SW_GRADIENT_SAT(x) ((x & 0x1) << 6)
+#define s_RGA2_MODE_CTRL_SW_INTR_CF_E(x) ((x & 0x1) << 7)
+#define s_RGA2_MODE_CTRL_SW_OSD_E(x) ((x & 0x1) << 8)
+#define s_RGA2_MODE_CTRL_SW_MOSAIC_EN(x) ((x & 0x1) << 9)
+#define s_RGA2_MODE_CTRL_SW_YIN_YOUT_EN(x) ((x & 0x1) << 10)
+/* RGA_SRC_INFO */
+#define m_RGA2_SRC_INFO_SW_SRC_FMT (0xf << 0)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP (0x1 << 4)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP (0x1 << 5)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP (0x1 << 6)
+#define m_RGA2_SRC_INFO_SW_SW_CP_ENDIAN (0x1 << 7)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE (0x3 << 8)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE (0x3 << 10)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE (0x3 << 12)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE (0x3 << 14)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE (0x3 << 16)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE (0x1 << 18)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E (0xf << 19)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E (0x1 << 23)
+#define m_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER (0x3 << 24)
+#define m_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL (0x1 << 26)
+#define m_RGA2_SRC_INFO_SW_SW_YUV10_E (0x1 << 27)
+#define m_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E (0x1 << 28)
+
+
+#define s_RGA2_SRC_INFO_SW_SRC_FMT(x) ((x & 0xf) << 0)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP(x) ((x & 0x1) << 4)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP(x) ((x & 0x1) << 5)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP(x) ((x & 0x1) << 6)
+#define s_RGA2_SRC_INFO_SW_SW_CP_ENDAIN(x) ((x & 0x1) << 7)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE(x) ((x & 0x3) << 8)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE(x) ((x & 0x3) << 10)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE(x) ((x & 0x3) << 12)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE(x) ((x & 0x3) << 14)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE(x) ((x & 0x3) << 16)
+
+#define s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE(x) ((x & 0x1) << 18)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E(x) ((x & 0xf) << 19)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E(x) ((x & 0x1) << 23)
+#define s_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER(x) ((x & 0x3) << 24)
+#define s_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL(x) ((x & 0x1) << 26)
+#define s_RGA2_SRC_INFO_SW_SW_YUV10_E(x) ((x & 0x1) << 27)
+#define s_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E(x) ((x & 0x1) << 28)
+
+/* RGA_SRC_VIR_INFO */
+#define m_RGA2_SRC_VIR_INFO_SW_SRC_VIR_STRIDE (0x7fff << 0)
+#define m_RGA2_SRC_VIR_INFO_SW_MASK_VIR_STRIDE (0x3ff << 16)
+
+#define s_RGA2_SRC_VIR_INFO_SW_SRC_VIR_STRIDE(x) ((x & 0x7fff) << 0)
+#define s_RGA2_SRC_VIR_INFO_SW_MASK_VIR_STRIDE(x) ((x & 0x3ff) << 16)
+
+
+/* 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 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)
+
+/* RGA2_OSD_CTRL0 */
+#define m_RGA2_OSD_CTRL0_SW_OSD_MODE (0x3 << 0)
+#define m_RGA2_OSD_CTRL0_SW_OSD_VER_MODE (0x1 << 2)
+#define m_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE (0x1 << 3)
+#define m_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM (0x1f << 4)
+#define m_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX (0x3f << 10)
+#define m_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH (0x3f << 20)
+#define m_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE (0x1 << 30)
+
+#define s_RGA2_OSD_CTRL0_SW_OSD_MODE(x) ((x & 0x3) << 0)
+#define s_RGA2_OSD_CTRL0_SW_OSD_VER_MODE(x) ((x & 0x1) << 2)
+#define s_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE(x) ((x & 0x1) << 3)
+#define s_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM(x) ((x & 0x1f) << 4)
+#define s_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX(x) ((x & 0x3ff) << 10)
+#define s_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH(x) ((x & 0x3ff) << 20)
+#define s_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE(x) ((x & 0x1) << 30)
+
+/* RGA2_OSD_CTRL1 */
+#define m_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL (0x1 << 0)
+#define m_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL (0x1 << 1)
+#define m_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR (0x1 << 2)
+#define m_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE (0x1 << 3)
+#define m_RGA2_OSD_CTRL1_SW_OSD_THRESH (0xff << 4)
+#define m_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN (0x1 << 12)
+#define m_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS (0x1 << 13)
+#define m_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS (0x1 << 14)
+#define m_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX (0xf << 16)
+
+#define s_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL(x) ((x & 0x1) << 0)
+#define s_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL(x) ((x & 0x1) << 1)
+#define s_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR(x) ((x & 0x1) << 2)
+#define s_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE(x) ((x & 0x1) << 3)
+#define s_RGA2_OSD_CTRL1_SW_OSD_THRESH(x) ((x & 0xff) << 4)
+#define s_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN(x) ((x & 0x1) << 12)
+#define s_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS(x) ((x & 0x1) << 13)
+#define s_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS(x) ((x & 0x1) << 14)
+#define s_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX(x) ((x & 0xf) << 16)
+
+/* RGA_DST_INFO */
+#define m_RGA2_DST_INFO_SW_DST_FMT (0xf << 0)
+#define m_RGA2_DST_INFO_SW_DST_RB_SWAP (0x1 << 4)
+#define m_RGA2_DST_INFO_SW_ALPHA_SWAP (0x1 << 5)
+#define m_RGA2_DST_INFO_SW_DST_UV_SWAP (0x1 << 6)
+#define m_RGA2_DST_INFO_SW_SRC1_FMT (0x7 << 7)
+#define m_RGA2_DST_INFO_SW_SRC1_RB_SWP (0x1 << 10)
+#define m_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP (0x1 << 11)
+#define m_RGA2_DST_INFO_SW_DITHER_UP_E (0x1 << 12)
+#define m_RGA2_DST_INFO_SW_DITHER_DOWN_E (0x1 << 13)
+#define m_RGA2_DST_INFO_SW_DITHER_MODE (0x3 << 14)
+#define m_RGA2_DST_INFO_SW_DST_CSC_MODE (0x3 << 16)
+#define m_RGA2_DST_INFO_SW_CSC_CLIP_MODE (0x1 << 18)
+#define m_RGA2_DST_INFO_SW_DST_CSC_MODE_2 (0x1 << 19)
+#define m_RGA2_DST_INFO_SW_SRC1_CSC_MODE (0x3 << 20)
+#define m_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE (0x1 << 22)
+#define m_RGA2_DST_INFO_SW_DST_UVHDS_MODE (0x1 << 23)
+#define m_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN (0x1 << 24)
+#define m_RGA2_DST_INFO_SW_DST_FMT_Y4_EN (0x1 << 25)
+#define m_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN (0x1 << 26)
+#define m_RGA2_DST_INFO_SW_DST_UVVDS_MODE (0x1 << 27)
+
+#define s_RGA2_DST_INFO_SW_DST_FMT(x) ((x & 0xf) << 0)
+#define s_RGA2_DST_INFO_SW_DST_RB_SWAP(x) ((x & 0x1) << 4)
+#define s_RGA2_DST_INFO_SW_ALPHA_SWAP(x) ((x & 0x1) << 5)
+#define s_RGA2_DST_INFO_SW_DST_UV_SWAP(x) ((x & 0x1) << 6)
+#define s_RGA2_DST_INFO_SW_SRC1_FMT(x) ((x & 0x7) << 7)
+#define s_RGA2_DST_INFO_SW_SRC1_RB_SWP(x) ((x & 0x1) << 10)
+#define s_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP(x) ((x & 0x1) << 11)
+#define s_RGA2_DST_INFO_SW_DITHER_UP_E(x) ((x & 0x1) << 12)
+#define s_RGA2_DST_INFO_SW_DITHER_DOWN_E(x) ((x & 0x1) << 13)
+#define s_RGA2_DST_INFO_SW_DITHER_MODE(x) ((x & 0x3) << 14)
+#define s_RGA2_DST_INFO_SW_DST_CSC_MODE(x) ((x & 0x3) << 16)
+#define s_RGA2_DST_INFO_SW_CSC_CLIP_MODE(x) ((x & 0x1) << 18)
+#define s_RGA2_DST_INFO_SW_DST_CSC_MODE_2(x) ((x & 0x1) << 19)
+#define s_RGA2_DST_INFO_SW_SRC1_CSC_MODE(x) ((x & 0x3) << 20)
+#define s_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE(x) ((x & 0x1) << 22)
+#define s_RGA2_DST_INFO_SW_DST_UVHDS_MODE(x) ((x & 0x1) << 23)
+#define s_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN(x) ((x & 0x1) << 24)
+#define s_RGA2_DST_INFO_SW_DST_FMT_Y4_EN(x) ((x & 0x1) << 25)
+#define s_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN(x) ((x & 0x1) << 26)
+#define s_RGA2_DST_INFO_SW_DST_UVVDS_MODE(x) ((x & 0x1) << 27)
+
+
+/* RGA_ALPHA_CTRL0 */
+#define m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0 (0x1 << 0)
+#define m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL (0x1 << 1)
+#define m_RGA2_ALPHA_CTRL0_SW_ROP_MODE (0x3 << 2)
+#define m_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA (0xff << 4)
+#define m_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA (0xff << 12)
+#define m_RGA2_ALPHA_CTRLO_SW_MASK_ENDIAN (0x1 << 20)
+
+#define s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0(x) ((x & 0x1) << 0)
+#define s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL(x) ((x & 0x1) << 1)
+#define s_RGA2_ALPHA_CTRL0_SW_ROP_MODE(x) ((x & 0x3) << 2)
+#define s_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA(x) ((x & 0xff) << 4)
+#define s_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA(x) ((x & 0xff) << 12)
+#define s_RGA2_ALPHA_CTRLO_SW_MASK_ENDIAN(x) ((x & 0x1) << 20)
+
+
+
+/* RGA_ALPHA_CTRL1 */
+#define m_RGA2_ALPHA_CTRL1_SW_DST_COLOR_M0 (0x1 << 0)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_COLOR_M0 (0x1 << 1)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M0 (0x7 << 2)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M0 (0x7 << 5)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M0 (0x1 << 8)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M0 (0x1 << 9)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M0 (0x3 << 10)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M0 (0x3 << 12)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M0 (0x1 << 14)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M0 (0x1 << 15)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M1 (0x7 << 16)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M1 (0x7 << 19)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M1 (0x1 << 22)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M1 (0x1 << 23)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M1 (0x3 << 24)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M1 (0x3 << 26)
+#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M1 (0x1 << 28)
+#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M1 (0x1 << 29)
+
+#define s_RGA2_ALPHA_CTRL1_SW_DST_COLOR_M0(x) ((x & 0x1) << 0)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_COLOR_M0(x) ((x & 0x1) << 1)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M0(x) ((x & 0x7) << 2)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M0(x) ((x & 0x7) << 5)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M0(x) ((x & 0x1) << 8)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M0(x) ((x & 0x1) << 9)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M0(x) ((x & 0x3) << 10)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M0(x) ((x & 0x3) << 12)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M0(x) ((x & 0x1) << 14)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M0(x) ((x & 0x1) << 15)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M1(x) ((x & 0x7) << 16)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M1(x) ((x & 0x7) << 19)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M1(x) ((x & 0x1) << 22)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M1(x) ((x & 0x1) << 23)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M1(x) ((x & 0x3) << 24)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M1(x) ((x & 0x3) << 26)
+#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M1(x) ((x & 0x1) << 28)
+#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M1(x) ((x & 0x1) << 29)
+
+
+
+/* RGA_MMU_CTRL1 */
+#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_EN (0x1 << 0)
+#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_FLUSH (0x1 << 1)
+#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_EN (0x1 << 2)
+#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_DIR (0x1 << 3)
+#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_EN (0x1 << 4)
+#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_FLUSH (0x1 << 5)
+#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_EN (0x1 << 6)
+#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_DIR (0x1 << 7)
+#define m_RGA2_MMU_CTRL1_SW_DST_MMU_EN (0x1 << 8)
+#define m_RGA2_MMU_CTRL1_SW_DST_MMU_FLUSH (0x1 << 9)
+#define m_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_EN (0x1 << 10)
+#define m_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_DIR (0x1 << 11)
+#define m_RGA2_MMU_CTRL1_SW_ELS_MMU_EN (0x1 << 12)
+#define m_RGA2_MMU_CTRL1_SW_ELS_MMU_FLUSH (0x1 << 13)
+
+#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_EN(x) ((x & 0x1) << 0)
+#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_FLUSH(x) ((x & 0x1) << 1)
+#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_EN(x) ((x & 0x1) << 2)
+#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_DIR(x) ((x & 0x1) << 3)
+#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_EN(x) ((x & 0x1) << 4)
+#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_FLUSH(x) ((x & 0x1) << 5)
+#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_EN(x) ((x & 0x1) << 6)
+#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_DIR(x) ((x & 0x1) << 7)
+#define s_RGA2_MMU_CTRL1_SW_DST_MMU_EN(x) ((x & 0x1) << 8)
+#define s_RGA2_MMU_CTRL1_SW_DST_MMU_FLUSH(x) ((x & 0x1) << 9)
+#define s_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_EN(x) ((x & 0x1) << 10)
+#define s_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_DIR(x) ((x & 0x1) << 11)
+#define s_RGA2_MMU_CTRL1_SW_ELS_MMU_EN(x) ((x & 0x1) << 12)
+#define s_RGA2_MMU_CTRL1_SW_ELS_MMU_FLUSH(x) ((x & 0x1) << 13)
+
+#define RGA2_VSP_BICUBIC_LIMIT 1996
+
+union rga2_color_ctrl {
+ uint32_t value;
+ struct {
+ uint32_t dst_color_mode:1;
+ uint32_t src_color_mode:1;
+
+ uint32_t dst_factor_mode:3;
+ uint32_t src_factor_mode:3;
+
+ uint32_t dst_alpha_cal_mode:1;
+ uint32_t src_alpha_cal_mode:1;
+
+ uint32_t dst_blend_mode:2;
+ uint32_t src_blend_mode:2;
+
+ uint32_t dst_alpha_mode:1;
+ uint32_t src_alpha_mode:1;
+ } bits;
+};
+
+union rga2_alpha_ctrl {
+ uint32_t value;
+ struct {
+ uint32_t dst_factor_mode:3;
+ uint32_t src_factor_mode:3;
+
+ uint32_t dst_alpha_cal_mode:1;
+ uint32_t src_alpha_cal_mode:1;
+
+ uint32_t dst_blend_mode:2;
+ uint32_t src_blend_mode:2;
+
+ uint32_t dst_alpha_mode:1;
+ uint32_t src_alpha_mode:1;
+ } bits;
+};
+
+extern const struct rga_backend_ops rga2_ops;
+
+#endif
+
diff --git a/drivers/video/rockchip/rga3/include/rga3_reg_info.h b/drivers/video/rockchip/rga3/include/rga3_reg_info.h
new file mode 100644
index 000000000..4db80cfb0
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga3_reg_info.h
@@ -0,0 +1,521 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __REG3_INFO_H__
+#define __REG3_INFO_H__
+
+#include "rga_drv.h"
+
+/* sys reg */
+#define RGA3_SYS_CTRL 0x000
+#define RGA3_CMD_CTRL 0x004
+#define RGA3_CMD_ADDR 0x008
+#define RGA3_MI_GROUP_CTRL 0x00c
+#define RGA3_ARQOS_CTRL 0x010
+#define RGA3_VERSION_NUM 0x018
+#define RGA3_VERSION_TIM 0x01c
+#define RGA3_INT_EN 0x020
+#define RGA3_INT_RAW 0x024
+#define RGA3_INT_MSK 0x028
+#define RGA3_INT_CLR 0x02c
+#define RGA3_RO_SRST 0x030
+#define RGA3_STATUS0 0x034
+#define RGA3_SCAN_CNT 0x038
+#define RGA3_CMD_STATE 0x040
+
+/* cmd reg */
+#define RGA3_WIN0_RD_CTRL_OFFSET 0x000
+#define RGA3_WIN0_Y_BASE_OFFSET 0x010
+#define RGA3_WIN0_U_BASE_OFFSET 0x014
+#define RGA3_WIN0_V_BASE_OFFSET 0x018
+#define RGA3_WIN0_VIR_STRIDE_OFFSET 0x01c
+#define RGA3_WIN0_FBC_OFF_OFFSET 0x020
+#define RGA3_WIN0_SRC_SIZE_OFFSET 0x024
+#define RGA3_WIN0_ACT_OFF_OFFSET 0x028
+#define RGA3_WIN0_ACT_SIZE_OFFSET 0x02c
+#define RGA3_WIN0_DST_SIZE_OFFSET 0x030
+#define RGA3_WIN0_SCL_FAC_OFFSET 0x034
+#define RGA3_WIN0_UV_VIR_STRIDE_OFFSET 0x038
+#define RGA3_WIN1_RD_CTRL_OFFSET 0x040
+#define RGA3_WIN1_Y_BASE_OFFSET 0x050
+#define RGA3_WIN1_U_BASE_OFFSET 0x054
+#define RGA3_WIN1_V_BASE_OFFSET 0x058
+#define RGA3_WIN1_VIR_STRIDE_OFFSET 0x05c
+#define RGA3_WIN1_FBC_OFF_OFFSET 0x060
+#define RGA3_WIN1_SRC_SIZE_OFFSET 0x064
+#define RGA3_WIN1_ACT_OFF_OFFSET 0x068
+#define RGA3_WIN1_ACT_SIZE_OFFSET 0x06c
+#define RGA3_WIN1_DST_SIZE_OFFSET 0x070
+#define RGA3_WIN1_SCL_FAC_OFFSET 0x074
+#define RGA3_WIN1_UV_VIR_STRIDE_OFFSET 0x078
+#define RGA3_OVLP_CTRL_OFFSET 0x080
+#define RGA3_OVLP_OFF_OFFSET 0x084
+#define RGA3_OVLP_TOP_KEY_MIN_OFFSET 0x088
+#define RGA3_OVLP_TOP_KEY_MAX_OFFSET 0x08c
+#define RGA3_OVLP_TOP_CTRL_OFFSET 0x090
+#define RGA3_OVLP_BOT_CTRL_OFFSET 0x094
+#define RGA3_OVLP_TOP_ALPHA_OFFSET 0x098
+#define RGA3_OVLP_BOT_ALPHA_OFFSET 0x09c
+#define RGA3_WR_CTRL_OFFSET 0x0a0
+#define RGA3_WR_FBCE_CTRL_OFFSET 0x0a4
+#define RGA3_WR_VIR_STRIDE_OFFSET 0x0a8
+#define RGA3_WR_PL_VIR_STRIDE_OFFSET 0x0ac
+#define RGA3_WR_Y_BASE_OFFSET 0x0b0
+#define RGA3_WR_U_BASE_OFFSET 0x0b4
+#define RGA3_WR_V_BASE_OFFSET 0x0b8
+
+/* RGA3_SYS_CTRL */
+#define m_RGA3_SYS_CTRL_FRMEND_AUTO_RSTN_EN (0x1 << 11)
+#define m_RGA3_SYS_CTRL_RGA_BIC_MODE (0x3 << 9)
+#define m_RGA3_SYS_CTRL_RGA_RAM_CLK_ON (0x1 << 8)
+#define m_RGA3_SYS_CTRL_CCLK_SRESET (0x1 << 4)
+#define m_RGA3_SYS_CTRL_ACLK_SRESET (0x1 << 3)
+#define m_RGA3_SYS_CTRL_RGA_LGC_CLK_ON (0x1 << 2)
+#define m_RGA3_SYS_CTRL_CMD_MODE (0x1 << 1)
+#define m_RGA3_SYS_CTRL_RGA_SART (0x1 << 0)
+
+#define s_RGA3_SYS_CTRL_RGA_BIC_MODE(x) ((x & 0x3) << 9)
+#define s_RGA3_SYS_CTRL_CCLK_SRESET(x) ((x & 0x1) << 4)
+#define s_RGA3_SYS_CTRL_ACLK_SRESET(x) ((x & 0x1) << 3)
+#define s_RGA3_SYS_CTRL_CMD_MODE(x) ((x & 0x1) << 1)
+
+/* TODO: RGA3_INT_EN/RGA3_INT_RAW/RGA3_INT_MSK/RGA3_INT_CLR */
+#define m_RGA3_INT_WIN1_VOR_FIFO_REN_ERR (0x1 << 29)
+#define m_RGA3_INT_WIN1_VOR_FIFO_WEN_ERR (0x1 << 28)
+#define m_RGA3_INT_WIN1_HOR_FIFO_REN_ERR (0x1 << 27)
+#define m_RGA3_INT_WIN1_HOR_FIFO_WEN_ERR (0x1 << 26)
+#define m_RGA3_INT_WIN1_IN_FIFO_REB_ERR (0x1 << 25)
+#define m_RGA3_INT_WIN1_IN_FIFO_WEN_ERR (0x1 << 24)
+#define m_RGA3_INT_WIN0_VOR_FIFO_REN_ERR (0x1 << 21)
+#define m_RGA3_INT_WIN0_VOR_FIFO_WEN_ERR (0x1 << 20)
+#define m_RGA3_INT_WIN0_HOR_FIFO_REN_ERR (0x1 << 19)
+#define m_RGA3_INT_WIN0_HOR_FIFO_WEN_ERR (0x1 << 18)
+#define m_RGA3_INT_WIN0_IN_FIFO_REB_ERR (0x1 << 17)
+#define m_RGA3_INT_WIN0_IN_FIFO_WEN_ERR (0x1 << 16)
+#define m_RGA3_INT_RGA_MI_WR_BUS_ERR (0x1 << 15)
+#define m_RGA3_INT_RGA_MI_WR_IN_HERR (0x1 << 14)
+//The signal is invalid, it will be pulled up every time, no need to care.
+// #define m_RGA3_INT_RGA_MI_WR_IN_VERR (0x1 << 13)
+#define m_RGA3_INT_WIN1_V_ERR (0x1 << 11)
+#define m_RGA3_INT_WIN1_H_ERR (0x1 << 10)
+#define m_RGA3_INT_WIN1_FBCD_DEC_ERR (0x1 << 9)
+#define m_RGA3_INT_WIN1_RD_FRM_END (0x1 << 8) //not error
+#define m_RGA3_INT_WIN0_V_ERR (0x1 << 7)
+#define m_RGA3_INT_WIN0_H_ERR (0x1 << 6)
+#define m_RGA3_INT_WIN0_FBCD_DEC_ERR (0x1 << 5)
+#define m_RGA3_INT_WIN0_RD_FRM_END (0x1 << 4) //not error
+#define m_RGA3_INT_CMD_LINE_FINISH (0x1 << 3) //not error
+#define m_RGA3_INT_RAG_MI_RD_BUS_ERR (0x1 << 2)
+#define m_RGA3_INT_RGA_MMU_INTR (0x1 << 1)
+#define m_RGA3_INT_FRM_DONE (0x1 << 0) //not error
+
+#define m_RGA3_INT_ERROR_MASK \
+ ( \
+ m_RGA3_INT_RGA_MMU_INTR | \
+ m_RGA3_INT_RAG_MI_RD_BUS_ERR | \
+ m_RGA3_INT_WIN0_FBCD_DEC_ERR | \
+ m_RGA3_INT_WIN0_H_ERR | \
+ m_RGA3_INT_WIN0_V_ERR | \
+ m_RGA3_INT_WIN1_FBCD_DEC_ERR | \
+ m_RGA3_INT_WIN1_H_ERR | \
+ m_RGA3_INT_WIN1_V_ERR | \
+ m_RGA3_INT_RGA_MI_WR_IN_HERR | \
+ m_RGA3_INT_RGA_MI_WR_BUS_ERR | \
+ m_RGA3_INT_WIN0_IN_FIFO_WEN_ERR | \
+ m_RGA3_INT_WIN0_IN_FIFO_REB_ERR | \
+ m_RGA3_INT_WIN0_HOR_FIFO_WEN_ERR | \
+ m_RGA3_INT_WIN0_HOR_FIFO_REN_ERR| \
+ m_RGA3_INT_WIN0_VOR_FIFO_WEN_ERR | \
+ m_RGA3_INT_WIN0_VOR_FIFO_REN_ERR | \
+ m_RGA3_INT_WIN1_IN_FIFO_WEN_ERR | \
+ m_RGA3_INT_WIN1_IN_FIFO_REB_ERR | \
+ m_RGA3_INT_WIN1_HOR_FIFO_WEN_ERR | \
+ m_RGA3_INT_WIN1_HOR_FIFO_REN_ERR| \
+ m_RGA3_INT_WIN1_VOR_FIFO_WEN_ERR | \
+ m_RGA3_INT_WIN1_VOR_FIFO_REN_ERR \
+ )
+
+/* RGA3_CMD_CTRL */
+#define m_RGA3_CMD_CTRL_CMD_INCR_NUM (0x3ff << 3)
+#define m_RGA3_CMD_CTRL_CMD_STOP_MODE (0x1 << 2)
+#define m_RGA3_CMD_CTRL_CMD_INCR_VALID_P (0x1 << 1)
+#define m_RGA3_CMD_CTRL_CMD_LINE_ST_P (0x1 << 0)
+
+/* RGA3_RO_SRST */
+#define m_RGA3_RO_SRST_RO_RST_DONE (0x3f << 0)
+
+/* RGA3_CMD_STATE */
+#define m_RGA3_CMD_STATE_CMD_CNT_CUR (0xfff << 16)
+#define m_RGA3_CMD_STATE_CMD_WORKING (0x1 << 0)
+
+/* RGA3_WIN0_RD_CTRL */
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE (0x1 << 0)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE (0x3 << 1)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT (0xf << 4)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT (0x3 << 8)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT (0x1 << 10)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE (0x1 << 11)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP (0x1 << 12)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP (0x1 << 13)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT (0x1 << 16)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR (0x1 << 17)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR (0x1 << 18)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY (0x1 << 20)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP (0x1 << 21)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY (0x1 << 22)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP (0x1 << 23)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN (0x1 << 24)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN (0x1 << 25)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE (0x3 << 26)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_PERF_OPT_DIS (0x1 << 29)
+#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_ALIGN_DIS (0x1 << 30)
+
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE(x) ((x & 0x1) << 0)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE(x) ((x & 0x3) << 1)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT(x) ((x & 0xf) << 4)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT(x) ((x & 0x3) << 8)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT(x) ((x & 0x1) << 10)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE(x) ((x & 0x1) << 11)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP(x) ((x & 0x1) << 12)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP(x) ((x & 0x1) << 13)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT(x) ((x & 0x1) << 16)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR(x) ((x & 0x1) << 17)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR(x) ((x & 0x1) << 18)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY(x) ((x & 0x1) << 20)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP(x) ((x & 0x1) << 21)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY(x) ((x & 0x1) << 22)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP(x) ((x & 0x1) << 23)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN(x) ((x & 0x1) << 24)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN(x) ((x & 0x1) << 25)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(x) ((x & 0x3) << 26)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_PERF_OPT_DIS(x) ((x & 0x1) << 29)
+#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_ALIGN_DIS(x) ((x & 0x1) << 30)
+
+/* RGA3_WIN0_FBC_OFF */
+#define m_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_XOFF (0x1fff << 0)
+#define m_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_YOFF (0x1fff << 16)
+
+#define s_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_XOFF(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_YOFF(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN0_SRC_SIZE */
+#define m_RGA3_WIN0_SRC_SIZE_SW_WIN0_SRC_WIDTH (0x1fff << 0)
+#define m_RGA3_WIN0_SRC_SIZE_SW_WIN0_SRC_HEIGHT (0x1fff << 16)
+
+#define s_RGA3_WIN0_SRC_OFF_SW_WIN0_SRC_WIDTH(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN0_SRC_OFF_SW_WIN0_SRC_HEIGHT(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN0_ACT_OFF */
+#define m_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_XOFF (0x1fff << 0)
+#define m_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_YOFF (0x1fff << 16)
+
+#define s_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_XOFF(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_YOFF(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN0_ACT_SIZE */
+#define m_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_WIDTH (0x1fff << 0)
+#define m_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_HEIGHT (0x1fff << 16)
+
+#define s_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_WIDTH(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_HEIGHT(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN0_DST_SIZE */
+#define m_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_WIDTH (0x1fff << 0)
+#define m_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_HEIGHT (0x1fff << 16)
+
+#define s_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_WIDTH(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_HEIGHT(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN0_SCL_FAC */
+#define m_RGA3_WIN0_SCL_FAC_SW_WIN0_VER_FAC (0xffff << 0)
+#define m_RGA3_WIN0_SCL_FAC_SW_WIN0_HOR_FAC (0xffff << 16)
+
+#define s_RGA3_WIN0_SCL_FAC_SW_WIN0_VER_FAC(x) ((x & 0xffff) << 0)
+#define s_RGA3_WIN0_SCL_FAC_SW_WIN0_HOR_FAC(x) ((x & 0xffff) << 16)
+
+/* RGA3_WIN1_RD_CTRL */
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE (0x1 << 0)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE (0x3 << 1)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT (0xf << 4)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT (0x3 << 8)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT (0x1 << 10)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE (0x1 << 11)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP (0x1 << 12)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP (0x1 << 13)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT (0x1 << 16)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR (0x1 << 17)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR (0x1 << 18)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY (0x1 << 20)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP (0x1 << 21)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY (0x1 << 22)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP (0x1 << 23)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN (0x1 << 24)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN (0x1 << 25)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_CSC_MODE (0x3 << 26)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_PERF_OPT_DIS (0x1 << 29)
+#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_ALIGN_DIS (0x1 << 30)
+
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE(x) ((x & 0x1) << 0)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE(x) ((x & 0x3) << 1)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT(x) ((x & 0xf) << 4)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT(x) ((x & 0x3) << 8)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT(x) ((x & 0x1) << 10)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE(x) ((x & 0x1) << 11)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP(x) ((x & 0x1) << 12)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP(x) ((x & 0x1) << 13)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT(x) ((x & 0x1) << 16)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR(x) ((x & 0x1) << 17)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR(x) ((x & 0x1) << 18)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY(x) ((x & 0x1) << 20)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP(x) ((x & 0x1) << 21)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY(x) ((x & 0x1) << 22)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP(x) ((x & 0x1) << 23)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN(x) ((x & 0x1) << 24)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN(x) ((x & 0x1) << 25)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_CSC_MODE(x) ((x & 0x3) << 26)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_PERF_OPT_DIS(x) ((x & 0x1) << 29)
+#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_ALIGN_DIS(x) ((x & 0x1) << 30)
+
+/* RGA3_WIN1_FBC_OFF */
+#define m_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_XOFF (0x1fff << 0)
+#define m_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_YOFF (0x1fff << 16)
+
+#define s_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_XOFF(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_YOFF(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN1_SRC_SIZE */
+#define m_RGA3_WIN1_SRC_SIZE_SW_WIN1_SRC_WIDTH (0x1fff << 0)
+#define m_RGA3_WIN1_SRC_SIZE_SW_WIN1_SRC_HEIGHT (0x1fff << 16)
+
+#define s_RGA3_WIN1_SRC_OFF_SW_WIN1_SRC_WIDTH(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN1_SRC_OFF_SW_WIN1_SRC_HEIGHT(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN1_ACT_OFF */
+#define m_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_XOFF (0x1fff << 0)
+#define m_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_YOFF (0x1fff << 16)
+
+#define s_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_XOFF(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_YOFF(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN1_ACT_SIZE */
+#define m_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_WIDTH (0x1fff << 0)
+#define m_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_HEIGHT (0x1fff << 16)
+
+#define s_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_WIDTH(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_HEIGHT(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN1_DST_SIZE */
+#define m_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_WIDTH (0x1fff << 0)
+#define m_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_HEIGHT (0x1fff << 16)
+
+#define s_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_WIDTH(x) ((x & 0x1fff) << 0)
+#define s_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_HEIGHT(x) ((x & 0x1fff) << 16)
+
+/* RGA3_WIN1_SCL_FAC */
+#define m_RGA3_WIN1_SCL_FAC_SW_WIN1_VER_FAC (0xffff << 0)
+#define m_RGA3_WIN1_SCL_FAC_SW_WIN1_HOR_FAC (0xffff << 16)
+
+#define s_RGA3_WIN1_SCL_FAC_SW_WIN1_VER_FAC(x) ((x & 0xffff) << 0)
+#define s_RGA3_WIN1_SCL_FAC_SW_WIN1_HOR_FAC(x) ((x & 0xffff) << 16)
+
+/* RGA3_OVLP_CTRL */
+#define m_RGA3_OVLP_CTRL_SW_OVLP_MODE (0x3 << 0)
+#define m_RGA3_OVLP_CTRL_SW_OVLP_FIELD (0x1 << 2)
+#define m_RGA3_OVLP_CTRL_SW_TOP_SWAP (0x1 << 3)
+#define m_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN (0x1 << 4)
+#define m_RGA3_OVLP_CTRL_SW_TOP_KEY_EN (0x7FFF << 5)
+#define m_RGA3_OVLP_CTRL_SW_OVLP_Y2R_EN (0x1 << 20)
+#define m_RGA3_OVLP_CTRL_SW_OVLP_R2Y_EN (0x1 << 21)
+#define m_RGA3_OVLP_CTRL_SW_OVLP_CSC_MODE (0x3 << 22)
+
+#define s_RGA3_OVLP_CTRL_SW_OVLP_MODE(x) ((x & 0x3) << 0)
+#define s_RGA3_OVLP_CTRL_SW_OVLP_FIELD(x) ((x & 0x1) << 2)
+#define s_RGA3_OVLP_CTRL_SW_TOP_SWAP(x) ((x & 0x1) << 3)
+#define s_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN(x) ((x & 0x1) << 4)
+#define s_RGA3_OVLP_CTRL_SW_TOP_KEY_EN(x) ((x & 0x7FFF) << 5)
+#define s_RGA3_OVLP_CTRL_SW_OVLP_Y2R_EN(x) ((x & 0x1) << 20)
+#define s_RGA3_OVLP_CTRL_SW_OVLP_R2Y_EN(x) ((x & 0x1) << 21)
+#define s_RGA3_OVLP_CTRL_SW_OVLP_CSC_MODE(x) ((x & 0x3) << 22)
+
+/* RGA3_OVLP_OFF */
+#define m_RGA3_OVLP_OFF_SW_OVLP_XOFF (0x1fff << 0)
+#define m_RGA3_OVLP_OFF_SW_OVLP_YOFF (0x1fff << 16)
+
+#define s_RGA3_OVLP_OFF_SW_OVLP_XOFF(x) ((x & 0x1fff) << 0)
+#define s_RGA3_OVLP_OFF_SW_OVLP_YOFF(x) ((x & 0x1fff) << 16)
+
+/* RGA3_OVLP_TOP_KEY_MIN */
+#define m_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_YG_MIN (0x3ff << 0)
+#define m_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_UB_MIN (0x3ff << 10)
+#define m_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_VR_MIN (0x3ff << 20)
+
+#define s_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_YG_MIN(x) ((x & 0x3f)f << 0)
+#define s_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_UB_MIN(x) ((x & 0x3ff) << 10)
+#define s_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_VR_MIN(x) ((x & 0x3ff) << 20)
+
+/* RGA3_OVLP_TOP_KEY_MAX */
+#define m_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_YG_MAX (0x3ff << 0)
+#define m_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_UB_MAX (0x3ff << 10)
+#define m_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_VR_MAX (0x3ff << 20)
+
+#define s_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_YG_MAX(x) ((x & 0x3ff) << 0)
+#define s_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_UB_MAX(x) ((x & 0x3ff) << 10)
+#define s_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_VR_MAX(x) ((x & 0x3ff) << 20)
+
+/* RGA3_OVLP_TOP_CTRL */
+#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_COLOR_M0 (0x1 << 0)
+#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_M0 (0x1 << 1)
+#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_BLEND_M0 (0x3 << 2)
+#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_CAL_M0 (0x1 << 4)
+#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_FACTOR_M0 (0x7 << 5)
+#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_GLOBAL_ALPHA (0xff << 16)
+
+#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_COLOR_M0(x) ((x & 0x1) << 0)
+#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_M0(x) ((x & 0x1) << 1)
+#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_BLEND_M0(x) ((x & 0x3) << 2)
+#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_CAL_M0(x) ((x & 0x1) << 4)
+#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_FACTOR_M0(x) ((x & 0x7) << 5)
+#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_GLOBAL_ALPHA(x) ((x & 0xff) << 16)
+
+/* RGA3_OVLP_BOT_CTRL */
+#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_COLOR_M0 (0x1 << 0)
+#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_M0 (0x1 << 1)
+#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_BLEND_M0 (0x3 << 2)
+#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_CAL_M0 (0x1 << 4)
+#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_FACTOR_M0 (0x7 << 5)
+#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_GLOBAL_ALPHA (0xff << 16)
+
+#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_COLOR_M0(x) ((x & 0x1) << 0)
+#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_M0(x) ((x & 0x1) << 1)
+#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_BLEND_M0(x) ((x & 0x3) << 2)
+#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_CAL_M0(x) ((x & 0x1) << 4)
+#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_FACTOR_M0(x) ((x & 0x7) << 5)
+#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_GLOBAL_ALPHA(x) ((x & 0xff) << 16)
+
+/* RGA3_OVLP_TOP_ALPHA */
+#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_M1 (0x1 << 1)
+#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_BLEND_M1 (0x3 << 2)
+#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_CAL_M1 (0x1 << 4)
+#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_FACTOR_M1 (0x7 << 5)
+
+#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_M1(x) ((x & 0x1) << 1)
+#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_BLEND_M1(x) ((x & 0x3) << 2)
+#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_CAL_M1(x) ((x & 0x1) << 4)
+#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_FACTOR_M1(x) ((x & 0x7) << 5)
+
+/* RGA3_OVLP_BOT_ALPHA */
+#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_M1 (0x1 << 1)
+#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_BLEND_M1 (0x3 << 2)
+#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_CAL_M1 (0x1 << 4)
+#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_FACTOR_M1 (0x7 << 5)
+
+#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_M1(x) ((x & 0x1) << 1)
+#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_BLEND_M1(x) ((x & 0x3) << 2)
+#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_CAL_M1(x) ((x & 0x1) << 4)
+#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_FACTOR_M1(x) ((x & 0x7) << 5)
+
+/* RGA3_WR_CTRL */
+#define m_RGA3_WR_CTRL_SW_WR_MODE (0x3 << 0)
+#define m_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN (0x1 << 2)
+#define m_RGA3_WR_CTRL_SW_WR_PIC_FORMAT (0xf << 4)
+#define m_RGA3_WR_CTRL_SW_WR_FORMAT (0x3 << 8)
+#define m_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT (0x1 << 10)
+#define m_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE (0x1 << 11)
+#define m_RGA3_WR_CTRL_SW_WR_PIX_SWAP (0x1 << 12)
+#define m_RGA3_WR_CTRL_SW_OUTSTANDING_MAX (0x3f << 13)
+#define m_RGA3_WR_CTRL_SW_WR_YC_SWAP (0x1 << 20)
+
+#define s_RGA3_WR_CTRL_SW_WR_MODE(x) ((x & 0x3) << 0)
+#define s_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN(x) ((x & 0x1) << 2)
+#define s_RGA3_WR_CTRL_SW_WR_PIC_FORMAT(x) ((x & 0xf) << 4)
+#define s_RGA3_WR_CTRL_SW_WR_FORMAT(x) ((x & 0x3) << 8)
+#define s_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT(x) ((x & 0x1) << 10)
+#define s_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE(x) ((x & 0x1) << 11)
+#define s_RGA3_WR_CTRL_SW_WR_PIX_SWAP(x) ((x & 0x1) << 12)
+#define s_RGA3_WR_CTRL_SW_OUTSTANDING_MAX(x) ((x & 0x3f) << 13)
+#define s_RGA3_WR_CTRL_SW_WR_YC_SWAP(x) ((x & 0x1) << 20)
+
+/* RGA3_WR_FBCE_CTRL */
+#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_BLKBD_OPT_DIS (0x1 << 0)
+#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS (0x1 << 1)
+#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO0_WATERMARK (0x3f << 2)
+#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO1_WATERMARK (0x3f << 8)
+#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_SIZE_ALIGN_DIS (0x1 << 31)
+
+#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_BLKBD_OPT_DIS(x) ((x & 0x1) << 0)
+#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS(x) ((x & 0x1) << 1)
+#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO0_WATERMARK(x) ((x & 0x3f) << 2)
+#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO1_WATERMARK(x) ((x & 0x3f) << 8)
+#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_SIZE_ALIGN_DIS(x) ((x & 0x1) << 31)
+
+/* RGA3_MMU_STATUS read_only */
+#define m_RGA3_MMU_STATUS_PAGING_ENABLED (0x1 << 0)
+#define m_RGA3_MMU_STATUS_PAGE_FAULT_ACTIVE (0x1 << 1)
+#define m_RGA3_MMU_STATUS_STAIL_ACTIVE (0x1 << 2)
+#define m_RGA3_MMU_STATUS_MMU_IDLE (0x1 << 3)
+#define m_RGA3_MMU_STATUS_REPLAY_BUFFER_EMPTY (0x1 << 4)
+#define m_RGA3_MMU_STATUS_PAGE_FAULT_IS_WRITE (0x1 << 5)
+#define m_RGA3_MMU_STATUS_PAGE_FAULT_BUS_ID (0x1f << 6)
+
+/* RGA3_MMU_INT_RAWSTAT read_only */
+#define m_RGA3_MMU_INT_RAWSTAT_READ_BUS_ERROR (0x1 << 0)
+#define m_RGA3_MMU_INT_RAWSTAT_PAGE_FAULT (0x1 << 1)
+
+/* RGA3_MMU_INT_CLEAR write_only */
+#define m_RGA3_MMU_INT_CLEAR_READ_BUS_ERROR (0x1 << 0)
+#define m_RGA3_MMU_INT_CLEAR_PAGE_FAULT (0x1 << 1)
+
+#define s_RGA3_MMU_INT_CLEAR_READ_BUS_ERROR(x) ((x & 0x1) << 0)
+#define s_RGA3_MMU_INT_CLEAR_PAGE_FAULT(x) ((x & 0x1) << 1)
+
+/* RGA3_MMU_INT_MASK */
+#define m_RGA3_MMU_INT_MASK_READ_BUS_ERROR (0x1 << 0)
+#define m_RGA3_MMU_INT_MASK_PAGE_FAULT (0x1 << 1)
+
+#define s_RGA3_MMU_INT_MASK_READ_BUS_ERROR(x) ((x & 0x1) << 0)
+#define s_RGA3_MMU_INT_MASK_PAGE_FAULT(x) ((x & 0x1) << 1)
+
+/* RGA3_MMU_INT_STATUS read_only */
+#define m_RGA3_MMU_INT_STATUS_READ_BUS_ERROR (0x1 << 0)
+#define m_RGA3_MMU_INT_STATUS_PAGE_FAULT (0x1 << 1)
+
+/* RGA3_MMU_AUTO_GATING */
+#define m_RGA3_MMU_AUTO_GATING_MMU_AUTO_GATING (0x1 << 1)
+#define m_RGA3_MMU_AUTO_GATING_MMU_CFG_MODE (0x1 << 1)
+#define m_RGA3_MMU_AUTO_GATING_MMU_BUG_FIXED_DISABLE (0x1 << 31)
+
+#define s_RGA3_MMU_AUTO_GATING_MMU_AUTO_GATING(x) ((x & 0x1) << 1)
+#define s_RGA3_MMU_AUTO_GATING_MMU_BUG_FIXED_DISABLE(x) ((x & 0x1) << 31)
+
+#define RGA3_ROT_BIT_ROT_90 BIT(0)
+#define RGA3_ROT_BIT_X_MIRROR BIT(1)
+#define RGA3_ROT_BIT_Y_MIRROR BIT(2)
+
+union rga3_color_ctrl {
+ uint32_t value;
+ struct {
+ uint32_t color_mode:1;
+ uint32_t alpha_mode:1;
+ uint32_t blend_mode:2;
+ uint32_t alpha_cal_mode:1;
+ uint32_t factor_mode:3;
+
+ uint32_t reserved:8;
+
+ uint32_t global_alpha:8;
+ } bits;
+};
+
+union rga3_alpha_ctrl {
+ uint32_t value;
+ struct {
+ uint32_t reserved:1;
+ uint32_t alpha_mode:1;
+ uint32_t blend_mode:2;
+ uint32_t alpha_cal_mode:1;
+ uint32_t factor_mode:3;
+ } bits;
+};
+
+extern const struct rga_backend_ops rga3_ops;
+
+#endif
+
diff --git a/drivers/video/rockchip/rga3/include/rga_common.h b/drivers/video/rockchip/rga3/include/rga_common.h
new file mode 100644
index 000000000..32e83cc9c
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_common.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author:
+ * Cerf Yu <cerf.yu@rock-chips.com>
+ */
+
+#ifndef __LINUX_RKRGA_COMMON_H_
+#define __LINUX_RKRGA_COMMON_H_
+
+#include "rga_drv.h"
+#include "rga_hw_config.h"
+
+#define RGA_GET_PAGE_COUNT(size) (((size) >> PAGE_SHIFT) + (((size) & (~PAGE_MASK)) ? 1 : 0))
+
+bool rga_is_rgb_format(uint32_t format);
+bool rga_is_yuv_format(uint32_t format);
+bool rga_is_alpha_format(uint32_t format);
+bool rga_is_yuv420_packed_format(uint32_t format);
+bool rga_is_yuv420_planar_format(uint32_t format);
+bool rga_is_yuv420_semi_planar_format(uint32_t format);
+bool rga_is_yuv422_packed_format(uint32_t format);
+bool rga_is_yuv422_planar_format(uint32_t format);
+bool rga_is_yuv422_semi_planar_format(uint32_t format);
+bool rga_is_yuv8bit_format(uint32_t format);
+bool rga_is_yuv10bit_format(uint32_t format);
+bool rga_is_yuv422p_format(uint32_t format);
+bool rga_is_only_y_format(uint32_t format);
+
+int rga_get_format_bits(uint32_t format);
+int rga_get_pixel_stride_from_format(uint32_t format);
+
+const char *rga_get_format_name(uint32_t format);
+const char *rga_get_render_mode_str(uint8_t mode);
+const char *rga_get_rotate_mode_str(uint8_t mode);
+const char *rga_get_blend_mode_str(enum rga_alpha_blend_mode mode);
+const char *rga_get_memory_type_str(uint8_t type);
+const char *rga_get_mmu_type_str(enum rga_mmu mmu_type);
+const char *rga_get_core_name(enum RGA_SCHEDULER_CORE core);
+
+void rga_convert_addr(struct rga_img_info_t *img, bool before_vir_get_channel);
+void rga_swap_pd_mode(struct rga_req *req_rga);
+int rga_image_size_cal(int w, int h, int format,
+ int *yrgb_size, int *uv_size, int *v_size);
+void rga_dump_memory_parm(struct rga_memory_parm *parm);
+void rga_dump_external_buffer(struct rga_external_buffer *buffer);
+
+#endif
diff --git a/drivers/video/rockchip/rga3/include/rga_debugger.h b/drivers/video/rockchip/rga3/include/rga_debugger.h
new file mode 100644
index 000000000..c274fe87f
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_debugger.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author:
+ * Cerf Yu <cerf.yu@rock-chips.com>
+ * Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#ifndef _RGA_DEBUGGER_H_
+#define _RGA_DEBUGGER_H_
+
+#include "rga_drv.h"
+
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER
+
+extern int RGA_DEBUG_REG;
+extern int RGA_DEBUG_MSG;
+extern int RGA_DEBUG_TIME;
+extern int RGA_DEBUG_INT_FLAG;
+extern int RGA_DEBUG_MM;
+extern int RGA_DEBUG_CHECK_MODE;
+extern int RGA_DEBUG_NONUSE;
+extern int RGA_DEBUG_DUMP_IMAGE;
+
+#define DEBUGGER_EN(name) (unlikely(RGA_DEBUG_##name ? true : false))
+
+/*
+ * struct rga_debugger - RGA debugger information
+ *
+ * This structure represents a debugger to be created by the rga driver
+ * or core.
+ */
+struct rga_debugger {
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS
+ /* Directory of debugfs file */
+ struct dentry *debugfs_dir;
+ struct list_head debugfs_entry_list;
+ struct mutex debugfs_lock;
+#endif
+
+#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS
+ /* Directory of procfs file */
+ struct proc_dir_entry *procfs_dir;
+ struct list_head procfs_entry_list;
+ struct mutex procfs_lock;
+#endif
+};
+
+/*
+ * struct rga_debugger_list - debugfs/procfs info list entry
+ *
+ * This structure represents a debugfs/procfs file to be created by the rga
+ * driver or core.
+ */
+struct rga_debugger_list {
+ /* File name */
+ const char *name;
+ /*
+ * Show callback. &seq_file->private will be set to the &struct
+ * rga_debugger_node corresponding to the instance of this info
+ * on a given &struct rga_debugger.
+ */
+ int (*show)(struct seq_file *seq, void *data);
+ /*
+ * Write callback. &seq_file->private will be set to the &struct
+ * rga_debugger_node corresponding to the instance of this info
+ * on a given &struct rga_debugger.
+ */
+ ssize_t (*write)(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp);
+ /* Procfs/Debugfs private data. */
+ void *data;
+};
+
+/*
+ * struct rga_debugger_node - Nodes for debugfs/procfs
+ *
+ * This structure represents each instance of procfs/debugfs created from the
+ * template.
+ */
+struct rga_debugger_node {
+ struct rga_debugger *debugger;
+
+ /* template for this node. */
+ const struct rga_debugger_list *info_ent;
+
+ /* Each Procfs/Debugfs file. */
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS
+ struct dentry *dent;
+#endif
+
+#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS
+ struct proc_dir_entry *pent;
+#endif
+
+ struct list_head list;
+};
+
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS
+int rga_debugfs_init(void);
+int rga_debugfs_remove(void);
+#else
+static inline int rga_debugfs_remove(void)
+{
+ return 0;
+}
+static inline int rga_debugfs_init(void)
+{
+ return 0;
+}
+#endif /* #ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS */
+
+#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS
+int rga_procfs_remove(void);
+int rga_procfs_init(void);
+#else
+static inline int rga_procfs_remove(void)
+{
+ return 0;
+}
+static inline int rga_procfs_init(void)
+{
+ return 0;
+}
+#endif /* #ifdef CONFIG_ROCKCHIP_RGA_PROC_FS */
+
+#else
+
+#define DEBUGGER_EN(name) (unlikely(false))
+
+#endif /* #ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER */
+
+void rga_cmd_print_debug_info(struct rga_req *req);
+void rga_request_task_debug_info(struct seq_file *m, struct rga_req *req);
+#ifdef CONFIG_NO_GKI
+void rga_dump_job_image(struct rga_job *dump_job);
+#else
+static inline void rga_dump_job_image(struct rga_job *dump_job)
+{
+}
+#endif /* #ifdef CONFIG_NO_GKI */
+
+#endif /* #ifndef _RGA_DEBUGGER_H_ */
+
diff --git a/drivers/video/rockchip/rga3/include/rga_dma_buf.h b/drivers/video/rockchip/rga3/include/rga_dma_buf.h
new file mode 100644
index 000000000..2ff0857a6
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_dma_buf.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author:
+ * Cerf Yu <cerf.yu@rock-chips.com>
+ * Huang Lee <Putin.li@rock-chips.com>
+ */
+#ifndef __RGA3_DMA_BUF_H__
+#define __RGA3_DMA_BUF_H__
+
+#include "rga_drv.h"
+
+#ifndef for_each_sgtable_sg
+/*
+ * Loop over each sg element in the given sg_table object.
+ */
+#define for_each_sgtable_sg(sgt, sg, i) \
+ for_each_sg((sgt)->sgl, sg, (sgt)->orig_nents, i)
+#endif
+
+int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr,
+ unsigned long v_addr, int format, uint32_t w,
+ uint32_t h, unsigned long *StartAddr, unsigned long *size);
+
+int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd);
+int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_info_t *img);
+
+int rga_iommu_map_sgt(struct sg_table *sgt, size_t size,
+ struct rga_dma_buffer *buffer,
+ struct device *rga_dev);
+int rga_iommu_map(phys_addr_t paddr, size_t size,
+ struct rga_dma_buffer *buffer,
+ struct device *rga_dev);
+void rga_iommu_unmap(struct rga_dma_buffer *buffer);
+
+int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer,
+ enum dma_data_direction dir, struct device *rga_dev);
+int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer,
+ enum dma_data_direction dir, struct device *rga_dev);
+void rga_dma_unmap_buf(struct rga_dma_buffer *rga_dma_buffer);
+
+void rga_dma_sync_flush_range(void *pstart, void *pend, struct rga_scheduler_t *scheduler);
+
+#endif /* #ifndef __RGA3_DMA_BUF_H__ */
+
diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h
new file mode 100644
index 000000000..c9d28387a
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_drv.h
@@ -0,0 +1,468 @@
+/* 6.18 renamed MAX_ORDER (exclusive) to MAX_PAGE_ORDER (inclusive) */
+#include <linux/mmzone.h>
+#ifndef MAX_ORDER
+#define MAX_ORDER (MAX_PAGE_ORDER + 1)
+#endif
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#ifndef __LINUX_RGA_DRV_H_
+#define __LINUX_RGA_DRV_H_
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/fdtable.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/syscalls.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched/mm.h>
+#include <linux/string_helpers.h>
+
+#include <asm/cacheflush.h>
+
+#include <linux/iommu.h>
+#include <linux/iova.h>
+#include <linux/pagemap.h>
+
+#ifdef CONFIG_DMABUF_CACHE
+#include <linux/dma-buf-cache.h>
+#else
+#include <linux/dma-buf.h>
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
+#include <linux/dma-map-ops.h>
+#endif
+
+#include <linux/hrtimer.h>
+
+#include "rga.h"
+
+#define RGA_CORE_REG_OFFSET 0x10000
+
+/* load interval: 1000ms */
+#define RGA_LOAD_INTERVAL_US 1000000
+
+/* timer interval: 1000ms */
+#define RGA_TIMER_INTERVAL_NS 1000000000
+
+#if ((defined(CONFIG_RK_IOMMU) || defined(CONFIG_ROCKCHIP_IOMMU)) \
+ && defined(CONFIG_ION_ROCKCHIP))
+#define CONFIG_RGA_IOMMU
+#endif
+
+/* Driver information */
+#define DRIVER_DESC "RGA multicore Device Driver"
+#define DRIVER_NAME "rga_multicore"
+
+#define STR_HELPER(x) #x
+#define STR(x) STR_HELPER(x)
+
+#define DRIVER_MAJOR_VERISON 1
+#define DRIVER_MINOR_VERSION 3
+#define DRIVER_REVISION_VERSION 1
+#define DRIVER_PATCH_VERSION
+
+#define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \
+ "." STR(DRIVER_REVISION_VERSION) STR(DRIVER_PATCH_VERSION))
+
+/* time limit */
+#define RGA_JOB_TIMEOUT_DELAY HZ
+#define RGA_RESET_TIMEOUT 1000
+
+#define RGA_MAX_SCHEDULER RGA_HW_SIZE
+#define RGA_MAX_BUS_CLK 10
+
+#define RGA_BUFFER_POOL_MAX_SIZE 64
+
+#ifndef ABS
+#define ABS(X) (((X) < 0) ? (-(X)) : (X))
+#endif
+
+#ifndef CLIP
+#define CLIP(x, a, b) (((x) < (a)) \
+ ? (a) : (((x) > (b)) ? (b) : (x)))
+#endif
+
+extern struct rga_drvdata_t *rga_drvdata;
+
+enum {
+ RGA3_SCHEDULER_CORE0 = 1 << 0,
+ RGA3_SCHEDULER_CORE1 = 1 << 1,
+ RGA2_SCHEDULER_CORE0 = 1 << 2,
+ RGA_CORE_MASK = 0x7,
+ RGA_NONE_CORE = 0x0,
+};
+
+enum {
+ RGA_CMD_SLAVE = 1,
+ RGA_CMD_MASTER = 2,
+};
+
+enum iommu_dma_cookie_type {
+ IOMMU_DMA_IOVA_COOKIE,
+ IOMMU_DMA_MSI_COOKIE,
+};
+
+enum rga_scheduler_status {
+ RGA_SCHEDULER_IDLE = 0,
+ RGA_SCHEDULER_WORKING,
+ RGA_SCHEDULER_ABORT,
+};
+
+enum rga_job_state {
+ RGA_JOB_STATE_PENDING = 0,
+ RGA_JOB_STATE_PREPARE,
+ RGA_JOB_STATE_RUNNING,
+ RGA_JOB_STATE_FINISH,
+ RGA_JOB_STATE_DONE,
+ RGA_JOB_STATE_INTR_ERR,
+ RGA_JOB_STATE_HW_TIMEOUT,
+ RGA_JOB_STATE_ABORT,
+};
+
+struct rga_iommu_dma_cookie {
+ enum iommu_dma_cookie_type type;
+
+ /* Full allocator for IOMMU_DMA_IOVA_COOKIE */
+ struct iova_domain iovad;
+};
+
+struct rga_iommu_info {
+ struct device *dev;
+ struct device *default_dev; /* for dma-buf_api */
+ struct iommu_domain *domain;
+ struct iommu_group *group;
+};
+
+struct rga_dma_buffer {
+ /* DMABUF information */
+ struct dma_buf *dma_buf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+ void *vmap_ptr;
+
+ struct iommu_domain *domain;
+
+ enum dma_data_direction dir;
+
+ dma_addr_t iova;
+ unsigned long size;
+ /*
+ * The offset of the first page of the sgt.
+ * Since alloc iova must be page aligned, the offset of the first page is
+ * identified separately.
+ */
+ size_t offset;
+
+ /* The scheduler of the mapping */
+ struct rga_scheduler_t *scheduler;
+};
+
+struct rga_virt_addr {
+ uint64_t addr;
+
+ struct page **pages;
+ int pages_order;
+ int page_count;
+ unsigned long size;
+
+ /* The offset of the first page of the virtual address */
+ size_t offset;
+
+ int result;
+};
+
+struct rga_internal_buffer {
+ /* DMA buffer */
+ struct rga_dma_buffer *dma_buffer;
+
+ /* virtual address */
+ struct rga_virt_addr *virt_addr;
+
+ /* physical address */
+ uint64_t phys_addr;
+
+ /* buffer size */
+ unsigned long size;
+
+ struct rga_memory_parm memory_parm;
+
+
+ struct mm_struct *current_mm;
+
+ /* memory type. */
+ uint32_t type;
+
+ uint32_t handle;
+
+ uint32_t mm_flag;
+
+ struct kref refcount;
+ struct rga_session *session;
+};
+
+struct rga_scheduler_t;
+
+struct rga_session {
+ int id;
+
+ pid_t tgid;
+
+ char *pname;
+};
+
+struct rga_job_buffer {
+ union {
+ struct {
+ struct rga_external_buffer *ex_y_addr;
+ struct rga_external_buffer *ex_uv_addr;
+ struct rga_external_buffer *ex_v_addr;
+ };
+ struct rga_external_buffer *ex_addr;
+ };
+
+ union {
+ struct {
+ struct rga_internal_buffer *y_addr;
+ struct rga_internal_buffer *uv_addr;
+ struct rga_internal_buffer *v_addr;
+ };
+ struct rga_internal_buffer *addr;
+ };
+
+ uint32_t *page_table;
+ int order;
+ int page_count;
+};
+
+struct rga_job {
+ struct list_head head;
+
+ struct rga_scheduler_t *scheduler;
+ struct rga_session *session;
+
+ struct rga_req rga_command_base;
+ uint32_t cmd_reg[32 * 8];
+ struct rga_full_csc full_csc;
+ struct rga_csc_clip full_csc_clip;
+ struct rga_pre_intr_info pre_intr_info;
+
+ struct rga_job_buffer src_buffer;
+ struct rga_job_buffer src1_buffer;
+ struct rga_job_buffer dst_buffer;
+ /* used by rga2 */
+ struct rga_job_buffer els_buffer;
+
+ /* for rga2 virtual_address */
+ struct mm_struct *mm;
+
+ /* job time stamp */
+ ktime_t timestamp;
+ /* The time when the job is actually executed on the hardware */
+ ktime_t hw_running_time;
+ /* The time only for hrtimer to calculate the load */
+ ktime_t hw_recoder_time;
+ unsigned int flags;
+ int request_id;
+ int priority;
+ int core;
+ int ret;
+ pid_t pid;
+ bool use_batch_mode;
+
+ struct kref refcount;
+ unsigned long state;
+ uint32_t intr_status;
+ uint32_t hw_status;
+ uint32_t cmd_status;
+};
+
+struct rga_backend_ops {
+ int (*get_version)(struct rga_scheduler_t *scheduler);
+ int (*set_reg)(struct rga_job *job, struct rga_scheduler_t *scheduler);
+ int (*init_reg)(struct rga_job *job);
+ void (*soft_reset)(struct rga_scheduler_t *scheduler);
+ int (*read_back_reg)(struct rga_job *job, struct rga_scheduler_t *scheduler);
+ int (*irq)(struct rga_scheduler_t *scheduler);
+ int (*isr_thread)(struct rga_job *job, struct rga_scheduler_t *scheduler);
+};
+
+struct rga_timer {
+ u32 busy_time;
+ u32 busy_time_record;
+};
+
+struct rga_scheduler_t {
+ struct device *dev;
+ void __iomem *rga_base;
+ struct rga_iommu_info *iommu_info;
+
+ struct clk *clks[RGA_MAX_BUS_CLK];
+ int num_clks;
+
+ enum rga_scheduler_status status;
+ int pd_refcount;
+
+ struct rga_job *running_job;
+ struct list_head todo_list;
+ spinlock_t irq_lock;
+ wait_queue_head_t job_done_wq;
+ const struct rga_backend_ops *ops;
+ const struct rga_hw_data *data;
+ int job_count;
+ int irq;
+ struct rga_version_t version;
+ int core;
+
+ struct rga_timer timer;
+};
+
+struct rga_request {
+ struct rga_req *task_list;
+ int task_count;
+ uint32_t finished_task_count;
+ uint32_t failed_task_count;
+
+ bool use_batch_mode;
+ bool is_running;
+ bool is_done;
+ int ret;
+ uint32_t sync_mode;
+
+ int32_t acquire_fence_fd;
+ int32_t release_fence_fd;
+ struct dma_fence *release_fence;
+ spinlock_t fence_lock;
+
+ wait_queue_head_t finished_wq;
+
+ int flags;
+ uint8_t mpi_config_flags;
+ int id;
+ struct rga_session *session;
+
+ spinlock_t lock;
+ struct kref refcount;
+
+ pid_t pid;
+
+ /*
+ * The mapping of virtual addresses to obtain physical addresses requires
+ * the memory mapping information of the current process.
+ */
+ struct mm_struct *current_mm;
+
+ struct rga_feature feature;
+ /* TODO: add some common work */
+};
+
+struct rga_pending_request_manager {
+ struct mutex lock;
+
+ /*
+ * @request_idr:
+ *
+ * Mapping of request id to object pointers. Used by the GEM
+ * subsystem. Protected by @lock.
+ */
+ struct idr request_idr;
+
+ int request_count;
+};
+
+struct rga_session_manager {
+ struct mutex lock;
+
+ struct idr ctx_id_idr;
+
+ int session_cnt;
+};
+
+struct rga_drvdata_t {
+ /* used by rga2's mmu lock */
+ struct mutex lock;
+
+ struct rga_scheduler_t *scheduler[RGA_MAX_SCHEDULER];
+ int num_of_scheduler;
+ /* The scheduler_index used by default for memory mapping. */
+ int map_scheduler_index;
+ struct rga_mmu_base *mmu_base;
+
+ struct delayed_work power_off_work;
+
+ struct rga_mm *mm;
+
+ /* rga_job pending manager, import by RGA_START_CONFIG */
+ struct rga_pending_request_manager *pend_request_manager;
+
+ struct rga_session_manager *session_manager;
+
+#ifdef CONFIG_ROCKCHIP_RGA_ASYNC
+ struct rga_fence_context *fence_ctx;
+#endif
+
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER
+ struct rga_debugger *debugger;
+#endif
+};
+
+struct rga_irqs_data_t {
+ const char *name;
+ irqreturn_t (*irq_hdl)(int irq, void *ctx);
+ irqreturn_t (*irq_thread)(int irq, void *ctx);
+};
+
+struct rga_match_data_t {
+ const char * const *clks;
+ int num_clks;
+};
+
+static inline int rga_read(int offset, struct rga_scheduler_t *scheduler)
+{
+ return readl(scheduler->rga_base + offset);
+}
+
+static inline void rga_write(int value, int offset, struct rga_scheduler_t *scheduler)
+{
+ writel(value, scheduler->rga_base + offset);
+}
+
+int rga_power_enable(struct rga_scheduler_t *scheduler);
+int rga_power_disable(struct rga_scheduler_t *scheduler);
+
+int rga_kernel_commit(struct rga_req *cmd);
+
+#endif /* __LINUX_RGA_FENCE_H_ */
diff --git a/drivers/video/rockchip/rga3/include/rga_fence.h b/drivers/video/rockchip/rga3/include/rga_fence.h
new file mode 100644
index 000000000..7e3bbeebb
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_fence.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#ifndef __LINUX_RGA_FENCE_H_
+#define __LINUX_RGA_FENCE_H_
+
+struct rga_fence_context {
+ unsigned int context;
+ unsigned int seqno;
+ spinlock_t spinlock;
+};
+
+struct rga_fence_waiter {
+ /* Base sync driver waiter structure */
+ struct dma_fence_cb waiter;
+
+ void *private;
+};
+
+#ifdef CONFIG_ROCKCHIP_RGA_ASYNC
+int rga_fence_context_init(struct rga_fence_context **ctx);
+void rga_fence_context_remove(struct rga_fence_context **ctx);
+
+struct dma_fence *rga_dma_fence_alloc(void);
+int rga_dma_fence_get_fd(struct dma_fence *fence);
+struct dma_fence *rga_get_dma_fence_from_fd(int fence_fd);
+int rga_dma_fence_wait(struct dma_fence *fence);
+int rga_dma_fence_add_callback(struct dma_fence *fence, dma_fence_func_t func, void *private);
+
+
+static inline void rga_dma_fence_put(struct dma_fence *fence)
+{
+ if (fence)
+ dma_fence_put(fence);
+}
+
+static inline void rga_dma_fence_signal(struct dma_fence *fence, int error)
+{
+ if (fence) {
+ if (error != 0)
+ dma_fence_set_error(fence, error);
+ dma_fence_signal(fence);
+ }
+}
+
+static inline int rga_dma_fence_get_status(struct dma_fence *fence)
+{
+ if (fence)
+ return dma_fence_get_status(fence);
+ else
+ return 1;
+}
+
+#else
+static inline struct dma_fence *rga_dma_fence_alloc(void)
+{
+ return NULL;
+}
+
+static inline int rga_dma_fence_get_fd(struct dma_fence *fence)
+{
+ return 0;
+}
+
+static inline struct dma_fence *rga_get_dma_fence_from_fd(int fence_fd)
+{
+ return NULL;
+}
+
+static inline int rga_dma_fence_wait(struct dma_fence *fence)
+{
+ return 0;
+}
+
+static inline int rga_dma_fence_add_callback(struct dma_fence *fence,
+ dma_fence_func_t func,
+ void *private)
+{
+ return 0;
+}
+
+static inline void rga_dma_fence_put(struct dma_fence *fence)
+{
+}
+
+static inline void rga_dma_fence_signal(struct dma_fence *fence, int error)
+{
+}
+
+static inline int rga_dma_fence_get_status(struct dma_fence *fence)
+{
+ return 0;
+}
+
+#endif /* #ifdef CONFIG_SYNC_FILE */
+
+#endif /* __LINUX_RGA_FENCE_H_ */
diff --git a/drivers/video/rockchip/rga3/include/rga_hw_config.h b/drivers/video/rockchip/rga3/include/rga_hw_config.h
new file mode 100644
index 000000000..46f7531aa
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_hw_config.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#ifndef __LINUX_RGA_HW_CONFIG_H_
+#define __LINUX_RGA_HW_CONFIG_H_
+
+#include "rga_drv.h"
+
+enum rga_mmu {
+ RGA_NONE_MMU = 0,
+ RGA_MMU = 1,
+ RGA_IOMMU = 2,
+};
+
+enum rga_hw_support_format_index {
+ RGA_RASTER_INDEX,
+ RGA_AFBC16x16_INDEX,
+ RGA_TILE8x8_INDEX,
+ RGA_FORMAT_INDEX_BUTT,
+};
+
+struct rga_win_data {
+ const char *name;
+ const uint32_t *formats[RGA_FORMAT_INDEX_BUTT];
+ uint32_t formats_count[RGA_FORMAT_INDEX_BUTT];
+
+ uint32_t supported_rotations;
+ uint32_t scale_up_mode;
+ uint32_t scale_down_mode;
+ uint32_t rd_mode;
+};
+
+struct rga_rect {
+ int width;
+ int height;
+};
+
+struct rga_rect_range {
+ struct rga_rect min;
+ struct rga_rect max;
+};
+
+struct rga_hw_data {
+ uint32_t version;
+ uint32_t feature;
+
+ uint32_t csc_r2y_mode;
+ uint32_t csc_y2r_mode;
+
+ struct rga_rect_range input_range;
+ struct rga_rect_range output_range;
+
+ unsigned int max_upscale_factor;
+ unsigned int max_downscale_factor;
+
+ uint32_t byte_stride_align;
+ uint32_t max_byte_stride;
+
+ const struct rga_win_data *win;
+ unsigned int win_size;
+
+ enum rga_mmu mmu;
+};
+
+extern const struct rga_hw_data rga3_data;
+extern const struct rga_hw_data rga2e_data;
+extern const struct rga_hw_data rga2e_1106_data;
+extern const struct rga_hw_data rga2e_iommu_data;
+
+/* Returns false if in range, true otherwise */
+static inline bool rga_hw_out_of_range(const struct rga_rect_range *range, int width, int height)
+{
+ return (width > range->max.width || height > range->max.height ||
+ width < range->min.width || height < range->min.height);
+}
+
+#endif /* __LINUX_RGA_HW_CONFIG_H_ */
diff --git a/drivers/video/rockchip/rga3/include/rga_iommu.h b/drivers/video/rockchip/rga3/include/rga_iommu.h
new file mode 100644
index 000000000..b80a1f48b
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_iommu.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __RGA_MMU_INFO_H__
+#define __RGA_MMU_INFO_H__
+
+#include "rga_drv.h"
+
+/* RGA_IOMMU register offsets */
+#define RGA_IOMMU_BASE 0xf00
+#define RGA_IOMMU_DTE_ADDR (RGA_IOMMU_BASE + 0x00) /* Directory table address */
+#define RGA_IOMMU_STATUS (RGA_IOMMU_BASE + 0x04)
+#define RGA_IOMMU_COMMAND (RGA_IOMMU_BASE + 0x08)
+#define RGA_IOMMU_PAGE_FAULT_ADDR (RGA_IOMMU_BASE + 0x0C) /* IOVA of last page fault */
+#define RGA_IOMMU_ZAP_ONE_LINE (RGA_IOMMU_BASE + 0x10) /* Shootdown one IOTLB entry */
+#define RGA_IOMMU_INT_RAWSTAT (RGA_IOMMU_BASE + 0x14) /* IRQ status ignoring mask */
+#define RGA_IOMMU_INT_CLEAR (RGA_IOMMU_BASE + 0x18) /* Acknowledge and re-arm irq */
+#define RGA_IOMMU_INT_MASK (RGA_IOMMU_BASE + 0x1C) /* IRQ enable */
+#define RGA_IOMMU_INT_STATUS (RGA_IOMMU_BASE + 0x20) /* IRQ status after masking */
+#define RGA_IOMMU_AUTO_GATING (RGA_IOMMU_BASE + 0x24)
+
+/* RGA_IOMMU_STATUS fields */
+#define RGA_IOMMU_STATUS_PAGING_ENABLED BIT(0)
+#define RGA_IOMMU_STATUS_PAGE_FAULT_ACTIVE BIT(1)
+#define RGA_IOMMU_STATUS_STALL_ACTIVE BIT(2)
+#define RGA_IOMMU_STATUS_IDLE BIT(3)
+#define RGA_IOMMU_STATUS_REPLAY_BUFFER_EMPTY BIT(4)
+#define RGA_IOMMU_STATUS_PAGE_FAULT_IS_WRITE BIT(5)
+#define RGA_IOMMU_STATUS_STALL_NOT_ACTIVE BIT(31)
+
+/* RGA_IOMMU_COMMAND command values */
+#define RGA_IOMMU_CMD_ENABLE_PAGING 0 /* Enable memory translation */
+#define RGA_IOMMU_CMD_DISABLE_PAGING 1 /* Disable memory translation */
+#define RGA_IOMMU_CMD_ENABLE_STALL 2 /* Stall paging to allow other cmds */
+#define RGA_IOMMU_CMD_DISABLE_STALL 3 /* Stop stall re-enables paging */
+#define RGA_IOMMU_CMD_ZAP_CACHE 4 /* Shoot down entire IOTLB */
+#define RGA_IOMMU_CMD_PAGE_FAULT_DONE 5 /* Clear page fault */
+#define RGA_IOMMU_CMD_FORCE_RESET 6 /* Reset all registers */
+
+/* RGA_IOMMU_INT_* register fields */
+#define RGA_IOMMU_IRQ_PAGE_FAULT 0x01 /* page fault */
+#define RGA_IOMMU_IRQ_BUS_ERROR 0x02 /* bus read error */
+#define RGA_IOMMU_IRQ_MASK (RGA_IOMMU_IRQ_PAGE_FAULT | RGA_IOMMU_IRQ_BUS_ERROR)
+
+/*
+ * The maximum input is 8192*8192, the maximum output is 4096*4096
+ * The size of physical pages requested is:
+ * (( maximum_input_value *
+ * maximum_input_value * format_bpp ) / 4K_page_size) + 1
+ */
+#define RGA2_PHY_PAGE_SIZE (((8192 * 8192 * 4) / 4096) + 1)
+
+struct rga_mmu_base {
+ unsigned int *buf_virtual;
+ struct page **pages;
+ u8 buf_order;
+ u8 pages_order;
+
+ int32_t front;
+ int32_t back;
+ int32_t size;
+ int32_t curr;
+};
+
+int rga_user_memory_check(struct page **pages, u32 w, u32 h, u32 format, int flag);
+int rga_set_mmu_base(struct rga_job *job, struct rga2_req *req);
+unsigned int *rga_mmu_buf_get(struct rga_mmu_base *mmu_base, uint32_t size);
+
+struct rga_mmu_base *rga_mmu_base_init(size_t size);
+void rga_mmu_base_free(struct rga_mmu_base **mmu_base);
+
+int rga_iommu_detach(struct rga_iommu_info *info);
+int rga_iommu_attach(struct rga_iommu_info *info);
+struct rga_iommu_info *rga_iommu_probe(struct device *dev);
+int rga_iommu_remove(struct rga_iommu_info *info);
+
+int rga_iommu_bind(void);
+void rga_iommu_unbind(void);
+
+#endif
+
diff --git a/drivers/video/rockchip/rga3/include/rga_job.h b/drivers/video/rockchip/rga3/include/rga_job.h
new file mode 100644
index 000000000..0fc776173
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_job.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#ifndef __LINUX_RKRGA_JOB_H_
+#define __LINUX_RKRGA_JOB_H_
+
+#include <linux/spinlock.h>
+#include <linux/dma-fence.h>
+
+#include "rga_drv.h"
+
+enum job_flags {
+ RGA_JOB_DONE = 1 << 0,
+ RGA_JOB_ASYNC = 1 << 1,
+ RGA_JOB_SYNC = 1 << 2,
+ RGA_JOB_USE_HANDLE = 1 << 3,
+ RGA_JOB_UNSUPPORT_RGA_MMU = 1 << 4,
+};
+
+void rga_job_scheduler_dump_info(struct rga_scheduler_t *scheduler);
+void rga_job_next(struct rga_scheduler_t *scheduler);
+struct rga_job *rga_job_done(struct rga_scheduler_t *scheduler);
+struct rga_job *rga_job_commit(struct rga_req *rga_command_base, struct rga_request *request);
+int rga_job_mpi_commit(struct rga_req *rga_command_base, struct rga_request *request);
+
+int rga_job_assign(struct rga_job *job);
+
+
+int rga_request_check(struct rga_user_request *req);
+struct rga_request *rga_request_lookup(struct rga_pending_request_manager *request_manager,
+ uint32_t id);
+
+int rga_request_commit(struct rga_request *user_request);
+void rga_request_session_destroy_abort(struct rga_session *session);
+int rga_request_put(struct rga_request *request);
+void rga_request_get(struct rga_request *request);
+int rga_request_free(struct rga_request *request);
+int rga_request_alloc(uint32_t flags, struct rga_session *session);
+
+struct rga_request *rga_request_config(struct rga_user_request *user_request);
+struct rga_request *rga_request_kernel_config(struct rga_user_request *user_request);
+int rga_request_submit(struct rga_request *request);
+int rga_request_mpi_submit(struct rga_req *req, struct rga_request *request);
+int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job *job);
+
+int rga_request_manager_init(struct rga_pending_request_manager **request_manager_session);
+int rga_request_manager_remove(struct rga_pending_request_manager **request_manager_session);
+
+#endif /* __LINUX_RKRGA_JOB_H_ */
diff --git a/drivers/video/rockchip/rga3/include/rga_mm.h b/drivers/video/rockchip/rga3/include/rga_mm.h
new file mode 100644
index 000000000..d68fd75dc
--- /dev/null
+++ b/drivers/video/rockchip/rga3/include/rga_mm.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author:
+ * Cerf Yu <cerf.yu@rock-chips.com>
+ */
+
+#ifndef __LINUX_RKRGA_MM_H_
+#define __LINUX_RKRGA_MM_H_
+
+#include "rga_drv.h"
+
+enum rga_mm_flag {
+ /* It will identify whether the buffer is within 0 ~ 4G. */
+ RGA_MEM_UNDER_4G = 1 << 0,
+ /* Logo enable IOMMU */
+ RGA_MEM_NEED_USE_IOMMU = 1 << 1,
+ /* Flag this is a physical contiguous memory. */
+ RGA_MEM_PHYSICAL_CONTIGUOUS = 1 << 2,
+ /* need force flush cache */
+ RGA_MEM_FORCE_FLUSH_CACHE = 1 << 3,
+};
+
+struct rga_mm {
+ struct mutex lock;
+
+ /*
+ * @memory_idr:
+ *
+ * Mapping of memory object handles to object pointers. Used by the GEM
+ * subsystem. Protected by @memory_lock.
+ */
+ struct idr memory_idr;
+
+ /* the count of buffer in the cached_list */
+ int buffer_count;
+};
+
+static inline bool rga_mm_is_invalid_dma_buffer(struct rga_dma_buffer *buffer)
+{
+ if (buffer == NULL)
+ return true;
+
+ return buffer->scheduler == NULL ? true : false;
+}
+
+struct rga_internal_buffer *rga_mm_lookup_handle(struct rga_mm *mm_session, uint32_t handle);
+int rga_mm_lookup_flag(struct rga_mm *mm_session, uint64_t handle);
+dma_addr_t rga_mm_lookup_iova(struct rga_internal_buffer *buffer);
+struct sg_table *rga_mm_lookup_sgt(struct rga_internal_buffer *buffer);
+
+void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer);
+void rga_mm_dump_info(struct rga_mm *session);
+
+int rga_mm_map_job_info(struct rga_job *job);
+void rga_mm_unmap_job_info(struct rga_job *job);
+
+int rga_mm_import_buffer(struct rga_external_buffer *external_buffer,
+ struct rga_session *session);
+int rga_mm_release_buffer(uint32_t handle);
+int rga_mm_session_release_buffer(struct rga_session *session);
+
+int rga_mm_init(struct rga_mm **session);
+int rga_mm_remove(struct rga_mm **session);
+
+#endif
diff --git a/drivers/video/rockchip/rga3/rga2_reg_info.c b/drivers/video/rockchip/rga3/rga2_reg_info.c
new file mode 100644
index 000000000..8792e8d64
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga2_reg_info.c
@@ -0,0 +1,2742 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga2_reg: " fmt
+
+#include "rga2_reg_info.h"
+#include "rga_dma_buf.h"
+#include "rga_iommu.h"
+#include "rga_common.h"
+#include "rga_hw_config.h"
+#include "rga_debugger.h"
+
+unsigned int rga2_rop_code[256] = {
+ 0x00000007, 0x00000451, 0x00006051, 0x00800051,
+ 0x00007041, 0x00800041, 0x00804830, 0x000004f0,//0
+ 0x00800765, 0x000004b0, 0x00000065, 0x000004f4,
+ 0x00000075, 0x000004e6, 0x00804850, 0x00800005,
+
+ 0x00006850, 0x00800050, 0x00805028, 0x00000568,
+ 0x00804031, 0x00000471, 0x002b6071, 0x018037aa,//1
+ 0x008007aa, 0x00036071, 0x00002c6a, 0x00803631,
+ 0x00002d68, 0x00802721, 0x008002d0, 0x000006d0,
+
+ 0x0080066e, 0x00000528, 0x00000066, 0x0000056c,
+ 0x018007aa, 0x0002e06a, 0x00003471, 0x00834031,//2
+ 0x00800631, 0x0002b471, 0x00006071, 0x008037aa,
+ 0x000036d0, 0x008002d4, 0x00002d28, 0x000006d4,
+
+ 0x0000006e, 0x00000565, 0x00003451, 0x00800006,
+ 0x000034f0, 0x00834830, 0x00800348, 0x00000748,//3
+ 0x00002f48, 0x0080034c, 0x000034b0, 0x0000074c,
+ 0x00000031, 0x00834850, 0x000034e6, 0x00800071,
+
+ 0x008006f4, 0x00000431, 0x018007a1, 0x00b6e870,
+ 0x00000074, 0x0000046e, 0x00002561, 0x00802f28,//4
+ 0x00800728, 0x0002a561, 0x000026c2, 0x008002c6,
+ 0x00007068, 0x018035aa, 0x00002c2a, 0x000006c6,
+
+ 0x0000006c, 0x00000475, 0x000024e2, 0x008036b0,
+ 0x00804051, 0x00800004, 0x00800251, 0x00000651,
+ 0x00002e4a, 0x0080024e, 0x00000028, 0x00824842,
+ 0x000024a2, 0x0000064e, 0x000024f4, 0x00800068,//5
+
+ 0x008006b0, 0x000234f0, 0x00002741, 0x00800345,
+ 0x00003651, 0x00800255, 0x00000030, 0x00834051,
+ 0x00a34842, 0x000002b0, 0x00800271, 0x0002b651,
+ 0x00800368, 0x0002a741, 0x0000364e, 0x00806830,//6
+
+ 0x00006870, 0x008037a2, 0x00003431, 0x00000745,
+ 0x00002521, 0x00000655, 0x0000346e, 0x00800062,
+ 0x008002f0, 0x000236d0, 0x000026d4, 0x00807028,
+ 0x000036c6, 0x00806031, 0x008005aa, 0x00000671,//7
+
+ 0x00800671, 0x000005aa, 0x00006031, 0x008036c6,
+ 0x00007028, 0x00802e55, 0x008236d0, 0x000002f0,
+ 0x00000070, 0x0080346e, 0x00800655, 0x00802521,
+ 0x00800745, 0x00803431, 0x000037a2, 0x00806870,//8
+
+ 0x00006830, 0x0080364e, 0x00822f48, 0x00000361,
+ 0x0082b651, 0x00000271, 0x00800231, 0x002b4051,
+ 0x00034051, 0x00800030, 0x0080026e, 0x00803651,
+ 0x0080036c, 0x00802741, 0x008234f0, 0x000006b0,//9
+
+ 0x00000068, 0x00802c75, 0x0080064e, 0x008024a2,
+ 0x0002c04a, 0x00800021, 0x00800275, 0x00802e51,
+ 0x00800651, 0x00000251, 0x00800000, 0x00004051,
+ 0x000036b0, 0x008024e2, 0x00800475, 0x00000045,//a
+
+ 0x008006c6, 0x00802c2a, 0x000035aa, 0x00807068,
+ 0x008002f4, 0x008026c2, 0x00822d68, 0x00000728,
+ 0x00002f28, 0x00802561, 0x0080046e, 0x00000046,
+ 0x00836870, 0x000007a2, 0x00800431, 0x00004071,//b
+
+ 0x00000071, 0x008034e6, 0x00034850, 0x00800031,
+ 0x0080074c, 0x008034b0, 0x00800365, 0x00802f48,
+ 0x00800748, 0x00000341, 0x000026a2, 0x008034f0,
+ 0x00800002, 0x00005048, 0x00800565, 0x00000055,//c
+
+ 0x008006d4, 0x00802d28, 0x008002e6, 0x008036d0,
+ 0x000037aa, 0x00806071, 0x0082b471, 0x00000631,
+ 0x00002e2a, 0x00803471, 0x00826862, 0x010007aa,
+ 0x0080056c, 0x00000054, 0x00800528, 0x00005068,//d
+
+ 0x008006d0, 0x000002d0, 0x00002721, 0x00802d68,
+ 0x00003631, 0x00802c6a, 0x00836071, 0x000007aa,
+ 0x010037aa, 0x00a36870, 0x00800471, 0x00004031,
+ 0x00800568, 0x00005028, 0x00000050, 0x00800545,//e
+
+ 0x00800001, 0x00004850, 0x008004e6, 0x0000004e,
+ 0x008004f4, 0x0000004c, 0x008004b0, 0x00004870,
+ 0x008004f0, 0x00004830, 0x00000048, 0x0080044e,
+ 0x00000051, 0x008004d4, 0x00800451, 0x00800007,//f
+};
+
+static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg)
+{
+ u32 *bRGA_SRC_X_FACTOR;
+ u32 *bRGA_SRC_Y_FACTOR;
+ u32 sw, sh;
+ u32 dw, dh;
+ u32 param_x, param_y;
+
+ bRGA_SRC_X_FACTOR = (u32 *) (base + RGA2_SRC_X_FACTOR_OFFSET);
+ bRGA_SRC_Y_FACTOR = (u32 *) (base + RGA2_SRC_Y_FACTOR_OFFSET);
+
+ if (((msg->rotate_mode & 0x3) == 1) ||
+ ((msg->rotate_mode & 0x3) == 3)) {
+ dw = msg->dst.act_h;
+ dh = msg->dst.act_w;
+ } else {
+ dw = msg->dst.act_w;
+ dh = msg->dst.act_h;
+ }
+
+ sw = msg->src.act_w;
+ sh = msg->src.act_h;
+
+ if (sw > dw) {
+#if SCALE_DOWN_LARGE
+ param_x = ((dw) << 16) / (sw) + 1;
+#else
+ param_x = ((dw) << 16) / (sw);
+#endif
+ *bRGA_SRC_X_FACTOR |= ((param_x & 0xffff) << 0);
+ } else if (sw < dw) {
+#if SCALE_UP_LARGE
+ param_x = ((sw - 1) << 16) / (dw - 1);
+#else
+ param_x = ((sw) << 16) / (dw);
+#endif
+ *bRGA_SRC_X_FACTOR |= ((param_x & 0xffff) << 16);
+ } else {
+ *bRGA_SRC_X_FACTOR = 0; //((1 << 14) << 16) | (1 << 14);
+ }
+
+ if (sh > dh) {
+#if SCALE_DOWN_LARGE
+ param_y = ((dh) << 16) / (sh) + 1;
+#else
+ param_y = ((dh) << 16) / (sh);
+#endif
+ *bRGA_SRC_Y_FACTOR |= ((param_y & 0xffff) << 0);
+ } else if (sh < dh) {
+#if SCALE_UP_LARGE
+ param_y = ((sh - 1) << 16) / (dh - 1);
+#else
+ param_y = ((sh) << 16) / (dh);
+#endif
+ *bRGA_SRC_Y_FACTOR |= ((param_y & 0xffff) << 16);
+ } else {
+ *bRGA_SRC_Y_FACTOR = 0; //((1 << 14) << 16) | (1 << 14);
+ }
+}
+
+static void RGA2_set_mode_ctrl(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_MODE_CTL;
+ u32 reg = 0;
+ u32 render_mode = msg->render_mode;
+
+ bRGA_MODE_CTL = (u32 *) (base + RGA2_MODE_CTRL_OFFSET);
+
+ if (msg->render_mode == UPDATE_PALETTE_TABLE_MODE)
+ render_mode = 0x3;
+
+ reg =
+ ((reg & (~m_RGA2_MODE_CTRL_SW_RENDER_MODE)) |
+ (s_RGA2_MODE_CTRL_SW_RENDER_MODE(render_mode)));
+ reg =
+ ((reg & (~m_RGA2_MODE_CTRL_SW_BITBLT_MODE)) |
+ (s_RGA2_MODE_CTRL_SW_BITBLT_MODE(msg->bitblt_mode)));
+ reg =
+ ((reg & (~m_RGA2_MODE_CTRL_SW_CF_ROP4_PAT)) |
+ (s_RGA2_MODE_CTRL_SW_CF_ROP4_PAT(msg->color_fill_mode)));
+ reg =
+ ((reg & (~m_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET)) |
+ (s_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET(msg->alpha_zero_key)));
+ reg =
+ ((reg & (~m_RGA2_MODE_CTRL_SW_GRADIENT_SAT)) |
+ (s_RGA2_MODE_CTRL_SW_GRADIENT_SAT(msg->alpha_rop_flag >> 7)));
+ reg =
+ ((reg & (~m_RGA2_MODE_CTRL_SW_INTR_CF_E)) |
+ (s_RGA2_MODE_CTRL_SW_INTR_CF_E(msg->CMD_fin_int_enable)));
+
+ reg = ((reg & (~m_RGA2_MODE_CTRL_SW_MOSAIC_EN)) |
+ (s_RGA2_MODE_CTRL_SW_MOSAIC_EN(msg->mosaic_info.enable)));
+
+ reg = ((reg & (~m_RGA2_MODE_CTRL_SW_YIN_YOUT_EN)) |
+ (s_RGA2_MODE_CTRL_SW_YIN_YOUT_EN(msg->yin_yout_en)));
+
+ reg = ((reg & (~m_RGA2_MODE_CTRL_SW_OSD_E)) |
+ (s_RGA2_MODE_CTRL_SW_OSD_E(msg->osd_info.enable)));
+
+ *bRGA_MODE_CTL = reg;
+}
+
+static void RGA2_set_reg_src_info(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_SRC_INFO;
+ u32 *bRGA_SRC_BASE0, *bRGA_SRC_BASE1, *bRGA_SRC_BASE2;
+ u32 *bRGA_SRC_VIR_INFO;
+ u32 *bRGA_SRC_ACT_INFO;
+ u32 *bRGA_MASK_ADDR;
+ u32 *bRGA_SRC_TR_COLOR0, *bRGA_SRC_TR_COLOR1;
+
+ u8 disable_uv_channel_en = 0;
+
+ u32 reg = 0;
+ u8 src0_format = 0;
+
+ u8 src0_rb_swp = 0;
+ u8 src0_alpha_swp = 0;
+
+ u8 src0_cbcr_swp = 0;
+ u8 pixel_width = 1;
+ u32 stride = 0;
+ u32 uv_stride = 0;
+ u32 mask_stride = 0;
+ u32 ydiv = 1, xdiv = 2;
+ u8 yuv10 = 0;
+
+ u32 sw, sh;
+ u32 dw, dh;
+ u8 rotate_mode;
+ u8 vsp_scale_mode = 0;
+ u8 scale_w_flag, scale_h_flag;
+
+ bRGA_SRC_INFO = (u32 *) (base + RGA2_SRC_INFO_OFFSET);
+
+ bRGA_SRC_BASE0 = (u32 *) (base + RGA2_SRC_BASE0_OFFSET);
+ bRGA_SRC_BASE1 = (u32 *) (base + RGA2_SRC_BASE1_OFFSET);
+ bRGA_SRC_BASE2 = (u32 *) (base + RGA2_SRC_BASE2_OFFSET);
+
+ bRGA_SRC_VIR_INFO = (u32 *) (base + RGA2_SRC_VIR_INFO_OFFSET);
+ bRGA_SRC_ACT_INFO = (u32 *) (base + RGA2_SRC_ACT_INFO_OFFSET);
+
+ bRGA_MASK_ADDR = (u32 *) (base + RGA2_MASK_BASE_OFFSET);
+
+ bRGA_SRC_TR_COLOR0 = (u32 *) (base + RGA2_SRC_TR_COLOR0_OFFSET);
+ bRGA_SRC_TR_COLOR1 = (u32 *) (base + RGA2_SRC_TR_COLOR1_OFFSET);
+
+ if (msg->src.format == RGA_FORMAT_YCbCr_420_SP_10B ||
+ msg->src.format == RGA_FORMAT_YCrCb_420_SP_10B) {
+ if ((msg->src.act_w == msg->dst.act_w) &&
+ (msg->src.act_h == msg->dst.act_h) &&
+ (msg->rotate_mode == 0))
+ msg->rotate_mode = 1 << 6;
+ }
+
+ {
+ rotate_mode = msg->rotate_mode & 0x3;
+
+ sw = msg->src.act_w;
+ sh = msg->src.act_h;
+
+ if ((rotate_mode == 1) | (rotate_mode == 3)) {
+ dw = msg->dst.act_h;
+ dh = msg->dst.act_w;
+ } else {
+ dw = msg->dst.act_w;
+ dh = msg->dst.act_h;
+ }
+
+ if (sw > dw)
+ scale_w_flag = 1;
+ else if (sw < dw)
+ scale_w_flag = 2;
+ else {
+ scale_w_flag = 0;
+ if (msg->rotate_mode >> 6)
+ scale_w_flag = 3;
+ }
+
+ if (sh > dh)
+ scale_h_flag = 1;
+ else if (sh < dh)
+ scale_h_flag = 2;
+ else {
+ scale_h_flag = 0;
+ if (msg->rotate_mode >> 6)
+ scale_h_flag = 3;
+ }
+
+ /* uvvds need to force tile mode. */
+ if (msg->uvvds_mode && scale_w_flag == 0)
+ scale_w_flag = 3;
+ }
+
+ /* VSP scale mode select, HSD > VSD > VSP > HSP */
+ if (scale_h_flag == 0x2) {
+ /* After HSD, VSP needs to check dst_width */
+ if ((scale_w_flag == 0x1) && (dw < RGA2_VSP_BICUBIC_LIMIT))
+ vsp_scale_mode = 0x0;
+ else if (sw < RGA2_VSP_BICUBIC_LIMIT)
+ vsp_scale_mode = 0x0;
+ else
+ /* default select bilinear */
+ vsp_scale_mode = 0x1;
+ }
+
+ switch (msg->src.format) {
+ case RGA_FORMAT_RGBA_8888:
+ src0_format = 0x0;
+ pixel_width = 4;
+ break;
+ case RGA_FORMAT_BGRA_8888:
+ src0_format = 0x0;
+ src0_rb_swp = 0x1;
+ pixel_width = 4;
+ break;
+ case RGA_FORMAT_RGBX_8888:
+ src0_format = 0x1;
+ pixel_width = 4;
+ msg->src_trans_mode &= 0x07;
+ break;
+ case RGA_FORMAT_BGRX_8888:
+ src0_format = 0x1;
+ src0_rb_swp = 0x1;
+ pixel_width = 4;
+ msg->src_trans_mode &= 0x07;
+ break;
+ case RGA_FORMAT_RGB_888:
+ src0_format = 0x2;
+ pixel_width = 3;
+ msg->src_trans_mode &= 0x07;
+ break;
+ case RGA_FORMAT_BGR_888:
+ src0_format = 0x2;
+ src0_rb_swp = 1;
+ pixel_width = 3;
+ msg->src_trans_mode &= 0x07;
+ break;
+ case RGA_FORMAT_RGB_565:
+ src0_format = 0x4;
+ pixel_width = 2;
+ msg->src_trans_mode &= 0x07;
+ break;
+ case RGA_FORMAT_RGBA_5551:
+ src0_format = 0x5;
+ pixel_width = 2;
+ break;
+ case RGA_FORMAT_RGBA_4444:
+ src0_format = 0x6;
+ pixel_width = 2;
+ break;
+ case RGA_FORMAT_BGR_565:
+ src0_format = 0x4;
+ pixel_width = 2;
+ msg->src_trans_mode &= 0x07;
+ src0_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_BGRA_5551:
+ src0_format = 0x5;
+ pixel_width = 2;
+ src0_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_BGRA_4444:
+ src0_format = 0x6;
+ pixel_width = 2;
+ src0_rb_swp = 0x1;
+ break;
+
+ /* ARGB */
+ /*
+ * In colorkey mode, xrgb/xbgr does not
+ * need to enable the alpha channel
+ */
+ case RGA_FORMAT_ARGB_8888:
+ src0_format = 0x0;
+ pixel_width = 4;
+ src0_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_8888:
+ src0_format = 0x0;
+ pixel_width = 4;
+ src0_alpha_swp = 1;
+ src0_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_XRGB_8888:
+ src0_format = 0x1;
+ pixel_width = 4;
+ src0_alpha_swp = 1;
+ msg->src_trans_mode &= 0x07;
+ break;
+ case RGA_FORMAT_XBGR_8888:
+ src0_format = 0x1;
+ pixel_width = 4;
+ src0_alpha_swp = 1;
+ src0_rb_swp = 0x1;
+ msg->src_trans_mode &= 0x07;
+ break;
+ case RGA_FORMAT_ARGB_5551:
+ src0_format = 0x5;
+ pixel_width = 2;
+ src0_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_5551:
+ src0_format = 0x5;
+ pixel_width = 2;
+ src0_alpha_swp = 1;
+ src0_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_ARGB_4444:
+ src0_format = 0x6;
+ pixel_width = 2;
+ src0_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_4444:
+ src0_format = 0x6;
+ pixel_width = 2;
+ src0_alpha_swp = 1;
+ src0_rb_swp = 0x1;
+ break;
+
+ case RGA_FORMAT_YVYU_422:
+ src0_format = 0x7;
+ pixel_width = 2;
+ src0_cbcr_swp = 1;
+ src0_rb_swp = 0x1;
+ break; //rbswap=ycswap
+ case RGA_FORMAT_VYUY_422:
+ src0_format = 0x7;
+ pixel_width = 2;
+ src0_cbcr_swp = 1;
+ src0_rb_swp = 0x0;
+ break;
+ case RGA_FORMAT_YUYV_422:
+ src0_format = 0x7;
+ pixel_width = 2;
+ src0_cbcr_swp = 0;
+ src0_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_UYVY_422:
+ src0_format = 0x7;
+ pixel_width = 2;
+ src0_cbcr_swp = 0;
+ src0_rb_swp = 0x0;
+ break;
+
+ case RGA_FORMAT_YCbCr_422_SP:
+ src0_format = 0x8;
+ xdiv = 1;
+ ydiv = 1;
+ break;
+ case RGA_FORMAT_YCbCr_422_P:
+ src0_format = 0x9;
+ xdiv = 2;
+ ydiv = 1;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP:
+ src0_format = 0xa;
+ xdiv = 1;
+ ydiv = 2;
+ break;
+ case RGA_FORMAT_YCbCr_420_P:
+ src0_format = 0xb;
+ xdiv = 2;
+ ydiv = 2;
+ break;
+ case RGA_FORMAT_YCrCb_422_SP:
+ src0_format = 0x8;
+ xdiv = 1;
+ ydiv = 1;
+ src0_cbcr_swp = 1;
+ break;
+ case RGA_FORMAT_YCrCb_422_P:
+ src0_format = 0x9;
+ xdiv = 2;
+ ydiv = 1;
+ src0_cbcr_swp = 1;
+ break;
+ case RGA_FORMAT_YCrCb_420_SP:
+ src0_format = 0xa;
+ xdiv = 1;
+ ydiv = 2;
+ src0_cbcr_swp = 1;
+ break;
+ case RGA_FORMAT_YCrCb_420_P:
+ src0_format = 0xb;
+ xdiv = 2;
+ ydiv = 2;
+ src0_cbcr_swp = 1;
+ break;
+
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ src0_format = 0xa;
+ xdiv = 1;
+ ydiv = 2;
+ yuv10 = 1;
+ break;
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ src0_format = 0xa;
+ xdiv = 1;
+ ydiv = 2;
+ src0_cbcr_swp = 1;
+ yuv10 = 1;
+ break;
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ src0_format = 0x8;
+ xdiv = 1;
+ ydiv = 1;
+ yuv10 = 1;
+ break;
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ src0_format = 0x8;
+ xdiv = 1;
+ ydiv = 1;
+ src0_cbcr_swp = 1;
+ yuv10 = 1;
+ break;
+
+ case RGA_FORMAT_YCbCr_400:
+ src0_format = 0x8;
+ /* When Yin_Yout is enabled, no need to go through the software. */
+ disable_uv_channel_en = msg->yin_yout_en ? false : true;
+ xdiv = 1;
+ ydiv = 1;
+ break;
+ };
+
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SRC_FMT)) |
+ (s_RGA2_SRC_INFO_SW_SRC_FMT(src0_format)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP(src0_rb_swp)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP(src0_alpha_swp)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP(src0_cbcr_swp)));
+
+ if (msg->src1.format == RGA_FORMAT_RGBA_2BPP)
+ reg = ((reg & (~m_RGA2_SRC_INFO_SW_SW_CP_ENDIAN)) |
+ (s_RGA2_SRC_INFO_SW_SW_CP_ENDAIN(msg->osd_info.bpp2_info.endian_swap & 1)));
+
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE(msg->yuv2rgb_mode)));
+
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE(msg->rotate_mode & 0x3)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE
+ ((msg->rotate_mode >> 4) & 0x3)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE((scale_w_flag))));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE((scale_h_flag))));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER((
+ msg->scale_bicu_mode))));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE(msg->src_trans_mode)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E(msg->src_trans_mode >> 1)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E)) |
+ (s_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E
+ ((msg->alpha_rop_flag >> 4) & 0x1)));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL)) |
+ (s_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL((vsp_scale_mode))));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_YUV10_E)) |
+ (s_RGA2_SRC_INFO_SW_SW_YUV10_E((yuv10))));
+
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E)) |
+ (s_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E((yuv10))));
+
+ RGA2_reg_get_param(base, msg);
+
+ stride = (((msg->src.vir_w * pixel_width) + 3) & ~3) >> 2;
+ uv_stride = ((msg->src.vir_w / xdiv + 3) & ~3);
+
+ if (disable_uv_channel_en == 1) {
+ /*
+ * When Y400 as the input format, because the current
+ * RGA does not support closing
+ * the access of the UV channel, the address of the UV
+ * channel access is equal to
+ * the address of the Y channel access to ensure that
+ * the UV channel can access,
+ * preventing the RGA hardware from reporting errors.
+ */
+ *bRGA_SRC_BASE0 =
+ (u32) (msg->src.yrgb_addr +
+ msg->src.y_offset * (stride << 2) +
+ msg->src.x_offset * pixel_width);
+ *bRGA_SRC_BASE1 = *bRGA_SRC_BASE0;
+ *bRGA_SRC_BASE2 = *bRGA_SRC_BASE0;
+ } else {
+ *bRGA_SRC_BASE0 =
+ (u32) (msg->src.yrgb_addr +
+ msg->src.y_offset * (stride << 2) +
+ msg->src.x_offset * pixel_width);
+ *bRGA_SRC_BASE1 =
+ (u32) (msg->src.uv_addr +
+ (msg->src.y_offset / ydiv) * uv_stride +
+ (msg->src.x_offset / xdiv));
+ *bRGA_SRC_BASE2 =
+ (u32) (msg->src.v_addr +
+ (msg->src.y_offset / ydiv) * uv_stride +
+ (msg->src.x_offset / xdiv));
+ }
+
+ //mask_stride = ((msg->src0_act.width + 31) & ~31) >> 5;
+ mask_stride = msg->rop_mask_stride;
+
+ *bRGA_SRC_VIR_INFO = stride | (mask_stride << 16);
+
+ *bRGA_SRC_ACT_INFO =
+ (msg->src.act_w - 1) | ((msg->src.act_h - 1) << 16);
+
+ *bRGA_MASK_ADDR = (u32) msg->rop_mask_addr;
+
+ *bRGA_SRC_INFO = reg;
+
+ *bRGA_SRC_TR_COLOR0 = msg->color_key_min;
+ *bRGA_SRC_TR_COLOR1 = msg->color_key_max;
+}
+
+static void RGA2_set_reg_dst_info(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_DST_INFO;
+ u32 *bRGA_DST_BASE0, *bRGA_DST_BASE1, *bRGA_DST_BASE2,
+ *bRGA_SRC_BASE3;
+ u32 *bRGA_DST_VIR_INFO;
+ u32 *bRGA_DST_ACT_INFO;
+
+ u32 *RGA_DST_Y4MAP_LUT0; //Y4 LUT0
+ u32 *RGA_DST_Y4MAP_LUT1; //Y4 LUT1
+ u32 *RGA_DST_NN_QUANTIZE_SCALE;
+ u32 *RGA_DST_NN_QUANTIZE_OFFSET;
+
+ u32 line_width_real;
+
+ u8 ydither_en = 0;
+
+ u8 src1_format = 0;
+ u8 src1_rb_swp = 0;
+ u8 src1_alpha_swp = 0;
+
+ u8 dst_format = 0;
+ u8 dst_rb_swp = 0;
+ u8 dst_cbcr_swp = 0;
+ u8 dst_alpha_swp = 0;
+
+ u8 dst_fmt_yuv400_en = 0;
+ u8 dst_fmt_y4_en = 0;
+ u8 dst_nn_quantize_en = 0;
+
+ u32 reg = 0;
+ u8 spw, dpw;
+ u8 bbp_shift = 0;
+ u32 s_stride, d_stride;
+ u32 x_mirr, y_mirr, rot_90_flag;
+ u32 yrgb_addr, u_addr, v_addr, s_yrgb_addr;
+ u32 d_uv_stride, x_div, y_div;
+ u32 y_lt_addr, y_ld_addr, y_rt_addr, y_rd_addr;
+ u32 u_lt_addr, u_ld_addr, u_rt_addr, u_rd_addr;
+ u32 v_lt_addr, v_ld_addr, v_rt_addr, v_rd_addr;
+
+ dpw = 1;
+ x_div = y_div = 1;
+
+ dst_nn_quantize_en = (msg->alpha_rop_flag >> 8) & 0x1;
+
+ bRGA_DST_INFO = (u32 *) (base + RGA2_DST_INFO_OFFSET);
+ bRGA_DST_BASE0 = (u32 *) (base + RGA2_DST_BASE0_OFFSET);
+ bRGA_DST_BASE1 = (u32 *) (base + RGA2_DST_BASE1_OFFSET);
+ bRGA_DST_BASE2 = (u32 *) (base + RGA2_DST_BASE2_OFFSET);
+
+ bRGA_SRC_BASE3 = (u32 *) (base + RGA2_SRC_BASE3_OFFSET);
+
+ bRGA_DST_VIR_INFO = (u32 *) (base + RGA2_DST_VIR_INFO_OFFSET);
+ bRGA_DST_ACT_INFO = (u32 *) (base + RGA2_DST_ACT_INFO_OFFSET);
+
+ RGA_DST_Y4MAP_LUT0 = (u32 *) (base + RGA2_DST_Y4MAP_LUT0_OFFSET);
+ RGA_DST_Y4MAP_LUT1 = (u32 *) (base + RGA2_DST_Y4MAP_LUT1_OFFSET);
+ RGA_DST_NN_QUANTIZE_SCALE =
+ (u32 *) (base + RGA2_DST_QUANTIZE_SCALE_OFFSET);
+ RGA_DST_NN_QUANTIZE_OFFSET =
+ (u32 *) (base + RGA2_DST_QUANTIZE_OFFSET_OFFSET);
+
+ switch (msg->src1.format) {
+ case RGA_FORMAT_RGBA_8888:
+ src1_format = 0x0;
+ spw = 4;
+ break;
+ case RGA_FORMAT_BGRA_8888:
+ src1_format = 0x0;
+ src1_rb_swp = 0x1;
+ spw = 4;
+ break;
+ case RGA_FORMAT_RGBX_8888:
+ src1_format = 0x1;
+ spw = 4;
+ break;
+ case RGA_FORMAT_BGRX_8888:
+ src1_format = 0x1;
+ src1_rb_swp = 0x1;
+ spw = 4;
+ break;
+ case RGA_FORMAT_RGB_888:
+ src1_format = 0x2;
+ spw = 3;
+ break;
+ case RGA_FORMAT_BGR_888:
+ src1_format = 0x2;
+ src1_rb_swp = 1;
+ spw = 3;
+ break;
+ case RGA_FORMAT_RGB_565:
+ src1_format = 0x4;
+ spw = 2;
+ break;
+ case RGA_FORMAT_RGBA_5551:
+ src1_format = 0x5;
+ spw = 2;
+ break;
+ case RGA_FORMAT_RGBA_4444:
+ src1_format = 0x6;
+ spw = 2;
+ break;
+ case RGA_FORMAT_BGR_565:
+ src1_format = 0x4;
+ spw = 2;
+ src1_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_BGRA_5551:
+ src1_format = 0x5;
+ spw = 2;
+ src1_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_BGRA_4444:
+ src1_format = 0x6;
+ spw = 2;
+ src1_rb_swp = 0x1;
+ break;
+
+ /* ARGB */
+ case RGA_FORMAT_ARGB_8888:
+ src1_format = 0x0;
+ spw = 4;
+ src1_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_8888:
+ src1_format = 0x0;
+ spw = 4;
+ src1_alpha_swp = 1;
+ src1_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_XRGB_8888:
+ src1_format = 0x1;
+ spw = 4;
+ src1_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_XBGR_8888:
+ src1_format = 0x1;
+ spw = 4;
+ src1_alpha_swp = 1;
+ src1_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_ARGB_5551:
+ src1_format = 0x5;
+ spw = 2;
+ src1_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_5551:
+ src1_format = 0x5;
+ spw = 2;
+ src1_alpha_swp = 1;
+ src1_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_ARGB_4444:
+ src1_format = 0x6;
+ spw = 2;
+ src1_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_4444:
+ src1_format = 0x6;
+ spw = 2;
+ src1_alpha_swp = 1;
+ src1_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_RGBA_2BPP:
+ src1_format = 0x0;
+ spw = 1;
+ /* 2BPP = 8 >> 2 = 2bit */
+ bbp_shift = 2;
+ src1_alpha_swp = msg->osd_info.bpp2_info.ac_swap;
+ break;
+ default:
+ spw = 4;
+ break;
+ };
+
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_FMT)) |
+ (s_RGA2_DST_INFO_SW_SRC1_FMT(src1_format)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_RB_SWP)) |
+ (s_RGA2_DST_INFO_SW_SRC1_RB_SWP(src1_rb_swp)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP)) |
+ (s_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP(src1_alpha_swp)));
+
+ switch (msg->dst.format) {
+ case RGA_FORMAT_RGBA_8888:
+ dst_format = 0x0;
+ dpw = 4;
+ break;
+ case RGA_FORMAT_BGRA_8888:
+ dst_format = 0x0;
+ dst_rb_swp = 0x1;
+ dpw = 4;
+ break;
+ case RGA_FORMAT_RGBX_8888:
+ dst_format = 0x1;
+ dpw = 4;
+ break;
+ case RGA_FORMAT_BGRX_8888:
+ dst_format = 0x1;
+ dst_rb_swp = 0x1;
+ dpw = 4;
+ break;
+ case RGA_FORMAT_RGB_888:
+ dst_format = 0x2;
+ dpw = 3;
+ break;
+ case RGA_FORMAT_BGR_888:
+ dst_format = 0x2;
+ dst_rb_swp = 1;
+ dpw = 3;
+ break;
+ case RGA_FORMAT_RGB_565:
+ dst_format = 0x4;
+ dpw = 2;
+ break;
+ case RGA_FORMAT_RGBA_5551:
+ dst_format = 0x5;
+ dpw = 2;
+ break;
+ case RGA_FORMAT_RGBA_4444:
+ dst_format = 0x6;
+ dpw = 2;
+ break;
+ case RGA_FORMAT_BGR_565:
+ dst_format = 0x4;
+ dpw = 2;
+ dst_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_BGRA_5551:
+ dst_format = 0x5;
+ dpw = 2;
+ dst_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_BGRA_4444:
+ dst_format = 0x6;
+ dpw = 2;
+ dst_rb_swp = 0x1;
+ break;
+
+ /* ARGB */
+ case RGA_FORMAT_ARGB_8888:
+ dst_format = 0x0;
+ dpw = 4;
+ dst_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_8888:
+ dst_format = 0x0;
+ dpw = 4;
+ dst_alpha_swp = 1;
+ dst_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_XRGB_8888:
+ dst_format = 0x1;
+ dpw = 4;
+ dst_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_XBGR_8888:
+ dst_format = 0x1;
+ dpw = 4;
+ dst_alpha_swp = 1;
+ dst_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_ARGB_5551:
+ dst_format = 0x5;
+ dpw = 2;
+ dst_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_5551:
+ dst_format = 0x5;
+ dpw = 2;
+ dst_alpha_swp = 1;
+ dst_rb_swp = 0x1;
+ break;
+ case RGA_FORMAT_ARGB_4444:
+ dst_format = 0x6;
+ dpw = 2;
+ dst_alpha_swp = 1;
+ break;
+ case RGA_FORMAT_ABGR_4444:
+ dst_format = 0x6;
+ dpw = 2;
+ dst_alpha_swp = 1;
+ dst_rb_swp = 0x1;
+ break;
+
+ case RGA_FORMAT_YCbCr_422_SP:
+ dst_format = 0x8;
+ x_div = 1;
+ y_div = 1;
+ break;
+ case RGA_FORMAT_YCbCr_422_P:
+ dst_format = 0x9;
+ x_div = 2;
+ y_div = 1;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP:
+ dst_format = 0xa;
+ x_div = 1;
+ y_div = 2;
+ break;
+ case RGA_FORMAT_YCbCr_420_P:
+ dst_format = 0xb;
+ dst_cbcr_swp = 1;
+ x_div = 2;
+ y_div = 2;
+ break;
+ case RGA_FORMAT_YCrCb_422_SP:
+ dst_format = 0x8;
+ dst_cbcr_swp = 1;
+ x_div = 1;
+ y_div = 1;
+ break;
+ case RGA_FORMAT_YCrCb_422_P:
+ dst_format = 0x9;
+ dst_cbcr_swp = 1;
+ x_div = 2;
+ y_div = 1;
+ break;
+ case RGA_FORMAT_YCrCb_420_SP:
+ dst_format = 0xa;
+ dst_cbcr_swp = 1;
+ x_div = 1;
+ y_div = 2;
+ break;
+ case RGA_FORMAT_YCrCb_420_P:
+ dst_format = 0xb;
+ x_div = 2;
+ y_div = 2;
+ break;
+
+ case RGA_FORMAT_YCbCr_400:
+ dst_format = 0x8;
+ dst_fmt_yuv400_en = 1;
+ x_div = 1;
+ y_div = 1;
+ break;
+ case RGA_FORMAT_Y4:
+ dst_format = 0x8;
+ dst_fmt_y4_en = 1;
+ dst_fmt_yuv400_en = 1;
+ x_div = 1;
+ y_div = 1;
+ break;
+
+ case RGA_FORMAT_YUYV_422:
+ dst_format = 0xe;
+ dpw = 2;
+ dst_cbcr_swp = 1;
+ break;
+ case RGA_FORMAT_YVYU_422:
+ dst_format = 0xe;
+ dpw = 2;
+ break;
+ case RGA_FORMAT_YUYV_420:
+ dst_format = 0xf;
+ dpw = 2;
+ dst_cbcr_swp = 1;
+ break;
+ case RGA_FORMAT_YVYU_420:
+ dst_format = 0xf;
+ dpw = 2;
+ break;
+ case RGA_FORMAT_UYVY_422:
+ dst_format = 0xc;
+ dpw = 2;
+ dst_cbcr_swp = 1;
+ break;
+ case RGA_FORMAT_VYUY_422:
+ dst_format = 0xc;
+ dpw = 2;
+ break;
+ case RGA_FORMAT_UYVY_420:
+ dst_format = 0xd;
+ dpw = 2;
+ dst_cbcr_swp = 1;
+ break;
+ case RGA_FORMAT_VYUY_420:
+ dst_format = 0xd;
+ dpw = 2;
+ break;
+ };
+
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_FMT)) |
+ (s_RGA2_DST_INFO_SW_DST_FMT(dst_format)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_RB_SWAP)) |
+ (s_RGA2_DST_INFO_SW_DST_RB_SWAP(dst_rb_swp)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_ALPHA_SWAP)) |
+ (s_RGA2_DST_INFO_SW_ALPHA_SWAP(dst_alpha_swp)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_UV_SWAP)) |
+ (s_RGA2_DST_INFO_SW_DST_UV_SWAP(dst_cbcr_swp)));
+
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN)) |
+ (s_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN(dst_fmt_yuv400_en)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_FMT_Y4_EN)) |
+ (s_RGA2_DST_INFO_SW_DST_FMT_Y4_EN(dst_fmt_y4_en)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN)) |
+ (s_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN(dst_nn_quantize_en)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DITHER_UP_E)) |
+ (s_RGA2_DST_INFO_SW_DITHER_UP_E(msg->alpha_rop_flag >> 5)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DITHER_DOWN_E)) |
+ (s_RGA2_DST_INFO_SW_DITHER_DOWN_E(msg->alpha_rop_flag >> 6)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DITHER_MODE)) |
+ (s_RGA2_DST_INFO_SW_DITHER_MODE(msg->dither_mode)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_CSC_MODE)) |
+ (s_RGA2_DST_INFO_SW_DST_CSC_MODE(msg->yuv2rgb_mode >> 2)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_CSC_CLIP_MODE)) |
+ (s_RGA2_DST_INFO_SW_CSC_CLIP_MODE(msg->yuv2rgb_mode >> 4)));
+ /* full csc enable */
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_DST_CSC_MODE_2)) |
+ (s_RGA2_DST_INFO_SW_DST_CSC_MODE_2(msg->full_csc_en)));
+ /*
+ * Some older chips do not support src1 csc mode,
+ * they do not have these two registers.
+ */
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_CSC_MODE)) |
+ (s_RGA2_DST_INFO_SW_SRC1_CSC_MODE(msg->yuv2rgb_mode >> 5)));
+ reg =
+ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE)) |
+ (s_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE(
+ msg->yuv2rgb_mode >> 7)));
+
+ reg = ((reg & (~m_RGA2_DST_INFO_SW_DST_UVHDS_MODE)) |
+ (s_RGA2_DST_INFO_SW_DST_UVHDS_MODE(msg->uvhds_mode)));
+ reg = ((reg & (~m_RGA2_DST_INFO_SW_DST_UVVDS_MODE)) |
+ (s_RGA2_DST_INFO_SW_DST_UVVDS_MODE(msg->uvvds_mode)));
+
+ ydither_en = (msg->dst.format == RGA_FORMAT_Y4)
+ && ((msg->alpha_rop_flag >> 6) & 0x1);
+
+ *bRGA_DST_INFO = reg;
+
+ s_stride = (((msg->src1.vir_w * spw >> bbp_shift) + 3) & ~3) >> 2;
+ d_stride = ((msg->dst.vir_w * dpw + 3) & ~3) >> 2;
+
+ if (dst_fmt_y4_en) {
+ /* Y4 output will HALF */
+ d_stride = ((d_stride + 1) & ~1) >> 1;
+ }
+
+ d_uv_stride = (d_stride << 2) / x_div;
+
+ *bRGA_DST_VIR_INFO = d_stride | (s_stride << 16);
+ if ((msg->dst.vir_w % 2 != 0) &&
+ (msg->dst.act_w == msg->src.act_w)
+ && (msg->dst.act_h == msg->src.act_h)
+ && (msg->dst.format == RGA_FORMAT_BGR_888
+ || msg->dst.format == RGA_FORMAT_RGB_888))
+ *bRGA_DST_ACT_INFO =
+ (msg->dst.act_w) | ((msg->dst.act_h - 1) << 16);
+ else
+ *bRGA_DST_ACT_INFO =
+ (msg->dst.act_w - 1) | ((msg->dst.act_h - 1) << 16);
+ s_stride <<= 2;
+ d_stride <<= 2;
+
+ if (((msg->rotate_mode & 0xf) == 0) ||
+ ((msg->rotate_mode & 0xf) == 1)) {
+ x_mirr = 0;
+ y_mirr = 0;
+ } else {
+ x_mirr = 1;
+ y_mirr = 1;
+ }
+
+ rot_90_flag = msg->rotate_mode & 1;
+ x_mirr = (x_mirr + ((msg->rotate_mode >> 4) & 1)) & 1;
+ y_mirr = (y_mirr + ((msg->rotate_mode >> 5) & 1)) & 1;
+
+ if (ydither_en) {
+ if (x_mirr && y_mirr) {
+ pr_err("ydither mode do not support rotate x_mirr=%d,y_mirr=%d\n",
+ x_mirr, y_mirr);
+ }
+
+ if (msg->dst.act_w != msg->src.act_w)
+ pr_err("ydither mode do not support x dir scale\n");
+
+ if (msg->dst.act_h != msg->src.act_h)
+ pr_err("ydither mode do not support y dir scale\n");
+ }
+
+ if (dst_fmt_y4_en) {
+ *RGA_DST_Y4MAP_LUT0 = (msg->gr_color.gr_x_r & 0xffff) |
+ (msg->gr_color.gr_x_g << 16);
+ *RGA_DST_Y4MAP_LUT1 = (msg->gr_color.gr_y_r & 0xffff) |
+ (msg->gr_color.gr_y_g << 16);
+ }
+
+ if (dst_nn_quantize_en) {
+ *RGA_DST_NN_QUANTIZE_SCALE = (msg->gr_color.gr_x_r & 0xffff) |
+ (msg->gr_color.gr_x_g << 10) |
+ (msg->gr_color.gr_x_b << 20);
+ *RGA_DST_NN_QUANTIZE_OFFSET = (msg->gr_color.gr_y_r & 0xffff) |
+ (msg->gr_color.gr_y_g << 10) |
+ (msg->gr_color.gr_y_b << 20);
+ }
+
+ s_yrgb_addr =
+ (u32) msg->src1.yrgb_addr + (msg->src1.y_offset * s_stride) +
+ (msg->src1.x_offset * spw >> bbp_shift);
+
+ *bRGA_SRC_BASE3 = s_yrgb_addr;
+
+ if (dst_fmt_y4_en) {
+ yrgb_addr = (u32) msg->dst.yrgb_addr +
+ (msg->dst.y_offset * d_stride) +
+ ((msg->dst.x_offset * dpw) >> 1);
+ } else {
+ yrgb_addr = (u32) msg->dst.yrgb_addr +
+ (msg->dst.y_offset * d_stride) +
+ (msg->dst.x_offset * dpw);
+ }
+ u_addr = (u32) msg->dst.uv_addr +
+ (msg->dst.y_offset / y_div) * d_uv_stride +
+ msg->dst.x_offset / x_div;
+ v_addr = (u32) msg->dst.v_addr +
+ (msg->dst.y_offset / y_div) * d_uv_stride +
+ msg->dst.x_offset / x_div;
+
+ y_lt_addr = yrgb_addr;
+ u_lt_addr = u_addr;
+ v_lt_addr = v_addr;
+
+ /* Warning */
+ line_width_real =
+ dst_fmt_y4_en ? ((msg->dst.act_w) >> 1) : msg->dst.act_w;
+
+ /*
+ * YUV packet mode is a new format, and the write behavior during
+ * rotation is different from the old format.
+ */
+ if (rga_is_yuv422_packed_format(msg->dst.format)) {
+ y_ld_addr = yrgb_addr + (msg->dst.act_h - 1) * (d_stride);
+ y_rt_addr = yrgb_addr + (msg->dst.act_w * 2 - 1);
+ y_rd_addr = y_ld_addr + (msg->dst.act_w * 2 - 1);
+ } else if (rga_is_yuv420_packed_format(msg->dst.format)) {
+ y_ld_addr = (u32)msg->dst.yrgb_addr +
+ ((msg->dst.y_offset + (msg->dst.act_h - 1)) * d_stride) +
+ msg->dst.x_offset;
+ y_rt_addr = yrgb_addr + (msg->dst.act_w * 2 - 1);
+ y_rd_addr = y_ld_addr + (msg->dst.act_w - 1);
+ } else {
+ /* 270 degree & Mirror V */
+ y_ld_addr = yrgb_addr + (msg->dst.act_h - 1) * (d_stride);
+ /* 90 degree & Mirror H */
+ y_rt_addr = yrgb_addr + (line_width_real - 1) * dpw;
+ /* 180 degree */
+ y_rd_addr = y_ld_addr + (line_width_real - 1) * dpw;
+ }
+
+ u_ld_addr = u_addr + ((msg->dst.act_h / y_div) - 1) * (d_uv_stride);
+ v_ld_addr = v_addr + ((msg->dst.act_h / y_div) - 1) * (d_uv_stride);
+
+ u_rt_addr = u_addr + (msg->dst.act_w / x_div) - 1;
+ v_rt_addr = v_addr + (msg->dst.act_w / x_div) - 1;
+
+ u_rd_addr = u_ld_addr + (msg->dst.act_w / x_div) - 1;
+ v_rd_addr = v_ld_addr + (msg->dst.act_w / x_div) - 1;
+
+ if (rot_90_flag == 0) {
+ if (y_mirr == 1) {
+ if (x_mirr == 1) {
+ yrgb_addr = y_rd_addr;
+ u_addr = u_rd_addr;
+ v_addr = v_rd_addr;
+ } else {
+ yrgb_addr = y_ld_addr;
+ u_addr = u_ld_addr;
+ v_addr = v_ld_addr;
+ }
+ } else {
+ if (x_mirr == 1) {
+ yrgb_addr = y_rt_addr;
+ u_addr = u_rt_addr;
+ v_addr = v_rt_addr;
+ } else {
+ yrgb_addr = y_lt_addr;
+ u_addr = u_lt_addr;
+ v_addr = v_lt_addr;
+ }
+ }
+ } else {
+ if (y_mirr == 1) {
+ if (x_mirr == 1) {
+ yrgb_addr = y_ld_addr;
+ u_addr = u_ld_addr;
+ v_addr = v_ld_addr;
+ } else {
+ yrgb_addr = y_rd_addr;
+ u_addr = u_rd_addr;
+ v_addr = v_rd_addr;
+ }
+ } else {
+ if (x_mirr == 1) {
+ yrgb_addr = y_lt_addr;
+ u_addr = u_lt_addr;
+ v_addr = v_lt_addr;
+ } else {
+ yrgb_addr = y_rt_addr;
+ u_addr = u_rt_addr;
+ v_addr = v_rt_addr;
+ }
+ }
+ }
+
+ *bRGA_DST_BASE0 = (u32) yrgb_addr;
+
+ if ((msg->dst.format == RGA_FORMAT_YCbCr_420_P)
+ || (msg->dst.format == RGA_FORMAT_YCrCb_420_P)) {
+ if (dst_cbcr_swp == 0) {
+ *bRGA_DST_BASE1 = (u32) v_addr;
+ *bRGA_DST_BASE2 = (u32) u_addr;
+ } else {
+ *bRGA_DST_BASE1 = (u32) u_addr;
+ *bRGA_DST_BASE2 = (u32) v_addr;
+ }
+ } else {
+ *bRGA_DST_BASE1 = (u32) u_addr;
+ *bRGA_DST_BASE2 = (u32) v_addr;
+ }
+}
+
+static void RGA2_set_reg_alpha_info(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_ALPHA_CTRL0;
+ u32 *bRGA_ALPHA_CTRL1;
+ u32 *bRGA_FADING_CTRL;
+ u32 reg = 0;
+ union rga2_color_ctrl color_ctrl;
+ union rga2_alpha_ctrl alpha_ctrl;
+ struct rga_alpha_config *config;
+
+ bRGA_ALPHA_CTRL0 = (u32 *) (base + RGA2_ALPHA_CTRL0_OFFSET);
+ bRGA_ALPHA_CTRL1 = (u32 *) (base + RGA2_ALPHA_CTRL1_OFFSET);
+ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET);
+
+ color_ctrl.value = 0;
+ alpha_ctrl.value = 0;
+ config = &msg->alpha_config;
+
+ color_ctrl.bits.src_color_mode =
+ config->fg_pre_multiplied ? RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED;
+ color_ctrl.bits.dst_color_mode =
+ config->bg_pre_multiplied ? RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED;
+
+ if (config->fg_pixel_alpha_en)
+ color_ctrl.bits.src_blend_mode =
+ config->fg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL :
+ RGA_ALPHA_PER_PIXEL;
+ else
+ color_ctrl.bits.src_blend_mode = RGA_ALPHA_GLOBAL;
+
+ if (config->bg_pixel_alpha_en)
+ color_ctrl.bits.dst_blend_mode =
+ config->bg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL :
+ RGA_ALPHA_PER_PIXEL;
+ else
+ color_ctrl.bits.dst_blend_mode = RGA_ALPHA_GLOBAL;
+
+ /*
+ * Since the hardware uses 256 as 1, the original alpha value needs to
+ * be + (alpha >> 7).
+ */
+ color_ctrl.bits.src_alpha_cal_mode = RGA_ALPHA_SATURATION;
+ color_ctrl.bits.dst_alpha_cal_mode = RGA_ALPHA_SATURATION;
+
+ /* porter duff alpha enable */
+ switch (config->mode) {
+ case RGA_ALPHA_BLEND_SRC:
+ /*
+ * SRC mode:
+ * Sf = 1, Df = 0
+ * [Rc,Ra] = [Sc,Sa]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ONE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ZERO;
+
+ break;
+
+ case RGA_ALPHA_BLEND_DST:
+ /*
+ * SRC mode:
+ * Sf = 0, Df = 1
+ * [Rc,Ra] = [Dc,Da]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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 ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ONE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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 ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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 ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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 ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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) ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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) ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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) ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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 ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_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) ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE;
+
+ break;
+
+ case RGA_ALPHA_BLEND_CLEAR:
+ /*
+ * DST-CLEAR mode:
+ * Sf = 0 , Df = 0
+ * [Rc,Ra] = [ 0, 0 ]
+ */
+ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO;
+
+ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT;
+ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ZERO;
+
+ break;
+
+ default:
+ break;
+ }
+
+ alpha_ctrl.bits.src_blend_mode = color_ctrl.bits.src_blend_mode;
+ alpha_ctrl.bits.dst_blend_mode = color_ctrl.bits.dst_blend_mode;
+
+ alpha_ctrl.bits.src_alpha_cal_mode = color_ctrl.bits.src_alpha_cal_mode;
+ alpha_ctrl.bits.dst_alpha_cal_mode = color_ctrl.bits.dst_alpha_cal_mode;
+
+ alpha_ctrl.bits.src_alpha_mode = color_ctrl.bits.src_alpha_mode;
+ alpha_ctrl.bits.src_factor_mode = color_ctrl.bits.src_factor_mode;
+
+ alpha_ctrl.bits.dst_alpha_mode = color_ctrl.bits.dst_alpha_mode;
+ alpha_ctrl.bits.dst_factor_mode = color_ctrl.bits.dst_factor_mode;
+
+ reg =
+ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0)) |
+ (s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0(msg->alpha_rop_flag)));
+ reg =
+ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL)) |
+ (s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL
+ (msg->alpha_rop_flag >> 1)));
+ reg =
+ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_ROP_MODE)) |
+ (s_RGA2_ALPHA_CTRL0_SW_ROP_MODE(msg->rop_mode)));
+ reg =
+ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA)) |
+ (s_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA
+ ((uint8_t)config->fg_global_alpha_value)));
+ reg =
+ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA)) |
+ (s_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA
+ ((uint8_t)config->bg_global_alpha_value)));
+
+ *bRGA_ALPHA_CTRL0 = reg;
+ *bRGA_ALPHA_CTRL1 = color_ctrl.value | (alpha_ctrl.value << 16);
+
+
+ if ((msg->alpha_rop_flag >> 2) & 1) {
+ *bRGA_FADING_CTRL = (1 << 24) | (msg->fading_b_value << 16) |
+ (msg->fading_g_value << 8) | (msg->fading_r_value);
+ }
+}
+
+static void RGA2_set_reg_rop_info(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_ALPHA_CTRL0;
+ u32 *bRGA_ROP_CTRL0;
+ u32 *bRGA_ROP_CTRL1;
+ u32 *bRGA_MASK_ADDR;
+ u32 *bRGA_FG_COLOR;
+ u32 *bRGA_PAT_CON;
+
+ u32 rop_code0 = 0;
+ u32 rop_code1 = 0;
+
+ bRGA_ALPHA_CTRL0 = (u32 *) (base + RGA2_ALPHA_CTRL0_OFFSET);
+ bRGA_ROP_CTRL0 = (u32 *) (base + RGA2_ROP_CTRL0_OFFSET);
+ bRGA_ROP_CTRL1 = (u32 *) (base + RGA2_ROP_CTRL1_OFFSET);
+ bRGA_MASK_ADDR = (u32 *) (base + RGA2_MASK_BASE_OFFSET);
+ bRGA_FG_COLOR = (u32 *) (base + RGA2_SRC_FG_COLOR_OFFSET);
+ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET);
+
+ if (msg->rop_mode == 0) {
+ rop_code0 = rga2_rop_code[(msg->rop_code & 0xff)];
+ } else if (msg->rop_mode == 1) {
+ rop_code0 = rga2_rop_code[(msg->rop_code & 0xff)];
+ } else if (msg->rop_mode == 2) {
+ rop_code0 = rga2_rop_code[(msg->rop_code & 0xff)];
+ rop_code1 = rga2_rop_code[(msg->rop_code & 0xff00) >> 8];
+ }
+
+ *bRGA_ROP_CTRL0 = rop_code0;
+ *bRGA_ROP_CTRL1 = rop_code1;
+ *bRGA_FG_COLOR = msg->fg_color;
+ *bRGA_MASK_ADDR = (u32) msg->rop_mask_addr;
+ *bRGA_PAT_CON = (msg->pat.act_w - 1) | ((msg->pat.act_h - 1) << 8)
+ | (msg->pat.x_offset << 16) | (msg->pat.y_offset << 24);
+ *bRGA_ALPHA_CTRL0 =
+ *bRGA_ALPHA_CTRL0 | (((msg->endian_mode >> 1) & 1) << 20);
+
+}
+
+static void RGA_set_reg_mosaic(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_MOSAIC_MODE;
+
+ bRGA_MOSAIC_MODE = (u32 *)(base + RGA2_MOSAIC_MODE_OFFSET);
+
+ *bRGA_MOSAIC_MODE = (u32)(msg->mosaic_info.mode & 0x7);
+}
+
+static void RGA2_set_reg_osd(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_OSD_CTRL0;
+ u32 *bRGA_OSD_CTRL1;
+ u32 *bRGA_OSD_INVERTSION_CAL0;
+ u32 *bRGA_OSD_INVERTSION_CAL1;
+ u32 *bRGA_OSD_COLOR0;
+ u32 *bRGA_OSD_COLOR1;
+ u32 *bRGA_OSD_LAST_FLAGS0;
+ u32 *bRGA_OSD_LAST_FLAGS1;
+ u32 reg;
+ u8 rgba2bpp_en = 0;
+ u8 block_num;
+ u16 fix_width;
+
+
+ bRGA_OSD_CTRL0 = (u32 *)(base + RGA2_OSD_CTRL0_OFFSET);
+ bRGA_OSD_CTRL1 = (u32 *)(base + RGA2_OSD_CTRL1_OFFSET);
+ bRGA_OSD_INVERTSION_CAL0 = (u32 *)(base + RGA2_OSD_INVERTSION_CAL0_OFFSET);
+ bRGA_OSD_INVERTSION_CAL1 = (u32 *)(base + RGA2_OSD_INVERTSION_CAL1_OFFSET);
+ bRGA_OSD_COLOR0 = (u32 *)(base + RGA2_OSD_COLOR0_OFFSET);
+ bRGA_OSD_COLOR1 = (u32 *)(base + RGA2_OSD_COLOR1_OFFSET);
+ bRGA_OSD_LAST_FLAGS0 = (u32 *)(base + RGA2_OSD_LAST_FLAGS0_OFFSET);
+ bRGA_OSD_LAST_FLAGS1 = (u32 *)(base + RGA2_OSD_LAST_FLAGS1_OFFSET);
+
+ /* To save the number of register bits. */
+ fix_width = msg->osd_info.mode_ctrl.block_fix_width / 2 - 1;
+
+ /* The register is '0' as the first. */
+ block_num = msg->osd_info.mode_ctrl.block_num - 1;
+
+ if (msg->src1.format == RGA_FORMAT_RGBA_2BPP)
+ rgba2bpp_en = 1;
+
+ reg = 0;
+ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_MODE)) |
+ (s_RGA2_OSD_CTRL0_SW_OSD_MODE(msg->osd_info.mode_ctrl.mode)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_VER_MODE)) |
+ (s_RGA2_OSD_CTRL0_SW_OSD_VER_MODE(msg->osd_info.mode_ctrl.direction_mode)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE)) |
+ (s_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE(msg->osd_info.mode_ctrl.width_mode)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM)) |
+ (s_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM(block_num)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX)) |
+ (s_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX(msg->osd_info.mode_ctrl.flags_index)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH)) |
+ (s_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH(fix_width)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE)) |
+ (s_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE(rgba2bpp_en)));
+ *bRGA_OSD_CTRL0 = reg;
+
+ reg = 0;
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL(msg->osd_info.mode_ctrl.color_mode)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL(msg->osd_info.mode_ctrl.invert_flags_mode)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR(msg->osd_info.mode_ctrl.default_color_sel)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE(msg->osd_info.mode_ctrl.invert_mode)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_THRESH)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_THRESH(msg->osd_info.mode_ctrl.invert_thresh)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN(msg->osd_info.mode_ctrl.invert_enable)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS(msg->osd_info.mode_ctrl.invert_enable >> 1)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS(msg->osd_info.mode_ctrl.invert_enable >> 2)));
+ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX)) |
+ (s_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX(msg->osd_info.mode_ctrl.unfix_index)));
+ *bRGA_OSD_CTRL1 = reg;
+
+ *bRGA_OSD_INVERTSION_CAL0 = ((msg->osd_info.cal_factor.crb_max) << 24) |
+ ((msg->osd_info.cal_factor.crb_min) << 16) |
+ ((msg->osd_info.cal_factor.yg_max) << 8) |
+ ((msg->osd_info.cal_factor.yg_min) << 0);
+ *bRGA_OSD_INVERTSION_CAL1 = ((msg->osd_info.cal_factor.alpha_max) << 8) |
+ ((msg->osd_info.cal_factor.alpha_min) << 0);
+
+ *bRGA_OSD_LAST_FLAGS0 = (msg->osd_info.last_flags0);
+ *bRGA_OSD_LAST_FLAGS1 = (msg->osd_info.last_flags1);
+
+ if (msg->osd_info.mode_ctrl.color_mode == 1) {
+ *bRGA_OSD_COLOR0 = (msg->osd_info.bpp2_info.color0.value & 0xffffff);
+ *bRGA_OSD_COLOR1 = (msg->osd_info.bpp2_info.color1.value & 0xffffff);
+ }
+
+ if (rgba2bpp_en) {
+ *bRGA_OSD_COLOR0 = msg->osd_info.bpp2_info.color0.value;
+ *bRGA_OSD_COLOR1 = msg->osd_info.bpp2_info.color1.value;
+ }
+}
+
+static void RGA2_set_reg_color_palette(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_SRC_BASE0, *bRGA_SRC_INFO, *bRGA_SRC_VIR_INFO,
+ *bRGA_SRC_ACT_INFO, *bRGA_SRC_FG_COLOR, *bRGA_SRC_BG_COLOR;
+ u32 *p;
+ short x_off, y_off;
+ u16 src_stride;
+ u8 shift;
+ u32 sw;
+ u32 byte_num;
+ u32 reg;
+
+ bRGA_SRC_BASE0 = (u32 *) (base + RGA2_SRC_BASE0_OFFSET);
+ bRGA_SRC_INFO = (u32 *) (base + RGA2_SRC_INFO_OFFSET);
+ bRGA_SRC_VIR_INFO = (u32 *) (base + RGA2_SRC_VIR_INFO_OFFSET);
+ bRGA_SRC_ACT_INFO = (u32 *) (base + RGA2_SRC_ACT_INFO_OFFSET);
+ bRGA_SRC_FG_COLOR = (u32 *) (base + RGA2_SRC_FG_COLOR_OFFSET);
+ bRGA_SRC_BG_COLOR = (u32 *) (base + RGA2_SRC_BG_COLOR_OFFSET);
+
+ reg = 0;
+
+ shift = 3 - msg->palette_mode;
+
+ x_off = msg->src.x_offset;
+ y_off = msg->src.y_offset;
+
+ sw = msg->src.vir_w;
+ byte_num = sw >> shift;
+
+ src_stride = (byte_num + 3) & (~3);
+
+ p = (u32 *) ((unsigned long)msg->src.yrgb_addr);
+
+ p = p + (x_off >> shift) + y_off * src_stride;
+
+ *bRGA_SRC_BASE0 = (unsigned long)p;
+
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SRC_FMT)) |
+ (s_RGA2_SRC_INFO_SW_SRC_FMT((msg->palette_mode | 0xc))));
+ reg =
+ ((reg & (~m_RGA2_SRC_INFO_SW_SW_CP_ENDIAN)) |
+ (s_RGA2_SRC_INFO_SW_SW_CP_ENDAIN(msg->endian_mode & 1)));
+ *bRGA_SRC_VIR_INFO = src_stride >> 2;
+ *bRGA_SRC_ACT_INFO =
+ (msg->src.act_w - 1) | ((msg->src.act_h - 1) << 16);
+ *bRGA_SRC_INFO = reg;
+
+ *bRGA_SRC_FG_COLOR = msg->fg_color;
+ *bRGA_SRC_BG_COLOR = msg->bg_color;
+
+}
+
+static void RGA2_set_reg_color_fill(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_CF_GR_A;
+ u32 *bRGA_CF_GR_B;
+ u32 *bRGA_CF_GR_G;
+ u32 *bRGA_CF_GR_R;
+ u32 *bRGA_SRC_FG_COLOR;
+ u32 *bRGA_MASK_ADDR;
+ u32 *bRGA_PAT_CON;
+
+ u32 mask_stride;
+ u32 *bRGA_SRC_VIR_INFO;
+
+ bRGA_SRC_FG_COLOR = (u32 *) (base + RGA2_SRC_FG_COLOR_OFFSET);
+
+ bRGA_CF_GR_A = (u32 *) (base + RGA2_CF_GR_A_OFFSET);
+ bRGA_CF_GR_B = (u32 *) (base + RGA2_CF_GR_B_OFFSET);
+ bRGA_CF_GR_G = (u32 *) (base + RGA2_CF_GR_G_OFFSET);
+ bRGA_CF_GR_R = (u32 *) (base + RGA2_CF_GR_R_OFFSET);
+
+ bRGA_MASK_ADDR = (u32 *) (base + RGA2_MASK_BASE_OFFSET);
+ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET);
+
+ bRGA_SRC_VIR_INFO = (u32 *) (base + RGA2_SRC_VIR_INFO_OFFSET);
+
+ mask_stride = msg->rop_mask_stride;
+
+ if (msg->color_fill_mode == 0) {
+ /* solid color */
+ *bRGA_CF_GR_A = (msg->gr_color.gr_x_a & 0xffff) |
+ (msg->gr_color.gr_y_a << 16);
+ *bRGA_CF_GR_B = (msg->gr_color.gr_x_b & 0xffff) |
+ (msg->gr_color.gr_y_b << 16);
+ *bRGA_CF_GR_G = (msg->gr_color.gr_x_g & 0xffff) |
+ (msg->gr_color.gr_y_g << 16);
+ *bRGA_CF_GR_R = (msg->gr_color.gr_x_r & 0xffff) |
+ (msg->gr_color.gr_y_r << 16);
+
+ *bRGA_SRC_FG_COLOR = msg->fg_color;
+ } else {
+ /* pattern color */
+ *bRGA_MASK_ADDR = (u32) msg->pat.yrgb_addr;
+ *bRGA_PAT_CON =
+ (msg->pat.act_w - 1) | ((msg->pat.act_h - 1) << 8)
+ | (msg->pat.x_offset << 16) | (msg->pat.y_offset << 24);
+ }
+ *bRGA_SRC_VIR_INFO = mask_stride << 16;
+}
+
+static void RGA2_set_reg_update_palette_table(u8 *base,
+ struct rga2_req *msg)
+{
+ u32 *bRGA_MASK_BASE;
+ u32 *bRGA_FADING_CTRL;
+
+ bRGA_MASK_BASE = (u32 *) (base + RGA2_MASK_BASE_OFFSET);
+ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET);
+
+ *bRGA_FADING_CTRL = msg->fading_g_value << 8;
+ *bRGA_MASK_BASE = (u32) msg->pat.yrgb_addr;
+}
+
+static void RGA2_set_reg_update_patten_buff(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_PAT_MST;
+ u32 *bRGA_PAT_CON;
+ u32 *bRGA_PAT_START_POINT;
+ u32 *bRGA_FADING_CTRL;
+ u32 reg = 0;
+ struct rga_img_info_t *pat;
+
+ u32 num, offset;
+
+ pat = &msg->pat;
+
+ num = (pat->act_w * pat->act_h) - 1;
+
+ offset = pat->act_w * pat->y_offset + pat->x_offset;
+
+ bRGA_PAT_START_POINT = (u32 *) (base + RGA2_FADING_CTRL_OFFSET);
+ bRGA_PAT_MST = (u32 *) (base + RGA2_MASK_BASE_OFFSET);
+ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET);
+ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET);
+
+ *bRGA_PAT_MST = (u32) msg->pat.yrgb_addr;
+ *bRGA_PAT_START_POINT = (pat->act_w * pat->y_offset) + pat->x_offset;
+
+ reg = (pat->act_w - 1) | ((pat->act_h - 1) << 8) |
+ (pat->x_offset << 16) | (pat->y_offset << 24);
+ *bRGA_PAT_CON = reg;
+
+ *bRGA_FADING_CTRL = (num << 8) | offset;
+}
+
+static void RGA2_set_pat_info(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_PAT_CON;
+ u32 *bRGA_FADING_CTRL;
+ u32 reg = 0;
+ struct rga_img_info_t *pat;
+
+ u32 num, offset;
+
+ pat = &msg->pat;
+
+ num = ((pat->act_w * pat->act_h) - 1) & 0xff;
+
+ offset = (pat->act_w * pat->y_offset) + pat->x_offset;
+
+ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET);
+ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET);
+
+ reg = (pat->act_w - 1) | ((pat->act_h - 1) << 8) |
+ (pat->x_offset << 16) | (pat->y_offset << 24);
+ *bRGA_PAT_CON = reg;
+ *bRGA_FADING_CTRL = (num << 8) | offset;
+}
+
+static void RGA2_set_mmu_reg_info(u8 *base, struct rga2_req *msg)
+{
+ u32 *bRGA_MMU_CTRL1;
+ u32 *bRGA_MMU_SRC_BASE;
+ u32 *bRGA_MMU_SRC1_BASE;
+ u32 *bRGA_MMU_DST_BASE;
+ u32 *bRGA_MMU_ELS_BASE;
+
+ u32 reg;
+
+ bRGA_MMU_CTRL1 = (u32 *) (base + RGA2_MMU_CTRL1_OFFSET);
+ bRGA_MMU_SRC_BASE = (u32 *) (base + RGA2_MMU_SRC_BASE_OFFSET);
+ bRGA_MMU_SRC1_BASE = (u32 *) (base + RGA2_MMU_SRC1_BASE_OFFSET);
+ bRGA_MMU_DST_BASE = (u32 *) (base + RGA2_MMU_DST_BASE_OFFSET);
+ bRGA_MMU_ELS_BASE = (u32 *) (base + RGA2_MMU_ELS_BASE_OFFSET);
+
+ reg = (msg->mmu_info.src0_mmu_flag & 0xf) |
+ ((msg->mmu_info.src1_mmu_flag & 0xf) << 4) |
+ ((msg->mmu_info.dst_mmu_flag & 0xf) << 8) |
+ ((msg->mmu_info.els_mmu_flag & 0x3) << 12);
+
+ *bRGA_MMU_CTRL1 = reg;
+ *bRGA_MMU_SRC_BASE = (u32) (msg->mmu_info.src0_base_addr) >> 4;
+ *bRGA_MMU_SRC1_BASE = (u32) (msg->mmu_info.src1_base_addr) >> 4;
+ *bRGA_MMU_DST_BASE = (u32) (msg->mmu_info.dst_base_addr) >> 4;
+ *bRGA_MMU_ELS_BASE = (u32) (msg->mmu_info.els_base_addr) >> 4;
+}
+
+static int rga2_gen_reg_info(u8 *base, struct rga2_req *msg)
+{
+ u8 dst_nn_quantize_en = 0;
+
+ RGA2_set_mode_ctrl(base, msg);
+
+ RGA2_set_pat_info(base, msg);
+
+ switch (msg->render_mode) {
+ case BITBLT_MODE:
+ RGA2_set_reg_src_info(base, msg);
+ RGA2_set_reg_dst_info(base, msg);
+ dst_nn_quantize_en = (msg->alpha_rop_flag >> 8) & 0x1;
+ if (dst_nn_quantize_en != 1) {
+ if ((msg->dst.format !=
+ RGA_FORMAT_Y4)) {
+ RGA2_set_reg_alpha_info(base, msg);
+ RGA2_set_reg_rop_info(base, msg);
+ }
+ }
+ if (msg->mosaic_info.enable)
+ RGA_set_reg_mosaic(base, msg);
+ if (msg->osd_info.enable)
+ RGA2_set_reg_osd(base, msg);
+
+ break;
+ case COLOR_FILL_MODE:
+ RGA2_set_reg_color_fill(base, msg);
+ RGA2_set_reg_dst_info(base, msg);
+ RGA2_set_reg_alpha_info(base, msg);
+ break;
+ case COLOR_PALETTE_MODE:
+ RGA2_set_reg_color_palette(base, msg);
+ RGA2_set_reg_dst_info(base, msg);
+ break;
+ case UPDATE_PALETTE_TABLE_MODE:
+ RGA2_set_reg_update_palette_table(base, msg);
+ break;
+ case UPDATE_PATTEN_BUF_MODE:
+ RGA2_set_reg_update_patten_buff(base, msg);
+ break;
+ default:
+ pr_err("ERROR msg render mode %d\n", msg->render_mode);
+ break;
+ }
+
+ RGA2_set_mmu_reg_info(base, msg);
+
+ return 0;
+}
+
+static void rga_cmd_to_rga2_cmd(struct rga_scheduler_t *scheduler,
+ struct rga_req *req_rga, struct rga2_req *req)
+{
+ if (req_rga->render_mode == 6)
+ req->render_mode = UPDATE_PALETTE_TABLE_MODE;
+ else if (req_rga->render_mode == 7)
+ req->render_mode = UPDATE_PATTEN_BUF_MODE;
+ else if (req_rga->render_mode == 5)
+ req->render_mode = BITBLT_MODE;
+ else
+ req->render_mode = req_rga->render_mode;
+
+ memcpy(&req->src, &req_rga->src, sizeof(req_rga->src));
+ memcpy(&req->dst, &req_rga->dst, sizeof(req_rga->dst));
+ /* The application will only import pat or src1. */
+ if (req->render_mode == UPDATE_PALETTE_TABLE_MODE)
+ memcpy(&req->pat, &req_rga->pat, sizeof(req_rga->pat));
+ else
+ memcpy(&req->src1, &req_rga->pat, sizeof(req_rga->pat));
+
+ req->src.format = req_rga->src.format;
+ req->dst.format = req_rga->dst.format;
+ req->src1.format = req_rga->pat.format;
+
+ switch (req_rga->rotate_mode & 0x0F) {
+ case 1:
+ if (req_rga->sina == 0 && req_rga->cosa == 65536) {
+ /* rotate 0 */
+ req->rotate_mode = 0;
+ } else if (req_rga->sina == 65536 && req_rga->cosa == 0) {
+ /* rotate 90 */
+ req->rotate_mode = 1;
+ req->dst.x_offset = req_rga->dst.x_offset;
+ req->dst.act_w = req_rga->dst.act_h;
+ req->dst.act_h = req_rga->dst.act_w;
+ } else if (req_rga->sina == 0 && req_rga->cosa == -65536) {
+ /* rotate 180 */
+ req->rotate_mode = 2;
+ req->dst.x_offset = req_rga->dst.x_offset;
+ req->dst.y_offset = req_rga->dst.y_offset;
+ } else if (req_rga->sina == -65536 && req_rga->cosa == 0) {
+ /* totate 270 */
+ req->rotate_mode = 3;
+ req->dst.y_offset = req_rga->dst.y_offset;
+ req->dst.act_w = req_rga->dst.act_h;
+ req->dst.act_h = req_rga->dst.act_w;
+ }
+ break;
+ case 2:
+ //x_mirror
+ req->rotate_mode |= (1 << 4);
+ break;
+ case 3:
+ //y_mirror
+ req->rotate_mode |= (2 << 4);
+ break;
+ case 4:
+ //x_mirror+y_mirror
+ req->rotate_mode |= (3 << 4);
+ break;
+ default:
+ req->rotate_mode = 0;
+ break;
+ }
+
+ switch ((req_rga->rotate_mode & 0xF0) >> 4) {
+ case 2:
+ //x_mirror
+ req->rotate_mode |= (1 << 4);
+ break;
+ case 3:
+ //y_mirror
+ req->rotate_mode |= (2 << 4);
+ break;
+ case 4:
+ //x_mirror+y_mirror
+ req->rotate_mode |= (3 << 4);
+ break;
+ }
+
+ req->LUT_addr = req_rga->LUT_addr;
+ req->rop_mask_addr = req_rga->rop_mask_addr;
+
+ req->bitblt_mode = req_rga->bsfilter_flag;
+
+ req->src_a_global_val = req_rga->alpha_global_value;
+ req->dst_a_global_val = req_rga->alpha_global_value;
+ req->rop_code = req_rga->rop_code;
+ req->rop_mode = req_rga->alpha_rop_mode;
+
+ req->color_fill_mode = req_rga->color_fill_mode;
+ req->alpha_zero_key = req_rga->alpha_rop_mode >> 4;
+ req->src_trans_mode = req_rga->src_trans_mode;
+ req->color_key_min = req_rga->color_key_min;
+ req->color_key_max = req_rga->color_key_max;
+
+ req->fg_color = req_rga->fg_color;
+ req->bg_color = req_rga->bg_color;
+ memcpy(&req->gr_color, &req_rga->gr_color, sizeof(req_rga->gr_color));
+
+ req->palette_mode = req_rga->palette_mode;
+ req->yuv2rgb_mode = req_rga->yuv2rgb_mode;
+ if (req_rga->full_csc.flag & 0x1)
+ req->full_csc_en = 1;
+ req->endian_mode = req_rga->endian_mode;
+ req->rgb2yuv_mode = 0;
+
+ req->fading_alpha_value = 0;
+ req->fading_r_value = req_rga->fading.r;
+ req->fading_g_value = req_rga->fading.g;
+ req->fading_b_value = req_rga->fading.b;
+
+ /* alpha mode set */
+ req->alpha_rop_flag = 0;
+ /* alpha_rop_enable */
+ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag & 1)));
+ /* rop_enable */
+ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 1) & 1) << 1);
+ /* fading_enable */
+ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 2) & 1) << 2);
+ /* alpha_cal_mode_sel */
+ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 4) & 1) << 3);
+ /* dst_dither_down */
+ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 5) & 1) << 6);
+ /* gradient fill mode sel */
+ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 6) & 1) << 7);
+ /* RGA_NN_QUANTIZE */
+ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 8) & 1) << 8);
+ req->dither_mode = req_rga->dither_mode;
+
+ /* RGA2 1106 add */
+ memcpy(&req->mosaic_info, &req_rga->mosaic_info, sizeof(req_rga->mosaic_info));
+
+ if ((scheduler->data->feature & RGA_YIN_YOUT) &&
+ rga_is_only_y_format(req->src.format) &&
+ rga_is_only_y_format(req->dst.format))
+ req->yin_yout_en = true;
+
+ req->uvhds_mode = req_rga->uvhds_mode;
+ req->uvvds_mode = req_rga->uvvds_mode;
+
+ memcpy(&req->osd_info, &req_rga->osd_info, sizeof(req_rga->osd_info));
+
+ 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 if (req->osd_info.enable) {
+ req->alpha_config.fg_pre_multiplied = true;
+ /* set dst(osd_block) real color mode */
+ 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->src.format);
+ if (req->bitblt_mode)
+ req->alpha_config.bg_pixel_alpha_en =
+ rga_is_alpha_format(req->src1.format);
+ else
+ req->alpha_config.bg_pixel_alpha_en =
+ rga_is_alpha_format(req->dst.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.bg_global_alpha_value = 0xff;
+ req->alpha_config.bg_global_alpha_value = 0xff;
+ }
+
+ req->alpha_config.mode = req_rga->PD_mode;
+ }
+ }
+
+ 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.dst_mmu_flag = 1;
+
+ if (req_rga->mmu_info.mmu_flag >> 31) {
+ req->mmu_info.src0_mmu_flag =
+ ((req_rga->mmu_info.mmu_flag >> 8) & 1);
+ req->mmu_info.src1_mmu_flag =
+ ((req_rga->mmu_info.mmu_flag >> 9) & 1);
+ req->mmu_info.dst_mmu_flag =
+ ((req_rga->mmu_info.mmu_flag >> 10) & 1);
+ req->mmu_info.els_mmu_flag =
+ ((req_rga->mmu_info.mmu_flag >> 11) & 1);
+ } else {
+ if (req_rga->src.yrgb_addr >= 0xa0000000) {
+ req->mmu_info.src0_mmu_flag = 0;
+ req->src.yrgb_addr =
+ req_rga->src.yrgb_addr - 0x60000000;
+ req->src.uv_addr =
+ req_rga->src.uv_addr - 0x60000000;
+ req->src.v_addr =
+ req_rga->src.v_addr - 0x60000000;
+ }
+
+ if (req_rga->dst.yrgb_addr >= 0xa0000000) {
+ req->mmu_info.dst_mmu_flag = 0;
+ req->dst.yrgb_addr =
+ req_rga->dst.yrgb_addr - 0x60000000;
+ }
+
+ if (req_rga->pat.yrgb_addr >= 0xa0000000) {
+ req->mmu_info.src1_mmu_flag = 0;
+ req->src1.yrgb_addr =
+ req_rga->pat.yrgb_addr - 0x60000000;
+ }
+ }
+ }
+}
+
+static void rga2_soft_reset(struct rga_scheduler_t *scheduler)
+{
+ u32 i;
+ u32 reg;
+ u32 iommu_dte_addr = 0;
+
+ if (scheduler->data->mmu == RGA_IOMMU)
+ iommu_dte_addr = rga_read(RGA_IOMMU_DTE_ADDR, scheduler);
+
+ rga_write(m_RGA2_SYS_CTRL_ACLK_SRESET_P | m_RGA2_SYS_CTRL_CCLK_SRESET_P |
+ m_RGA2_SYS_CTRL_RST_PROTECT_P,
+ RGA2_SYS_CTRL, scheduler);
+
+ for (i = 0; i < RGA_RESET_TIMEOUT; i++) {
+ /* RGA_SYS_CTRL */
+ reg = rga_read(RGA2_SYS_CTRL, scheduler) & 1;
+
+ if (reg == 0)
+ break;
+
+ udelay(1);
+ }
+
+ 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)
+ pr_err("RAG2 core[%d] soft reset timeout.\n", scheduler->core);
+ else
+ pr_info("RGA2 core[%d] soft reset complete.\n", scheduler->core);
+
+}
+
+static int rga2_check_param(const struct rga_hw_data *data, const struct rga2_req *req)
+{
+ if (!((req->render_mode == COLOR_FILL_MODE))) {
+ if (unlikely(rga_hw_out_of_range(&data->input_range,
+ req->src.act_w, req->src.act_h))) {
+ pr_err("invalid src resolution act_w = %d, act_h = %d\n",
+ req->src.act_w, req->src.act_h);
+ return -EINVAL;
+ }
+
+ if (unlikely(req->src.vir_w * rga_get_pixel_stride_from_format(req->src.format) >
+ data->max_byte_stride * 8)) {
+ pr_err("invalid src stride, stride = %d, max_byte_stride = %d\n",
+ req->src.vir_w, data->max_byte_stride);
+ return -EINVAL;
+ }
+
+ if (unlikely(req->src.vir_w < req->src.act_w)) {
+ pr_err("invalid src_vir_w act_w = %d, vir_w = %d\n",
+ req->src.act_w, req->src.vir_w);
+ return -EINVAL;
+ }
+ }
+
+ if (unlikely(rga_hw_out_of_range(&data->output_range, req->dst.act_w, req->dst.act_h))) {
+ pr_err("invalid dst resolution act_w = %d, act_h = %d\n",
+ req->dst.act_w, req->dst.act_h);
+ return -EINVAL;
+ }
+
+ if (unlikely(req->dst.vir_w * rga_get_pixel_stride_from_format(req->dst.format) >
+ data->max_byte_stride * 8)) {
+ pr_err("invalid dst stride, stride = %d, max_byte_stride = %d\n",
+ req->dst.vir_w, data->max_byte_stride);
+ return -EINVAL;
+ }
+
+ if (unlikely(req->dst.vir_w < req->dst.act_w)) {
+ if (req->rotate_mode != 1) {
+ pr_err("invalid dst_vir_w act_h = %d, vir_h = %d\n",
+ req->dst.act_w, req->dst.vir_w);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int rga2_align_check(struct rga2_req *req)
+{
+ if (rga_is_yuv10bit_format(req->src.format))
+ if ((req->src.vir_w % 16) || (req->src.x_offset % 2) ||
+ (req->src.act_w % 2) || (req->src.y_offset % 2) ||
+ (req->src.act_h % 2) || (req->src.vir_h % 2))
+ pr_info("err src wstride, 10bit yuv\n");
+ if (rga_is_yuv10bit_format(req->dst.format))
+ if ((req->dst.vir_w % 16) || (req->dst.x_offset % 2) ||
+ (req->dst.act_w % 2) || (req->dst.y_offset % 2) ||
+ (req->dst.act_h % 2) || (req->dst.vir_h % 2))
+ pr_info("err dst wstride, 10bit yuv\n");
+ if (rga_is_yuv8bit_format(req->src.format))
+ if ((req->src.vir_w % 4) || (req->src.x_offset % 2) ||
+ (req->src.act_w % 2) || (req->src.y_offset % 2) ||
+ (req->src.act_h % 2) || (req->src.vir_h % 2))
+ pr_info("err src wstride, 8bit yuv\n");
+ if (rga_is_yuv8bit_format(req->dst.format))
+ if ((req->dst.vir_w % 4) || (req->dst.x_offset % 2) ||
+ (req->dst.act_w % 2) || (req->dst.y_offset % 2) ||
+ (req->dst.act_h % 2) || (req->dst.vir_h % 2))
+ pr_info("err dst wstride, 8bit yuv\n");
+
+ return 0;
+}
+
+static void print_debug_info(struct rga2_req *req)
+{
+ pr_info("render_mode:%s,bitblit_mode=%d,rotate_mode:%s\n",
+ rga_get_render_mode_str(req->render_mode), req->bitblt_mode,
+ rga_get_rotate_mode_str(req->rotate_mode));
+
+ pr_info("src: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
+ (unsigned long)req->src.yrgb_addr,
+ (unsigned long)req->src.uv_addr,
+ (unsigned long)req->src.v_addr,
+ req->src.act_w, req->src.act_h,
+ req->src.vir_w, req->src.vir_h);
+ pr_info("src: xoff=%d yoff=%d format=%s\n",
+ req->src.x_offset, req->src.y_offset,
+ rga_get_format_name(req->src.format));
+
+ if (req->src1.yrgb_addr != 0 || req->src1.uv_addr != 0
+ || req->src1.v_addr != 0) {
+ pr_info("src1: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
+ (unsigned long)req->src1.yrgb_addr,
+ (unsigned long)req->src1.uv_addr,
+ (unsigned long)req->src1.v_addr,
+ req->src1.act_w, req->src1.act_h,
+ req->src1.vir_w, req->src1.vir_h);
+ pr_info("src1: xoff=%d yoff=%d format=%s\n",
+ req->src1.x_offset, req->src1.y_offset,
+ rga_get_format_name(req->src1.format));
+ }
+
+ pr_info("dst: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
+ (unsigned long)req->dst.yrgb_addr,
+ (unsigned long)req->dst.uv_addr,
+ (unsigned long)req->dst.v_addr,
+ req->dst.act_w, req->dst.act_h,
+ req->dst.vir_w, req->dst.vir_h);
+ pr_info("dst: xoff=%d yoff=%d format=%s\n",
+ req->dst.x_offset, req->dst.y_offset,
+ rga_get_format_name(req->dst.format));
+
+ pr_info("mmu: src=%.2x src1=%.2x dst=%.2x els=%.2x\n",
+ req->mmu_info.src0_mmu_flag, req->mmu_info.src1_mmu_flag,
+ req->mmu_info.dst_mmu_flag, req->mmu_info.els_mmu_flag);
+ pr_info("alpha: flag %x mode=%s\n",
+ req->alpha_rop_flag, rga_get_blend_mode_str(req->alpha_config.mode));
+ pr_info("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);
+ pr_info("alpha: fg_global_alpha=%x bg_global_alpha=%x\n",
+ req->alpha_config.fg_global_alpha_value, req->alpha_config.bg_global_alpha_value);
+ pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode);
+}
+
+static int rga2_init_reg(struct rga_job *job)
+{
+ struct rga2_req req;
+ int ret = 0;
+ struct rga_scheduler_t *scheduler = NULL;
+ ktime_t timestamp = ktime_get();
+
+ scheduler = job->scheduler;
+ if (unlikely(scheduler == NULL)) {
+ pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ memset(&req, 0x0, sizeof(req));
+
+ rga_cmd_to_rga2_cmd(scheduler, &job->rga_command_base, &req);
+ if (req.full_csc_en) {
+ memcpy(&job->full_csc, &job->rga_command_base.full_csc, sizeof(job->full_csc));
+ if (job->rga_command_base.feature.full_csc_clip_en) {
+ memcpy(&job->full_csc_clip, &job->rga_command_base.full_csc_clip,
+ sizeof(job->full_csc_clip));
+ } else {
+ job->full_csc_clip.y.max = 0xff;
+ job->full_csc_clip.y.min = 0x0;
+ job->full_csc_clip.uv.max = 0xff;
+ job->full_csc_clip.uv.min = 0x0;
+ }
+
+ } else {
+ job->full_csc_clip.y.max = 0xff;
+ job->full_csc_clip.y.min = 0x0;
+ job->full_csc_clip.uv.max = 0xff;
+ job->full_csc_clip.uv.min = 0x0;
+ }
+ memcpy(&job->pre_intr_info, &job->rga_command_base.pre_intr_info,
+ sizeof(job->pre_intr_info));
+
+ /* check value if legal */
+ ret = rga2_check_param(scheduler->data, &req);
+ if (ret == -EINVAL) {
+ pr_err("req argument is inval\n");
+ return ret;
+ }
+
+ rga2_align_check(&req);
+
+ /* for debug */
+ if (DEBUGGER_EN(MSG))
+ print_debug_info(&req);
+
+ /* RGA2 mmu set */
+ if ((req.mmu_info.src0_mmu_flag & 1) || (req.mmu_info.src1_mmu_flag & 1) ||
+ (req.mmu_info.dst_mmu_flag & 1) || (req.mmu_info.els_mmu_flag & 1)) {
+ if (scheduler->data->mmu != RGA_MMU) {
+ pr_err("core[%d] has no MMU, please use physically contiguous memory.\n",
+ scheduler->core);
+ pr_err("mmu_flag[src, src1, dst, els] = [0x%x, 0x%x, 0x%x, 0x%x]\n",
+ req.mmu_info.src0_mmu_flag, req.mmu_info.src1_mmu_flag,
+ req.mmu_info.dst_mmu_flag, req.mmu_info.els_mmu_flag);
+ return -EINVAL;
+ }
+
+ ret = rga_set_mmu_base(job, &req);
+ if (ret < 0) {
+ pr_err("%s, [%d] set mmu info error\n", __func__,
+ __LINE__);
+ return -EFAULT;
+ }
+ }
+
+ /* In slave mode, the current frame completion interrupt must be enabled. */
+ if (scheduler->data->mmu == RGA_IOMMU)
+ req.CMD_fin_int_enable = 1;
+
+ if (rga2_gen_reg_info((uint8_t *)job->cmd_reg, &req) == -1) {
+ pr_err("gen reg info error\n");
+ return -EINVAL;
+ }
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], generate register cost time %lld us\n",
+ job->request_id, ktime_us_delta(ktime_get(), timestamp));
+
+ return ret;
+}
+
+static void rga2_dump_read_back_sys_reg(struct rga_scheduler_t *scheduler)
+{
+ int i;
+ unsigned long flags;
+ uint32_t sys_reg[24] = {0};
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ for (i = 0; i < 24; i++)
+ sys_reg[i] = rga_read(RGA2_SYS_REG_BASE + i * 4, scheduler);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ pr_info("SYS_READ_BACK_REG\n");
+ for (i = 0; i < 6; i++)
+ pr_info("0x%04x : %.8x %.8x %.8x %.8x\n",
+ RGA2_SYS_REG_BASE + i * 0x10,
+ sys_reg[0 + i * 4], sys_reg[1 + i * 4],
+ sys_reg[2 + i * 4], sys_reg[3 + i * 4]);
+}
+
+static void rga2_dump_read_back_csc_reg(struct rga_scheduler_t *scheduler)
+{
+ int i;
+ unsigned long flags;
+ uint32_t csc_reg[12] = {0};
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ for (i = 0; i < 12; i++)
+ csc_reg[i] = rga_read(RGA2_CSC_REG_BASE + i * 4, scheduler);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ pr_info("CSC_READ_BACK_REG\n");
+ for (i = 0; i < 3; i++)
+ pr_info("0x%04x : %.8x %.8x %.8x %.8x\n",
+ RGA2_CSC_REG_BASE + i * 0x10,
+ csc_reg[0 + i * 4], csc_reg[1 + i * 4],
+ csc_reg[2 + i * 4], csc_reg[3 + i * 4]);
+}
+
+static void rga2_dump_read_back_cmd_reg(struct rga_scheduler_t *scheduler)
+{
+ int i;
+ unsigned long flags;
+ uint32_t cmd_reg[32] = {0};
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ for (i = 0; i < 32; i++)
+ cmd_reg[i] = rga_read(RGA2_CMD_REG_BASE + i * 4, scheduler);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ pr_info("CMD_READ_BACK_REG\n");
+ for (i = 0; i < 8; i++)
+ pr_info("0x%04x : %.8x %.8x %.8x %.8x\n",
+ RGA2_CMD_REG_BASE + i * 0x10,
+ cmd_reg[0 + i * 4], cmd_reg[1 + i * 4],
+ cmd_reg[2 + i * 4], cmd_reg[3 + i * 4]);
+}
+
+static void rga2_dump_read_back_reg(struct rga_scheduler_t *scheduler)
+{
+ rga2_dump_read_back_sys_reg(scheduler);
+ rga2_dump_read_back_csc_reg(scheduler);
+ rga2_dump_read_back_cmd_reg(scheduler);
+}
+
+static void rga2_set_pre_intr_reg(struct rga_job *job, struct rga_scheduler_t *scheduler)
+{
+ uint32_t reg;
+
+ if (job->pre_intr_info.read_intr_en) {
+ reg = s_RGA2_READ_LINE_SW_INTR_LINE_RD_TH(job->pre_intr_info.read_threshold);
+ rga_write(reg, RGA2_READ_LINE_CNT, scheduler);
+ }
+
+ if (job->pre_intr_info.write_intr_en) {
+ reg = s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_START(job->pre_intr_info.write_start);
+ reg = ((reg & (~m_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP)) |
+ (s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP(job->pre_intr_info.write_step)));
+ rga_write(reg, RGA2_WRITE_LINE_CNT, scheduler);
+ }
+
+ reg = rga_read(RGA2_SYS_CTRL, scheduler);
+ reg = ((reg & (~m_RGA2_SYS_CTRL_HOLD_MODE_EN)) |
+ (s_RGA2_SYS_CTRL_HOLD_MODE_EN(job->pre_intr_info.read_hold_en)));
+ rga_write(reg, RGA2_SYS_CTRL, scheduler);
+
+ reg = rga_read(RGA2_INT, scheduler);
+ reg = (reg | s_RGA2_INT_LINE_RD_CLEAR(0x1) | s_RGA2_INT_LINE_WR_CLEAR(0x1));
+ reg = ((reg & (~m_RGA2_INT_LINE_RD_EN)) |
+ (s_RGA2_INT_LINE_RD_EN(job->pre_intr_info.read_intr_en)));
+ reg = ((reg & (~m_RGA2_INT_LINE_WR_EN)) |
+ (s_RGA2_INT_LINE_WR_EN(job->pre_intr_info.write_intr_en)));
+ rga_write(reg, RGA2_INT, scheduler);
+}
+
+static void rga2_set_reg_full_csc(struct rga_job *job, struct rga_scheduler_t *scheduler)
+{
+ /* full csc coefficient */
+ /* Y coefficient */
+ rga_write(job->full_csc.coe_y.r_v |
+ (job->full_csc_clip.y.max << 16) | (job->full_csc_clip.y.min << 24),
+ RGA2_DST_CSC_00, scheduler);
+ rga_write(job->full_csc.coe_y.g_y |
+ (job->full_csc_clip.uv.max << 16) | (job->full_csc_clip.uv.min << 24),
+ RGA2_DST_CSC_01, scheduler);
+ rga_write(job->full_csc.coe_y.b_u, RGA2_DST_CSC_02, scheduler);
+ rga_write(job->full_csc.coe_y.off, RGA2_DST_CSC_OFF0, scheduler);
+
+ /* U coefficient */
+ rga_write(job->full_csc.coe_u.r_v, RGA2_DST_CSC_10, scheduler);
+ rga_write(job->full_csc.coe_u.g_y, RGA2_DST_CSC_11, scheduler);
+ rga_write(job->full_csc.coe_u.b_u, RGA2_DST_CSC_12, scheduler);
+ rga_write(job->full_csc.coe_u.off, RGA2_DST_CSC_OFF1, scheduler);
+
+ /* V coefficient */
+ rga_write(job->full_csc.coe_v.r_v, RGA2_DST_CSC_20, scheduler);
+ rga_write(job->full_csc.coe_v.g_y, RGA2_DST_CSC_21, scheduler);
+ rga_write(job->full_csc.coe_v.b_u, RGA2_DST_CSC_22, scheduler);
+ rga_write(job->full_csc.coe_v.off, RGA2_DST_CSC_OFF2, scheduler);
+}
+
+static int rga2_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler)
+{
+ int i;
+ bool master_mode_en;
+ uint32_t sys_ctrl;
+ ktime_t now = ktime_get();
+
+ /*
+ * 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 (job->pre_intr_info.enable)
+ rga2_set_pre_intr_reg(job, scheduler);
+
+ if (job->full_csc.flag)
+ rga2_set_reg_full_csc(job, scheduler);
+
+ if (DEBUGGER_EN(REG)) {
+ uint32_t *p;
+
+ rga2_dump_read_back_sys_reg(scheduler);
+ rga2_dump_read_back_csc_reg(scheduler);
+
+ p = job->cmd_reg;
+ pr_info("CMD_REG\n");
+ for (i = 0; i < 8; i++)
+ pr_info("i = %x : %.8x %.8x %.8x %.8x\n", i,
+ p[0 + i * 4], p[1 + i * 4],
+ p[2 + i * 4], p[3 + i * 4]);
+ }
+
+ /* All CMD finish int */
+ rga_write(rga_read(RGA2_INT, scheduler) |
+ m_RGA2_INT_ERROR_ENABLE_MASK | m_RGA2_INT_ALL_CMD_DONE_INT_EN,
+ RGA2_INT, scheduler);
+
+ /* sys_reg init */
+ sys_ctrl = m_RGA2_SYS_CTRL_AUTO_CKG | m_RGA2_SYS_CTRL_AUTO_RST |
+ m_RGA2_SYS_CTRL_RST_PROTECT_P | m_RGA2_SYS_CTRL_DST_WR_OPT_DIS |
+ m_RGA2_SYS_CTRL_SRC0YUV420SP_RD_OPT_DIS;
+
+ if (master_mode_en) {
+ /* master mode */
+ sys_ctrl |= s_RGA2_SYS_CTRL_CMD_MODE(1);
+
+ /* cmd buffer flush cache to ddr */
+ rga_dma_sync_flush_range(&job->cmd_reg[0], &job->cmd_reg[32], scheduler);
+
+ /* set cmd_addr */
+ rga_write(virt_to_phys(job->cmd_reg), RGA2_CMD_BASE, scheduler);
+ rga_write(sys_ctrl, RGA2_SYS_CTRL, scheduler);
+ rga_write(m_RGA2_CMD_CTRL_CMD_LINE_ST_P, RGA2_CMD_CTRL, scheduler);
+ } else {
+ /* slave mode */
+ sys_ctrl |= s_RGA2_SYS_CTRL_CMD_MODE(0) | m_RGA2_SYS_CTRL_CMD_OP_ST_P;
+
+ /* set cmd_reg */
+ for (i = 0; i <= 32; i++)
+ rga_write(job->cmd_reg[i], 0x100 + i * 4, scheduler);
+
+ rga_write(sys_ctrl, RGA2_SYS_CTRL, scheduler);
+ }
+
+ if (DEBUGGER_EN(REG))
+ pr_info("sys_ctrl = %x, int = %x\n",
+ rga_read(RGA2_SYS_CTRL, scheduler),
+ rga_read(RGA2_INT, scheduler));
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], set register cost time %lld us\n",
+ job->request_id, ktime_us_delta(now, job->timestamp));
+
+ job->hw_running_time = now;
+ job->hw_recoder_time = now;
+
+ if (DEBUGGER_EN(REG))
+ rga2_dump_read_back_reg(scheduler);
+
+ return 0;
+}
+
+static int rga2_get_version(struct rga_scheduler_t *scheduler)
+{
+ u32 major_version, minor_version, svn_version;
+ u32 reg_version;
+
+ if (!scheduler) {
+ pr_err("scheduler is null\n");
+ return -EINVAL;
+ }
+
+ reg_version = rga_read(RGA2_VERSION_NUM, scheduler);
+
+ major_version = (reg_version & RGA2_MAJOR_VERSION_MASK) >> 24;
+ minor_version = (reg_version & RGA2_MINOR_VERSION_MASK) >> 20;
+ svn_version = (reg_version & RGA2_SVN_VERSION_MASK);
+
+ /*
+ * some old rga ip has no rga version register, so force set to 2.00
+ */
+ if (!major_version && !minor_version)
+ major_version = 2;
+
+ 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 rga2_read_back_reg(struct rga_job *job, struct rga_scheduler_t *scheduler)
+{
+ if (job->rga_command_base.osd_info.enable) {
+ job->rga_command_base.osd_info.cur_flags0 = rga_read(RGA2_OSD_CUR_FLAGS0,
+ scheduler);
+ job->rga_command_base.osd_info.cur_flags1 = rga_read(RGA2_OSD_CUR_FLAGS1,
+ scheduler);
+ }
+
+ return 0;
+}
+
+static int rga2_irq(struct rga_scheduler_t *scheduler)
+{
+ struct rga_job *job = scheduler->running_job;
+
+ /* The hardware interrupt top-half don't need to lock the scheduler. */
+ if (job == NULL)
+ return IRQ_HANDLED;
+
+ if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state))
+ return IRQ_WAKE_THREAD;
+
+ job->intr_status = rga_read(RGA2_INT, scheduler);
+ job->hw_status = rga_read(RGA2_STATUS2, scheduler);
+ job->cmd_status = rga_read(RGA2_STATUS1, scheduler);
+
+ if (DEBUGGER_EN(INT_FLAG))
+ pr_info("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_RGA2_INT_CUR_CMD_DONE_INT_FLAG | m_RGA2_INT_ALL_CMD_DONE_INT_FLAG)) {
+ set_bit(RGA_JOB_STATE_FINISH, &job->state);
+ } else if (job->intr_status & m_RGA2_INT_ERROR_FLAG_MASK) {
+ set_bit(RGA_JOB_STATE_INTR_ERR, &job->state);
+
+ pr_err("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);
+ }
+
+ /*clear INTR */
+ rga_write(rga_read(RGA2_INT, scheduler) |
+ (m_RGA2_INT_ERROR_CLEAR_MASK |
+ m_RGA2_INT_ALL_CMD_DONE_INT_CLEAR | m_RGA2_INT_NOW_CMD_DONE_INT_CLEAR |
+ m_RGA2_INT_LINE_RD_CLEAR | m_RGA2_INT_LINE_WR_CLEAR),
+ RGA2_INT, scheduler);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int rga2_isr_thread(struct rga_job *job, struct rga_scheduler_t *scheduler)
+{
+ if (DEBUGGER_EN(INT_FLAG))
+ pr_info("isr thread, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n",
+ rga_read(RGA2_INT, scheduler),
+ rga_read(RGA2_STATUS2, scheduler),
+ rga_read(RGA2_STATUS1, scheduler));
+
+ if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) {
+ if (job->hw_status & m_RGA2_STATUS2_RPP_ERROR)
+ pr_err("RGA current status: rpp error!\n");
+ if (job->hw_status & m_RGA2_STATUS2_BUS_ERROR)
+ pr_err("RGA current status: bus error!\n");
+
+ if (job->intr_status & m_RGA2_INT_ERROR_INT_FLAG) {
+ pr_err("RGA bus error intr, please check your configuration and buffer.\n");
+ job->ret = -EFAULT;
+ } else if (job->intr_status & m_RGA2_INT_MMU_INT_FLAG) {
+ pr_err("mmu failed, please check size of the buffer or whether the buffer has been freed.\n");
+ job->ret = -EACCES;
+ }
+
+ if (job->ret == 0) {
+ pr_err("rga intr error[0x%x]!\n", job->intr_status);
+ job->ret = -EFAULT;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+const struct rga_backend_ops rga2_ops = {
+ .get_version = rga2_get_version,
+ .set_reg = rga2_set_reg,
+ .init_reg = rga2_init_reg,
+ .soft_reset = rga2_soft_reset,
+ .read_back_reg = rga2_read_back_reg,
+ .irq = rga2_irq,
+ .isr_thread = rga2_isr_thread,
+};
diff --git a/drivers/video/rockchip/rga3/rga3_reg_info.c b/drivers/video/rockchip/rga3/rga3_reg_info.c
new file mode 100644
index 000000000..2b61833aa
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga3_reg_info.c
@@ -0,0 +1,2191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga3_reg: " fmt
+
+#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 == RGA_RASTER_MODE && 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 == RGA_RASTER_MODE && 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 splitneed 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:
+ pr_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.bg_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)
+ pr_err("RGA3 core[%d] soft reset timeout. SYS_CTRL[0x%x], RO_SRST[0x%x]\n",
+ scheduler->core, rga_read(RGA3_SYS_CTRL, scheduler),
+ rga_read(RGA3_RO_SRST, scheduler));
+ else
+ pr_info("RGA3 core[%d] soft reset complete.\n", scheduler->core);
+}
+
+static int rga3_scale_check(const struct rga3_req *req)
+{
+ u32 win0_saw, win0_sah, win0_daw, win0_dah;
+ u32 win1_saw, win1_sah, win1_daw, win1_dah;
+
+ 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 (((win0_saw >> 3) > win0_daw) || ((win0_sah >> 3) > win0_dah)) {
+ pr_info("win0 unsupported to scaling less than 1/8 times.\n");
+ return -EINVAL;
+ }
+ if (((win0_daw >> 3) > win0_saw) || ((win0_dah >> 3) > win0_sah)) {
+ pr_info("win0 unsupported to scaling more than 8 times.\n");
+ return -EINVAL;
+ }
+
+ 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 (((win1_saw >> 3) > win1_daw) || ((win1_sah >> 3) > win1_dah)) {
+ pr_info("win1 unsupported to scaling less than 1/8 times.\n");
+ return -EINVAL;
+ }
+ if (((win1_daw >> 3) > win1_saw) || ((win1_dah >> 3) > win1_sah)) {
+ pr_info("win1 unsupported to scaling more than 8 times.\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int rga3_check_param(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))) {
+ pr_err("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)) {
+ pr_err("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))) {
+ pr_err("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)) {
+ pr_err("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))) {
+ pr_err("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)) {
+ pr_err("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))) {
+ pr_err("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(req) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void print_debug_info(struct rga3_req *req)
+{
+ pr_info("render_mode:%s, bitblit_mode=%d, rotate_mode:%x\n",
+ rga_get_render_mode_str(req->render_mode), req->bitblt_mode,
+ req->rotate_mode);
+ pr_info("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);
+ pr_info("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));
+ pr_info("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);
+ pr_info("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) {
+ pr_info("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);
+ pr_info("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));
+ pr_info("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);
+ pr_info("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);
+ }
+
+ pr_info("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);
+ pr_info("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);
+
+ pr_info("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);
+ pr_info("alpha: flag %x mode=%s\n",
+ req->alpha_rop_flag, rga_get_blend_mode_str(req->alpha_config.mode));
+ pr_info("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);
+ pr_info("alpha: fg_global_alpha=%x bg_global_alpha=%x\n",
+ req->alpha_config.fg_global_alpha_value, req->alpha_config.bg_global_alpha_value);
+ pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode);
+}
+
+static int rga3_align_check(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))
+ pr_info("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))
+ pr_info("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))
+ pr_info("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))
+ pr_info("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)) {
+ pr_err("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(scheduler->data, &req);
+ if (ret == -EINVAL) {
+ pr_err("req argument is inval\n");
+ return ret;
+ }
+
+ rga3_align_check(&req);
+
+ /* for debug */
+ if (DEBUGGER_EN(MSG))
+ print_debug_info(&req);
+
+ if (rga3_gen_reg_info((uint8_t *) job->cmd_reg, &req) == -1) {
+ pr_err("RKA: gen reg info error\n");
+ return -EINVAL;
+ }
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], generate register cost time %lld us\n",
+ job->request_id, ktime_us_delta(ktime_get(), timestamp));
+
+ return ret;
+}
+
+static void rga3_dump_read_back_reg(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);
+
+ pr_info("CMD_READ_BACK_REG\n");
+ for (i = 0; i < 12; i++)
+ pr_info("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;
+ ktime_t now = ktime_get();
+
+ /*
+ * 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)) {
+ uint32_t *p;
+
+ p = job->cmd_reg;
+ pr_info("CMD_REG\n");
+ for (i = 0; i < 12; i++)
+ pr_info("i = %x : %.8x %.8x %.8x %.8x\n", i,
+ p[0 + i * 4], p[1 + i * 4],
+ p[2 + i * 4], p[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);
+
+ /* cmd buffer flush cache to ddr */
+ rga_dma_sync_flush_range(&job->cmd_reg[0], &job->cmd_reg[50], scheduler);
+
+ rga_write(virt_to_phys(job->cmd_reg), 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(job->cmd_reg[i], 0x100 + i * 4, scheduler);
+
+ rga_write(sys_ctrl, RGA3_SYS_CTRL, scheduler);
+ }
+
+ if (DEBUGGER_EN(REG)) {
+ pr_info("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));
+
+ pr_info("hw_status = 0x%x, cmd_status = 0x%x\n",
+ rga_read(RGA3_STATUS0, scheduler),
+ rga_read(RGA3_CMD_STATE, scheduler));
+ }
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], set register cost time %lld us\n",
+ job->request_id, ktime_us_delta(now, job->timestamp));
+
+ job->hw_running_time = now;
+ job->hw_recoder_time = now;
+
+ if (DEBUGGER_EN(REG))
+ rga3_dump_read_back_reg(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) {
+ pr_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_irq(struct rga_scheduler_t *scheduler)
+{
+ struct rga_job *job = scheduler->running_job;
+
+ if (job == NULL)
+ return IRQ_HANDLED;
+
+ if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state))
+ return IRQ_WAKE_THREAD;
+
+ 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);
+
+ if (DEBUGGER_EN(INT_FLAG))
+ pr_info("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);
+
+ pr_err("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);
+ }
+
+ /*clear INTR */
+ rga_write(m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH | m_RGA3_INT_ERROR_MASK,
+ RGA3_INT_CLR, scheduler);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int rga3_isr_thread(struct rga_job *job, struct rga_scheduler_t *scheduler)
+{
+ if (DEBUGGER_EN(INT_FLAG))
+ pr_info("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) {
+ pr_err("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) {
+ pr_err("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) {
+ pr_err("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) {
+ pr_err("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) {
+ pr_err("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,
+ .irq = rga3_irq,
+ .isr_thread = rga3_isr_thread,
+};
diff --git a/drivers/video/rockchip/rga3/rga_common.c b/drivers/video/rockchip/rga3/rga_common.c
new file mode 100644
index 000000000..80d4821fb
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_common.c
@@ -0,0 +1,772 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Cerf Yu <cerf.yu@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_common: " fmt
+
+#include "rga.h"
+#include "rga_common.h"
+
+bool rga_is_rgb_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_RGBA_8888:
+ case RGA_FORMAT_RGBX_8888:
+ case RGA_FORMAT_RGB_888:
+ case RGA_FORMAT_BGRA_8888:
+ case RGA_FORMAT_BGRX_8888:
+ case RGA_FORMAT_BGR_888:
+ case RGA_FORMAT_RGB_565:
+ case RGA_FORMAT_RGBA_5551:
+ case RGA_FORMAT_RGBA_4444:
+ case RGA_FORMAT_BGR_565:
+ case RGA_FORMAT_BGRA_5551:
+ case RGA_FORMAT_BGRA_4444:
+ case RGA_FORMAT_ARGB_8888:
+ case RGA_FORMAT_XRGB_8888:
+ case RGA_FORMAT_ARGB_5551:
+ case RGA_FORMAT_ARGB_4444:
+ case RGA_FORMAT_ABGR_8888:
+ case RGA_FORMAT_XBGR_8888:
+ case RGA_FORMAT_ABGR_5551:
+ case RGA_FORMAT_ABGR_4444:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_Y4:
+ case RGA_FORMAT_YCbCr_400:
+
+ case RGA_FORMAT_YCbCr_422_SP:
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCbCr_420_SP:
+ case RGA_FORMAT_YCbCr_420_P:
+ case RGA_FORMAT_YCrCb_422_SP:
+ case RGA_FORMAT_YCrCb_422_P:
+ case RGA_FORMAT_YCrCb_420_SP:
+ case RGA_FORMAT_YCrCb_420_P:
+
+ case RGA_FORMAT_YVYU_422:
+ case RGA_FORMAT_YVYU_420:
+ case RGA_FORMAT_VYUY_422:
+ case RGA_FORMAT_VYUY_420:
+ case RGA_FORMAT_YUYV_422:
+ case RGA_FORMAT_YUYV_420:
+ case RGA_FORMAT_UYVY_422:
+ case RGA_FORMAT_UYVY_420:
+
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_alpha_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_RGBA_8888:
+ case RGA_FORMAT_BGRA_8888:
+ case RGA_FORMAT_RGBA_5551:
+ case RGA_FORMAT_RGBA_4444:
+ case RGA_FORMAT_BGRA_5551:
+ case RGA_FORMAT_BGRA_4444:
+ case RGA_FORMAT_ARGB_8888:
+ case RGA_FORMAT_ARGB_5551:
+ case RGA_FORMAT_ARGB_4444:
+ case RGA_FORMAT_ABGR_8888:
+ case RGA_FORMAT_ABGR_5551:
+ case RGA_FORMAT_ABGR_4444:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv420_packed_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YVYU_420:
+ case RGA_FORMAT_VYUY_420:
+ case RGA_FORMAT_YUYV_420:
+ case RGA_FORMAT_UYVY_420:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv420_planar_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YCbCr_420_P:
+ case RGA_FORMAT_YCrCb_420_P:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv420_semi_planar_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YCbCr_420_SP:
+ case RGA_FORMAT_YCrCb_420_SP:
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv422_packed_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YVYU_422:
+ case RGA_FORMAT_VYUY_422:
+ case RGA_FORMAT_YUYV_422:
+ case RGA_FORMAT_UYVY_422:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv422_planar_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCrCb_422_P:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv422_semi_planar_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YCbCr_422_SP:
+ case RGA_FORMAT_YCrCb_422_SP:
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv8bit_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_Y4:
+ case RGA_FORMAT_YCbCr_400:
+
+ case RGA_FORMAT_YCbCr_422_SP:
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCbCr_420_SP:
+ case RGA_FORMAT_YCbCr_420_P:
+ case RGA_FORMAT_YCrCb_422_SP:
+ case RGA_FORMAT_YCrCb_422_P:
+ case RGA_FORMAT_YCrCb_420_SP:
+ case RGA_FORMAT_YCrCb_420_P:
+
+ case RGA_FORMAT_YVYU_422:
+ case RGA_FORMAT_YVYU_420:
+ case RGA_FORMAT_VYUY_422:
+ case RGA_FORMAT_VYUY_420:
+ case RGA_FORMAT_YUYV_422:
+ case RGA_FORMAT_YUYV_420:
+ case RGA_FORMAT_UYVY_422:
+ case RGA_FORMAT_UYVY_420:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv10bit_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_yuv422p_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCrCb_422_P:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rga_is_only_y_format(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_YCbCr_400:
+ case RGA_FORMAT_Y4:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const char *rga_get_format_name(uint32_t format)
+{
+ switch (format) {
+ case RGA_FORMAT_RGBA_8888:
+ return "RGBA8888";
+ case RGA_FORMAT_RGBX_8888:
+ return "RGBX8888";
+ case RGA_FORMAT_RGB_888:
+ return "RGB888";
+ case RGA_FORMAT_BGRA_8888:
+ return "BGRA8888";
+ case RGA_FORMAT_BGRX_8888:
+ return "BGRX8888";
+ case RGA_FORMAT_BGR_888:
+ return "BGR888";
+ case RGA_FORMAT_RGB_565:
+ return "RGB565";
+ case RGA_FORMAT_RGBA_5551:
+ return "RGBA5551";
+ case RGA_FORMAT_RGBA_4444:
+ return "RGBA4444";
+ case RGA_FORMAT_BGR_565:
+ return "BGR565";
+ case RGA_FORMAT_BGRA_5551:
+ return "BGRA5551";
+ case RGA_FORMAT_BGRA_4444:
+ return "BGRA4444";
+
+ case RGA_FORMAT_YCbCr_422_SP:
+ return "YCbCr422SP";
+ case RGA_FORMAT_YCbCr_422_P:
+ return "YCbCr422P";
+ case RGA_FORMAT_YCbCr_420_SP:
+ return "YCbCr420SP";
+ case RGA_FORMAT_YCbCr_420_P:
+ return "YCbCr420P";
+ case RGA_FORMAT_YCrCb_422_SP:
+ return "YCrCb422SP";
+ case RGA_FORMAT_YCrCb_422_P:
+ return "YCrCb422P";
+ case RGA_FORMAT_YCrCb_420_SP:
+ return "YCrCb420SP";
+ case RGA_FORMAT_YCrCb_420_P:
+ return "YCrCb420P";
+
+ case RGA_FORMAT_YVYU_422:
+ return "YVYU422";
+ case RGA_FORMAT_YVYU_420:
+ return "YVYU420";
+ case RGA_FORMAT_VYUY_422:
+ return "VYUY422";
+ case RGA_FORMAT_VYUY_420:
+ return "VYUY420";
+ case RGA_FORMAT_YUYV_422:
+ return "YUYV422";
+ case RGA_FORMAT_YUYV_420:
+ return "YUYV420";
+ case RGA_FORMAT_UYVY_422:
+ return "UYVY422";
+ case RGA_FORMAT_UYVY_420:
+ return "UYVY420";
+
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ return "YCrCb420SP10B";
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ return "YCbCr420SP10B";
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ return "YCbCr422SP10B";
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ return "YCrCb422SP10B";
+ case RGA_FORMAT_BPP1:
+ return "BPP1";
+ case RGA_FORMAT_BPP2:
+ return "BPP2";
+ case RGA_FORMAT_BPP4:
+ return "BPP4";
+ case RGA_FORMAT_BPP8:
+ return "BPP8";
+ case RGA_FORMAT_YCbCr_400:
+ return "YCbCr400";
+ case RGA_FORMAT_Y4:
+ return "y4";
+
+ case RGA_FORMAT_ARGB_8888:
+ return "ARGB8888";
+ case RGA_FORMAT_XRGB_8888:
+ return "XRGB8888";
+ case RGA_FORMAT_ARGB_5551:
+ return "ARGB5551";
+ case RGA_FORMAT_ARGB_4444:
+ return "ARGB4444";
+ case RGA_FORMAT_ABGR_8888:
+ return "ABGR8888";
+ case RGA_FORMAT_XBGR_8888:
+ return "XBGR8888";
+ case RGA_FORMAT_ABGR_5551:
+ return "ABGR5551";
+ case RGA_FORMAT_ABGR_4444:
+ return "ABGR4444";
+
+ case RGA_FORMAT_RGBA_2BPP:
+ return "RGBA2BPP";
+
+ default:
+ return "UNF";
+ }
+}
+
+int rga_get_format_bits(uint32_t format)
+{
+ int bits = 0;
+
+ switch (format) {
+ case RGA_FORMAT_RGBA_8888:
+ case RGA_FORMAT_RGBX_8888:
+ case RGA_FORMAT_BGRA_8888:
+ case RGA_FORMAT_BGRX_8888:
+ case RGA_FORMAT_ARGB_8888:
+ case RGA_FORMAT_XRGB_8888:
+ case RGA_FORMAT_ABGR_8888:
+ case RGA_FORMAT_XBGR_8888:
+ bits = 32;
+ break;
+ case RGA_FORMAT_RGB_888:
+ case RGA_FORMAT_BGR_888:
+ bits = 24;
+ break;
+ case RGA_FORMAT_RGB_565:
+ case RGA_FORMAT_RGBA_5551:
+ case RGA_FORMAT_RGBA_4444:
+ case RGA_FORMAT_BGR_565:
+ case RGA_FORMAT_BGRA_5551:
+ case RGA_FORMAT_BGRA_4444:
+ case RGA_FORMAT_ARGB_5551:
+ case RGA_FORMAT_ARGB_4444:
+ case RGA_FORMAT_ABGR_5551:
+ case RGA_FORMAT_ABGR_4444:
+ case RGA_FORMAT_YCbCr_422_SP:
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCrCb_422_SP:
+ case RGA_FORMAT_YCrCb_422_P:
+ case RGA_FORMAT_YUYV_422:
+ case RGA_FORMAT_YVYU_422:
+ case RGA_FORMAT_UYVY_422:
+ case RGA_FORMAT_VYUY_422:
+ /* YUV 420 packed according to the arrangement of YUV422 packed. */
+ case RGA_FORMAT_YUYV_420:
+ case RGA_FORMAT_YVYU_420:
+ case RGA_FORMAT_UYVY_420:
+ case RGA_FORMAT_VYUY_420:
+ bits = 16;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP:
+ case RGA_FORMAT_YCbCr_420_P:
+ case RGA_FORMAT_YCrCb_420_SP:
+ case RGA_FORMAT_YCrCb_420_P:
+ bits = 12;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ bits = 15;
+ break;
+ case RGA_FORMAT_YCbCr_400:
+ case RGA_FORMAT_BPP8:
+ bits = 8;
+ break;
+ case RGA_FORMAT_Y4:
+ case RGA_FORMAT_BPP4:
+ bits = 4;
+ break;
+ case RGA_FORMAT_BPP2:
+ bits = 2;
+ break;
+ case RGA_FORMAT_BPP1:
+ bits = 1;
+ break;
+ default:
+ pr_err("unknown format [0x%x]\n", format);
+ return -1;
+ }
+
+ return bits;
+}
+
+int rga_get_pixel_stride_from_format(uint32_t format)
+{
+ int pixel_stride = 0;
+
+ switch (format) {
+ case RGA_FORMAT_RGBA_8888:
+ case RGA_FORMAT_RGBX_8888:
+ case RGA_FORMAT_BGRA_8888:
+ case RGA_FORMAT_BGRX_8888:
+ case RGA_FORMAT_ARGB_8888:
+ case RGA_FORMAT_XRGB_8888:
+ case RGA_FORMAT_ABGR_8888:
+ case RGA_FORMAT_XBGR_8888:
+ pixel_stride = 32;
+ break;
+ case RGA_FORMAT_RGB_888:
+ case RGA_FORMAT_BGR_888:
+ pixel_stride = 24;
+ break;
+ case RGA_FORMAT_RGB_565:
+ case RGA_FORMAT_RGBA_5551:
+ case RGA_FORMAT_RGBA_4444:
+ case RGA_FORMAT_BGR_565:
+ case RGA_FORMAT_BGRA_5551:
+ case RGA_FORMAT_BGRA_4444:
+ case RGA_FORMAT_ARGB_5551:
+ case RGA_FORMAT_ARGB_4444:
+ case RGA_FORMAT_ABGR_5551:
+ case RGA_FORMAT_ABGR_4444:
+ case RGA_FORMAT_YVYU_422:
+ case RGA_FORMAT_YVYU_420:
+ case RGA_FORMAT_VYUY_422:
+ case RGA_FORMAT_VYUY_420:
+ case RGA_FORMAT_YUYV_422:
+ case RGA_FORMAT_YUYV_420:
+ case RGA_FORMAT_UYVY_422:
+ case RGA_FORMAT_UYVY_420:
+ pixel_stride = 16;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ pixel_stride = 10;
+ break;
+ case RGA_FORMAT_BPP1:
+ case RGA_FORMAT_BPP2:
+ case RGA_FORMAT_BPP4:
+ case RGA_FORMAT_BPP8:
+ case RGA_FORMAT_YCbCr_400:
+ case RGA_FORMAT_YCbCr_420_SP:
+ case RGA_FORMAT_YCbCr_420_P:
+ case RGA_FORMAT_YCrCb_420_SP:
+ case RGA_FORMAT_YCrCb_420_P:
+ case RGA_FORMAT_YCbCr_422_SP:
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCrCb_422_SP:
+ case RGA_FORMAT_YCrCb_422_P:
+ pixel_stride = 8;
+ break;
+ case RGA_FORMAT_Y4:
+ pixel_stride = 4;
+ break;
+ default:
+ pr_err("unknown format [0x%x]\n", format);
+ return -1;
+ }
+
+ return pixel_stride;
+}
+
+const char *rga_get_render_mode_str(uint8_t mode)
+{
+ switch (mode) {
+ case 0x0:
+ return "bitblt";
+ case 0x1:
+ return "RGA_COLOR_PALETTE";
+ case 0x2:
+ return "RGA_COLOR_FILL";
+ case 0x3:
+ return "update_palette_table";
+ case 0x4:
+ return "update_patten_buff";
+ default:
+ return "UNF";
+ }
+}
+
+const char *rga_get_rotate_mode_str(uint8_t mode)
+{
+ switch (mode) {
+ case 0x0:
+ return "0";
+ case 0x1:
+ return "90 degree";
+ case 0x2:
+ return "180 degree";
+ case 0x3:
+ return "270 degree";
+ case 0x10:
+ return "xmirror";
+ case 0x20:
+ return "ymirror";
+ case 0x30:
+ return "xymirror";
+ default:
+ return "UNF";
+ }
+}
+
+const char *rga_get_blend_mode_str(enum rga_alpha_blend_mode mode)
+{
+ switch (mode) {
+ case RGA_ALPHA_NONE:
+ return "no blend";
+
+ case RGA_ALPHA_BLEND_SRC:
+ return "src";
+
+ case RGA_ALPHA_BLEND_DST:
+ return "dst";
+
+ case RGA_ALPHA_BLEND_SRC_OVER:
+ return "src-over";
+
+ case RGA_ALPHA_BLEND_DST_OVER:
+ return "dst-over";
+
+ case RGA_ALPHA_BLEND_SRC_IN:
+ return "src-in";
+
+ case RGA_ALPHA_BLEND_DST_IN:
+ return "dst-in";
+
+ case RGA_ALPHA_BLEND_SRC_OUT:
+ return "src-out";
+
+ case RGA_ALPHA_BLEND_DST_OUT:
+ return "dst-out";
+
+ case RGA_ALPHA_BLEND_SRC_ATOP:
+ return "src-atop";
+
+ case RGA_ALPHA_BLEND_DST_ATOP:
+ return "dst-atop";
+
+ case RGA_ALPHA_BLEND_XOR:
+ return "xor";
+
+ case RGA_ALPHA_BLEND_CLEAR:
+ return "clear";
+
+ default:
+ return "check reg for more imformation";
+ }
+}
+
+const char *rga_get_memory_type_str(uint8_t type)
+{
+ switch (type) {
+ case RGA_DMA_BUFFER:
+ return "dma_fd";
+ case RGA_VIRTUAL_ADDRESS:
+ return "virt_addr";
+ case RGA_PHYSICAL_ADDRESS:
+ return "phys_addr";
+ case RGA_DMA_BUFFER_PTR:
+ return "dma_buf_ptr";
+ default:
+ return "UNF";
+ }
+}
+
+const char *rga_get_mmu_type_str(enum rga_mmu mmu_type)
+{
+ switch (mmu_type) {
+ case RGA_MMU:
+ return "RGA_MMU";
+ case RGA_IOMMU:
+ return "RK_IOMMU";
+ default:
+ return "NONE_MMU";
+ }
+}
+
+const char *rga_get_core_name(enum RGA_SCHEDULER_CORE core)
+{
+ switch (core) {
+ case RGA_SCHEDULER_RGA3_CORE0:
+ return "RGA3_core0";
+ case RGA_SCHEDULER_RGA3_CORE1:
+ return "RGA3_core1";
+ case RGA_SCHEDULER_RGA2_CORE0:
+ return "RGA2_core0";
+ default:
+ return "unknown_core";
+ }
+}
+
+void rga_convert_addr(struct rga_img_info_t *img, bool before_vir_get_channel)
+{
+ /*
+ * If it is not using dma fd, the virtual/phyical address is assigned
+ * to the address of the corresponding channel.
+ */
+
+ //img->yrgb_addr = img->uv_addr;
+
+ /*
+ * if before_vir_get_channel is true, then convert addr by default
+ * when has iova (before_vir_get_channel is false),
+ * need to consider whether fbc case
+ */
+ if (img->rd_mode != RGA_FBC_MODE || before_vir_get_channel) {
+ img->uv_addr = img->yrgb_addr + (img->vir_w * img->vir_h);
+
+ //warning: rga3 may need /2 for all
+ if (rga_is_yuv422p_format(img->format))
+ img->v_addr =
+ img->uv_addr + (img->vir_w * img->vir_h) / 2;
+ else
+ img->v_addr =
+ img->uv_addr + (img->vir_w * img->vir_h) / 4;
+ } else {
+ img->uv_addr = img->yrgb_addr;
+ img->v_addr = 0;
+ }
+}
+
+void rga_swap_pd_mode(struct rga_req *req_rga)
+{
+ if (((req_rga->alpha_rop_flag) & 1)) {
+ if ((req_rga->alpha_rop_flag >> 3) & 1) {
+ if (req_rga->PD_mode == 1)
+ req_rga->PD_mode = 2;
+ else if (req_rga->PD_mode == 2)
+ req_rga->PD_mode = 1;
+ else if (req_rga->PD_mode == 3)
+ req_rga->PD_mode = 4;
+ else if (req_rga->PD_mode == 4)
+ req_rga->PD_mode = 3;
+ }
+ }
+}
+
+int rga_image_size_cal(int w, int h, int format,
+ int *yrgb_size, int *uv_size, int *v_size)
+{
+ int yrgb = 0;
+ int uv = 0;
+ int v = 0;
+
+ switch (format) {
+ case RGA_FORMAT_RGBA_8888:
+ case RGA_FORMAT_RGBX_8888:
+ case RGA_FORMAT_BGRA_8888:
+ case RGA_FORMAT_BGRX_8888:
+ case RGA_FORMAT_ARGB_8888:
+ case RGA_FORMAT_XRGB_8888:
+ case RGA_FORMAT_ABGR_8888:
+ case RGA_FORMAT_XBGR_8888:
+ yrgb = w * h * 4;
+ break;
+ case RGA_FORMAT_RGB_888:
+ case RGA_FORMAT_BGR_888:
+ yrgb = w * h * 3;
+ break;
+ case RGA_FORMAT_RGB_565:
+ case RGA_FORMAT_RGBA_5551:
+ case RGA_FORMAT_RGBA_4444:
+ case RGA_FORMAT_BGR_565:
+ case RGA_FORMAT_BGRA_5551:
+ case RGA_FORMAT_BGRA_4444:
+ case RGA_FORMAT_ARGB_5551:
+ case RGA_FORMAT_ARGB_4444:
+ case RGA_FORMAT_ABGR_5551:
+ case RGA_FORMAT_ABGR_4444:
+ case RGA_FORMAT_YVYU_422:
+ case RGA_FORMAT_VYUY_422:
+ case RGA_FORMAT_YUYV_422:
+ case RGA_FORMAT_UYVY_422:
+ /* YUV 420 packed according to the arrangement of YUV422 packed. */
+ case RGA_FORMAT_YVYU_420:
+ case RGA_FORMAT_VYUY_420:
+ case RGA_FORMAT_YUYV_420:
+ case RGA_FORMAT_UYVY_420:
+ yrgb = w * h * 2;
+ break;
+ /* YUV FORMAT */
+ case RGA_FORMAT_YCbCr_422_SP:
+ case RGA_FORMAT_YCrCb_422_SP:
+ /* 10bit format stride is externally configured. */
+ case RGA_FORMAT_YCbCr_422_SP_10B:
+ case RGA_FORMAT_YCrCb_422_SP_10B:
+ yrgb = w * h;
+ uv = w * h;
+ break;
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCrCb_422_P:
+ yrgb = w * h;
+ uv = (w * h) >> 1;
+ v = uv;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP:
+ case RGA_FORMAT_YCrCb_420_SP:
+ /* 10bit format stride is externally configured. */
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ yrgb = w * h;
+ uv = (w * h) >> 1;
+ break;
+ case RGA_FORMAT_YCbCr_420_P:
+ case RGA_FORMAT_YCrCb_420_P:
+ yrgb = w * h;
+ uv = (w * h) >> 2;
+ v = uv;
+ break;
+ case RGA_FORMAT_YCbCr_400:
+ yrgb = w * h;
+ break;
+ case RGA_FORMAT_Y4:
+ yrgb = (w * h) >> 1;
+ break;
+ default:
+ pr_err("Unsuport format [0x%x]\n", format);
+ return -EFAULT;
+ }
+
+ if (yrgb_size != NULL)
+ *yrgb_size = yrgb;
+ if (uv_size != NULL)
+ *uv_size = uv;
+ if (v_size != NULL)
+ *v_size = v;
+
+ return (yrgb + uv + v);
+}
+
+void rga_dump_memory_parm(struct rga_memory_parm *parm)
+{
+ pr_info("memory param: w = %d, h = %d, f = %s(0x%x), size = %d\n",
+ parm->width, parm->height, rga_get_format_name(parm->format),
+ parm->format, parm->size);
+}
+
+void rga_dump_external_buffer(struct rga_external_buffer *buffer)
+{
+ pr_info("external: memory = 0x%lx, type = %s\n",
+ (unsigned long)buffer->memory, rga_get_memory_type_str(buffer->type));
+ rga_dump_memory_parm(&buffer->memory_parm);
+}
diff --git a/drivers/video/rockchip/rga3/rga_debugger.c b/drivers/video/rockchip/rga3/rga_debugger.c
new file mode 100644
index 000000000..fe2103147
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_debugger.c
@@ -0,0 +1,970 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author:
+ * Cerf Yu <cerf.yu@rock-chips.com>
+ * Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_debugger: " fmt
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/syscalls.h>
+#include <linux/debugfs.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include "rga.h"
+#include "rga_debugger.h"
+#include "rga_drv.h"
+#include "rga_mm.h"
+#include "rga_common.h"
+
+#define RGA_DEBUGGER_ROOT_NAME "rkrga"
+
+#define STR_ENABLE(en) (en ? "EN" : "DIS")
+
+int RGA_DEBUG_REG;
+int RGA_DEBUG_MSG;
+int RGA_DEBUG_TIME;
+int RGA_DEBUG_INT_FLAG;
+int RGA_DEBUG_MM;
+int RGA_DEBUG_CHECK_MODE;
+int RGA_DEBUG_NONUSE;
+int RGA_DEBUG_DEBUG_MODE;
+int RGA_DEBUG_DUMP_IMAGE;
+
+#ifdef CONFIG_NO_GKI
+static char g_dump_path[100] = "/data";
+#endif
+
+static int rga_debug_show(struct seq_file *m, void *data)
+{
+ seq_printf(m, "REG [%s]\n"
+ "MSG [%s]\n"
+ "TIME [%s]\n"
+ "INT [%s]\n"
+ "MM [%s]\n"
+ "CHECK [%s]\n"
+ "STOP [%s]\n",
+ STR_ENABLE(RGA_DEBUG_REG),
+ STR_ENABLE(RGA_DEBUG_MSG),
+ STR_ENABLE(RGA_DEBUG_TIME),
+ STR_ENABLE(RGA_DEBUG_INT_FLAG),
+ STR_ENABLE(RGA_DEBUG_MM),
+ STR_ENABLE(RGA_DEBUG_CHECK_MODE),
+ STR_ENABLE(RGA_DEBUG_NONUSE));
+
+ seq_puts(m, "\nhelp:\n");
+ seq_puts(m, " 'echo reg > debug' to enable/disable register log printing.\n");
+ seq_puts(m, " 'echo msg > debug' to enable/disable message log printing.\n");
+ seq_puts(m, " 'echo time > debug' to enable/disable time log printing.\n");
+ seq_puts(m, " 'echo int > debug' to enable/disable interruppt log printing.\n");
+ seq_puts(m, " 'echo mm > debug' to enable/disable memory manager log printing.\n");
+ seq_puts(m, " 'echo check > debug' to enable/disable check mode.\n");
+ seq_puts(m, " 'echo stop > debug' to enable/disable stop using hardware\n");
+
+ return 0;
+}
+
+static ssize_t rga_debug_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ char buf[14];
+
+ if (len > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+ buf[len - 1] = '\0';
+
+ if (strncmp(buf, "reg", 4) == 0) {
+ if (RGA_DEBUG_REG) {
+ RGA_DEBUG_REG = 0;
+ pr_info("close rga reg!\n");
+ } else {
+ RGA_DEBUG_REG = 1;
+ pr_info("open rga reg!\n");
+ }
+ } else if (strncmp(buf, "msg", 3) == 0) {
+ if (RGA_DEBUG_MSG) {
+ RGA_DEBUG_MSG = 0;
+ pr_info("close rga test MSG!\n");
+ } else {
+ RGA_DEBUG_MSG = 1;
+ pr_info("open rga test MSG!\n");
+ }
+ } else if (strncmp(buf, "time", 4) == 0) {
+ if (RGA_DEBUG_TIME) {
+ RGA_DEBUG_TIME = 0;
+ pr_info("close rga test time!\n");
+ } else {
+ RGA_DEBUG_TIME = 1;
+ pr_info("open rga test time!\n");
+ }
+ } else if (strncmp(buf, "int", 3) == 0) {
+ if (RGA_DEBUG_INT_FLAG) {
+ RGA_DEBUG_INT_FLAG = 0;
+ pr_info("close inturrupt MSG!\n");
+ } else {
+ RGA_DEBUG_INT_FLAG = 1;
+ pr_info("open inturrupt MSG!\n");
+ }
+ } else if (strncmp(buf, "mm", 2) == 0) {
+ if (RGA_DEBUG_MM) {
+ RGA_DEBUG_MM = 0;
+ pr_info("close rga mm log!\n");
+ } else {
+ RGA_DEBUG_MM = 1;
+ pr_info("open rga mm log!\n");
+ }
+ } else if (strncmp(buf, "check", 5) == 0) {
+ if (RGA_DEBUG_CHECK_MODE) {
+ RGA_DEBUG_CHECK_MODE = 0;
+ pr_info("close rga check flag!\n");
+ } else {
+ RGA_DEBUG_CHECK_MODE = 1;
+ pr_info("open rga check flag!\n");
+ }
+ } else if (strncmp(buf, "stop", 4) == 0) {
+ if (RGA_DEBUG_NONUSE) {
+ RGA_DEBUG_NONUSE = 0;
+ pr_info("using rga hardware!\n");
+ } else {
+ RGA_DEBUG_NONUSE = 1;
+ pr_info("stop using rga hardware!\n");
+ }
+ } else if (strncmp(buf, "debug", 3) == 0) {
+ if (RGA_DEBUG_DEBUG_MODE) {
+ RGA_DEBUG_REG = 0;
+ RGA_DEBUG_MSG = 0;
+ RGA_DEBUG_TIME = 0;
+ RGA_DEBUG_INT_FLAG = 0;
+
+ RGA_DEBUG_DEBUG_MODE = 0;
+ pr_info("close debug mode!\n");
+ } else {
+ RGA_DEBUG_REG = 1;
+ RGA_DEBUG_MSG = 1;
+ RGA_DEBUG_TIME = 1;
+ RGA_DEBUG_INT_FLAG = 1;
+
+ RGA_DEBUG_DEBUG_MODE = 1;
+ pr_info("open debug mode!\n");
+ }
+ } else if (strncmp(buf, "slt", 3) == 0) {
+ pr_err("Null");
+ }
+
+ return len;
+}
+
+static int rga_version_show(struct seq_file *m, void *data)
+{
+ seq_printf(m, "%s: v%s\n", DRIVER_DESC, DRIVER_VERSION);
+
+ return 0;
+}
+
+static int rga_load_show(struct seq_file *m, void *data)
+{
+ struct rga_scheduler_t *scheduler = NULL;
+ struct rga_session_manager *session_manager = NULL;
+ struct rga_session *session = NULL;
+ unsigned long flags;
+ int id = 0;
+ int i;
+ int load;
+ u32 busy_time_total;
+
+ session_manager = rga_drvdata->session_manager;
+
+ seq_printf(m, "num of scheduler = %d\n", rga_drvdata->num_of_scheduler);
+ seq_printf(m, "================= load ==================\n");
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+
+ seq_printf(m, "scheduler[%d]: %s\n",
+ i, dev_driver_string(scheduler->dev));
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ busy_time_total = scheduler->timer.busy_time_record;
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ load = (busy_time_total * 100 / RGA_LOAD_INTERVAL_US);
+ if (load > 100)
+ load = 100;
+
+ seq_printf(m, "\t load = %d%%\n", load);
+ seq_printf(m, "-----------------------------------\n");
+ }
+
+ mutex_lock(&session_manager->lock);
+
+ idr_for_each_entry(&session_manager->ctx_id_idr, session, id)
+ seq_printf(m, "\t process %d: pid = %d, name: %s\n", id,
+ session->tgid, session->pname);
+
+ mutex_unlock(&session_manager->lock);
+
+ return 0;
+}
+
+static int rga_scheduler_show(struct seq_file *m, void *data)
+{
+ struct rga_scheduler_t *scheduler = NULL;
+ int i;
+
+ seq_printf(m, "num of scheduler = %d\n", rga_drvdata->num_of_scheduler);
+ seq_printf(m, "===================================\n");
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+
+ seq_printf(m, "scheduler[%d]: %s\n",
+ i, dev_driver_string(scheduler->dev));
+ seq_printf(m, "-----------------------------------\n");
+ seq_printf(m, "pd_ref = %d\n", scheduler->pd_refcount);
+ }
+
+ return 0;
+}
+
+static int rga_mm_session_show(struct seq_file *m, void *data)
+{
+ int id;
+ struct rga_mm *mm_session = NULL;
+ struct rga_internal_buffer *dump_buffer;
+
+ mm_session = rga_drvdata->mm;
+
+ mutex_lock(&mm_session->lock);
+
+ seq_puts(m, "rga_mm dump:\n");
+ seq_printf(m, "buffer count = %d\n", mm_session->buffer_count);
+ seq_puts(m, "===============================================================\n");
+
+ idr_for_each_entry(&mm_session->memory_idr, dump_buffer, id) {
+ seq_printf(m, "handle = %d refcount = %d mm_flag = 0x%x tgid = %d\n",
+ dump_buffer->handle, kref_read(&dump_buffer->refcount),
+ dump_buffer->mm_flag, dump_buffer->session->tgid);
+
+ switch (dump_buffer->type) {
+ case RGA_DMA_BUFFER:
+ case RGA_DMA_BUFFER_PTR:
+ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer))
+ break;
+
+ seq_puts(m, "dma_buffer:\n");
+ seq_printf(m, "\t dma_buf = %p, iova = 0x%lxsgt = 0x%p, size = %ld, map_core = 0x%x\n",
+ dump_buffer->dma_buffer->dma_buf,
+ (unsigned long)dump_buffer->dma_buffer->iova,
+ dump_buffer->dma_buffer->sgt,
+ dump_buffer->dma_buffer->size,
+ dump_buffer->dma_buffer->scheduler->core);
+
+ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
+ seq_printf(m, "\t is contiguous, pa = 0x%lx\n",
+ (unsigned long)dump_buffer->phys_addr);
+
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ if (dump_buffer->virt_addr == NULL)
+ break;
+ seq_puts(m, "virtual address:\n");
+ seq_printf(m, "\t va = 0x%lx, pages = 0x%p, size = %ld\n",
+ (unsigned long)dump_buffer->virt_addr->addr,
+ dump_buffer->virt_addr->pages,
+ dump_buffer->virt_addr->size);
+
+ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer))
+ break;
+
+ seq_printf(m, "\t iova = 0x%lx, offset = 0x%lx, sgt = 0x%p, size = %ld, map_core = 0x%x\n",
+ (unsigned long)dump_buffer->dma_buffer->iova,
+ (unsigned long)dump_buffer->dma_buffer->offset,
+ dump_buffer->dma_buffer->sgt,
+ dump_buffer->dma_buffer->size,
+ dump_buffer->dma_buffer->scheduler->core);
+
+ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
+ seq_printf(m, "\t is contiguous, pa = 0x%lx\n",
+ (unsigned long)dump_buffer->phys_addr);
+
+ break;
+ case RGA_PHYSICAL_ADDRESS:
+ seq_puts(m, "physical address:\n");
+ seq_printf(m, "\t pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr);
+ break;
+ default:
+ seq_puts(m, "Illegal external buffer!\n");
+ break;
+ }
+
+ seq_puts(m, "---------------------------------------------------------------\n");
+ }
+ mutex_unlock(&mm_session->lock);
+
+ return 0;
+}
+
+static int rga_request_manager_show(struct seq_file *m, void *data)
+{
+ int id, i;
+ struct rga_pending_request_manager *request_manager;
+ struct rga_request *request;
+ struct rga_req *task_list;
+ unsigned long flags;
+ int task_count = 0;
+ int finished_task_count = 0, failed_task_count = 0;
+
+ request_manager = rga_drvdata->pend_request_manager;
+
+ seq_puts(m, "rga internal request dump:\n");
+ seq_printf(m, "request count = %d\n", request_manager->request_count);
+ seq_puts(m, "===============================================================\n");
+
+ mutex_lock(&request_manager->lock);
+
+ idr_for_each_entry(&request_manager->request_idr, request, id) {
+ seq_printf(m, "------------------ request: %d ------------------\n", request->id);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ task_count = request->task_count;
+ finished_task_count = request->finished_task_count;
+ failed_task_count = request->failed_task_count;
+ task_list = request->task_list;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ if (task_list == NULL) {
+ seq_puts(m, "\t can not find task list from id\n");
+ continue;
+ }
+
+ seq_printf(m, "\t set cmd num: %d, finish job: %d, failed job: %d, flags = 0x%x, ref = %d\n",
+ task_count, finished_task_count, failed_task_count,
+ request->flags, kref_read(&request->refcount));
+
+ seq_puts(m, "\t cmd dump:\n\n");
+
+ for (i = 0; i < request->task_count; i++)
+ rga_request_task_debug_info(m, &(task_list[i]));
+ }
+
+ mutex_unlock(&request_manager->lock);
+
+ return 0;
+}
+
+#ifdef CONFIG_NO_GKI
+static int rga_dump_path_show(struct seq_file *m, void *data)
+{
+ seq_printf(m, "dump path: %s\n", g_dump_path);
+
+ return 0;
+}
+
+static ssize_t rga_dump_path_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ char buf[100];
+
+ if (len > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+ buf[len - 1] = '\0';
+
+ snprintf(g_dump_path, sizeof(buf), "%s", buf);
+ pr_info("dump path change to: %s\n", g_dump_path);
+
+ return len;
+}
+
+static int rga_dump_image_show(struct seq_file *m, void *data)
+{
+ seq_printf(m, "dump image count: %d\n", RGA_DEBUG_DUMP_IMAGE);
+
+ return 0;
+}
+
+static ssize_t rga_dump_image_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ int ret;
+ int dump_count = 0;
+ char buf[14];
+
+ if (len > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+ buf[len - 1] = '\0';
+
+ ret = kstrtoint(buf, 10, &dump_count);
+ if (ret) {
+ pr_err("Failed to parse str[%s]\n", buf);
+ return -EFAULT;
+ }
+
+ if (dump_count <= 0) {
+ pr_err("dump_image count is invalid [%d]!\n", dump_count);
+ return -EINVAL;
+ }
+
+ RGA_DEBUG_DUMP_IMAGE = dump_count;
+ pr_info("dump image %d\n", RGA_DEBUG_DUMP_IMAGE);
+
+ return len;
+}
+#endif /* #ifdef CONFIG_NO_GKI */
+
+static int rga_hardware_show(struct seq_file *m, void *data)
+{
+ struct rga_scheduler_t *scheduler = NULL;
+ const struct rga_hw_data *hw_data = NULL;
+ int i;
+
+ seq_puts(m, "===================================\n");
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+ hw_data = scheduler->data;
+
+ seq_printf(m, "%s, core %d: version: %s\n",
+ dev_driver_string(scheduler->dev),
+ scheduler->core, scheduler->version.str);
+ seq_printf(m, "input range: %dx%d ~ %dx%d\n",
+ hw_data->input_range.min.width, hw_data->input_range.min.height,
+ hw_data->input_range.max.width, hw_data->input_range.max.height);
+ seq_printf(m, "output range: %dx%d ~ %dx%d\n",
+ hw_data->output_range.min.width, hw_data->output_range.min.height,
+ hw_data->output_range.max.width, hw_data->output_range.max.height);
+ seq_printf(m, "scale limit: 1/%d ~ %d\n",
+ (1 << hw_data->max_downscale_factor),
+ (1 << hw_data->max_upscale_factor));
+ seq_printf(m, "byte_stride_align: %d\n", hw_data->byte_stride_align);
+ seq_printf(m, "max_byte_stride: %d\n", hw_data->max_byte_stride);
+ seq_printf(m, "csc: RGB2YUV 0x%x YUV2RGB 0x%x\n",
+ hw_data->csc_r2y_mode, hw_data->csc_y2r_mode);
+ seq_printf(m, "feature: 0x%x\n", hw_data->feature);
+ seq_printf(m, "mmu: %s\n", rga_get_mmu_type_str(hw_data->mmu));
+ seq_puts(m, "-----------------------------------\n");
+ }
+
+ return 0;
+}
+
+static struct rga_debugger_list rga_debugger_root_list[] = {
+ {"debug", rga_debug_show, rga_debug_write, NULL},
+ {"driver_version", rga_version_show, NULL, NULL},
+ {"load", rga_load_show, NULL, NULL},
+ {"scheduler_status", rga_scheduler_show, NULL, NULL},
+ {"mm_session", rga_mm_session_show, NULL, NULL},
+ {"request_manager", rga_request_manager_show, NULL, NULL},
+#ifdef CONFIG_NO_GKI
+ {"dump_path", rga_dump_path_show, rga_dump_path_write, NULL},
+ {"dump_image", rga_dump_image_show, rga_dump_image_write, NULL},
+#endif
+ {"hardware", rga_hardware_show, NULL, NULL},
+};
+
+static ssize_t rga_debugger_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *priv = file->private_data;
+ struct rga_debugger_node *node = priv->private;
+
+ if (node->info_ent->write)
+ return node->info_ent->write(file, ubuf, len, offp);
+ else
+ return len;
+}
+
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS
+static int rga_debugfs_open(struct inode *inode, struct file *file)
+{
+ struct rga_debugger_node *node = inode->i_private;
+
+ return single_open(file, node->info_ent->show, node);
+}
+
+static const struct file_operations rga_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = rga_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = rga_debugger_write,
+};
+
+static int rga_debugfs_remove_files(struct rga_debugger *debugger)
+{
+ struct rga_debugger_node *pos, *q;
+ struct list_head *entry_list;
+
+ mutex_lock(&debugger->debugfs_lock);
+
+ /* Delete debugfs entry list */
+ entry_list = &debugger->debugfs_entry_list;
+ list_for_each_entry_safe(pos, q, entry_list, list) {
+ if (pos->dent == NULL)
+ continue;
+ list_del(&pos->list);
+ kfree(pos);
+ pos = NULL;
+ }
+
+ /* Delete all debugfs node in this directory */
+ debugfs_remove_recursive(debugger->debugfs_dir);
+ debugger->debugfs_dir = NULL;
+
+ mutex_unlock(&debugger->debugfs_lock);
+
+ return 0;
+}
+
+static int rga_debugfs_create_files(const struct rga_debugger_list *files,
+ int count, struct dentry *root,
+ struct rga_debugger *debugger)
+{
+ int i;
+ struct dentry *ent;
+ struct rga_debugger_node *tmp;
+
+ for (i = 0; i < count; i++) {
+ tmp = kmalloc(sizeof(struct rga_debugger_node), GFP_KERNEL);
+ if (tmp == NULL) {
+ pr_err("Cannot alloc node path /sys/kernel/debug/%pd/%s\n",
+ root, files[i].name);
+ goto MALLOC_FAIL;
+ }
+
+ tmp->info_ent = &files[i];
+ tmp->debugger = debugger;
+
+ ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
+ root, tmp, &rga_debugfs_fops);
+ if (!ent) {
+ pr_err("Cannot create /sys/kernel/debug/%pd/%s\n", root,
+ files[i].name);
+ goto CREATE_FAIL;
+ }
+
+ tmp->dent = ent;
+
+ mutex_lock(&debugger->debugfs_lock);
+ list_add_tail(&tmp->list, &debugger->debugfs_entry_list);
+ mutex_unlock(&debugger->debugfs_lock);
+ }
+
+ return 0;
+
+CREATE_FAIL:
+ kfree(tmp);
+MALLOC_FAIL:
+ rga_debugfs_remove_files(debugger);
+
+ return -1;
+}
+
+int rga_debugfs_remove(void)
+{
+ struct rga_debugger *debugger;
+
+ debugger = rga_drvdata->debugger;
+
+ rga_debugfs_remove_files(debugger);
+
+ return 0;
+}
+
+int rga_debugfs_init(void)
+{
+ int ret;
+ struct rga_debugger *debugger;
+
+ debugger = rga_drvdata->debugger;
+
+ debugger->debugfs_dir =
+ debugfs_create_dir(RGA_DEBUGGER_ROOT_NAME, NULL);
+ if (IS_ERR_OR_NULL(debugger->debugfs_dir)) {
+ pr_err("failed on mkdir /sys/kernel/debug/%s\n",
+ RGA_DEBUGGER_ROOT_NAME);
+ debugger->debugfs_dir = NULL;
+ return -EIO;
+ }
+
+ ret = rga_debugfs_create_files(rga_debugger_root_list, ARRAY_SIZE(rga_debugger_root_list),
+ debugger->debugfs_dir, debugger);
+ if (ret) {
+ pr_err("Could not install rga_debugger_root_list debugfs\n");
+ goto CREATE_FAIL;
+ }
+
+ return 0;
+
+CREATE_FAIL:
+ rga_debugfs_remove();
+
+ return ret;
+}
+#endif /* #ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS */
+
+#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS
+static int rga_procfs_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ struct rga_debugger_node *node = pde_data(inode);
+#else
+ struct rga_debugger_node *node = PDE_DATA(inode);
+#endif
+
+ return single_open(file, node->info_ent->show, node);
+}
+
+static const struct proc_ops rga_procfs_fops = {
+ .proc_open = rga_procfs_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = rga_debugger_write,
+};
+
+static int rga_procfs_remove_files(struct rga_debugger *debugger)
+{
+ struct rga_debugger_node *pos, *q;
+ struct list_head *entry_list;
+
+ mutex_lock(&debugger->procfs_lock);
+
+ /* Delete procfs entry list */
+ entry_list = &debugger->procfs_entry_list;
+ list_for_each_entry_safe(pos, q, entry_list, list) {
+ if (pos->pent == NULL)
+ continue;
+ list_del(&pos->list);
+ kfree(pos);
+ pos = NULL;
+ }
+
+ /* Delete all procfs node in this directory */
+ proc_remove(debugger->procfs_dir);
+ debugger->procfs_dir = NULL;
+
+ mutex_unlock(&debugger->procfs_lock);
+
+ return 0;
+}
+
+static int rga_procfs_create_files(const struct rga_debugger_list *files,
+ int count, struct proc_dir_entry *root,
+ struct rga_debugger *debugger)
+{
+ int i;
+ struct proc_dir_entry *ent;
+ struct rga_debugger_node *tmp;
+
+ for (i = 0; i < count; i++) {
+ tmp = kmalloc(sizeof(struct rga_debugger_node), GFP_KERNEL);
+ if (tmp == NULL) {
+ pr_err("Cannot alloc node path for /proc/%s/%s\n",
+ RGA_DEBUGGER_ROOT_NAME, files[i].name);
+ goto MALLOC_FAIL;
+ }
+
+ tmp->info_ent = &files[i];
+ tmp->debugger = debugger;
+
+ ent = proc_create_data(files[i].name, S_IFREG | S_IRUGO,
+ root, &rga_procfs_fops, tmp);
+ if (!ent) {
+ pr_err("Cannot create /proc/%s/%s\n",
+ RGA_DEBUGGER_ROOT_NAME, files[i].name);
+ goto CREATE_FAIL;
+ }
+
+ tmp->pent = ent;
+
+ mutex_lock(&debugger->procfs_lock);
+ list_add_tail(&tmp->list, &debugger->procfs_entry_list);
+ mutex_unlock(&debugger->procfs_lock);
+ }
+
+ return 0;
+
+CREATE_FAIL:
+ kfree(tmp);
+MALLOC_FAIL:
+ rga_procfs_remove_files(debugger);
+ return -1;
+}
+
+int rga_procfs_remove(void)
+{
+ struct rga_debugger *debugger;
+
+ debugger = rga_drvdata->debugger;
+
+ rga_procfs_remove_files(debugger);
+
+ return 0;
+}
+
+int rga_procfs_init(void)
+{
+ int ret;
+ struct rga_debugger *debugger;
+
+ debugger = rga_drvdata->debugger;
+
+ debugger->procfs_dir = proc_mkdir(RGA_DEBUGGER_ROOT_NAME, NULL);
+ if (IS_ERR_OR_NULL(debugger->procfs_dir)) {
+ pr_err("failed on mkdir /proc/%s\n", RGA_DEBUGGER_ROOT_NAME);
+ debugger->procfs_dir = NULL;
+ return -EIO;
+ }
+
+ ret = rga_procfs_create_files(rga_debugger_root_list, ARRAY_SIZE(rga_debugger_root_list),
+ debugger->procfs_dir, debugger);
+ if (ret) {
+ pr_err("Could not install rga_debugger_root_list procfs\n");
+ goto CREATE_FAIL;
+ }
+
+ return 0;
+
+CREATE_FAIL:
+ rga_procfs_remove();
+
+ return ret;
+}
+#endif /* #ifdef CONFIG_ROCKCHIP_RGA_PROC_FS */
+
+void rga_request_task_debug_info(struct seq_file *m, struct rga_req *req)
+{
+ seq_printf(m, "\t\t rotate_mode = %d\n", req->rotate_mode);
+ seq_printf(m, "\t\t src: y = %lx uv = %lx v = %lx aw = %d ah = %d vw = %d vh = %d\n",
+ (unsigned long)req->src.yrgb_addr, (unsigned long)req->src.uv_addr,
+ (unsigned long)req->src.v_addr, req->src.act_w, req->src.act_h,
+ req->src.vir_w, req->src.vir_h);
+ seq_printf(m, "\t\t src: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n",
+ req->src.x_offset, req->src.y_offset, req->src.format, req->src.rd_mode);
+
+ if (req->pat.yrgb_addr != 0 || req->pat.uv_addr != 0
+ || req->pat.v_addr != 0) {
+ seq_printf(m, "\t\t pat: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
+ (unsigned long)req->pat.yrgb_addr, (unsigned long)req->pat.uv_addr,
+ (unsigned long)req->pat.v_addr, req->pat.act_w, req->pat.act_h,
+ req->pat.vir_w, req->pat.vir_h);
+ seq_printf(m, "\t\t xoff = %d yoff = %d, format = 0x%x, rd_mode = %d\n",
+ req->pat.x_offset, req->pat.y_offset, req->pat.format, req->pat.rd_mode);
+ }
+
+ seq_printf(m, "\t\t dst: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
+ (unsigned long)req->dst.yrgb_addr, (unsigned long)req->dst.uv_addr,
+ (unsigned long)req->dst.v_addr, req->dst.act_w, req->dst.act_h,
+ req->dst.vir_w, req->dst.vir_h);
+ seq_printf(m, "\t\t dst: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n",
+ req->dst.x_offset, req->dst.y_offset, req->dst.format, req->dst.rd_mode);
+
+ seq_printf(m, "\t\t mmu: mmu_flag=%x en=%x\n",
+ req->mmu_info.mmu_flag, req->mmu_info.mmu_en);
+ seq_printf(m, "\t\t alpha: rop_mode = %x\n", req->alpha_rop_mode);
+ seq_printf(m, "\t\t yuv2rgb mode is %x\n", req->yuv2rgb_mode);
+ seq_printf(m, "\t\t set core = %d, priority = %d, in_fence_fd = %d\n",
+ req->core, req->priority, req->in_fence_fd);
+}
+
+void rga_cmd_print_debug_info(struct rga_req *req)
+{
+ pr_info("render_mode = %d, bitblit_mode=%d, rotate_mode = %d\n",
+ req->render_mode, req->bsfilter_flag,
+ req->rotate_mode);
+
+ pr_info("src: y = %lx uv = %lx v = %lx aw = %d ah = %d vw = %d vh = %d\n",
+ (unsigned long)req->src.yrgb_addr,
+ (unsigned long)req->src.uv_addr,
+ (unsigned long)req->src.v_addr,
+ req->src.act_w, req->src.act_h,
+ req->src.vir_w, req->src.vir_h);
+ pr_info("src: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n",
+ req->src.x_offset, req->src.y_offset,
+ req->src.format, req->src.rd_mode);
+
+ if (req->pat.yrgb_addr != 0 || req->pat.uv_addr != 0
+ || req->pat.v_addr != 0) {
+ pr_info("pat: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
+ (unsigned long)req->pat.yrgb_addr,
+ (unsigned long)req->pat.uv_addr,
+ (unsigned long)req->pat.v_addr,
+ req->pat.act_w, req->pat.act_h,
+ req->pat.vir_w, req->pat.vir_h);
+ pr_info("pat: xoff = %d yoff = %d, format = 0x%x, rd_mode = %d\n",
+ req->pat.x_offset, req->pat.y_offset,
+ req->pat.format, req->pat.rd_mode);
+ }
+
+ pr_info("dst: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
+ (unsigned long)req->dst.yrgb_addr,
+ (unsigned long)req->dst.uv_addr,
+ (unsigned long)req->dst.v_addr,
+ req->dst.act_w, req->dst.act_h,
+ req->dst.vir_w, req->dst.vir_h);
+ pr_info("dst: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n",
+ req->dst.x_offset, req->dst.y_offset,
+ req->dst.format, req->dst.rd_mode);
+
+ pr_info("mmu: mmu_flag=%x en=%x\n",
+ req->mmu_info.mmu_flag, req->mmu_info.mmu_en);
+ pr_info("alpha: rop_mode = %x\n", req->alpha_rop_mode);
+ pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode);
+ pr_info("set core = %d, priority = %d, in_fence_fd = %d\n",
+ req->core, req->priority, req->in_fence_fd);
+}
+
+#ifdef CONFIG_NO_GKI
+static int rga_dump_image_to_file(struct rga_internal_buffer *dump_buffer,
+ const char *channel_name,
+ int plane_id,
+ int core)
+{
+ char file_name[100];
+ struct file *file;
+ size_t size = 0;
+ loff_t pos = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ int ret;
+ struct iosys_map map;
+#endif
+ void *kvaddr = NULL;
+ void *kvaddr_origin = NULL;
+
+ switch (dump_buffer->type) {
+ case RGA_DMA_BUFFER:
+ case RGA_DMA_BUFFER_PTR:
+ if (IS_ERR_OR_NULL(dump_buffer->dma_buffer->dma_buf)) {
+ pr_err("Failed to dump dma_buf 0x%px\n",
+ dump_buffer->dma_buffer->dma_buf);
+ return -EINVAL;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ ret = dma_buf_vmap(dump_buffer->dma_buffer->dma_buf, &map);
+ kvaddr = ret ? NULL : map.vaddr;
+#else
+ kvaddr = dma_buf_vmap(dump_buffer->dma_buffer->dma_buf);
+#endif
+ if (!kvaddr) {
+ pr_err("can't vmap the dma buffer!\n");
+ return -EINVAL;
+ }
+
+ kvaddr_origin = kvaddr;
+ kvaddr += dump_buffer->dma_buffer->offset;
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ kvaddr = vmap(dump_buffer->virt_addr->pages, dump_buffer->virt_addr->page_count,
+ VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+ if (!kvaddr) {
+ pr_err("dump_vaddr vmap error!, 0x%lx\n",
+ (unsigned long)dump_buffer->virt_addr->addr);
+ return -EFAULT;
+ }
+
+ kvaddr_origin = kvaddr;
+ kvaddr += dump_buffer->virt_addr->offset;
+ break;
+ case RGA_PHYSICAL_ADDRESS:
+ kvaddr = phys_to_virt(dump_buffer->phys_addr);
+ break;
+ default:
+ pr_err("unsupported memory type[%x]\n", dump_buffer->type);
+ return -EINVAL;
+ }
+
+ size = dump_buffer->size;
+
+ if (kvaddr == NULL) {
+ pr_err("dump addr is NULL!\n");
+ return -EFAULT;
+ }
+
+ if (size <= 0) {
+ pr_err("dump buffer size[%lx] is invalid!\n", (unsigned long)size);
+ return -EFAULT;
+ }
+
+ if (dump_buffer->memory_parm.width == 0 &&
+ dump_buffer->memory_parm.height == 0)
+ snprintf(file_name, 100, "%s/%d_core%d_%s_plane%d_%s_size%zu_%s.bin",
+ g_dump_path,
+ RGA_DEBUG_DUMP_IMAGE, core, channel_name, plane_id,
+ rga_get_memory_type_str(dump_buffer->type),
+ size,
+ rga_get_format_name(dump_buffer->memory_parm.format));
+ else
+ snprintf(file_name, 100, "%s/%d_core%d_%s_plane%d_%s_w%d_h%d_%s.bin",
+ g_dump_path,
+ RGA_DEBUG_DUMP_IMAGE, core, channel_name, plane_id,
+ rga_get_memory_type_str(dump_buffer->type),
+ dump_buffer->memory_parm.width,
+ dump_buffer->memory_parm.height,
+ rga_get_format_name(dump_buffer->memory_parm.format));
+
+ file = filp_open(file_name, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (!IS_ERR(file)) {
+ kernel_write(file, kvaddr, size, &pos);
+ pr_info("dump image to: %s\n", file_name);
+ fput(file);
+ } else {
+ pr_info("open %s failed\n", file_name);
+ }
+
+ switch (dump_buffer->type) {
+ case RGA_DMA_BUFFER:
+ case RGA_DMA_BUFFER_PTR:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ dma_buf_vunmap(dump_buffer->dma_buffer->dma_buf, &map);
+#else
+ dma_buf_vunmap(dump_buffer->dma_buffer->dma_buf, kvaddr_origin);
+#endif
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ vunmap(kvaddr_origin);
+ break;
+ }
+
+ return 0;
+}
+
+static inline void rga_dump_channel_image(struct rga_job_buffer *job_buffer,
+ const char *channel_name,
+ int core)
+{
+ if (job_buffer->y_addr)
+ rga_dump_image_to_file(job_buffer->y_addr, channel_name, 0, core);
+ if (job_buffer->uv_addr)
+ rga_dump_image_to_file(job_buffer->uv_addr, channel_name, 1, core);
+ if (job_buffer->v_addr)
+ rga_dump_image_to_file(job_buffer->v_addr, channel_name, 2, core);
+}
+
+void rga_dump_job_image(struct rga_job *dump_job)
+{
+ rga_dump_channel_image(&dump_job->src_buffer, "src", dump_job->core);
+ rga_dump_channel_image(&dump_job->src1_buffer, "src1", dump_job->core);
+ rga_dump_channel_image(&dump_job->dst_buffer, "dst", dump_job->core);
+ rga_dump_channel_image(&dump_job->els_buffer, "els", dump_job->core);
+
+ if (RGA_DEBUG_DUMP_IMAGE > 0)
+ RGA_DEBUG_DUMP_IMAGE--;
+}
+#endif /* #ifdef CONFIG_NO_GKI */
diff --git a/drivers/video/rockchip/rga3/rga_dma_buf.c b/drivers/video/rockchip/rga3/rga_dma_buf.c
new file mode 100644
index 000000000..3032ad475
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_dma_buf.c
@@ -0,0 +1,546 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_dma_buf: " fmt
+
+#include "rga_dma_buf.h"
+#include "rga.h"
+#include "rga_common.h"
+#include "rga_job.h"
+#include "rga_debugger.h"
+
+static int rga_dma_info_to_prot(enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ return IOMMU_READ | IOMMU_WRITE;
+ case DMA_TO_DEVICE:
+ return IOMMU_READ;
+ case DMA_FROM_DEVICE:
+ return IOMMU_WRITE;
+ default:
+ return 0;
+ }
+}
+
+int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr,
+ unsigned long v_addr, int format, uint32_t w,
+ uint32_t h, unsigned long *StartAddr, unsigned long *size)
+{
+ uint32_t size_yrgb = 0;
+ uint32_t size_uv = 0;
+ uint32_t size_v = 0;
+ uint32_t stride = 0;
+ unsigned long start, end;
+ uint32_t pageCount;
+
+ switch (format) {
+ case RGA_FORMAT_RGBA_8888:
+ case RGA_FORMAT_RGBX_8888:
+ case RGA_FORMAT_BGRA_8888:
+ case RGA_FORMAT_BGRX_8888:
+ case RGA_FORMAT_ARGB_8888:
+ case RGA_FORMAT_XRGB_8888:
+ case RGA_FORMAT_ABGR_8888:
+ case RGA_FORMAT_XBGR_8888:
+ stride = (w * 4 + 3) & (~3);
+ size_yrgb = stride * h;
+ start = yrgb_addr >> PAGE_SHIFT;
+ end = yrgb_addr + size_yrgb;
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_RGB_888:
+ case RGA_FORMAT_BGR_888:
+ stride = (w * 3 + 3) & (~3);
+ size_yrgb = stride * h;
+ start = yrgb_addr >> PAGE_SHIFT;
+ end = yrgb_addr + size_yrgb;
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_RGB_565:
+ case RGA_FORMAT_RGBA_5551:
+ case RGA_FORMAT_RGBA_4444:
+ case RGA_FORMAT_BGR_565:
+ case RGA_FORMAT_BGRA_5551:
+ case RGA_FORMAT_BGRA_4444:
+ case RGA_FORMAT_ARGB_5551:
+ case RGA_FORMAT_ARGB_4444:
+ case RGA_FORMAT_ABGR_5551:
+ case RGA_FORMAT_ABGR_4444:
+ stride = (w * 2 + 3) & (~3);
+ size_yrgb = stride * h;
+ start = yrgb_addr >> PAGE_SHIFT;
+ end = yrgb_addr + size_yrgb;
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+
+ /* YUV FORMAT */
+ case RGA_FORMAT_YCbCr_422_SP:
+ case RGA_FORMAT_YCrCb_422_SP:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ size_uv = stride * h;
+ start = min(yrgb_addr, uv_addr);
+ start >>= PAGE_SHIFT;
+ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv));
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_YCbCr_422_P:
+ case RGA_FORMAT_YCrCb_422_P:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ size_uv = ((stride >> 1) * h);
+ size_v = ((stride >> 1) * h);
+ start = min3(yrgb_addr, uv_addr, v_addr);
+ start = start >> PAGE_SHIFT;
+ end =
+ max3((yrgb_addr + size_yrgb), (uv_addr + size_uv),
+ (v_addr + size_v));
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP:
+ case RGA_FORMAT_YCrCb_420_SP:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ size_uv = (stride * (h >> 1));
+ start = min(yrgb_addr, uv_addr);
+ start >>= PAGE_SHIFT;
+ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv));
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_YCbCr_420_P:
+ case RGA_FORMAT_YCrCb_420_P:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ size_uv = ((stride >> 1) * (h >> 1));
+ size_v = ((stride >> 1) * (h >> 1));
+ start = min3(yrgb_addr, uv_addr, v_addr);
+ start >>= PAGE_SHIFT;
+ end =
+ max3((yrgb_addr + size_yrgb), (uv_addr + size_uv),
+ (v_addr + size_v));
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_YCbCr_400:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ start = yrgb_addr >> PAGE_SHIFT;
+ end = yrgb_addr + size_yrgb;
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_Y4:
+ stride = ((w + 3) & (~3)) >> 1;
+ size_yrgb = stride * h;
+ start = yrgb_addr >> PAGE_SHIFT;
+ end = yrgb_addr + size_yrgb;
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_YVYU_422:
+ case RGA_FORMAT_VYUY_422:
+ case RGA_FORMAT_YUYV_422:
+ case RGA_FORMAT_UYVY_422:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ size_uv = stride * h;
+ start = min(yrgb_addr, uv_addr);
+ start >>= PAGE_SHIFT;
+ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv));
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_YVYU_420:
+ case RGA_FORMAT_VYUY_420:
+ case RGA_FORMAT_YUYV_420:
+ case RGA_FORMAT_UYVY_420:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ size_uv = (stride * (h >> 1));
+ start = min(yrgb_addr, uv_addr);
+ start >>= PAGE_SHIFT;
+ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv));
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ case RGA_FORMAT_YCbCr_420_SP_10B:
+ case RGA_FORMAT_YCrCb_420_SP_10B:
+ stride = (w + 3) & (~3);
+ size_yrgb = stride * h;
+ size_uv = (stride * (h >> 1));
+ start = min(yrgb_addr, uv_addr);
+ start >>= PAGE_SHIFT;
+ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv));
+ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pageCount = end - start;
+ break;
+ default:
+ pageCount = 0;
+ start = 0;
+ break;
+ }
+
+ *StartAddr = start;
+
+ if (size != NULL)
+ *size = size_yrgb + size_uv + size_v;
+
+ return pageCount;
+}
+
+static dma_addr_t rga_iommu_dma_alloc_iova(struct iommu_domain *domain,
+ size_t size, u64 dma_limit,
+ struct device *dev)
+{
+ struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
+ unsigned long shift, iova_len, iova = 0;
+
+ shift = iova_shift(iovad);
+ iova_len = size >> shift;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0))
+ /*
+ * Freeing non-power-of-two-sized allocations back into the IOVA caches
+ * will come back to bite us badly, so we have to waste a bit of space
+ * rounding up anything cacheable to make sure that can't happen. The
+ * order of the unadjusted size will still match upon freeing.
+ */
+ if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
+ iova_len = roundup_pow_of_two(iova_len);
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
+ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit);
+#else
+ if (dev->bus_dma_mask)
+ dma_limit &= dev->bus_dma_mask;
+#endif
+
+ if (domain->geometry.force_aperture)
+ dma_limit = min(dma_limit, (u64)domain->geometry.aperture_end);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 19, 111) && \
+ LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0))
+ iova = alloc_iova_fast(iovad, iova_len,
+ min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn),
+ true);
+#else
+ iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true);
+#endif
+
+ return (dma_addr_t)iova << shift;
+}
+
+static void rga_iommu_dma_free_iova(struct iommu_domain *domain,
+ dma_addr_t iova, size_t size)
+{
+ struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
+
+ free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad));
+}
+
+static inline struct iommu_domain *rga_iommu_get_dma_domain(struct device *dev)
+{
+ return iommu_get_domain_for_dev(dev);
+}
+
+void rga_iommu_unmap(struct rga_dma_buffer *buffer)
+{
+ if (buffer == NULL)
+ return;
+ if (buffer->iova == 0)
+ return;
+
+ iommu_unmap(buffer->domain, buffer->iova, buffer->size);
+ rga_iommu_dma_free_iova(buffer->domain, buffer->iova, buffer->size);
+}
+
+int rga_iommu_map_sgt(struct sg_table *sgt, size_t size,
+ struct rga_dma_buffer *buffer,
+ struct device *rga_dev)
+{
+ struct iommu_domain *domain = NULL;
+ struct rga_iommu_dma_cookie *cookie;
+ struct iova_domain *iovad;
+ dma_addr_t iova;
+ size_t map_size;
+ unsigned long align_size;
+
+ if (sgt == NULL) {
+ pr_err("can not map iommu, because sgt is null!\n");
+ return -EINVAL;
+ }
+
+ domain = rga_iommu_get_dma_domain(rga_dev);
+ cookie = (void *)domain->iova_cookie;
+ iovad = &cookie->iovad;
+ align_size = iova_align(iovad, size);
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("iova_align size = %ld", align_size);
+
+ iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev);
+ if (!iova) {
+ pr_err("rga_iommu_dma_alloc_iova failed");
+ return -ENOMEM;
+ }
+
+ map_size = iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents,
+ rga_dma_info_to_prot(DMA_BIDIRECTIONAL), GFP_KERNEL);
+ if (map_size < align_size) {
+ pr_err("iommu can not map sgt to iova");
+ rga_iommu_dma_free_iova(domain, iova, align_size);
+ return -EINVAL;
+ }
+
+ buffer->domain = domain;
+ buffer->iova = iova;
+ buffer->size = align_size;
+
+ return 0;
+}
+
+int rga_iommu_map(phys_addr_t paddr, size_t size,
+ struct rga_dma_buffer *buffer,
+ struct device *rga_dev)
+{
+ int ret;
+ struct iommu_domain *domain = NULL;
+ struct rga_iommu_dma_cookie *cookie;
+ struct iova_domain *iovad;
+ dma_addr_t iova;
+ unsigned long align_size;
+
+ if (paddr == 0) {
+ pr_err("can not map iommu, because phys_addr is 0!\n");
+ return -EINVAL;
+ }
+
+ domain = rga_iommu_get_dma_domain(rga_dev);
+ cookie = (void *)domain->iova_cookie;
+ iovad = &cookie->iovad;
+ align_size = iova_align(iovad, size);
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("iova_align size = %ld", align_size);
+
+ iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev);
+ if (!iova) {
+ pr_err("rga_iommu_dma_alloc_iova failed");
+ return -ENOMEM;
+ }
+
+ ret = iommu_map(domain, iova, paddr, align_size,
+ rga_dma_info_to_prot(DMA_BIDIRECTIONAL), GFP_KERNEL);
+ if (ret) {
+ pr_err("iommu can not map phys_addr to iova");
+ rga_iommu_dma_free_iova(domain, iova, align_size);
+ return ret;
+ }
+
+ buffer->domain = domain;
+ buffer->iova = iova;
+ buffer->size = align_size;
+
+ return 0;
+}
+
+int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd)
+{
+ int bits = 32;
+ int temp_data = 0;
+ void *one_line = NULL;
+
+ bits = rga_get_format_bits(format);
+ if (bits < 0)
+ return -1;
+
+ one_line = kzalloc(w * 4, GFP_KERNEL);
+ if (!one_line) {
+ pr_err("kzalloc fail %s[%d]\n", __func__, __LINE__);
+ return 0;
+ }
+
+ temp_data = w * (h - 1) * bits >> 3;
+ if (fd > 0) {
+ pr_info("vaddr is%p, bits is %d, fd check\n", vaddr, bits);
+ memcpy(one_line, (char *)vaddr + temp_data, w * bits >> 3);
+ pr_info("fd check ok\n");
+ } else {
+ pr_info("vir addr memory check.\n");
+ memcpy((void *)((char *)vaddr + temp_data), one_line,
+ w * bits >> 3);
+ pr_info("vir addr check ok.\n");
+ }
+
+ kfree(one_line);
+ return 0;
+}
+
+int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_info_t *img)
+{
+ int ret = 0;
+ void *vaddr;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ struct iosys_map map;
+#endif
+ struct dma_buf *dma_buf;
+
+ dma_buf = rga_dma_buffer->dma_buf;
+
+ if (!IS_ERR_OR_NULL(dma_buf)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ ret = dma_buf_vmap(dma_buf, &map);
+ vaddr = ret ? NULL : map.vaddr;
+#else
+ vaddr = dma_buf_vmap(dma_buf);
+#endif
+ if (vaddr) {
+ ret = rga_virtual_memory_check(vaddr, img->vir_w,
+ img->vir_h, img->format, img->yrgb_addr);
+ } else {
+ pr_err("can't vmap the dma buffer!\n");
+ return -EINVAL;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ dma_buf_vunmap(dma_buf, &map);
+#else
+ dma_buf_vunmap(dma_buf, vaddr);
+#endif
+ }
+
+ return ret;
+}
+
+int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer,
+ enum dma_data_direction dir, struct device *rga_dev)
+{
+ struct dma_buf_attachment *attach = NULL;
+ struct sg_table *sgt = NULL;
+ struct scatterlist *sg = NULL;
+ int i, ret = 0;
+
+ if (dma_buf != NULL) {
+ get_dma_buf(dma_buf);
+ } else {
+ pr_err("dma_buf is invalid[%p]\n", dma_buf);
+ return -EINVAL;
+ }
+
+ attach = dma_buf_attach(dma_buf, rga_dev);
+ if (IS_ERR(attach)) {
+ ret = PTR_ERR(attach);
+ pr_err("Failed to attach dma_buf, ret[%d]\n", ret);
+ goto err_get_attach;
+ }
+
+ sgt = dma_buf_map_attachment(attach, dir);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ pr_err("Failed to map attachment, ret[%d]\n", ret);
+ goto err_get_sgt;
+ }
+
+ rga_dma_buffer->dma_buf = dma_buf;
+ rga_dma_buffer->attach = attach;
+ rga_dma_buffer->sgt = sgt;
+ rga_dma_buffer->iova = sg_dma_address(sgt->sgl);
+ rga_dma_buffer->dir = dir;
+ rga_dma_buffer->size = 0;
+ for_each_sgtable_sg(sgt, sg, i)
+ rga_dma_buffer->size += sg_dma_len(sg);
+
+ return ret;
+
+err_get_sgt:
+ if (attach)
+ dma_buf_detach(dma_buf, attach);
+err_get_attach:
+ if (dma_buf)
+ dma_buf_put(dma_buf);
+
+ return ret;
+}
+
+int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer,
+ enum dma_data_direction dir, struct device *rga_dev)
+{
+ struct dma_buf *dma_buf = NULL;
+ struct dma_buf_attachment *attach = NULL;
+ struct sg_table *sgt = NULL;
+ struct scatterlist *sg = NULL;
+ int i, ret = 0;
+
+ dma_buf = dma_buf_get(fd);
+ if (IS_ERR(dma_buf)) {
+ ret = PTR_ERR(dma_buf);
+ pr_err("Fail to get dma_buf from fd[%d], ret[%d]\n", fd, ret);
+ return ret;
+ }
+
+ attach = dma_buf_attach(dma_buf, rga_dev);
+ if (IS_ERR(attach)) {
+ ret = PTR_ERR(attach);
+ pr_err("Failed to attach dma_buf, ret[%d]\n", ret);
+ goto err_get_attach;
+ }
+
+ sgt = dma_buf_map_attachment(attach, dir);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ pr_err("Failed to map attachment, ret[%d]\n", ret);
+ goto err_get_sgt;
+ }
+
+ rga_dma_buffer->dma_buf = dma_buf;
+ rga_dma_buffer->attach = attach;
+ rga_dma_buffer->sgt = sgt;
+ rga_dma_buffer->iova = sg_dma_address(sgt->sgl);
+ rga_dma_buffer->dir = dir;
+ rga_dma_buffer->size = 0;
+ for_each_sgtable_sg(sgt, sg, i)
+ rga_dma_buffer->size += sg_dma_len(sg);
+
+ return ret;
+
+err_get_sgt:
+ if (attach)
+ dma_buf_detach(dma_buf, attach);
+err_get_attach:
+ if (dma_buf)
+ dma_buf_put(dma_buf);
+
+ return ret;
+}
+
+void rga_dma_unmap_buf(struct rga_dma_buffer *rga_dma_buffer)
+{
+ if (rga_dma_buffer->attach && rga_dma_buffer->sgt)
+ dma_buf_unmap_attachment(rga_dma_buffer->attach,
+ rga_dma_buffer->sgt,
+ rga_dma_buffer->dir);
+
+ if (rga_dma_buffer->attach) {
+ dma_buf_detach(rga_dma_buffer->dma_buf, rga_dma_buffer->attach);
+ dma_buf_put(rga_dma_buffer->dma_buf);
+ }
+}
+
+void rga_dma_sync_flush_range(void *pstart, void *pend, struct rga_scheduler_t *scheduler)
+{
+ dma_sync_single_for_device(scheduler->dev, virt_to_phys(pstart),
+ pend - pstart, DMA_TO_DEVICE);
+}
diff --git a/drivers/video/rockchip/rga3/rga_drv.c b/drivers/video/rockchip/rga3/rga_drv.c
new file mode 100644
index 000000000..351f5db27
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_drv.c
@@ -0,0 +1,1612 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga: " fmt
+
+#include "rga2_reg_info.h"
+#include "rga3_reg_info.h"
+#include "rga_dma_buf.h"
+#include "rga_mm.h"
+
+#include "rga_job.h"
+#include "rga_fence.h"
+#include "rga_hw_config.h"
+
+#include "rga_iommu.h"
+#include "rga_debugger.h"
+#include "rga_common.h"
+
+struct rga_drvdata_t *rga_drvdata;
+
+/* set hrtimer */
+static struct hrtimer timer;
+static ktime_t kt;
+
+static struct rga_session *rga_session_init(void);
+static int rga_session_deinit(struct rga_session *session);
+
+static int rga_mpi_set_channel_buffer(struct dma_buf *dma_buf,
+ struct rga_img_info_t *channel_info,
+ struct rga_session *session)
+{
+ struct rga_external_buffer buffer;
+
+ memset(&buffer, 0x0, sizeof(buffer));
+ buffer.memory = (unsigned long)dma_buf;
+ buffer.type = RGA_DMA_BUFFER_PTR;
+ buffer.memory_parm.width = channel_info->vir_w;
+ buffer.memory_parm.height = channel_info->vir_h;
+ buffer.memory_parm.format = channel_info->format;
+
+ buffer.handle = rga_mm_import_buffer(&buffer, session);
+ if (buffer.handle == 0) {
+ pr_err("can not import dma_buf %p\n", dma_buf);
+ return -EFAULT;
+ }
+ channel_info->yrgb_addr = buffer.handle;
+
+ return 0;
+}
+
+static void rga_mpi_set_channel_info(uint32_t flags_mask, uint32_t flags,
+ struct rga_video_frame_info *mpi_frame,
+ struct rga_img_info_t *channel_info,
+ struct rga_img_info_t *cache_info)
+{
+ uint32_t fix_enable_flag, cache_info_flag;
+
+ switch (flags_mask) {
+ case RGA_CONTEXT_SRC_MASK:
+ fix_enable_flag = RGA_CONTEXT_SRC_FIX_ENABLE;
+ cache_info_flag = RGA_CONTEXT_SRC_CACHE_INFO;
+ break;
+ case RGA_CONTEXT_PAT_MASK:
+ fix_enable_flag = RGA_CONTEXT_PAT_FIX_ENABLE;
+ cache_info_flag = RGA_CONTEXT_PAT_CACHE_INFO;
+ break;
+ case RGA_CONTEXT_DST_MASK:
+ fix_enable_flag = RGA_CONTEXT_DST_FIX_ENABLE;
+ cache_info_flag = RGA_CONTEXT_DST_CACHE_INFO;
+ break;
+ default:
+ return;
+ }
+
+ if (flags & fix_enable_flag) {
+ channel_info->x_offset = mpi_frame->x_offset;
+ channel_info->y_offset = mpi_frame->y_offset;
+ channel_info->act_w = mpi_frame->width;
+ channel_info->act_h = mpi_frame->height;
+ channel_info->vir_w = mpi_frame->vir_w;
+ channel_info->vir_h = mpi_frame->vir_h;
+ channel_info->rd_mode = mpi_frame->rd_mode;
+ channel_info->format = mpi_frame->format;
+
+ if (flags & cache_info_flag) {
+ /* Replace the config of src in ctx with the config of mpi src. */
+ cache_info->x_offset = mpi_frame->x_offset;
+ cache_info->y_offset = mpi_frame->y_offset;
+ cache_info->act_w = mpi_frame->width;
+ cache_info->act_h = mpi_frame->height;
+ cache_info->vir_w = mpi_frame->vir_w;
+ cache_info->vir_h = mpi_frame->vir_h;
+ cache_info->rd_mode = mpi_frame->rd_mode;
+ cache_info->format = mpi_frame->format;
+
+ }
+ }
+}
+
+int rga_mpi_commit(struct rga_mpi_job_t *mpi_job)
+{
+ int ret = 0;
+ struct rga_pending_request_manager *request_manager;
+ struct rga_request *request;
+ struct rga_req *cached_cmd;
+ struct rga_req mpi_cmd;
+ unsigned long flags;
+
+ request_manager = rga_drvdata->pend_request_manager;
+
+ mutex_lock(&request_manager->lock);
+ request = rga_request_lookup(request_manager, mpi_job->ctx_id);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("can not find request from id[%d]", mpi_job->ctx_id);
+ mutex_unlock(&request_manager->lock);
+ return -EINVAL;
+ }
+
+ if (request->task_count > 1) {
+ /* TODO */
+ pr_err("Currently request does not support multiple tasks!");
+ mutex_unlock(&request_manager->lock);
+ return -EINVAL;
+ }
+
+ /*
+ * The mpi commit will use the request repeatedly, so an additional
+ * get() is added here.
+ */
+ rga_request_get(request);
+ mutex_unlock(&request_manager->lock);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ /* TODO: batch mode need mpi async mode */
+ request->sync_mode = RGA_BLIT_SYNC;
+
+ cached_cmd = request->task_list;
+ memcpy(&mpi_cmd, cached_cmd, sizeof(mpi_cmd));
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ /* set channel info */
+ if ((mpi_job->src != NULL) && (request->flags & RGA_CONTEXT_SRC_MASK))
+ rga_mpi_set_channel_info(RGA_CONTEXT_SRC_MASK,
+ request->flags,
+ mpi_job->src,
+ &mpi_cmd.src,
+ &cached_cmd->src);
+
+ if ((mpi_job->pat != NULL) && (request->flags & RGA_CONTEXT_PAT_MASK))
+ rga_mpi_set_channel_info(RGA_CONTEXT_PAT_MASK,
+ request->flags,
+ mpi_job->pat,
+ &mpi_cmd.pat,
+ &cached_cmd->pat);
+
+ if ((mpi_job->dst != NULL) && (request->flags & RGA_CONTEXT_DST_MASK))
+ rga_mpi_set_channel_info(RGA_CONTEXT_DST_MASK,
+ request->flags,
+ mpi_job->dst,
+ &mpi_cmd.dst,
+ &cached_cmd->dst);
+
+ /* set buffer handle */
+ if (mpi_job->dma_buf_src0 != NULL) {
+ ret = rga_mpi_set_channel_buffer(mpi_job->dma_buf_src0,
+ &mpi_cmd.src,
+ request->session);
+ if (ret < 0) {
+ pr_err("src channel set buffer handle failed!\n");
+ goto err_put_request;
+ }
+ }
+
+ if (mpi_job->dma_buf_src1 != NULL) {
+ ret = rga_mpi_set_channel_buffer(mpi_job->dma_buf_src1,
+ &mpi_cmd.pat,
+ request->session);
+ if (ret < 0) {
+ pr_err("src1 channel set buffer handle failed!\n");
+ goto err_put_request;
+ }
+ }
+
+ if (mpi_job->dma_buf_dst != NULL) {
+ ret = rga_mpi_set_channel_buffer(mpi_job->dma_buf_dst,
+ &mpi_cmd.dst,
+ request->session);
+ if (ret < 0) {
+ pr_err("dst channel set buffer handle failed!\n");
+ goto err_put_request;
+ }
+ }
+
+ mpi_cmd.handle_flag = 1;
+ mpi_cmd.mmu_info.mmu_en = 0;
+ mpi_cmd.mmu_info.mmu_flag = 0;
+
+ if (DEBUGGER_EN(MSG))
+ rga_cmd_print_debug_info(&mpi_cmd);
+
+ ret = rga_request_mpi_submit(&mpi_cmd, request);
+ if (ret < 0) {
+ if (ret == -ERESTARTSYS) {
+ if (DEBUGGER_EN(MSG))
+ pr_err("%s, commit mpi job failed, by a software interrupt.\n",
+ __func__);
+ } else {
+ pr_err("%s, commit mpi job failed\n", __func__);
+ }
+
+ goto err_put_request;
+ }
+
+ if ((mpi_job->dma_buf_src0 != NULL) && (mpi_cmd.src.yrgb_addr > 0))
+ rga_mm_release_buffer(mpi_cmd.src.yrgb_addr);
+ if ((mpi_job->dma_buf_src1 != NULL) && (mpi_cmd.pat.yrgb_addr > 0))
+ rga_mm_release_buffer(mpi_cmd.pat.yrgb_addr);
+ if ((mpi_job->dma_buf_dst != NULL) && (mpi_cmd.dst.yrgb_addr > 0))
+ rga_mm_release_buffer(mpi_cmd.dst.yrgb_addr);
+
+ /* copy dst info to mpi job for next node */
+ if (mpi_job->output != NULL) {
+ mpi_job->output->x_offset = mpi_cmd.dst.x_offset;
+ mpi_job->output->y_offset = mpi_cmd.dst.y_offset;
+ mpi_job->output->width = mpi_cmd.dst.act_w;
+ mpi_job->output->height = mpi_cmd.dst.act_h;
+ mpi_job->output->vir_w = mpi_cmd.dst.vir_w;
+ mpi_job->output->vir_h = mpi_cmd.dst.vir_h;
+ mpi_job->output->rd_mode = mpi_cmd.dst.rd_mode;
+ mpi_job->output->format = mpi_cmd.dst.format;
+ }
+
+ return 0;
+
+err_put_request:
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rga_mpi_commit);
+
+int rga_kernel_commit(struct rga_req *cmd)
+{
+ int ret = 0;
+ int request_id;
+ struct rga_user_request kernel_request;
+ struct rga_request *request = NULL;
+ struct rga_session *session = NULL;
+ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager;
+
+ session = rga_session_init();
+ if (IS_ERR(session))
+ return PTR_ERR(session);
+
+ request_id = rga_request_alloc(0, session);
+ if (request_id < 0) {
+ pr_err("request alloc error!\n");
+ ret = request_id;
+ return ret;
+ }
+
+ memset(&kernel_request, 0, sizeof(kernel_request));
+ kernel_request.id = request_id;
+ kernel_request.task_ptr = (uint64_t)(unsigned long)cmd;
+ kernel_request.task_num = 1;
+ kernel_request.sync_mode = RGA_BLIT_SYNC;
+
+ ret = rga_request_check(&kernel_request);
+ if (ret < 0) {
+ pr_err("user request check error!\n");
+ goto err_free_request_by_id;
+ }
+
+ request = rga_request_kernel_config(&kernel_request);
+ if (IS_ERR(request)) {
+ pr_err("request[%d] config failed!\n", kernel_request.id);
+ ret = -EFAULT;
+ goto err_free_request_by_id;
+ }
+
+ if (DEBUGGER_EN(MSG)) {
+ pr_info("kernel blit mode: request id = %d", kernel_request.id);
+ rga_cmd_print_debug_info(cmd);
+ }
+
+ ret = rga_request_submit(request);
+ if (ret < 0) {
+ pr_err("request[%d] submit failed!\n", kernel_request.id);
+ goto err_put_request;
+ }
+
+err_put_request:
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+
+ rga_session_deinit(session);
+
+ return ret;
+
+err_free_request_by_id:
+ mutex_lock(&request_manager->lock);
+
+ request = rga_request_lookup(request_manager, request_id);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("can not find request from id[%d]", request_id);
+ mutex_unlock(&request_manager->lock);
+ return -EINVAL;
+ }
+
+ rga_request_free(request);
+
+ mutex_unlock(&request_manager->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rga_kernel_commit);
+
+static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer)
+{
+ struct rga_drvdata_t *rga = rga_drvdata;
+ struct rga_scheduler_t *scheduler = NULL;
+ struct rga_job *job = NULL;
+ unsigned long flags;
+ int i;
+
+ ktime_t now = ktime_get();
+
+ for (i = 0; i < rga->num_of_scheduler; i++) {
+ scheduler = rga->scheduler[i];
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ /* if timer action on job running */
+ job = scheduler->running_job;
+ if (job) {
+ scheduler->timer.busy_time += ktime_us_delta(now, job->hw_recoder_time);
+ job->hw_recoder_time = now;
+ }
+
+ scheduler->timer.busy_time_record = scheduler->timer.busy_time;
+ scheduler->timer.busy_time = 0;
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ }
+
+ hrtimer_forward_now(timer, kt);
+ return HRTIMER_RESTART;
+}
+
+static void rga_init_timer(void)
+{
+ kt = ktime_set(0, RGA_TIMER_INTERVAL_NS);
+ hrtimer_setup(&timer, hrtimer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
+}
+
+static void rga_cancel_timer(void)
+{
+ hrtimer_cancel(&timer);
+}
+
+#ifndef RGA_DISABLE_PM
+int rga_power_enable(struct rga_scheduler_t *scheduler)
+{
+ int ret = -EINVAL;
+ int i;
+ unsigned long flags;
+
+ pm_runtime_get_sync(scheduler->dev);
+ pm_stay_awake(scheduler->dev);
+
+ for (i = 0; i < scheduler->num_clks; i++) {
+ if (!IS_ERR(scheduler->clks[i])) {
+ ret = clk_prepare_enable(scheduler->clks[i]);
+ if (ret < 0)
+ goto err_enable_clk;
+ }
+ }
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ scheduler->pd_refcount++;
+ if (scheduler->status == RGA_SCHEDULER_IDLE)
+ scheduler->status = RGA_SCHEDULER_WORKING;
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ return 0;
+
+err_enable_clk:
+ for (--i; i >= 0; --i)
+ if (!IS_ERR(scheduler->clks[i]))
+ clk_disable_unprepare(scheduler->clks[i]);
+
+ pm_relax(scheduler->dev);
+ pm_runtime_put_sync_suspend(scheduler->dev);
+
+ return ret;
+}
+
+int rga_power_disable(struct rga_scheduler_t *scheduler)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ if (scheduler->status == RGA_SCHEDULER_IDLE ||
+ scheduler->pd_refcount == 0) {
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ WARN(true, "%s already idle!\n", dev_driver_string(scheduler->dev));
+ return -1;
+ }
+
+ scheduler->pd_refcount--;
+ if (scheduler->pd_refcount == 0)
+ scheduler->status = RGA_SCHEDULER_IDLE;
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ for (i = scheduler->num_clks - 1; i >= 0; i--)
+ if (!IS_ERR(scheduler->clks[i]))
+ clk_disable_unprepare(scheduler->clks[i]);
+
+ pm_relax(scheduler->dev);
+ pm_runtime_put_sync_suspend(scheduler->dev);
+
+ return 0;
+}
+
+static void rga_power_enable_all(void)
+{
+ struct rga_scheduler_t *scheduler = NULL;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+ ret = rga_power_enable(scheduler);
+ if (ret < 0)
+ pr_err("power enable failed");
+ }
+}
+
+static void rga_power_disable_all(void)
+{
+ struct rga_scheduler_t *scheduler = NULL;
+ int i;
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+ rga_power_disable(scheduler);
+ }
+}
+
+#else
+int rga_power_enable(struct rga_scheduler_t *scheduler)
+{
+ return 0;
+}
+
+int rga_power_disable(struct rga_scheduler_t *scheduler)
+{
+ return 0;
+}
+
+static inline void rga_power_enable_all(void) {}
+static inline void rga_power_disable_all(void) {}
+#endif /* #ifndef RGA_DISABLE_PM */
+
+static int rga_session_manager_init(struct rga_session_manager **session_manager_ptr)
+{
+ struct rga_session_manager *session_manager = NULL;
+
+ *session_manager_ptr = kzalloc(sizeof(struct rga_session_manager), GFP_KERNEL);
+ if (*session_manager_ptr == NULL) {
+ pr_err("can not kzalloc for rga_session_manager\n");
+ return -ENOMEM;
+ }
+
+ session_manager = *session_manager_ptr;
+
+ mutex_init(&session_manager->lock);
+
+ idr_init_base(&session_manager->ctx_id_idr, 1);
+
+ return 0;
+}
+
+/*
+ * Called at driver close to release the rga session's id references.
+ */
+static int rga_session_free_remove_idr_cb(int id, void *ptr, void *data)
+{
+ struct rga_session *session = ptr;
+
+ idr_remove(&rga_drvdata->session_manager->ctx_id_idr, session->id);
+ kfree(session);
+
+ return 0;
+}
+
+static int rga_session_free_remove_idr(struct rga_session *session)
+{
+ struct rga_session_manager *session_manager;
+
+ session_manager = rga_drvdata->session_manager;
+
+ mutex_lock(&session_manager->lock);
+
+ session_manager->session_cnt--;
+ idr_remove(&session_manager->ctx_id_idr, session->id);
+
+ mutex_unlock(&session_manager->lock);
+
+ return 0;
+}
+
+static int rga_session_manager_remove(struct rga_session_manager **session_manager_ptr)
+{
+ struct rga_session_manager *session_manager = *session_manager_ptr;
+
+ mutex_lock(&session_manager->lock);
+
+ idr_for_each(&session_manager->ctx_id_idr, &rga_session_free_remove_idr_cb, session_manager);
+ idr_destroy(&session_manager->ctx_id_idr);
+
+ mutex_unlock(&session_manager->lock);
+
+ kfree(*session_manager_ptr);
+
+ *session_manager_ptr = NULL;
+
+ return 0;
+}
+
+static struct rga_session *rga_session_init(void)
+{
+ int new_id;
+
+ struct rga_session_manager *session_manager = NULL;
+ struct rga_session *session = NULL;
+
+ session_manager = rga_drvdata->session_manager;
+ if (session_manager == NULL) {
+ pr_err("rga_session_manager is null!\n");
+ return ERR_PTR(-EFAULT);
+ }
+
+ session = kzalloc(sizeof(*session), GFP_KERNEL);
+ if (!session) {
+ pr_err("rga_session alloc failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mutex_lock(&session_manager->lock);
+
+ idr_preload(GFP_KERNEL);
+ new_id = idr_alloc_cyclic(&session_manager->ctx_id_idr, session, 1, 0, GFP_NOWAIT);
+ idr_preload_end();
+ if (new_id < 0) {
+ mutex_unlock(&session_manager->lock);
+
+ pr_err("rga_session alloc id failed!\n");
+ kfree(session);
+ return ERR_PTR(new_id);
+ }
+
+ session->id = new_id;
+ session_manager->session_cnt++;
+
+ mutex_unlock(&session_manager->lock);
+
+ session->tgid = current->tgid;
+ session->pname = kstrdup_quotable_cmdline(current, GFP_KERNEL);
+
+ return session;
+}
+
+static int rga_session_deinit(struct rga_session *session)
+{
+ rga_request_session_destroy_abort(session);
+ rga_mm_session_release_buffer(session);
+
+ rga_session_free_remove_idr(session);
+
+ kfree(session->pname);
+ kfree(session);
+
+ return 0;
+}
+
+static long rga_ioctl_import_buffer(unsigned long arg, struct rga_session *session)
+{
+ int i;
+ int ret = 0;
+ struct rga_buffer_pool buffer_pool;
+ struct rga_external_buffer *external_buffer = NULL;
+
+ if (unlikely(copy_from_user(&buffer_pool,
+ (struct rga_buffer_pool *)arg,
+ sizeof(buffer_pool)))) {
+ pr_err("rga_buffer_pool copy_from_user failed!\n");
+ return -EFAULT;
+ }
+
+ if (buffer_pool.size > RGA_BUFFER_POOL_SIZE_MAX) {
+ pr_err("Cannot import more than %d buffers at a time!\n",
+ RGA_BUFFER_POOL_SIZE_MAX);
+ return -EFBIG;
+ }
+
+ if (buffer_pool.buffers_ptr == 0) {
+ pr_err("Import buffers is NULL!\n");
+ return -EFAULT;
+ }
+
+ external_buffer = kmalloc(sizeof(struct rga_external_buffer) * buffer_pool.size,
+ GFP_KERNEL);
+ if (external_buffer == NULL) {
+ pr_err("external buffer list alloc error!\n");
+ return -ENOMEM;
+ }
+
+ if (unlikely(copy_from_user(external_buffer,
+ u64_to_user_ptr(buffer_pool.buffers_ptr),
+ sizeof(struct rga_external_buffer) * buffer_pool.size))) {
+ pr_err("rga_buffer_pool external_buffer list copy_from_user failed\n");
+ ret = -EFAULT;
+
+ goto err_free_external_buffer;
+ }
+
+ for (i = 0; i < buffer_pool.size; i++) {
+ if (DEBUGGER_EN(MSG)) {
+ pr_info("import buffer info:\n");
+ rga_dump_external_buffer(&external_buffer[i]);
+ }
+
+ ret = rga_mm_import_buffer(&external_buffer[i], session);
+ if (ret <= 0) {
+ pr_err("buffer[%d] mm import buffer failed! memory = 0x%lx, type = %s(0x%x)\n",
+ i, (unsigned long)external_buffer[i].memory,
+ rga_get_memory_type_str(external_buffer[i].type),
+ external_buffer[i].type);
+
+ goto err_free_external_buffer;
+ }
+
+ external_buffer[i].handle = ret;
+ }
+
+ if (unlikely(copy_to_user(u64_to_user_ptr(buffer_pool.buffers_ptr),
+ external_buffer,
+ sizeof(struct rga_external_buffer) * buffer_pool.size))) {
+ pr_err("rga_buffer_pool external_buffer list copy_to_user failed\n");
+ ret = -EFAULT;
+
+ goto err_free_external_buffer;
+ }
+
+err_free_external_buffer:
+ kfree(external_buffer);
+ return ret;
+}
+
+static long rga_ioctl_release_buffer(unsigned long arg)
+{
+ int i;
+ int ret = 0;
+ struct rga_buffer_pool buffer_pool;
+ struct rga_external_buffer *external_buffer = NULL;
+
+ if (unlikely(copy_from_user(&buffer_pool,
+ (struct rga_buffer_pool *)arg,
+ sizeof(buffer_pool)))) {
+ pr_err("rga_buffer_pool copy_from_user failed!\n");
+ return -EFAULT;
+ }
+
+ if (buffer_pool.size > RGA_BUFFER_POOL_SIZE_MAX) {
+ pr_err("Cannot release more than %d buffers at a time!\n",
+ RGA_BUFFER_POOL_SIZE_MAX);
+ return -EFBIG;
+ }
+
+ if (buffer_pool.buffers_ptr == 0) {
+ pr_err("Release buffers is NULL!\n");
+ return -EFAULT;
+ }
+
+ external_buffer = kmalloc(sizeof(struct rga_external_buffer) * buffer_pool.size,
+ GFP_KERNEL);
+ if (external_buffer == NULL) {
+ pr_err("external buffer list alloc error!\n");
+ return -ENOMEM;
+ }
+
+ if (unlikely(copy_from_user(external_buffer,
+ u64_to_user_ptr(buffer_pool.buffers_ptr),
+ sizeof(struct rga_external_buffer) * buffer_pool.size))) {
+ pr_err("rga_buffer_pool external_buffer list copy_from_user failed\n");
+ ret = -EFAULT;
+
+ goto err_free_external_buffer;
+ }
+
+ for (i = 0; i < buffer_pool.size; i++) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("release buffer handle[%d]\n", external_buffer[i].handle);
+
+ ret = rga_mm_release_buffer(external_buffer[i].handle);
+ if (ret < 0) {
+ pr_err("buffer[%d] mm release buffer failed! handle = %d\n",
+ i, external_buffer[i].handle);
+
+ goto err_free_external_buffer;
+ }
+ }
+
+err_free_external_buffer:
+ kfree(external_buffer);
+ return ret;
+}
+
+static long rga_ioctl_request_create(unsigned long arg, struct rga_session *session)
+{
+ uint32_t id;
+ uint32_t flags;
+
+ if (copy_from_user(&flags, (void *)arg, sizeof(uint32_t))) {
+ pr_err("%s failed to copy from usrer!\n", __func__);
+ return -EFAULT;
+ }
+
+ id = rga_request_alloc(flags, session);
+
+ if (copy_to_user((void *)arg, &id, sizeof(uint32_t))) {
+ pr_err("%s failed to copy to usrer!\n", __func__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static long rga_ioctl_request_submit(unsigned long arg, bool run_enbale)
+{
+ int ret = 0;
+ struct rga_pending_request_manager *request_manager = NULL;
+ struct rga_user_request user_request;
+ struct rga_request *request = NULL;
+
+ request_manager = rga_drvdata->pend_request_manager;
+
+ if (unlikely(copy_from_user(&user_request,
+ (struct rga_user_request *)arg,
+ sizeof(user_request)))) {
+ pr_err("%s copy_from_user failed!\n", __func__);
+ return -EFAULT;
+ }
+
+ ret = rga_request_check(&user_request);
+ if (ret < 0) {
+ pr_err("user request check error!\n");
+ return ret;
+ }
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("config request id = %d", user_request.id);
+
+ request = rga_request_config(&user_request);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("request[%d] config failed!\n", user_request.id);
+ return -EFAULT;
+ }
+
+ if (run_enbale) {
+ ret = rga_request_submit(request);
+ if (ret < 0) {
+ pr_err("request[%d] submit failed!\n", user_request.id);
+ return -EFAULT;
+ }
+
+ if (request->sync_mode == RGA_BLIT_ASYNC) {
+ user_request.release_fence_fd = request->release_fence_fd;
+ if (copy_to_user((struct rga_req *)arg,
+ &user_request, sizeof(user_request))) {
+ pr_err("copy_to_user failed\n");
+ return -EFAULT;
+ }
+ }
+ }
+
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+
+ return 0;
+}
+
+static long rga_ioctl_request_cancel(unsigned long arg)
+{
+ uint32_t id;
+ struct rga_pending_request_manager *request_manager;
+ struct rga_request *request;
+
+ request_manager = rga_drvdata->pend_request_manager;
+ if (request_manager == NULL) {
+ pr_err("rga_pending_request_manager is null!\n");
+ return -EFAULT;
+ }
+
+ if (unlikely(copy_from_user(&id, (uint32_t *)arg, sizeof(uint32_t)))) {
+ pr_err("request id copy_from_user failed!\n");
+ return -EFAULT;
+ }
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("config cancel request id = %d", id);
+
+ mutex_lock(&request_manager->lock);
+
+ request = rga_request_lookup(request_manager, id);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("can not find request from id[%d]", id);
+ mutex_unlock(&request_manager->lock);
+ return -EINVAL;
+ }
+
+ rga_request_put(request);
+
+ mutex_unlock(&request_manager->lock);
+
+ return 0;
+}
+
+static long rga_ioctl_blit(unsigned long arg, uint32_t cmd, struct rga_session *session)
+{
+ int ret = 0;
+ int request_id;
+ struct rga_user_request user_request;
+ struct rga_req *rga_req;
+ struct rga_request *request = NULL;
+ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager;
+
+ request_id = rga_request_alloc(0, session);
+ if (request_id < 0) {
+ pr_err("request alloc error!\n");
+ ret = request_id;
+ return ret;
+ }
+
+ memset(&user_request, 0, sizeof(user_request));
+ user_request.id = request_id;
+ user_request.task_ptr = arg;
+ user_request.task_num = 1;
+ user_request.sync_mode = cmd;
+
+ ret = rga_request_check(&user_request);
+ if (ret < 0) {
+ pr_err("user request check error!\n");
+ goto err_free_request_by_id;
+ }
+
+ request = rga_request_config(&user_request);
+ if (IS_ERR(request)) {
+ pr_err("request[%d] config failed!\n", user_request.id);
+ ret = -EFAULT;
+ goto err_free_request_by_id;
+ }
+
+ rga_req = request->task_list;
+ /* In the BLIT_SYNC/BLIT_ASYNC command, in_fence_fd needs to be set. */
+ request->acquire_fence_fd = rga_req->in_fence_fd;
+
+ ret = rga_request_submit(request);
+ if (ret < 0) {
+ pr_err("request[%d] submit failed!\n", user_request.id);
+ goto err_put_request;
+ }
+
+ if (request->sync_mode == RGA_BLIT_ASYNC) {
+ rga_req->out_fence_fd = request->release_fence_fd;
+ if (copy_to_user((struct rga_req *)arg, rga_req, sizeof(struct rga_req))) {
+ pr_err("copy_to_user failed\n");
+ ret = -EFAULT;
+ goto err_put_request;
+ }
+ }
+
+err_put_request:
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+
+ return ret;
+
+err_free_request_by_id:
+ mutex_lock(&request_manager->lock);
+
+ request = rga_request_lookup(request_manager, request_id);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("can not find request from id[%d]", request_id);
+ mutex_unlock(&request_manager->lock);
+ return -EINVAL;
+ }
+
+ rga_request_free(request);
+
+ mutex_unlock(&request_manager->lock);
+
+ return ret;
+}
+
+static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
+{
+ int ret = 0;
+ int i = 0;
+ int major_version = 0, minor_version = 0;
+ char version[16] = { 0 };
+ struct rga_version_t driver_version;
+ struct rga_hw_versions_t hw_versions;
+ struct rga_drvdata_t *rga = rga_drvdata;
+ struct rga_session *session = file->private_data;
+
+ if (!rga) {
+ pr_err("rga_drvdata is null, rga is not init\n");
+ return -ENODEV;
+ }
+
+ if (DEBUGGER_EN(NONUSE))
+ return 0;
+
+ switch (cmd) {
+ case RGA_BLIT_SYNC:
+ case RGA_BLIT_ASYNC:
+ ret = rga_ioctl_blit(arg, cmd, session);
+
+ break;
+ case RGA_CACHE_FLUSH:
+ case RGA_FLUSH:
+ case RGA_GET_RESULT:
+ break;
+ case RGA_GET_VERSION:
+ sscanf(rga->scheduler[i]->version.str, "%x.%x.%*x",
+ &major_version, &minor_version);
+ snprintf(version, 5, "%x.%02x", major_version, minor_version);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+ /* TODO: userspcae to get version */
+ if (copy_to_user((void *)arg, version, sizeof(version)))
+ ret = -EFAULT;
+#else
+ if (copy_to_user((void *)arg, RGA3_VERSION,
+ sizeof(RGA3_VERSION)))
+ ret = -EFAULT;
+#endif
+ break;
+ case RGA2_GET_VERSION:
+ for (i = 0; i < rga->num_of_scheduler; i++) {
+ if (rga->scheduler[i]->ops == &rga2_ops) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+ if (copy_to_user((void *)arg, rga->scheduler[i]->version.str,
+ sizeof(rga->scheduler[i]->version.str)))
+ ret = -EFAULT;
+#else
+ if (copy_to_user((void *)arg, RGA3_VERSION,
+ sizeof(RGA3_VERSION)))
+ ret = -EFAULT;
+#endif
+ else
+ ret = true;
+
+ break;
+ }
+ }
+
+ /* This will indicate that the RGA2 version number cannot be obtained. */
+ if (ret != true)
+ ret = -EFAULT;
+
+ break;
+
+ case RGA_IOC_GET_HW_VERSION:
+ /* RGA hardware version */
+ hw_versions.size = rga->num_of_scheduler > RGA_HW_SIZE ?
+ RGA_HW_SIZE : rga->num_of_scheduler;
+
+ for (i = 0; i < hw_versions.size; i++) {
+ memcpy(&hw_versions.version[i], &rga->scheduler[i]->version,
+ sizeof(rga->scheduler[i]->version));
+ }
+
+ if (copy_to_user((void *)arg, &hw_versions, sizeof(hw_versions)))
+ ret = -EFAULT;
+ else
+ ret = true;
+
+ break;
+
+ case RGA_IOC_GET_DRVIER_VERSION:
+ /* Driver version */
+ driver_version.major = DRIVER_MAJOR_VERISON;
+ driver_version.minor = DRIVER_MINOR_VERSION;
+ driver_version.revision = DRIVER_REVISION_VERSION;
+ strncpy((char *)driver_version.str, DRIVER_VERSION, sizeof(driver_version.str));
+
+ if (copy_to_user((void *)arg, &driver_version, sizeof(driver_version)))
+ ret = -EFAULT;
+ else
+ ret = true;
+
+ break;
+
+ case RGA_IOC_IMPORT_BUFFER:
+ rga_power_enable_all();
+
+ ret = rga_ioctl_import_buffer(arg, session);
+
+ rga_power_disable_all();
+
+ break;
+
+ case RGA_IOC_RELEASE_BUFFER:
+ rga_power_enable_all();
+
+ ret = rga_ioctl_release_buffer(arg);
+
+ rga_power_disable_all();
+
+ break;
+
+ case RGA_IOC_REQUEST_CREATE:
+ ret = rga_ioctl_request_create(arg, session);
+
+ break;
+
+ case RGA_IOC_REQUEST_SUBMIT:
+ ret = rga_ioctl_request_submit(arg, true);
+
+ break;
+
+ case RGA_IOC_REQUEST_CONFIG:
+ ret = rga_ioctl_request_submit(arg, false);
+
+ break;
+
+ case RGA_IOC_REQUEST_CANCEL:
+ ret = rga_ioctl_request_cancel(arg);
+
+ break;
+
+ case RGA_IMPORT_DMA:
+ case RGA_RELEASE_DMA:
+ default:
+ pr_err("unknown ioctl cmd!\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER
+static int rga_debugger_init(struct rga_debugger **debugger_p)
+{
+ struct rga_debugger *debugger;
+
+ *debugger_p = kzalloc(sizeof(struct rga_debugger), GFP_KERNEL);
+ if (*debugger_p == NULL) {
+ pr_err("can not alloc for rga debugger\n");
+ return -ENOMEM;
+ }
+
+ debugger = *debugger_p;
+
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS
+ mutex_init(&debugger->debugfs_lock);
+ INIT_LIST_HEAD(&debugger->debugfs_entry_list);
+#endif
+
+#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS
+ mutex_init(&debugger->procfs_lock);
+ INIT_LIST_HEAD(&debugger->procfs_entry_list);
+#endif
+
+ rga_debugfs_init();
+ rga_procfs_init();
+
+ return 0;
+}
+
+static int rga_debugger_remove(struct rga_debugger **debugger_p)
+{
+ rga_debugfs_remove();
+ rga_procfs_remove();
+
+ kfree(*debugger_p);
+ *debugger_p = NULL;
+
+ return 0;
+}
+#endif
+
+static int rga_open(struct inode *inode, struct file *file)
+{
+ struct rga_session *session = NULL;
+
+ session = rga_session_init();
+ if (IS_ERR(session))
+ return PTR_ERR(session);
+
+ file->private_data = (void *)session;
+
+ return nonseekable_open(inode, file);
+}
+
+static int rga_release(struct inode *inode, struct file *file)
+{
+ struct rga_session *session = file->private_data;
+
+ rga_session_deinit(session);
+
+ return 0;
+}
+
+static irqreturn_t rga_irq_handler(int irq, void *data)
+{
+ irqreturn_t irq_ret = IRQ_NONE;
+ struct rga_scheduler_t *scheduler = data;
+
+ if (scheduler->ops->irq)
+ irq_ret = scheduler->ops->irq(scheduler);
+
+ return irq_ret;
+}
+
+static irqreturn_t rga_isr_thread(int irq, void *data)
+{
+ irqreturn_t irq_ret = IRQ_NONE;
+ struct rga_scheduler_t *scheduler = data;
+ struct rga_job *job;
+
+ job = rga_job_done(scheduler);
+ if (job == NULL) {
+ pr_err("isr thread invalid job!\n");
+ return IRQ_HANDLED;
+ }
+
+ if (scheduler->ops->isr_thread)
+ irq_ret = scheduler->ops->isr_thread(job, scheduler);
+
+ rga_request_release_signal(scheduler, job);
+
+ rga_job_next(scheduler);
+
+ rga_power_disable(scheduler);
+
+ return irq_ret;
+}
+
+const struct file_operations rga_fops = {
+ .owner = THIS_MODULE,
+ .open = rga_open,
+ .release = rga_release,
+ .unlocked_ioctl = rga_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = rga_ioctl,
+#endif
+};
+
+static struct miscdevice rga_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "rga",
+ .fops = &rga_fops,
+};
+
+static const char *const old_rga2_clks[] = {
+ "aclk_rga",
+ "hclk_rga",
+ "clk_rga",
+};
+
+static const char *const rk3588_rga2_clks[] = {
+ "aclk_rga2",
+ "hclk_rga2",
+ "clk_rga2",
+};
+
+static const char *const rga3_core_0_clks[] = {
+ "aclk_rga3_0",
+ "hclk_rga3_0",
+ "clk_rga3_0",
+};
+
+static const char *const rga3_core_1_clks[] = {
+ "aclk_rga3_1",
+ "hclk_rga3_1",
+ "clk_rga3_1",
+};
+
+static const struct rga_match_data_t old_rga2_match_data = {
+ .clks = old_rga2_clks,
+ .num_clks = ARRAY_SIZE(old_rga2_clks),
+};
+
+static const struct rga_match_data_t rk3588_rga2_match_data = {
+ .clks = rk3588_rga2_clks,
+ .num_clks = ARRAY_SIZE(rk3588_rga2_clks),
+};
+
+static const struct rga_match_data_t rga3_core0_match_data = {
+ .clks = rga3_core_0_clks,
+ .num_clks = ARRAY_SIZE(rga3_core_0_clks),
+};
+
+static const struct rga_match_data_t rga3_core1_match_data = {
+ .clks = rga3_core_1_clks,
+ .num_clks = ARRAY_SIZE(rga3_core_1_clks),
+};
+
+static const struct of_device_id rga3_core0_dt_ids[] = {
+ {
+ .compatible = "rockchip,rga3_core0",
+ .data = &rga3_core0_match_data,
+ },
+ {},
+};
+
+static const struct of_device_id rga3_core1_dt_ids[] = {
+ {
+ .compatible = "rockchip,rga3_core1",
+ .data = &rga3_core1_match_data,
+ },
+ {},
+};
+
+static const struct of_device_id rga2_dt_ids[] = {
+ {
+ .compatible = "rockchip,rga2_core0",
+ .data = &rk3588_rga2_match_data,
+ },
+ {
+ .compatible = "rockchip,rga2",
+ .data = &old_rga2_match_data,
+ },
+ {},
+};
+
+static void init_scheduler(struct rga_scheduler_t *scheduler,
+ const char *name)
+{
+ spin_lock_init(&scheduler->irq_lock);
+ INIT_LIST_HEAD(&scheduler->todo_list);
+ init_waitqueue_head(&scheduler->job_done_wq);
+
+ if (!strcmp(name, "rga3_core0")) {
+ scheduler->ops = &rga3_ops;
+ /* TODO: get by hw version */
+ scheduler->core = RGA3_SCHEDULER_CORE0;
+ } else if (!strcmp(name, "rga3_core1")) {
+ scheduler->ops = &rga3_ops;
+ scheduler->core = RGA3_SCHEDULER_CORE1;
+ } else if (!strcmp(name, "rga2")) {
+ scheduler->ops = &rga2_ops;
+ scheduler->core = RGA2_SCHEDULER_CORE0;
+ }
+}
+
+static int rga_drv_probe(struct platform_device *pdev)
+{
+#ifndef RGA_DISABLE_PM
+ int i;
+#endif
+ int ret = 0;
+ int irq;
+ struct resource *res;
+ const struct rga_match_data_t *match_data;
+ const struct of_device_id *match;
+ struct rga_scheduler_t *scheduler;
+ struct device *dev = &pdev->dev;
+ struct rga_drvdata_t *data = rga_drvdata;
+
+ if (!dev->of_node)
+ return -EINVAL;
+
+ if (!strcmp(dev_driver_string(dev), "rga3_core0"))
+ match = of_match_device(rga3_core0_dt_ids, dev);
+ else if (!strcmp(dev_driver_string(dev), "rga3_core1"))
+ match = of_match_device(rga3_core1_dt_ids, dev);
+ else if (!strcmp(dev_driver_string(dev), "rga2"))
+ match = of_match_device(rga2_dt_ids, dev);
+ else
+ match = NULL;
+
+ if (!match) {
+ dev_err(dev, "%s missing DT entry!\n", dev_driver_string(dev));
+ return -EINVAL;
+ }
+
+ scheduler = devm_kzalloc(dev, sizeof(struct rga_scheduler_t), GFP_KERNEL);
+ if (scheduler == NULL) {
+ pr_err("failed to allocate scheduler. dev name = %s\n", dev_driver_string(dev));
+ return -ENOMEM;
+ }
+
+ init_scheduler(scheduler, dev_driver_string(dev));
+
+ scheduler->dev = dev;
+
+ /* map the registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("get memory resource failed.\n");
+ return -ENXIO;
+ }
+
+ scheduler->rga_base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!scheduler->rga_base) {
+ pr_err("ioremap failed\n");
+ ret = -ENOENT;
+ return ret;
+ }
+
+ /* get the IRQ */
+ match_data = match->data;
+
+ /* there are irq names in dts */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no irq %s in dts\n", dev_driver_string(dev));
+ return irq;
+ }
+
+ scheduler->irq = irq;
+
+ pr_info("%s, irq = %d, match scheduler\n", dev_driver_string(dev), irq);
+
+ ret = devm_request_threaded_irq(dev, irq,
+ rga_irq_handler,
+ rga_isr_thread,
+ IRQF_SHARED,
+ dev_driver_string(dev), scheduler);
+ if (ret < 0) {
+ pr_err("request irq name: %s failed: %d\n", dev_driver_string(dev), ret);
+ return ret;
+ }
+
+
+#ifndef RGA_DISABLE_PM
+ /* clk init */
+ for (i = 0; i < match_data->num_clks; i++) {
+ struct clk *clk = devm_clk_get(dev, match_data->clks[i]);
+
+ if (IS_ERR(clk))
+ pr_err("failed to get %s\n", match_data->clks[i]);
+
+ scheduler->clks[i] = clk;
+ }
+ scheduler->num_clks = match_data->num_clks;
+
+ /* PM init */
+ device_init_wakeup(dev, true);
+ pm_runtime_enable(scheduler->dev);
+
+ ret = pm_runtime_get_sync(scheduler->dev);
+ if (ret < 0) {
+ pr_err("failed to get pm runtime, ret = %d\n", ret);
+ goto pm_disable;
+ }
+
+ for (i = 0; i < scheduler->num_clks; i++) {
+ if (!IS_ERR(scheduler->clks[i])) {
+ ret = clk_prepare_enable(scheduler->clks[i]);
+ if (ret < 0) {
+ pr_err("failed to enable clk\n");
+ goto pm_disable;
+ }
+ }
+ }
+#endif /* #ifndef RGA_DISABLE_PM */
+
+ scheduler->ops->get_version(scheduler);
+ pr_info("%s hardware loaded successfully, hw_version:%s.\n",
+ dev_driver_string(dev), scheduler->version.str);
+
+ /* TODO: get by hw version, Currently only supports judgment 1106. */
+ if (scheduler->core == RGA3_SCHEDULER_CORE0 ||
+ scheduler->core == RGA3_SCHEDULER_CORE1) {
+ scheduler->data = &rga3_data;
+ } else if (scheduler->core == RGA2_SCHEDULER_CORE0) {
+ if (!strcmp(scheduler->version.str, "3.3.87975"))
+ scheduler->data = &rga2e_1106_data;
+ else if (!strcmp(scheduler->version.str, "3.6.92812") ||
+ !strcmp(scheduler->version.str, "3.7.93215"))
+ scheduler->data = &rga2e_iommu_data;
+ else
+ scheduler->data = &rga2e_data;
+ }
+
+ data->scheduler[data->num_of_scheduler] = scheduler;
+
+ data->num_of_scheduler++;
+
+#ifndef RGA_DISABLE_PM
+ for (i = scheduler->num_clks - 1; i >= 0; i--)
+ if (!IS_ERR(scheduler->clks[i]))
+ clk_disable_unprepare(scheduler->clks[i]);
+
+ pm_runtime_put_sync(dev);
+#endif /* #ifndef RGA_DISABLE_PM */
+
+ if (scheduler->data->mmu == RGA_IOMMU) {
+ scheduler->iommu_info = rga_iommu_probe(dev);
+ if (IS_ERR(scheduler->iommu_info)) {
+ dev_err(dev, "failed to attach iommu\n");
+ scheduler->iommu_info = NULL;
+ }
+ }
+
+ platform_set_drvdata(pdev, scheduler);
+
+ pr_info("%s probe successfully\n", dev_driver_string(dev));
+
+ return 0;
+
+#ifndef RGA_DISABLE_PM
+pm_disable:
+ device_init_wakeup(dev, false);
+ pm_runtime_disable(dev);
+#endif /* #ifndef RGA_DISABLE_PM */
+
+ return ret;
+}
+
+static void rga_drv_remove(struct platform_device *pdev)
+{
+#ifndef RGA_DISABLE_PM
+ device_init_wakeup(&pdev->dev, false);
+ pm_runtime_disable(&pdev->dev);
+#endif /* #ifndef RGA_DISABLE_PM */
+
+ return;
+}
+
+static struct platform_driver rga3_core0_driver = {
+ .probe = rga_drv_probe,
+ .remove = rga_drv_remove,
+ .driver = {
+ .name = "rga3_core0",
+ .of_match_table = of_match_ptr(rga3_core0_dt_ids),
+ },
+};
+
+static struct platform_driver rga3_core1_driver = {
+ .probe = rga_drv_probe,
+ .remove = rga_drv_remove,
+ .driver = {
+ .name = "rga3_core1",
+ .of_match_table = of_match_ptr(rga3_core1_dt_ids),
+ },
+};
+
+static struct platform_driver rga2_driver = {
+ .probe = rga_drv_probe,
+ .remove = rga_drv_remove,
+ .driver = {
+ .name = "rga2",
+ .of_match_table = of_match_ptr(rga2_dt_ids),
+ },
+};
+
+static int __init rga_init(void)
+{
+ int ret;
+
+ rga_drvdata = kzalloc(sizeof(struct rga_drvdata_t), GFP_KERNEL);
+ if (rga_drvdata == NULL) {
+ pr_err("failed to allocate driver data.\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&rga_drvdata->lock);
+
+ ret = platform_driver_register(&rga3_core0_driver);
+ if (ret != 0) {
+ pr_err("Platform device rga3_core0_driver register failed (%d).\n", ret);
+ goto err_free_drvdata;
+ }
+
+ ret = platform_driver_register(&rga3_core1_driver);
+ if (ret != 0) {
+ pr_err("Platform device rga3_core1_driver register failed (%d).\n", ret);
+ goto err_unregister_rga3_core0;
+ }
+
+ ret = platform_driver_register(&rga2_driver);
+ if (ret != 0) {
+ pr_err("Platform device rga2_driver register failed (%d).\n", ret);
+ goto err_unregister_rga3_core1;
+ }
+
+ ret = rga_iommu_bind();
+ if (ret < 0) {
+ pr_err("rga iommu bind failed!\n");
+ goto err_unregister_rga2;
+ }
+
+ ret = misc_register(&rga_dev);
+ if (ret) {
+ pr_err("cannot register miscdev (%d)\n", ret);
+ goto err_unbind_iommu;
+ }
+
+ rga_init_timer();
+
+ rga_mm_init(&rga_drvdata->mm);
+
+ rga_request_manager_init(&rga_drvdata->pend_request_manager);
+
+ rga_session_manager_init(&rga_drvdata->session_manager);
+
+#ifdef CONFIG_ROCKCHIP_RGA_ASYNC
+ rga_fence_context_init(&rga_drvdata->fence_ctx);
+#endif
+
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER
+ rga_debugger_init(&rga_drvdata->debugger);
+#endif
+
+ pr_info("Module initialized. v%s\n", DRIVER_VERSION);
+
+ return 0;
+
+err_unbind_iommu:
+ rga_iommu_unbind();
+
+err_unregister_rga2:
+ platform_driver_unregister(&rga2_driver);
+
+err_unregister_rga3_core1:
+ platform_driver_unregister(&rga3_core1_driver);
+
+err_unregister_rga3_core0:
+ platform_driver_unregister(&rga3_core0_driver);
+
+err_free_drvdata:
+ kfree(rga_drvdata);
+
+ return ret;
+}
+
+static void __exit rga_exit(void)
+{
+#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER
+ rga_debugger_remove(&rga_drvdata->debugger);
+#endif
+
+#ifdef CONFIG_ROCKCHIP_RGA_ASYNC
+ rga_fence_context_remove(&rga_drvdata->fence_ctx);
+#endif
+
+ rga_mm_remove(&rga_drvdata->mm);
+
+ rga_request_manager_remove(&rga_drvdata->pend_request_manager);
+
+ rga_session_manager_remove(&rga_drvdata->session_manager);
+
+ rga_cancel_timer();
+
+ rga_iommu_unbind();
+
+ platform_driver_unregister(&rga3_core0_driver);
+ platform_driver_unregister(&rga3_core1_driver);
+ platform_driver_unregister(&rga2_driver);
+
+ misc_deregister(&rga_dev);
+
+ kfree(rga_drvdata);
+
+ pr_info("Module exited. v%s\n", DRIVER_VERSION);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
+module_init(rga_init);
+#elif defined CONFIG_VIDEO_REVERSE_IMAGE
+fs_initcall(rga_init);
+#else
+late_initcall(rga_init);
+#endif
+#else
+fs_initcall(rga_init);
+#endif
+module_exit(rga_exit);
+
+/* Module information */
+MODULE_AUTHOR("putin.li@rock-chips.com");
+MODULE_DESCRIPTION("Driver for rga device");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_IMPORT_NS
+MODULE_IMPORT_NS("DMA_BUF");
+#endif
diff --git a/drivers/video/rockchip/rga3/rga_fence.c b/drivers/video/rockchip/rga3/rga_fence.c
new file mode 100644
index 000000000..7d831d55d
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_fence.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_fence: " fmt
+
+#include <linux/dma-fence.h>
+#include <linux/sync_file.h>
+#include <linux/slab.h>
+
+#include "rga_drv.h"
+#include "rga_fence.h"
+
+static const char *rga_fence_get_name(struct dma_fence *fence)
+{
+ return DRIVER_NAME;
+}
+
+static const struct dma_fence_ops rga_fence_ops = {
+ .get_driver_name = rga_fence_get_name,
+ .get_timeline_name = rga_fence_get_name,
+};
+
+int rga_fence_context_init(struct rga_fence_context **ctx)
+{
+ struct rga_fence_context *fence_ctx = NULL;
+
+ fence_ctx = kzalloc(sizeof(struct rga_fence_context), GFP_KERNEL);
+ if (!fence_ctx) {
+ pr_err("can not kzalloc for rga_fence_context!\n");
+ return -ENOMEM;
+ }
+
+ fence_ctx->context = dma_fence_context_alloc(1);
+ spin_lock_init(&fence_ctx->spinlock);
+
+ *ctx = fence_ctx;
+
+ return 0;
+}
+
+void rga_fence_context_remove(struct rga_fence_context **ctx)
+{
+ if (*ctx == NULL)
+ return;
+
+ kfree(*ctx);
+ *ctx = NULL;
+}
+
+struct dma_fence *rga_dma_fence_alloc(void)
+{
+ struct rga_fence_context *fence_ctx = rga_drvdata->fence_ctx;
+ struct dma_fence *fence = NULL;
+
+ if (fence_ctx == NULL) {
+ pr_err("fence_context is NULL!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+ if (!fence)
+ return ERR_PTR(-ENOMEM);
+
+ dma_fence_init(fence, &rga_fence_ops, &fence_ctx->spinlock,
+ fence_ctx->context, ++fence_ctx->seqno);
+
+ return fence;
+}
+
+int rga_dma_fence_get_fd(struct dma_fence *fence)
+{
+ struct sync_file *sync_file = NULL;
+ int fence_fd = -1;
+
+ if (!fence)
+ return -EINVAL;
+
+ fence_fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fence_fd < 0)
+ return fence_fd;
+
+ sync_file = sync_file_create(fence);
+ if (!sync_file) {
+ put_unused_fd(fence_fd);
+ return -ENOMEM;
+ }
+
+ fd_install(fence_fd, sync_file->file);
+
+ return fence_fd;
+}
+
+struct dma_fence *rga_get_dma_fence_from_fd(int fence_fd)
+{
+ struct dma_fence *fence;
+
+ fence = sync_file_get_fence(fence_fd);
+ if (!fence)
+ pr_err("can not get fence from fd\n");
+
+ return fence;
+}
+
+int rga_dma_fence_wait(struct dma_fence *fence)
+{
+ int ret = 0;
+
+ ret = dma_fence_wait(fence, true);
+
+ dma_fence_put(fence);
+
+ return ret;
+}
+
+int rga_dma_fence_add_callback(struct dma_fence *fence, dma_fence_func_t func, void *private)
+{
+ int ret;
+ struct rga_fence_waiter *waiter = NULL;
+
+ waiter = kmalloc(sizeof(*waiter), GFP_KERNEL);
+ if (!waiter) {
+ pr_err("%s: Failed to allocate waiter\n", __func__);
+ return -ENOMEM;
+ }
+
+ waiter->private = private;
+
+ ret = dma_fence_add_callback(fence, &waiter->waiter, func);
+ if (ret == -ENOENT) {
+ pr_err("'input fence' has been already signaled.");
+ goto err_free_waiter;
+ } else if (ret == -EINVAL) {
+ pr_err("%s: failed to add callback to dma_fence, err: %d\n", __func__, ret);
+ goto err_free_waiter;
+ }
+
+ return ret;
+
+err_free_waiter:
+ kfree(waiter);
+ return ret;
+}
diff --git a/drivers/video/rockchip/rga3/rga_hw_config.c b/drivers/video/rockchip/rga3/rga_hw_config.c
new file mode 100644
index 000000000..0cf2599b9
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_hw_config.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author:
+ * Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#include "rga_hw_config.h"
+
+/* RGA 1Word = 4Byte */
+#define WORD_TO_BYTE(w) ((w) * 4)
+
+const uint32_t rga3_input_raster_format[] = {
+ RGA_FORMAT_RGBA_8888,
+ RGA_FORMAT_BGRA_8888,
+ RGA_FORMAT_RGB_888,
+ RGA_FORMAT_BGR_888,
+ RGA_FORMAT_RGB_565,
+ RGA_FORMAT_BGR_565,
+ RGA_FORMAT_YCbCr_422_SP,
+ RGA_FORMAT_YCbCr_420_SP,
+ RGA_FORMAT_YCrCb_422_SP,
+ RGA_FORMAT_YCrCb_420_SP,
+ RGA_FORMAT_YVYU_422,
+ RGA_FORMAT_VYUY_422,
+ RGA_FORMAT_YUYV_422,
+ RGA_FORMAT_UYVY_422,
+ RGA_FORMAT_YCbCr_420_SP_10B,
+ RGA_FORMAT_YCrCb_420_SP_10B,
+ RGA_FORMAT_YCbCr_422_SP_10B,
+ RGA_FORMAT_YCrCb_422_SP_10B,
+ RGA_FORMAT_ARGB_8888,
+ RGA_FORMAT_ABGR_8888,
+};
+
+const uint32_t rga3_output_raster_format[] = {
+ RGA_FORMAT_RGBA_8888,
+ RGA_FORMAT_BGRA_8888,
+ RGA_FORMAT_RGB_888,
+ RGA_FORMAT_BGR_888,
+ RGA_FORMAT_RGB_565,
+ RGA_FORMAT_BGR_565,
+ RGA_FORMAT_YCbCr_422_SP,
+ RGA_FORMAT_YCbCr_420_SP,
+ RGA_FORMAT_YCrCb_422_SP,
+ RGA_FORMAT_YCrCb_420_SP,
+ RGA_FORMAT_YVYU_422,
+ RGA_FORMAT_VYUY_422,
+ RGA_FORMAT_YUYV_422,
+ RGA_FORMAT_UYVY_422,
+ RGA_FORMAT_YCbCr_420_SP_10B,
+ RGA_FORMAT_YCrCb_420_SP_10B,
+ RGA_FORMAT_YCbCr_422_SP_10B,
+ RGA_FORMAT_YCrCb_422_SP_10B,
+};
+
+const uint32_t rga3_fbcd_format[] = {
+ RGA_FORMAT_RGBA_8888,
+ RGA_FORMAT_BGRA_8888,
+ RGA_FORMAT_RGB_888,
+ RGA_FORMAT_BGR_888,
+ RGA_FORMAT_RGB_565,
+ RGA_FORMAT_BGR_565,
+ RGA_FORMAT_YCbCr_422_SP,
+ RGA_FORMAT_YCbCr_420_SP,
+ RGA_FORMAT_YCrCb_422_SP,
+ RGA_FORMAT_YCrCb_420_SP,
+ RGA_FORMAT_YCbCr_420_SP_10B,
+ RGA_FORMAT_YCrCb_420_SP_10B,
+ RGA_FORMAT_YCbCr_422_SP_10B,
+ RGA_FORMAT_YCrCb_422_SP_10B,
+};
+
+const uint32_t rga3_tile_format[] = {
+ RGA_FORMAT_YCbCr_422_SP,
+ RGA_FORMAT_YCbCr_420_SP,
+ RGA_FORMAT_YCrCb_422_SP,
+ RGA_FORMAT_YCrCb_420_SP,
+ RGA_FORMAT_YCbCr_420_SP_10B,
+ RGA_FORMAT_YCrCb_420_SP_10B,
+ RGA_FORMAT_YCbCr_422_SP_10B,
+ RGA_FORMAT_YCrCb_422_SP_10B,
+};
+
+const uint32_t rga2e_input_raster_format[] = {
+ RGA_FORMAT_RGBA_8888,
+ RGA_FORMAT_RGBX_8888,
+ RGA_FORMAT_BGRA_8888,
+ RGA_FORMAT_BGRX_8888,
+ RGA_FORMAT_RGB_888,
+ RGA_FORMAT_BGR_888,
+ RGA_FORMAT_RGB_565,
+ RGA_FORMAT_BGR_565,
+ RGA_FORMAT_YCbCr_422_P,
+ RGA_FORMAT_YCbCr_420_P,
+ RGA_FORMAT_YCrCb_422_P,
+ RGA_FORMAT_YCrCb_420_P,
+ RGA_FORMAT_YCbCr_422_SP,
+ RGA_FORMAT_YCbCr_420_SP,
+ RGA_FORMAT_YCrCb_422_SP,
+ RGA_FORMAT_YCrCb_420_SP,
+ RGA_FORMAT_YVYU_422,
+ RGA_FORMAT_VYUY_422,
+ RGA_FORMAT_YUYV_422,
+ RGA_FORMAT_UYVY_422,
+ RGA_FORMAT_YCbCr_420_SP_10B,
+ RGA_FORMAT_YCrCb_420_SP_10B,
+ RGA_FORMAT_YCbCr_422_SP_10B,
+ RGA_FORMAT_YCrCb_422_SP_10B,
+ RGA_FORMAT_YCbCr_400,
+ RGA_FORMAT_RGBA_5551,
+ RGA_FORMAT_BGRA_5551,
+ RGA_FORMAT_RGBA_4444,
+ RGA_FORMAT_BGRA_4444,
+ RGA_FORMAT_XRGB_8888,
+ RGA_FORMAT_XBGR_8888,
+ RGA_FORMAT_BPP1,
+ RGA_FORMAT_BPP2,
+ RGA_FORMAT_BPP4,
+ RGA_FORMAT_BPP8,
+ RGA_FORMAT_ARGB_8888,
+ RGA_FORMAT_ARGB_5551,
+ RGA_FORMAT_ARGB_4444,
+ RGA_FORMAT_ABGR_8888,
+ RGA_FORMAT_ABGR_5551,
+ RGA_FORMAT_ABGR_4444,
+};
+
+const uint32_t rga2e_output_raster_format[] = {
+ RGA_FORMAT_RGBA_8888,
+ RGA_FORMAT_RGBX_8888,
+ RGA_FORMAT_BGRA_8888,
+ RGA_FORMAT_BGRX_8888,
+ RGA_FORMAT_RGB_888,
+ RGA_FORMAT_BGR_888,
+ RGA_FORMAT_RGB_565,
+ RGA_FORMAT_BGR_565,
+ RGA_FORMAT_YCbCr_422_P,
+ RGA_FORMAT_YCbCr_420_P,
+ RGA_FORMAT_YCrCb_422_P,
+ RGA_FORMAT_YCrCb_420_P,
+ RGA_FORMAT_YCbCr_422_SP,
+ RGA_FORMAT_YCbCr_420_SP,
+ RGA_FORMAT_YCrCb_422_SP,
+ RGA_FORMAT_YCrCb_420_SP,
+ RGA_FORMAT_YVYU_420,
+ RGA_FORMAT_VYUY_420,
+ RGA_FORMAT_YUYV_420,
+ RGA_FORMAT_UYVY_420,
+ RGA_FORMAT_YVYU_422,
+ RGA_FORMAT_VYUY_422,
+ RGA_FORMAT_YUYV_422,
+ RGA_FORMAT_UYVY_422,
+ RGA_FORMAT_YCbCr_420_SP_10B,
+ RGA_FORMAT_YCrCb_420_SP_10B,
+ RGA_FORMAT_YCbCr_422_SP_10B,
+ RGA_FORMAT_YCrCb_422_SP_10B,
+ RGA_FORMAT_Y4,
+ RGA_FORMAT_YCbCr_400,
+ RGA_FORMAT_RGBA_5551,
+ RGA_FORMAT_BGRA_5551,
+ RGA_FORMAT_RGBA_4444,
+ RGA_FORMAT_BGRA_4444,
+ RGA_FORMAT_XRGB_8888,
+ RGA_FORMAT_XBGR_8888,
+ RGA_FORMAT_ARGB_8888,
+ RGA_FORMAT_ARGB_5551,
+ RGA_FORMAT_ARGB_4444,
+ RGA_FORMAT_ABGR_8888,
+ RGA_FORMAT_ABGR_5551,
+ RGA_FORMAT_ABGR_4444,
+};
+
+const struct rga_win_data rga3_win_data[] = {
+ {
+ .name = "rga3-win0",
+ .formats[RGA_RASTER_INDEX] = rga3_input_raster_format,
+ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga3_input_raster_format),
+ .formats[RGA_AFBC16x16_INDEX] = rga3_fbcd_format,
+ .formats_count[RGA_AFBC16x16_INDEX] = ARRAY_SIZE(rga3_fbcd_format),
+ .formats[RGA_TILE8x8_INDEX] = rga3_tile_format,
+ .formats_count[RGA_TILE8x8_INDEX] = ARRAY_SIZE(rga3_tile_format),
+ .supported_rotations = RGA_MODE_ROTATE_MASK,
+ .scale_up_mode = RGA_SCALE_UP_BIC,
+ .scale_down_mode = RGA_SCALE_DOWN_AVG,
+ .rd_mode = RGA_RASTER_MODE | RGA_FBC_MODE | RGA_TILE_MODE,
+
+ },
+
+ {
+ .name = "rga3-win1",
+ .formats[RGA_RASTER_INDEX] = rga3_input_raster_format,
+ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga3_input_raster_format),
+ .formats[RGA_AFBC16x16_INDEX] = rga3_fbcd_format,
+ .formats_count[RGA_AFBC16x16_INDEX] = ARRAY_SIZE(rga3_fbcd_format),
+ .formats[RGA_TILE8x8_INDEX] = rga3_tile_format,
+ .formats_count[RGA_TILE8x8_INDEX] = ARRAY_SIZE(rga3_tile_format),
+ .supported_rotations = RGA_MODE_ROTATE_MASK,
+ .scale_up_mode = RGA_SCALE_UP_BIC,
+ .scale_down_mode = RGA_SCALE_DOWN_AVG,
+ .rd_mode = RGA_RASTER_MODE | RGA_FBC_MODE | RGA_TILE_MODE,
+
+ },
+
+ {
+ .name = "rga3-wr",
+ .formats[RGA_RASTER_INDEX] = rga3_output_raster_format,
+ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga3_output_raster_format),
+ .formats[RGA_AFBC16x16_INDEX] = rga3_fbcd_format,
+ .formats_count[RGA_AFBC16x16_INDEX] = ARRAY_SIZE(rga3_fbcd_format),
+ .formats[RGA_TILE8x8_INDEX] = rga3_tile_format,
+ .formats_count[RGA_TILE8x8_INDEX] = ARRAY_SIZE(rga3_tile_format),
+ .supported_rotations = 0,
+ .scale_up_mode = RGA_SCALE_UP_NONE,
+ .scale_down_mode = RGA_SCALE_DOWN_NONE,
+ .rd_mode = RGA_RASTER_MODE | RGA_FBC_MODE | RGA_TILE_MODE,
+
+ },
+};
+
+const struct rga_win_data rga2e_win_data[] = {
+ {
+ .name = "rga2e-src0",
+ .formats[RGA_RASTER_INDEX] = rga2e_input_raster_format,
+ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_input_raster_format),
+ .supported_rotations = RGA_MODE_ROTATE_MASK,
+ .scale_up_mode = RGA_SCALE_UP_BIC,
+ .scale_down_mode = RGA_SCALE_DOWN_AVG,
+ .rd_mode = RGA_RASTER_MODE,
+
+ },
+
+ {
+ .name = "rga2e-src1",
+ .formats[RGA_RASTER_INDEX] = rga2e_input_raster_format,
+ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_input_raster_format),
+ .supported_rotations = RGA_MODE_ROTATE_MASK,
+ .scale_up_mode = RGA_SCALE_UP_BIC,
+ .scale_down_mode = RGA_SCALE_DOWN_AVG,
+ .rd_mode = RGA_RASTER_MODE,
+
+ },
+
+ {
+ .name = "rga2-dst",
+ .formats[RGA_RASTER_INDEX] = rga2e_output_raster_format,
+ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_output_raster_format),
+ .supported_rotations = 0,
+ .scale_up_mode = RGA_SCALE_UP_NONE,
+ .scale_down_mode = RGA_SCALE_DOWN_NONE,
+ .rd_mode = RGA_RASTER_MODE,
+
+ },
+};
+
+const struct rga_hw_data rga3_data = {
+ .version = 0,
+ .input_range = {{68, 2}, {8176, 8176}},
+ .output_range = {{68, 2}, {8128, 8128}},
+
+ .win = rga3_win_data,
+ .win_size = ARRAY_SIZE(rga3_win_data),
+ /* 1 << factor mean real factor */
+ .max_upscale_factor = 3,
+ .max_downscale_factor = 3,
+
+ .byte_stride_align = 16,
+ .max_byte_stride = WORD_TO_BYTE(8192),
+
+ .feature = RGA_COLOR_KEY,
+ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F |
+ RGA_MODE_CSC_BT709 | RGA_MODE_CSC_BT2020,
+ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F |
+ RGA_MODE_CSC_BT709 | RGA_MODE_CSC_BT2020,
+ .mmu = RGA_IOMMU,
+};
+
+const struct rga_hw_data rga2e_data = {
+ .version = 0,
+ .input_range = {{2, 2}, {8192, 8192}},
+ .output_range = {{2, 2}, {4096, 4096}},
+
+ .win = rga2e_win_data,
+ .win_size = ARRAY_SIZE(rga2e_win_data),
+ /* 1 << factor mean real factor */
+ .max_upscale_factor = 4,
+ .max_downscale_factor = 4,
+
+ .byte_stride_align = 4,
+ .max_byte_stride = WORD_TO_BYTE(8192),
+
+ .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE |
+ RGA_COLOR_KEY | RGA_ROP_CALCULATE |
+ RGA_NN_QUANTIZE | RGA_DITHER | RGA_FULL_CSC,
+ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F,
+ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F |
+ RGA_MODE_CSC_BT709,
+ .mmu = RGA_MMU,
+};
+
+const struct rga_hw_data rga2e_1106_data = {
+ .version = 0,
+ .input_range = {{2, 2}, {8192, 8192}},
+ .output_range = {{2, 2}, {4096, 4096}},
+
+ .win = rga2e_win_data,
+ .win_size = ARRAY_SIZE(rga2e_win_data),
+ /* 1 << factor mean real factor */
+ .max_upscale_factor = 4,
+ .max_downscale_factor = 4,
+
+ .byte_stride_align = 4,
+ .max_byte_stride = WORD_TO_BYTE(8192),
+
+ .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE |
+ RGA_COLOR_KEY | RGA_ROP_CALCULATE |
+ RGA_NN_QUANTIZE | RGA_DITHER | RGA_MOSAIC |
+ RGA_YIN_YOUT | RGA_YUV_HDS | RGA_YUV_VDS |
+ RGA_OSD | RGA_PRE_INTR | RGA_FULL_CSC,
+ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F |
+ RGA_MODE_CSC_BT709,
+ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F |
+ RGA_MODE_CSC_BT709,
+ .mmu = RGA_NONE_MMU,
+};
+
+const struct rga_hw_data rga2e_iommu_data = {
+ .version = 0,
+ .input_range = {{2, 2}, {8192, 8192}},
+ .output_range = {{2, 2}, {4096, 4096}},
+
+ .win = rga2e_win_data,
+ .win_size = ARRAY_SIZE(rga2e_win_data),
+ /* 1 << factor mean real factor */
+ .max_upscale_factor = 4,
+ .max_downscale_factor = 4,
+
+ .byte_stride_align = 4,
+ .max_byte_stride = WORD_TO_BYTE(8192),
+
+ .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE |
+ RGA_COLOR_KEY | RGA_ROP_CALCULATE |
+ RGA_NN_QUANTIZE | RGA_DITHER | RGA_MOSAIC |
+ RGA_YIN_YOUT | RGA_YUV_HDS | RGA_YUV_VDS |
+ RGA_OSD | RGA_PRE_INTR | RGA_FULL_CSC,
+ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F |
+ RGA_MODE_CSC_BT709,
+ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F |
+ RGA_MODE_CSC_BT709,
+ .mmu = RGA_IOMMU,
+};
diff --git a/drivers/video/rockchip/rga3/rga_iommu.c b/drivers/video/rockchip/rga3/rga_iommu.c
new file mode 100644
index 000000000..6ef9cbc0d
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_iommu.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_iommu: " fmt
+
+#include "rga_iommu.h"
+#include "rga_dma_buf.h"
+#include "rga_mm.h"
+#include "rga_job.h"
+#include "rga_common.h"
+#include "rga_hw_config.h"
+
+int rga_user_memory_check(struct page **pages, u32 w, u32 h, u32 format, int flag)
+{
+ int bits;
+ void *vaddr = NULL;
+ int taipage_num;
+ int taidata_num;
+ int *tai_vaddr = NULL;
+
+ bits = rga_get_format_bits(format);
+ if (bits < 0)
+ return -1;
+
+ taipage_num = w * h * bits / 8 / (1024 * 4);
+ taidata_num = w * h * bits / 8 % (1024 * 4);
+ if (taidata_num == 0) {
+ vaddr = kmap(pages[taipage_num - 1]);
+ tai_vaddr = (int *)vaddr + 1023;
+ } else {
+ vaddr = kmap(pages[taipage_num]);
+ tai_vaddr = (int *)vaddr + taidata_num / 4 - 1;
+ }
+
+ if (flag == 1) {
+ pr_info("src user memory check\n");
+ pr_info("tai data is %d\n", *tai_vaddr);
+ } else {
+ pr_info("dst user memory check\n");
+ pr_info("tai data is %d\n", *tai_vaddr);
+ }
+
+ if (taidata_num == 0)
+ kunmap(pages[taipage_num - 1]);
+ else
+ kunmap(pages[taipage_num]);
+
+ return 0;
+}
+
+int rga_set_mmu_base(struct rga_job *job, struct rga2_req *req)
+{
+ if (job->src_buffer.page_table) {
+ rga_dma_sync_flush_range(job->src_buffer.page_table,
+ (job->src_buffer.page_table +
+ job->src_buffer.page_count),
+ job->scheduler);
+ req->mmu_info.src0_base_addr = virt_to_phys(job->src_buffer.page_table);
+ }
+
+ if (job->src1_buffer.page_table) {
+ rga_dma_sync_flush_range(job->src1_buffer.page_table,
+ (job->src1_buffer.page_table +
+ job->src1_buffer.page_count),
+ job->scheduler);
+ req->mmu_info.src1_base_addr = virt_to_phys(job->src1_buffer.page_table);
+ }
+
+ if (job->dst_buffer.page_table) {
+ rga_dma_sync_flush_range(job->dst_buffer.page_table,
+ (job->dst_buffer.page_table +
+ job->dst_buffer.page_count),
+ job->scheduler);
+ req->mmu_info.dst_base_addr = virt_to_phys(job->dst_buffer.page_table);
+
+ if (((req->alpha_rop_flag & 1) == 1) && (req->bitblt_mode == 0)) {
+ req->mmu_info.src1_base_addr = req->mmu_info.dst_base_addr;
+ req->mmu_info.src1_mmu_flag = req->mmu_info.dst_mmu_flag;
+ }
+ }
+
+ if (job->els_buffer.page_table) {
+ rga_dma_sync_flush_range(job->els_buffer.page_table,
+ (job->els_buffer.page_table +
+ job->els_buffer.page_count),
+ job->scheduler);
+ req->mmu_info.els_base_addr = virt_to_phys(job->els_buffer.page_table);
+ }
+
+ return 0;
+}
+
+static int rga_mmu_buf_get_try(struct rga_mmu_base *t, uint32_t size)
+{
+ int ret = 0;
+
+ if ((t->back - t->front) > t->size) {
+ if (t->front + size > t->back - t->size) {
+ pr_info("front %d, back %d dsize %d size %d",
+ t->front, t->back, t->size, size);
+ ret = -ENOMEM;
+ goto out;
+ }
+ } else {
+ if ((t->front + size) > t->back) {
+ pr_info("front %d, back %d dsize %d size %d",
+ t->front, t->back, t->size, size);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (t->front + size > t->size) {
+ if (size > (t->back - t->size)) {
+ pr_info("front %d, back %d dsize %d size %d",
+ t->front, t->back, t->size, size);
+ ret = -ENOMEM;
+ goto out;
+ }
+ t->front = 0;
+ }
+ }
+out:
+ return ret;
+}
+
+unsigned int *rga_mmu_buf_get(struct rga_mmu_base *mmu_base, uint32_t size)
+{
+ int ret;
+ unsigned int *buf = NULL;
+
+ WARN_ON(!mutex_is_locked(&rga_drvdata->lock));
+
+ size = ALIGN(size, 16);
+
+ ret = rga_mmu_buf_get_try(mmu_base, size);
+ if (ret < 0) {
+ pr_err("Get MMU mem failed\n");
+ return NULL;
+ }
+
+ buf = mmu_base->buf_virtual + mmu_base->front;
+
+ mmu_base->front += size;
+
+ if (mmu_base->back + size > 2 * mmu_base->size)
+ mmu_base->back = size + mmu_base->size;
+ else
+ mmu_base->back += size;
+
+ return buf;
+}
+
+struct rga_mmu_base *rga_mmu_base_init(size_t size)
+{
+ int order = 0;
+ struct rga_mmu_base *mmu_base;
+
+ mmu_base = kzalloc(sizeof(*mmu_base), GFP_KERNEL);
+ if (mmu_base == NULL) {
+ pr_err("Cannot alloc mmu_base!\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /*
+ * malloc pre scale mid buf mmu table:
+ * size * channel_num * address_size
+ */
+ order = get_order(size * 3 * sizeof(*mmu_base->buf_virtual));
+ if (order >= MAX_ORDER) {
+ pr_err("Can not alloc pages with order[%d] for mmu_page_table, max_order = %d\n",
+ order, MAX_ORDER);
+ goto err_free_mmu_base;
+ }
+
+ mmu_base->buf_virtual = (uint32_t *) __get_free_pages(GFP_KERNEL | GFP_DMA32, order);
+ if (mmu_base->buf_virtual == NULL) {
+ pr_err("Can not alloc pages for mmu_page_table\n");
+ goto err_free_mmu_base;
+ }
+ mmu_base->buf_order = order;
+
+ order = get_order(size * sizeof(*mmu_base->pages));
+ if (order >= MAX_ORDER) {
+ pr_err("Can not alloc pages with order[%d] for mmu_base->pages, max_order = %d\n",
+ order, MAX_ORDER);
+ goto err_free_buf_virtual;
+ }
+
+ mmu_base->pages = (struct page **)__get_free_pages(GFP_KERNEL | GFP_DMA32, order);
+ if (mmu_base->pages == NULL) {
+ pr_err("Can not alloc pages for mmu_base->pages\n");
+ goto err_free_buf_virtual;
+ }
+ mmu_base->pages_order = order;
+
+ mmu_base->front = 0;
+ mmu_base->back = RGA2_PHY_PAGE_SIZE * 3;
+ mmu_base->size = RGA2_PHY_PAGE_SIZE * 3;
+
+ return mmu_base;
+
+err_free_buf_virtual:
+ free_pages((unsigned long)mmu_base->buf_virtual, mmu_base->buf_order);
+ mmu_base->buf_order = 0;
+
+err_free_mmu_base:
+ kfree(mmu_base);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+void rga_mmu_base_free(struct rga_mmu_base **mmu_base)
+{
+ struct rga_mmu_base *base = *mmu_base;
+
+ if (base->buf_virtual != NULL) {
+ free_pages((unsigned long)base->buf_virtual, base->buf_order);
+ base->buf_virtual = NULL;
+ base->buf_order = 0;
+ }
+
+ if (base->pages != NULL) {
+ free_pages((unsigned long)base->pages, base->pages_order);
+ base->pages = NULL;
+ base->pages_order = 0;
+ }
+
+ kfree(base);
+ *mmu_base = NULL;
+}
+
+static int rga_iommu_intr_fault_handler(struct iommu_domain *iommu, struct device *iommu_dev,
+ unsigned long iova, int status, void *arg)
+{
+ struct rga_scheduler_t *scheduler = (struct rga_scheduler_t *)arg;
+ struct rga_job *job = scheduler->running_job;
+
+ if (job == NULL)
+ return 0;
+
+ pr_err("IOMMU intr fault, IOVA[0x%lx], STATUS[0x%x]\n", iova, status);
+ if (scheduler->ops->irq)
+ scheduler->ops->irq(scheduler);
+
+ /* iommu interrupts on rga2 do not affect rga2 itself. */
+ if (!test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) {
+ set_bit(RGA_JOB_STATE_INTR_ERR, &job->state);
+ scheduler->ops->soft_reset(scheduler);
+ }
+
+ if (status & RGA_IOMMU_IRQ_PAGE_FAULT) {
+ pr_err("RGA IOMMU: page fault! Please check the memory size.\n");
+ job->ret = -EACCES;
+ } else if (status & RGA_IOMMU_IRQ_BUS_ERROR) {
+ pr_err("RGA IOMMU: bus error! Please check if the memory is invalid or has been freed.\n");
+ job->ret = -EACCES;
+ } else {
+ pr_err("RGA IOMMU: Wrong IOMMU interrupt signal!\n");
+ }
+
+ return 0;
+}
+
+int rga_iommu_detach(struct rga_iommu_info *info)
+{
+ if (!info)
+ return 0;
+
+ iommu_detach_group(info->domain, info->group);
+ return 0;
+}
+
+int rga_iommu_attach(struct rga_iommu_info *info)
+{
+ if (!info)
+ return 0;
+
+ return iommu_attach_group(info->domain, info->group);
+}
+
+struct rga_iommu_info *rga_iommu_probe(struct device *dev)
+{
+ int ret = 0;
+ struct rga_iommu_info *info = NULL;
+ struct iommu_domain *domain = NULL;
+ struct iommu_group *group = NULL;
+
+ group = iommu_group_get(dev);
+ if (!group)
+ return ERR_PTR(-EINVAL);
+
+ domain = iommu_get_domain_for_dev(dev);
+ if (!domain) {
+ ret = -EINVAL;
+ goto err_put_group;
+ }
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ ret = -ENOMEM;
+ goto err_put_group;
+ }
+
+ info->dev = dev;
+ info->default_dev = info->dev;
+ info->group = group;
+ info->domain = domain;
+
+ return info;
+
+err_put_group:
+ if (group)
+ iommu_group_put(group);
+
+ return ERR_PTR(ret);
+}
+
+int rga_iommu_remove(struct rga_iommu_info *info)
+{
+ if (!info)
+ return 0;
+
+ iommu_group_put(info->group);
+
+ return 0;
+}
+
+int rga_iommu_bind(void)
+{
+ int i;
+ int ret;
+ struct rga_scheduler_t *scheduler = NULL;
+ struct rga_iommu_info *main_iommu = NULL;
+ int main_iommu_index = -1;
+ int main_mmu_index = -1;
+ int another_index = -1;
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+
+ switch (scheduler->data->mmu) {
+ case RGA_IOMMU:
+ if (scheduler->iommu_info == NULL)
+ continue;
+
+ if (main_iommu == NULL) {
+ main_iommu = scheduler->iommu_info;
+ main_iommu_index = i;
+ iommu_set_fault_handler(main_iommu->domain,
+ rga_iommu_intr_fault_handler,
+ (void *)scheduler);
+ } else {
+ scheduler->iommu_info->domain = main_iommu->domain;
+ scheduler->iommu_info->default_dev = main_iommu->default_dev;
+ rga_iommu_attach(scheduler->iommu_info);
+ }
+
+ break;
+
+ case RGA_MMU:
+ if (rga_drvdata->mmu_base != NULL)
+ continue;
+
+ rga_drvdata->mmu_base = rga_mmu_base_init(RGA2_PHY_PAGE_SIZE);
+ if (IS_ERR(rga_drvdata->mmu_base)) {
+ dev_err(scheduler->dev, "rga mmu base init failed!\n");
+ ret = PTR_ERR(rga_drvdata->mmu_base);
+ rga_drvdata->mmu_base = NULL;
+
+ return ret;
+ }
+
+ main_mmu_index = i;
+
+ break;
+ default:
+ if (another_index != RGA_NONE_CORE)
+ another_index = i;
+
+ break;
+ }
+ }
+
+ /*
+ * priority order: iommu > mmu > another
+ * The scheduler core with IOMMU will be used preferentially as the
+ * default memory-mapped core. This ensures that all cores can obtain
+ * the required memory data when they are equipped with different
+ * versions of cores.
+ */
+ if (main_iommu_index >= 0) {
+ rga_drvdata->map_scheduler_index = main_iommu_index;
+ } else if (main_mmu_index >= 0) {
+ rga_drvdata->map_scheduler_index = main_mmu_index;
+ } else if (another_index >= 0) {
+ rga_drvdata->map_scheduler_index = another_index;
+ } else {
+ rga_drvdata->map_scheduler_index = -1;
+ pr_err("%s, binding map scheduler failed!\n", __func__);
+ return -EFAULT;
+ }
+
+ pr_info("IOMMU binding successfully, default mapping core[0x%x]\n",
+ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index]->core);
+
+ return 0;
+}
+
+void rga_iommu_unbind(void)
+{
+ int i;
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++)
+ if (rga_drvdata->scheduler[i]->iommu_info != NULL)
+ rga_iommu_detach(rga_drvdata->scheduler[i]->iommu_info);
+
+ if (rga_drvdata->mmu_base)
+ rga_mmu_base_free(&rga_drvdata->mmu_base);
+
+ rga_drvdata->map_scheduler_index = -1;
+}
diff --git a/drivers/video/rockchip/rga3/rga_job.c b/drivers/video/rockchip/rga3/rga_job.c
new file mode 100644
index 000000000..fae613bbf
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_job.c
@@ -0,0 +1,1423 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_job: " fmt
+
+#include "rga_job.h"
+#include "rga_fence.h"
+#include "rga_dma_buf.h"
+#include "rga_mm.h"
+#include "rga_iommu.h"
+#include "rga_debugger.h"
+#include "rga_common.h"
+
+static void rga_job_free(struct rga_job *job)
+{
+ free_page((unsigned long)job);
+}
+
+static void rga_job_kref_release(struct kref *ref)
+{
+ struct rga_job *job;
+
+ job = container_of(ref, struct rga_job, refcount);
+
+ rga_job_free(job);
+}
+
+static int rga_job_put(struct rga_job *job)
+{
+ return kref_put(&job->refcount, rga_job_kref_release);
+}
+
+static void rga_job_get(struct rga_job *job)
+{
+ kref_get(&job->refcount);
+}
+
+static int rga_job_cleanup(struct rga_job *job)
+{
+ rga_job_put(job);
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], job cleanup total cost time %lld us\n",
+ job->request_id,
+ ktime_us_delta(ktime_get(), job->timestamp));
+
+ return 0;
+}
+
+static int rga_job_judgment_support_core(struct rga_job *job)
+{
+ int ret = 0;
+ uint32_t mm_flag;
+ struct rga_req *req;
+ struct rga_mm *mm;
+
+ req = &job->rga_command_base;
+ mm = rga_drvdata->mm;
+ if (mm == NULL) {
+ pr_err("rga mm is null!\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&mm->lock);
+
+ if (likely(req->src.yrgb_addr > 0)) {
+ ret = rga_mm_lookup_flag(mm, req->src.yrgb_addr);
+ if (ret < 0)
+ goto out_finish;
+ else
+ mm_flag = (uint32_t)ret;
+
+ if (~mm_flag & RGA_MEM_UNDER_4G) {
+ job->flags |= RGA_JOB_UNSUPPORT_RGA_MMU;
+ goto out_finish;
+ }
+ }
+
+ if (likely(req->dst.yrgb_addr > 0)) {
+ ret = rga_mm_lookup_flag(mm, req->dst.yrgb_addr);
+ if (ret < 0)
+ goto out_finish;
+ else
+ mm_flag = (uint32_t)ret;
+
+ if (~mm_flag & RGA_MEM_UNDER_4G) {
+ job->flags |= RGA_JOB_UNSUPPORT_RGA_MMU;
+ goto out_finish;
+ }
+ }
+
+ if (req->pat.yrgb_addr > 0) {
+ ret = rga_mm_lookup_flag(mm, req->pat.yrgb_addr);
+ if (ret < 0)
+ goto out_finish;
+ else
+ mm_flag = (uint32_t)ret;
+
+ if (~mm_flag & RGA_MEM_UNDER_4G) {
+ job->flags |= RGA_JOB_UNSUPPORT_RGA_MMU;
+ goto out_finish;
+ }
+ }
+
+out_finish:
+ mutex_unlock(&mm->lock);
+
+ return ret;
+}
+
+static struct rga_job *rga_job_alloc(struct rga_req *rga_command_base)
+{
+ struct rga_job *job = NULL;
+
+ job = (struct rga_job *)get_zeroed_page(GFP_KERNEL | GFP_DMA32);
+ if (!job)
+ return NULL;
+
+ INIT_LIST_HEAD(&job->head);
+ kref_init(&job->refcount);
+
+ job->timestamp = ktime_get();
+ job->pid = current->pid;
+
+ job->rga_command_base = *rga_command_base;
+
+ if (rga_command_base->priority > 0) {
+ if (rga_command_base->priority > RGA_SCHED_PRIORITY_MAX)
+ job->priority = RGA_SCHED_PRIORITY_MAX;
+ else
+ job->priority = rga_command_base->priority;
+ }
+
+ if (job->rga_command_base.handle_flag & 1) {
+ job->flags |= RGA_JOB_USE_HANDLE;
+
+ rga_job_judgment_support_core(job);
+ }
+
+ return job;
+}
+
+static void rga_job_dump_info(struct rga_job *job)
+{
+ pr_info("job: reqeust_id = %d, priority = %d, core = %d\n",
+ job->request_id, job->priority, job->core);
+}
+
+void rga_job_scheduler_dump_info(struct rga_scheduler_t *scheduler)
+{
+ struct rga_job *job_pos;
+
+ lockdep_assert_held(&scheduler->irq_lock);
+
+ pr_info("===============================================================\n");
+ pr_info("%s core = %d job_count = %d status = %d\n",
+ dev_driver_string(scheduler->dev),
+ scheduler->core, scheduler->job_count, scheduler->status);
+
+ if (scheduler->running_job)
+ rga_job_dump_info(scheduler->running_job);
+
+ list_for_each_entry(job_pos, &scheduler->todo_list, head) {
+ rga_job_dump_info(job_pos);
+ }
+
+ pr_info("===============================================================\n");
+}
+
+static int rga_job_run(struct rga_job *job, struct rga_scheduler_t *scheduler)
+{
+ int ret = 0;
+
+ /* enable power */
+ ret = rga_power_enable(scheduler);
+ if (ret < 0) {
+ pr_err("power enable failed");
+ return ret;
+ }
+
+ ret = scheduler->ops->set_reg(job, scheduler);
+ if (ret < 0) {
+ pr_err("set reg failed");
+ rga_power_disable(scheduler);
+ return ret;
+ }
+
+ set_bit(RGA_JOB_STATE_RUNNING, &job->state);
+
+ /* for debug */
+ if (DEBUGGER_EN(MSG))
+ rga_job_dump_info(job);
+
+ return ret;
+}
+
+void rga_job_next(struct rga_scheduler_t *scheduler)
+{
+ int ret;
+ struct rga_job *job = NULL;
+ unsigned long flags;
+
+next_job:
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ if (scheduler->running_job ||
+ list_empty(&scheduler->todo_list)) {
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ return;
+ }
+
+ job = list_first_entry(&scheduler->todo_list, struct rga_job, head);
+
+ list_del_init(&job->head);
+
+ scheduler->job_count--;
+
+ scheduler->running_job = job;
+ set_bit(RGA_JOB_STATE_PREPARE, &job->state);
+ rga_job_get(job);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ ret = rga_job_run(job, scheduler);
+ /* If some error before hw run */
+ if (ret < 0) {
+ pr_err("some error on rga_job_run before hw start, %s(%d)\n", __func__, __LINE__);
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ scheduler->running_job = NULL;
+ rga_job_put(job);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ job->ret = ret;
+ rga_request_release_signal(scheduler, job);
+
+ goto next_job;
+ }
+
+ rga_job_put(job);
+}
+
+struct rga_job *rga_job_done(struct rga_scheduler_t *scheduler)
+{
+ struct rga_job *job;
+ unsigned long flags;
+ ktime_t now = ktime_get();
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ job = scheduler->running_job;
+ if (job == NULL) {
+ pr_err("core[0x%x] running job has been cleanup.\n", scheduler->core);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ return NULL;
+ }
+ scheduler->running_job = NULL;
+
+ scheduler->timer.busy_time += ktime_us_delta(now, job->hw_recoder_time);
+ set_bit(RGA_JOB_STATE_DONE, &job->state);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ if (scheduler->ops->read_back_reg)
+ scheduler->ops->read_back_reg(job, scheduler);
+
+ if (DEBUGGER_EN(DUMP_IMAGE))
+ rga_dump_job_image(job);
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], hardware[%s] cost time %lld us\n",
+ job->request_id,
+ rga_get_core_name(scheduler->core),
+ ktime_us_delta(now, job->hw_running_time));
+
+ rga_mm_unmap_job_info(job);
+
+ return job;
+}
+
+static void rga_job_scheduler_timeout_clean(struct rga_scheduler_t *scheduler)
+{
+ unsigned long flags;
+ struct rga_job *job = NULL;
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ if (scheduler->running_job == NULL || scheduler->running_job->hw_running_time == 0) {
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ return;
+ }
+
+ job = scheduler->running_job;
+ if (ktime_ms_delta(ktime_get(), job->hw_running_time) >= RGA_JOB_TIMEOUT_DELAY) {
+ scheduler->running_job = NULL;
+ scheduler->status = RGA_SCHEDULER_ABORT;
+ scheduler->ops->soft_reset(scheduler);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ rga_mm_unmap_job_info(job);
+
+ job->ret = -EBUSY;
+ rga_request_release_signal(scheduler, job);
+
+ rga_power_disable(scheduler);
+ } else {
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ }
+}
+
+static void rga_job_insert_todo_list(struct rga_job *job)
+{
+ bool first_match = 0;
+ unsigned long flags;
+ struct rga_job *job_pos;
+ struct rga_scheduler_t *scheduler = job->scheduler;
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ /* priority policy set by userspace */
+ if (list_empty(&scheduler->todo_list)
+ || (job->priority == RGA_SCHED_PRIORITY_DEFAULT)) {
+ list_add_tail(&job->head, &scheduler->todo_list);
+ } else {
+ list_for_each_entry(job_pos, &scheduler->todo_list, head) {
+ if (job->priority > job_pos->priority &&
+ (!first_match)) {
+ list_add(&job->head, &job_pos->head);
+ first_match = true;
+ }
+
+ /*
+ * Increase the priority of subsequent tasks
+ * after inserting into the list
+ */
+ if (first_match)
+ job_pos->priority++;
+ }
+
+ if (!first_match)
+ list_add_tail(&job->head, &scheduler->todo_list);
+ }
+
+ scheduler->job_count++;
+ set_bit(RGA_JOB_STATE_PENDING, &job->state);
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+}
+
+static struct rga_scheduler_t *rga_job_schedule(struct rga_job *job)
+{
+ int i;
+ struct rga_scheduler_t *scheduler = NULL;
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+ rga_job_scheduler_timeout_clean(scheduler);
+ }
+
+ if (rga_drvdata->num_of_scheduler > 1) {
+ job->core = rga_job_assign(job);
+ if (job->core <= 0) {
+ pr_err("job assign failed");
+ job->ret = -EINVAL;
+ return NULL;
+ }
+ } else {
+ job->core = rga_drvdata->scheduler[0]->core;
+ job->scheduler = rga_drvdata->scheduler[0];
+ }
+
+ scheduler = job->scheduler;
+ if (scheduler == NULL) {
+ pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__);
+ job->ret = -EFAULT;
+ return NULL;
+ }
+
+ return scheduler;
+}
+
+struct rga_job *rga_job_commit(struct rga_req *rga_command_base, struct rga_request *request)
+{
+ int ret;
+ struct rga_job *job = NULL;
+ struct rga_scheduler_t *scheduler = NULL;
+
+ job = rga_job_alloc(rga_command_base);
+ if (!job) {
+ pr_err("failed to alloc rga job!\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ job->use_batch_mode = request->use_batch_mode;
+ job->request_id = request->id;
+ job->session = request->session;
+ job->mm = request->current_mm;
+
+ scheduler = rga_job_schedule(job);
+ if (scheduler == NULL) {
+ pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__);
+ goto err_free_job;
+ }
+
+ /* Memory mapping needs to keep pd enabled. */
+ if (rga_power_enable(scheduler) < 0) {
+ pr_err("power enable failed");
+ job->ret = -EFAULT;
+ goto err_free_job;
+ }
+
+ ret = rga_mm_map_job_info(job);
+ if (ret < 0) {
+ pr_err("%s: failed to map job info\n", __func__);
+ job->ret = ret;
+ goto err_power_disable;
+ }
+
+ ret = scheduler->ops->init_reg(job);
+ if (ret < 0) {
+ pr_err("%s: init reg failed", __func__);
+ job->ret = ret;
+ goto err_unmap_job_info;
+ }
+
+ rga_job_insert_todo_list(job);
+
+ rga_job_next(scheduler);
+
+ rga_power_disable(scheduler);
+
+ return job;
+
+err_unmap_job_info:
+ rga_mm_unmap_job_info(job);
+
+err_power_disable:
+ rga_power_disable(scheduler);
+
+err_free_job:
+ ret = job->ret;
+ rga_request_release_signal(scheduler, job);
+
+ return ERR_PTR(ret);
+}
+
+static bool rga_is_need_current_mm(struct rga_req *req)
+{
+ int mmu_flag;
+ struct rga_img_info_t *src0 = NULL;
+ struct rga_img_info_t *src1 = NULL;
+ struct rga_img_info_t *dst = NULL;
+ struct rga_img_info_t *els = NULL;
+
+ src0 = &req->src;
+ dst = &req->dst;
+ if (req->render_mode != UPDATE_PALETTE_TABLE_MODE)
+ src1 = &req->pat;
+ else
+ els = &req->pat;
+
+ if (likely(src0 != NULL)) {
+ mmu_flag = ((req->mmu_info.mmu_flag >> 8) & 1);
+ if (mmu_flag && src0->uv_addr)
+ return true;
+ }
+
+ if (likely(dst != NULL)) {
+ mmu_flag = ((req->mmu_info.mmu_flag >> 10) & 1);
+ if (mmu_flag && dst->uv_addr)
+ return true;
+ }
+
+ if (src1 != NULL) {
+ mmu_flag = ((req->mmu_info.mmu_flag >> 9) & 1);
+ if (mmu_flag && src1->uv_addr)
+ return true;
+ }
+
+ if (els != NULL) {
+ mmu_flag = ((req->mmu_info.mmu_flag >> 11) & 1);
+ if (mmu_flag && els->uv_addr)
+ return true;
+ }
+
+ return false;
+}
+
+static struct mm_struct *rga_request_get_current_mm(struct rga_request *request)
+{
+ int i;
+
+ for (i = 0; i < request->task_count; i++) {
+ if (rga_is_need_current_mm(&(request->task_list[i]))) {
+ mmgrab(current->mm);
+ mmget(current->mm);
+
+ return current->mm;
+ }
+ }
+
+ return NULL;
+}
+
+static void rga_request_put_current_mm(struct mm_struct *mm)
+{
+ if (mm == NULL)
+ return;
+
+ mmput(mm);
+ mmdrop(mm);
+}
+
+static int rga_request_add_acquire_fence_callback(int acquire_fence_fd,
+ struct rga_request *request,
+ dma_fence_func_t cb_func)
+{
+ int ret;
+ struct dma_fence *acquire_fence = NULL;
+ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager;
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("acquire_fence_fd = %d", acquire_fence_fd);
+
+ acquire_fence = rga_get_dma_fence_from_fd(acquire_fence_fd);
+ if (IS_ERR_OR_NULL(acquire_fence)) {
+ pr_err("%s: failed to get acquire dma_fence from[%d]\n",
+ __func__, acquire_fence_fd);
+ return -EINVAL;
+ }
+
+ if (!request->feature.user_close_fence) {
+ /* close acquire fence fd */
+#ifdef CONFIG_NO_GKI
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+ close_fd(acquire_fence_fd);
+#else
+ ksys_close(acquire_fence_fd);
+#endif
+#else
+ pr_err("Please update the driver to v1.2.28 to prevent acquire_fence_fd leaks.");
+ return -EFAULT;
+#endif
+ }
+
+
+ ret = rga_dma_fence_get_status(acquire_fence);
+ if (ret < 0) {
+ pr_err("%s: Current acquire fence unexpectedly has error status before signal\n",
+ __func__);
+ return ret;
+ } else if (ret > 0) {
+ /* has been signaled */
+ return ret;
+ }
+
+ /*
+ * Ensure that the request will not be free early when
+ * the callback is called.
+ */
+ mutex_lock(&request_manager->lock);
+ rga_request_get(request);
+ mutex_unlock(&request_manager->lock);
+
+ ret = rga_dma_fence_add_callback(acquire_fence, cb_func, (void *)request);
+ if (ret < 0) {
+ if (ret != -ENOENT)
+ pr_err("%s: failed to add fence callback\n", __func__);
+
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+ return ret;
+ }
+
+ return 0;
+}
+
+int rga_request_check(struct rga_user_request *req)
+{
+ if (req->id <= 0) {
+ pr_err("user request id[%d] is invalid", req->id);
+ return -EINVAL;
+ }
+
+ if (req->task_num <= 0) {
+ pr_err("invalied user request!\n");
+ return -EINVAL;
+ }
+
+ if (req->task_ptr == 0) {
+ pr_err("task_ptr is NULL!\n");
+ return -EINVAL;
+ }
+
+ if (req->task_num > RGA_TASK_NUM_MAX) {
+ pr_err("Only supports running %d tasks, now %d\n",
+ RGA_TASK_NUM_MAX, req->task_num);
+ return -EFBIG;
+ }
+
+ return 0;
+}
+
+struct rga_request *rga_request_lookup(struct rga_pending_request_manager *manager, uint32_t id)
+{
+ struct rga_request *request = NULL;
+
+ WARN_ON(!mutex_is_locked(&manager->lock));
+
+ request = idr_find(&manager->request_idr, id);
+
+ return request;
+}
+
+static int rga_request_scheduler_job_abort(struct rga_request *request)
+{
+ int i;
+ unsigned long flags;
+ enum rga_scheduler_status scheduler_status;
+ int running_abort_count = 0, todo_abort_count = 0;
+ struct rga_scheduler_t *scheduler = NULL;
+ struct rga_job *job, *job_q;
+ LIST_HEAD(list_to_free);
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ list_for_each_entry_safe(job, job_q, &scheduler->todo_list, head) {
+ if (request->id == job->request_id) {
+ list_move(&job->head, &list_to_free);
+ scheduler->job_count--;
+
+ todo_abort_count++;
+ }
+ }
+
+ job = NULL;
+ if (scheduler->running_job) {
+ if (request->id == scheduler->running_job->request_id) {
+ job = scheduler->running_job;
+ scheduler_status = scheduler->status;
+ scheduler->running_job = NULL;
+ scheduler->status = RGA_SCHEDULER_ABORT;
+ list_add_tail(&job->head, &list_to_free);
+
+ if (job->hw_running_time != 0) {
+ scheduler->timer.busy_time +=
+ ktime_us_delta(ktime_get(), job->hw_recoder_time);
+ scheduler->ops->soft_reset(scheduler);
+ }
+
+ pr_err("reset core[%d] by request[%d] abort",
+ scheduler->core, request->id);
+ running_abort_count++;
+ }
+ }
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+
+ if (job && scheduler_status == RGA_SCHEDULER_WORKING)
+ rga_power_disable(scheduler);
+ }
+
+ /* Clean up the jobs in the todo list that need to be free. */
+ list_for_each_entry_safe(job, job_q, &list_to_free, head) {
+ rga_mm_unmap_job_info(job);
+
+ job->ret = -EBUSY;
+ rga_job_cleanup(job);
+ }
+
+ /* This means it has been cleaned up. */
+ if (running_abort_count + todo_abort_count == 0)
+ return 1;
+
+ pr_err("request[%d] abort! finished %d failed %d running_abort %d todo_abort %d\n",
+ request->id, request->finished_task_count, request->failed_task_count,
+ running_abort_count, todo_abort_count);
+
+ return 0;
+}
+
+static void rga_request_release_abort(struct rga_request *request, int err_code)
+{
+ unsigned long flags;
+ struct mm_struct *current_mm;
+ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager;
+
+ if (rga_request_scheduler_job_abort(request) > 0)
+ return;
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ if (request->is_done) {
+ spin_unlock_irqrestore(&request->lock, flags);
+ return;
+ }
+
+ request->is_running = false;
+ request->is_done = false;
+ current_mm = request->current_mm;
+ request->current_mm = NULL;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ rga_request_put_current_mm(current_mm);
+
+ rga_dma_fence_signal(request->release_fence, err_code);
+
+ mutex_lock(&request_manager->lock);
+ /* current submit request put */
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+}
+
+void rga_request_session_destroy_abort(struct rga_session *session)
+{
+ int request_id;
+ struct rga_request *request;
+ struct rga_pending_request_manager *request_manager;
+
+ request_manager = rga_drvdata->pend_request_manager;
+ if (request_manager == NULL) {
+ pr_err("rga_pending_request_manager is null!\n");
+ return;
+ }
+
+ mutex_lock(&request_manager->lock);
+
+ idr_for_each_entry(&request_manager->request_idr, request, request_id) {
+ if (session == request->session) {
+ pr_err("[tgid:%d pid:%d] destroy request[%d] when the user exits",
+ session->tgid, current->pid, request->id);
+ rga_request_put(request);
+ }
+ }
+
+ mutex_unlock(&request_manager->lock);
+}
+
+static int rga_request_timeout_query_state(struct rga_request *request)
+{
+ int i;
+ unsigned long flags;
+ struct rga_scheduler_t *scheduler = NULL;
+ struct rga_job *job = NULL;
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ if (scheduler->running_job) {
+ job = scheduler->running_job;
+ if (request->id == job->request_id) {
+ if (test_bit(RGA_JOB_STATE_DONE, &job->state) &&
+ test_bit(RGA_JOB_STATE_FINISH, &job->state)) {
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ return request->ret;
+ } else if (!test_bit(RGA_JOB_STATE_DONE, &job->state) &&
+ test_bit(RGA_JOB_STATE_FINISH, &job->state)) {
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ pr_err("request[%d] hardware has finished, but the software has timeout!\n",
+ request->id);
+ return -EBUSY;
+ } else if (!test_bit(RGA_JOB_STATE_DONE, &job->state) &&
+ !test_bit(RGA_JOB_STATE_FINISH, &job->state)) {
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ pr_err("request[%d] hardware has timeout.\n", request->id);
+ return -EBUSY;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ }
+
+ return request->ret;
+}
+
+static int rga_request_wait(struct rga_request *request)
+{
+ int left_time;
+ int ret;
+
+ left_time = wait_event_timeout(request->finished_wq, request->is_done,
+ RGA_JOB_TIMEOUT_DELAY * request->task_count);
+
+ switch (left_time) {
+ case 0:
+ ret = rga_request_timeout_query_state(request);
+ goto err_request_abort;
+ case -ERESTARTSYS:
+ ret = -ERESTARTSYS;
+ goto err_request_abort;
+ default:
+ ret = request->ret;
+ break;
+ }
+
+ return ret;
+
+err_request_abort:
+ rga_request_release_abort(request, ret);
+
+ return ret;
+}
+
+int rga_request_commit(struct rga_request *request)
+{
+ int ret;
+ int i = 0;
+ struct rga_job *job;
+
+ for (i = 0; i < request->task_count; i++) {
+ struct rga_req *req = &(request->task_list[i]);
+
+ if (DEBUGGER_EN(MSG)) {
+ pr_info("commit request[%d] task[%d]:\n", request->id, i);
+ rga_cmd_print_debug_info(req);
+ }
+
+ job = rga_job_commit(req, request);
+ if (IS_ERR(job)) {
+ pr_err("request[%d] task[%d] job_commit failed.\n", request->id, i);
+ rga_request_release_abort(request, PTR_ERR(job));
+
+ return PTR_ERR(job);
+ }
+ }
+
+ if (request->sync_mode == RGA_BLIT_SYNC) {
+ ret = rga_request_wait(request);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rga_request_acquire_fence_signaled_cb(struct dma_fence *fence,
+ struct dma_fence_cb *_waiter)
+{
+ int ret;
+ unsigned long flags;
+ struct mm_struct *current_mm;
+ struct rga_fence_waiter *waiter = (struct rga_fence_waiter *)_waiter;
+ struct rga_request *request = (struct rga_request *)waiter->private;
+ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager;
+
+ ret = rga_request_commit(request);
+ if (ret < 0) {
+ pr_err("acquire_fence callback: rga request[%d] commit failed!\n", request->id);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ request->is_running = false;
+ current_mm = request->current_mm;
+ request->current_mm = NULL;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ rga_request_put_current_mm(current_mm);
+
+ /*
+ * Since the callback is called while holding &dma_fence.lock,
+ * the _locked API is used here.
+ */
+ if (dma_fence_get_status_locked(request->release_fence) == 0)
+ dma_fence_signal_locked(request->release_fence);
+ }
+
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+
+ kfree(waiter);
+}
+
+int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job *job)
+{
+ struct rga_pending_request_manager *request_manager;
+ struct rga_request *request;
+ struct mm_struct *current_mm;
+ int finished_count, failed_count;
+ bool is_finished = false;
+ unsigned long flags;
+
+ request_manager = rga_drvdata->pend_request_manager;
+ if (request_manager == NULL) {
+ pr_err("rga_pending_request_manager is null!\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&request_manager->lock);
+
+ request = rga_request_lookup(request_manager, job->request_id);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("can not find internal request from id[%d]", job->request_id);
+ mutex_unlock(&request_manager->lock);
+ return -EINVAL;
+ }
+
+ rga_request_get(request);
+ mutex_unlock(&request_manager->lock);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ if (job->ret < 0) {
+ request->failed_task_count++;
+ request->ret = job->ret;
+ } else {
+ request->finished_task_count++;
+ }
+
+ failed_count = request->failed_task_count;
+ finished_count = request->finished_task_count;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ if ((failed_count + finished_count) >= request->task_count) {
+ spin_lock_irqsave(&request->lock, flags);
+
+ request->is_running = false;
+ request->is_done = true;
+ current_mm = request->current_mm;
+ request->current_mm = NULL;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ rga_request_put_current_mm(current_mm);
+
+ rga_dma_fence_signal(request->release_fence, request->ret);
+
+ is_finished = true;
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("request[%d] finished %d failed %d\n",
+ request->id, finished_count, failed_count);
+
+ /* current submit request put */
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+ }
+
+ mutex_lock(&request_manager->lock);
+
+ if (is_finished)
+ wake_up(&request->finished_wq);
+
+ rga_request_put(request);
+
+ mutex_unlock(&request_manager->lock);
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], job done total cost time %lld us\n",
+ job->request_id,
+ ktime_us_delta(ktime_get(), job->timestamp));
+
+ rga_job_cleanup(job);
+
+ return 0;
+}
+
+struct rga_request *rga_request_config(struct rga_user_request *user_request)
+{
+ int ret;
+ unsigned long flags;
+ struct rga_pending_request_manager *request_manager;
+ struct rga_request *request;
+ struct rga_req *task_list;
+
+ request_manager = rga_drvdata->pend_request_manager;
+ if (request_manager == NULL) {
+ pr_err("rga_pending_request_manager is null!\n");
+ return ERR_PTR(-EFAULT);
+ }
+
+ mutex_lock(&request_manager->lock);
+
+ request = rga_request_lookup(request_manager, user_request->id);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("can not find request from id[%d]", user_request->id);
+ mutex_unlock(&request_manager->lock);
+ return ERR_PTR(-EINVAL);
+ }
+
+ rga_request_get(request);
+ mutex_unlock(&request_manager->lock);
+
+ task_list = kmalloc_array(user_request->task_num, sizeof(struct rga_req), GFP_KERNEL);
+ if (task_list == NULL) {
+ pr_err("task_req list alloc error!\n");
+ ret = -ENOMEM;
+ goto err_put_request;
+ }
+
+ if (unlikely(copy_from_user(task_list, u64_to_user_ptr(user_request->task_ptr),
+ sizeof(struct rga_req) * user_request->task_num))) {
+ pr_err("rga_user_request task list copy_from_user failed\n");
+ ret = -EFAULT;
+ goto err_free_task_list;
+ }
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ request->use_batch_mode = true;
+ request->task_list = task_list;
+ request->task_count = user_request->task_num;
+ request->sync_mode = user_request->sync_mode;
+ request->mpi_config_flags = user_request->mpi_config_flags;
+ request->acquire_fence_fd = user_request->acquire_fence_fd;
+ request->feature = task_list[0].feature;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ return request;
+
+err_free_task_list:
+ kfree(task_list);
+err_put_request:
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+
+ return ERR_PTR(ret);
+}
+
+struct rga_request *rga_request_kernel_config(struct rga_user_request *user_request)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct rga_pending_request_manager *request_manager;
+ struct rga_request *request;
+ struct rga_req *task_list;
+
+ request_manager = rga_drvdata->pend_request_manager;
+ if (request_manager == NULL) {
+ pr_err("rga_pending_request_manager is null!\n");
+ return ERR_PTR(-EFAULT);
+ }
+
+ mutex_lock(&request_manager->lock);
+
+ request = rga_request_lookup(request_manager, user_request->id);
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("can not find request from id[%d]", user_request->id);
+ mutex_unlock(&request_manager->lock);
+ return ERR_PTR(-EINVAL);
+ }
+
+ rga_request_get(request);
+ mutex_unlock(&request_manager->lock);
+
+ task_list = kmalloc_array(user_request->task_num, sizeof(struct rga_req), GFP_KERNEL);
+ if (task_list == NULL) {
+ pr_err("task_req list alloc error!\n");
+ ret = -ENOMEM;
+ goto err_put_request;
+ }
+
+ memcpy(task_list, u64_to_user_ptr(user_request->task_ptr),
+ sizeof(struct rga_req) * user_request->task_num);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ request->use_batch_mode = true;
+ request->task_list = task_list;
+ request->task_count = user_request->task_num;
+ request->sync_mode = user_request->sync_mode;
+ request->mpi_config_flags = user_request->mpi_config_flags;
+ request->acquire_fence_fd = user_request->acquire_fence_fd;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ return request;
+
+err_put_request:
+ mutex_lock(&request_manager->lock);
+ rga_request_put(request);
+ mutex_unlock(&request_manager->lock);
+
+ return ERR_PTR(ret);
+}
+
+int rga_request_submit(struct rga_request *request)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct dma_fence *release_fence;
+ struct mm_struct *current_mm;
+
+ current_mm = rga_request_get_current_mm(request);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ if (request->is_running) {
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ pr_err("can not re-config when request is running\n");
+ ret = -EFAULT;
+ goto err_put_current_mm;
+ }
+
+ if (request->task_list == NULL) {
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ pr_err("can not find task list from id[%d]\n", request->id);
+ ret = -EINVAL;
+ goto err_put_current_mm;
+ }
+
+ /* Reset */
+ request->is_running = true;
+ request->is_done = false;
+ request->finished_task_count = 0;
+ request->failed_task_count = 0;
+ request->current_mm = current_mm;
+
+ /* Unlock after ensuring that the current request will not be resubmitted. */
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ if (request->sync_mode == RGA_BLIT_ASYNC) {
+ release_fence = rga_dma_fence_alloc();
+ if (IS_ERR(release_fence)) {
+ pr_err("Can not alloc release fence!\n");
+ ret = IS_ERR(release_fence);
+ goto err_reset_request;
+ }
+ request->release_fence = release_fence;
+
+ if (request->acquire_fence_fd > 0) {
+ ret = rga_request_add_acquire_fence_callback(
+ request->acquire_fence_fd, request,
+ rga_request_acquire_fence_signaled_cb);
+ if (ret == 0) {
+ /* acquire fence active */
+ goto export_release_fence_fd;
+ } else if (ret > 0) {
+ /* acquire fence has been signaled */
+ goto request_commit;
+ } else {
+ pr_err("Failed to add callback with acquire fence fd[%d]!\n",
+ request->acquire_fence_fd);
+ goto err_put_release_fence;
+ }
+ }
+ }
+
+request_commit:
+ ret = rga_request_commit(request);
+ if (ret < 0) {
+ pr_err("rga request[%d] commit failed!\n", request->id);
+ goto err_put_release_fence;
+ }
+
+export_release_fence_fd:
+ if (request->release_fence != NULL) {
+ ret = rga_dma_fence_get_fd(request->release_fence);
+ if (ret < 0) {
+ pr_err("Failed to alloc release fence fd!\n");
+ rga_request_release_abort(request, ret);
+ return ret;
+ }
+
+ request->release_fence_fd = ret;
+ }
+
+ return 0;
+
+err_put_release_fence:
+ if (request->release_fence != NULL) {
+ rga_dma_fence_put(request->release_fence);
+ request->release_fence = NULL;
+ }
+
+err_reset_request:
+ spin_lock_irqsave(&request->lock, flags);
+
+ request->current_mm = NULL;
+ request->is_running = false;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+err_put_current_mm:
+ rga_request_put_current_mm(current_mm);
+
+ return ret;
+}
+
+int rga_request_mpi_submit(struct rga_req *req, struct rga_request *request)
+{
+ int ret = 0;
+ struct rga_job *job = NULL;
+ unsigned long flags;
+
+ if (request->sync_mode == RGA_BLIT_ASYNC) {
+ pr_err("mpi unsupported async mode!\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ if (request->is_running) {
+ pr_err("can not re-config when request is running");
+ spin_unlock_irqrestore(&request->lock, flags);
+ return -EFAULT;
+ }
+
+ if (request->task_list == NULL) {
+ pr_err("can not find task list from id[%d]", request->id);
+ spin_unlock_irqrestore(&request->lock, flags);
+ return -EINVAL;
+ }
+
+ /* Reset */
+ request->is_running = true;
+ request->is_done = false;
+ request->finished_task_count = 0;
+ request->failed_task_count = 0;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ job = rga_job_commit(req, request);
+ if (IS_ERR_OR_NULL(job)) {
+ pr_err("failed to commit job!\n");
+ return job ? PTR_ERR(job) : -EFAULT;
+ }
+
+ ret = rga_request_wait(request);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int rga_request_free(struct rga_request *request)
+{
+ struct rga_pending_request_manager *request_manager;
+ struct rga_req *task_list;
+ unsigned long flags;
+
+ request_manager = rga_drvdata->pend_request_manager;
+ if (request_manager == NULL) {
+ pr_err("rga_pending_request_manager is null!\n");
+ return -EFAULT;
+ }
+
+ WARN_ON(!mutex_is_locked(&request_manager->lock));
+
+ if (IS_ERR_OR_NULL(request)) {
+ pr_err("request already freed");
+ return -EFAULT;
+ }
+
+ request_manager->request_count--;
+ idr_remove(&request_manager->request_idr, request->id);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ task_list = request->task_list;
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ if (task_list != NULL)
+ kfree(task_list);
+
+ kfree(request);
+
+ return 0;
+}
+
+static void rga_request_kref_release(struct kref *ref)
+{
+ struct rga_request *request;
+ struct mm_struct *current_mm;
+ unsigned long flags;
+
+ request = container_of(ref, struct rga_request, refcount);
+
+ if (rga_dma_fence_get_status(request->release_fence) == 0)
+ rga_dma_fence_signal(request->release_fence, -EFAULT);
+
+ spin_lock_irqsave(&request->lock, flags);
+
+ rga_dma_fence_put(request->release_fence);
+ current_mm = request->current_mm;
+ request->current_mm = NULL;
+
+ if (!request->is_running || request->is_done) {
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ rga_request_put_current_mm(current_mm);
+
+ goto free_request;
+ }
+
+ spin_unlock_irqrestore(&request->lock, flags);
+
+ rga_request_put_current_mm(current_mm);
+
+ rga_request_scheduler_job_abort(request);
+
+free_request:
+ rga_request_free(request);
+}
+
+/*
+ * Called at driver close to release the request's id references.
+ */
+static int rga_request_free_cb(int id, void *ptr, void *data)
+{
+ return rga_request_free((struct rga_request *)ptr);
+}
+
+int rga_request_alloc(uint32_t flags, struct rga_session *session)
+{
+ int new_id;
+ struct rga_pending_request_manager *request_manager;
+ struct rga_request *request;
+
+ request_manager = rga_drvdata->pend_request_manager;
+ if (request_manager == NULL) {
+ pr_err("rga_pending_request_manager is null!\n");
+ return -EFAULT;
+ }
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL) {
+ pr_err("can not kzalloc for rga_request\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&request->lock);
+ init_waitqueue_head(&request->finished_wq);
+
+ request->pid = current->pid;
+ request->flags = flags;
+ request->session = session;
+ kref_init(&request->refcount);
+
+ /*
+ * Get the user-visible handle using idr. Preload and perform
+ * allocation under our spinlock.
+ */
+ mutex_lock(&request_manager->lock);
+
+ idr_preload(GFP_KERNEL);
+ new_id = idr_alloc_cyclic(&request_manager->request_idr, request, 1, 0, GFP_NOWAIT);
+ idr_preload_end();
+ if (new_id < 0) {
+ pr_err("request alloc id failed!\n");
+
+ mutex_unlock(&request_manager->lock);
+ kfree(request);
+ return new_id;
+ }
+
+ request->id = new_id;
+ request_manager->request_count++;
+
+ mutex_unlock(&request_manager->lock);
+
+ return request->id;
+}
+
+int rga_request_put(struct rga_request *request)
+{
+ return kref_put(&request->refcount, rga_request_kref_release);
+}
+
+void rga_request_get(struct rga_request *request)
+{
+ kref_get(&request->refcount);
+}
+
+int rga_request_manager_init(struct rga_pending_request_manager **request_manager_session)
+{
+ struct rga_pending_request_manager *request_manager = NULL;
+
+ *request_manager_session = kzalloc(sizeof(struct rga_pending_request_manager), GFP_KERNEL);
+ if (*request_manager_session == NULL) {
+ pr_err("can not kzalloc for rga_pending_request_manager\n");
+ return -ENOMEM;
+ }
+
+ request_manager = *request_manager_session;
+
+ mutex_init(&request_manager->lock);
+
+ idr_init_base(&request_manager->request_idr, 1);
+
+ return 0;
+}
+
+int rga_request_manager_remove(struct rga_pending_request_manager **request_manager_session)
+{
+ struct rga_pending_request_manager *request_manager = *request_manager_session;
+
+ mutex_lock(&request_manager->lock);
+
+ idr_for_each(&request_manager->request_idr, &rga_request_free_cb, request_manager);
+ idr_destroy(&request_manager->request_idr);
+
+ mutex_unlock(&request_manager->lock);
+
+ kfree(*request_manager_session);
+
+ *request_manager_session = NULL;
+
+ return 0;
+}
diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c
new file mode 100644
index 000000000..51a31f450
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_mm.c
@@ -0,0 +1,2229 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Cerf Yu <cerf.yu@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_mm: " fmt
+
+#include "rga.h"
+#include "rga_job.h"
+#include "rga_mm.h"
+#include "rga_dma_buf.h"
+#include "rga_common.h"
+#include "rga_iommu.h"
+#include "rga_hw_config.h"
+#include "rga_debugger.h"
+
+static void rga_current_mm_read_lock(struct mm_struct *mm)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
+ mmap_read_lock(mm);
+#else
+ down_read(&mm->mmap_sem);
+#endif
+}
+
+static void rga_current_mm_read_unlock(struct mm_struct *mm)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
+ mmap_read_unlock(mm);
+#else
+ up_read(&mm->mmap_sem);
+#endif
+}
+
+static int rga_get_user_pages_from_vma(struct page **pages, unsigned long Memory,
+ uint32_t pageCount, struct mm_struct *current_mm)
+{
+ int ret = 0;
+ int i;
+ struct vm_area_struct *vma;
+ spinlock_t *ptl;
+ pte_t *pte;
+ pgd_t *pgd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
+ p4d_t *p4d;
+#endif
+ pud_t *pud;
+ pmd_t *pmd;
+ unsigned long pfn;
+
+ for (i = 0; i < pageCount; i++) {
+ vma = find_vma(current_mm, (Memory + i) << PAGE_SHIFT);
+ if (!vma) {
+ pr_err("page[%d] failed to get vma\n", i);
+ ret = RGA_OUT_OF_RESOURCES;
+ break;
+ }
+
+ pgd = pgd_offset(current_mm, (Memory + i) << PAGE_SHIFT);
+ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) {
+ pr_err("page[%d] failed to get pgd\n", i);
+ ret = RGA_OUT_OF_RESOURCES;
+ break;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
+ /*
+ * In the four-level page table,
+ * it will do nothing and return pgd.
+ */
+ p4d = p4d_offset(pgd, (Memory + i) << PAGE_SHIFT);
+ if (p4d_none(*p4d) || unlikely(p4d_bad(*p4d))) {
+ pr_err("page[%d] failed to get p4d\n", i);
+ ret = RGA_OUT_OF_RESOURCES;
+ break;
+ }
+
+ pud = pud_offset(p4d, (Memory + i) << PAGE_SHIFT);
+#else
+ pud = pud_offset(pgd, (Memory + i) << PAGE_SHIFT);
+#endif
+
+ if (pud_none(*pud) || unlikely(pud_bad(*pud))) {
+ pr_err("page[%d] failed to get pud\n", i);
+ ret = RGA_OUT_OF_RESOURCES;
+ break;
+ }
+ pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT);
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
+ pr_err("page[%d] failed to get pmd\n", i);
+ ret = RGA_OUT_OF_RESOURCES;
+ break;
+ }
+ pte = pte_offset_map_lock(current_mm, pmd,
+ (Memory + i) << PAGE_SHIFT, &ptl);
+ if (pte_none(*pte)) {
+ pr_err("page[%d] failed to get pte\n", i);
+ pte_unmap_unlock(pte, ptl);
+ ret = RGA_OUT_OF_RESOURCES;
+ break;
+ }
+
+ pfn = pte_pfn(*pte);
+ pages[i] = pfn_to_page(pfn);
+ pte_unmap_unlock(pte, ptl);
+ }
+
+ if (ret == RGA_OUT_OF_RESOURCES && i > 0)
+ pr_err("Only get buffer %d byte from vma, but current image required %d byte",
+ (int)(i * PAGE_SIZE), (int)(pageCount * PAGE_SIZE));
+
+ return ret;
+}
+
+static int rga_get_user_pages(struct page **pages, unsigned long Memory,
+ uint32_t pageCount, int writeFlag,
+ struct mm_struct *current_mm)
+{
+ uint32_t i;
+ int32_t ret = 0;
+ int32_t result;
+
+ rga_current_mm_read_lock(current_mm);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) && \
+ LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
+ result = get_user_pages(current, current_mm, Memory << PAGE_SHIFT,
+ pageCount, writeFlag ? FOLL_WRITE : 0,
+ pages, NULL);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
+ result = get_user_pages(current, current_mm, Memory << PAGE_SHIFT,
+ pageCount, writeFlag ? FOLL_WRITE : 0, 0, pages, NULL);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
+ result = get_user_pages_remote(current, current_mm,
+ Memory << PAGE_SHIFT,
+ pageCount, writeFlag ? FOLL_WRITE : 0, pages, NULL);
+#else
+ result = get_user_pages_remote(current_mm, Memory << PAGE_SHIFT,
+ pageCount, writeFlag ? FOLL_WRITE : 0, pages, NULL);
+#endif
+
+ if (result > 0 && result >= pageCount) {
+ ret = result;
+ } else {
+ if (result > 0)
+ for (i = 0; i < result; i++)
+ put_page(pages[i]);
+
+ ret = rga_get_user_pages_from_vma(pages, Memory, pageCount, current_mm);
+ if (ret < 0 && result > 0) {
+ pr_err("Only get buffer %d byte from user pages, but current image required %d byte\n",
+ (int)(result * PAGE_SIZE), (int)(pageCount * PAGE_SIZE));
+ }
+ }
+
+ rga_current_mm_read_unlock(current_mm);
+
+ return ret;
+}
+
+static void rga_free_sgt(struct sg_table **sgt_ptr)
+{
+ if (sgt_ptr == NULL || *sgt_ptr == NULL)
+ return;
+
+ sg_free_table(*sgt_ptr);
+ kfree(*sgt_ptr);
+ *sgt_ptr = NULL;
+}
+
+static struct sg_table *rga_alloc_sgt(struct rga_virt_addr *virt_addr)
+{
+ int ret;
+ struct sg_table *sgt = NULL;
+
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+ if (sgt == NULL) {
+ pr_err("%s alloc sgt error!\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* get sg form pages. */
+ /* iova requires minimum page alignment, so sgt cannot have offset */
+ ret = sg_alloc_table_from_pages(sgt,
+ virt_addr->pages,
+ virt_addr->page_count,
+ 0,
+ virt_addr->size,
+ GFP_KERNEL);
+ if (ret) {
+ pr_err("sg_alloc_table_from_pages failed");
+ goto out_free_sgt;
+ }
+
+ return sgt;
+
+out_free_sgt:
+ kfree(sgt);
+
+ return ERR_PTR(ret);
+}
+
+static void rga_free_virt_addr(struct rga_virt_addr **virt_addr_p)
+{
+ int i;
+ struct rga_virt_addr *virt_addr = NULL;
+
+ if (virt_addr_p == NULL)
+ return;
+
+ virt_addr = *virt_addr_p;
+ if (virt_addr == NULL)
+ return;
+
+ for (i = 0; i < virt_addr->result; i++)
+ put_page(virt_addr->pages[i]);
+
+ free_pages((unsigned long)virt_addr->pages, virt_addr->pages_order);
+ kfree(virt_addr);
+ *virt_addr_p = NULL;
+}
+
+static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p,
+ uint64_t viraddr,
+ struct rga_memory_parm *memory_parm,
+ int writeFlag,
+ struct mm_struct *mm)
+{
+ int i;
+ int ret;
+ int result = 0;
+ int order;
+ unsigned int count;
+ int img_size;
+ size_t offset;
+ unsigned long size;
+ struct page **pages = NULL;
+ struct rga_virt_addr *virt_addr = NULL;
+
+ if (memory_parm->size)
+ img_size = memory_parm->size;
+ else
+ img_size = rga_image_size_cal(memory_parm->width,
+ memory_parm->height,
+ memory_parm->format,
+ NULL, NULL, NULL);
+
+ offset = viraddr & (~PAGE_MASK);
+ count = RGA_GET_PAGE_COUNT(img_size + offset);
+ size = count * PAGE_SIZE;
+ if (!size) {
+ pr_err("failed to calculating buffer size! size = %ld, count = %d, offset = %ld\n",
+ size, count, (unsigned long)offset);
+ rga_dump_memory_parm(memory_parm);
+ return -EFAULT;
+ }
+
+ /* alloc pages and page_table */
+ order = get_order(count * sizeof(struct page *));
+ if (order >= MAX_ORDER) {
+ pr_err("Can not alloc pages with order[%d] for viraddr pages, max_order = %d\n",
+ order, MAX_ORDER);
+ return -ENOMEM;
+ }
+
+ pages = (struct page **)__get_free_pages(GFP_KERNEL, order);
+ if (pages == NULL) {
+ pr_err("%s can not alloc pages for viraddr pages\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* get pages from virtual address. */
+ ret = rga_get_user_pages(pages, viraddr >> PAGE_SHIFT, count, writeFlag, mm);
+ if (ret < 0) {
+ pr_err("failed to get pages from virtual adrees: 0x%lx\n",
+ (unsigned long)viraddr);
+ ret = -EINVAL;
+ goto out_free_pages;
+ } else if (ret > 0) {
+ /* For put pages */
+ result = ret;
+ }
+
+ *virt_addr_p = kzalloc(sizeof(struct rga_virt_addr), GFP_KERNEL);
+ if (*virt_addr_p == NULL) {
+ pr_err("%s alloc virt_addr error!\n", __func__);
+ ret = -ENOMEM;
+ goto out_put_and_free_pages;
+ }
+ virt_addr = *virt_addr_p;
+
+ virt_addr->addr = viraddr;
+ virt_addr->pages = pages;
+ virt_addr->pages_order = order;
+ virt_addr->page_count = count;
+ virt_addr->size = size;
+ virt_addr->offset = offset;
+ virt_addr->result = result;
+
+ return 0;
+
+out_put_and_free_pages:
+ for (i = 0; i < result; i++)
+ put_page(pages[i]);
+out_free_pages:
+ free_pages((unsigned long)pages, order);
+
+ return ret;
+}
+
+static inline bool rga_mm_check_memory_limit(struct rga_scheduler_t *scheduler, int mm_flag)
+{
+ if (!scheduler)
+ return false;
+
+ if (scheduler->data->mmu == RGA_MMU &&
+ !(mm_flag & RGA_MEM_UNDER_4G)) {
+ pr_err("%s unsupported memory larger than 4G!\n",
+ rga_get_mmu_type_str(scheduler->data->mmu));
+ return false;
+ }
+
+ return true;
+}
+
+/* If it is within 0~4G, return 1 (true). */
+static int rga_mm_check_range_sgt(struct sg_table *sgt)
+{
+ int i;
+ struct scatterlist *sg;
+ phys_addr_t s_phys = 0;
+
+ for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
+ s_phys = sg_phys(sg);
+ if ((s_phys > 0xffffffff) || (s_phys + sg->length > 0xffffffff))
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline int rga_mm_check_range_phys_addr(phys_addr_t paddr, size_t size)
+{
+ return ((paddr + size) <= 0xffffffff);
+}
+
+static inline bool rga_mm_check_contiguous_sgt(struct sg_table *sgt)
+{
+ if (sgt->orig_nents == 1)
+ return true;
+
+ return false;
+}
+
+static void rga_mm_unmap_dma_buffer(struct rga_internal_buffer *internal_buffer)
+{
+ if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer))
+ return;
+
+ rga_dma_unmap_buf(internal_buffer->dma_buffer);
+
+ if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS &&
+ internal_buffer->phys_addr > 0)
+ internal_buffer->phys_addr = 0;
+
+ kfree(internal_buffer->dma_buffer);
+ internal_buffer->dma_buffer = NULL;
+}
+
+static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer,
+ struct rga_internal_buffer *internal_buffer,
+ struct rga_job *job)
+{
+ int ret;
+ int ex_buffer_size;
+ uint32_t mm_flag = 0;
+ phys_addr_t phys_addr = 0;
+ struct rga_dma_buffer *buffer;
+ struct device *map_dev;
+ struct rga_scheduler_t *scheduler;
+
+ scheduler = job ? job->scheduler :
+ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index];
+ if (scheduler == NULL) {
+ pr_err("Invalid scheduler device!\n");
+ return -EINVAL;
+ }
+
+ if (external_buffer->memory_parm.size)
+ ex_buffer_size = external_buffer->memory_parm.size;
+ else
+ ex_buffer_size = rga_image_size_cal(external_buffer->memory_parm.width,
+ external_buffer->memory_parm.height,
+ external_buffer->memory_parm.format,
+ NULL, NULL, NULL);
+ if (ex_buffer_size <= 0) {
+ pr_err("failed to calculating buffer size!\n");
+ rga_dump_memory_parm(&external_buffer->memory_parm);
+ return ex_buffer_size == 0 ? -EINVAL : ex_buffer_size;
+ }
+
+ /*
+ * dma-buf api needs to use default_domain of main dev,
+ * and not IOMMU for devices without iommu_info ptr.
+ */
+ map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev;
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (buffer == NULL) {
+ pr_err("%s alloc internal_buffer error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ switch (external_buffer->type) {
+ case RGA_DMA_BUFFER:
+ ret = rga_dma_map_fd((int)external_buffer->memory,
+ buffer, DMA_BIDIRECTIONAL,
+ map_dev);
+ break;
+ case RGA_DMA_BUFFER_PTR:
+ ret = rga_dma_map_buf((struct dma_buf *)u64_to_user_ptr(external_buffer->memory),
+ buffer, DMA_BIDIRECTIONAL,
+ map_dev);
+ break;
+ default:
+ ret = -EFAULT;
+ break;
+ }
+ if (ret < 0) {
+ pr_err("%s core[%d] map dma buffer error!\n",
+ __func__, scheduler->core);
+ goto free_buffer;
+ }
+
+ if (buffer->size < ex_buffer_size) {
+ pr_err("Only get buffer %ld byte from %s = 0x%lx, but current image required %d byte\n",
+ buffer->size, rga_get_memory_type_str(external_buffer->type),
+ (unsigned long)external_buffer->memory, ex_buffer_size);
+ rga_dump_memory_parm(&external_buffer->memory_parm);
+ ret = -EINVAL;
+ goto unmap_buffer;
+ }
+
+ buffer->scheduler = scheduler;
+
+ if (rga_mm_check_range_sgt(buffer->sgt))
+ mm_flag |= RGA_MEM_UNDER_4G;
+
+ /*
+ * If it's physically contiguous, then the RGA_MMU can
+ * directly use the physical address.
+ */
+ if (rga_mm_check_contiguous_sgt(buffer->sgt)) {
+ phys_addr = sg_phys(buffer->sgt->sgl);
+ if (phys_addr == 0) {
+ pr_err("%s get physical address error!", __func__);
+ ret = -EFAULT;
+ goto unmap_buffer;
+ }
+
+ mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS;
+ }
+
+ if (!rga_mm_check_memory_limit(scheduler, mm_flag)) {
+ pr_err("scheduler core[%d] unsupported mm_flag[0x%x]!\n",
+ scheduler->core, mm_flag);
+ ret = -EINVAL;
+ goto unmap_buffer;
+ }
+
+ internal_buffer->dma_buffer = buffer;
+ internal_buffer->mm_flag = mm_flag;
+ internal_buffer->phys_addr = phys_addr ? phys_addr : 0;
+
+ return 0;
+
+unmap_buffer:
+ rga_dma_unmap_buf(buffer);
+
+free_buffer:
+ kfree(buffer);
+
+ return ret;
+}
+
+static void rga_mm_unmap_virt_addr(struct rga_internal_buffer *internal_buffer)
+{
+ WARN_ON(internal_buffer->dma_buffer == NULL || internal_buffer->virt_addr == NULL);
+
+ if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer))
+ return;
+
+ switch (internal_buffer->dma_buffer->scheduler->data->mmu) {
+ case RGA_IOMMU:
+ rga_iommu_unmap(internal_buffer->dma_buffer);
+ break;
+ case RGA_MMU:
+ dma_unmap_sg(internal_buffer->dma_buffer->scheduler->dev,
+ internal_buffer->dma_buffer->sgt->sgl,
+ internal_buffer->dma_buffer->sgt->orig_nents,
+ DMA_BIDIRECTIONAL);
+ break;
+ default:
+ break;
+ }
+
+ if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS &&
+ internal_buffer->phys_addr > 0)
+ internal_buffer->phys_addr = 0;
+
+ rga_free_sgt(&internal_buffer->dma_buffer->sgt);
+
+ kfree(internal_buffer->dma_buffer);
+ internal_buffer->dma_buffer = NULL;
+
+ rga_free_virt_addr(&internal_buffer->virt_addr);
+
+ mmput(internal_buffer->current_mm);
+ mmdrop(internal_buffer->current_mm);
+ internal_buffer->current_mm = NULL;
+}
+
+static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer,
+ struct rga_internal_buffer *internal_buffer,
+ struct rga_job *job, int write_flag)
+{
+ int ret;
+ uint32_t mm_flag = 0;
+ phys_addr_t phys_addr = 0;
+ struct sg_table *sgt;
+ struct rga_virt_addr *virt_addr;
+ struct rga_dma_buffer *buffer;
+ struct rga_scheduler_t *scheduler;
+
+ scheduler = job ? job->scheduler :
+ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index];
+ if (scheduler == NULL) {
+ pr_err("Invalid scheduler device!\n");
+ return -EINVAL;
+ }
+
+ internal_buffer->current_mm = job ? job->mm : current->mm;
+ if (internal_buffer->current_mm == NULL) {
+ pr_err("%s, cannot get current mm!\n", __func__);
+ return -EFAULT;
+ }
+ mmgrab(internal_buffer->current_mm);
+ mmget(internal_buffer->current_mm);
+
+ ret = rga_alloc_virt_addr(&virt_addr,
+ external_buffer->memory,
+ &internal_buffer->memory_parm,
+ write_flag, internal_buffer->current_mm);
+ if (ret < 0) {
+ pr_err("Can not alloc rga_virt_addr from 0x%lx\n",
+ (unsigned long)external_buffer->memory);
+ goto put_current_mm;
+ }
+
+ sgt = rga_alloc_sgt(virt_addr);
+ if (IS_ERR(sgt)) {
+ pr_err("alloc sgt error!\n");
+ ret = PTR_ERR(sgt);
+ goto free_virt_addr;
+ }
+
+ if (rga_mm_check_range_sgt(sgt))
+ mm_flag |= RGA_MEM_UNDER_4G;
+
+ if (rga_mm_check_contiguous_sgt(sgt)) {
+ phys_addr = sg_phys(sgt->sgl);
+ if (phys_addr == 0) {
+ pr_err("%s get physical address error!", __func__);
+ ret = -EFAULT;
+ goto free_sgt;
+ }
+
+ mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS;
+ }
+
+ /*
+ * Some userspace virtual addresses do not have an
+ * interface for flushing the cache, so it is mandatory
+ * to flush the cache when the virtual address is used.
+ */
+ mm_flag |= RGA_MEM_FORCE_FLUSH_CACHE;
+
+ if (!rga_mm_check_memory_limit(scheduler, mm_flag)) {
+ pr_err("scheduler core[%d] unsupported mm_flag[0x%x]!\n",
+ scheduler->core, mm_flag);
+ ret = -EINVAL;
+ goto free_sgt;
+ }
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (buffer == NULL) {
+ pr_err("%s alloc internal dma_buffer error!\n", __func__);
+ ret = -ENOMEM;
+ goto free_sgt;
+ }
+
+ switch (scheduler->data->mmu) {
+ case RGA_IOMMU:
+ ret = rga_iommu_map_sgt(sgt, virt_addr->size, buffer, scheduler->dev);
+ if (ret < 0) {
+ pr_err("%s core[%d] iommu_map virtual address error!\n",
+ __func__, scheduler->core);
+ goto free_dma_buffer;
+ }
+ break;
+ case RGA_MMU:
+ ret = dma_map_sg(scheduler->dev, sgt->sgl, sgt->orig_nents, DMA_BIDIRECTIONAL);
+ if (ret == 0) {
+ pr_err("%s core[%d] dma_map_sgt error! va = 0x%lx, nents = %d\n",
+ __func__, scheduler->core,
+ (unsigned long)virt_addr->addr, sgt->orig_nents);
+ ret = -EINVAL;
+ goto free_dma_buffer;
+ }
+ break;
+ default:
+ if (mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
+ break;
+
+ pr_err("Current %s[%d] cannot support physically discontinuous virtual address!\n",
+ rga_get_mmu_type_str(scheduler->data->mmu), scheduler->data->mmu);
+ ret = -EOPNOTSUPP;
+ goto free_dma_buffer;
+ }
+
+ buffer->sgt = sgt;
+ buffer->offset = virt_addr->offset;
+ buffer->size = virt_addr->size;
+ buffer->scheduler = scheduler;
+
+ internal_buffer->virt_addr = virt_addr;
+ internal_buffer->dma_buffer = buffer;
+ internal_buffer->mm_flag = mm_flag;
+ internal_buffer->phys_addr = phys_addr ? phys_addr + virt_addr->offset : 0;
+
+ return 0;
+
+free_dma_buffer:
+ kfree(buffer);
+free_sgt:
+ rga_free_sgt(&sgt);
+free_virt_addr:
+ rga_free_virt_addr(&virt_addr);
+put_current_mm:
+ mmput(internal_buffer->current_mm);
+ mmdrop(internal_buffer->current_mm);
+ internal_buffer->current_mm = NULL;
+
+ return ret;
+}
+
+static void rga_mm_unmap_phys_addr(struct rga_internal_buffer *internal_buffer)
+{
+ WARN_ON(internal_buffer->dma_buffer == NULL);
+
+ if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer))
+ return;
+
+ if (internal_buffer->dma_buffer->scheduler->data->mmu == RGA_IOMMU)
+ rga_iommu_unmap(internal_buffer->dma_buffer);
+
+ kfree(internal_buffer->dma_buffer);
+ internal_buffer->dma_buffer = NULL;
+ internal_buffer->phys_addr = 0;
+ internal_buffer->size = 0;
+}
+
+static int rga_mm_map_phys_addr(struct rga_external_buffer *external_buffer,
+ struct rga_internal_buffer *internal_buffer,
+ struct rga_job *job)
+{
+ int ret;
+ phys_addr_t phys_addr;
+ int buffer_size;
+ uint32_t mm_flag = 0;
+ struct rga_dma_buffer *buffer;
+ struct rga_scheduler_t *scheduler;
+
+ scheduler = job ? job->scheduler :
+ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index];
+ if (scheduler == NULL) {
+ pr_err("Invalid scheduler device!\n");
+ return -EINVAL;
+ }
+
+ if (internal_buffer->memory_parm.size)
+ buffer_size = internal_buffer->memory_parm.size;
+ else
+ buffer_size = rga_image_size_cal(internal_buffer->memory_parm.width,
+ internal_buffer->memory_parm.height,
+ internal_buffer->memory_parm.format,
+ NULL, NULL, NULL);
+ if (buffer_size <= 0) {
+ pr_err("Failed to get phys addr size!\n");
+ rga_dump_memory_parm(&internal_buffer->memory_parm);
+ return buffer_size == 0 ? -EINVAL : buffer_size;
+ }
+
+ phys_addr = external_buffer->memory;
+ mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS;
+ if (rga_mm_check_range_phys_addr(phys_addr, buffer_size))
+ mm_flag |= RGA_MEM_UNDER_4G;
+
+ if (!rga_mm_check_memory_limit(scheduler, mm_flag)) {
+ pr_err("scheduler core[%d] unsupported mm_flag[0x%x]!\n",
+ scheduler->core, mm_flag);
+ return -EINVAL;
+ }
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (buffer == NULL) {
+ pr_err("%s alloc internal dma buffer error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (scheduler->data->mmu == RGA_IOMMU) {
+ ret = rga_iommu_map(phys_addr, buffer_size, buffer, scheduler->dev);
+ if (ret < 0) {
+ pr_err("%s core[%d] map phys_addr error!\n", __func__, scheduler->core);
+ goto free_dma_buffer;
+ }
+ }
+
+ buffer->scheduler = scheduler;
+
+ internal_buffer->phys_addr = phys_addr;
+ internal_buffer->size = buffer_size;
+ internal_buffer->mm_flag = mm_flag;
+ internal_buffer->dma_buffer = buffer;
+
+ return 0;
+
+free_dma_buffer:
+ kfree(buffer);
+
+ return ret;
+}
+
+static int rga_mm_unmap_buffer(struct rga_internal_buffer *internal_buffer)
+{
+ switch (internal_buffer->type) {
+ case RGA_DMA_BUFFER:
+ case RGA_DMA_BUFFER_PTR:
+ rga_mm_unmap_dma_buffer(internal_buffer);
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ rga_mm_unmap_virt_addr(internal_buffer);
+ break;
+ case RGA_PHYSICAL_ADDRESS:
+ rga_mm_unmap_phys_addr(internal_buffer);
+ break;
+ default:
+ pr_err("Illegal external buffer!\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int rga_mm_map_buffer(struct rga_external_buffer *external_buffer,
+ struct rga_internal_buffer *internal_buffer,
+ struct rga_job *job, int write_flag)
+{
+ int ret;
+
+ memcpy(&internal_buffer->memory_parm, &external_buffer->memory_parm,
+ sizeof(internal_buffer->memory_parm));
+
+ switch (external_buffer->type) {
+ case RGA_DMA_BUFFER:
+ case RGA_DMA_BUFFER_PTR:
+ internal_buffer->type = external_buffer->type;
+
+ ret = rga_mm_map_dma_buffer(external_buffer, internal_buffer, job);
+ if (ret < 0) {
+ pr_err("%s map dma_buf error!\n", __func__);
+ return ret;
+ }
+
+ internal_buffer->size = internal_buffer->dma_buffer->size -
+ internal_buffer->dma_buffer->offset;
+ internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU;
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ internal_buffer->type = RGA_VIRTUAL_ADDRESS;
+
+ ret = rga_mm_map_virt_addr(external_buffer, internal_buffer, job, write_flag);
+ if (ret < 0) {
+ pr_err("%s map virtual address error!\n", __func__);
+ return ret;
+ }
+
+ internal_buffer->size = internal_buffer->virt_addr->size -
+ internal_buffer->virt_addr->offset;
+ internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU;
+ break;
+ case RGA_PHYSICAL_ADDRESS:
+ internal_buffer->type = RGA_PHYSICAL_ADDRESS;
+
+ ret = rga_mm_map_phys_addr(external_buffer, internal_buffer, job);
+ if (ret < 0) {
+ pr_err("%s map physical address error!\n", __func__);
+ return ret;
+ }
+
+ internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU;
+ break;
+ default:
+ pr_err("Illegal external buffer!\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void rga_mm_kref_release_buffer(struct kref *ref)
+{
+ struct rga_internal_buffer *internal_buffer;
+
+ internal_buffer = container_of(ref, struct rga_internal_buffer, refcount);
+ rga_mm_unmap_buffer(internal_buffer);
+
+ idr_remove(&rga_drvdata->mm->memory_idr, internal_buffer->handle);
+ kfree(internal_buffer);
+ rga_drvdata->mm->buffer_count--;
+}
+
+/*
+ * Called at driver close to release the memory's handle references.
+ */
+static int rga_mm_handle_remove(int id, void *ptr, void *data)
+{
+ struct rga_internal_buffer *internal_buffer = ptr;
+
+ rga_mm_kref_release_buffer(&internal_buffer->refcount);
+
+ return 0;
+}
+
+static void rga_mm_buffer_destroy(struct rga_internal_buffer *buffer)
+{
+ rga_mm_kref_release_buffer(&buffer->refcount);
+}
+
+static struct rga_internal_buffer *
+rga_mm_lookup_external(struct rga_mm *mm_session,
+ struct rga_external_buffer *external_buffer,
+ struct mm_struct *current_mm)
+{
+ int id;
+ struct dma_buf *dma_buf = NULL;
+ struct rga_internal_buffer *temp_buffer = NULL;
+ struct rga_internal_buffer *output_buffer = NULL;
+
+ WARN_ON(!mutex_is_locked(&mm_session->lock));
+
+ switch (external_buffer->type) {
+ case RGA_DMA_BUFFER:
+ dma_buf = dma_buf_get((int)external_buffer->memory);
+ if (IS_ERR(dma_buf))
+ return (struct rga_internal_buffer *)dma_buf;
+
+ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) {
+ if (temp_buffer->dma_buffer == NULL)
+ continue;
+
+ if (temp_buffer->dma_buffer[0].dma_buf == dma_buf) {
+ output_buffer = temp_buffer;
+ break;
+ }
+ }
+
+ dma_buf_put(dma_buf);
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) {
+ if (temp_buffer->virt_addr == NULL)
+ continue;
+
+ if (temp_buffer->virt_addr->addr == external_buffer->memory) {
+ if (temp_buffer->current_mm == current_mm) {
+ output_buffer = temp_buffer;
+ break;
+ }
+
+ continue;
+ }
+ }
+
+ break;
+ case RGA_PHYSICAL_ADDRESS:
+ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) {
+ if (temp_buffer->phys_addr == external_buffer->memory) {
+ output_buffer = temp_buffer;
+ break;
+ }
+ }
+
+ break;
+ case RGA_DMA_BUFFER_PTR:
+ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) {
+ if (temp_buffer->dma_buffer == NULL)
+ continue;
+
+ if ((unsigned long)temp_buffer->dma_buffer[0].dma_buf ==
+ external_buffer->memory) {
+ output_buffer = temp_buffer;
+ break;
+ }
+ }
+
+ break;
+
+ default:
+ pr_err("Illegal external buffer!\n");
+ return NULL;
+ }
+
+ return output_buffer;
+}
+
+struct rga_internal_buffer *rga_mm_lookup_handle(struct rga_mm *mm_session, uint32_t handle)
+{
+ struct rga_internal_buffer *output_buffer;
+
+ WARN_ON(!mutex_is_locked(&mm_session->lock));
+
+ output_buffer = idr_find(&mm_session->memory_idr, handle);
+
+ return output_buffer;
+}
+
+int rga_mm_lookup_flag(struct rga_mm *mm_session, uint64_t handle)
+{
+ struct rga_internal_buffer *output_buffer;
+
+ output_buffer = rga_mm_lookup_handle(mm_session, handle);
+ if (output_buffer == NULL) {
+ pr_err("This handle[%ld] is illegal.\n", (unsigned long)handle);
+ return -EINVAL;
+ }
+
+ return output_buffer->mm_flag;
+}
+
+dma_addr_t rga_mm_lookup_iova(struct rga_internal_buffer *buffer)
+{
+ if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer))
+ return 0;
+
+ return buffer->dma_buffer->iova + buffer->dma_buffer->offset;
+}
+
+struct sg_table *rga_mm_lookup_sgt(struct rga_internal_buffer *buffer)
+{
+ if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer))
+ return NULL;
+
+ return buffer->dma_buffer->sgt;
+}
+
+void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer)
+{
+ pr_info("handle = %d refcount = %d mm_flag = 0x%x\n",
+ dump_buffer->handle, kref_read(&dump_buffer->refcount),
+ dump_buffer->mm_flag);
+
+ switch (dump_buffer->type) {
+ case RGA_DMA_BUFFER:
+ case RGA_DMA_BUFFER_PTR:
+ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer))
+ break;
+
+ pr_info("dma_buffer:\n");
+ pr_info("dma_buf = %p, iova = 0x%lx, sgt = %p, size = %ld, map_core = 0x%x\n",
+ dump_buffer->dma_buffer->dma_buf,
+ (unsigned long)dump_buffer->dma_buffer->iova,
+ dump_buffer->dma_buffer->sgt,
+ dump_buffer->dma_buffer->size,
+ dump_buffer->dma_buffer->scheduler->core);
+
+ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
+ pr_info("is contiguous, pa = 0x%lx\n",
+ (unsigned long)dump_buffer->phys_addr);
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ if (dump_buffer->virt_addr == NULL)
+ break;
+
+ pr_info("virtual address:\n");
+ pr_info("va = 0x%lx, pages = %p, size = %ld\n",
+ (unsigned long)dump_buffer->virt_addr->addr,
+ dump_buffer->virt_addr->pages,
+ dump_buffer->virt_addr->size);
+
+ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer))
+ break;
+
+ pr_info("iova = 0x%lx, offset = 0x%lx, sgt = %p, size = %ld, map_core = 0x%x\n",
+ (unsigned long)dump_buffer->dma_buffer->iova,
+ (unsigned long)dump_buffer->dma_buffer->offset,
+ dump_buffer->dma_buffer->sgt,
+ dump_buffer->dma_buffer->size,
+ dump_buffer->dma_buffer->scheduler->core);
+
+ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
+ pr_info("is contiguous, pa = 0x%lx\n",
+ (unsigned long)dump_buffer->phys_addr);
+ break;
+ case RGA_PHYSICAL_ADDRESS:
+ pr_info("physical address: pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr);
+ break;
+ default:
+ pr_err("Illegal external buffer!\n");
+ break;
+ }
+}
+
+void rga_mm_dump_info(struct rga_mm *mm_session)
+{
+ int id;
+ struct rga_internal_buffer *dump_buffer;
+
+ WARN_ON(!mutex_is_locked(&mm_session->lock));
+
+ pr_info("rga mm info:\n");
+
+ pr_info("buffer count = %d\n", mm_session->buffer_count);
+ pr_info("===============================================================\n");
+
+ idr_for_each_entry(&mm_session->memory_idr, dump_buffer, id) {
+ rga_mm_dump_buffer(dump_buffer);
+
+ pr_info("---------------------------------------------------------------\n");
+ }
+}
+
+static bool rga_mm_is_need_mmu(struct rga_job *job, struct rga_internal_buffer *buffer)
+{
+ if (buffer == NULL || job == NULL || job->scheduler == NULL)
+ return false;
+
+ /* RK_IOMMU no need to configure enable or not in the driver. */
+ if (job->scheduler->data->mmu == RGA_IOMMU)
+ return false;
+
+ /* RK_MMU need to configure enable or not in the driver. */
+ if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
+ return false;
+ else if (buffer->mm_flag & RGA_MEM_NEED_USE_IOMMU)
+ return true;
+
+ return false;
+}
+
+static int rga_mm_set_mmu_flag(struct rga_job *job)
+{
+ struct rga_mmu_t *mmu_info;
+ int src_mmu_en;
+ int src1_mmu_en;
+ int dst_mmu_en;
+ int els_mmu_en;
+
+ src_mmu_en = rga_mm_is_need_mmu(job, job->src_buffer.addr);
+ src1_mmu_en = rga_mm_is_need_mmu(job, job->src1_buffer.addr);
+ dst_mmu_en = rga_mm_is_need_mmu(job, job->dst_buffer.addr);
+ els_mmu_en = rga_mm_is_need_mmu(job, job->els_buffer.addr);
+
+ mmu_info = &job->rga_command_base.mmu_info;
+ memset(mmu_info, 0x0, sizeof(*mmu_info));
+ if (src_mmu_en)
+ mmu_info->mmu_flag |= (0x1 << 8);
+ if (src1_mmu_en)
+ mmu_info->mmu_flag |= (0x1 << 9);
+ if (dst_mmu_en)
+ mmu_info->mmu_flag |= (0x1 << 10);
+ if (els_mmu_en)
+ mmu_info->mmu_flag |= (0x1 << 11);
+
+ if (mmu_info->mmu_flag & (0xf << 8)) {
+ mmu_info->mmu_flag |= 1;
+ mmu_info->mmu_flag |= 1 << 31;
+ mmu_info->mmu_en = 1;
+ }
+
+ return 0;
+}
+
+static int rga_mm_sgt_to_page_table(struct sg_table *sg,
+ uint32_t *page_table,
+ int32_t pageCount,
+ int32_t use_dma_address)
+{
+ uint32_t i;
+ unsigned long Address;
+ uint32_t mapped_size = 0;
+ uint32_t len;
+ struct scatterlist *sgl = sg->sgl;
+ uint32_t sg_num = 0;
+ uint32_t break_flag = 0;
+
+ do {
+ /*
+ * The length of each sgl is expected to be obtained here, not
+ * the length of the entire dma_buf, so sg_dma_len() is not used.
+ */
+ len = sgl->length >> PAGE_SHIFT;
+
+ if (use_dma_address)
+ /*
+ * The fd passed by user space gets sg through
+ * dma_buf_map_attachment, so dma_address can
+ * be use here.
+ * When the mapped device does not have iommu, it will
+ * return the first address of the real physical page
+ * when it meets the requirements of the current device,
+ * and will trigger swiotlb when it does not meet the
+ * requirements to obtain a software-mapped physical
+ * address that is mapped to meet the device address
+ * requirements.
+ */
+ Address = sg_dma_address(sgl);
+ else
+ Address = sg_phys(sgl);
+
+ for (i = 0; i < len; i++) {
+ if (mapped_size + i >= pageCount) {
+ break_flag = 1;
+ break;
+ }
+ page_table[mapped_size + i] = (uint32_t)(Address + (i << PAGE_SHIFT));
+ }
+ if (break_flag)
+ break;
+ mapped_size += len;
+ sg_num += 1;
+ } while ((sgl = sg_next(sgl)) && (mapped_size < pageCount) && (sg_num < sg->orig_nents));
+
+ return 0;
+}
+
+static int rga_mm_set_mmu_base(struct rga_job *job,
+ struct rga_img_info_t *img,
+ struct rga_job_buffer *job_buf)
+{
+ int ret;
+ int yrgb_count = 0;
+ int uv_count = 0;
+ int v_count = 0;
+ int page_count = 0;
+ int order = 0;
+ uint32_t *page_table = NULL;
+ struct sg_table *sgt = NULL;
+
+ int img_size, yrgb_size, uv_size, v_size;
+ int img_offset = 0;
+ int yrgb_offset = 0;
+ int uv_offset = 0;
+ int v_offset = 0;
+
+ img_size = rga_image_size_cal(img->vir_w, img->vir_h, img->format,
+ &yrgb_size, &uv_size, &v_size);
+ if (img_size <= 0) {
+ pr_err("Image size cal error! width = %d, height = %d, format = %s\n",
+ img->vir_w, img->vir_h, rga_get_format_name(img->format));
+ return -EINVAL;
+ }
+
+ /* using third-address */
+ if (job_buf->uv_addr) {
+ if (job_buf->y_addr->virt_addr != NULL)
+ yrgb_offset = job_buf->y_addr->virt_addr->offset;
+ if (job_buf->uv_addr->virt_addr != NULL)
+ uv_offset = job_buf->uv_addr->virt_addr->offset;
+ if (job_buf->v_addr->virt_addr != NULL)
+ v_offset = job_buf->v_addr->virt_addr->offset;
+
+ yrgb_count = RGA_GET_PAGE_COUNT(yrgb_size + yrgb_offset);
+ uv_count = RGA_GET_PAGE_COUNT(uv_size + uv_offset);
+ v_count = RGA_GET_PAGE_COUNT(v_size + v_offset);
+ page_count = yrgb_count + uv_count + v_count;
+
+ if (page_count <= 0) {
+ pr_err("page count cal error! yrba = %d, uv = %d, v = %d\n",
+ yrgb_count, uv_count, v_count);
+ return -EFAULT;
+ }
+
+ if (job->flags & RGA_JOB_USE_HANDLE) {
+ order = get_order(page_count * sizeof(uint32_t *));
+ if (order >= MAX_ORDER) {
+ pr_err("Can not alloc pages with order[%d] for page_table, max_order = %d\n",
+ order, MAX_ORDER);
+ return -ENOMEM;
+ }
+
+ page_table = (uint32_t *)__get_free_pages(GFP_KERNEL | GFP_DMA32, order);
+ if (page_table == NULL) {
+ pr_err("%s can not alloc pages for page_table, order = %d\n",
+ __func__, order);
+ return -ENOMEM;
+ }
+ } else {
+ mutex_lock(&rga_drvdata->lock);
+
+ page_table = rga_mmu_buf_get(rga_drvdata->mmu_base, page_count);
+ if (page_table == NULL) {
+ pr_err("mmu_buf get error!\n");
+ mutex_unlock(&rga_drvdata->lock);
+ return -EFAULT;
+ }
+
+ mutex_unlock(&rga_drvdata->lock);
+ }
+
+ sgt = rga_mm_lookup_sgt(job_buf->y_addr);
+ if (sgt == NULL) {
+ pr_err("rga2 cannot get sgt from internal buffer!\n");
+ ret = -EINVAL;
+ goto err_free_page_table;
+ }
+ rga_mm_sgt_to_page_table(sgt, page_table, yrgb_count, false);
+
+ sgt = rga_mm_lookup_sgt(job_buf->uv_addr);
+ if (sgt == NULL) {
+ pr_err("rga2 cannot get sgt from internal buffer!\n");
+ ret = -EINVAL;
+ goto err_free_page_table;
+ }
+ rga_mm_sgt_to_page_table(sgt, page_table + yrgb_count, uv_count, false);
+
+ sgt = rga_mm_lookup_sgt(job_buf->v_addr);
+ if (sgt == NULL) {
+ pr_err("rga2 cannot get sgt from internal buffer!\n");
+ ret = -EINVAL;
+ goto err_free_page_table;
+ }
+ rga_mm_sgt_to_page_table(sgt, page_table + yrgb_count + uv_count, v_count, false);
+
+ img->yrgb_addr = yrgb_offset;
+ img->uv_addr = (yrgb_count << PAGE_SHIFT) + uv_offset;
+ img->v_addr = ((yrgb_count + uv_count) << PAGE_SHIFT) + v_offset;
+ } else {
+ if (job_buf->addr->virt_addr != NULL)
+ img_offset = job_buf->addr->virt_addr->offset;
+
+ page_count = RGA_GET_PAGE_COUNT(img_size + img_offset);
+ if (page_count < 0) {
+ pr_err("page count cal error! yrba = %d, uv = %d, v = %d\n",
+ yrgb_count, uv_count, v_count);
+ return -EFAULT;
+ }
+
+ if (job->flags & RGA_JOB_USE_HANDLE) {
+ order = get_order(page_count * sizeof(uint32_t *));
+ if (order >= MAX_ORDER) {
+ pr_err("Can not alloc pages with order[%d] for page_table, max_order = %d\n",
+ order, MAX_ORDER);
+ return -ENOMEM;
+ }
+
+ page_table = (uint32_t *)__get_free_pages(GFP_KERNEL | GFP_DMA32, order);
+ if (page_table == NULL) {
+ pr_err("%s can not alloc pages for page_table, order = %d\n",
+ __func__, order);
+ return -ENOMEM;
+ }
+ } else {
+ mutex_lock(&rga_drvdata->lock);
+
+ page_table = rga_mmu_buf_get(rga_drvdata->mmu_base, page_count);
+ if (page_table == NULL) {
+ pr_err("mmu_buf get error!\n");
+ mutex_unlock(&rga_drvdata->lock);
+ return -EFAULT;
+ }
+
+ mutex_unlock(&rga_drvdata->lock);
+ }
+
+ sgt = rga_mm_lookup_sgt(job_buf->addr);
+ if (sgt == NULL) {
+ pr_err("rga2 cannot get sgt from internal buffer!\n");
+ ret = -EINVAL;
+ goto err_free_page_table;
+ }
+ rga_mm_sgt_to_page_table(sgt, page_table, page_count, false);
+
+ img->yrgb_addr = img_offset;
+ rga_convert_addr(img, false);
+ }
+
+ job_buf->page_table = page_table;
+ job_buf->order = order;
+ job_buf->page_count = page_count;
+
+ return 0;
+
+err_free_page_table:
+ if (job->flags & RGA_JOB_USE_HANDLE)
+ free_pages((unsigned long)page_table, order);
+ return ret;
+}
+
+static int rga_mm_sync_dma_sg_for_device(struct rga_internal_buffer *buffer,
+ struct rga_job *job,
+ enum dma_data_direction dir)
+{
+ struct sg_table *sgt;
+ struct rga_scheduler_t *scheduler;
+
+ scheduler = buffer->dma_buffer->scheduler;
+ if (scheduler == NULL) {
+ pr_err("%s(%d), failed to get scheduler, core = 0x%x\n",
+ __func__, __LINE__, job->core);
+ return -EFAULT;
+ }
+
+ if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS &&
+ scheduler->data->mmu != RGA_IOMMU) {
+ dma_sync_single_for_device(scheduler->dev, buffer->phys_addr, buffer->size, dir);
+ } else {
+ sgt = rga_mm_lookup_sgt(buffer);
+ if (sgt == NULL) {
+ pr_err("%s(%d), failed to get sgt, core = 0x%x\n",
+ __func__, __LINE__, job->core);
+ return -EINVAL;
+ }
+
+ dma_sync_sg_for_device(scheduler->dev, sgt->sgl, sgt->orig_nents, dir);
+ }
+
+ return 0;
+}
+
+static int rga_mm_sync_dma_sg_for_cpu(struct rga_internal_buffer *buffer,
+ struct rga_job *job,
+ enum dma_data_direction dir)
+{
+ struct sg_table *sgt;
+ struct rga_scheduler_t *scheduler;
+
+ scheduler = buffer->dma_buffer->scheduler;
+ if (scheduler == NULL) {
+ pr_err("%s(%d), failed to get scheduler, core = 0x%x\n",
+ __func__, __LINE__, job->core);
+ return -EFAULT;
+ }
+
+ if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS &&
+ scheduler->data->mmu != RGA_IOMMU) {
+ dma_sync_single_for_cpu(scheduler->dev, buffer->phys_addr, buffer->size, dir);
+ } else {
+ sgt = rga_mm_lookup_sgt(buffer);
+ if (sgt == NULL) {
+ pr_err("%s(%d), failed to get sgt, core = 0x%x\n",
+ __func__, __LINE__, job->core);
+ return -EINVAL;
+ }
+
+ dma_sync_sg_for_cpu(scheduler->dev, sgt->sgl, sgt->orig_nents, dir);
+ }
+
+ return 0;
+}
+
+static int rga_mm_get_buffer_info(struct rga_job *job,
+ struct rga_internal_buffer *internal_buffer,
+ uint64_t *channel_addr)
+{
+ uint64_t addr;
+
+ switch (job->scheduler->data->mmu) {
+ case RGA_IOMMU:
+ addr = rga_mm_lookup_iova(internal_buffer);
+ if (addr == 0) {
+ pr_err("core[%d] lookup buffer_type[0x%x] iova error!\n",
+ job->core, internal_buffer->type);
+ return -EINVAL;
+ }
+ break;
+ case RGA_MMU:
+ default:
+ if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) {
+ addr = internal_buffer->phys_addr;
+ break;
+ }
+
+ switch (internal_buffer->type) {
+ case RGA_DMA_BUFFER:
+ case RGA_DMA_BUFFER_PTR:
+ addr = 0;
+ break;
+ case RGA_VIRTUAL_ADDRESS:
+ addr = internal_buffer->virt_addr->addr;
+ break;
+ case RGA_PHYSICAL_ADDRESS:
+ addr = internal_buffer->phys_addr;
+ break;
+ default:
+ pr_err("Illegal external buffer!\n");
+ return -EFAULT;
+ }
+ break;
+ }
+
+ *channel_addr = addr;
+
+ return 0;
+}
+
+static int rga_mm_get_buffer(struct rga_mm *mm,
+ struct rga_job *job,
+ uint64_t handle,
+ uint64_t *channel_addr,
+ struct rga_internal_buffer **buf,
+ int require_size,
+ enum dma_data_direction dir)
+{
+ int ret = 0;
+ struct rga_internal_buffer *internal_buffer = NULL;
+
+ if (handle == 0) {
+ pr_err("No buffer handle can be used!\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&mm->lock);
+ *buf = rga_mm_lookup_handle(mm, handle);
+ if (*buf == NULL) {
+ pr_err("This handle[%ld] is illegal.\n", (unsigned long)handle);
+
+ mutex_unlock(&mm->lock);
+ return -EFAULT;
+ }
+
+ internal_buffer = *buf;
+ kref_get(&internal_buffer->refcount);
+
+ if (DEBUGGER_EN(MM)) {
+ pr_info("handle[%d] get info:\n", (int)handle);
+ rga_mm_dump_buffer(internal_buffer);
+ }
+
+ mutex_unlock(&mm->lock);
+
+ ret = rga_mm_get_buffer_info(job, internal_buffer, channel_addr);
+ if (ret < 0) {
+ pr_err("handle[%ld] failed to get internal buffer info!\n", (unsigned long)handle);
+ return ret;
+ }
+
+ if (internal_buffer->size < require_size) {
+ ret = -EINVAL;
+ pr_err("Only get buffer %ld byte from handle[%ld], but current required %d byte\n",
+ internal_buffer->size, (unsigned long)handle, require_size);
+
+ goto put_internal_buffer;
+ }
+
+ if (internal_buffer->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE) {
+ /*
+ * Some userspace virtual addresses do not have an
+ * interface for flushing the cache, so it is mandatory
+ * to flush the cache when the virtual address is used.
+ */
+ ret = rga_mm_sync_dma_sg_for_device(internal_buffer, job, dir);
+ if (ret < 0) {
+ pr_err("sync sgt for device error!\n");
+ goto put_internal_buffer;
+ }
+ }
+
+ return 0;
+
+put_internal_buffer:
+ mutex_lock(&mm->lock);
+ kref_put(&internal_buffer->refcount, rga_mm_kref_release_buffer);
+ mutex_unlock(&mm->lock);
+
+ return ret;
+
+}
+
+static void rga_mm_put_buffer(struct rga_mm *mm,
+ struct rga_job *job,
+ struct rga_internal_buffer *internal_buffer,
+ enum dma_data_direction dir)
+{
+ if (internal_buffer->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE && dir != DMA_NONE)
+ if (rga_mm_sync_dma_sg_for_cpu(internal_buffer, job, dir))
+ pr_err("sync sgt for cpu error!\n");
+
+ if (DEBUGGER_EN(MM)) {
+ pr_info("handle[%d] put info:\n", (int)internal_buffer->handle);
+ rga_mm_dump_buffer(internal_buffer);
+ }
+
+ mutex_lock(&mm->lock);
+ kref_put(&internal_buffer->refcount, rga_mm_kref_release_buffer);
+ mutex_unlock(&mm->lock);
+}
+
+static void rga_mm_put_channel_handle_info(struct rga_mm *mm,
+ struct rga_job *job,
+ struct rga_job_buffer *job_buf,
+ enum dma_data_direction dir)
+{
+ if (job_buf->y_addr)
+ rga_mm_put_buffer(mm, job, job_buf->y_addr, dir);
+ if (job_buf->uv_addr)
+ rga_mm_put_buffer(mm, job, job_buf->uv_addr, dir);
+ if (job_buf->v_addr)
+ rga_mm_put_buffer(mm, job, job_buf->v_addr, dir);
+
+ if (job_buf->page_table)
+ free_pages((unsigned long)job_buf->page_table, job_buf->order);
+}
+
+static int rga_mm_get_channel_handle_info(struct rga_mm *mm,
+ struct rga_job *job,
+ struct rga_img_info_t *img,
+ struct rga_job_buffer *job_buf,
+ enum dma_data_direction dir)
+{
+ int ret = 0;
+ int handle = 0;
+ int img_size, yrgb_size, uv_size, v_size;
+
+ img_size = rga_image_size_cal(img->vir_w, img->vir_h, img->format,
+ &yrgb_size, &uv_size, &v_size);
+ if (img_size <= 0) {
+ pr_err("Image size cal error! width = %d, height = %d, format = %s\n",
+ img->vir_w, img->vir_h, rga_get_format_name(img->format));
+ return -EINVAL;
+ }
+
+ /* using third-address */
+ if (img->uv_addr > 0) {
+ handle = img->yrgb_addr;
+ if (handle > 0) {
+ ret = rga_mm_get_buffer(mm, job, handle, &img->yrgb_addr,
+ &job_buf->y_addr, yrgb_size, dir);
+ if (ret < 0) {
+ pr_err("handle[%d] Can't get y/rgb address info!\n", handle);
+ return ret;
+ }
+ }
+
+ handle = img->uv_addr;
+ if (handle > 0) {
+ ret = rga_mm_get_buffer(mm, job, handle, &img->uv_addr,
+ &job_buf->uv_addr, uv_size, dir);
+ if (ret < 0) {
+ pr_err("handle[%d] Can't get uv address info!\n", handle);
+ return ret;
+ }
+ }
+
+ handle = img->v_addr;
+ if (handle > 0) {
+ ret = rga_mm_get_buffer(mm, job, handle, &img->v_addr,
+ &job_buf->v_addr, v_size, dir);
+ if (ret < 0) {
+ pr_err("handle[%d] Can't get uv address info!\n", handle);
+ return ret;
+ }
+ }
+ } else {
+ handle = img->yrgb_addr;
+ if (handle > 0) {
+ ret = rga_mm_get_buffer(mm, job, handle, &img->yrgb_addr,
+ &job_buf->addr, img_size, dir);
+ if (ret < 0) {
+ pr_err("handle[%d] Can't get y/rgb address info!\n", handle);
+ return ret;
+ }
+ }
+
+ rga_convert_addr(img, false);
+ }
+
+ if (job->scheduler->data->mmu == RGA_MMU &&
+ rga_mm_is_need_mmu(job, job_buf->addr)) {
+ ret = rga_mm_set_mmu_base(job, img, job_buf);
+ if (ret < 0) {
+ pr_err("Can't set RGA2 MMU_BASE from handle!\n");
+
+ rga_mm_put_channel_handle_info(mm, job, job_buf, dir);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int rga_mm_get_handle_info(struct rga_job *job)
+{
+ int ret = 0;
+ struct rga_req *req = NULL;
+ struct rga_mm *mm = NULL;
+ enum dma_data_direction dir;
+
+ req = &job->rga_command_base;
+ mm = rga_drvdata->mm;
+
+ switch (req->render_mode) {
+ case BITBLT_MODE:
+ case COLOR_PALETTE_MODE:
+ if (unlikely(req->src.yrgb_addr <= 0)) {
+ pr_err("render_mode[0x%x] src0 channel handle[%ld] must is valid!",
+ req->render_mode, (unsigned long)req->src.yrgb_addr);
+ return -EINVAL;
+ }
+
+ if (unlikely(req->dst.yrgb_addr <= 0)) {
+ pr_err("render_mode[0x%x] dst channel handle[%ld] must is valid!",
+ req->render_mode, (unsigned long)req->dst.yrgb_addr);
+ return -EINVAL;
+ }
+
+ if (req->bsfilter_flag) {
+ if (unlikely(req->pat.yrgb_addr <= 0)) {
+ pr_err("render_mode[0x%x] src1/pat channel handle[%ld] must is valid!",
+ req->render_mode, (unsigned long)req->pat.yrgb_addr);
+ return -EINVAL;
+ }
+ }
+
+ break;
+ case COLOR_FILL_MODE:
+ if (unlikely(req->dst.yrgb_addr <= 0)) {
+ pr_err("render_mode[0x%x] dst channel handle[%ld] must is valid!",
+ req->render_mode, (unsigned long)req->dst.yrgb_addr);
+ return -EINVAL;
+ }
+
+ break;
+
+ case UPDATE_PALETTE_TABLE_MODE:
+ case UPDATE_PATTEN_BUF_MODE:
+ if (unlikely(req->pat.yrgb_addr <= 0)) {
+ pr_err("render_mode[0x%x] lut/pat channel handle[%ld] must is valid!, req->render_mode",
+ req->render_mode, (unsigned long)req->pat.yrgb_addr);
+ return -EINVAL;
+ }
+
+ break;
+ default:
+ pr_err("%s, unknown render mode!\n", __func__);
+ break;
+ }
+
+ if (likely(req->src.yrgb_addr > 0)) {
+ ret = rga_mm_get_channel_handle_info(mm, job, &req->src,
+ &job->src_buffer,
+ DMA_TO_DEVICE);
+ if (ret < 0) {
+ pr_err("Can't get src buffer info from handle!\n");
+ return ret;
+ }
+ }
+
+ if (likely(req->dst.yrgb_addr > 0)) {
+ ret = rga_mm_get_channel_handle_info(mm, job, &req->dst,
+ &job->dst_buffer,
+ DMA_TO_DEVICE);
+ if (ret < 0) {
+ pr_err("Can't get dst buffer info from handle!\n");
+ return ret;
+ }
+ }
+
+ if (likely(req->pat.yrgb_addr > 0)) {
+
+ if (req->render_mode != UPDATE_PALETTE_TABLE_MODE) {
+ if (req->bsfilter_flag)
+ dir = DMA_BIDIRECTIONAL;
+ else
+ dir = DMA_TO_DEVICE;
+
+ ret = rga_mm_get_channel_handle_info(mm, job, &req->pat,
+ &job->src1_buffer,
+ dir);
+ } else {
+ ret = rga_mm_get_channel_handle_info(mm, job, &req->pat,
+ &job->els_buffer,
+ DMA_BIDIRECTIONAL);
+ }
+ if (ret < 0) {
+ pr_err("Can't get pat buffer info from handle!\n");
+ return ret;
+ }
+ }
+
+ rga_mm_set_mmu_flag(job);
+
+ return 0;
+}
+
+static void rga_mm_put_handle_info(struct rga_job *job)
+{
+ struct rga_mm *mm = rga_drvdata->mm;
+
+ rga_mm_put_channel_handle_info(mm, job, &job->src_buffer, DMA_NONE);
+ rga_mm_put_channel_handle_info(mm, job, &job->dst_buffer, DMA_FROM_DEVICE);
+ rga_mm_put_channel_handle_info(mm, job, &job->src1_buffer, DMA_NONE);
+ rga_mm_put_channel_handle_info(mm, job, &job->els_buffer, DMA_NONE);
+}
+
+static void rga_mm_put_channel_external_buffer(struct rga_job_buffer *job_buffer)
+{
+ if (job_buffer->ex_addr->type == RGA_DMA_BUFFER_PTR)
+ dma_buf_put((struct dma_buf *)(unsigned long)job_buffer->ex_addr->memory);
+
+ kfree(job_buffer->ex_addr);
+ job_buffer->ex_addr = NULL;
+}
+
+static int rga_mm_get_channel_external_buffer(int mmu_flag,
+ struct rga_img_info_t *img_info,
+ struct rga_job_buffer *job_buffer)
+{
+ struct dma_buf *dma_buf = NULL;
+ struct rga_external_buffer *external_buffer = NULL;
+
+ /* Default unsupported multi-planar format */
+ external_buffer = kzalloc(sizeof(*external_buffer), GFP_KERNEL);
+ if (external_buffer == NULL) {
+ pr_err("Cannot alloc job_buffer!\n");
+ return -ENOMEM;
+ }
+
+ if (img_info->yrgb_addr) {
+ dma_buf = dma_buf_get(img_info->yrgb_addr);
+ if (IS_ERR(dma_buf)) {
+ pr_err("%s dma_buf_get fail fd[%lu]\n",
+ __func__, (unsigned long)img_info->yrgb_addr);
+ kfree(external_buffer);
+ return -EINVAL;
+ }
+
+ external_buffer->memory = (unsigned long)dma_buf;
+ external_buffer->type = RGA_DMA_BUFFER_PTR;
+ } else if (mmu_flag && img_info->uv_addr) {
+ external_buffer->memory = (uint64_t)img_info->uv_addr;
+ external_buffer->type = RGA_VIRTUAL_ADDRESS;
+ } else if (img_info->uv_addr) {
+ external_buffer->memory = (uint64_t)img_info->uv_addr;
+ external_buffer->type = RGA_PHYSICAL_ADDRESS;
+ } else {
+ kfree(external_buffer);
+ return -EINVAL;
+ }
+
+ external_buffer->memory_parm.width = img_info->vir_w;
+ external_buffer->memory_parm.height = img_info->vir_h;
+ external_buffer->memory_parm.format = img_info->format;
+
+ job_buffer->ex_addr = external_buffer;
+
+ return 0;
+}
+
+static void rga_mm_put_external_buffer(struct rga_job *job)
+{
+ if (job->src_buffer.ex_addr)
+ rga_mm_put_channel_external_buffer(&job->src_buffer);
+ if (job->src1_buffer.ex_addr)
+ rga_mm_put_channel_external_buffer(&job->src1_buffer);
+ if (job->dst_buffer.ex_addr)
+ rga_mm_put_channel_external_buffer(&job->dst_buffer);
+ if (job->els_buffer.ex_addr)
+ rga_mm_put_channel_external_buffer(&job->els_buffer);
+}
+
+static int rga_mm_get_external_buffer(struct rga_job *job)
+{
+ int ret = -EINVAL;
+ int mmu_flag;
+
+ struct rga_img_info_t *src0 = NULL;
+ struct rga_img_info_t *src1 = NULL;
+ struct rga_img_info_t *dst = NULL;
+ struct rga_img_info_t *els = NULL;
+
+ if (job->rga_command_base.render_mode != COLOR_FILL_MODE)
+ src0 = &job->rga_command_base.src;
+
+ if (job->rga_command_base.render_mode != UPDATE_PALETTE_TABLE_MODE)
+ src1 = job->rga_command_base.bsfilter_flag ?
+ &job->rga_command_base.pat : NULL;
+ else
+ els = &job->rga_command_base.pat;
+
+ dst = &job->rga_command_base.dst;
+
+ if (likely(src0)) {
+ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 8) & 1);
+ ret = rga_mm_get_channel_external_buffer(mmu_flag, src0, &job->src_buffer);
+ if (ret < 0) {
+ pr_err("Cannot get src0 channel buffer!\n");
+ return ret;
+ }
+ }
+
+ if (likely(dst)) {
+ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 10) & 1);
+ ret = rga_mm_get_channel_external_buffer(mmu_flag, dst, &job->dst_buffer);
+ if (ret < 0) {
+ pr_err("Cannot get dst channel buffer!\n");
+ goto error_put_buffer;
+ }
+ }
+
+ if (src1) {
+ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 9) & 1);
+ ret = rga_mm_get_channel_external_buffer(mmu_flag, src1, &job->src1_buffer);
+ if (ret < 0) {
+ pr_err("Cannot get src1 channel buffer!\n");
+ goto error_put_buffer;
+ }
+ }
+
+ if (els) {
+ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 11) & 1);
+ ret = rga_mm_get_channel_external_buffer(mmu_flag, els, &job->els_buffer);
+ if (ret < 0) {
+ pr_err("Cannot get els channel buffer!\n");
+ goto error_put_buffer;
+ }
+ }
+
+ return 0;
+error_put_buffer:
+ rga_mm_put_external_buffer(job);
+ return ret;
+}
+
+static void rga_mm_unmap_channel_job_buffer(struct rga_job *job,
+ struct rga_job_buffer *job_buffer,
+ enum dma_data_direction dir)
+{
+ if (job_buffer->addr->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE && dir != DMA_NONE)
+ if (rga_mm_sync_dma_sg_for_cpu(job_buffer->addr, job, dir))
+ pr_err("sync sgt for cpu error!\n");
+
+ rga_mm_unmap_buffer(job_buffer->addr);
+ kfree(job_buffer->addr);
+
+ job_buffer->page_table = NULL;
+}
+
+static int rga_mm_map_channel_job_buffer(struct rga_job *job,
+ struct rga_img_info_t *img,
+ struct rga_job_buffer *job_buffer,
+ enum dma_data_direction dir,
+ int write_flag)
+{
+ int ret;
+ struct rga_internal_buffer *buffer = NULL;
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (buffer == NULL) {
+ pr_err("%s alloc internal_buffer error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = rga_mm_map_buffer(job_buffer->ex_addr, buffer, job, write_flag);
+ if (ret < 0) {
+ pr_err("job buffer map failed!\n");
+ goto error_free_buffer;
+ }
+
+ ret = rga_mm_get_buffer_info(job, buffer, &img->yrgb_addr);
+ if (ret < 0) {
+ pr_err("Failed to get internal buffer info!\n");
+ goto error_unmap_buffer;
+ }
+
+ if (buffer->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE) {
+ ret = rga_mm_sync_dma_sg_for_device(buffer, job, dir);
+ if (ret < 0) {
+ pr_err("sync sgt for device error!\n");
+ goto error_unmap_buffer;
+ }
+ }
+
+ rga_convert_addr(img, false);
+
+ job_buffer->addr = buffer;
+
+ if (job->scheduler->data->mmu == RGA_MMU &&
+ rga_mm_is_need_mmu(job, job_buffer->addr)) {
+ ret = rga_mm_set_mmu_base(job, img, job_buffer);
+ if (ret < 0) {
+ pr_err("Can't set RGA2 MMU_BASE!\n");
+ job_buffer->addr = NULL;
+ goto error_unmap_buffer;
+ }
+ }
+
+ return 0;
+
+error_unmap_buffer:
+ rga_mm_unmap_buffer(buffer);
+error_free_buffer:
+ kfree(buffer);
+
+ return ret;
+}
+
+static void rga_mm_unmap_buffer_info(struct rga_job *job)
+{
+ if (job->src_buffer.addr)
+ rga_mm_unmap_channel_job_buffer(job, &job->src_buffer, DMA_NONE);
+ if (job->dst_buffer.addr)
+ rga_mm_unmap_channel_job_buffer(job, &job->dst_buffer, DMA_FROM_DEVICE);
+ if (job->src1_buffer.addr)
+ rga_mm_unmap_channel_job_buffer(job, &job->src1_buffer, DMA_NONE);
+ if (job->els_buffer.addr)
+ rga_mm_unmap_channel_job_buffer(job, &job->els_buffer, DMA_NONE);
+
+ rga_mm_put_external_buffer(job);
+}
+
+static int rga_mm_map_buffer_info(struct rga_job *job)
+{
+ int ret = 0;
+ struct rga_req *req = NULL;
+ enum dma_data_direction dir;
+
+ ret = rga_mm_get_external_buffer(job);
+ if (ret < 0) {
+ pr_err("failed to get external buffer from job_cmd!\n");
+ return ret;
+ }
+
+ req = &job->rga_command_base;
+
+ if (likely(job->src_buffer.ex_addr)) {
+ ret = rga_mm_map_channel_job_buffer(job, &req->src,
+ &job->src_buffer,
+ DMA_TO_DEVICE, false);
+ if (ret < 0) {
+ pr_err("src channel map job buffer failed!");
+ goto error_unmap_buffer;
+ }
+ }
+
+ if (likely(job->dst_buffer.ex_addr)) {
+ ret = rga_mm_map_channel_job_buffer(job, &req->dst,
+ &job->dst_buffer,
+ DMA_TO_DEVICE, true);
+ if (ret < 0) {
+ pr_err("dst channel map job buffer failed!");
+ goto error_unmap_buffer;
+ }
+ }
+
+ if (job->src1_buffer.ex_addr) {
+ if (req->bsfilter_flag)
+ dir = DMA_BIDIRECTIONAL;
+ else
+ dir = DMA_TO_DEVICE;
+
+ ret = rga_mm_map_channel_job_buffer(job, &req->pat,
+ &job->src1_buffer,
+ dir, false);
+ if (ret < 0) {
+ pr_err("src1 channel map job buffer failed!");
+ goto error_unmap_buffer;
+ }
+ }
+
+ if (job->els_buffer.ex_addr) {
+ ret = rga_mm_map_channel_job_buffer(job, &req->pat,
+ &job->els_buffer,
+ DMA_BIDIRECTIONAL, false);
+ if (ret < 0) {
+ pr_err("els channel map job buffer failed!");
+ goto error_unmap_buffer;
+ }
+ }
+
+ rga_mm_set_mmu_flag(job);
+ return 0;
+
+error_unmap_buffer:
+ rga_mm_unmap_buffer_info(job);
+
+ return ret;
+}
+
+int rga_mm_map_job_info(struct rga_job *job)
+{
+ int ret;
+ ktime_t timestamp = ktime_get();
+
+ if (job->flags & RGA_JOB_USE_HANDLE) {
+ ret = rga_mm_get_handle_info(job);
+ if (ret < 0) {
+ pr_err("failed to get buffer from handle\n");
+ return ret;
+ }
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], get buffer_handle info cost %lld us\n",
+ job->request_id, ktime_us_delta(ktime_get(), timestamp));
+ } else {
+ ret = rga_mm_map_buffer_info(job);
+ if (ret < 0) {
+ pr_err("failed to map buffer\n");
+ return ret;
+ }
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], map buffer cost %lld us\n",
+ job->request_id, ktime_us_delta(ktime_get(), timestamp));
+ }
+
+ return 0;
+}
+
+void rga_mm_unmap_job_info(struct rga_job *job)
+{
+ ktime_t timestamp = ktime_get();
+
+ if (job->flags & RGA_JOB_USE_HANDLE) {
+ rga_mm_put_handle_info(job);
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], put buffer_handle info cost %lld us\n",
+ job->request_id, ktime_us_delta(ktime_get(), timestamp));
+ } else {
+ rga_mm_unmap_buffer_info(job);
+
+ if (DEBUGGER_EN(TIME))
+ pr_info("request[%d], unmap buffer cost %lld us\n",
+ job->request_id, ktime_us_delta(ktime_get(), timestamp));
+ }
+}
+
+/*
+ * rga_mm_import_buffer - Importing external buffer into the RGA driver
+ *
+ * @external_buffer: [in] Parameters of external buffer
+ * @session: [in] Session of the current process
+ *
+ * returns:
+ * if return value > 0, the buffer import is successful and is the generated
+ * buffer-handle, negative error code on failure.
+ */
+int rga_mm_import_buffer(struct rga_external_buffer *external_buffer,
+ struct rga_session *session)
+{
+ int ret = 0, new_id;
+ struct rga_mm *mm;
+ struct rga_internal_buffer *internal_buffer;
+
+ mm = rga_drvdata->mm;
+ if (mm == NULL) {
+ pr_err("rga mm is null!\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&mm->lock);
+
+ /* first, Check whether to rga_mm */
+ internal_buffer = rga_mm_lookup_external(mm, external_buffer, current->mm);
+ if (!IS_ERR_OR_NULL(internal_buffer)) {
+ kref_get(&internal_buffer->refcount);
+
+ mutex_unlock(&mm->lock);
+
+ if (DEBUGGER_EN(MM)) {
+ pr_info("import existing buffer:\n");
+ rga_mm_dump_buffer(internal_buffer);
+ }
+
+ return internal_buffer->handle;
+ }
+
+ /* finally, map and cached external_buffer in rga_mm */
+ internal_buffer = kzalloc(sizeof(struct rga_internal_buffer), GFP_KERNEL);
+ if (internal_buffer == NULL) {
+ pr_err("%s alloc internal_buffer error!\n", __func__);
+
+ mutex_unlock(&mm->lock);
+ return -ENOMEM;
+ }
+
+ ret = rga_mm_map_buffer(external_buffer, internal_buffer, NULL, true);
+ if (ret < 0)
+ goto FREE_INTERNAL_BUFFER;
+
+ kref_init(&internal_buffer->refcount);
+ internal_buffer->session = session;
+
+ /*
+ * Get the user-visible handle using idr. Preload and perform
+ * allocation under our spinlock.
+ */
+ idr_preload(GFP_KERNEL);
+ new_id = idr_alloc_cyclic(&mm->memory_idr, internal_buffer, 1, 0, GFP_NOWAIT);
+ idr_preload_end();
+ if (new_id < 0) {
+ pr_err("internal_buffer alloc id failed!\n");
+ ret = new_id;
+ goto FREE_INTERNAL_BUFFER;
+ }
+
+ internal_buffer->handle = new_id;
+ mm->buffer_count++;
+
+ if (DEBUGGER_EN(MM)) {
+ pr_info("import buffer:\n");
+ rga_mm_dump_buffer(internal_buffer);
+ }
+
+ mutex_unlock(&mm->lock);
+ return internal_buffer->handle;
+
+FREE_INTERNAL_BUFFER:
+ mutex_unlock(&mm->lock);
+ kfree(internal_buffer);
+
+ return ret;
+}
+
+int rga_mm_release_buffer(uint32_t handle)
+{
+ struct rga_mm *mm;
+ struct rga_internal_buffer *internal_buffer;
+
+ mm = rga_drvdata->mm;
+ if (mm == NULL) {
+ pr_err("rga mm is null!\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&mm->lock);
+
+ /* Find the buffer that has been imported */
+ internal_buffer = rga_mm_lookup_handle(mm, handle);
+ if (IS_ERR_OR_NULL(internal_buffer)) {
+ pr_err("This is not a buffer that has been imported, handle = %d\n", (int)handle);
+
+ mutex_unlock(&mm->lock);
+ return -ENOENT;
+ }
+
+ if (DEBUGGER_EN(MM)) {
+ pr_info("release buffer:\n");
+ rga_mm_dump_buffer(internal_buffer);
+ }
+
+ kref_put(&internal_buffer->refcount, rga_mm_kref_release_buffer);
+
+ mutex_unlock(&mm->lock);
+ return 0;
+}
+
+int rga_mm_session_release_buffer(struct rga_session *session)
+{
+ int i;
+ struct rga_mm *mm;
+ struct rga_internal_buffer *buffer;
+
+ mm = rga_drvdata->mm;
+ if (mm == NULL) {
+ pr_err("rga mm is null!\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&mm->lock);
+
+ idr_for_each_entry(&mm->memory_idr, buffer, i) {
+ if (session == buffer->session) {
+ pr_err("[tgid:%d] Destroy handle[%d] when the user exits\n",
+ session->tgid, buffer->handle);
+ rga_mm_buffer_destroy(buffer);
+ }
+ }
+
+ mutex_unlock(&mm->lock);
+ return 0;
+}
+
+int rga_mm_init(struct rga_mm **mm_session)
+{
+ struct rga_mm *mm = NULL;
+
+ *mm_session = kzalloc(sizeof(struct rga_mm), GFP_KERNEL);
+ if (*mm_session == NULL) {
+ pr_err("can not kzalloc for rga buffer mm_session\n");
+ return -ENOMEM;
+ }
+
+ mm = *mm_session;
+
+ mutex_init(&mm->lock);
+ idr_init_base(&mm->memory_idr, 1);
+
+ return 0;
+}
+
+int rga_mm_remove(struct rga_mm **mm_session)
+{
+ struct rga_mm *mm = *mm_session;
+
+ mutex_lock(&mm->lock);
+
+ idr_for_each(&mm->memory_idr, &rga_mm_handle_remove, mm);
+ idr_destroy(&mm->memory_idr);
+
+ mutex_unlock(&mm->lock);
+
+ kfree(*mm_session);
+ *mm_session = NULL;
+
+ return 0;
+}
diff --git a/drivers/video/rockchip/rga3/rga_policy.c b/drivers/video/rockchip/rga3/rga_policy.c
new file mode 100644
index 000000000..c87ce1881
--- /dev/null
+++ b/drivers/video/rockchip/rga3/rga_policy.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Author: Huang Lee <Putin.li@rock-chips.com>
+ */
+
+#define pr_fmt(fmt) "rga_policy: " fmt
+
+#include "rga_job.h"
+#include "rga_common.h"
+#include "rga_hw_config.h"
+#include "rga_debugger.h"
+
+#define GET_GCD(n1, n2) \
+ ({ \
+ int i; \
+ int gcd = 1; \
+ for (i = 1; i <= (n1) && i <= (n2); i++) { \
+ if ((n1) % i == 0 && (n2) % i == 0) \
+ gcd = i; \
+ } \
+ gcd; \
+ })
+#define GET_LCM(n1, n2, gcd) (((n1) * (n2)) / gcd)
+
+static int rga_set_feature(struct rga_req *rga_base)
+{
+ int feature = 0;
+
+ if (rga_base->render_mode == COLOR_FILL_MODE)
+ feature |= RGA_COLOR_FILL;
+
+ if (rga_base->render_mode == COLOR_PALETTE_MODE)
+ feature |= RGA_COLOR_PALETTE;
+
+ if (rga_base->color_key_max > 0 || rga_base->color_key_min > 0)
+ feature |= RGA_COLOR_KEY;
+
+ if ((rga_base->alpha_rop_flag >> 1) & 1)
+ feature |= RGA_ROP_CALCULATE;
+
+ if ((rga_base->alpha_rop_flag >> 8) & 1)
+ feature |= RGA_NN_QUANTIZE;
+
+ return feature;
+}
+
+static bool rga_check_csc_constant(const struct rga_hw_data *data, struct rga_req *rga_base,
+ uint32_t mode, uint32_t flag)
+{
+ if (mode & flag)
+ return true;
+
+ if ((rga_base->full_csc.flag & 0x1) && (data->feature & RGA_FULL_CSC))
+ return true;
+
+ return false;
+}
+
+static bool rga_check_csc(const struct rga_hw_data *data, struct rga_req *rga_base)
+{
+ switch (rga_base->yuv2rgb_mode) {
+ case 0x1:
+ return rga_check_csc_constant(data, rga_base,
+ data->csc_y2r_mode, RGA_MODE_CSC_BT601L);
+ case 0x2:
+ return rga_check_csc_constant(data, rga_base,
+ data->csc_y2r_mode, RGA_MODE_CSC_BT601F);
+ case 0x3:
+ return rga_check_csc_constant(data, rga_base,
+ data->csc_y2r_mode, RGA_MODE_CSC_BT709);
+ case 0x1 << 2:
+ return rga_check_csc_constant(data, rga_base,
+ data->csc_r2y_mode, RGA_MODE_CSC_BT601F);
+ case 0x2 << 2:
+ return rga_check_csc_constant(data, rga_base,
+ data->csc_r2y_mode, RGA_MODE_CSC_BT601L);
+ case 0x3 << 2:
+ return rga_check_csc_constant(data, rga_base,
+ data->csc_r2y_mode, RGA_MODE_CSC_BT709);
+ default:
+ break;
+ }
+
+ if ((rga_base->full_csc.flag & 0x1)) {
+ if (data->feature & RGA_FULL_CSC)
+ return true;
+ else
+ return false;
+ }
+
+ return true;
+}
+
+static bool rga_check_resolution(const struct rga_rect_range *range, int width, int height)
+{
+ if (width > range->max.width || height > range->max.height)
+ return false;
+
+ if (width < range->min.width || height < range->min.height)
+ return false;
+
+ return true;
+}
+
+static bool rga_check_format(const struct rga_hw_data *data,
+ int rd_mode, int format, int win_num)
+{
+ int i;
+ const uint32_t *formats;
+ uint32_t format_count;
+
+ switch (rd_mode) {
+ case RGA_RASTER_MODE:
+ formats = data->win[win_num].formats[RGA_RASTER_INDEX];
+ format_count = data->win[win_num].formats_count[RGA_RASTER_INDEX];
+ break;
+ case RGA_FBC_MODE:
+ formats = data->win[win_num].formats[RGA_AFBC16x16_INDEX];
+ format_count = data->win[win_num].formats_count[RGA_AFBC16x16_INDEX];
+ break;
+ case RGA_TILE_MODE:
+ formats = data->win[win_num].formats[RGA_TILE8x8_INDEX];
+ format_count = data->win[win_num].formats_count[RGA_TILE8x8_INDEX];
+ break;
+ default:
+ return false;
+ }
+
+ if (formats == NULL || format_count == 0)
+ return false;
+
+ for (i = 0; i < format_count; i++)
+ if (format == formats[i])
+ return true;
+
+ return false;
+}
+
+static bool rga_check_align(uint32_t byte_stride_align, uint32_t format, uint16_t w_stride)
+{
+ int bit_stride, pixel_stride, align, gcd;
+
+ pixel_stride = rga_get_pixel_stride_from_format(format);
+ if (pixel_stride <= 0)
+ return false;
+
+ bit_stride = pixel_stride * w_stride;
+
+ if (bit_stride % (byte_stride_align * 8) == 0)
+ return true;
+
+ if (DEBUGGER_EN(MSG)) {
+ gcd = GET_GCD(pixel_stride, byte_stride_align * 8);
+ align = GET_LCM(pixel_stride, byte_stride_align * 8, gcd) / pixel_stride;
+ pr_info("unsupported width stride %d, 0x%x should be %d aligned!",
+ w_stride, format, align);
+ }
+
+ return false;
+}
+
+static bool rga_check_src0(const struct rga_hw_data *data,
+ struct rga_img_info_t *src0)
+{
+ if (!rga_check_resolution(&data->input_range, src0->act_w, src0->act_h))
+ return false;
+
+ if (data == &rga3_data &&
+ !rga_check_resolution(&data->input_range,
+ src0->act_w + src0->x_offset,
+ src0->act_h + src0->y_offset))
+ return false;
+
+ if (!rga_check_format(data, src0->rd_mode, src0->format, 0))
+ return false;
+
+ if (!rga_check_align(data->byte_stride_align, src0->format, src0->vir_w))
+ return false;
+
+ return true;
+}
+
+static bool rga_check_src1(const struct rga_hw_data *data,
+ struct rga_img_info_t *src1)
+{
+ if (!rga_check_resolution(&data->input_range, src1->act_w, src1->act_h))
+ return false;
+
+ if (data == &rga3_data &&
+ !rga_check_resolution(&data->input_range,
+ src1->act_w + src1->x_offset,
+ src1->act_h + src1->y_offset))
+ return false;
+
+ if (!rga_check_format(data, src1->rd_mode, src1->format, 1))
+ return false;
+
+ if (!rga_check_align(data->byte_stride_align, src1->format, src1->vir_w))
+ return false;
+
+ return true;
+}
+
+static bool rga_check_dst(const struct rga_hw_data *data,
+ struct rga_img_info_t *dst)
+{
+ if (!rga_check_resolution(&data->output_range, dst->act_w, dst->act_h))
+ return false;
+
+ if (data == &rga3_data &&
+ !rga_check_resolution(&data->output_range,
+ dst->act_w + dst->x_offset,
+ dst->act_h + dst->y_offset))
+ return false;
+
+ if (!rga_check_format(data, dst->rd_mode, dst->format, 2))
+ return false;
+
+ if (!rga_check_align(data->byte_stride_align, dst->format, dst->vir_w))
+ return false;
+
+ return true;
+}
+
+static bool rga_check_scale(const struct rga_hw_data *data,
+ struct rga_req *rga_base)
+{
+ struct rga_img_info_t *src0 = &rga_base->src;
+ struct rga_img_info_t *dst = &rga_base->dst;
+
+ int sw, sh;
+ int dw, dh;
+
+ sw = src0->act_w;
+ sh = src0->act_h;
+
+ if ((rga_base->sina == 65536 && rga_base->cosa == 0)
+ || (rga_base->sina == -65536 && rga_base->cosa == 0)) {
+ dw = dst->act_h;
+ dh = dst->act_w;
+ } else {
+ dw = dst->act_w;
+ dh = dst->act_h;
+ }
+
+ if (sw > dw) {
+ if ((sw >> data->max_downscale_factor) > dw)
+ return false;
+ } else if (sw < dw) {
+ if ((sw << data->max_upscale_factor) < dw)
+ return false;
+ }
+
+ if (sh > dh) {
+ if ((sh >> data->max_downscale_factor) > dh)
+ return false;
+ } else if (sh < dh) {
+ if ((sh << data->max_upscale_factor) < dh)
+ return false;
+ }
+
+ return true;
+}
+
+int rga_job_assign(struct rga_job *job)
+{
+ struct rga_img_info_t *src0 = &job->rga_command_base.src;
+ struct rga_img_info_t *src1 = &job->rga_command_base.pat;
+ struct rga_img_info_t *dst = &job->rga_command_base.dst;
+
+ struct rga_req *rga_base = &job->rga_command_base;
+ const struct rga_hw_data *data;
+ struct rga_scheduler_t *scheduler = NULL;
+
+ int feature;
+ int core = RGA_NONE_CORE;
+ int optional_cores = RGA_NONE_CORE;
+ int specified_cores = RGA_NONE_CORE;
+ int i;
+ int min_of_job_count = -1;
+ unsigned long flags;
+
+ /* assigned by userspace */
+ if (rga_base->core > RGA_NONE_CORE) {
+ if (rga_base->core > RGA_CORE_MASK) {
+ pr_err("invalid setting core by user\n");
+ goto finish;
+ } else if (rga_base->core & RGA_CORE_MASK)
+ specified_cores = rga_base->core;
+ }
+
+ feature = rga_set_feature(rga_base);
+
+ /* function */
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ data = rga_drvdata->scheduler[i]->data;
+ scheduler = rga_drvdata->scheduler[i];
+
+ if ((specified_cores != RGA_NONE_CORE) &&
+ (!(scheduler->core & specified_cores)))
+ continue;
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("start policy on core = %d", scheduler->core);
+
+ if (scheduler->data->mmu == RGA_MMU &&
+ job->flags & RGA_JOB_UNSUPPORT_RGA_MMU) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("RGA2 only support under 4G memory!\n");
+ continue;
+ }
+
+ if (feature > 0) {
+ if (!(feature & data->feature)) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, break on feature",
+ scheduler->core);
+ continue;
+ }
+ }
+
+ /* only colorfill need single win (colorpalette?) */
+ if (!(feature & 1)) {
+ if (src1->yrgb_addr > 0) {
+ if ((!(src0->rd_mode & data->win[0].rd_mode)) ||
+ (!(src1->rd_mode & data->win[1].rd_mode)) ||
+ (!(dst->rd_mode & data->win[2].rd_mode))) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, ABC break on rd_mode",
+ scheduler->core);
+ continue;
+ }
+ } else {
+ if ((!(src0->rd_mode & data->win[0].rd_mode)) ||
+ (!(dst->rd_mode & data->win[2].rd_mode))) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, ABB break on rd_mode",
+ scheduler->core);
+ continue;
+ }
+ }
+
+ if (!rga_check_scale(data, rga_base)) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, break on rga_check_scale",
+ scheduler->core);
+ continue;
+ }
+
+ if (!rga_check_src0(data, src0)) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, break on rga_check_src0",
+ scheduler->core);
+ continue;
+ }
+
+ if (src1->yrgb_addr > 0) {
+ if (!rga_check_src1(data, src1)) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, break on rga_check_src1",
+ scheduler->core);
+ continue;
+ }
+ }
+ }
+
+ if (!rga_check_dst(data, dst)) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, break on rga_check_dst",
+ scheduler->core);
+ continue;
+ }
+
+ if (!rga_check_csc(data, rga_base)) {
+ if (DEBUGGER_EN(MSG))
+ pr_info("core = %d, break on rga_check_csc",
+ scheduler->core);
+ continue;
+ }
+
+ optional_cores |= scheduler->core;
+ }
+
+ if (DEBUGGER_EN(MSG))
+ pr_info("optional_cores = %d\n", optional_cores);
+
+ if (optional_cores == 0) {
+ core = -1;
+ pr_err("invalid function policy\n");
+ goto finish;
+ }
+
+ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
+ scheduler = rga_drvdata->scheduler[i];
+
+ if (optional_cores & scheduler->core) {
+ spin_lock_irqsave(&scheduler->irq_lock, flags);
+
+ if (scheduler->running_job == NULL) {
+ core = scheduler->core;
+ job->scheduler = scheduler;
+ spin_unlock_irqrestore(&scheduler->irq_lock,
+ flags);
+ break;
+ } else {
+ if ((min_of_job_count == -1) ||
+ (min_of_job_count > scheduler->job_count)) {
+ min_of_job_count = scheduler->job_count;
+ core = scheduler->core;
+ job->scheduler = scheduler;
+ }
+ }
+
+ spin_unlock_irqrestore(&scheduler->irq_lock, flags);
+ }
+ }
+
+ /* TODO: need consider full load */
+finish:
+ if (DEBUGGER_EN(MSG))
+ pr_info("assign core: %d\n", core);
+
+ return core;
+}