- 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
17109 lines
465 KiB
Diff
17109 lines
465 KiB
Diff
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 split,need to redesign
|
||
+ * this judge, which consider RGBA8888 format
|
||
+ */
|
||
+ reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN)) |
|
||
+ (s_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN(config->enable)));
|
||
+
|
||
+ *bRGA_OVERLAP_CTRL = reg;
|
||
+
|
||
+ *bRGA3_OVLP_OFF = msg->wr.x_offset | (msg->wr.y_offset << 16);
|
||
+}
|
||
+
|
||
+static int rga3_gen_reg_info(u8 *base, struct rga3_req *msg)
|
||
+{
|
||
+ switch (msg->render_mode) {
|
||
+ case BITBLT_MODE:
|
||
+ RGA3_set_reg_win0_info(base, msg);
|
||
+ RGA3_set_reg_win1_info(base, msg);
|
||
+ RGA3_set_reg_overlap_info(base, msg);
|
||
+ RGA3_set_reg_wr_info(base, msg);
|
||
+ break;
|
||
+ default:
|
||
+ 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;
|
||
+}
|