From 9f95b5fc62bf526b03fc5cb2b2f6ffb50b6e0575 Mon Sep 17 00:00:00 2001 From: Li Huang Date: Tue, 25 Jan 2022 15:19:16 +0800 Subject: [PATCH] video: rockchip: rga3: Init multi rga Signed-off-by: Li Huang Change-Id: Ib19d2d141e6b0eefa9d67b062e564559f58fb0b4 --- drivers/video/rockchip/Kconfig | 1 + drivers/video/rockchip/Makefile | 1 + drivers/video/rockchip/rga3/Kconfig | 30 + drivers/video/rockchip/rga3/Makefile | 8 + drivers/video/rockchip/rga3/include/rga.h | 673 +++++ .../rockchip/rga3/include/rga2_mmu_info.h | 45 + .../rockchip/rga3/include/rga2_reg_info.h | 332 +++ .../rockchip/rga3/include/rga3_reg_info.h | 450 +++ .../video/rockchip/rga3/include/rga_common.h | 18 + .../rockchip/rga3/include/rga_debugger.h | 133 + .../video/rockchip/rga3/include/rga_dma_buf.h | 34 + drivers/video/rockchip/rga3/include/rga_drv.h | 379 +++ .../video/rockchip/rga3/include/rga_fence.h | 28 + .../rockchip/rga3/include/rga_hw_config.h | 56 + drivers/video/rockchip/rga3/include/rga_job.h | 40 + drivers/video/rockchip/rga3/include/rga_mm.h | 52 + drivers/video/rockchip/rga3/rga2_mmu_info.c | 1266 +++++++++ drivers/video/rockchip/rga3/rga2_reg_info.c | 2517 +++++++++++++++++ drivers/video/rockchip/rga3/rga3_reg_info.c | 2126 ++++++++++++++ drivers/video/rockchip/rga3/rga_common.c | 262 ++ drivers/video/rockchip/rga3/rga_debugger.c | 572 ++++ drivers/video/rockchip/rga3/rga_dma_buf.c | 1199 ++++++++ drivers/video/rockchip/rga3/rga_drv.c | 1039 +++++++ drivers/video/rockchip/rga3/rga_fence.c | 136 + drivers/video/rockchip/rga3/rga_hw_config.c | 229 ++ drivers/video/rockchip/rga3/rga_job.c | 745 +++++ drivers/video/rockchip/rga3/rga_mm.c | 1135 ++++++++ drivers/video/rockchip/rga3/rga_policy.c | 319 +++ 28 files changed, 13825 insertions(+) create mode 100644 drivers/video/rockchip/rga3/Kconfig create mode 100644 drivers/video/rockchip/rga3/Makefile create mode 100644 drivers/video/rockchip/rga3/include/rga.h create mode 100644 drivers/video/rockchip/rga3/include/rga2_mmu_info.h create mode 100644 drivers/video/rockchip/rga3/include/rga2_reg_info.h create mode 100644 drivers/video/rockchip/rga3/include/rga3_reg_info.h create mode 100644 drivers/video/rockchip/rga3/include/rga_common.h create mode 100644 drivers/video/rockchip/rga3/include/rga_debugger.h create mode 100644 drivers/video/rockchip/rga3/include/rga_dma_buf.h create mode 100644 drivers/video/rockchip/rga3/include/rga_drv.h create mode 100644 drivers/video/rockchip/rga3/include/rga_fence.h create mode 100644 drivers/video/rockchip/rga3/include/rga_hw_config.h create mode 100644 drivers/video/rockchip/rga3/include/rga_job.h create mode 100644 drivers/video/rockchip/rga3/include/rga_mm.h create mode 100644 drivers/video/rockchip/rga3/rga2_mmu_info.c create mode 100644 drivers/video/rockchip/rga3/rga2_reg_info.c create mode 100644 drivers/video/rockchip/rga3/rga3_reg_info.c create mode 100644 drivers/video/rockchip/rga3/rga_common.c create mode 100644 drivers/video/rockchip/rga3/rga_debugger.c create mode 100644 drivers/video/rockchip/rga3/rga_dma_buf.c create mode 100644 drivers/video/rockchip/rga3/rga_drv.c create mode 100644 drivers/video/rockchip/rga3/rga_fence.c create mode 100644 drivers/video/rockchip/rga3/rga_hw_config.c create mode 100644 drivers/video/rockchip/rga3/rga_job.c create mode 100644 drivers/video/rockchip/rga3/rga_mm.c create mode 100644 drivers/video/rockchip/rga3/rga_policy.c diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 790f1f4227c1..e8f18642e999 100644 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 source "drivers/video/rockchip/rga/Kconfig" source "drivers/video/rockchip/rga2/Kconfig" +source "drivers/video/rockchip/rga3/Kconfig" source "drivers/video/rockchip/iep/Kconfig" source "drivers/video/rockchip/mpp/Kconfig" diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index e01d878568aa..6305e2326ef3 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_ROCKCHIP_RGA) += rga/ obj-$(CONFIG_ROCKCHIP_RGA2) += rga2/ +obj-$(CONFIG_ROCKCHIP_MULTI_RGA) += rga3/ obj-$(CONFIG_IEP) += iep/ obj-$(CONFIG_ROCKCHIP_MPP_SERVICE) += mpp/ diff --git a/drivers/video/rockchip/rga3/Kconfig b/drivers/video/rockchip/rga3/Kconfig new file mode 100644 index 000000000000..6c40b9b03a91 --- /dev/null +++ b/drivers/video/rockchip/rga3/Kconfig @@ -0,0 +1,30 @@ +# 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_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 000000000000..16bcf4f88b36 --- /dev/null +++ b/drivers/video/rockchip/rga3/Makefile @@ -0,0 +1,8 @@ +# 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_dma_buf.o rga_fence.o rga_job.o rga_hw_config.o rga2_reg_info.o rga2_mmu_info.o rga_policy.o rga_mm.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 000000000000..27e8eb446f30 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga.h @@ -0,0 +1,673 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _RGA_DRIVER_H_ +#define _RGA_DRIVER_H_ + +#include +#include + +/* 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_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_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 +}; + +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, +}; + +/* 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, +}; + +/* 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, +}; + +enum { + RGA2_FORMAT_RGBA_8888 = 0x0, + RGA2_FORMAT_RGBX_8888 = 0x1, + RGA2_FORMAT_RGB_888 = 0x2, + RGA2_FORMAT_BGRA_8888 = 0x3, + RGA2_FORMAT_BGRX_8888 = 0x4, + RGA2_FORMAT_BGR_888 = 0x5, + RGA2_FORMAT_RGB_565 = 0x6, + RGA2_FORMAT_RGBA_5551 = 0x7, + RGA2_FORMAT_RGBA_4444 = 0x8, + RGA2_FORMAT_BGR_565 = 0x9, + RGA2_FORMAT_BGRA_5551 = 0xa, + RGA2_FORMAT_BGRA_4444 = 0xb, + + RGA2_FORMAT_Y4 = 0xe, + RGA2_FORMAT_YCbCr_400 = 0xf, + + RGA2_FORMAT_YCbCr_422_SP = 0x10, + RGA2_FORMAT_YCbCr_422_P = 0x11, + RGA2_FORMAT_YCbCr_420_SP = 0x12, + RGA2_FORMAT_YCbCr_420_P = 0x13, + RGA2_FORMAT_YCrCb_422_SP = 0x14, + RGA2_FORMAT_YCrCb_422_P = 0x15, + RGA2_FORMAT_YCrCb_420_SP = 0x16, + RGA2_FORMAT_YCrCb_420_P = 0x17, + + RGA2_FORMAT_YVYU_422 = 0x18, + RGA2_FORMAT_YVYU_420 = 0x19, + RGA2_FORMAT_VYUY_422 = 0x1a, + RGA2_FORMAT_VYUY_420 = 0x1b, + RGA2_FORMAT_YUYV_422 = 0x1c, + RGA2_FORMAT_YUYV_420 = 0x1d, + RGA2_FORMAT_UYVY_422 = 0x1e, + RGA2_FORMAT_UYVY_420 = 0x1f, + + RGA2_FORMAT_YCbCr_420_SP_10B = 0x20, + RGA2_FORMAT_YCrCb_420_SP_10B = 0x21, + RGA2_FORMAT_YCbCr_422_SP_10B = 0x22, + RGA2_FORMAT_YCrCb_422_SP_10B = 0x23, + + RGA2_FORMAT_BPP_1 = 0x24, + RGA2_FORMAT_BPP_2 = 0x25, + RGA2_FORMAT_BPP_4 = 0x26, + RGA2_FORMAT_BPP_8 = 0x27, + + RGA2_FORMAT_ARGB_8888 = 0x28, + RGA2_FORMAT_XRGB_8888 = 0x29, + RGA2_FORMAT_ARGB_5551 = 0x2a, + RGA2_FORMAT_ARGB_4444 = 0x2b, + RGA2_FORMAT_ABGR_8888 = 0x2c, + RGA2_FORMAT_XBGR_8888 = 0x2d, + RGA2_FORMAT_ABGR_5551 = 0x2e, + RGA2_FORMAT_ABGR_4444 = 0x2f, +}; + +#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; +}; + +struct rga_external_buffer { + uint64_t memory; + uint32_t type; + + uint32_t handle; + struct rga_memory_parm memory_parm; + + uint8_t reserve[256]; +}; + +struct rga_buffer_pool { + struct rga_external_buffer __user *buffers; + 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_t { + int16_t r_v; + int16_t g_y; + int16_t b_u; + int32_t off; +}; + +struct rga_full_csc_t { + uint8_t flag; + struct rga_csc_coe_t coe_y; + struct rga_csc_coe_t coe_u; + struct rga_csc_coe_t coe_v; +}; + +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 is_10b_compact; + uint16_t is_10b_endian; + + uint16_t enable; +}; + +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; + + /* 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_t full_csc; + + int32_t in_fence_fd; + uint8_t core; + uint8_t priority; + int32_t out_fence_fd; + + uint8_t handle_flag; + + uint8_t reservr[127]; +}; + +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; + + /* [0] SrcAlphaMode0 */ + /* [2:1] SrcGlobalAlphaMode0 */ + /* [3] SrcAlphaSelectMode0 */ + /* [6:4] SrcFactorMode0 */ + /* [7] SrcColorMode */ + + /* [8] DstAlphaMode0 */ + /* [10:9] DstGlobalAlphaMode0 */ + /* [11] DstAlphaSelectMode0 */ + /* [14:12] DstFactorMode0 */ + /* [15] DstColorMode0 */ + u16 alpha_mode_0; + + /* [0] SrcAlphaMode1 */ + /* [2:1] SrcGlobalAlphaMode1 */ + /* [3] SrcAlphaSelectMode1 */ + /* [6:4] SrcFactorMode1 */ + + /* [8] DstAlphaMode1 */ + /* [10:9] DstGlobalAlphaMode1 */ + /* [11] DstAlphaSelectMode1 */ + /* [14:12] DstFactorMode1 */ + u16 alpha_mode_1; + + /* 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; + + /* [1:0] src0 csc mode */ + /* [3:2] dst csc mode */ + /* [4] dst csc clip enable */ + /* [6:5] src1 csc mdoe */ + /* [7] src1 csc clip enable */ + /* full color space convert */ + struct rga_full_csc_t full_csc; + + /* 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; +}; + +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; + + u16 alpha_mode_0; + u16 alpha_mode_1; + + 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_mpi_job_t { + struct dma_buf *dma_buf_src0; + struct dma_buf *dma_buf_src1; + struct dma_buf *dma_buf_dst; +}; + +int rga_mpi_commit(struct rga_req *cmd, struct rga_mpi_job_t *mpi_job); + +#endif /*_RGA_DRIVER_H_*/ diff --git a/drivers/video/rockchip/rga3/include/rga2_mmu_info.h b/drivers/video/rockchip/rga3/include/rga2_mmu_info.h new file mode 100644 index 000000000000..816caa0f5302 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga2_mmu_info.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __RGA_MMU_INFO_H__ +#define __RGA_MMU_INFO_H__ + +#include "rga_drv.h" + +/* + * 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) + +enum { + MMU_MAP_CLEAN = 1 << 0, + MMU_MAP_INVALID = 1 << 1, + MMU_MAP_MASK = 0x03, + MMU_UNMAP_CLEAN = 1 << 2, + MMU_UNMAP_INVALID = 1 << 3, + MMU_UNMAP_MASK = 0x0c, +}; + +struct rga2_mmu_info_t { + int32_t front; + int32_t back; + int32_t size; + int32_t curr; + unsigned int *buf; + unsigned int *buf_virtual; + + struct page **pages; + + u8 buf_order; + u8 pages_order; +}; + +void rga2_dma_flush_cache_for_virtual_address(struct rga2_mmu_other_t *reg, + struct rga_scheduler_t *scheduler); + +int rga2_set_mmu_reg_info(struct rga2_mmu_other_t *reg, + struct rga2_req *req, struct rga_job *job); + +#endif + 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 000000000000..be55b883c510 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga2_reg_info.h @@ -0,0 +1,332 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __REG2_INFO_H__ +#define __REG2_INFO_H__ + +#include "rga_drv.h" + +/* General Registers */ +#define RGA2_SYS_CTRL 0x000 +#define RGA2_CMD_CTRL 0x004 +#define RGA2_CMD_BASE 0x008 +#define RGA2_STATUS 0x00c +#define RGA2_INT 0x010 +#define RGA2_MMU_CTRL0 0x018 +#define RGA2_MMU_CMD_BASE 0x01c +#define RGA2_VERSION_NUM 0x028 + +/* Full Csc Coefficient */ +#define RGA2_CSC_COE_BASE 0x60 + +#define rRGA_SYS_CTRL \ + (*(volatile u32 *)(RGA2_BASE + RGA2_SYS_CTRL_OFFSET)) +#define rRGA_CMD_CTRL \ + (*(volatile u32 *)(RGA2_BASE + RGA2_CMD_CTRL_OFFSET)) +#define rRGA_CMD_BASE \ + (*(volatile u32 *)(RGA2_BASE + RGA2_CMD_BASE_OFFSET)) +#define rRGA_STATUS \ + (*(volatile u32 *)(RGA2_BASE + RGA2_STATUS_OFFSET)) +#define rRGA_INT \ + (*(volatile u32 *)(RGA2_BASE + RGA2_INT_OFFSET)) +#define rRGA_MMU_CTRL0 \ + (*(volatile u32 *)(RGA2_BASE + RGA2_MMU_CTRL0_OFFSET)) +#define rRGA_MMU_CMD_BASE \ + (*(volatile u32 *)(RGA2_BASE + RGA2_MMU_CMD_BASE_OFFSET)) +#define rRGA_CMD_ADDR \ + (*(volatile u32 *)(RGA2_BASE + RGA2_CMD_ADDR)) + +/* RGA_INT */ +#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 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_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 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) + +/* 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_ENDAIN (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) + + +/* 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_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_SRC1_CSC_MODE (0x3<<20) +#define m_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE (0x1<<22) + +#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_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_SRC1_CSC_MODE(x) ((x&0x3)<<20) +#define s_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE(x) ((x&0x1)<<22) + + +/* 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_SYS_CTRL_OFFSET 0x0 +#define RGA2_CMD_CTRL_OFFSET 0x4 +#define RGA2_CMD_BASE_OFFSET 0x8 +#define RGA2_STATUS_OFFSET 0xc +#define RGA2_INT_OFFSET 0x10 +#define RGA2_MMU_CTRL0_OFFSET 0x14 +#define RGA2_MMU_CMD_BASE_OFFSET 0x18 + +/* dst full csc */ +#define RGA2_DST_CSC_00_OFFSET 0x0 +#define RGA2_DST_CSC_01_OFFSET 0x4 +#define RGA2_DST_CSC_02_OFFSET 0x8 +#define RGA2_DST_CSC_OFF0_OFFSET 0xc +#define RGA2_DST_CSC_10_OFFSET 0x10 +#define RGA2_DST_CSC_11_OFFSET 0x14 +#define RGA2_DST_CSC_12_OFFSET 0x18 +#define RGA2_DST_CSC_OFF1_OFFSET 0x1c +#define RGA2_DST_CSC_20_OFFSET 0x20 +#define RGA2_DST_CSC_21_OFFSET 0x24 +#define RGA2_DST_CSC_22_OFFSET 0x28 +#define RGA2_DST_CSC_OFF2_OFFSET 0x2c + +#define RGA2_MODE_CTRL_OFFSET 0x00 +#define RGA2_SRC_INFO_OFFSET 0x04 +#define RGA2_SRC_BASE0_OFFSET 0x08 +#define RGA2_SRC_BASE1_OFFSET 0x0c +#define RGA2_SRC_BASE2_OFFSET 0x10 +#define RGA2_SRC_BASE3_OFFSET 0x14 +#define RGA2_SRC_VIR_INFO_OFFSET 0x18 +#define RGA2_SRC_ACT_INFO_OFFSET 0x1c +#define RGA2_SRC_X_FACTOR_OFFSET 0x20 +#define RGA2_SRC_Y_FACTOR_OFFSET 0x24 +#define RGA2_SRC_BG_COLOR_OFFSET 0x28 +#define RGA2_SRC_FG_COLOR_OFFSET 0x2c +#define RGA2_SRC_TR_COLOR0_OFFSET 0x30 +#define RGA2_CF_GR_A_OFFSET 0x30 // repeat +#define RGA2_SRC_TR_COLOR1_OFFSET 0x34 +#define RGA2_CF_GR_B_OFFSET 0x34 // repeat +#define RGA2_DST_INFO_OFFSET 0x38 +#define RGA2_DST_BASE0_OFFSET 0x3c +#define RGA2_DST_BASE1_OFFSET 0x40 +#define RGA2_DST_BASE2_OFFSET 0x44 +#define RGA2_DST_VIR_INFO_OFFSET 0x48 +#define RGA2_DST_ACT_INFO_OFFSET 0x4c +#define RGA2_ALPHA_CTRL0_OFFSET 0x50 +#define RGA2_ALPHA_CTRL1_OFFSET 0x54 +#define RGA2_FADING_CTRL_OFFSET 0x58 +#define RGA2_PAT_CON_OFFSET 0x5c +#define RGA2_ROP_CTRL0_OFFSET 0x60 +#define RGA2_CF_GR_G_OFFSET 0x60 // repeat +#define RGA2_DST_Y4MAP_LUT0_OFFSET 0x60 // repeat +#define RGA2_DST_QUANTIZE_SCALE_OFFSET 0x60 // repeat +#define RGA2_ROP_CTRL1_OFFSET 0x64 +#define RGA2_CF_GR_R_OFFSET 0x64 // repeat +#define RGA2_DST_Y4MAP_LUT1_OFFSET 0x64 // repeat +#define RGA2_DST_QUANTIZE_OFFSET_OFFSET 0x64 // repeat +#define RGA2_MASK_BASE_OFFSET 0x68 +#define RGA2_MMU_CTRL1_OFFSET 0x6c +#define RGA2_MMU_SRC_BASE_OFFSET 0x70 +#define RGA2_MMU_SRC1_BASE_OFFSET 0x74 +#define RGA2_MMU_DST_BASE_OFFSET 0x78 +#define RGA2_MMU_ELS_BASE_OFFSET 0x7c + +int rga2_gen_reg_info(unsigned char *base, + unsigned char *csc_base, struct rga2_req *msg); + +void rga_cmd_to_rga2_cmd(struct rga_req *req_rga, struct rga2_req *req); + +void rga2_soft_reset(struct rga_scheduler_t *scheduler); +int rga2_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler); +int rga2_init_reg(struct rga_job *job); +int rga2_get_version(struct rga_scheduler_t *scheduler); + +#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 000000000000..df5914ad3371 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga3_reg_info.h @@ -0,0 +1,450 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __REG3_INFO_H__ +#define __REG3_INFO_H__ + +#include "rga_drv.h" + +//General Registers +/* yqw: status和int寄存器尚不明了,无法进行修改。 */ +//#define RGA2_STATUS 0x00c +//#define RGA2_INT 0x010 + +#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_STATUS1 0x03c +#define RGA3_CMD_STATE 0x040 + +/* TODO: RGA_INT */ + +/* 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) + +/* sys_reg */ +#define RGA3_SYS_CTRL_OFFSET 0x000 +#define RGA3_CMD_CTRL_OFFSET 0x004 +#define RGA3_CMD_ADDR_OFFSET 0x008 +#define RGA3_MI_GROUP_CTRL_OFFSET 0x00c +#define RGA3_ARQOS_CTRL_OFFSET 0x010 +#define RGA3_VERSION_NUM_OFFSET 0x018 +#define RGA3_VERSION_TIM_OFFSET 0x01c +#define RGA3_INT_EN_OFFSET 0x020 +#define RGA3_INT_RAW_OFFSET 0x024 +#define RGA3_INT_MSK_OFFSET 0x028 +#define RGA3_INT_CLR_OFFSET 0x02c +#define RGA3_RO_SRST_OFFSET 0x030 +#define RGA3_STATUS0_OFFSET 0x034 +#define RGA3_SCAN_CNT_OFFSET 0x038 +#define RGA3_STATUS1_OFFSET 0x03c +#define RGA3_CMD_STATE_OFFSET 0x040 + +/* op_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 +#define RGA3_MMU_DTE_ADDR_OFFSET 0x0f00 +#define RGA3_MMU_STATUS_OFFSET 0x0f04 +#define RGA3_MMU_COMMAND_OFFSET 0x0f08 +#define RGA3_MMU_PAGE_FAULT_ADDR_OFFSET 0x0f0c +#define RGA3_MMU_ZAP_ONE_LINE_OFFSET 0x0f10 +#define RGA3_MMU_INT_RAWSTAT_OFFSET 0x0f14 +#define RGA3_MMU_INT_CLEAR_OFFSET 0x0f18 +#define RGA3_MMU_INT_MASK_OFFSET 0x0f1c +#define RGA3_MMU_INT_STATUS_OFFSET 0x0f20 +#define RGA3_MMU_AUTO_GATING_OFFSET 0x0f24 +#define RGA3_MMU_REG_LOAD_EN_OFFSET 0x0f28 + +int rga3_gen_reg_info(unsigned char *base, struct rga3_req *msg); +void rga_cmd_to_rga3_cmd(struct rga_req *req_rga, struct rga3_req *req); +//void RGA_MSG_2_RGA3_MSG_32(struct rga_req_32 *req_rga, struct rga3_req *req); + +void rga3_soft_reset(struct rga_scheduler_t *scheduler); +int rga3_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler); +int rga3_init_reg(struct rga_job *job); +int rga3_get_version(struct rga_scheduler_t *scheduler); + +#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 000000000000..4f3b0925739b --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: + * Cerf Yu + */ + +#ifndef __LINUX_RKRGA_COMMON_H_ +#define __LINUX_RKRGA_COMMON_H_ + +void rga_user_format_convert(uint32_t *df, uint32_t sf); + +bool rga_is_yuv422p_format(u32 format); +void rga_convert_addr(struct rga_img_info_t *img, bool before_vir_get_channel); +int rga_get_format_bits(u32 format); + +#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 000000000000..015688aafcc1 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_debugger.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: + * Cerf Yu + * Huang Lee + */ + +#ifndef _RGA_DEBUGGER_H_ +#define _RGA_DEBUGGER_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_CHECK_MODE; +extern int RGA_DEBUG_NONUSE; +extern int RGA_DEBUG_INT_FLAG; + +#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); + +#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 000000000000..52866321dd09 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_dma_buf.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: + * Cerf Yu + * Huang Lee + */ +#ifndef __RGA3_DMA_BUF_H__ +#define __RGA3_DMA_BUF_H__ + +#include "rga_drv.h" + +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_dma_buf_get(struct rga_job *job); + +int rga_iommu_map_virt_addr(struct rga_memory_parm *memory_parm, + struct rga_dma_buffer *virt_dma_buf, + struct device *rga_dev, + struct mm_struct *mm); +void rga_iommu_unmap_virt_addr(struct rga_dma_buffer *virt_addr); + +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_fd(struct rga_dma_buffer *rga_dma_buffer); + +int rga_dma_get_info(struct rga_job *job); +void rga_dma_put_info(struct rga_job *job); + +#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 000000000000..1292abf22277 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_drv.h @@ -0,0 +1,379 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#ifndef __LINUX_RGA_DRV_H_ +#define __LINUX_RGA_DRV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +#include +#endif + +#include + +#include "rga.h" +#include "rga_debugger.h" + +#define RGA_CORE_REG_OFFSET 0x10000 + +/* sample interval: 1000ms */ +#define RGA_LOAD_INTERVAL 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 2 +#define DRIVER_REVISION_VERSION 2 + +#define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \ + "." STR(DRIVER_REVISION_VERSION)) + +/* time limit */ +#define RGA_ASYNC_TIMEOUT_DELAY 500 +#define RGA_SYNC_TIMEOUT_DELAY HZ +#define RGA_RESET_TIMEOUT 1000 + +#define RGA_MAX_SCHEDULER 3 +#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 iommu_dma_cookie_type { + IOMMU_DMA_IOVA_COOKIE, + IOMMU_DMA_MSI_COOKIE, +}; + +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; + + struct rga_job *job; +}; + +struct rga_iommu_dma_cookie { + enum iommu_dma_cookie_type type; + + /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ + struct iova_domain iovad; +}; + +/* + * legacy: Wait for the import process to completely replace the current + * dma_map and remove it + */ +struct rga_dma_buffer_t { + /* DMABUF information */ + struct dma_buf *dma_buf; + struct dma_buf_attachment *attach; + struct sg_table *sgt; + + dma_addr_t iova; + unsigned long size; + void *vaddr; + enum dma_data_direction dir; + + /* It indicates whether the buffer is cached */ + bool cached; + + struct list_head link; + struct kref refcount; + + struct iommu_domain *domain; + struct rga_iommu_dma_cookie *cookie; + + /* + * use dma_buf directly, + * do not call dma_buf_put, such as mpi + */ + bool use_dma_buf; + + bool use_viraddr; +}; + +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; + struct rga_iommu_dma_cookie *cookie; + + 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 core of the mapping */ + int core; +}; + +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; + uint32_t dma_buffer_size; + + /* virtual address */ + struct rga_virt_addr *virt_addr; + + /* physical address */ + uint64_t phys_addr; + + 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; +}; + +/* + * yqw add: + * In order to use the virtual address to refresh the cache, + * it may be merged into sgt later. + */ +struct rga2_mmu_other_t { + uint32_t *MMU_src0_base; + uint32_t *MMU_src1_base; + uint32_t *MMU_dst_base; + uint32_t MMU_src0_count; + uint32_t MMU_src1_count; + uint32_t MMU_dst_count; + + uint32_t MMU_len; + bool MMU_map; +}; + +struct rga_job { + struct list_head head; + struct rga_req rga_command_base; + uint32_t cmd_reg[32 * 8]; + uint32_t csc_reg[12]; + + struct rga_dma_buffer_t *rga_dma_buffer_src0; + struct rga_dma_buffer_t *rga_dma_buffer_src1; + struct rga_dma_buffer_t *rga_dma_buffer_dst; + /* used by rga2 */ + struct rga_dma_buffer_t *rga_dma_buffer_els; + + struct rga_internal_buffer *src_buffer; + struct rga_internal_buffer *src1_buffer; + struct rga_internal_buffer *dst_buffer; + /* used by rga2 */ + struct rga_internal_buffer *els_buffer; + + struct dma_buf *dma_buf_src0; + struct dma_buf *dma_buf_src1; + struct dma_buf *dma_buf_dst; + struct dma_buf *dma_buf_els; + + /* for rga2 virtual_address */ + struct mm_struct *mm; + struct rga2_mmu_other_t vir_page_table; + + struct dma_fence *out_fence; + struct dma_fence *in_fence; + spinlock_t fence_lock; + ktime_t timestamp; + ktime_t running_time; + unsigned int flags; + int job_id; + int priority; + int core; + int ret; +}; + +struct rga_scheduler_t; + +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); +}; + +struct rga_timer { + u32 busy_time; + u32 busy_time_record; +}; + +struct rga_scheduler_t { + struct device *dev; + void __iomem *rga_base; + + struct clk *clks[RGA_MAX_BUS_CLK]; + int num_clks; + + 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_drvdata_t { + struct miscdevice miscdev; + + struct rga_fence_context *fence_ctx; + + /* used by rga2's mmu lock */ + struct mutex lock; + + struct rga_scheduler_t *rga_scheduler[RGA_MAX_SCHEDULER]; + int num_of_scheduler; + + struct delayed_work power_off_work; + struct wake_lock wake_lock; + + struct rga_mm *mm; + +#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; + const struct rga_irqs_data_t *irqs; + int num_irqs; +}; + +static inline int rga_read(int offset, struct rga_scheduler_t *rga_scheduler) +{ + return readl(rga_scheduler->rga_base + offset); +} + +static inline void rga_write(int value, int offset, struct rga_scheduler_t *rga_scheduler) +{ + writel(value, rga_scheduler->rga_base + offset); +} + +int rga_power_enable(struct rga_scheduler_t *rga_scheduler); +int rga_power_disable(struct rga_scheduler_t *rga_scheduler); + +#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 000000000000..6ab3ccf447de --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_fence.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#ifndef __LINUX_RGA_FENCE_H_ +#define __LINUX_RGA_FENCE_H_ + +#include "rga_drv.h" + +struct rga_fence_context *rga_fence_context_alloc(void); + +void rga_fence_context_free(struct rga_fence_context *fence_ctx); + +int rga_out_fence_alloc(struct rga_job *job); + +int rga_out_fence_get_fd(struct rga_job *job); + +struct dma_fence *rga_get_input_fence(int in_fence_fd); + +int rga_wait_input_fence(struct dma_fence *in_fence); + +int rga_add_dma_fence_callback(struct rga_job *job, + struct dma_fence *in_fence, dma_fence_func_t func); + +#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 000000000000..2f36f7817339 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_hw_config.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#ifndef __LINUX_RGA_HW_CONFIG_H_ +#define __LINUX_RGA_HW_CONFIG_H_ + +#include "rga_drv.h" + +struct rga_rect { + int w; + int h; +}; + +struct rga_win_data { + const char *name; + const uint32_t *raster_formats; + const uint32_t *fbc_formats; + const uint32_t *tile_formats; + uint32_t num_of_raster_formats; + uint32_t num_of_fbc_formats; + uint32_t num_of_tile_formats; + + const unsigned int supported_rotations; + const unsigned int scale_up_mode; + const unsigned int scale_down_mode; + const unsigned int rd_mode; + +}; + +struct rga_hw_data { + uint32_t version; + uint32_t feature; + + uint32_t csc_r2y_mode; + uint32_t csc_y2r_mode; + + struct rga_rect max_input; + struct rga_rect max_output; + struct rga_rect min_input; + struct rga_rect min_output; + + unsigned int max_upscale_factor; + unsigned int max_downscale_factor; + + const struct rga_win_data *win; + unsigned int win_size; +}; + +extern const struct rga_hw_data rga3_data; +extern const struct rga_hw_data rga2e_data; + +#endif /* __LINUX_RGA_HW_CONFIG_H_ */ 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 000000000000..10b0a9253350 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_job.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#ifndef __LINUX_RKRGA_JOB_H_ +#define __LINUX_RKRGA_JOB_H_ + +#include +#include + +#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_RGA2 = 1 << 4, +}; + +struct rga_scheduler_t *rga_job_get_scheduler(int core); + +void rga_job_done(struct rga_scheduler_t *rga_scheduler, int ret); +int rga_job_commit(struct rga_req *rga_command_base, int flags); + +int rga_job_mpi_commit(struct rga_req *rga_command_base, + struct rga_mpi_job_t *mpi_job, int flags); + +int rga_job_assign(struct rga_job *job); + +struct rga_job * +rga_scheduler_get_pending_job_list(struct rga_scheduler_t *scheduler); + +struct rga_job * +rga_scheduler_get_running_job(struct rga_scheduler_t *scheduler); + +#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 000000000000..0683ecab30c0 --- /dev/null +++ b/drivers/video/rockchip/rga3/include/rga_mm.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: + * Cerf Yu + */ + +#ifndef __LINUX_RKRGA_MM_H_ +#define __LINUX_RKRGA_MM_H_ + +#include "rga_drv.h" + +enum memory_flag { + /* It will identify whether the buffer is within 0 ~ 4G. */ + RGA_MM_UNDER_4G = 1 << 0, + /* Logo enable IOMMU */ + RGA_MM_NEED_USE_IOMMU = 1 << 1, +}; + +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; +}; + +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, int core); +struct sg_table *rga_mm_lookup_sgt(struct rga_internal_buffer *buffer, int core); + +void rga_mm_dump_info(struct rga_mm *session); + +int rga_mm_get_handle_info(struct rga_job *job); +void rga_mm_put_handle_info(struct rga_job *job); + +uint32_t rga_mm_import_buffer(struct rga_external_buffer *external_buffer); +int rga_mm_release_buffer(uint32_t handle); + +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_mmu_info.c b/drivers/video/rockchip/rga3/rga2_mmu_info.c new file mode 100644 index 000000000000..f75fa383a27f --- /dev/null +++ b/drivers/video/rockchip/rga3/rga2_mmu_info.c @@ -0,0 +1,1266 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#define pr_fmt(fmt) "rga2_mmu: " fmt + +#include "rga2_mmu_info.h" +#include "rga_dma_buf.h" +#include "rga_mm.h" +#include "rga_job.h" +#include "rga_common.h" + +extern struct rga2_mmu_info_t rga2_mmu_info; + +#define KERNEL_SPACE_VALID 0xc0000000 + +#define V7_VATOPA_SUCESS_MASK (0x1) +#define V7_VATOPA_GET_PADDR(X) (X & 0xFFFFF000) +#define V7_VATOPA_GET_INER(X) ((X>>4) & 7) +#define V7_VATOPA_GET_OUTER(X) ((X>>2) & 3) +#define V7_VATOPA_GET_SH(X) ((X>>7) & 1) +#define V7_VATOPA_GET_NS(X) ((X>>9) & 1) +#define V7_VATOPA_GET_SS(X) ((X>>1) & 1) + +static void rga2_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); +} + +static dma_addr_t rga2_dma_map_flush_page(struct page *page, int map, struct rga_scheduler_t *scheduler) +{ + dma_addr_t paddr = 0; + + /* + * Through dma_map_page to ensure that the physical address + * will not exceed the addressing range of dma. + */ + + if (map & MMU_MAP_MASK) { + switch (map) { + case MMU_MAP_CLEAN: + paddr = dma_map_page(scheduler->dev, page, 0, + PAGE_SIZE, DMA_TO_DEVICE); + break; + case MMU_MAP_INVALID: + paddr = dma_map_page(scheduler->dev, page, 0, + PAGE_SIZE, DMA_FROM_DEVICE); + break; + case MMU_MAP_CLEAN | MMU_MAP_INVALID: + paddr = dma_map_page(scheduler->dev, page, 0, + PAGE_SIZE, DMA_BIDIRECTIONAL); + break; + default: + paddr = 0; + pr_err("unknown map cmd 0x%x\n", map); + break; + } + + return paddr; + } else if (map & MMU_UNMAP_MASK) { + paddr = page_to_phys(page); + + switch (map) { + case MMU_UNMAP_CLEAN: + dma_unmap_page(scheduler->dev, paddr, + PAGE_SIZE, DMA_TO_DEVICE); + break; + case MMU_UNMAP_INVALID: + dma_unmap_page(scheduler->dev, paddr, + PAGE_SIZE, DMA_FROM_DEVICE); + break; + case MMU_UNMAP_CLEAN | MMU_UNMAP_INVALID: + dma_unmap_page(scheduler->dev, paddr, + PAGE_SIZE, DMA_BIDIRECTIONAL); + break; + default: + paddr = 0; + pr_err("unknown map cmd 0x%x\n", map); + break; + } + + return paddr; + } + + pr_err("failed to flush page, map= %x\n", map); + return 0; +} + +void rga2_dma_flush_cache_for_virtual_address(struct rga2_mmu_other_t *reg, + struct rga_scheduler_t *scheduler) +{ + int i; + + if (reg->MMU_src0_base != NULL) { + for (i = 0; i < reg->MMU_src0_count; i++) + rga2_dma_map_flush_page(phys_to_page(reg->MMU_src0_base[i]), + MMU_UNMAP_CLEAN, scheduler); + } + + if (reg->MMU_src1_base != NULL) { + for (i = 0; i < reg->MMU_src1_count; i++) + rga2_dma_map_flush_page(phys_to_page(reg->MMU_src1_base[i]), + MMU_UNMAP_CLEAN, scheduler); + } + + if (reg->MMU_dst_base != NULL) { + for (i = 0; i < reg->MMU_dst_count; i++) + rga2_dma_map_flush_page(phys_to_page(reg->MMU_dst_base[i]), + MMU_UNMAP_INVALID, scheduler); + } +} + +static int rga2_mmu_buf_get(struct rga2_mmu_info_t *t, uint32_t size) +{ + mutex_lock(&rga_drvdata->lock); + t->front += size; + mutex_unlock(&rga_drvdata->lock); + + return 0; +} + +static int rga2_mmu_buf_get_try(struct rga2_mmu_info_t *t, uint32_t size) +{ + int ret = 0; + + mutex_lock(&rga_drvdata->lock); + 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: + mutex_unlock(&rga_drvdata->lock); + return ret; +} + +static int rga2_mem_size_cal(unsigned long Mem, uint32_t MemSize, + unsigned long *StartAddr) +{ + unsigned long start, end; + uint32_t pageCount; + + end = (Mem + (MemSize + PAGE_SIZE - 1)) >> PAGE_SHIFT; + start = Mem >> PAGE_SHIFT; + pageCount = end - start; + *StartAddr = start; + return pageCount; +} + +static int rga2_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; +} + +static int rga2_MapUserMemory(struct page **pages, uint32_t *pageTable, + unsigned long Memory, uint32_t pageCount, + int writeFlag, int map, struct rga_scheduler_t *scheduler, + struct mm_struct *mm) +{ + struct vm_area_struct *vma; + int32_t result; + uint32_t i; + uint32_t status; + unsigned long Address; + unsigned long pfn; + struct page __maybe_unused *page; + 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; + + status = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + mmap_read_lock(mm); +#else + down_read(&mm->mmap_sem); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) + result = get_user_pages(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, mm, Memory << PAGE_SHIFT, + pageCount, writeFlag, 0, pages, NULL); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) + result = get_user_pages_remote(current, mm, + Memory << PAGE_SHIFT, + pageCount, writeFlag, pages, NULL, NULL); +#else + result = get_user_pages_remote(mm, Memory << PAGE_SHIFT, + pageCount, writeFlag, pages, NULL, NULL); +#endif + + if (result > 0 && result >= pageCount) { + /* Fill the page table. */ + for (i = 0; i < pageCount; i++) { + /* Get the physical address from page struct. */ + pageTable[i] = rga2_dma_map_flush_page(pages[i], map, scheduler); + } + + for (i = 0; i < result; i++) + put_page(pages[i]); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + mmap_read_unlock(mm); +#else + up_read(&mm->mmap_sem); +#endif + return 0; + } + + if (result > 0) { + for (i = 0; i < result; i++) + put_page(pages[i]); + } + + for (i = 0; i < pageCount; i++) { + vma = find_vma(mm, (Memory + i) << PAGE_SHIFT); + if (!vma) { + pr_err("failed to get vma, result = %d, pageCount = %d\n", + result, pageCount); + status = RGA_OUT_OF_RESOURCES; + break; + } + + pgd = pgd_offset(mm, (Memory + i) << PAGE_SHIFT); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) { + pr_err("failed to get pgd, result = %d, pageCount = %d\n", + result, pageCount); + status = 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("failed to get p4d, result = %d, pageCount = %d\n", + result, pageCount); + status = 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("failed to get pud, result = %d, pageCount = %d\n", + result, pageCount); + status = RGA_OUT_OF_RESOURCES; + break; + } + pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { + pr_err("failed to get pmd, result = %d, pageCount = %d\n", + result, pageCount); + status = RGA_OUT_OF_RESOURCES; + break; + } + pte = pte_offset_map_lock(mm, pmd, + (Memory + i) << PAGE_SHIFT, &ptl); + if (pte_none(*pte)) { + pr_err("failed to get pte, result = %d, pageCount = %d\n", + result, pageCount); + pte_unmap_unlock(pte, ptl); + status = RGA_OUT_OF_RESOURCES; + break; + } + + pfn = pte_pfn(*pte); + Address = ((pfn << PAGE_SHIFT) | + (((unsigned long)((Memory + i) << PAGE_SHIFT)) & + ~PAGE_MASK)); + + pageTable[i] = rga2_dma_map_flush_page(phys_to_page(Address), map, scheduler); + + pte_unmap_unlock(pte, ptl); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + mmap_read_unlock(mm); +#else + up_read(&mm->mmap_sem); +#endif + + return status; +} + +static int rga2_MapION(struct sg_table *sg, + uint32_t *Memory, int32_t pageCount) +{ + 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 { + len = sg_dma_len(sgl) >> PAGE_SHIFT; + + /* + * The fd passed by user space gets sg through + * dma_buf_map_attachment, + * so dma_address can be use here. + */ + Address = sg_dma_address(sgl); + + for (i = 0; i < len; i++) { + if (mapped_size + i >= pageCount) { + break_flag = 1; + break; + } + Memory[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->nents)); + + return 0; +} + +static int rga2_mmu_flush_cache(struct rga2_mmu_other_t *reg, + struct rga2_req *req, struct rga_job *job) +{ + int DstMemSize; + unsigned long DstStart, DstPageCount; + uint32_t *MMU_Base; + int ret; + int status; + struct page **pages = NULL; + struct rga_scheduler_t *scheduler = NULL; + + MMU_Base = NULL; + DstPageCount = 0; + DstStart = 0; + + scheduler = rga_job_get_scheduler(job->core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + return ret; + } + + if (reg->MMU_map != true) { + status = -EINVAL; + goto out; + } + + /* cal dst buf mmu info */ + if (req->mmu_info.dst_mmu_flag & 1) { + DstPageCount = rga_buf_size_cal(req->dst.yrgb_addr, + req->dst.uv_addr, + req->dst.v_addr, + req->dst.format, + req->dst.vir_w, + req->dst.vir_h, &DstStart, NULL); + if (DstPageCount == 0) + return -EINVAL; + } + /* Cal out the needed mem size */ + DstMemSize = (DstPageCount + 15) & (~15); + + if (rga2_mmu_buf_get_try(&rga2_mmu_info, DstMemSize)) { + pr_err("Get MMU mem failed\n"); + status = RGA_MALLOC_ERROR; + goto out; + } + pages = rga2_mmu_info.pages; + mutex_lock(&rga_drvdata->lock); + MMU_Base = rga2_mmu_info.buf_virtual + + (rga2_mmu_info.front & (rga2_mmu_info.size - 1)); + + mutex_unlock(&rga_drvdata->lock); + if (DstMemSize) { + if (job->rga_dma_buffer_dst) { + status = -EINVAL; + goto out; + } else { + ret = rga2_MapUserMemory(&pages[0], + MMU_Base, + DstStart, DstPageCount, 1, + MMU_MAP_CLEAN | + MMU_MAP_INVALID, scheduler, job->mm); + if (DEBUGGER_EN(CHECK_MODE)) + rga2_user_memory_check(&pages[0], + req->dst.vir_w, + req->dst.vir_h, + req->dst.format, 2); + } + if (ret < 0) { + pr_err("rga2 unmap dst memory failed\n"); + status = ret; + goto out; + } + } + rga2_mmu_buf_get(&rga2_mmu_info, DstMemSize); + reg->MMU_len = DstMemSize; + status = 0; +out: + return status; +} + +static int rga2_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 { + len = sg_dma_len(sgl) >> PAGE_SHIFT; + if (len == 0) + 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. + */ + 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->nents)); + + return 0; +} + +static int rga2_mmu_set_channel_internal(struct rga_scheduler_t *scheduler, + struct rga_internal_buffer *internal_buffer, + uint32_t *mmu_base, + unsigned long page_count, + uint32_t **virt_flush_base, + uint32_t *virt_flush_count, + int map_flag) +{ + struct sg_table *sgt = NULL; + + sgt = rga_mm_lookup_sgt(internal_buffer, scheduler->core); + if (sgt == NULL) { + pr_err("rga2 cannot get sgt from handle!\n"); + return -EINVAL; + } + + if (internal_buffer->type == RGA_VIRTUAL_ADDRESS) { + rga2_sgt_to_page_table(sgt, mmu_base, page_count, false); + } else { + page_count = (page_count + 15) & (~15); + rga2_sgt_to_page_table(sgt, mmu_base, page_count, true); + } + + return page_count; +} + +static int rga2_mmu_info_BitBlt_mode(struct rga2_mmu_other_t *reg, + struct rga2_req *req, struct rga_job *job) +{ + int Src0MemSize, DstMemSize, Src1MemSize; + unsigned long Src0Start, Src1Start, DstStart; + unsigned long Src0PageCount, Src1PageCount, DstPageCount; + uint32_t AllSize; + uint32_t *MMU_Base, *MMU_Base_phys; + int ret; + int status; + int map_flag; + uint32_t uv_size, v_size; + struct page **pages = NULL; + + struct rga_scheduler_t *scheduler = NULL; + + scheduler = rga_job_get_scheduler(job->core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + return ret; + } + + MMU_Base = NULL; + Src0PageCount = 0; + Src1PageCount = 0; + DstPageCount = 0; + Src0Start = 0; + Src1Start = 0; + DstStart = 0; + + /* cal src0 buf mmu info */ + if (req->mmu_info.src0_mmu_flag & 1) { + Src0PageCount = rga_buf_size_cal(req->src.yrgb_addr, + req->src.uv_addr, + req->src.v_addr, + req->src.format, + req->src.vir_w, + (req->src.vir_h), &Src0Start, NULL); + if (Src0PageCount == 0) + return -EINVAL; + } + /* cal src1 buf mmu info */ + if (req->mmu_info.src1_mmu_flag & 1) { + Src1PageCount = rga_buf_size_cal(req->src1.yrgb_addr, + req->src1.uv_addr, + req->src1.v_addr, + req->src1.format, + req->src1.vir_w, + (req->src1.vir_h), + &Src1Start, NULL); + if (Src1PageCount == 0) + return -EINVAL; + } + /* cal dst buf mmu info */ + if (req->mmu_info.dst_mmu_flag & 1) { + DstPageCount = rga_buf_size_cal(req->dst.yrgb_addr, + req->dst.uv_addr, + req->dst.v_addr, + req->dst.format, + req->dst.vir_w, + req->dst.vir_h, &DstStart, NULL); + if (DstPageCount == 0) + return -EINVAL; + } + /* Cal out the needed mem size */ + Src0MemSize = (Src0PageCount + 15) & (~15); + Src1MemSize = (Src1PageCount + 15) & (~15); + DstMemSize = (DstPageCount + 15) & (~15); + AllSize = Src0MemSize + Src1MemSize + DstMemSize; + + if (rga2_mmu_buf_get_try(&rga2_mmu_info, AllSize)) { + pr_err("Get MMU mem failed\n"); + status = RGA_MALLOC_ERROR; + goto out; + } + + pages = rga2_mmu_info.pages; + if (pages == NULL) { + pr_err("MMU malloc pages mem failed\n"); + return -EINVAL; + } + + mutex_lock(&rga_drvdata->lock); + + MMU_Base = rga2_mmu_info.buf_virtual + rga2_mmu_info.front; + MMU_Base_phys = rga2_mmu_info.buf + rga2_mmu_info.front; + + mutex_unlock(&rga_drvdata->lock); + + if (Src0MemSize) { + if (job->src_buffer) { + ret = rga2_mmu_set_channel_internal(scheduler, + job->src_buffer, + MMU_Base, + Src0PageCount, + ®->MMU_src0_base, + ®->MMU_src0_count, + MMU_MAP_CLEAN); + if (ret < 0) { + pr_err("src0 channel set mmu base error!\n"); + return ret; + } + } else { + if (job->rga_dma_buffer_src0) { + ret = rga2_MapION(job->rga_dma_buffer_src0->sgt, + &MMU_Base[0], Src0MemSize); + } else { + ret = rga2_MapUserMemory(&pages[0], &MMU_Base[0], + Src0Start, Src0PageCount, + 0, MMU_MAP_CLEAN, scheduler, job->mm); + if (DEBUGGER_EN(CHECK_MODE)) + /* TODO: */ + rga2_user_memory_check(&pages[0], + req->src.vir_w, + req->src.vir_h, + req->src.format, 1); + /* Save pagetable to unmap. */ + reg->MMU_src0_base = MMU_Base; + reg->MMU_src0_count = Src0PageCount; + } + } + + if (ret < 0) { + pr_err("rga2 map src0 memory failed\n"); + status = ret; + goto out; + } + /* change the buf address in req struct */ + req->mmu_info.src0_base_addr = (((unsigned long)MMU_Base_phys)); + uv_size = (req->src.uv_addr + - (Src0Start << PAGE_SHIFT)) >> PAGE_SHIFT; + v_size = (req->src.v_addr + - (Src0Start << PAGE_SHIFT)) >> PAGE_SHIFT; + + req->src.yrgb_addr = (req->src.yrgb_addr & (~PAGE_MASK)); + req->src.uv_addr = (req->src.uv_addr & (~PAGE_MASK)) | + (uv_size << PAGE_SHIFT); + req->src.v_addr = (req->src.v_addr & (~PAGE_MASK)) | + (v_size << PAGE_SHIFT); + } + + if (Src1MemSize) { + if (job->src1_buffer) { + ret = rga2_mmu_set_channel_internal(scheduler, + job->src1_buffer, + MMU_Base + Src0MemSize, + Src1PageCount, + ®->MMU_src1_base, + ®->MMU_src1_count, + MMU_MAP_CLEAN); + if (ret < 0) { + pr_err("src1 channel set mmu base error!\n"); + return ret; + } + } else { + if (job->rga_dma_buffer_src1) { + ret = rga2_MapION(job->rga_dma_buffer_src1->sgt, + MMU_Base + Src0MemSize, Src1MemSize); + } else { + ret = rga2_MapUserMemory(&pages[0], + MMU_Base + Src0MemSize, + Src1Start, Src1PageCount, + 0, MMU_MAP_CLEAN, scheduler, job->mm); + + /* Save pagetable to unmap. */ + reg->MMU_src1_base = MMU_Base + Src0MemSize; + reg->MMU_src1_count = Src1PageCount; + } + } + + if (ret < 0) { + pr_err("rga2 map src1 memory failed\n"); + status = ret; + goto out; + } + /* change the buf address in req struct */ + req->mmu_info.src1_base_addr = ((unsigned long)(MMU_Base_phys + + Src0MemSize)); + req->src1.yrgb_addr = (req->src1.yrgb_addr & (~PAGE_MASK)); + } + + if (DstMemSize) { + if (req->alpha_mode_0 != 0 && req->bitblt_mode == 0) + /* + * The blend mode of src + dst => dst + * requires clean and invalidate + */ + map_flag = MMU_MAP_CLEAN | MMU_MAP_INVALID; + else + map_flag = MMU_MAP_INVALID; + + if (job->dst_buffer) { + ret = rga2_mmu_set_channel_internal(scheduler, + job->dst_buffer, + MMU_Base + Src0MemSize + Src1MemSize, + DstPageCount, + ®->MMU_dst_base, + ®->MMU_dst_count, + map_flag); + if (ret < 0) { + pr_err("dst channel set mmu base error!\n"); + return ret; + } + } else { + if (job->rga_dma_buffer_dst) { + ret = rga2_MapION(job->rga_dma_buffer_dst->sgt, + MMU_Base + Src0MemSize + Src1MemSize, + DstMemSize); + } else { + ret = rga2_MapUserMemory(&pages[0], + MMU_Base + Src0MemSize + Src1MemSize, + DstStart, DstPageCount, + 1, map_flag, + scheduler, job->mm); + + if (DEBUGGER_EN(CHECK_MODE)) + rga2_user_memory_check(&pages[0], + req->dst.vir_w, + req->dst.vir_h, + req->dst.format, 2); + + /* Save pagetable to invalid cache and unmap. */ + reg->MMU_dst_base = MMU_Base + Src0MemSize + Src1MemSize; + reg->MMU_dst_count = DstPageCount; + } + } + + if (ret < 0) { + pr_err("rga2 map dst memory failed\n"); + status = ret; + goto out; + } + + /* change the buf address in req struct */ + req->mmu_info.dst_base_addr = ((unsigned long)(MMU_Base_phys + + Src0MemSize + + Src1MemSize)); + req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK)); + uv_size = (req->dst.uv_addr + - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; + v_size = (req->dst.v_addr + - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; + req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | + ((uv_size) << PAGE_SHIFT); + req->dst.v_addr = (req->dst.v_addr & (~PAGE_MASK)) | + ((v_size) << PAGE_SHIFT); + + 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; + } + } + /* flush data to DDR */ + rga2_dma_sync_flush_range(MMU_Base, (MMU_Base + AllSize), scheduler); + rga2_mmu_buf_get(&rga2_mmu_info, AllSize); + reg->MMU_len = AllSize; + status = 0; +out: + return status; +} + +static int rga2_mmu_info_color_palette_mode(struct rga2_mmu_other_t *reg, + struct rga2_req *req, + struct rga_job *job) +{ + int SrcMemSize, DstMemSize; + unsigned long SrcStart, DstStart; + unsigned long SrcPageCount, DstPageCount; + struct page **pages = NULL; + uint32_t uv_size, v_size; + uint32_t AllSize; + uint32_t *MMU_Base = NULL, *MMU_Base_phys; + int ret; + uint32_t stride; + + uint8_t shift; + uint32_t sw, byte_num; + + struct rga_scheduler_t *scheduler = NULL; + + if (job->flags & RGA_JOB_USE_HANDLE) { + pr_err("color palette mode can not support handle.\n"); + return -EINVAL; + } + + scheduler = rga_job_get_scheduler(job->core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + return ret; + } + + shift = 3 - (req->palette_mode & 3); + sw = req->src.vir_w * req->src.vir_h; + byte_num = sw >> shift; + stride = (byte_num + 3) & (~3); + + SrcStart = 0; + DstStart = 0; + SrcPageCount = 0; + DstPageCount = 0; + + do { + if (req->mmu_info.src0_mmu_flag) { + if (req->mmu_info.els_mmu_flag & 1) { + req->mmu_info.src0_mmu_flag = 0; + req->mmu_info.src1_mmu_flag = 0; + } else { + req->mmu_info.els_mmu_flag = + req->mmu_info.src0_mmu_flag; + req->mmu_info.src0_mmu_flag = 0; + } + + SrcPageCount = + rga2_mem_size_cal(req->src.yrgb_addr, stride, + &SrcStart); + if (SrcPageCount == 0) + return -EINVAL; + } + + if (req->mmu_info.dst_mmu_flag) { + DstPageCount = + rga_buf_size_cal(req->dst.yrgb_addr, + req->dst.uv_addr, req->dst.v_addr, + req->dst.format, req->dst.vir_w, + req->dst.vir_h, &DstStart, NULL); + if (DstPageCount == 0) + return -EINVAL; + } + + SrcMemSize = (SrcPageCount + 15) & (~15); + DstMemSize = (DstPageCount + 15) & (~15); + + AllSize = SrcMemSize + DstMemSize; + + if (rga2_mmu_buf_get_try(&rga2_mmu_info, AllSize)) { + pr_err("Get MMU mem failed\n"); + break; + } + + pages = rga2_mmu_info.pages; + if (pages == NULL) { + pr_err("MMU malloc pages mem failed\n"); + return -EINVAL; + } + + mutex_lock(&rga_drvdata->lock); + MMU_Base = rga2_mmu_info.buf_virtual + rga2_mmu_info.front; + MMU_Base_phys = rga2_mmu_info.buf + rga2_mmu_info.front; + mutex_unlock(&rga_drvdata->lock); + + if (SrcMemSize) { + if (job->rga_dma_buffer_src0) { + ret = rga2_MapION(job->rga_dma_buffer_src0->sgt, + &MMU_Base[0], SrcMemSize); + } else { + ret = rga2_MapUserMemory(&pages[0], + &MMU_Base[0], SrcStart, SrcPageCount, + 0, MMU_MAP_CLEAN, scheduler, job->mm); + + if (DEBUGGER_EN(CHECK_MODE)) + rga2_user_memory_check(&pages[0], + req->src.vir_w, req->src.vir_h, + req->src.format, 1); + } + + if (ret < 0) { + pr_err("rga2 map src0 memory failed\n"); + break; + } + + /* change the buf address in req struct */ + req->mmu_info.els_base_addr = + (((unsigned long)MMU_Base_phys)); + /* + * The color palette mode will not have + * YUV format as input, + * so UV component address is not needed + */ + req->src.yrgb_addr = + (req->src.yrgb_addr & (~PAGE_MASK)); + } + + if (DstMemSize) { + if (job->rga_dma_buffer_dst) { + ret = rga2_MapION(job->rga_dma_buffer_dst->sgt, + MMU_Base + SrcMemSize, + DstMemSize); + } else { + ret = + rga2_MapUserMemory(&pages[0], + MMU_Base + SrcMemSize, + DstStart, DstPageCount, + 1, MMU_MAP_INVALID, scheduler, job->mm); + + if (DEBUGGER_EN(CHECK_MODE)) + rga2_user_memory_check(&pages[0], + req->dst.vir_w, req->dst.vir_h, + req->dst.format, 1); + } + + if (ret < 0) { + pr_err("rga2 map dst memory failed\n"); + break; + } + + /* change the buf address in req struct */ + req->mmu_info.dst_base_addr = + ((unsigned long)(MMU_Base_phys + SrcMemSize)); + req->dst.yrgb_addr = + (req->dst.yrgb_addr & (~PAGE_MASK)); + + uv_size = (req->dst.uv_addr + - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; + v_size = (req->dst.v_addr + - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; + req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | + ((uv_size) << PAGE_SHIFT); + req->dst.v_addr = (req->dst.v_addr & (~PAGE_MASK)) | + ((v_size) << PAGE_SHIFT); + } + + /* flush data to DDR */ + rga2_dma_sync_flush_range(MMU_Base, (MMU_Base + AllSize), scheduler); + rga2_mmu_buf_get(&rga2_mmu_info, AllSize); + reg->MMU_len = AllSize; + + return 0; + } while (0); + + return 0; +} + +static int rga2_mmu_info_color_fill_mode(struct rga2_mmu_other_t *reg, + struct rga2_req *req, + struct rga_job *job) +{ + int DstMemSize = 0; + unsigned long DstStart = 0; + unsigned long DstPageCount = 0; + struct page **pages = NULL; + uint32_t uv_size, v_size; + uint32_t AllSize; + uint32_t *MMU_Base, *MMU_Base_phys; + int ret; + int status; + struct sg_table *sgt; + + struct rga_scheduler_t *scheduler = NULL; + + scheduler = rga_job_get_scheduler(job->core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + return ret; + } + + MMU_Base = NULL; + + do { + if (req->mmu_info.dst_mmu_flag & 1) { + DstPageCount = rga_buf_size_cal(req->dst.yrgb_addr, + req->dst.uv_addr, req->dst.v_addr, + req->dst.format, req->dst.vir_w, + req->dst.vir_h, &DstStart, NULL); + if (DstPageCount == 0) + return -EINVAL; + } + + DstMemSize = (DstPageCount + 15) & (~15); + AllSize = DstMemSize; + + if (rga2_mmu_buf_get_try(&rga2_mmu_info, AllSize)) { + pr_err("Get MMU mem failed\n"); + status = RGA_MALLOC_ERROR; + break; + } + + pages = rga2_mmu_info.pages; + if (pages == NULL) { + pr_err("MMU malloc pages mem failed\n"); + return -EINVAL; + } + + mutex_lock(&rga_drvdata->lock); + MMU_Base_phys = rga2_mmu_info.buf + rga2_mmu_info.front; + MMU_Base = rga2_mmu_info.buf_virtual + rga2_mmu_info.front; + mutex_unlock(&rga_drvdata->lock); + + if (DstMemSize) { + if (job->dst_buffer) { + switch (job->dst_buffer->type) { + case RGA_DMA_BUFFER: + sgt = rga_mm_lookup_sgt(job->dst_buffer, scheduler->core); + if (sgt == NULL) { + pr_err("rga2 cannot get sgt from handle!\n"); + status = -EFAULT; + goto out; + } + ret = rga2_MapION(sgt, &MMU_Base[0], DstMemSize); + + break; + case RGA_VIRTUAL_ADDRESS: + ret = rga2_MapUserMemory(&pages[0], &MMU_Base[0], + DstStart, DstPageCount, + 1, MMU_MAP_INVALID, + scheduler, + job->dst_buffer->current_mm); + + /* Save pagetable to invalid cache and unmap. */ + reg->MMU_dst_base = MMU_Base; + reg->MMU_dst_count = DstPageCount; + + break; + default: + status = -EFAULT; + goto out; + } + + } else { + if (job->rga_dma_buffer_dst) { + ret = rga2_MapION(job->rga_dma_buffer_dst->sgt, + &MMU_Base[0], DstMemSize); + } else { + ret = rga2_MapUserMemory(&pages[0], + &MMU_Base[0], DstStart, + DstPageCount, 1, + MMU_MAP_INVALID, + scheduler, job->mm); + } + } + if (ret < 0) { + pr_err("map dst memory failed\n"); + status = ret; + break; + } + + /* change the buf address in req struct */ + req->mmu_info.dst_base_addr = + ((unsigned long)MMU_Base_phys); + req->dst.yrgb_addr = + (req->dst.yrgb_addr & (~PAGE_MASK)); + + uv_size = (req->dst.uv_addr + - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; + v_size = (req->dst.v_addr + - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; + req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | + ((uv_size) << PAGE_SHIFT); + req->dst.v_addr = (req->dst.v_addr & (~PAGE_MASK)) | + ((v_size) << PAGE_SHIFT); + } + + /* flush data to DDR */ + rga2_dma_sync_flush_range(MMU_Base, (MMU_Base + AllSize + 1), scheduler); + rga2_mmu_buf_get(&rga2_mmu_info, AllSize); + reg->MMU_len = AllSize; + + return 0; + } while (0); + +out: + return status; +} + +static int rga2_mmu_info_update_palette_table_mode(struct rga2_mmu_other_t *reg, + struct rga2_req *req, + struct rga_job *job) +{ + int LutMemSize = 0; + unsigned long LutStart = 0; + unsigned long LutPageCount = 0; + struct page **pages = NULL; + uint32_t uv_size, v_size; + uint32_t AllSize; + uint32_t *MMU_Base, *MMU_Base_phys; + int ret, status; + + struct rga_scheduler_t *scheduler = NULL; + + if (job->flags & RGA_JOB_USE_HANDLE) { + pr_err("update palette table mode can not support handle.\n"); + return -EINVAL; + } + + scheduler = rga_job_get_scheduler(job->core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + return ret; + } + + MMU_Base = NULL; + + do { + /* cal lut buf mmu info */ + if (req->mmu_info.els_mmu_flag & 1) { + req->mmu_info.src0_mmu_flag = + req->mmu_info.src0_mmu_flag == + 1 ? 0 : req->mmu_info.src0_mmu_flag; + req->mmu_info.src1_mmu_flag = + req->mmu_info.src1_mmu_flag == + 1 ? 0 : req->mmu_info.src1_mmu_flag; + req->mmu_info.dst_mmu_flag = + req->mmu_info.dst_mmu_flag == + 1 ? 0 : req->mmu_info.dst_mmu_flag; + + LutPageCount = + rga_buf_size_cal(req->pat.yrgb_addr, + req->pat.uv_addr, req->pat.v_addr, + req->pat.format, req->pat.vir_w, + req->pat.vir_h, &LutStart, NULL); + if (LutPageCount == 0) + return -EINVAL; + } + + LutMemSize = (LutPageCount + 15) & (~15); + AllSize = LutMemSize; + + if (rga2_mmu_buf_get_try(&rga2_mmu_info, AllSize)) { + pr_err("Get MMU mem failed\n"); + status = RGA_MALLOC_ERROR; + break; + } + + pages = rga2_mmu_info.pages; + if (pages == NULL) { + pr_err("MMU malloc pages mem failed\n"); + return -EINVAL; + } + + mutex_lock(&rga_drvdata->lock); + MMU_Base = rga2_mmu_info.buf_virtual + rga2_mmu_info.front; + MMU_Base_phys = rga2_mmu_info.buf + rga2_mmu_info.front; + mutex_unlock(&rga_drvdata->lock); + + if (LutMemSize) { + if (job->rga_dma_buffer_els) { + ret = rga2_MapION(job->rga_dma_buffer_els->sgt, + &MMU_Base[0], LutMemSize); + } else { + ret = rga2_MapUserMemory(&pages[0], + &MMU_Base[0], LutStart, + LutPageCount, 0, MMU_MAP_CLEAN, scheduler, job->mm); + } + if (ret < 0) { + pr_err("rga2 map palette memory failed\n"); + status = ret; + break; + } + + /* change the buf address in req struct */ + req->mmu_info.els_base_addr = + (((unsigned long)MMU_Base_phys)); + + req->pat.yrgb_addr = + (req->pat.yrgb_addr & (~PAGE_MASK)); + + uv_size = (req->pat.uv_addr + - (LutStart << PAGE_SHIFT)) >> PAGE_SHIFT; + v_size = (req->pat.v_addr + - (LutStart << PAGE_SHIFT)) >> PAGE_SHIFT; + req->pat.uv_addr = (req->pat.uv_addr & (~PAGE_MASK)) | + ((uv_size) << PAGE_SHIFT); + req->pat.v_addr = (req->pat.v_addr & (~PAGE_MASK)) | + ((v_size) << PAGE_SHIFT); + } + + /* flush data to DDR */ + rga2_dma_sync_flush_range(MMU_Base, (MMU_Base + AllSize), scheduler); + rga2_mmu_buf_get(&rga2_mmu_info, AllSize); + reg->MMU_len = AllSize; + + return 0; + } while (0); + + return status; +} + +int rga2_set_mmu_reg_info(struct rga2_mmu_other_t *reg, struct rga2_req *req, + struct rga_job *job) +{ + int ret; + + if (reg->MMU_map == true) { + ret = rga2_mmu_flush_cache(reg, req, job); + return ret; + } + + switch (req->render_mode) { + case BITBLT_MODE: + ret = rga2_mmu_info_BitBlt_mode(reg, req, job); + break; + case COLOR_PALETTE_MODE: + ret = rga2_mmu_info_color_palette_mode(reg, req, job); + break; + case COLOR_FILL_MODE: + ret = rga2_mmu_info_color_fill_mode(reg, req, job); + break; + case UPDATE_PALETTE_TABLE_MODE: + ret = rga2_mmu_info_update_palette_table_mode(reg, req, job); + break; + default: + ret = -1; + break; + } + + return ret; +} 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 000000000000..807131828d58 --- /dev/null +++ b/drivers/video/rockchip/rga3/rga2_reg_info.c @@ -0,0 +1,2517 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#define pr_fmt(fmt) "rga2_reg: " fmt + +#include "rga_job.h" +#include "rga2_reg_info.h" +#include "rga2_mmu_info.h" +#include "rga_common.h" + +extern struct rga2_mmu_info_t rga2_mmu_info; + +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 == 4) + render_mode = 3; + + 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))); + + *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 src_fmt_yuv400_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 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 == RGA2_FORMAT_YCbCr_420_SP_10B || + msg->src.format == RGA2_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; + } + } + + switch (msg->src.format) { + case RGA2_FORMAT_RGBA_8888: + src0_format = 0x0; + pixel_width = 4; + break; + case RGA2_FORMAT_BGRA_8888: + src0_format = 0x0; + src0_rb_swp = 0x1; + pixel_width = 4; + break; + case RGA2_FORMAT_RGBX_8888: + src0_format = 0x1; + pixel_width = 4; + msg->src_trans_mode &= 0x07; + break; + case RGA2_FORMAT_BGRX_8888: + src0_format = 0x1; + src0_rb_swp = 0x1; + pixel_width = 4; + msg->src_trans_mode &= 0x07; + break; + case RGA2_FORMAT_RGB_888: + src0_format = 0x2; + pixel_width = 3; + msg->src_trans_mode &= 0x07; + break; + case RGA2_FORMAT_BGR_888: + src0_format = 0x2; + src0_rb_swp = 1; + pixel_width = 3; + msg->src_trans_mode &= 0x07; + break; + case RGA2_FORMAT_RGB_565: + src0_format = 0x4; + pixel_width = 2; + msg->src_trans_mode &= 0x07; + break; + case RGA2_FORMAT_RGBA_5551: + src0_format = 0x5; + pixel_width = 2; + break; + case RGA2_FORMAT_RGBA_4444: + src0_format = 0x6; + pixel_width = 2; + break; + case RGA2_FORMAT_BGR_565: + src0_format = 0x4; + pixel_width = 2; + msg->src_trans_mode &= 0x07; + src0_rb_swp = 0x1; + break; + case RGA2_FORMAT_BGRA_5551: + src0_format = 0x5; + pixel_width = 2; + src0_rb_swp = 0x1; + break; + case RGA2_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 RGA2_FORMAT_ARGB_8888: + src0_format = 0x0; + pixel_width = 4; + src0_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_8888: + src0_format = 0x0; + pixel_width = 4; + src0_alpha_swp = 1; + src0_rb_swp = 0x1; + break; + case RGA2_FORMAT_XRGB_8888: + src0_format = 0x1; + pixel_width = 4; + src0_alpha_swp = 1; + msg->src_trans_mode &= 0x07; + break; + case RGA2_FORMAT_XBGR_8888: + src0_format = 0x1; + pixel_width = 4; + src0_alpha_swp = 1; + src0_rb_swp = 0x1; + msg->src_trans_mode &= 0x07; + break; + case RGA2_FORMAT_ARGB_5551: + src0_format = 0x5; + pixel_width = 2; + src0_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_5551: + src0_format = 0x5; + pixel_width = 2; + src0_alpha_swp = 1; + src0_rb_swp = 0x1; + break; + case RGA2_FORMAT_ARGB_4444: + src0_format = 0x6; + pixel_width = 2; + src0_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_4444: + src0_format = 0x6; + pixel_width = 2; + src0_alpha_swp = 1; + src0_rb_swp = 0x1; + break; + + case RGA2_FORMAT_YVYU_422: + src0_format = 0x7; + pixel_width = 2; + src0_cbcr_swp = 1; + src0_rb_swp = 0x1; + break; //rbswap=ycswap + case RGA2_FORMAT_VYUY_422: + src0_format = 0x7; + pixel_width = 2; + src0_cbcr_swp = 1; + src0_rb_swp = 0x0; + break; + case RGA2_FORMAT_YUYV_422: + src0_format = 0x7; + pixel_width = 2; + src0_cbcr_swp = 0; + src0_rb_swp = 0x1; + break; + case RGA2_FORMAT_UYVY_422: + src0_format = 0x7; + pixel_width = 2; + src0_cbcr_swp = 0; + src0_rb_swp = 0x0; + break; + + case RGA2_FORMAT_YCbCr_422_SP: + src0_format = 0x8; + xdiv = 1; + ydiv = 1; + break; + case RGA2_FORMAT_YCbCr_422_P: + src0_format = 0x9; + xdiv = 2; + ydiv = 1; + break; + case RGA2_FORMAT_YCbCr_420_SP: + src0_format = 0xa; + xdiv = 1; + ydiv = 2; + break; + case RGA2_FORMAT_YCbCr_420_P: + src0_format = 0xb; + xdiv = 2; + ydiv = 2; + break; + case RGA2_FORMAT_YCrCb_422_SP: + src0_format = 0x8; + xdiv = 1; + ydiv = 1; + src0_cbcr_swp = 1; + break; + case RGA2_FORMAT_YCrCb_422_P: + src0_format = 0x9; + xdiv = 2; + ydiv = 1; + src0_cbcr_swp = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP: + src0_format = 0xa; + xdiv = 1; + ydiv = 2; + src0_cbcr_swp = 1; + break; + case RGA2_FORMAT_YCrCb_420_P: + src0_format = 0xb; + xdiv = 2; + ydiv = 2; + src0_cbcr_swp = 1; + break; + + case RGA2_FORMAT_YCbCr_420_SP_10B: + src0_format = 0xa; + xdiv = 1; + ydiv = 2; + yuv10 = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP_10B: + src0_format = 0xa; + xdiv = 1; + ydiv = 2; + src0_cbcr_swp = 1; + yuv10 = 1; + break; + case RGA2_FORMAT_YCbCr_422_SP_10B: + src0_format = 0x8; + xdiv = 1; + ydiv = 1; + yuv10 = 1; + break; + case RGA2_FORMAT_YCrCb_422_SP_10B: + src0_format = 0x8; + xdiv = 1; + ydiv = 1; + src0_cbcr_swp = 1; + yuv10 = 1; + break; + + case RGA2_FORMAT_YCbCr_400: + src0_format = 0x8; + src_fmt_yuv400_en = 1; + 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))); + 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(( + msg->scale_bicu_mode >> 4)))); + 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 (src_fmt_yuv400_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; + 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 RGA2_FORMAT_RGBA_8888: + src1_format = 0x0; + spw = 4; + break; + case RGA2_FORMAT_BGRA_8888: + src1_format = 0x0; + src1_rb_swp = 0x1; + spw = 4; + break; + case RGA2_FORMAT_RGBX_8888: + src1_format = 0x1; + spw = 4; + break; + case RGA2_FORMAT_BGRX_8888: + src1_format = 0x1; + src1_rb_swp = 0x1; + spw = 4; + break; + case RGA2_FORMAT_RGB_888: + src1_format = 0x2; + spw = 3; + break; + case RGA2_FORMAT_BGR_888: + src1_format = 0x2; + src1_rb_swp = 1; + spw = 3; + break; + case RGA2_FORMAT_RGB_565: + src1_format = 0x4; + spw = 2; + break; + case RGA2_FORMAT_RGBA_5551: + src1_format = 0x5; + spw = 2; + break; + case RGA2_FORMAT_RGBA_4444: + src1_format = 0x6; + spw = 2; + break; + case RGA2_FORMAT_BGR_565: + src1_format = 0x4; + spw = 2; + src1_rb_swp = 0x1; + break; + case RGA2_FORMAT_BGRA_5551: + src1_format = 0x5; + spw = 2; + src1_rb_swp = 0x1; + break; + case RGA2_FORMAT_BGRA_4444: + src1_format = 0x6; + spw = 2; + src1_rb_swp = 0x1; + break; + + /* ARGB */ + case RGA2_FORMAT_ARGB_8888: + src1_format = 0x0; + spw = 4; + src1_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_8888: + src1_format = 0x0; + spw = 4; + src1_alpha_swp = 1; + src1_rb_swp = 0x1; + break; + case RGA2_FORMAT_XRGB_8888: + src1_format = 0x1; + spw = 4; + src1_alpha_swp = 1; + break; + case RGA2_FORMAT_XBGR_8888: + src1_format = 0x1; + spw = 4; + src1_alpha_swp = 1; + src1_rb_swp = 0x1; + break; + case RGA2_FORMAT_ARGB_5551: + src1_format = 0x5; + spw = 2; + src1_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_5551: + src1_format = 0x5; + spw = 2; + src1_alpha_swp = 1; + src1_rb_swp = 0x1; + break; + case RGA2_FORMAT_ARGB_4444: + src1_format = 0x6; + spw = 2; + src1_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_4444: + src1_format = 0x6; + spw = 2; + src1_alpha_swp = 1; + src1_rb_swp = 0x1; + 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 RGA2_FORMAT_RGBA_8888: + dst_format = 0x0; + dpw = 4; + break; + case RGA2_FORMAT_BGRA_8888: + dst_format = 0x0; + dst_rb_swp = 0x1; + dpw = 4; + break; + case RGA2_FORMAT_RGBX_8888: + dst_format = 0x1; + dpw = 4; + break; + case RGA2_FORMAT_BGRX_8888: + dst_format = 0x1; + dst_rb_swp = 0x1; + dpw = 4; + break; + case RGA2_FORMAT_RGB_888: + dst_format = 0x2; + dpw = 3; + break; + case RGA2_FORMAT_BGR_888: + dst_format = 0x2; + dst_rb_swp = 1; + dpw = 3; + break; + case RGA2_FORMAT_RGB_565: + dst_format = 0x4; + dpw = 2; + break; + case RGA2_FORMAT_RGBA_5551: + dst_format = 0x5; + dpw = 2; + break; + case RGA2_FORMAT_RGBA_4444: + dst_format = 0x6; + dpw = 2; + break; + case RGA2_FORMAT_BGR_565: + dst_format = 0x4; + dpw = 2; + dst_rb_swp = 0x1; + break; + case RGA2_FORMAT_BGRA_5551: + dst_format = 0x5; + dpw = 2; + dst_rb_swp = 0x1; + break; + case RGA2_FORMAT_BGRA_4444: + dst_format = 0x6; + dpw = 2; + dst_rb_swp = 0x1; + break; + + /* ARGB */ + case RGA2_FORMAT_ARGB_8888: + dst_format = 0x0; + dpw = 4; + dst_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_8888: + dst_format = 0x0; + dpw = 4; + dst_alpha_swp = 1; + dst_rb_swp = 0x1; + break; + case RGA2_FORMAT_XRGB_8888: + dst_format = 0x1; + dpw = 4; + dst_alpha_swp = 1; + break; + case RGA2_FORMAT_XBGR_8888: + dst_format = 0x1; + dpw = 4; + dst_alpha_swp = 1; + dst_rb_swp = 0x1; + break; + case RGA2_FORMAT_ARGB_5551: + dst_format = 0x5; + dpw = 2; + dst_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_5551: + dst_format = 0x5; + dpw = 2; + dst_alpha_swp = 1; + dst_rb_swp = 0x1; + break; + case RGA2_FORMAT_ARGB_4444: + dst_format = 0x6; + dpw = 2; + dst_alpha_swp = 1; + break; + case RGA2_FORMAT_ABGR_4444: + dst_format = 0x6; + dpw = 2; + dst_alpha_swp = 1; + dst_rb_swp = 0x1; + break; + + case RGA2_FORMAT_YCbCr_422_SP: + dst_format = 0x8; + x_div = 1; + y_div = 1; + break; + case RGA2_FORMAT_YCbCr_422_P: + dst_format = 0x9; + x_div = 2; + y_div = 1; + break; + case RGA2_FORMAT_YCbCr_420_SP: + dst_format = 0xa; + x_div = 1; + y_div = 2; + break; + case RGA2_FORMAT_YCbCr_420_P: + dst_format = 0xb; + dst_cbcr_swp = 1; + x_div = 2; + y_div = 2; + break; + case RGA2_FORMAT_YCrCb_422_SP: + dst_format = 0x8; + dst_cbcr_swp = 1; + x_div = 1; + y_div = 1; + break; + case RGA2_FORMAT_YCrCb_422_P: + dst_format = 0x9; + dst_cbcr_swp = 1; + x_div = 2; + y_div = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP: + dst_format = 0xa; + dst_cbcr_swp = 1; + x_div = 1; + y_div = 2; + break; + case RGA2_FORMAT_YCrCb_420_P: + dst_format = 0xb; + x_div = 2; + y_div = 2; + break; + + case RGA2_FORMAT_YCbCr_400: + dst_format = 0x8; + dst_fmt_yuv400_en = 1; + x_div = 1; + y_div = 1; + break; + case RGA2_FORMAT_Y4: + dst_format = 0x8; + dst_fmt_y4_en = 1; + dst_fmt_yuv400_en = 1; + x_div = 1; + y_div = 1; + break; + + case RGA2_FORMAT_YUYV_422: + dst_format = 0xe; + dpw = 2; + dst_cbcr_swp = 1; + break; + case RGA2_FORMAT_YVYU_422: + dst_format = 0xe; + dpw = 2; + break; + case RGA2_FORMAT_YUYV_420: + dst_format = 0xf; + dpw = 2; + dst_cbcr_swp = 1; + break; + case RGA2_FORMAT_YVYU_420: + dst_format = 0xf; + dpw = 2; + break; + case RGA2_FORMAT_UYVY_422: + dst_format = 0xc; + dpw = 2; + dst_cbcr_swp = 1; + break; + case RGA2_FORMAT_VYUY_422: + dst_format = 0xc; + dpw = 2; + break; + case RGA2_FORMAT_UYVY_420: + dst_format = 0xd; + dpw = 2; + dst_cbcr_swp = 1; + break; + case RGA2_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.flag))); + /* + * 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))); + + ydither_en = (msg->dst.format == RGA2_FORMAT_Y4) + && ((msg->alpha_rop_flag >> 6) & 0x1); + + *bRGA_DST_INFO = reg; + + s_stride = ((msg->src1.vir_w * spw + 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 == RGA2_FORMAT_BGR_888 + || msg->dst.format == RGA2_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); + + *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; + + if (msg->dst.format < 0x18 || + (msg->dst.format >= RGA2_FORMAT_ARGB_8888 && + msg->dst.format <= RGA2_FORMAT_ABGR_4444)) { + /* 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; + } else { + if (msg->dst.format == RGA2_FORMAT_YUYV_422 || + msg->dst.format == RGA2_FORMAT_YVYU_422 || + msg->dst.format == RGA2_FORMAT_UYVY_422 || + msg->dst.format == RGA2_FORMAT_VYUY_422) { + 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 { + 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); + } + } + + 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 == RGA2_FORMAT_YCbCr_420_P) + || (msg->dst.format == RGA2_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 reg0 = 0; + u32 reg1 = 0; + + 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); + + reg0 = + ((reg0 & (~m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0)) | + (s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0(msg->alpha_rop_flag))); + reg0 = + ((reg0 & (~m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL)) | + (s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL + (msg->alpha_rop_flag >> 1))); + reg0 = + ((reg0 & (~m_RGA2_ALPHA_CTRL0_SW_ROP_MODE)) | + (s_RGA2_ALPHA_CTRL0_SW_ROP_MODE(msg->rop_mode))); + reg0 = + ((reg0 & (~m_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA)) | + (s_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA + (msg->src_a_global_val))); + reg0 = + ((reg0 & (~m_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA)) | + (s_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA + (msg->dst_a_global_val))); + + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_COLOR_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_COLOR_M0 + (msg->alpha_mode_0 >> 15))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_COLOR_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_COLOR_M0 + (msg->alpha_mode_0 >> 7))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M0 + (msg->alpha_mode_0 >> 12))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M0 + (msg->alpha_mode_0 >> 4))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M0 + (msg->alpha_mode_0 >> 11))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M0 + (msg->alpha_mode_0 >> 3))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M0 + (msg->alpha_mode_0 >> 9))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M0 + (msg->alpha_mode_0 >> 1))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M0 + (msg->alpha_mode_0 >> 8))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M0)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M0 + (msg->alpha_mode_0 >> 0))); + + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M1 + (msg->alpha_mode_1 >> 12))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M1 + (msg->alpha_mode_1 >> 4))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M1 + (msg->alpha_mode_1 >> 11))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M1 + (msg->alpha_mode_1 >> 3))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M1(msg->alpha_mode_1 >> 9))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M1(msg->alpha_mode_1 >> 1))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M1(msg->alpha_mode_1 >> 8))); + reg1 = + ((reg1 & (~m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M1)) | + (s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M1(msg->alpha_mode_1 >> 0))); + + *bRGA_ALPHA_CTRL0 = reg0; + *bRGA_ALPHA_CTRL1 = reg1; + + 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 RGA2_set_reg_full_csc(u8 *base, struct rga2_req *msg) +{ + u32 *bRGA2_DST_CSC_00; + u32 *bRGA2_DST_CSC_01; + u32 *bRGA2_DST_CSC_02; + u32 *bRGA2_DST_CSC_OFF0; + + u32 *bRGA2_DST_CSC_10; + u32 *bRGA2_DST_CSC_11; + u32 *bRGA2_DST_CSC_12; + u32 *bRGA2_DST_CSC_OFF1; + + u32 *bRGA2_DST_CSC_20; + u32 *bRGA2_DST_CSC_21; + u32 *bRGA2_DST_CSC_22; + u32 *bRGA2_DST_CSC_OFF2; + + bRGA2_DST_CSC_00 = (u32 *) (base + RGA2_DST_CSC_00_OFFSET); + bRGA2_DST_CSC_01 = (u32 *) (base + RGA2_DST_CSC_01_OFFSET); + bRGA2_DST_CSC_02 = (u32 *) (base + RGA2_DST_CSC_02_OFFSET); + bRGA2_DST_CSC_OFF0 = (u32 *) (base + RGA2_DST_CSC_OFF0_OFFSET); + + bRGA2_DST_CSC_10 = (u32 *) (base + RGA2_DST_CSC_10_OFFSET); + bRGA2_DST_CSC_11 = (u32 *) (base + RGA2_DST_CSC_11_OFFSET); + bRGA2_DST_CSC_12 = (u32 *) (base + RGA2_DST_CSC_12_OFFSET); + bRGA2_DST_CSC_OFF1 = (u32 *) (base + RGA2_DST_CSC_OFF1_OFFSET); + + bRGA2_DST_CSC_20 = (u32 *) (base + RGA2_DST_CSC_20_OFFSET); + bRGA2_DST_CSC_21 = (u32 *) (base + RGA2_DST_CSC_21_OFFSET); + bRGA2_DST_CSC_22 = (u32 *) (base + RGA2_DST_CSC_22_OFFSET); + bRGA2_DST_CSC_OFF2 = (u32 *) (base + RGA2_DST_CSC_OFF2_OFFSET); + + /* full csc coefficient */ + /* Y coefficient */ + *bRGA2_DST_CSC_00 = msg->full_csc.coe_y.r_v; + *bRGA2_DST_CSC_01 = msg->full_csc.coe_y.g_y; + *bRGA2_DST_CSC_02 = msg->full_csc.coe_y.b_u; + *bRGA2_DST_CSC_OFF0 = msg->full_csc.coe_y.off; + /* U coefficient */ + *bRGA2_DST_CSC_10 = msg->full_csc.coe_u.r_v; + *bRGA2_DST_CSC_11 = msg->full_csc.coe_u.g_y; + *bRGA2_DST_CSC_12 = msg->full_csc.coe_u.b_u; + *bRGA2_DST_CSC_OFF1 = msg->full_csc.coe_u.off; + /* V coefficient */ + *bRGA2_DST_CSC_20 = msg->full_csc.coe_v.r_v; + *bRGA2_DST_CSC_21 = msg->full_csc.coe_v.g_y; + *bRGA2_DST_CSC_22 = msg->full_csc.coe_v.b_u; + *bRGA2_DST_CSC_OFF2 = msg->full_csc.coe_v.off; +} + +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_ENDAIN)) | + (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; +} + +int rga2_gen_reg_info(u8 *base, u8 *csc_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 != + RGA2_FORMAT_Y4)) { + RGA2_set_reg_alpha_info(base, msg); + RGA2_set_reg_rop_info(base, msg); + } + + if (msg->full_csc.flag) + RGA2_set_reg_full_csc(csc_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; +} + +void rga_cmd_to_rga2_cmd(struct rga_req *req_rga, struct rga2_req *req) +{ + u16 alpha_mode_0, alpha_mode_1; + + 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)); + + rga_user_format_convert(&req->src.format, req_rga->src.format); + rga_user_format_convert(&req->dst.format, req_rga->dst.format); + rga_user_format_convert(&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; + } + + if ((req->dst.act_w > 2048) && (req->src.act_h < req->dst.act_h)) + req->scale_bicu_mode |= (1 << 4); + + 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)); + memcpy(&req->full_csc, &req_rga->full_csc, sizeof(req_rga->full_csc)); + + req->palette_mode = req_rga->palette_mode; + req->yuv2rgb_mode = req_rga->yuv2rgb_mode; + 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; + + if (((req_rga->alpha_rop_flag) & 1)) { + if ((req_rga->alpha_rop_flag >> 3) & 1) { + /* porter duff alpha enable */ + switch (req_rga->PD_mode) { + /* dst = 0 */ + case 0: + break; + /* dst = src */ + case 1: + req->alpha_mode_0 = 0x0212; + req->alpha_mode_1 = 0x0212; + break; + /* dst = dst */ + case 2: + req->alpha_mode_0 = 0x1202; + req->alpha_mode_1 = 0x1202; + break; + /* dst = (256*sc + (256 - sa)*dc) >> 8 */ + case 3: + if ((req_rga->alpha_rop_mode & 3) == 0) { + /* both use globalAlpha. */ + alpha_mode_0 = 0x3010; + alpha_mode_1 = 0x3010; + } else if ((req_rga->alpha_rop_mode & 3) == 1) { + /* Do not use globalAlpha. */ + alpha_mode_0 = 0x3212; + alpha_mode_1 = 0x3212; + } else if ((req_rga->alpha_rop_mode & 3) == 2) { + /* + * dst use globalAlpha, + * and dst has pixelAlpha. + */ + alpha_mode_0 = 0x3014; + alpha_mode_1 = 0x3014; + } else { + /* + * dst use globalAlpha, and + * dst does not have pixelAlpha. + */ + alpha_mode_0 = 0x3012; + alpha_mode_1 = 0x3012; + } + req->alpha_mode_0 = alpha_mode_0; + req->alpha_mode_1 = alpha_mode_1; + break; + /* dst = (sc*(256-da) + 256*dc) >> 8 */ + case 4: + /* Do not use globalAlpha. */ + req->alpha_mode_0 = 0x1232; + req->alpha_mode_1 = 0x1232; + break; + /* dst = (da*sc) >> 8 */ + case 5: + break; + /* dst = (sa*dc) >> 8 */ + case 6: + break; + /* dst = ((256-da)*sc) >> 8 */ + case 7: + break; + /* dst = ((256-sa)*dc) >> 8 */ + case 8: + break; + /* dst = (da*sc + (256-sa)*dc) >> 8 */ + case 9: + req->alpha_mode_0 = 0x3040; + req->alpha_mode_1 = 0x3040; + break; + /* dst = ((256-da)*sc + (sa*dc)) >> 8 */ + case 10: + break; + /* dst = ((256-da)*sc + (256-sa)*dc) >> 8 */ + case 11: + break; + case 12: + req->alpha_mode_0 = 0x0010; + req->alpha_mode_1 = 0x0820; + break; + default: + break; + } + /* Real color mode */ + if ((req_rga->alpha_rop_flag >> 9) & 1) { + if (req->alpha_mode_0 & (0x01 << 1)) + req->alpha_mode_0 |= (1 << 7); + if (req->alpha_mode_0 & (0x01 << 9)) + req->alpha_mode_0 |= (1 << 15); + } + } else { + if ((req_rga->alpha_rop_mode & 3) == 0) { + req->alpha_mode_0 = 0x3040; + req->alpha_mode_1 = 0x3040; + } else if ((req_rga->alpha_rop_mode & 3) == 1) { + req->alpha_mode_0 = 0x3042; + req->alpha_mode_1 = 0x3242; + } else if ((req_rga->alpha_rop_mode & 3) == 2) { + req->alpha_mode_0 = 0x3044; + req->alpha_mode_1 = 0x3044; + } + } + } + + 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; + } + } + } +} + +void rga2_soft_reset(struct rga_scheduler_t *rga_scheduler) +{ + u32 i; + u32 reg; + + rga_write((1 << 3) | (1 << 4) | (1 << 6), RGA2_SYS_CTRL, rga_scheduler); + + for (i = 0; i < RGA_RESET_TIMEOUT; i++) { + /* RGA_SYS_CTRL */ + reg = rga_read(RGA2_SYS_CTRL, rga_scheduler) & 1; + + if (reg == 0) + break; + + udelay(1); + } + + if (i == RGA_RESET_TIMEOUT) + pr_err("soft reset timeout.\n"); +} + +static int rga2_check_param(const struct rga2_req *req) +{ + if (!((req->render_mode == COLOR_FILL_MODE))) { + if (unlikely + ((req->src.act_w <= 0) || (req->src.act_w > 8192) + || (req->src.act_h <= 0) || (req->src.act_h > 8192))) { + pr_err("invalid src resolution act_w = %d, act_h = %d\n", + req->src.act_w, req->src.act_h); + return -EINVAL; + } + } + + if (!((req->render_mode == COLOR_FILL_MODE))) { + if (unlikely + ((req->src.vir_w <= 0) || (req->src.vir_w > 8192) + || (req->src.vir_h <= 0) || (req->src.vir_h > 8192))) { + pr_err("invalid src resolution vir_w = %d, vir_h = %d\n", + req->src.vir_w, req->src.vir_h); + return -EINVAL; + } + } + + /* check dst width and height */ + if (unlikely + ((req->dst.act_w <= 0) || (req->dst.act_w > 4096) + || (req->dst.act_h <= 0) || (req->dst.act_h > 4096))) { + 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 <= 0) || (req->dst.vir_w > 4096) + || (req->dst.vir_h <= 0) || (req->dst.vir_h > 4096))) { + pr_err("invalid dst resolution vir_w = %d, vir_h = %d\n", + req->dst.vir_w, req->dst.vir_h); + return -EINVAL; + } + //check src_vir_w + 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; + } + //check dst_vir_w + 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 bool rga2_is_yuv10bit_format(uint32_t format) +{ + bool ret = false; + + switch (format) { + case RGA2_FORMAT_YCbCr_420_SP_10B: + case RGA2_FORMAT_YCrCb_420_SP_10B: + case RGA2_FORMAT_YCbCr_422_SP_10B: + case RGA2_FORMAT_YCrCb_422_SP_10B: + ret = true; + break; + } + return ret; +} + +static bool rga2_is_yuv8bit_format(uint32_t format) +{ + bool ret = false; + + switch (format) { + case RGA2_FORMAT_YCbCr_422_SP: + case RGA2_FORMAT_YCbCr_422_P: + case RGA2_FORMAT_YCbCr_420_SP: + case RGA2_FORMAT_YCbCr_420_P: + case RGA2_FORMAT_YCrCb_422_SP: + case RGA2_FORMAT_YCrCb_422_P: + case RGA2_FORMAT_YCrCb_420_SP: + case RGA2_FORMAT_YCrCb_420_P: + ret = true; + break; + } + return ret; +} + +static int rga2_align_check(struct rga2_req *req) +{ + if (rga2_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 (rga2_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 (rga2_is_yuv8bit_format(req->src.format)) + if ((req->src.vir_w % 8) || (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 (rga2_is_yuv8bit_format(req->dst.format)) + if ((req->dst.vir_w % 8) || (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 const char *rga2_get_render_mode_str(u8 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"; + } +} + +static const char *rga2_get_rotate_mode_str(u8 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"; + } +} + +static const char *rga2_get_format_name(uint32_t format) +{ + switch (format) { + case RGA2_FORMAT_RGBA_8888: + return "RGBA8888"; + case RGA2_FORMAT_RGBX_8888: + return "RGBX8888"; + case RGA2_FORMAT_RGB_888: + return "RGB888"; + case RGA2_FORMAT_BGRA_8888: + return "BGRA8888"; + case RGA2_FORMAT_BGRX_8888: + return "BGRX8888"; + case RGA2_FORMAT_BGR_888: + return "BGR888"; + case RGA2_FORMAT_RGB_565: + return "RGB565"; + case RGA2_FORMAT_RGBA_5551: + return "RGBA5551"; + case RGA2_FORMAT_RGBA_4444: + return "RGBA4444"; + case RGA2_FORMAT_BGR_565: + return "BGR565"; + case RGA2_FORMAT_BGRA_5551: + return "BGRA5551"; + case RGA2_FORMAT_BGRA_4444: + return "BGRA4444"; + case RGA2_FORMAT_ARGB_8888: + return "ARGB8888"; + case RGA2_FORMAT_XRGB_8888: + return "XBGR8888"; + case RGA2_FORMAT_ARGB_5551: + return "ARGB5551"; + case RGA2_FORMAT_ARGB_4444: + return "ARGB4444"; + case RGA2_FORMAT_ABGR_8888: + return "ABGR8888"; + case RGA2_FORMAT_XBGR_8888: + return "XBGR8888"; + case RGA2_FORMAT_ABGR_5551: + return "ABGR5551"; + case RGA2_FORMAT_ABGR_4444: + return "ABGR4444"; + + case RGA2_FORMAT_YCbCr_422_SP: + return "YCbCr422SP"; + case RGA2_FORMAT_YCbCr_422_P: + return "YCbCr422P"; + case RGA2_FORMAT_YCbCr_420_SP: + return "YCbCr420SP"; + case RGA2_FORMAT_YCbCr_420_P: + return "YCbCr420P"; + case RGA2_FORMAT_YCrCb_422_SP: + return "YCrCb422SP"; + case RGA2_FORMAT_YCrCb_422_P: + return "YCrCb422P"; + case RGA2_FORMAT_YCrCb_420_SP: + return "YCrCb420SP"; + case RGA2_FORMAT_YCrCb_420_P: + return "YCrCb420P"; + + case RGA2_FORMAT_YVYU_422: + return "YVYU422"; + case RGA2_FORMAT_YVYU_420: + return "YVYU420"; + case RGA2_FORMAT_VYUY_422: + return "VYUY422"; + case RGA2_FORMAT_VYUY_420: + return "VYUY420"; + case RGA2_FORMAT_YUYV_422: + return "YUYV422"; + case RGA2_FORMAT_YUYV_420: + return "YUYV420"; + case RGA2_FORMAT_UYVY_422: + return "UYVY422"; + case RGA2_FORMAT_UYVY_420: + return "UYVY420"; + + case RGA2_FORMAT_YCbCr_420_SP_10B: + return "YCrCb420SP10B"; + case RGA2_FORMAT_YCrCb_420_SP_10B: + return "YCbCr420SP10B"; + case RGA2_FORMAT_YCbCr_422_SP_10B: + return "YCbCr422SP10B"; + case RGA2_FORMAT_YCrCb_422_SP_10B: + return "YCrCb422SP10B"; + case RGA2_FORMAT_BPP_1: + return "BPP1"; + case RGA2_FORMAT_BPP_2: + return "BPP2"; + case RGA2_FORMAT_BPP_4: + return "BPP4"; + case RGA2_FORMAT_BPP_8: + return "BPP8"; + case RGA2_FORMAT_YCbCr_400: + return "YCbCr400"; + case RGA2_FORMAT_Y4: + return "y4"; + default: + return "UNF"; + } +} + +static const char *rga2_get_blend_mode_str(u16 alpha_rop_flag, u16 alpha_mode_0, + u16 alpha_mode_1) +{ + if (alpha_rop_flag == 0) { + return "no blend"; + } else if (alpha_rop_flag == 0x9) { + if (alpha_mode_0 == 0x381A && alpha_mode_1 == 0x381A) + return "105 src + (1-src.a)*dst"; + else if (alpha_mode_0 == 0x483A && alpha_mode_1 == 0x483A) + return "405 src.a * src + (1-src.a) * dst"; + else + return "check reg for more imformation"; + } else { + return "check reg for more imformation"; + } +} + +static void print_debug_info(struct rga2_req *req) +{ + pr_info("render_mode:%s,bitblit_mode=%d,rotate_mode:%s\n", + rga2_get_render_mode_str(req->render_mode), req->bitblt_mode, + rga2_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, + rga2_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, + rga2_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, + rga2_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 mode0=%x mode1=%x\n", req->alpha_rop_flag, + req->alpha_mode_0, req->alpha_mode_1); + pr_info("blend mode is %s\n", + rga2_get_blend_mode_str(req->alpha_rop_flag, req->alpha_mode_0, + req->alpha_mode_1)); + pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode); +} + +int rga2_init_reg(struct rga_job *job) +{ + struct rga2_req req; + int ret = 0; + struct rga2_mmu_info_t *tbuf = &rga2_mmu_info; + struct rga_scheduler_t *scheduler = NULL; + + scheduler = rga_job_get_scheduler(job->core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + return ret; + } + + memset(&req, 0x0, sizeof(req)); + + rga_cmd_to_rga2_cmd(&job->rga_command_base, &req); + + /* check value if legal */ + ret = rga2_check_param(&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)) { + ret = rga2_set_mmu_reg_info(&job->vir_page_table, &req, job); + if (ret < 0) { + pr_err("%s, [%d] set mmu info error\n", __func__, + __LINE__); + return -EFAULT; + } + } + + mutex_lock(&rga_drvdata->lock); + + if (job->vir_page_table.MMU_len && tbuf) { + if (tbuf->back + job->vir_page_table.MMU_len > 2 * tbuf->size) + tbuf->back = job->vir_page_table.MMU_len + tbuf->size; + else + tbuf->back += job->vir_page_table.MMU_len; + } + + mutex_unlock(&rga_drvdata->lock); + + if (rga2_gen_reg_info((uint8_t *)job->cmd_reg, + (uint8_t *)job->csc_reg, &req) == -1) { + pr_err("gen reg info error\n"); + return -EINVAL; + } + + return ret; +} + +static void rga_dma_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); +} + +static void rga2_dump_read_back_reg(struct rga_scheduler_t *scheduler) +{ + int i; + unsigned long flags; + uint32_t cmd_reg[32] = {0}; + uint32_t csc_reg[12] = {0}; + + spin_lock_irqsave(&scheduler->irq_lock, flags); + + for (i = 0; i < 32; i++) + cmd_reg[i] = rga_read(0x100 + i * 4, scheduler); + + for (i = 0; i < 12; i++) + csc_reg[i] = rga_read(RGA2_CSC_COE_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("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]); + + pr_info("CSC_READ_BACK_REG\n"); + for (i = 0; i < 3; i++) + pr_info("%.8x %.8x %.8x %.8x\n", + csc_reg[0 + i * 4], csc_reg[1 + i * 4], + csc_reg[2 + i * 4], csc_reg[3 + i * 4]); +} + +int rga2_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) +{ + ktime_t now = ktime_get(); + int i; + + rga_dma_flush_range(&job->cmd_reg[0], &job->cmd_reg[32], scheduler); + + rga_write(0x0, RGA2_SYS_CTRL, scheduler); + +#ifndef CONFIG_ROCKCHIP_FPGA + /* CMD buff */ + rga_write(virt_to_phys(job->cmd_reg), RGA2_CMD_BASE, scheduler); +#else + + /* slave mode */ + { + int32_t m, *cmd; + + cmd = job->cmd_reg; + pr_info("set reg\n"); + for (m = 0; m <= 32; m++) + rga_write(cmd[m], 0x100 + m * 4, scheduler); + } + +#endif + + /* full csc reg */ + for (i = 0; i < 12; i++) { + rga_write(job->csc_reg[i], RGA2_CSC_COE_BASE + i * 4, + scheduler); + } + + if (DEBUGGER_EN(REG)) { + int32_t *p; + + 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]); + + p = job->csc_reg; + pr_info("CSC_REG\n"); + for (i = 0; i < 3; i++) + pr_info("%.8x %.8x %.8x %.8x\n", + p[0 + i * 4], p[1 + i * 4], + p[2 + i * 4], p[3 + i * 4]); + } + +#ifndef CONFIG_ROCKCHIP_FPGA + /* master mode */ + rga_write((0x1 << 1) | (0x1 << 2) | (0x1 << 5) | (0x1 << 6), + RGA2_SYS_CTRL, scheduler); +#else + /* slave mode */ + rga_write((0x0 << 1) | (0x1 << 2) | (0x1 << 5) | (0x1 << 6), + RGA2_SYS_CTRL, scheduler); +#endif + + /* All CMD finish int */ + rga_write(rga_read(RGA2_INT, scheduler) | (0x1 << 10) | (0x1 << 9) | + (0x1 << 8), RGA2_INT, scheduler); + + if (DEBUGGER_EN(TIME)) { + pr_err("sys_ctrl = %x, int = %x, set cmd use time = %lld\n", + rga_read(RGA2_SYS_CTRL, scheduler), + rga_read(RGA2_INT, scheduler), + ktime_to_us(ktime_sub(now, job->running_time))); + } + + job->timestamp = now; + job->running_time = now; + + rga_write(1, RGA2_CMD_CTRL, scheduler); + + if (DEBUGGER_EN(REG)) + rga2_dump_read_back_reg(scheduler); + + return 0; +} + +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; +} 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 000000000000..ee63ea227387 --- /dev/null +++ b/drivers/video/rockchip/rga3/rga3_reg_info.c @@ -0,0 +1,2126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#define pr_fmt(fmt) "rga3_reg: " fmt + +#include "rga3_reg_info.h" +#include "rga_common.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) { + switch (msg->rotate_mode) { + /* rot 90 */ + case 0x1: + rotate_mode = 1; + break; + /* rot 180 */ + case 0x2: + xmirror = 1; + ymirror = 1; + break; + /* rot 270 or rot -90 */ + case 0x3: + rotate_mode = 1; + xmirror = 1; + ymirror = 1; + break; + /* ymirror */ + case 0x4: + ymirror = 1; + break; + /* xmirror */ + case 0x5: + xmirror = 1; + break; + /* rot 90 + xmirror */ + case 0x6: + rotate_mode = 1; + xmirror = 1; + break; + /* rot 90 + ymirror */ + case 0x7: + rotate_mode = 1; + ymirror = 1; + break; + /* bypass */ + default: + break; + }; + } + + /* scale */ + dw = msg->win0.dst_act_w; + dh = msg->win0.dst_act_h; + + if (msg->win0.rotate_mode != 0) { + if (msg->rotate_mode == 1 || msg->rotate_mode == 3 || + msg->rotate_mode == 6 || msg->rotate_mode == 7) { + 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); + if ((sw - 1) % (dw - 1) == 0) { + pr_err("hor_up_fac modify xxxx\n"); + 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); + if ((sh - 1) % (dh - 1) == 0) { + pr_err("ver_up_fac modify yyyy\n"); + param_y = param_y - 1; + } + } else + param_y = FACTOR_MAX * (dh - 1) / (sh - 1) + 1; + + switch (msg->win0.format) { + case RGA2_FORMAT_RGBA_8888: + win_format = 0x8; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_BGRA_8888: + win_format = 0x6; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_ARGB_8888: + win_format = 0x9; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_ABGR_8888: + win_format = 0x7; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_RGB_888: + win_format = 0x5; + pixel_width = 3; + win_interleaved = 2; + win_pix_swp = 1; + break; + case RGA2_FORMAT_BGR_888: + win_format = 0x5; + pixel_width = 3; + win_interleaved = 2; + break; + case RGA2_FORMAT_RGB_565: + win_format = 0x4; + pixel_width = 2; + win_interleaved = 2; + win_pix_swp = 1; + break; + case RGA2_FORMAT_BGR_565: + win_format = 0x4; + pixel_width = 2; + win_interleaved = 2; + break; + + case RGA2_FORMAT_YVYU_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 1; + win_yc_swp = 1; + win_interleaved = 2; + break; + case RGA2_FORMAT_VYUY_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 1; + win_yc_swp = 0; + win_interleaved = 2; + break; + case RGA2_FORMAT_YUYV_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 0; + win_yc_swp = 1; + win_interleaved = 2; + break; + case RGA2_FORMAT_UYVY_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 0; + win_yc_swp = 0; + win_interleaved = 2; + break; + + case RGA2_FORMAT_YCbCr_422_SP: + win_format = 0x1; + break; + case RGA2_FORMAT_YCbCr_420_SP: + win_format = 0x0; + break; + case RGA2_FORMAT_YCrCb_422_SP: + win_format = 0x1; + win_pix_swp = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP: + win_format = 0x0; + win_pix_swp = 1; + break; + + case RGA2_FORMAT_YCbCr_420_SP_10B: + win_format = 0x2; + yuv10 = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP_10B: + win_format = 0x2; + yuv10 = 1; + win_pix_swp = 1; + break; + case RGA2_FORMAT_YCbCr_422_SP_10B: + win_format = 0x3; + yuv10 = 1; + break; + case RGA2_FORMAT_YCrCb_422_SP_10B: + win_format = 0x3; + yuv10 = 1; + win_pix_swp = 1; + break; + }; + + if (msg->win0.format <= RGA2_FORMAT_BGRA_4444 + && msg->wr.format > RGA2_FORMAT_BGRA_4444) + win_r2y = 1; + if (msg->win0.format >= RGA2_FORMAT_BGRA_4444 + && msg->wr.format < RGA2_FORMAT_BGRA_4444) + 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->win1.yrgb_addr == 0) { + 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))); + } else { + reg = + ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY)) | + (s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY(1))); + reg = + ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP)) | + (s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP(0))); + reg = + ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY)) | + (s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY(1))); + reg = + ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP)) | + (s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP(0))); + } + + /* 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 roster 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; + + /* stride need align to 16 */ + if (msg->win0.rd_mode != 1) + stride = (((msg->win0.vir_w * pixel_width) + 15) & ~15) >> 2; + else + stride = ((msg->win0.vir_w + 15) & ~15) >> 2; + + if (msg->win0.format == RGA2_FORMAT_YCbCr_420_SP + || msg->win0.format == RGA2_FORMAT_YCrCb_420_SP + || msg->win0.format == RGA2_FORMAT_YCbCr_420_SP_10B + || msg->win0.format == RGA2_FORMAT_YCrCb_420_SP_10B) + uv_stride = ((msg->win0.vir_w + 15) & ~15) >> 2; + else + uv_stride = stride; + + *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 */ + *bRGA3_WIN0_SRC_SIZE = (msg->win0.src_act_w + + msg->win0.x_offset) | ((msg->win0.y_offset + + msg->win0.src_act_h) << 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) { + switch (msg->rotate_mode) { + /* rot 90 */ + case 0x1: + rotate_mode = 1; + break; + /* rot 180 */ + case 0x2: + xmirror = 1; + ymirror = 1; + break; + /* rot 270 or rot -90 */ + case 0x3: + rotate_mode = 1; + xmirror = 1; + ymirror = 1; + break; + /* ymirror */ + case 0x4: + ymirror = 1; + break; + /* xmirror */ + case 0x5: + xmirror = 1; + break; + /* rot 90 + xmirror */ + case 0x6: + rotate_mode = 1; + xmirror = 1; + break; + /* rot 90 + ymirror */ + case 0x7: + rotate_mode = 1; + ymirror = 1; + break; + /* bypass */ + }; + } + + /* scale */ + dw = msg->win1.dst_act_w; + dh = msg->win1.dst_act_h; + + if (msg->rotate_mode == 1 || msg->rotate_mode == 3 || + msg->rotate_mode == 6 || msg->rotate_mode == 7) { + 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); + if ((sw - 1) % (dw - 1) == 0) { + pr_err("hor_up_fac modify xxxx\n"); + 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); + if ((sh - 1) % (dh - 1) == 0) { + pr_err("ver_up_fac modify yyyy\n"); + param_y = param_y - 1; + } + } else + param_y = (FACTOR_MAX * (dh - 1)) / (sh - 1) + 1; + + switch (msg->win1.format) { + case RGA2_FORMAT_RGBA_8888: + win_format = 0x8; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_BGRA_8888: + win_format = 0x6; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_ARGB_8888: + win_format = 0x9; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_ABGR_8888: + win_format = 0x7; + pixel_width = 4; + win_interleaved = 2; + break; + case RGA2_FORMAT_RGB_888: + win_format = 0x5; + pixel_width = 3; + win_interleaved = 2; + win_pix_swp = 1; + break; + case RGA2_FORMAT_BGR_888: + win_format = 0x5; + pixel_width = 3; + win_interleaved = 2; + break; + case RGA2_FORMAT_RGB_565: + win_format = 0x4; + pixel_width = 2; + win_interleaved = 2; + win_pix_swp = 1; + break; + case RGA2_FORMAT_BGR_565: + win_format = 0x4; + pixel_width = 2; + win_interleaved = 2; + break; + + case RGA2_FORMAT_YVYU_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 1; + win_yc_swp = 1; + win_interleaved = 2; + break; + case RGA2_FORMAT_VYUY_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 1; + win_yc_swp = 0; + win_interleaved = 2; + break; + case RGA2_FORMAT_YUYV_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 0; + win_yc_swp = 1; + win_interleaved = 2; + break; + case RGA2_FORMAT_UYVY_422: + win_format = 0x1; + pixel_width = 2; + win_pix_swp = 0; + win_yc_swp = 0; + win_interleaved = 2; + break; + + case RGA2_FORMAT_YCbCr_422_SP: + win_format = 0x1; + break; + case RGA2_FORMAT_YCbCr_420_SP: + win_format = 0x0; + break; + case RGA2_FORMAT_YCrCb_422_SP: + win_format = 0x1; + win_pix_swp = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP: + win_format = 0x0; + win_pix_swp = 1; + break; + + case RGA2_FORMAT_YCbCr_420_SP_10B: + win_format = 0x2; + yuv10 = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP_10B: + win_format = 0x2; + win_pix_swp = 1; + yuv10 = 1; + break; + case RGA2_FORMAT_YCbCr_422_SP_10B: + win_format = 0x3; + yuv10 = 1; + break; + case RGA2_FORMAT_YCrCb_422_SP_10B: + win_format = 0x3; + win_pix_swp = 1; + yuv10 = 1; + break; + }; + + if (msg->win1.format <= RGA2_FORMAT_BGR_565 + && msg->wr.format > RGA2_FORMAT_BGR_565) + win_r2y = 1; + if (msg->win1.format >= RGA2_FORMAT_BGR_565 + && msg->wr.format < RGA2_FORMAT_BGR_565) + 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; + + /* stride need align to 16 */ + if (msg->win1.rd_mode != 1) + stride = (((msg->win1.vir_w * pixel_width) + 15) & ~15) >> 2; + else + stride = ((msg->win1.vir_w + 15) & ~15) >> 2; + + if (msg->win1.format == RGA2_FORMAT_YCbCr_420_SP + || msg->win1.format == RGA2_FORMAT_YCrCb_420_SP + || msg->win1.format == RGA2_FORMAT_YCbCr_420_SP_10B + || msg->win1.format == RGA2_FORMAT_YCrCb_420_SP_10B) + uv_stride = ((msg->win1.vir_w + 15) & ~15) >> 2; + else + uv_stride = stride; + + *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 RGA2_FORMAT_RGBA_8888: + wr_format = 0x6; + pixel_width = 4; + wr_interleaved = 2; + wr_pix_swp = 1; + break; + case RGA2_FORMAT_BGRA_8888: + wr_format = 0x6; + pixel_width = 4; + wr_interleaved = 2; + break; + case RGA2_FORMAT_RGB_888: + wr_format = 0x5; + pixel_width = 3; + wr_interleaved = 2; + wr_pix_swp = 1; + break; + case RGA2_FORMAT_BGR_888: + wr_format = 0x5; + pixel_width = 3; + wr_interleaved = 2; + break; + case RGA2_FORMAT_RGB_565: + wr_format = 0x4; + pixel_width = 2; + wr_interleaved = 2; + wr_pix_swp = 1; + break; + case RGA2_FORMAT_BGR_565: + wr_format = 0x4; + pixel_width = 2; + wr_interleaved = 2; + break; + + case RGA2_FORMAT_YVYU_422: + wr_format = 0x1; + pixel_width = 2; + wr_pix_swp = 1; + wr_yc_swp = 1; + wr_interleaved = 2; + break; + case RGA2_FORMAT_VYUY_422: + wr_format = 0x1; + pixel_width = 2; + wr_pix_swp = 1; + wr_yc_swp = 0; + wr_interleaved = 2; + break; + case RGA2_FORMAT_YUYV_422: + wr_format = 0x1; + pixel_width = 2; + wr_pix_swp = 0; + wr_yc_swp = 1; + wr_interleaved = 2; + break; + case RGA2_FORMAT_UYVY_422: + wr_format = 0x1; + pixel_width = 2; + wr_pix_swp = 0; + wr_yc_swp = 0; + wr_interleaved = 2; + break; + + case RGA2_FORMAT_YCbCr_422_SP: + wr_format = 0x1; + break; + case RGA2_FORMAT_YCbCr_420_SP: + wr_format = 0x0; + break; + case RGA2_FORMAT_YCrCb_422_SP: + wr_format = 0x1; + wr_pix_swp = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP: + wr_format = 0x0; + wr_pix_swp = 1; + break; + + case RGA2_FORMAT_YCbCr_420_SP_10B: + wr_format = 0x2; + yuv10 = 1; + break; + case RGA2_FORMAT_YCrCb_420_SP_10B: + wr_format = 0x2; + wr_pix_swp = 1; + yuv10 = 1; + break; + case RGA2_FORMAT_YCbCr_422_SP_10B: + wr_format = 0x3; + yuv10 = 1; + break; + case RGA2_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(0))); + + 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; + + /* stride need align to 16 */ + if (msg->wr.rd_mode != 1) { + stride = (((msg->wr.vir_w * pixel_width) + 15) & ~15) >> 2; + *bRGA3_WR_U_BASE = (u32) msg->wr.uv_addr; + uv_stride = ((msg->wr.vir_w + 15) & ~15) >> 2; + } else { + stride = ((msg->wr.vir_w + 15) & ~15) >> 2; + /* need to calculate fbcd header size */ + vir_h = ((msg->wr.vir_h + 15) & ~15); + *bRGA3_WR_U_BASE = (u32) (msg->wr.uv_addr + ((stride * vir_h)>>2)); + /* 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_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; + + 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). */ + reg = 0; + reg = + ((reg & (~m_RGA3_OVLP_TOP_CTRL_SW_TOP_COLOR_M0)) | + (s_RGA3_OVLP_TOP_CTRL_SW_TOP_COLOR_M0 + (msg->alpha_mode_0 >> 7))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_M0)) | + (s_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_M0 + (msg->alpha_mode_0 >> 0))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_CTRL_SW_TOP_BLEND_M0)) | + (s_RGA3_OVLP_TOP_CTRL_SW_TOP_BLEND_M0 + (msg->alpha_mode_0 >> 1))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_CAL_M0)) | + (s_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_CAL_M0 + (msg->alpha_mode_0 >> 3))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_CTRL_SW_TOP_FACTOR_M0)) | + (s_RGA3_OVLP_TOP_CTRL_SW_TOP_FACTOR_M0 + (msg->alpha_mode_0 >> 4))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_CTRL_SW_TOP_GLOBAL_ALPHA)) | + (s_RGA3_OVLP_TOP_CTRL_SW_TOP_GLOBAL_ALPHA + (msg->win1_a_global_val))); + *bRGA_OVERLAP_TOP_CTRL = reg; + + reg = 0; + reg = + ((reg & (~m_RGA3_OVLP_BOT_CTRL_SW_BOT_COLOR_M0)) | + (s_RGA3_OVLP_BOT_CTRL_SW_BOT_COLOR_M0 + (msg->alpha_mode_0 >> 15))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_M0)) | + (s_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_M0 + (msg->alpha_mode_0 >> 8))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_CTRL_SW_BOT_BLEND_M0)) | + (s_RGA3_OVLP_BOT_CTRL_SW_BOT_BLEND_M0 + (msg->alpha_mode_0 >> 9))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_CAL_M0)) | + (s_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_CAL_M0 + (msg->alpha_mode_0 >> 11))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_CTRL_SW_BOT_FACTOR_M0)) | + (s_RGA3_OVLP_BOT_CTRL_SW_BOT_FACTOR_M0 + (msg->alpha_mode_0 >> 12))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_CTRL_SW_BOT_GLOBAL_ALPHA)) | + (s_RGA3_OVLP_BOT_CTRL_SW_BOT_GLOBAL_ALPHA + (msg->win0_a_global_val))); + *bRGA_OVERLAP_BOT_CTRL = reg; + + reg = 0; + reg = + ((reg & (~m_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_M1)) | + (s_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_M1 + (msg->alpha_mode_1 >> 0))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_ALPHA_SW_TOP_BLEND_M1)) | + (s_RGA3_OVLP_TOP_ALPHA_SW_TOP_BLEND_M1 + (msg->alpha_mode_1 >> 1))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_CAL_M1)) | + (s_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_CAL_M1 + (msg->alpha_mode_1 >> 3))); + reg = + ((reg & (~m_RGA3_OVLP_TOP_ALPHA_SW_TOP_FACTOR_M1)) | + (s_RGA3_OVLP_TOP_ALPHA_SW_TOP_FACTOR_M1 + (msg->alpha_mode_1 >> 4))); + *bRGA_OVERLAP_TOP_ALPHA = reg; + + reg = 0; + reg = + ((reg & (~m_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_M1)) | + (s_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_M1 + (msg->alpha_mode_1 >> 8))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_ALPHA_SW_BOT_BLEND_M1)) | + (s_RGA3_OVLP_BOT_ALPHA_SW_BOT_BLEND_M1 + (msg->alpha_mode_1 >> 9))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_CAL_M1)) | + (s_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_CAL_M1 + (msg->alpha_mode_1 >> 11))); + reg = + ((reg & (~m_RGA3_OVLP_BOT_ALPHA_SW_BOT_FACTOR_M1)) | + (s_RGA3_OVLP_BOT_ALPHA_SW_BOT_FACTOR_M1 + (msg->alpha_mode_1 >> 12))); + + *bRGA_OVERLAP_BOT_ALPHA = reg; + + /* 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 (msg->wr.format >= RGA2_FORMAT_BGR_565) + 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 + */ + if (msg->alpha_mode_1 > 0 && msg->alpha_mode_0 > 0) + reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN)) | + (s_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN(1))); + + *bRGA_OVERLAP_CTRL = reg; + + *bRGA3_OVLP_OFF = msg->wr.x_offset | (msg->wr.y_offset << 16); +} + +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; + + win->is_10b_compact = img->is_10b_compact; + 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; + + req->wr.is_10b_compact = req_rga->dst.is_10b_compact; + req->wr.is_10b_endian = req_rga->dst.is_10b_endian; +} + +/* TODO: common part */ +void rga_cmd_to_rga3_cmd(struct rga_req *req_rga, struct rga3_req *req) +{ + u16 alpha_mode_0, alpha_mode_1; + + 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 = 1; + } else if (req_rga->sina == 0 && req_rga->cosa == -65536) { + /* rot 180 */ + req->rotate_mode = 2; + } else if (req_rga->sina == -65536 && req_rga->cosa == 0) { + /* rot 270 or -90 */ + req->rotate_mode = 3; + } else if (req_rga->sina == 0 && req_rga->cosa == 65536) { + /* bypass */ + req->rotate_mode = 0; + } + break; + case 0x2: + /* xmirror */ + req->rotate_mode = 5; + break; + case 0x3: + /* ymirror */ + req->rotate_mode = 4; + break; + case 0x4: + /* x+y mirror = rot 180 */ + req->rotate_mode = 2; + break; + default: + req->rotate_mode = 0; + break; + } + + switch ((req_rga->rotate_mode & 0xf0) >> 4) { + /* xmirror */ + case 2: + if (req->rotate_mode == 1) { + /* xmirror + rot 90 */ + req->rotate_mode = 6; + } + break; + /* ymirror */ + case 3: + if (req->rotate_mode == 1) { + /* ymirror + rot 90 */ + req->rotate_mode = 7; + } + break; + } + + /* default use 2 reg, bot_blend_m1 && bot_alpha_cal_m1 */ + if (req_rga->src.format == RGA2_FORMAT_RGBA_8888) + req->alpha_mode_1 = 0x0a00; + + /* 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)) { + 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); + + rga_user_format_convert(&req->win0.format, req_rga->src.format); + rga_user_format_convert(&req->wr.format, req_rga->dst.format); + } else { + /* A+B->C */ + if (req_rga->pat.yrgb_addr != 0) { + set_win_info(&req->win0, &req_rga->pat); + 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->win0, &req_rga->pat); + addr_copy(&req->wr, &req_rga->dst); + + rga_user_format_convert(&req->win0.format, req_rga->src.format); + rga_user_format_convert(&req->wr.format, req_rga->dst.format); + rga_user_format_convert(&req->win1.format, req_rga->pat.format); + + } else { + /* A+B->B */ + set_win_info(&req->win1, &req_rga->src); + set_win_info(&req->win0, &req_rga->dst); + + /* enable win1 rotate */ + req->win1.rotate_mode = 1; + /* only win1 && wr support fbcd, win0 default raster */ + req->win0.rd_mode = 0; + + addr_copy(&req->win1, &req_rga->src); + addr_copy(&req->win0, &req_rga->dst); + addr_copy(&req->wr, &req_rga->dst); + + rga_user_format_convert(&req->win1.format, req_rga->src.format); + rga_user_format_convert(&req->wr.format, req_rga->dst.format); + rga_user_format_convert(&req->win0.format, req_rga->dst.format); + } + + /* 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 == 1 || req->rotate_mode == 3 || + req->rotate_mode == 6 || req->rotate_mode == 7) { + 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) { + /* porter duff alpha enable */ + switch (req_rga->PD_mode) { + /* dst = 0 */ + case 0: + break; + /* dst = src */ + case 1: + req->alpha_mode_0 = 0x0212; + req->alpha_mode_1 = 0x0212; + break; + /* dst = dst */ + case 2: + req->alpha_mode_0 = 0x1202; + req->alpha_mode_1 = 0x1202; + break; + /* dst = (256*sc + (256 - sa)*dc) >> 8 */ + case 3: + if ((req_rga->alpha_rop_mode & 3) == 0) { + /* both use globalAlpha. */ + alpha_mode_0 = 0x3010; + alpha_mode_1 = 0x3010; + } else if ((req_rga->alpha_rop_mode & 3) == 1) { + /* Do not use globalAlpha. */ + alpha_mode_0 = 0x3212; + alpha_mode_1 = 0x3212; + } else if ((req_rga->alpha_rop_mode & 3) == 2) { + /* + * dst use globalAlpha, + * and dst has pixelAlpha. + */ + alpha_mode_0 = 0x3014; + alpha_mode_1 = 0x3014; + } else { + /* + * dst use globalAlpha, + * and dst does not have pixelAlpha. + */ + alpha_mode_0 = 0x3012; + alpha_mode_1 = 0x3012; + } + req->alpha_mode_0 = alpha_mode_0; + req->alpha_mode_1 = alpha_mode_1; + break; + /* dst = (sc*(256-da) + 256*dc) >> 8 */ + case 4: + /* Do not use globalAlpha. */ + req->alpha_mode_0 = 0x1232; + req->alpha_mode_1 = 0x1232; + break; + /* dst = (da*sc) >> 8 */ + case 5: + break; + /* dst = (sa*dc) >> 8 */ + case 6: + break; + /* dst = ((256-da)*sc) >> 8 */ + case 7: + break; + /* dst = ((256-sa)*dc) >> 8 */ + case 8: + break; + /* dst = (da*sc + (256-sa)*dc) >> 8 */ + case 9: + req->alpha_mode_0 = 0x3040; + req->alpha_mode_1 = 0x3040; + break; + /* dst = ((256-da)*sc + (sa*dc)) >> 8 */ + case 10: + break; + /* dst = ((256-da)*sc + (256-sa)*dc) >> 8 */ + case 11: + break; + case 12: + req->alpha_mode_0 = 0x0010; + req->alpha_mode_1 = 0x0820; + break; + default: + break; + } + /* Real color mode */ + if ((req_rga->alpha_rop_flag >> 9) & 1) { + if (req->alpha_mode_0 & (0x01 << 1)) + req->alpha_mode_0 |= (1 << 7); + if (req->alpha_mode_0 & (0x01 << 9)) + req->alpha_mode_0 |= (1 << 15); + } + } else { + if ((req_rga->alpha_rop_mode & 3) == 0) { + req->alpha_mode_0 = 0x3040; + req->alpha_mode_1 = 0x3040; + } else if ((req_rga->alpha_rop_mode & 3) == 1) { + req->alpha_mode_0 = 0x3042; + req->alpha_mode_1 = 0x3242; + } else if ((req_rga->alpha_rop_mode & 3) == 2) { + req->alpha_mode_0 = 0x3044; + req->alpha_mode_1 = 0x3044; + } + } + } + + req->win0_a_global_val = req_rga->alpha_global_value; + req->win1_a_global_val = req_rga->alpha_global_value; + + /* 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 */ + req->color_key_min = req_rga->color_key_min; + req->color_key_max = req_rga->color_key_max; + + 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; + } +} + +void rga3_soft_reset(struct rga_scheduler_t *scheduler) +{ + u32 i; + u32 reg; + u32 mmu_addr; + + mmu_addr = rga_read(0xf00, scheduler); + + rga_write((1 << 3) | (1 << 4), RGA3_SYS_CTRL, scheduler); + + pr_err("soft reset sys_ctrl = %x, ro_rest = %x", + rga_read(RGA3_SYS_CTRL, scheduler), + rga_read(RGA3_RO_SRST, scheduler)); + + mdelay(20); + + pr_err("soft reset sys_ctrl = %x, ro_rest = %x", + rga_read(RGA3_SYS_CTRL, scheduler), + rga_read(RGA3_RO_SRST, scheduler)); + + rga_write((0 << 3) | (0 << 4), RGA3_SYS_CTRL, scheduler); + + pr_err("soft after reset sys_ctrl = %x, ro_rest = %x", + rga_read(RGA3_SYS_CTRL, scheduler), + rga_read(RGA3_RO_SRST, scheduler)); + + rga_write(1, RGA3_INT_CLR, scheduler); + + rga_write(mmu_addr, 0xf00, scheduler); + rga_write(0, 0xf08, scheduler); + + if (DEBUGGER_EN(INT_FLAG)) + pr_info("irq INT[%x], STATS0[%x], STATS1[%x]\n", + rga_read(RGA3_INT_RAW, scheduler), + rga_read(RGA3_STATUS0, scheduler), + rga_read(RGA3_STATUS1, scheduler)); + + for (i = 0; i < RGA_RESET_TIMEOUT; i++) { + reg = rga_read(RGA3_SYS_CTRL, scheduler) & 1; + + if (reg == 0) + break; + + udelay(1); + } + + if (i == RGA_RESET_TIMEOUT) + pr_err("soft reset timeout.\n"); +} + +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 rga3_req *req) +{ + if (!((req->render_mode == COLOR_FILL_MODE))) { + if (unlikely((req->win0.src_act_w <= 0) || + (req->win0.src_act_w > 8176) + || (req->win0.src_act_h <= 0) + || (req->win0.src_act_h > 8176) + || (req->win0.dst_act_w <= 0) + || (req->win0.dst_act_w > 8128) + || (req->win0.dst_act_h <= 0) + || (req->win0.dst_act_h > 8128))) { + pr_err("invalid win0 act sw = %d, sh = %d, dw = %d, dh = %d\n", + req->win0.src_act_w, req->win0.src_act_h, + req->win0.dst_act_w, req->win0.dst_act_h); + return -EINVAL; + } + } + + if (req->win1.yrgb_addr != 0) { + if (unlikely((req->win1.src_act_w <= 0) || + (req->win1.src_act_w > 8176) + || (req->win1.src_act_h <= 0) + || (req->win1.src_act_h > 8176) + || (req->win1.dst_act_w <= 0) + || (req->win1.dst_act_w > 8128) + || (req->win1.dst_act_h <= 0) + || (req->win1.dst_act_h > 8128))) { + pr_err("invalid win1 act sw = %d, sh = %d, dw = %d, dh = %d\n", + req->win1.src_act_w, req->win1.src_act_h, + req->win1.dst_act_w, req->win1.dst_act_h); + return -EINVAL; + } + + if (unlikely + ((req->win1.vir_w <= 0) || (req->win1.vir_w > 8192 * 2) + || (req->win1.vir_h <= 0) + || (req->win1.vir_h > 8192 * 2))) { + pr_err("invalid win1 stride vir_w = %d, vir_h = %d\n", + req->win1.vir_w, req->win1.vir_h); + 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 win1.dst size = %d x %d\n", + req->win1.dst_act_w, req->win1.dst_act_h); + pr_err("invalid win0.dst size = %d x %d\n", + req->win0.dst_act_w, req->win0.dst_act_h); + return -EINVAL; + } + } + } + + if (!((req->render_mode == COLOR_FILL_MODE))) { + if (unlikely + ((req->win0.vir_w <= 0) || (req->win0.vir_w > 8192) + || (req->win0.vir_h <= 0) + || (req->win0.vir_h > 8192))) { + pr_err("invalid win0 vir_w = %d, vir_h = %d\n", + req->win0.vir_w, req->win0.vir_h); + return -EINVAL; + } + } + + if (unlikely + ((req->wr.vir_w <= 0) || (req->wr.vir_w > 8192 * 2) + || (req->wr.vir_h <= 0) || (req->wr.vir_h > 8192 * 2))) { + pr_err("invalid wr vir_w = %d, vir_h = %d\n", + req->wr.vir_w, req->wr.vir_h); + return -EINVAL; + } + + if (rga3_scale_check(req) < 0) + return -EINVAL; + + return 0; +} + +static const char *rga3_get_blend_mode_str(u16 alpha_rop_flag, u16 alpha_mode_0, + u16 alpha_mode_1) +{ + if (alpha_rop_flag == 0) { + return "no blend"; + } else if (alpha_rop_flag == 0x9) { + if (alpha_mode_0 == 0x381A && alpha_mode_1 == 0x381A) + return "105 src + (1-src.a)*dst"; + else if (alpha_mode_0 == 0x483A && alpha_mode_1 == 0x483A) + return "405 src.a * src + (1-src.a) * dst"; + else + return "check reg for more imformation"; + } else { + return "check reg for more imformation"; + } +} + +static const char *rga3_get_render_mode_str(u8 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"; + } +} + +static bool rga3_is_yuv10bit_format(uint32_t format) +{ + bool ret = false; + + switch (format) { + case RGA2_FORMAT_YCbCr_420_SP_10B: + case RGA2_FORMAT_YCrCb_420_SP_10B: + case RGA2_FORMAT_YCbCr_422_SP_10B: + case RGA2_FORMAT_YCrCb_422_SP_10B: + ret = true; + break; + } + return ret; +} + +static bool rga3_is_yuv8bit_format(uint32_t format) +{ + bool ret = false; + + switch (format) { + case RGA2_FORMAT_YCbCr_422_SP: + case RGA2_FORMAT_YCbCr_422_P: + case RGA2_FORMAT_YCbCr_420_SP: + case RGA2_FORMAT_YCbCr_420_P: + case RGA2_FORMAT_YCrCb_422_SP: + case RGA2_FORMAT_YCrCb_422_P: + case RGA2_FORMAT_YCrCb_420_SP: + case RGA2_FORMAT_YCrCb_420_P: + ret = true; + break; + } + return ret; +} + +static const char *rga3_get_format_name(uint32_t format) +{ + switch (format) { + case RGA2_FORMAT_RGBA_8888: + return "RGBA8888"; + case RGA2_FORMAT_RGBX_8888: + return "RGBX8888"; + case RGA2_FORMAT_RGB_888: + return "RGB888"; + case RGA2_FORMAT_BGRA_8888: + return "BGRA8888"; + case RGA2_FORMAT_BGRX_8888: + return "BGRX8888"; + case RGA2_FORMAT_BGR_888: + return "BGR888"; + case RGA2_FORMAT_RGB_565: + return "RGB565"; + case RGA2_FORMAT_RGBA_5551: + return "RGBA5551"; + case RGA2_FORMAT_RGBA_4444: + return "RGBA4444"; + case RGA2_FORMAT_BGR_565: + return "BGR565"; + case RGA2_FORMAT_BGRA_5551: + return "BGRA5551"; + case RGA2_FORMAT_BGRA_4444: + return "BGRA4444"; + + case RGA2_FORMAT_YCbCr_422_SP: + return "YCbCr422SP"; + case RGA2_FORMAT_YCbCr_422_P: + return "YCbCr422P"; + case RGA2_FORMAT_YCbCr_420_SP: + return "YCbCr420SP"; + case RGA2_FORMAT_YCbCr_420_P: + return "YCbCr420P"; + case RGA2_FORMAT_YCrCb_422_SP: + return "YCrCb422SP"; + case RGA2_FORMAT_YCrCb_422_P: + return "YCrCb422P"; + case RGA2_FORMAT_YCrCb_420_SP: + return "YCrCb420SP"; + case RGA2_FORMAT_YCrCb_420_P: + return "YCrCb420P"; + + case RGA2_FORMAT_YVYU_422: + return "YVYU422"; + case RGA2_FORMAT_YVYU_420: + return "YVYU420"; + case RGA2_FORMAT_VYUY_422: + return "VYUY422"; + case RGA2_FORMAT_VYUY_420: + return "VYUY420"; + case RGA2_FORMAT_YUYV_422: + return "YUYV422"; + case RGA2_FORMAT_YUYV_420: + return "YUYV420"; + case RGA2_FORMAT_UYVY_422: + return "UYVY422"; + case RGA2_FORMAT_UYVY_420: + return "UYVY420"; + + case RGA2_FORMAT_YCbCr_420_SP_10B: + return "YCrCb420SP10B"; + case RGA2_FORMAT_YCrCb_420_SP_10B: + return "YCbCr420SP10B"; + case RGA2_FORMAT_YCbCr_422_SP_10B: + return "YCbCr422SP10B"; + case RGA2_FORMAT_YCrCb_422_SP_10B: + return "YCrCb422SP10B"; + case RGA2_FORMAT_BPP_1: + return "BPP1"; + case RGA2_FORMAT_BPP_2: + return "BPP2"; + case RGA2_FORMAT_BPP_4: + return "BPP4"; + case RGA2_FORMAT_BPP_8: + return "BPP8"; + case RGA2_FORMAT_YCbCr_400: + return "YCbCr400"; + case RGA2_FORMAT_Y4: + return "y4"; + default: + return "UNF"; + } +} + +static void print_debug_info(struct rga3_req *req) +{ + pr_info("render_mode:%s, bitblit_mode=%d, rotate_mode:%x\n", + rga3_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, + rga3_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, + rga3_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\n, rdmode = %d\n", + req->wr.x_offset, req->wr.y_offset, + rga3_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 mode0=%x mode1=%x\n", req->alpha_rop_flag, + req->alpha_mode_0, req->alpha_mode_1); + pr_info("blend mode is %s\n", + rga3_get_blend_mode_str(req->alpha_rop_flag, req->alpha_mode_0, + req->alpha_mode_1)); + pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode); +} + +static int rga3_align_check(struct rga3_req *req) +{ + if (rga3_is_yuv10bit_format(req->win0.format)) + if ((req->win0.vir_w % 16) || (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 (rga3_is_yuv10bit_format(req->win1.format)) + if ((req->win1.vir_w % 16) || (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 (rga3_is_yuv8bit_format(req->win0.format)) + if ((req->win0.vir_w % 8) || (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 (rga3_is_yuv8bit_format(req->win1.format)) + if ((req->win1.vir_w % 8) || (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; +} + +int rga3_init_reg(struct rga_job *job) +{ + struct rga3_req req; + int ret = 0; + + memset(&req, 0x0, sizeof(req)); + + rga_cmd_to_rga3_cmd(&job->rga_command_base, &req); + + /* check value if legal */ + ret = rga3_check_param(&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; + } + + 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]); +} + +int rga3_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) +{ + ktime_t now = ktime_get(); + + //rga_dma_flush_range(&job->cmd_reg[0], &job->cmd_reg[50], scheduler); + + rga_write(0x0, RGA3_SYS_CTRL, scheduler); + +#if 0 + /* CMD buff */ + rga_write(virt_to_phys(job->cmd_reg), RGA3_CMD_ADDR, scheduler); +#else + { + int32_t m, *cmd; + + cmd = job->cmd_reg; + for (m = 0; m <= 50; m++) + rga_write(cmd[m], 0x100 + m * 4, scheduler); + } +#endif + + if (DEBUGGER_EN(REG)) { + int32_t i, *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]); + } + +#if 0 + /* master mode */ + rga_write((0x1 << 1) | (0x1 << 2) | (0x1 << 5) | (0x1 << 6), + RGA3_SYS_CTRL, scheduler); +#else + /* slave mode */ + //rga_write(1, 0xf08, scheduler); +#endif + + /* All CMD finish int */ + rga_write(1, RGA3_INT_EN, scheduler); + + if (DEBUGGER_EN(MSG)) { + pr_err("sys_ctrl = %x, int_en = %x, int_raw = %x\n", + rga_read(RGA3_SYS_CTRL, scheduler), + rga_read(RGA3_INT_EN, scheduler), + rga_read(RGA3_INT_RAW, scheduler)); + + pr_err("status0 = %x, status1 = %x\n", + rga_read(RGA3_STATUS0, scheduler), + rga_read(RGA3_STATUS1, scheduler)); + } + + if (DEBUGGER_EN(TIME)) + pr_err("set cmd use time = %lld\n", ktime_to_us(ktime_sub(now, job->running_time))); + + job->timestamp = now; + job->running_time = now; + + rga_write(1, RGA3_SYS_CTRL, scheduler); + + if (DEBUGGER_EN(REG)) + rga3_dump_read_back_reg(scheduler); + + return 0; +} + +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; +} diff --git a/drivers/video/rockchip/rga3/rga_common.c b/drivers/video/rockchip/rga3/rga_common.c new file mode 100644 index 000000000000..c0b828ae18f8 --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_common.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Cerf Yu + */ + +#define pr_fmt(fmt) "rga_common: " fmt + +#include "rga.h" + +void rga_user_format_convert(uint32_t *df, uint32_t sf) +{ + switch (sf) { + case 0x0: + *df = RGA2_FORMAT_RGBA_8888; + break; + case 0x1: + *df = RGA2_FORMAT_RGBX_8888; + break; + case 0x2: + *df = RGA2_FORMAT_RGB_888; + break; + case 0x3: + *df = RGA2_FORMAT_BGRA_8888; + break; + case 0x4: + *df = RGA2_FORMAT_RGB_565; + break; + case 0x5: + *df = RGA2_FORMAT_RGBA_5551; + break; + case 0x6: + *df = RGA2_FORMAT_RGBA_4444; + break; + case 0x7: + *df = RGA2_FORMAT_BGR_888; + break; + case 0x16: + *df = RGA2_FORMAT_BGRX_8888; + break; + case 0x8: + *df = RGA2_FORMAT_YCbCr_422_SP; + break; + case 0x9: + *df = RGA2_FORMAT_YCbCr_422_P; + break; + case 0xa: + *df = RGA2_FORMAT_YCbCr_420_SP; + break; + case 0xb: + *df = RGA2_FORMAT_YCbCr_420_P; + break; + case 0xc: + *df = RGA2_FORMAT_YCrCb_422_SP; + break; + case 0xd: + *df = RGA2_FORMAT_YCrCb_422_P; + break; + case 0xe: + *df = RGA2_FORMAT_YCrCb_420_SP; + break; + case 0xf: + *df = RGA2_FORMAT_YCrCb_420_P; + break; + + case 0x10: + *df = RGA2_FORMAT_BPP_1; + break; + case 0x11: + *df = RGA2_FORMAT_BPP_2; + break; + case 0x12: + *df = RGA2_FORMAT_BPP_4; + break; + case 0x13: + *df = RGA2_FORMAT_BPP_8; + break; + + case 0x14: + *df = RGA2_FORMAT_Y4; + break; + case 0x15: + *df = RGA2_FORMAT_YCbCr_400; + break; + + case 0x18: + *df = RGA2_FORMAT_YVYU_422; + break; + case 0x19: + *df = RGA2_FORMAT_YVYU_420; + break; + case 0x1a: + *df = RGA2_FORMAT_VYUY_422; + break; + case 0x1b: + *df = RGA2_FORMAT_VYUY_420; + break; + case 0x1c: + *df = RGA2_FORMAT_YUYV_422; + break; + case 0x1d: + *df = RGA2_FORMAT_YUYV_420; + break; + case 0x1e: + *df = RGA2_FORMAT_UYVY_422; + break; + case 0x1f: + *df = RGA2_FORMAT_UYVY_420; + break; + + case 0x20: + *df = RGA2_FORMAT_YCbCr_420_SP_10B; + break; + case 0x21: + *df = RGA2_FORMAT_YCrCb_420_SP_10B; + break; + case 0x22: + *df = RGA2_FORMAT_YCbCr_422_SP_10B; + break; + case 0x23: + *df = RGA2_FORMAT_YCrCb_422_SP_10B; + break; + + case 0x24: + *df = RGA2_FORMAT_BGR_565; + break; + case 0x25: + *df = RGA2_FORMAT_BGRA_5551; + break; + case 0x26: + *df = RGA2_FORMAT_BGRA_4444; + break; + + case 0x28: + *df = RGA2_FORMAT_ARGB_8888; + break; + case 0x29: + *df = RGA2_FORMAT_XRGB_8888; + break; + case 0x2a: + *df = RGA2_FORMAT_ARGB_5551; + break; + case 0x2b: + *df = RGA2_FORMAT_ARGB_4444; + break; + case 0x2c: + *df = RGA2_FORMAT_ABGR_8888; + break; + case 0x2d: + *df = RGA2_FORMAT_XBGR_8888; + break; + case 0x2e: + *df = RGA2_FORMAT_ABGR_5551; + break; + case 0x2f: + *df = RGA2_FORMAT_ABGR_4444; + break; + } +} + +bool rga_is_yuv422p_format(u32 format) +{ + bool ret = false; + + switch (format) { + case RGA2_FORMAT_YCbCr_422_P: + case RGA2_FORMAT_YCrCb_422_P: + ret = true; + break; + } + return ret; +} + +void rga_convert_addr(struct rga_img_info_t *img, bool before_vir_get_channel) +{ + uint32_t fmt = 0; + + rga_user_format_convert(&fmt, img->format); + + /* + * 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(fmt)) + 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; + } +} + +int rga_get_format_bits(u32 format) +{ + int bits = 0; + + switch (format) { + case RGA2_FORMAT_RGBA_8888: + case RGA2_FORMAT_RGBX_8888: + case RGA2_FORMAT_BGRA_8888: + case RGA2_FORMAT_BGRX_8888: + case RGA2_FORMAT_ARGB_8888: + case RGA2_FORMAT_XRGB_8888: + case RGA2_FORMAT_ABGR_8888: + case RGA2_FORMAT_XBGR_8888: + bits = 32; + break; + case RGA2_FORMAT_RGB_888: + case RGA2_FORMAT_BGR_888: + bits = 24; + break; + case RGA2_FORMAT_RGB_565: + case RGA2_FORMAT_RGBA_5551: + case RGA2_FORMAT_RGBA_4444: + case RGA2_FORMAT_BGR_565: + case RGA2_FORMAT_YCbCr_422_SP: + case RGA2_FORMAT_YCbCr_422_P: + case RGA2_FORMAT_YCrCb_422_SP: + case RGA2_FORMAT_YCrCb_422_P: + case RGA2_FORMAT_BGRA_5551: + case RGA2_FORMAT_BGRA_4444: + case RGA2_FORMAT_ARGB_5551: + case RGA2_FORMAT_ARGB_4444: + case RGA2_FORMAT_ABGR_5551: + case RGA2_FORMAT_ABGR_4444: + bits = 16; + break; + case RGA2_FORMAT_YCbCr_420_SP: + case RGA2_FORMAT_YCbCr_420_P: + case RGA2_FORMAT_YCrCb_420_SP: + case RGA2_FORMAT_YCrCb_420_P: + bits = 12; + break; + case RGA2_FORMAT_YCbCr_420_SP_10B: + case RGA2_FORMAT_YCrCb_420_SP_10B: + case RGA2_FORMAT_YCbCr_422_SP_10B: + case RGA2_FORMAT_YCrCb_422_SP_10B: + bits = 15; + break; + default: + pr_err("unknown format [%d]\n", format); + return -1; + } + + return bits; +} diff --git a/drivers/video/rockchip/rga3/rga_debugger.c b/drivers/video/rockchip/rga3/rga_debugger.c new file mode 100644 index 000000000000..457e4b12fe73 --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_debugger.c @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: + * Cerf Yu + * Huang Lee + */ + +#define pr_fmt(fmt) "rga_debugger: " fmt + +#include +#include +#include +#include +#include +#include + +#include "rga.h" +#include "rga_debugger.h" +#include "rga_drv.h" +#include "rga_mm.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_CHECK_MODE; +int RGA_DEBUG_NONUSE; +int RGA_DEBUG_INT_FLAG; + +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" + "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_CHECK_MODE), + STR_ENABLE(RGA_DEBUG_NONUSE), + STR_ENABLE(RGA_DEBUG_INT_FLAG)); + + 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 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, "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, "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, "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 *rga_scheduler = NULL; + unsigned long flags; + int i; + int load; + u32 busy_time_total; + + 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++) { + rga_scheduler = rga_drvdata->rga_scheduler[i]; + + seq_printf(m, "scheduler[%d]: %s\n", + i, dev_driver_string(rga_scheduler->dev)); + + spin_lock_irqsave(&rga_scheduler->irq_lock, flags); + + busy_time_total = rga_scheduler->timer.busy_time_record; + + spin_unlock_irqrestore(&rga_scheduler->irq_lock, flags); + + load = (busy_time_total * 100000 / RGA_LOAD_INTERVAL); + seq_printf(m, "load = %d", load); + seq_printf(m, "-----------------------------------\n"); + } + return 0; +} + +static int rga_scheduler_show(struct seq_file *m, void *data) +{ + struct rga_scheduler_t *rga_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++) { + rga_scheduler = rga_drvdata->rga_scheduler[i]; + + seq_printf(m, "scheduler[%d]: %s\n", + i, dev_driver_string(rga_scheduler->dev)); + seq_printf(m, "-----------------------------------\n"); + seq_printf(m, "pd_ref = %d\n", rga_scheduler->pd_refcount); + } + + return 0; +} + +static int rga_mm_session_show(struct seq_file *m, void *data) +{ + int id, i; + 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\n", + dump_buffer->handle, kref_read(&dump_buffer->refcount), + dump_buffer->mm_flag); + + switch (dump_buffer->type) { + case RGA_DMA_BUFFER: + seq_puts(m, "dma_buffer:\n"); + for (i = 0; i < dump_buffer->dma_buffer_size; i++) { + seq_printf(m, "\t core %d:\n", dump_buffer->dma_buffer[i].core); + seq_printf(m, "\t\t dma_buf = %p, iova = 0x%lx\n", + dump_buffer->dma_buffer[i].dma_buf, + (unsigned long)dump_buffer->dma_buffer[i].iova); + } + break; + case RGA_VIRTUAL_ADDRESS: + seq_puts(m, "virtual address:\n"); + seq_printf(m, "\t 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); + + for (i = 0; i < dump_buffer->dma_buffer_size; i++) { + seq_printf(m, "\t core %d:\n", dump_buffer->dma_buffer[i].core); + seq_printf(m, "\t\t iova = 0x%lx, sgt = %p, size = %ld\n", + (unsigned long)dump_buffer->dma_buffer[i].iova, + dump_buffer->dma_buffer[i].sgt, + dump_buffer->dma_buffer[i].size); + } + 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; +} + +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}, +}; + +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_RGA2_PROC_FS +static int rga_procfs_open(struct inode *inode, struct file *file) +{ + struct rga_debugger_node *node = PDE_DATA(inode); + + return single_open(file, node->info_ent->show, node); +} + +static const struct file_operations rga_procfs_fops = { + .owner = THIS_MODULE, + .open = rga_procfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .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_cmd_print_debug_info(struct rga_req *req) +{ + pr_info("============= start ==============\n"); + 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); +} 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 000000000000..c141a4b7e644 --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_dma_buf.c @@ -0,0 +1,1199 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#define pr_fmt(fmt) "rga_dma_buf: " fmt + +#include "rga_dma_buf.h" +#include "rga.h" +#include "rga_common.h" +#include "rga_job.h" + +/** + * rga_dma_info_to_prot - Translate DMA API directions and attributes to IOMMU API + * page flags. + * @dir: Direction of DMA transfer + * @coherent: Is the DMA master cache-coherent? + * @attrs: DMA attributes for the mapping + * + * Return: corresponding IOMMU API page protection flags + */ +static int rga_dma_info_to_prot(enum dma_data_direction dir, bool coherent) +{ + int prot = coherent ? IOMMU_CACHE : 0; + + switch (dir) { + case DMA_BIDIRECTIONAL: + return prot | IOMMU_READ | IOMMU_WRITE; + case DMA_TO_DEVICE: + return prot | IOMMU_READ; + case DMA_FROM_DEVICE: + return prot | 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 RGA2_FORMAT_RGBA_8888: + case RGA2_FORMAT_RGBX_8888: + case RGA2_FORMAT_BGRA_8888: + case RGA2_FORMAT_BGRX_8888: + case RGA2_FORMAT_ARGB_8888: + case RGA2_FORMAT_XRGB_8888: + case RGA2_FORMAT_ABGR_8888: + case RGA2_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 RGA2_FORMAT_RGB_888: + case RGA2_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 RGA2_FORMAT_RGB_565: + case RGA2_FORMAT_RGBA_5551: + case RGA2_FORMAT_RGBA_4444: + case RGA2_FORMAT_BGR_565: + case RGA2_FORMAT_BGRA_5551: + case RGA2_FORMAT_BGRA_4444: + case RGA2_FORMAT_ARGB_5551: + case RGA2_FORMAT_ARGB_4444: + case RGA2_FORMAT_ABGR_5551: + case RGA2_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 RGA2_FORMAT_YCbCr_422_SP: + case RGA2_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 RGA2_FORMAT_YCbCr_422_P: + case RGA2_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 RGA2_FORMAT_YCbCr_420_SP: + case RGA2_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 RGA2_FORMAT_YCbCr_420_P: + case RGA2_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 RGA2_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 RGA2_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 RGA2_FORMAT_YVYU_422: + case RGA2_FORMAT_VYUY_422: + case RGA2_FORMAT_YUYV_422: + case RGA2_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 RGA2_FORMAT_YVYU_420: + case RGA2_FORMAT_VYUY_420: + case RGA2_FORMAT_YUYV_420: + case RGA2_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 RGA2_FORMAT_YCbCr_420_SP_10B: + case RGA2_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 int rga_MapUserMemory(struct page **pages, uint32_t *pageTable, + unsigned long Memory, uint32_t pageCount, int writeFlag, + struct mm_struct *mm) +{ + uint32_t i, status; + int32_t result; + unsigned long Address; + unsigned long pfn; + struct page __maybe_unused *page; + 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; + + status = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + mmap_read_lock(mm); +#else + down_read(&mm->mmap_sem); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) + result = get_user_pages(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, mm, Memory << PAGE_SHIFT, + pageCount, writeFlag, 0, pages, NULL); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) + result = get_user_pages_remote(current, mm, + Memory << PAGE_SHIFT, + pageCount, writeFlag, pages, NULL, NULL); +#else + result = get_user_pages_remote(mm, Memory << PAGE_SHIFT, + pageCount, writeFlag, pages, NULL, NULL); +#endif + + if (result > 0 && result >= pageCount) { + /* Fill the page table. */ + for (i = 0; i < pageCount; i++) { + /* Get the physical address from page struct. */ + pageTable[i] = page_to_phys(pages[i]); + } + + for (i = 0; i < result; i++) + put_page(pages[i]); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + mmap_read_unlock(mm); +#else + up_read(&mm->mmap_sem); +#endif + return 0; + } + + if (result > 0) { + for (i = 0; i < result; i++) + put_page(pages[i]); + } + + for (i = 0; i < pageCount; i++) { + vma = find_vma(mm, (Memory + i) << PAGE_SHIFT); + if (!vma) { + pr_err("failed to get vma, result = %d, pageCount = %d\n", + result, pageCount); + status = RGA_OUT_OF_RESOURCES; + break; + } + + pgd = pgd_offset(mm, (Memory + i) << PAGE_SHIFT); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) { + pr_err("failed to get pgd, result = %d, pageCount = %d\n", + result, pageCount); + status = 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("failed to get p4d, result = %d, pageCount = %d\n", + result, pageCount); + status = 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("failed to get pud, result = %d, pageCount = %d\n", + result, pageCount); + status = RGA_OUT_OF_RESOURCES; + break; + } + pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { + pr_err("failed to get pmd, result = %d, pageCount = %d\n", + result, pageCount); + status = RGA_OUT_OF_RESOURCES; + break; + } + pte = pte_offset_map_lock(mm, pmd, + (Memory + i) << PAGE_SHIFT, &ptl); + if (pte_none(*pte)) { + pr_err("failed to get pte, result = %d, pageCount = %d\n", + result, pageCount); + pte_unmap_unlock(pte, ptl); + status = RGA_OUT_OF_RESOURCES; + break; + } + + pfn = pte_pfn(*pte); + Address = ((pfn << PAGE_SHIFT) | + (((unsigned long)((Memory + i) << PAGE_SHIFT)) & + ~PAGE_MASK)); + + pages[i] = pfn_to_page(pfn); + pageTable[i] = (uint32_t)Address; + pte_unmap_unlock(pte, ptl); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + mmap_read_unlock(mm); +#else + up_read(&mm->mmap_sem); +#endif + + return status; +} + +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 = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; + unsigned long shift, iova_len, iova = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) + dma_addr_t limit; +#endif + + shift = iova_shift(iovad); + iova_len = size >> shift; + /* + * 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); + +#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(5, 10, 0)) + iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); +#else + limit = min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn); + + iova = alloc_iova_fast(iovad, iova_len, limit, true); +#endif + + return (dma_addr_t)iova << shift; +} + +static void rga_iommu_dma_free_iova(struct rga_iommu_dma_cookie *cookie, + dma_addr_t iova, size_t size) +{ + struct iova_domain *iovad = &cookie->iovad; + + free_iova_fast(iovad, iova_pfn(iovad, iova), + size >> iova_shift(iovad)); +} + +static inline size_t rga_iommu_map_sg(struct iommu_domain *domain, + unsigned long iova, struct scatterlist *sg, + unsigned int nents, int prot) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + return iommu_map_sg_atomic(domain, iova, sg, nents, prot); +#else + return iommu_map_sg(domain, iova, sg, nents, prot); +#endif +} + +static inline bool rga_dev_is_dma_coherent(struct device *dev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + return dev_is_dma_coherent(dev); +#else + return dev->archdata.dma_coherent; +#endif +} + +static inline struct iommu_domain *rga_iommu_get_dma_domain(struct device *dev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + return iommu_get_dma_domain(dev); +#else + return iommu_get_domain_for_dev(dev); +#endif +} + +static inline void rga_dma_flush_cache_by_sgt(struct sg_table *sgt) +{ + struct scatterlist *sg; + int i; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) + arch_dma_prep_coherent(sg_page(sg), sg->length); +#else + for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) + __dma_flush_area(sg_page(sg), sg->length); +#endif +} + +static void rga_viraddr_put_channel_info(struct rga_dma_buffer_t **rga_dma_buffer) +{ + struct rga_dma_buffer_t *buffer; + + buffer = *rga_dma_buffer; + if (buffer == NULL) + return; + + if (!buffer->use_viraddr) + return; + + iommu_unmap(buffer->domain, buffer->iova, buffer->size); + rga_iommu_dma_free_iova(buffer->cookie, buffer->iova, buffer->size); + + kfree(buffer); + + *rga_dma_buffer = NULL; +} + +void rga_iommu_unmap_virt_addr(struct rga_dma_buffer *virt_dma_buf) +{ + if (virt_dma_buf == NULL) + return; + if (virt_dma_buf->iova == 0) + return; + + iommu_unmap(virt_dma_buf->domain, virt_dma_buf->iova, virt_dma_buf->size); + rga_iommu_dma_free_iova(virt_dma_buf->cookie, virt_dma_buf->iova, virt_dma_buf->size); +} + +int rga_iommu_map_virt_addr(struct rga_memory_parm *memory_parm, + struct rga_dma_buffer *virt_dma_buf, + struct device *rga_dev, + struct mm_struct *mm) +{ + unsigned long size; + size_t map_size; + bool coherent; + int ioprot; + struct iommu_domain *domain = NULL; + struct rga_iommu_dma_cookie *cookie; + struct iova_domain *iovad; + dma_addr_t iova; + struct sg_table *sgt = NULL; + + coherent = rga_dev_is_dma_coherent(rga_dev); + domain = rga_iommu_get_dma_domain(rga_dev); + ioprot = rga_dma_info_to_prot(DMA_BIDIRECTIONAL, coherent); + + cookie = domain->iova_cookie; + iovad = &cookie->iovad; + size = iova_align(iovad, virt_dma_buf->size); + sgt = virt_dma_buf->sgt; + if (sgt == NULL) { + pr_err("can not map iommu, because sgt is null!\n"); + return -EFAULT; + } + + if (DEBUGGER_EN(MSG)) + pr_debug("iova_align size = %ld", size); + + iova = rga_iommu_dma_alloc_iova(domain, size, rga_dev->coherent_dma_mask, rga_dev); + if (!iova) { + pr_err("rga_iommu_dma_alloc_iova failed"); + return -ENOMEM; + } + + if (!(ioprot & IOMMU_CACHE)) + rga_dma_flush_cache_by_sgt(sgt); + + map_size = rga_iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents, ioprot); + if (map_size < size) { + pr_err("iommu can not map sgt to iova"); + return -EINVAL; + } + + virt_dma_buf->cookie = cookie; + virt_dma_buf->domain = domain; + virt_dma_buf->iova = iova; + virt_dma_buf->size = size; + + return 0; +} + +static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info, + struct rga_dma_buffer_t **rga_dma_buffer, + int writeFlag, int core, struct mm_struct *mm) +{ + struct rga_scheduler_t *scheduler = NULL; + struct rga_dma_buffer_t *alloc_buffer; + + unsigned long size; + unsigned long start_addr; + unsigned int count; + int pages_order = 0; + int page_table_order = 0; + + uint32_t *page_table = NULL; + struct page **pages = NULL; + struct sg_table sgt; + + int ret = 0; + size_t map_size = 0; + + struct iommu_domain *domain = NULL; + struct rga_iommu_dma_cookie *cookie; + struct iova_domain *iovad; + bool coherent; + int ioprot; + dma_addr_t iova; + + int format; + + alloc_buffer = + kmalloc(sizeof(struct rga_dma_buffer_t), + GFP_KERNEL); + if (alloc_buffer == NULL) { + pr_err("rga_dma_buffer alloc error!\n"); + return -ENOMEM; + } + + rga_user_format_convert(&format, channel_info->format); + + scheduler = rga_job_get_scheduler(core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + goto out_free_buffer; + } + + coherent = rga_dev_is_dma_coherent(scheduler->dev); + domain = rga_iommu_get_dma_domain(scheduler->dev); + ioprot = rga_dma_info_to_prot(DMA_BIDIRECTIONAL, coherent); + cookie = domain->iova_cookie; + iovad = &cookie->iovad; + + /* Calculate page size. */ + count = rga_buf_size_cal(channel_info->yrgb_addr, channel_info->uv_addr, + channel_info->v_addr, format, + channel_info->vir_w, channel_info->vir_h, + &start_addr, NULL); + size = count * PAGE_SIZE; + + /* alloc pages and page_table */ + pages_order = get_order(count * sizeof(struct page *)); + pages = (struct page **)__get_free_pages(GFP_KERNEL, pages_order); + if (pages == NULL) { + pr_err("Can not alloc pages for pages\n"); + ret = -ENOMEM; + goto out_free_buffer; + } + + page_table_order = get_order(count * sizeof(uint32_t *)); + page_table = (uint32_t *)__get_free_pages(GFP_KERNEL, page_table_order); + if (page_table == NULL) { + pr_err("Can not alloc pages for page_table\n"); + ret = -ENOMEM; + goto out_free_pages; + } + + /* get pages from virtual address. */ + ret = rga_MapUserMemory(pages, page_table, start_addr, count, writeFlag, mm); + if (ret) { + pr_err("failed to get pages"); + ret = -EINVAL; + goto out_free_pages_table; + } + + size = iova_align(iovad, size); + + if (DEBUGGER_EN(MSG)) + pr_err("iova_align size = %ld", size); + + iova = rga_iommu_dma_alloc_iova(domain, size, scheduler->dev->coherent_dma_mask, + scheduler->dev); + if (!iova) { + pr_err("rga_iommu_dma_alloc_iova failed"); + ret = -ENOMEM; + goto out_free_pages_table; + } + + /* get sg form pages. */ + if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL)) { + pr_err("sg_alloc_table_from_pages failed"); + ret = -ENOMEM; + goto out_free_sg; + } + + if (!(ioprot & IOMMU_CACHE)) + rga_dma_flush_cache_by_sgt(&sgt); + + map_size = rga_iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, ioprot); + if (map_size < size) { + pr_err("iommu can not map sgt to iova"); + ret = -EINVAL; + goto out_free_sg; + } + + /* + * When the virtual address has an in-page offset, it needs to be offset to + * the corresponding starting point. + */ + channel_info->yrgb_addr = iova + (channel_info->yrgb_addr & (~PAGE_MASK)); + + alloc_buffer->iova = iova; + alloc_buffer->size = size; + alloc_buffer->cookie = cookie; + alloc_buffer->use_viraddr = true; + alloc_buffer->domain = domain; + + sg_free_table(&sgt); + + free_pages((unsigned long)pages, pages_order); + free_pages((unsigned long)page_table, page_table_order); + + *rga_dma_buffer = alloc_buffer; + + return ret; + +out_free_sg: + sg_free_table(&sgt); + rga_iommu_dma_free_iova(cookie, iova, size); + +out_free_pages_table: + free_pages((unsigned long)page_table, page_table_order); + +out_free_pages: + free_pages((unsigned long)pages, pages_order); + +out_free_buffer: + kfree(alloc_buffer); + + return ret; +} + +static 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; +} + +static int rga_dma_memory_check(struct rga_dma_buffer_t *rga_dma_buffer, + struct rga_img_info_t *img) +{ + int ret = 0; + void *vaddr; + struct dma_buf *dma_buf; + + dma_buf = rga_dma_buffer->dma_buf; + + if (!IS_ERR_OR_NULL(dma_buf)) { + vaddr = dma_buf_vmap(dma_buf); + 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; + } + + dma_buf_vunmap(dma_buf, vaddr); + } + + 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; + int ret = 0; + + dma_buf = dma_buf_get(fd); + if (IS_ERR(dma_buf)) { + pr_err("dma_buf_get fail fd[%d]\n", fd); + ret = -EINVAL; + return ret; + } + + attach = dma_buf_attach(dma_buf, rga_dev); + if (IS_ERR(attach)) { + pr_err("Failed to attach dma_buf\n"); + ret = -EINVAL; + goto err_get_attach; + } + + sgt = dma_buf_map_attachment(attach, dir); + if (IS_ERR(sgt)) { + pr_err("Failed to map src attachment\n"); + ret = -EINVAL; + 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->size = sg_dma_len(sgt->sgl); + rga_dma_buffer->dir = dir; + + 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_fd(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); + } +} + +static int rga_dma_map_buffer(struct dma_buf *dma_buf, + struct rga_dma_buffer_t *rga_dma_buffer, + enum dma_data_direction dir, struct device *rga_dev) +{ + struct dma_buf_attachment *attach = NULL; + struct sg_table *sgt = NULL; + + int ret = 0; + + attach = dma_buf_attach(dma_buf, rga_dev); + if (IS_ERR(attach)) { + ret = -EINVAL; + pr_err("Failed to attach dma_buf\n"); + goto err_get_attach; + } + + sgt = dma_buf_map_attachment(attach, dir); + if (IS_ERR(sgt)) { + ret = -EINVAL; + pr_err("Failed to map src attachment\n"); + goto err_get_sg; + } + + 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); + + /* TODO: size for check */ + rga_dma_buffer->size = sg_dma_len(sgt->sgl); + rga_dma_buffer->dir = dir; + + return ret; + +err_get_sg: + if (sgt) + dma_buf_unmap_attachment(attach, sgt, dir); + if (attach) + dma_buf_detach(dma_buf, attach); +err_get_attach: + if (dma_buf && (rga_dma_buffer->use_dma_buf == false)) + dma_buf_put(dma_buf); + + return ret; +} + +static void rga_dma_unmap_buffer(struct rga_dma_buffer_t *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); +} + +static int rga_dma_buf_get_channel_info(struct rga_img_info_t *channel_info, + struct rga_dma_buffer_t **rga_dma_buffer, int mmu_flag, + struct dma_buf **dma_buf, int core) +{ + int ret; + struct rga_dma_buffer_t *alloc_buffer; + struct rga_scheduler_t *scheduler = NULL; + + if (unlikely(!mmu_flag && *dma_buf)) { + pr_err("Fix it please enable mmu on dma buf channel\n"); + return -EINVAL; + } else if (mmu_flag && *dma_buf) { + /* perform a single mapping to dma buffer */ + alloc_buffer = + kmalloc(sizeof(struct rga_dma_buffer_t), + GFP_KERNEL); + if (alloc_buffer == NULL) { + pr_err("rga_dma_buffer alloc error!\n"); + return -ENOMEM; + } + + alloc_buffer->use_dma_buf = false; + alloc_buffer->use_viraddr = false; + + scheduler = rga_job_get_scheduler(core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + kfree(alloc_buffer); + ret = -EINVAL; + return ret; + } + + ret = + rga_dma_map_buffer(*dma_buf, alloc_buffer, + DMA_BIDIRECTIONAL, scheduler->dev); + if (ret < 0) { + pr_err("Can't map dma-buf\n"); + kfree(alloc_buffer); + return ret; + } + + *rga_dma_buffer = alloc_buffer; + } + + if (DEBUGGER_EN(CHECK_MODE)) { + ret = rga_dma_memory_check(*rga_dma_buffer, + channel_info); + if (ret < 0) { + pr_err("Channel check memory error!\n"); + /* + * Note: This error is released by external + * rga_dma_put_channel_info(). + */ + return ret; + } + } + + /* The value of dma_fd is no longer needed. */ + channel_info->yrgb_addr = 0; + + if (core == RGA3_SCHEDULER_CORE0 || core == RGA3_SCHEDULER_CORE1) + if (*rga_dma_buffer) + channel_info->yrgb_addr = (*rga_dma_buffer)->iova; + + return 0; +} + +static void rga_dma_put_channel_info(struct rga_dma_buffer_t **rga_dma_buffer, struct dma_buf **dma_buf) +{ + struct rga_dma_buffer_t *buffer; + + buffer = *rga_dma_buffer; + if (buffer == NULL) + return; + + if (buffer->use_viraddr) + return; + + rga_dma_unmap_buffer(buffer); + if (*dma_buf) + dma_buf_put(*dma_buf); + + kfree(buffer); + + *rga_dma_buffer = NULL; + *dma_buf = NULL; +} + +int rga_dma_buf_get(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; + + src0 = &job->rga_command_base.src; + dst = &job->rga_command_base.dst; + if (job->rga_command_base.render_mode != UPDATE_PALETTE_TABLE_MODE) + src1 = &job->rga_command_base.pat; + else + els = &job->rga_command_base.pat; + + if (likely(src0 != NULL)) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 8) & 1); + if (mmu_flag && src0->yrgb_addr) { + job->dma_buf_src0 = dma_buf_get(src0->yrgb_addr); + if (IS_ERR(job->dma_buf_src0)) { + ret = -EINVAL; + pr_err("%s src0 dma_buf_get fail fd[%lu]\n", + __func__, (unsigned long)src0->yrgb_addr); + return ret; + } + } + } + + if (likely(dst != NULL)) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 10) & 1); + if (mmu_flag && dst->yrgb_addr) { + job->dma_buf_dst = dma_buf_get(dst->yrgb_addr); + if (IS_ERR(job->dma_buf_dst)) { + ret = -EINVAL; + pr_err("%s dst dma_buf_get fail fd[%lu]\n", + __func__, (unsigned long)dst->yrgb_addr); + return ret; + } + } + } + + if (src1 != NULL) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 9) & 1); + if (mmu_flag && src1->yrgb_addr) { + job->dma_buf_src1 = dma_buf_get(src1->yrgb_addr); + if (IS_ERR(job->dma_buf_src0)) { + ret = -EINVAL; + pr_err("%s src1 dma_buf_get fail fd[%lu]\n", + __func__, (unsigned long)src1->yrgb_addr); + return ret; + } + } + } + + if (els != NULL) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 11) & 1); + if (mmu_flag && els->yrgb_addr) { + job->dma_buf_els = dma_buf_get(els->yrgb_addr); + if (IS_ERR(job->dma_buf_els)) { + ret = -EINVAL; + pr_err("%s els dma_buf_get fail fd[%lu]\n", + __func__, (unsigned long)els->yrgb_addr); + return ret; + } + } + } + + return 0; +} + +int rga_dma_get_info(struct rga_job *job) +{ + int ret = 0; + uint32_t 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 = &job->rga_command_base.src; + dst = &job->rga_command_base.dst; + if (job->rga_command_base.render_mode != UPDATE_PALETTE_TABLE_MODE) + src1 = &job->rga_command_base.pat; + else + els = &job->rga_command_base.pat; + + /* src0 channel */ + if (likely(src0 != NULL)) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 8) & 1); + if (job->dma_buf_src0 != NULL) { + ret = rga_dma_buf_get_channel_info(src0, + &job->rga_dma_buffer_src0, mmu_flag, + &job->dma_buf_src0, job->core); + + if (unlikely(ret < 0)) { + pr_err("src0 channel get info error!\n"); + goto src0_channel_err; + } + + if (src0->yrgb_addr <= 0) + job->rga_dma_buffer_src0->use_dma_buf = true; + } else { + src0->yrgb_addr = src0->uv_addr; + rga_convert_addr(src0, true); + if (job->core == RGA3_SCHEDULER_CORE0 || job->core == RGA3_SCHEDULER_CORE1) { + if (src0->yrgb_addr > 0 && mmu_flag) { + ret = rga_viraddr_get_channel_info(src0, &job->rga_dma_buffer_src0, + 0, job->core, job->mm); + + if (unlikely(ret < 0)) { + pr_err("src0 channel viraddr get info error!\n"); + return ret; + } + } + } + } + + rga_convert_addr(src0, false); + } + + /* dst channel */ + if (likely(dst != NULL)) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 10) & 1); + if (job->dma_buf_dst != NULL) { + ret = rga_dma_buf_get_channel_info(dst, + &job->rga_dma_buffer_dst, mmu_flag, + &job->dma_buf_dst, job->core); + + if (unlikely(ret < 0)) { + pr_err("dst channel get info error!\n"); + goto dst_channel_err; + } + + if (dst->yrgb_addr <= 0) + job->rga_dma_buffer_dst->use_dma_buf = true; + } else { + dst->yrgb_addr = dst->uv_addr; + rga_convert_addr(dst, true); + if (job->core == RGA3_SCHEDULER_CORE0 || job->core == RGA3_SCHEDULER_CORE1) { + if (dst->yrgb_addr > 0 && mmu_flag) { + ret = rga_viraddr_get_channel_info(dst, &job->rga_dma_buffer_dst, + 1, job->core, job->mm); + + if (unlikely(ret < 0)) { + pr_err("dst channel viraddr get info error!\n"); + return ret; + } + } + } + } + + rga_convert_addr(dst, false); + } + + /* src1 channel */ + if (src1 != NULL) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 9) & 1); + if (job->dma_buf_src1 != NULL) { + ret = rga_dma_buf_get_channel_info(src1, + &job->rga_dma_buffer_src1, mmu_flag, + &job->dma_buf_src1, job->core); + + if (unlikely(ret < 0)) { + pr_err("src1 channel get info error!\n"); + goto src1_channel_err; + } + + if (src1->yrgb_addr <= 0) + job->rga_dma_buffer_src1->use_dma_buf = true; + } else { + src1->yrgb_addr = src1->uv_addr; + rga_convert_addr(src1, true); + if (job->core == RGA3_SCHEDULER_CORE0 || job->core == RGA3_SCHEDULER_CORE1) { + if (src1->yrgb_addr > 0 && mmu_flag) { + ret = rga_viraddr_get_channel_info(src1, &job->rga_dma_buffer_src1, + 0, job->core, job->mm); + + if (unlikely(ret < 0)) { + pr_err("src1 channel viraddr get info error!\n"); + return ret; + } + } + } + } + + rga_convert_addr(src1, false); + } + + /* els channel */ + if (els != NULL) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 11) & 1); + if (job->dma_buf_els != NULL) { + ret = rga_dma_buf_get_channel_info(els, + &job->rga_dma_buffer_els, mmu_flag, + &job->dma_buf_els, job->core); + + if (unlikely(ret < 0)) { + pr_err("els channel get info error!\n"); + goto els_channel_err; + } + + if (els->yrgb_addr <= 0) + job->rga_dma_buffer_els->use_dma_buf = true; + } else { + els->yrgb_addr = els->uv_addr; + rga_convert_addr(els, true); + if (job->core == RGA3_SCHEDULER_CORE0 || job->core == RGA3_SCHEDULER_CORE1) { + if (els->yrgb_addr > 0 && mmu_flag) { + ret = rga_viraddr_get_channel_info(els, &job->rga_dma_buffer_els, + 0, job->core, job->mm); + + if (unlikely(ret < 0)) { + pr_err("els channel viraddr get info error!\n"); + return ret; + } + } + } + } + + rga_convert_addr(els, false); + } + + return 0; + +els_channel_err: + rga_dma_put_channel_info(&job->rga_dma_buffer_els, &job->dma_buf_els); +dst_channel_err: + rga_dma_put_channel_info(&job->rga_dma_buffer_dst, &job->dma_buf_dst); +src1_channel_err: + rga_dma_put_channel_info(&job->rga_dma_buffer_src1, &job->dma_buf_src1); +src0_channel_err: + rga_dma_put_channel_info(&job->rga_dma_buffer_src0, &job->dma_buf_src0); + + return ret; +} + +void rga_dma_put_info(struct rga_job *job) +{ + rga_dma_put_channel_info(&job->rga_dma_buffer_src0, &job->dma_buf_src0); + rga_viraddr_put_channel_info(&job->rga_dma_buffer_src0); + rga_dma_put_channel_info(&job->rga_dma_buffer_src1, &job->dma_buf_src1); + rga_viraddr_put_channel_info(&job->rga_dma_buffer_src1); + rga_dma_put_channel_info(&job->rga_dma_buffer_dst, &job->dma_buf_dst); + rga_viraddr_put_channel_info(&job->rga_dma_buffer_dst); + rga_dma_put_channel_info(&job->rga_dma_buffer_els, &job->dma_buf_els); + rga_viraddr_put_channel_info(&job->rga_dma_buffer_els); +} diff --git a/drivers/video/rockchip/rga3/rga_drv.c b/drivers/video/rockchip/rga3/rga_drv.c new file mode 100644 index 000000000000..327f3eb1ea4a --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_drv.c @@ -0,0 +1,1039 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#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 "rga2_mmu_info.h" +#include "rga_debugger.h" + +struct rga2_mmu_info_t rga2_mmu_info; + +struct rga_drvdata_t *rga_drvdata; + +/* set hrtimer */ +static struct hrtimer timer; +static ktime_t kt; + +static 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 +}; + +static 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 +}; + +int rga_mpi_commit(struct rga_req *cmd, struct rga_mpi_job_t *mpi_job) +{ + int ret; + + if (DEBUGGER_EN(MSG)) + rga_cmd_print_debug_info(cmd); + + ret = rga_job_mpi_commit(cmd, mpi_job, RGA_BLIT_SYNC); + 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__); + } + + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(rga_mpi_commit); + +int rga_kernel_commit(struct rga_req *cmd) +{ + int ret; + + if (DEBUGGER_EN(MSG)) + rga_cmd_print_debug_info(cmd); + + ret = rga_job_commit(cmd, RGA_BLIT_SYNC); + if (ret < 0) { + if (ret == -ERESTARTSYS) { + if (DEBUGGER_EN(MSG)) + pr_err("%s, commit kernel job failed, by a software interrupt.\n", + __func__); + } else { + pr_err("%s, commit kernel job failed\n", __func__); + } + + return ret; + } + + 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->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->timestamp); + job->timestamp = 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_LOAD_INTERVAL); + hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer_start(&timer, kt, HRTIMER_MODE_REL); + timer.function = hrtimer_handler; +} + +static void rga_cancel_timer(void) +{ + hrtimer_cancel(&timer); +} + +#ifndef CONFIG_ROCKCHIP_FPGA +int rga_power_enable(struct rga_scheduler_t *rga_scheduler) +{ + int ret = -EINVAL; + int i; + + pm_runtime_get_sync(rga_scheduler->dev); + pm_stay_awake(rga_scheduler->dev); + + for (i = 0; i < rga_scheduler->num_clks; i++) { + if (!IS_ERR(rga_scheduler->clks[i])) { + ret = clk_prepare_enable(rga_scheduler->clks[i]); + if (ret < 0) + goto err_enable_clk; + } + } + + return 0; + +err_enable_clk: + for (--i; i >= 0; --i) + if (!IS_ERR(rga_scheduler->clks[i])) + clk_disable_unprepare(rga_scheduler->clks[i]); + + pm_relax(rga_scheduler->dev); + pm_runtime_put_sync_suspend(rga_scheduler->dev); + + rga_scheduler->pd_refcount++; + + return ret; +} + +int rga_power_disable(struct rga_scheduler_t *rga_scheduler) +{ + int i; + + for (i = rga_scheduler->num_clks - 1; i >= 0; i--) + if (!IS_ERR(rga_scheduler->clks[i])) + clk_disable_unprepare(rga_scheduler->clks[i]); + + pm_relax(rga_scheduler->dev); + pm_runtime_put_sync_suspend(rga_scheduler->dev); + + rga_scheduler->pd_refcount--; + + return 0; +} + +#endif //CONFIG_ROCKCHIP_FPGA + +static long rga_ioctl_import_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 import more than %d buffers at a time!\n", + RGA_BUFFER_POOL_SIZE_MAX); + return -EFBIG; + } + + if (buffer_pool.buffers == NULL) { + 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, buffer_pool.buffers, + 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++) { + ret = rga_mm_import_buffer(&external_buffer[i]); + if (ret < 0) { + pr_err("buffer[%d] mm import buffer failed!\n", i); + + goto err_free_external_buffer; + } + + external_buffer[i].handle = ret; + } + + if (unlikely(copy_to_user(buffer_pool.buffers, 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 == NULL) { + 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, buffer_pool.buffers, + 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++) { + ret = rga_mm_release_buffer(external_buffer[i].handle); + if (ret < 0) { + pr_err("buffer[%d] mm release buffer failed!\n", i); + + goto err_free_external_buffer; + } + } + +err_free_external_buffer: + kfree(external_buffer); + return ret; +} + +static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg) +{ + struct rga_drvdata_t *rga = rga_drvdata; + struct rga_req req_rga; + 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; + + 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: + if (unlikely(copy_from_user(&req_rga, + (struct rga_req *)arg, sizeof(struct rga_req)))) { + pr_err("copy_from_user failed\n"); + ret = -EFAULT; + break; + } + + if (DEBUGGER_EN(MSG)) + rga_cmd_print_debug_info(&req_rga); + + ret = rga_job_commit(&req_rga, cmd); + if (ret < 0) { + if (ret == -ERESTARTSYS) { + if (DEBUGGER_EN(MSG)) + pr_err("rga_job_commit failed, by a software interrupt.\n"); + } else { + pr_err("rga_job_commit failed\n"); + } + + break; + } + + if (copy_to_user((struct rga_req *)arg, + &req_rga, sizeof(struct rga_req))) { + pr_err("copy_to_user failed\n"); + ret = -EFAULT; + break; + } + + break; + case RGA_CACHE_FLUSH: + case RGA_FLUSH: + case RGA_GET_RESULT: + break; + case RGA_GET_VERSION: + sscanf(rga->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->rga_scheduler[i]->ops == &rga2_ops) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + if (copy_to_user((void *)arg, rga->rga_scheduler[i]->version.str, + sizeof(rga->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->rga_scheduler[i]->version, + sizeof(rga->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: + ret = rga_ioctl_import_buffer(arg); + + break; + + case RGA_IOC_RELEASE_BUFFER: + ret = rga_ioctl_release_buffer(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) +{ + return nonseekable_open(inode, file); +} + +static int rga_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static irqreturn_t rga3_irq_handler(int irq, void *data) +{ + struct rga_scheduler_t *rga_scheduler = data; + + if (DEBUGGER_EN(INT_FLAG)) + pr_info("irqthread INT[%x],STATS0[%x], STATS1[%x]\n", + rga_read(RGA3_INT_RAW, rga_scheduler), + rga_read(RGA3_STATUS0, rga_scheduler), + rga_read(RGA3_STATUS1, rga_scheduler)); + + /* TODO: if error interrupt then soft reset hardware */ + //rga_scheduler->ops->soft_reset(job->core); + + /*clear INT */ + rga_write(1, RGA3_INT_CLR, rga_scheduler); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t rga3_irq_thread(int irq, void *data) +{ + struct rga_scheduler_t *rga_scheduler = data; + struct rga_job *job; + + job = rga_scheduler->running_job; + + if (!job) { + pr_err("running job is invaild on irq thread\n"); + return IRQ_HANDLED; + } + + if (DEBUGGER_EN(INT_FLAG)) + pr_info("irq INT[%x], STATS0[%x], STATS1[%x]\n", + rga_read(RGA3_INT_RAW, rga_scheduler), + rga_read(RGA3_STATUS0, rga_scheduler), + rga_read(RGA3_STATUS1, rga_scheduler)); + + rga_job_done(rga_scheduler, 0); + + return IRQ_HANDLED; +} + +static irqreturn_t rga2_irq_handler(int irq, void *data) +{ + struct rga_scheduler_t *rga_scheduler = data; + + if (DEBUGGER_EN(INT_FLAG)) + pr_info("irqthread INT[%x],STATS0[%x]\n", + rga_read(RGA2_INT, rga_scheduler), rga_read(RGA2_STATUS, + rga_scheduler)); + + /*if error interrupt then soft reset hardware */ + //warning + if (rga_read(RGA2_INT, rga_scheduler) & 0x01) { + pr_err("err irq! INT[%x],STATS0[%x]\n", + rga_read(RGA2_INT, rga_scheduler), + rga_read(RGA2_STATUS, rga_scheduler)); + rga_scheduler->ops->soft_reset(rga_scheduler); + } + + /*clear INT */ + rga_write(rga_read(RGA2_INT, rga_scheduler) | (0x1 << 4) | (0x1 << 5) | + (0x1 << 6) | (0x1 << 7), RGA2_INT, rga_scheduler); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t rga2_irq_thread(int irq, void *data) +{ + struct rga_scheduler_t *rga_scheduler = data; + struct rga_job *job; + + job = rga_scheduler->running_job; + + if (!job) + return IRQ_HANDLED; + + if (DEBUGGER_EN(INT_FLAG)) + pr_info("irq INT[%x], STATS0[%x]\n", + rga_read(RGA2_INT, rga_scheduler), rga_read(RGA2_STATUS, + rga_scheduler)); + + rga_job_done(rga_scheduler, 0); + + return IRQ_HANDLED; +} + +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 = { + .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_irqs_data_t single_rga2_irqs[] = { + {"rga2_irq", rga2_irq_handler, rga2_irq_thread} +}; + +static const struct rga_irqs_data_t rga3_core0_irqs[] = { + {"rga3_core0_irq", rga3_irq_handler, rga3_irq_thread} +}; + +static const struct rga_irqs_data_t rga3_core1_irqs[] = { + {"rga3_core1_irq", rga3_irq_handler, rga3_irq_thread} +}; + +static const struct rga_match_data_t old_rga2_match_data = { + .clks = old_rga2_clks, + .num_clks = ARRAY_SIZE(old_rga2_clks), + .irqs = single_rga2_irqs, + .num_irqs = ARRAY_SIZE(single_rga2_irqs) +}; + +static const struct rga_match_data_t rk3588_rga2_match_data = { + .clks = rk3588_rga2_clks, + .num_clks = ARRAY_SIZE(rk3588_rga2_clks), + .irqs = single_rga2_irqs, + .num_irqs = ARRAY_SIZE(single_rga2_irqs) +}; + +static const struct rga_match_data_t rga3_core0_match_data = { + .clks = rga3_core_0_clks, + .num_clks = ARRAY_SIZE(rga3_core_0_clks), + .irqs = rga3_core0_irqs, + .num_irqs = ARRAY_SIZE(rga3_core0_irqs) +}; + +static const struct rga_match_data_t rga3_core1_match_data = { + .clks = rga3_core_1_clks, + .num_clks = ARRAY_SIZE(rga3_core_1_clks), + .irqs = rga3_core1_irqs, + .num_irqs = ARRAY_SIZE(rga3_core1_irqs) +}; + +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 *rga_scheduler, + const char *name) +{ + spin_lock_init(&rga_scheduler->irq_lock); + INIT_LIST_HEAD(&rga_scheduler->todo_list); + init_waitqueue_head(&rga_scheduler->job_done_wq); + + if (!strcmp(name, "rga3_core0")) { + rga_scheduler->ops = &rga3_ops; + /* TODO: get by hw version */ + rga_scheduler->data = &rga3_data; + rga_scheduler->core = RGA3_SCHEDULER_CORE0; + } else if (!strcmp(name, "rga3_core1")) { + rga_scheduler->ops = &rga3_ops; + rga_scheduler->data = &rga3_data; + rga_scheduler->core = RGA3_SCHEDULER_CORE1; + } else if (!strcmp(name, "rga2")) { + rga_scheduler->ops = &rga2_ops; + rga_scheduler->data = &rga2e_data; + rga_scheduler->core = RGA2_SCHEDULER_CORE0; + } +} + +static int rga_drv_probe(struct platform_device *pdev) +{ + struct rga_drvdata_t *data = rga_drvdata; + struct resource *res; + int ret = 0; + const struct of_device_id *match = NULL; + struct device *dev = &pdev->dev; + const struct rga_match_data_t *match_data; + int i, irq; + struct rga_scheduler_t *rga_scheduler = NULL; + + if (!pdev->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); + + if (!match) { + dev_err(dev, "%s missing DT entry!\n", dev_driver_string(dev)); + return -EINVAL; + } + + rga_scheduler = + devm_kzalloc(&pdev->dev, sizeof(struct rga_scheduler_t), + GFP_KERNEL); + if (rga_scheduler == NULL) { + pr_err("failed to allocate scheduler. dev name = %s\n", + dev_driver_string(dev)); + return -ENOMEM; + } + + init_scheduler(rga_scheduler, + dev_driver_string(dev)); + + rga_scheduler->dev = &pdev->dev; + + /* map the registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + pr_err("get memory resource failed.\n"); + return -ENXIO; + } + + rga_scheduler->rga_base = + devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!rga_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", + match_data->irqs[0].name); + return irq; + } + + rga_scheduler->irq = irq; + + pr_err("%s, irq = %d, match scheduler\n", + match_data->irqs[0].name, irq); + + ret = devm_request_threaded_irq(dev, irq, + match_data->irqs[0].irq_hdl, + match_data->irqs[0].irq_thread, IRQF_SHARED, + dev_driver_string(dev), + rga_scheduler); + if (ret < 0) { + pr_err("request irq name: %s failed: %d\n", + match_data->irqs[0].name, ret); + return ret; + } + +#ifndef CONFIG_ROCKCHIP_FPGA + 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]); + + rga_scheduler->clks[i] = clk; + } + rga_scheduler->num_clks = match_data->num_clks; +#endif + + platform_set_drvdata(pdev, rga_scheduler); + + device_init_wakeup(dev, true); + + /* PM init */ +#ifndef CONFIG_ROCKCHIP_FPGA + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(rga_scheduler->dev); + if (ret < 0) { + pr_err("failed to get pm runtime, ret = %d\n", + ret); + goto failed; + } + + for (i = 0; i < rga_scheduler->num_clks; i++) { + if (!IS_ERR(rga_scheduler->clks[i])) { + ret = clk_prepare_enable(rga_scheduler->clks[i]); + if (ret < 0) { + pr_err("failed to enable clk\n"); + goto failed; + } + } + } +#endif //CONFIG_ROCKCHIP_FPGA + + rga_scheduler->ops->get_version(rga_scheduler); + pr_err("Driver loaded successfully rga[%d] ver:%s\n", i, + rga_scheduler->version.str); + + data->rga_scheduler[data->num_of_scheduler] = rga_scheduler; + + data->num_of_scheduler++; + + for (i = rga_scheduler->num_clks - 1; i >= 0; i--) + if (!IS_ERR(rga_scheduler->clks[i])) + clk_disable_unprepare(rga_scheduler->clks[i]); + + pm_runtime_put_sync(&pdev->dev); + + pr_err("probe successfully\n"); + + return 0; + +failed: + device_init_wakeup(dev, false); + pm_runtime_disable(dev); + + return ret; +} + +static int rga_drv_remove(struct platform_device *pdev) +{ + device_init_wakeup(&pdev->dev, false); +#ifndef CONFIG_ROCKCHIP_FPGA + pm_runtime_disable(&pdev->dev); +#endif //CONFIG_ROCKCHIP_FPGA + + return 0; +} + +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; + int order = 0; + + uint32_t *buf_p; + uint32_t *buf; + + /* + * malloc pre scale mid buf mmu table: + * RGA2_PHY_PAGE_SIZE * channel_num * address_size + */ + order = get_order(RGA2_PHY_PAGE_SIZE * 3 * sizeof(buf_p)); + buf_p = (uint32_t *) __get_free_pages(GFP_KERNEL | GFP_DMA32, order); + if (buf_p == NULL) { + pr_err("Can not alloc pages for mmu_page_table\n"); + return -ENOMEM; + } + + rga2_mmu_info.buf_virtual = buf_p; + rga2_mmu_info.buf_order = order; + +#if (defined(CONFIG_ARM) && defined(CONFIG_ARM_LPAE)) + buf = + (uint32_t *) (uint32_t) + virt_to_phys((void *)((unsigned long)buf_p)); +#else + buf = (uint32_t *) virt_to_phys((void *)((unsigned long)buf_p)); +#endif + rga2_mmu_info.buf = buf; + rga2_mmu_info.front = 0; + rga2_mmu_info.back = RGA2_PHY_PAGE_SIZE * 3; + rga2_mmu_info.size = RGA2_PHY_PAGE_SIZE * 3; + + order = get_order(RGA2_PHY_PAGE_SIZE * sizeof(struct page *)); + rga2_mmu_info.pages = + (struct page **)__get_free_pages(GFP_KERNEL | GFP_DMA32, order); + if (rga2_mmu_info.pages == NULL) + pr_err("Can not alloc pages for rga2_mmu_info.pages\n"); + + rga2_mmu_info.pages_order = order; + + 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); + + wake_lock_init(&rga_drvdata->wake_lock, WAKE_LOCK_SUSPEND, "rga"); + + ret = platform_driver_register(&rga3_core0_driver); + if (ret != 0) { + pr_err("Platform device rga3_core0_driver register failed (%d).\n", ret); + return ret; + } + + ret = platform_driver_register(&rga3_core1_driver); + if (ret != 0) { + pr_err("Platform device rga3_core1_driver register failed (%d).\n", ret); + return ret; + } + + ret = platform_driver_register(&rga2_driver); + if (ret != 0) { + pr_err("Platform device rga2_driver register failed (%d).\n", ret); + return ret; + } + + rga_init_timer(); + + rga_drvdata->fence_ctx = rga_fence_context_alloc(); + if (IS_ERR(rga_drvdata->fence_ctx)) { + pr_err("failed to allocate fence context for RGA\n"); + ret = PTR_ERR(rga_drvdata->fence_ctx); + return ret; + } + + ret = misc_register(&rga_dev); + if (ret) { + pr_err("cannot register miscdev (%d)\n", ret); + return ret; + } + + rga_mm_init(&rga_drvdata->mm); + +#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER + rga_debugger_init(&rga_drvdata->debugger); +#endif + + pr_info("Module initialized. v%s\n", DRIVER_VERSION); + + return 0; +} + +static void __exit rga_exit(void) +{ + free_pages((unsigned long)rga2_mmu_info.buf_virtual, + rga2_mmu_info.buf_order); + free_pages((unsigned long)rga2_mmu_info.pages, rga2_mmu_info.pages_order); + +#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER + rga_debugger_remove(&rga_drvdata->debugger); +#endif + + rga_mm_remove(&rga_drvdata->mm); + + wake_lock_destroy(&rga_drvdata->wake_lock); + + rga_fence_context_free(rga_drvdata->fence_ctx); + + rga_cancel_timer(); + + platform_driver_unregister(&rga3_core0_driver); + platform_driver_unregister(&rga3_core1_driver); + platform_driver_unregister(&rga2_driver); + + misc_deregister(&(rga_drvdata->miscdev)); + + kfree(rga_drvdata); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT +module_init(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"); diff --git a/drivers/video/rockchip/rga3/rga_fence.c b/drivers/video/rockchip/rga3/rga_fence.c new file mode 100644 index 000000000000..34bfd0a09a94 --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_fence.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#define pr_fmt(fmt) "rga_fence: " fmt + +#include +#include +#include + +#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, +}; + +struct rga_fence_context *rga_fence_context_alloc(void) +{ + struct rga_fence_context *fence_ctx = NULL; + + fence_ctx = kzalloc(sizeof(*fence_ctx), GFP_KERNEL); + if (!fence_ctx) + return ERR_PTR(-ENOMEM); + + fence_ctx->context = dma_fence_context_alloc(1); + spin_lock_init(&fence_ctx->spinlock); + + return fence_ctx; +} + +void rga_fence_context_free(struct rga_fence_context *fence_ctx) +{ + kfree(fence_ctx); +} + +int rga_out_fence_alloc(struct rga_job *job) +{ + struct rga_fence_context *fence_ctx = rga_drvdata->fence_ctx; + struct dma_fence *fence = NULL; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return -ENOMEM; + + dma_fence_init(fence, &rga_fence_ops, &job->fence_lock, + fence_ctx->context, ++fence_ctx->seqno); + + job->out_fence = fence; + + return 0; +} + +int rga_out_fence_get_fd(struct rga_job *job) +{ + struct sync_file *sync_file = NULL; + int fence_fd = -1; + + if (!job->out_fence) + return -EINVAL; + + fence_fd = get_unused_fd_flags(O_CLOEXEC); + if (fence_fd < 0) + return fence_fd; + + sync_file = sync_file_create(job->out_fence); + if (!sync_file) + return -ENOMEM; + + fd_install(fence_fd, sync_file->file); + + return fence_fd; +} + +struct dma_fence *rga_get_input_fence(int in_fence_fd) +{ + struct dma_fence *in_fence; + + in_fence = sync_file_get_fence(in_fence_fd); + + if (!in_fence) + pr_err("can not get in-fence from fd\n"); + + return in_fence; +} + +int rga_wait_input_fence(struct dma_fence *in_fence) +{ + int ret = 0; + + ret = dma_fence_wait(in_fence, true); + + dma_fence_put(in_fence); + + return ret; +} + +int rga_add_dma_fence_callback(struct rga_job *job, struct dma_fence *in_fence, + dma_fence_func_t func) +{ + struct rga_fence_waiter *waiter; + int ret; + + waiter = kmalloc(sizeof(*waiter), GFP_KERNEL); + if (!waiter) { + pr_err("%s: Failed to allocate waiter\n", __func__); + return -ENOMEM; + } + + waiter->job = job; + + ret = dma_fence_add_callback(in_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 000000000000..ca1f4c3ab26d --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_hw_config.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: + * Huang Lee + */ + +#include "rga_hw_config.h" + +const uint32_t rga3_raster_format[] = { + RGA2_FORMAT_RGBA_8888, + RGA2_FORMAT_BGRA_8888, + RGA2_FORMAT_RGB_888, + RGA2_FORMAT_BGR_888, + RGA2_FORMAT_RGB_565, + RGA2_FORMAT_BGR_565, + RGA2_FORMAT_YCbCr_422_SP, + RGA2_FORMAT_YCbCr_420_SP, + RGA2_FORMAT_YCrCb_422_SP, + RGA2_FORMAT_YCrCb_420_SP, + RGA2_FORMAT_YVYU_422, + RGA2_FORMAT_VYUY_422, + RGA2_FORMAT_YUYV_422, + RGA2_FORMAT_UYVY_422, + RGA2_FORMAT_YCbCr_420_SP_10B, + RGA2_FORMAT_YCrCb_420_SP_10B, + RGA2_FORMAT_YCbCr_422_SP_10B, + RGA2_FORMAT_YCrCb_422_SP_10B, +}; + +const uint32_t rga3_fbcd_format[] = { + RGA2_FORMAT_RGBA_8888, + RGA2_FORMAT_BGRA_8888, + RGA2_FORMAT_RGB_888, + RGA2_FORMAT_BGR_888, + RGA2_FORMAT_RGB_565, + RGA2_FORMAT_BGR_565, + RGA2_FORMAT_YCbCr_422_SP, + RGA2_FORMAT_YCbCr_420_SP, + RGA2_FORMAT_YCrCb_422_SP, + RGA2_FORMAT_YCrCb_420_SP, + RGA2_FORMAT_YCbCr_420_SP_10B, + RGA2_FORMAT_YCrCb_420_SP_10B, + RGA2_FORMAT_YCbCr_422_SP_10B, + RGA2_FORMAT_YCrCb_422_SP_10B, +}; + +const uint32_t rga3_tile_format[] = { + RGA2_FORMAT_YCbCr_422_SP, + RGA2_FORMAT_YCbCr_420_SP, + RGA2_FORMAT_YCrCb_422_SP, + RGA2_FORMAT_YCrCb_420_SP, + RGA2_FORMAT_YCbCr_420_SP_10B, + RGA2_FORMAT_YCrCb_420_SP_10B, + RGA2_FORMAT_YCbCr_422_SP_10B, + RGA2_FORMAT_YCrCb_422_SP_10B, +}; + +const uint32_t rga2e_raster_format[] = { + RGA2_FORMAT_RGBA_8888, + RGA2_FORMAT_RGBX_8888, + RGA2_FORMAT_BGRA_8888, + RGA2_FORMAT_BGRX_8888, + RGA2_FORMAT_RGB_888, + RGA2_FORMAT_BGR_888, + RGA2_FORMAT_RGB_565, + RGA2_FORMAT_BGR_565, + RGA2_FORMAT_YCbCr_422_P, + RGA2_FORMAT_YCbCr_420_P, + RGA2_FORMAT_YCrCb_422_P, + RGA2_FORMAT_YCrCb_420_P, + RGA2_FORMAT_YCbCr_422_SP, + RGA2_FORMAT_YCbCr_420_SP, + RGA2_FORMAT_YCrCb_422_SP, + RGA2_FORMAT_YCrCb_420_SP, + RGA2_FORMAT_YVYU_422, + RGA2_FORMAT_VYUY_422, + RGA2_FORMAT_YUYV_422, + RGA2_FORMAT_UYVY_422, + RGA2_FORMAT_YCbCr_420_SP_10B, + RGA2_FORMAT_YCrCb_420_SP_10B, + RGA2_FORMAT_YCbCr_422_SP_10B, + RGA2_FORMAT_YCrCb_422_SP_10B, + RGA2_FORMAT_Y4, + RGA2_FORMAT_YCbCr_400, + RGA2_FORMAT_RGBA_5551, + RGA2_FORMAT_BGRA_5551, + RGA2_FORMAT_RGBA_4444, + RGA2_FORMAT_BGRA_4444, + RGA2_FORMAT_XRGB_8888, + RGA2_FORMAT_XBGR_8888, + RGA2_FORMAT_BPP_1, + RGA2_FORMAT_BPP_2, + RGA2_FORMAT_BPP_4, + RGA2_FORMAT_BPP_8, + RGA2_FORMAT_ARGB_8888, + RGA2_FORMAT_ARGB_5551, + RGA2_FORMAT_ARGB_4444, + RGA2_FORMAT_ABGR_8888, + RGA2_FORMAT_ABGR_5551, + RGA2_FORMAT_ABGR_4444, +}; + +const struct rga_win_data rga3_win_data[] = { + { + .name = "rga3-win0", + .raster_formats = rga3_raster_format, + .num_of_raster_formats = ARRAY_SIZE(rga3_raster_format), + .fbc_formats = rga3_fbcd_format, + .num_of_fbc_formats = ARRAY_SIZE(rga3_fbcd_format), + .tile_formats = rga3_tile_format, + .num_of_tile_formats = 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", + .raster_formats = rga3_raster_format, + .num_of_raster_formats = ARRAY_SIZE(rga3_raster_format), + .fbc_formats = rga3_fbcd_format, + .num_of_fbc_formats = ARRAY_SIZE(rga3_fbcd_format), + .tile_formats = rga3_tile_format, + .num_of_tile_formats = 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", + .raster_formats = rga3_raster_format, + .num_of_raster_formats = ARRAY_SIZE(rga3_raster_format), + .fbc_formats = rga3_fbcd_format, + .num_of_fbc_formats = ARRAY_SIZE(rga3_fbcd_format), + .tile_formats = rga3_tile_format, + .num_of_tile_formats = 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", + .raster_formats = rga2e_raster_format, + .num_of_raster_formats = ARRAY_SIZE(rga2e_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", + .raster_formats = rga2e_raster_format, + .num_of_raster_formats = ARRAY_SIZE(rga2e_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", + .raster_formats = rga2e_raster_format, + .num_of_raster_formats = ARRAY_SIZE(rga2e_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, + .min_input = { 128, 128 }, + .min_output = { 128, 128 }, + .max_input = { 8176, 8176 }, + .max_output = { 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, + + .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, +}; + +const struct rga_hw_data rga2e_data = { + .version = 0, + .min_input = { 0, 0 }, + .min_output = { 0, 0 }, + .max_input = { 8192, 8192 }, + .max_output = { 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, + + .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE | + RGA_COLOR_KEY | RGA_ROP_CALCULATE | + RGA_NN_QUANTIZE | RGA_DITHER, + .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, +}; diff --git a/drivers/video/rockchip/rga3/rga_job.c b/drivers/video/rockchip/rga3/rga_job.c new file mode 100644 index 000000000000..fb14f4cd334c --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_job.c @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#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 "rga2_mmu_info.h" + +struct rga_job * +rga_scheduler_get_pending_job_list(struct rga_scheduler_t *scheduler) +{ + unsigned long flags; + struct rga_job *job; + + spin_lock_irqsave(&scheduler->irq_lock, flags); + + job = list_first_entry_or_null(&scheduler->todo_list, + struct rga_job, head); + + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + + return job; +} + +struct rga_job * +rga_scheduler_get_running_job(struct rga_scheduler_t *scheduler) +{ + unsigned long flags; + struct rga_job *job; + + spin_lock_irqsave(&scheduler->irq_lock, flags); + + job = scheduler->running_job; + + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + + return job; +} + +struct rga_scheduler_t *rga_job_get_scheduler(int core) +{ + struct rga_scheduler_t *scheduler = NULL; + int i; + + for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { + if (core == rga_drvdata->rga_scheduler[i]->core) { + scheduler = rga_drvdata->rga_scheduler[i]; + + if (DEBUGGER_EN(MSG)) + pr_info("job choose core: %d\n", + rga_drvdata->rga_scheduler[i]->core); + break; + } + } + + return scheduler; +} + +static int rga_job_get_current_mm(struct rga_job *job) +{ + 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 = &job->rga_command_base.src; + dst = &job->rga_command_base.dst; + if (job->rga_command_base.render_mode != UPDATE_PALETTE_TABLE_MODE) + src1 = &job->rga_command_base.pat; + else + els = &job->rga_command_base.pat; + + if (likely(src0 != NULL)) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 8) & 1); + if (mmu_flag && src0->uv_addr) + goto get_current_mm; + } + + if (likely(dst != NULL)) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 10) & 1); + if (mmu_flag && dst->uv_addr) + goto get_current_mm; + } + + if (src1 != NULL) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 9) & 1); + if (mmu_flag && src1->yrgb_addr) + goto get_current_mm; + } + + if (els != NULL) { + mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 11) & 1); + if (mmu_flag && els->yrgb_addr) + goto get_current_mm; + } + + return 0; + +get_current_mm: + mmgrab(current->mm); + mmget(current->mm); + job->mm = current->mm; + + return 1; +} + +static void rga_job_put_current_mm(struct rga_job *job) +{ + if (job->mm == NULL) + return; + + mmput(job->mm); + mmdrop(job->mm); + job->mm = NULL; +} + +static void rga_job_free(struct rga_job *job) +{ + if (job->out_fence) + dma_fence_put(job->out_fence); + + if (~job->flags & RGA_JOB_USE_HANDLE) + rga_job_put_current_mm(job); + + free_page((unsigned long)job); +} + +static int rga_job_cleanup(struct rga_job *job) +{ + rga_job_free(job); + + 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_MM_UNDER_4G) { + job->flags |= RGA_JOB_UNSUPPORT_RGA2; + 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_MM_UNDER_4G) { + job->flags |= RGA_JOB_UNSUPPORT_RGA2; + 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_MM_UNDER_4G) { + job->flags |= RGA_JOB_UNSUPPORT_RGA2; + 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; + + spin_lock_init(&job->fence_lock); + INIT_LIST_HEAD(&job->head); + + job->timestamp = ktime_get(); + job->running_time = ktime_get(); + + 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); + } else { + rga_job_get_current_mm(job); + } + + return job; +} + +static void print_job_info(struct rga_job *job) +{ + pr_info("job: priority = %d, core = %d\n", + job->priority, job->core); +} + +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; + } + + if (job->flags & RGA_JOB_USE_HANDLE) { + ret = rga_mm_get_handle_info(job); + if (ret < 0) { + pr_err("%s: failed to get buffer from handle\n", __func__); + goto failed; + } + } else { + ret = rga_dma_get_info(job); + if (ret < 0) { + pr_err("dma buf get failed"); + goto failed; + } + } + + ret = scheduler->ops->init_reg(job); + if (ret < 0) { + pr_err("init reg failed"); + goto failed; + } + + ret = scheduler->ops->set_reg(job, scheduler); + if (ret < 0) { + pr_err("set reg failed"); + goto failed; + } + + /* for debug */ + if (DEBUGGER_EN(MSG)) + print_job_info(job); + + return ret; + +failed: + rga_power_disable(scheduler); + + return ret; +} + +static void rga_job_next(struct rga_scheduler_t *rga_scheduler) +{ + struct rga_job *job = NULL; + unsigned long flags; + +next_job: + spin_lock_irqsave(&rga_scheduler->irq_lock, flags); + + if (rga_scheduler->running_job || + list_empty(&rga_scheduler->todo_list)) { + spin_unlock_irqrestore(&rga_scheduler->irq_lock, flags); + return; + } + + job = list_first_entry(&rga_scheduler->todo_list, struct rga_job, head); + + list_del_init(&job->head); + + rga_scheduler->job_count--; + + rga_scheduler->running_job = job; + + spin_unlock_irqrestore(&rga_scheduler->irq_lock, flags); + + job->ret = rga_job_run(job, rga_scheduler); + + /* If some error before hw run */ + if (job->ret < 0) { + pr_err("some error on rga_job_run before hw start, %s(%d)\n", + __func__, __LINE__); + + spin_lock_irqsave(&rga_scheduler->irq_lock, flags); + + rga_scheduler->running_job = NULL; + + spin_unlock_irqrestore(&rga_scheduler->irq_lock, flags); + + if (job->flags & RGA_JOB_USE_HANDLE) + rga_mm_put_handle_info(job); + else + rga_dma_put_info(job); + + if (job->out_fence) + dma_fence_signal(job->out_fence); + + if (job->flags & RGA_JOB_ASYNC) + rga_job_cleanup(job); + else { + job->flags |= RGA_JOB_DONE; + wake_up(&rga_scheduler->job_done_wq); + } + + goto next_job; + } +} + +void rga_job_done(struct rga_scheduler_t *rga_scheduler, int ret) +{ + struct rga_job *job; + unsigned long flags; + + ktime_t now = ktime_get(); + + spin_lock_irqsave(&rga_scheduler->irq_lock, flags); + + job = rga_scheduler->running_job; + rga_scheduler->running_job = NULL; + + rga_scheduler->timer.busy_time += ktime_us_delta(now, job->timestamp); + + spin_unlock_irqrestore(&rga_scheduler->irq_lock, flags); + + job->flags |= RGA_JOB_DONE; + job->ret = ret; + + if (DEBUGGER_EN(TIME)) + pr_err("%s use time = %lld\n", __func__, + ktime_us_delta(now, job->running_time)); + + job->running_time = now; + + if (job->core == RGA2_SCHEDULER_CORE0) + rga2_dma_flush_cache_for_virtual_address(&job->vir_page_table, + rga_scheduler); + + if (job->flags & RGA_JOB_USE_HANDLE) + rga_mm_put_handle_info(job); + else + rga_dma_put_info(job); + + if (job->out_fence) + dma_fence_signal(job->out_fence); + + if (job->flags & RGA_JOB_ASYNC) + rga_job_cleanup(job); + + wake_up(&rga_scheduler->job_done_wq); + + rga_job_next(rga_scheduler); + + rga_power_disable(rga_scheduler); +} + +static void rga_job_timeout_clean(struct rga_scheduler_t *scheduler) +{ + unsigned long flags; + struct rga_job *job = NULL; + ktime_t now = ktime_get(); + + spin_lock_irqsave(&scheduler->irq_lock, flags); + + job = scheduler->running_job; + if (job && (job->flags & RGA_JOB_ASYNC) && + (ktime_to_ms(ktime_sub(now, job->timestamp)) >= RGA_ASYNC_TIMEOUT_DELAY)) { + scheduler->running_job = NULL; + + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + + scheduler->ops->soft_reset(scheduler); + + if (job->flags & RGA_JOB_USE_HANDLE) + rga_mm_put_handle_info(job); + else + rga_dma_put_info(job); + + if (job->out_fence) + dma_fence_signal(job->out_fence); + + rga_job_cleanup(job); + + rga_power_disable(scheduler); + } else { + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + } +} + +static struct rga_scheduler_t *rga_job_schedule(struct rga_job *job) +{ + unsigned long flags; + struct rga_scheduler_t *scheduler = NULL; + struct rga_job *job_pos; + bool first_match = 0; + + if (rga_drvdata->num_of_scheduler > 1) { + job->core = rga_job_assign(job); + if (job->core <= 0) { + pr_err("job assign failed"); + return NULL; + } + } else { + job->core = rga_drvdata->rga_scheduler[0]->core; + } + + scheduler = rga_job_get_scheduler(job->core); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__); + return NULL; + } + + rga_job_timeout_clean(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++; + + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + + rga_job_next(scheduler); + + return scheduler; +} + +static void rga_running_job_abort(struct rga_job *job, + struct rga_scheduler_t *rga_scheduler) +{ + unsigned long flags; + + spin_lock_irqsave(&rga_scheduler->irq_lock, flags); + + /* invalid job */ + if (job == rga_scheduler->running_job) { + rga_scheduler->running_job = NULL; + } + + spin_unlock_irqrestore(&rga_scheduler->irq_lock, flags); + + rga_job_cleanup(job); +} + +static void rga_invalid_job_abort(struct rga_job *job) +{ + rga_job_cleanup(job); +} + +static inline int rga_job_wait(struct rga_scheduler_t *rga_scheduler, + struct rga_job *job) +{ + int left_time; + ktime_t now; + int ret; + + left_time = wait_event_interruptible_timeout(rga_scheduler->job_done_wq, + job->flags & RGA_JOB_DONE, RGA_SYNC_TIMEOUT_DELAY); + + switch (left_time) { + case 0: + pr_err("%s timeout", __func__); + rga_scheduler->ops->soft_reset(rga_scheduler); + ret = -EBUSY; + break; + case -ERESTARTSYS: + ret = -ERESTARTSYS; + break; + default: + ret = 0; + break; + } + + now = ktime_get(); + + if (DEBUGGER_EN(TIME)) + pr_err("%s use time = %lld\n", __func__, + ktime_to_us(ktime_sub(now, job->running_time))); + + return ret; +} + +static void rga_input_fence_signaled(struct dma_fence *fence, + struct dma_fence_cb *_waiter) +{ + struct rga_fence_waiter *waiter = (struct rga_fence_waiter *)_waiter; + struct rga_scheduler_t *scheduler = NULL; + + ktime_t now; + + now = ktime_get(); + + if (DEBUGGER_EN(TIME)) + pr_err("rga job wait in_fence signal use time = %lld\n", + ktime_to_us(ktime_sub(now, waiter->job->timestamp))); + + scheduler = rga_job_schedule(waiter->job); + + if (scheduler == NULL) + pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__); + + kfree(waiter); +} + +int rga_job_commit(struct rga_req *rga_command_base, int flags) +{ + struct rga_job *job = NULL; + struct rga_scheduler_t *scheduler = NULL; + struct dma_fence *in_fence; + int ret = 0; + + job = rga_job_alloc(rga_command_base); + if (!job) { + pr_err("failed to alloc rga job!\n"); + return -ENOMEM; + } + + /* + * because fd can not pass on other thread, + * so need to get dma_buf first. + */ + ret = rga_dma_buf_get(job); + if (ret < 0) { + pr_err("%s: failed to get dma buf from fd\n", + __func__); + rga_job_free(job); + return ret; + } + + if (flags == RGA_BLIT_ASYNC) { + ret = rga_out_fence_alloc(job); + if (ret) { + rga_job_free(job); + return ret; + } + job->flags |= RGA_JOB_ASYNC; + rga_command_base->out_fence_fd = rga_out_fence_get_fd(job); + + if (DEBUGGER_EN(MSG)) + pr_err("in_fence_fd = %d", + rga_command_base->in_fence_fd); + + /* if input fence is valiable */ + if (rga_command_base->in_fence_fd > 0) { + in_fence = rga_get_input_fence( + rga_command_base->in_fence_fd); + if (!in_fence) { + pr_err("%s: failed to get input dma_fence\n", + __func__); + rga_job_free(job); + return ret; + } + + /* close input fence fd */ + ksys_close(rga_command_base->in_fence_fd); + + ret = dma_fence_get_status(in_fence); + /* ret = 1: fence has been signaled */ + if (ret == 1) { + scheduler = rga_job_schedule(job); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", + __func__, __LINE__); + ret = -EINVAL; + goto invalid_job; + } + /* if input fence is valid */ + } else if (ret == 0) { + ret = rga_add_dma_fence_callback(job, + in_fence, rga_input_fence_signaled); + if (ret < 0) { + pr_err("%s: failed to add fence callback\n", + __func__); + rga_job_free(job); + return ret; + } + } else { + pr_err("%s: fence status error\n", __func__); + rga_job_free(job); + return ret; + } + } else { + scheduler = rga_job_schedule(job); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", + __func__, __LINE__); + ret = -EINVAL; + goto invalid_job; + } + } + + return ret; + /* sync mode: wait utill job finish */ + } else if (flags == RGA_BLIT_SYNC) { + scheduler = rga_job_schedule(job); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + goto invalid_job; + } + + ret = job->ret; + if (ret < 0) { + pr_err("some error on job, %s(%d)\n", __func__, + __LINE__); + goto running_job_abort; + } + + ret = rga_job_wait(scheduler, job); + if (ret < 0) { + goto running_job_abort; + } + + rga_job_cleanup(job); + } + return ret; + +invalid_job: + rga_invalid_job_abort(job); + return ret; + +/* only used by SYNC mode */ +running_job_abort: + rga_running_job_abort(job, scheduler); + return ret; +} + +int rga_job_mpi_commit(struct rga_req *rga_command_base, + struct rga_mpi_job_t *mpi_job, int flags) +{ + struct rga_job *job = NULL; + struct rga_scheduler_t *scheduler = NULL; + int ret = 0; + + job = rga_job_alloc(rga_command_base); + if (!job) { + pr_err("failed to alloc rga job!\n"); + return -ENOMEM; + } + + if (mpi_job != NULL) { + job->dma_buf_src0 = mpi_job->dma_buf_src0; + job->dma_buf_src1 = mpi_job->dma_buf_src1; + job->dma_buf_dst = mpi_job->dma_buf_dst; + } + + if (flags == RGA_BLIT_ASYNC) { + //TODO: + pr_err("rk-debug TODO\n"); + } else if (flags == RGA_BLIT_SYNC) { + scheduler = rga_job_schedule(job); + if (scheduler == NULL) { + pr_err("failed to get scheduler, %s(%d)\n", __func__, + __LINE__); + ret = -EINVAL; + goto invalid_job; + } + + ret = job->ret; + if (ret < 0) { + pr_err("some error on job, %s(%d)\n", __func__, + __LINE__); + goto running_job_abort; + } + + ret = rga_job_wait(scheduler, job); + if (ret < 0) { + goto running_job_abort; + } + rga_job_cleanup(job); + } + return ret; + +invalid_job: + rga_invalid_job_abort(job); + return ret; + +/* only used by SYNC mode */ +running_job_abort: + rga_running_job_abort(job, scheduler); + return ret; +} diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c new file mode 100644 index 000000000000..8fbf859f8495 --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -0,0 +1,1135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Cerf Yu + */ + +#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" + +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("failed to get vma\n"); + 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("failed to get pgd\n"); + 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("failed to get p4d\n"); + 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("failed to get pud\n"); + ret = RGA_OUT_OF_RESOURCES; + break; + } + pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { + pr_err("failed to get pmd\n"); + 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("failed to get pte\n"); + 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); + } + + 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, 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, pages, NULL, NULL); +#else + result = get_user_pages_remote(current_mm, Memory << PAGE_SHIFT, + pageCount, writeFlag, pages, NULL, 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) { + pr_err("Can not get user pages from vma, result = %d, pagecount = %d\n", + result, pageCount); + } + } + + rga_current_mm_read_unlock(current_mm); + + return ret; +} + +static void rga_free_sgt(struct rga_dma_buffer *virt_dma_buf) +{ + if (virt_dma_buf->sgt == NULL) + return; + + sg_free_table(virt_dma_buf->sgt); + kfree(virt_dma_buf->sgt); + virt_dma_buf->sgt = NULL; +} + +static int rga_alloc_sgt(struct rga_virt_addr *virt_addr, + struct rga_dma_buffer *virt_dma_buf) +{ + int ret; + struct sg_table *sgt = NULL; + + sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (sgt == NULL) { + pr_err("%s alloc sgt error!\n", __func__); + return -ENOMEM; + } + + /* get sg form pages. */ + if (sg_alloc_table_from_pages(sgt, virt_addr->pages, + virt_addr->page_count, 0, + virt_addr->size, GFP_KERNEL)) { + pr_err("sg_alloc_table_from_pages failed"); + ret = -ENOMEM; + goto out_free_sgt; + } + + virt_dma_buf->sgt = sgt; + virt_dma_buf->size = virt_addr->size; + virt_dma_buf->offset = virt_addr->offset; + + return 0; + +out_free_sgt: + kfree(sgt); + + return 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; + int format; + unsigned int count; + unsigned long start_addr; + unsigned long size; + struct page **pages = NULL; + struct rga_virt_addr *virt_addr = NULL; + + rga_user_format_convert(&format, memory_parm->format); + + /* Calculate page size. */ + count = rga_buf_size_cal(viraddr, viraddr, viraddr, format, + memory_parm->width, memory_parm->height, + &start_addr, NULL); + size = count * PAGE_SIZE; + + /* alloc pages and page_table */ + order = get_order(count * sizeof(struct page *)); + pages = (struct page **)__get_free_pages(GFP_KERNEL, order); + if (pages == NULL) { + pr_err("%s can not alloc pages for pages\n", __func__); + return -ENOMEM; + } + + /* get pages from virtual address. */ + ret = rga_get_user_pages(pages, start_addr, count, writeFlag, mm); + if (ret < 0) { + pr_err("failed to get pages"); + 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 = viraddr & (~PAGE_MASK); + 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; +} + +/* 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 void rga_mm_unmap_dma_buffer(struct rga_internal_buffer *internal_buffer) +{ + int i; + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) + rga_dma_unmap_fd(&internal_buffer->dma_buffer[i]); + + 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) +{ + int ret, i; + + internal_buffer->dma_buffer_size = rga_drvdata->num_of_scheduler; + internal_buffer->dma_buffer = kcalloc(internal_buffer->dma_buffer_size, + sizeof(struct rga_dma_buffer), GFP_KERNEL); + if (internal_buffer->dma_buffer == NULL) { + pr_err("%s alloc internal_buffer error!\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) { + /* If the physical address is greater than 4G, there is no need to map RGA2. */ + if ((rga_drvdata->rga_scheduler[i]->core == RGA2_SCHEDULER_CORE0) && + (~internal_buffer->mm_flag & RGA_MM_UNDER_4G) && + i != 0) + continue; + + ret = rga_dma_map_fd((int)external_buffer->memory, + &internal_buffer->dma_buffer[i], + DMA_BIDIRECTIONAL, + rga_drvdata->rga_scheduler[i]->dev); + if (ret < 0) { + pr_err("%s core[%d] map dma buffer error!\n", + __func__, rga_drvdata->rga_scheduler[0]->core); + goto FREE_RGA_DMA_BUF; + } + + internal_buffer->dma_buffer[i].core = rga_drvdata->rga_scheduler[i]->core; + + /* At first, check whether the physical address is greater than 4G. */ + if (i == 0) + if (rga_mm_check_range_sgt(internal_buffer->dma_buffer[0].sgt)) + internal_buffer->mm_flag |= RGA_MM_UNDER_4G; + } + + return 0; + +FREE_RGA_DMA_BUF: + rga_mm_unmap_dma_buffer(internal_buffer); + + return ret; +} + +static void rga_mm_unmap_virt_addr(struct rga_internal_buffer *internal_buffer) +{ + int i; + + WARN_ON(internal_buffer->dma_buffer == NULL || internal_buffer->virt_addr == NULL); + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) + if (rga_drvdata->rga_scheduler[i]->core == RGA3_SCHEDULER_CORE0 || + rga_drvdata->rga_scheduler[i]->core == RGA3_SCHEDULER_CORE1) + rga_iommu_unmap_virt_addr(&internal_buffer->dma_buffer[i]); + else if (internal_buffer->dma_buffer[i].core != 0) + dma_unmap_sg(rga_drvdata->rga_scheduler[i]->dev, + internal_buffer->dma_buffer[i].sgt->sgl, + internal_buffer->dma_buffer[i].sgt->orig_nents, + DMA_BIDIRECTIONAL); + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) + rga_free_sgt(&internal_buffer->dma_buffer[i]); + kfree(internal_buffer->dma_buffer); + internal_buffer->dma_buffer_size = 0; + + 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) +{ + int i; + int ret; + + internal_buffer->current_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(&internal_buffer->virt_addr, + external_buffer->memory, + &internal_buffer->memory_parm, + 0, 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; + } + + internal_buffer->dma_buffer = kcalloc(rga_drvdata->num_of_scheduler, + sizeof(struct rga_dma_buffer), GFP_KERNEL); + if (internal_buffer->dma_buffer == NULL) { + pr_err("%s alloc internal_buffer->dma_buffer error!\n", __func__); + ret = -ENOMEM; + goto free_virt_addr; + } + internal_buffer->dma_buffer_size = rga_drvdata->num_of_scheduler; + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) { + /* If the physical address is greater than 4G, there is no need to map RGA2. */ + if ((rga_drvdata->rga_scheduler[i]->core == RGA2_SCHEDULER_CORE0) && + (~internal_buffer->mm_flag & RGA_MM_UNDER_4G) && + i != 0) + continue; + + ret = rga_alloc_sgt(internal_buffer->virt_addr, + &internal_buffer->dma_buffer[i]); + if (ret < 0) { + pr_err("%s core[%d] alloc sgt error!\n", __func__, + rga_drvdata->rga_scheduler[0]->core); + goto free_sgt_and_dma_buffer; + } + + if (i == 0) + if (rga_mm_check_range_sgt(internal_buffer->dma_buffer[0].sgt)) + internal_buffer->mm_flag |= RGA_MM_UNDER_4G; + } + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) { + if ((rga_drvdata->rga_scheduler[i]->core == RGA2_SCHEDULER_CORE0) && + (~internal_buffer->mm_flag & RGA_MM_UNDER_4G)) + continue; + + if (rga_drvdata->rga_scheduler[i]->core == RGA3_SCHEDULER_CORE0 || + rga_drvdata->rga_scheduler[i]->core == RGA3_SCHEDULER_CORE1) { + ret = rga_iommu_map_virt_addr(&internal_buffer->memory_parm, + &internal_buffer->dma_buffer[i], + rga_drvdata->rga_scheduler[i]->dev, + internal_buffer->current_mm); + if (ret < 0) { + pr_err("%s core[%d] iommu_map virtual address error!\n", + __func__, rga_drvdata->rga_scheduler[i]->core); + goto unmap_virt_addr; + } + } else { + ret = dma_map_sg(rga_drvdata->rga_scheduler[i]->dev, + internal_buffer->dma_buffer[i].sgt->sgl, + internal_buffer->dma_buffer[i].sgt->orig_nents, + DMA_BIDIRECTIONAL); + if (ret == 0) { + pr_err("%s core[%d] dma_map_sgt error! va = 0x%lx, nents = %d\n", + __func__, rga_drvdata->rga_scheduler[i]->core, + (unsigned long)internal_buffer->virt_addr->addr, + internal_buffer->dma_buffer[i].sgt->orig_nents); + goto unmap_virt_addr; + } + } + + internal_buffer->dma_buffer[i].core = rga_drvdata->rga_scheduler[i]->core; + } + + return 0; + +unmap_virt_addr: + for (i = 0; i < internal_buffer->dma_buffer_size; i++) + if (rga_drvdata->rga_scheduler[i]->core == RGA3_SCHEDULER_CORE0 || + rga_drvdata->rga_scheduler[i]->core == RGA3_SCHEDULER_CORE1) + rga_iommu_unmap_virt_addr(&internal_buffer->dma_buffer[i]); + else if (internal_buffer->dma_buffer[i].core != 0) + dma_unmap_sg(rga_drvdata->rga_scheduler[i]->dev, + internal_buffer->dma_buffer[i].sgt->sgl, + internal_buffer->dma_buffer[i].sgt->orig_nents, + DMA_BIDIRECTIONAL); +free_sgt_and_dma_buffer: + for (i = 0; i < internal_buffer->dma_buffer_size; i++) + rga_free_sgt(&internal_buffer->dma_buffer[i]); + kfree(internal_buffer->dma_buffer); +free_virt_addr: + rga_free_virt_addr(&internal_buffer->virt_addr); +put_current_mm: + mmput(internal_buffer->current_mm); + mmdrop(internal_buffer->current_mm); + internal_buffer->current_mm = NULL; + + return ret; +} + +static int rga_mm_unmap_buffer(struct rga_internal_buffer *internal_buffer) +{ + switch (internal_buffer->type) { + case RGA_DMA_BUFFER: + rga_mm_unmap_dma_buffer(internal_buffer); + break; + case RGA_VIRTUAL_ADDRESS: + rga_mm_unmap_virt_addr(internal_buffer); + break; + case RGA_PHYSICAL_ADDRESS: + internal_buffer->phys_addr = 0; + 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) +{ + int ret; + + memcpy(&internal_buffer->memory_parm, &external_buffer->memory_parm, + sizeof(internal_buffer->memory_parm)); + + switch (external_buffer->type) { + case RGA_DMA_BUFFER: + internal_buffer->type = RGA_DMA_BUFFER; + + ret = rga_mm_map_dma_buffer(external_buffer, internal_buffer); + if (ret < 0) { + pr_err("%s map dma_buf error!\n", __func__); + return ret; + } + + internal_buffer->mm_flag |= RGA_MM_NEED_USE_IOMMU; + break; + case RGA_VIRTUAL_ADDRESS: + internal_buffer->type = RGA_VIRTUAL_ADDRESS; + + ret = rga_mm_map_virt_addr(external_buffer, internal_buffer); + if (ret < 0) { + pr_err("%s iommu_map virtual address error!\n", __func__); + return ret; + } + + internal_buffer->mm_flag |= RGA_MM_NEED_USE_IOMMU; + break; + case RGA_PHYSICAL_ADDRESS: + internal_buffer->type = RGA_PHYSICAL_ADDRESS; + + internal_buffer->phys_addr = external_buffer->memory; + 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 struct rga_internal_buffer * +rga_mm_lookup_external(struct rga_mm *mm_session, + struct rga_external_buffer *external_buffer) +{ + 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) { + output_buffer = temp_buffer; + break; + } + } + + 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; + 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, int core) +{ + int i; + + for (i = 0; i < buffer->dma_buffer_size; i++) + if (buffer->dma_buffer[i].core == core) + return buffer->dma_buffer[i].iova + buffer->dma_buffer[i].offset; + + return 0; +} + +struct sg_table *rga_mm_lookup_sgt(struct rga_internal_buffer *buffer, int core) +{ + int i; + + for (i = 0; i < buffer->dma_buffer_size; i++) + if (buffer->dma_buffer[i].core == core) + return buffer->dma_buffer[i].sgt; + + return NULL; +} + +void rga_mm_dump_info(struct rga_mm *mm_session) +{ + int id, i; + 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) { + 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: + pr_info("dma_buffer:\n"); + for (i = 0; i < dump_buffer->dma_buffer_size; i++) { + pr_info("\t core %d:\n", dump_buffer->dma_buffer[i].core); + pr_info("\t\t dma_buf = %p, iova = 0x%lx\n", + dump_buffer->dma_buffer[i].dma_buf, + (unsigned long)dump_buffer->dma_buffer[i].iova); + } + break; + case RGA_VIRTUAL_ADDRESS: + pr_info("virtual address:\n"); + pr_info("\t 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); + + for (i = 0; i < dump_buffer->dma_buffer_size; i++) { + pr_info("\t core %d:\n", dump_buffer->dma_buffer[i].core); + pr_info("\t\t iova = 0x%lx, sgt = %p, size = %ld\n", + (unsigned long)dump_buffer->dma_buffer[i].iova, + dump_buffer->dma_buffer[i].sgt, + dump_buffer->dma_buffer[i].size); + } + break; + case RGA_PHYSICAL_ADDRESS: + pr_info("physical address:\n"); + pr_info("\t pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr); + break; + default: + pr_err("Illegal external buffer!\n"); + break; + } + + pr_info("---------------------------------------------------------------\n"); + } +} + +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 = job->src_buffer ? job->src_buffer->mm_flag & RGA_MM_NEED_USE_IOMMU : 0; + src1_mmu_en = job->src1_buffer ? job->src1_buffer->mm_flag & RGA_MM_NEED_USE_IOMMU : 0; + dst_mmu_en = job->dst_buffer ? job->dst_buffer->mm_flag & RGA_MM_NEED_USE_IOMMU : 0; + els_mmu_en = job->els_buffer ? job->els_buffer->mm_flag & RGA_MM_NEED_USE_IOMMU : 0; + + mmu_info = &job->rga_command_base.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_sync_dma_sg_for_device(struct rga_internal_buffer *buffer, + int core, + enum dma_data_direction dir) +{ + struct sg_table *sgt; + struct rga_scheduler_t *scheduler; + + scheduler = rga_job_get_scheduler(core); + if (scheduler == NULL) { + pr_err("%s(%d), failed to get scheduler, core = 0x%x\n", + __func__, __LINE__, core); + return -EFAULT; + } + + sgt = rga_mm_lookup_sgt(buffer, core); + if (sgt == NULL) { + pr_err("%s(%d), failed to get sgt, core = 0x%x\n", + __func__, __LINE__, 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, + int core, + enum dma_data_direction dir) +{ + struct sg_table *sgt; + struct rga_scheduler_t *scheduler; + + scheduler = rga_job_get_scheduler(core); + if (scheduler == NULL) { + pr_err("%s(%d), failed to get scheduler, core = 0x%x\n", + __func__, __LINE__, core); + return -EFAULT; + } + + sgt = rga_mm_lookup_sgt(buffer, core); + if (sgt == NULL) { + pr_err("%s(%d), failed to get sgt, core = 0x%x\n", + __func__, __LINE__, core); + return -EINVAL; + } + + dma_sync_sg_for_cpu(scheduler->dev, sgt->sgl, sgt->orig_nents, dir); + + return 0; +} + +static int rga_mm_get_channel_handle_info(struct rga_mm *mm, + struct rga_job *job, + struct rga_img_info_t *img, + struct rga_internal_buffer **buf, + enum dma_data_direction dir) +{ + int ret = 0; + struct rga_internal_buffer *internal_buffer = NULL; + + if (!(img->yrgb_addr > 0)) { + pr_err("No buffer handle can be used!\n"); + return -EFAULT; + } + + mutex_lock(&mm->lock); + *buf = rga_mm_lookup_handle(mm, img->yrgb_addr); + if (*buf == NULL) { + pr_err("This handle[%ld] is illegal.\n", (unsigned long)img->yrgb_addr); + + ret = -EFAULT; + goto unlock_mm_and_return; + } + + internal_buffer = *buf; + kref_get(&internal_buffer->refcount); + + switch (internal_buffer->type) { + case RGA_DMA_BUFFER: + if (job->core == RGA3_SCHEDULER_CORE0 || + job->core == RGA3_SCHEDULER_CORE1) { + img->yrgb_addr = rga_mm_lookup_iova(internal_buffer, job->core); + if (img->yrgb_addr == 0) { + pr_err("lookup dma_buf iova error!\n"); + + ret = -EINVAL; + goto unlock_mm_and_return; + } + } else { + img->yrgb_addr = 0; + } + + break; + case RGA_VIRTUAL_ADDRESS: + if (job->core == RGA3_SCHEDULER_CORE0 || + job->core == RGA3_SCHEDULER_CORE1) { + img->yrgb_addr = rga_mm_lookup_iova(internal_buffer, job->core); + if (img->yrgb_addr == 0) { + pr_err("lookup virt_addr iova error!\n"); + + ret = -EINVAL; + goto unlock_mm_and_return; + } + } else { + img->yrgb_addr = internal_buffer->virt_addr->addr; + } + + /* + * 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->core, dir); + if (ret < 0) { + pr_err("sync sgt for device error!\n"); + goto unlock_mm_and_return; + } + + break; + case RGA_PHYSICAL_ADDRESS: + img->yrgb_addr = internal_buffer->phys_addr; + break; + default: + pr_err("Illegal external buffer!\n"); + + ret = -EFAULT; + goto unlock_mm_and_return; + } + mutex_unlock(&mm->lock); + + rga_convert_addr(img, false); + + return 0; +unlock_mm_and_return: + mutex_unlock(&mm->lock); + return ret; +} + +static void rga_mm_put_channel_handle_info(struct rga_mm *mm, + struct rga_internal_buffer *internal_buffer, + int core, + enum dma_data_direction dir) +{ + int ret; + + if (internal_buffer->type == RGA_VIRTUAL_ADDRESS && dir != DMA_NONE) { + ret = rga_mm_sync_dma_sg_for_cpu(internal_buffer, core, dir); + if (ret < 0) { + pr_err("sync sgt for cpu error!\n"); + goto put_internal_buffer; + } + } + +put_internal_buffer: + mutex_lock(&mm->lock); + + kref_put(&internal_buffer->refcount, rga_mm_kref_release_buffer); + + mutex_unlock(&mm->lock); +} + +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; + + 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!\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!\n"); + return ret; + } + } + + if (likely(req->pat.yrgb_addr > 0)) { + + if (job->rga_command_base.render_mode != UPDATE_PALETTE_TABLE_MODE) { + if (job->rga_command_base.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!\n"); + return ret; + } + } + + rga_mm_set_mmu_flag(job); + + return 0; +} + +void rga_mm_put_handle_info(struct rga_job *job) +{ + struct rga_mm *mm = NULL; + + mm = rga_drvdata->mm; + + if (job->src_buffer) + rga_mm_put_channel_handle_info(mm, job->src_buffer, job->core, DMA_NONE); + if (job->dst_buffer) + rga_mm_put_channel_handle_info(mm, job->dst_buffer, job->core, DMA_FROM_DEVICE); + if (job->src1_buffer) + rga_mm_put_channel_handle_info(mm, job->src1_buffer, job->core, DMA_NONE); + if (job->els_buffer) + rga_mm_put_channel_handle_info(mm, job->els_buffer, job->core, DMA_NONE); +} + +uint32_t rga_mm_import_buffer(struct rga_external_buffer *external_buffer) +{ + int ret = 0; + 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); + if (!IS_ERR_OR_NULL(internal_buffer)) { + kref_get(&internal_buffer->refcount); + + mutex_unlock(&mm->lock); + 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); + if (ret < 0) + goto FREE_INTERNAL_BUFFER; + + kref_init(&internal_buffer->refcount); + + /* + * Get the user-visible handle using idr. Preload and perform + * allocation under our spinlock. + */ + idr_preload(GFP_KERNEL); + internal_buffer->handle = idr_alloc(&mm->memory_idr, internal_buffer, 1, 0, GFP_KERNEL); + idr_preload_end(); + + mm->buffer_count++; + + 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; + } + + kref_put(&internal_buffer->refcount, rga_mm_kref_release_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 000000000000..bcf1ef168e5e --- /dev/null +++ b/drivers/video/rockchip/rga3/rga_policy.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Rockchip Electronics Co., Ltd. + * + * Author: Huang Lee + */ + +#define pr_fmt(fmt) "rga_policy: " fmt + +#include "rga_job.h" +#include "rga_common.h" +#include "rga_hw_config.h" + +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_format(const struct rga_hw_data *data, + int rd_mode, int format, int win_num) +{ + int i; + bool matched = false; + + if (rd_mode == RGA_RASTER_MODE) { + for (i = 0; i < data->win[win_num].num_of_raster_formats; i++) { + if (format == data->win[win_num].raster_formats[i]) { + matched = true; + break; + } + } + } else if (rd_mode == RGA_FBC_MODE) { + for (i = 0; i < data->win[win_num].num_of_fbc_formats; i++) { + if (format == data->win[win_num].fbc_formats[i]) { + matched = true; + break; + } + } + } else if (rd_mode == RGA_TILE_MODE) { + for (i = 0; i < data->win[win_num].num_of_tile_formats; i++) { + if (format == data->win[win_num].tile_formats[i]) { + matched = true; + break; + } + } + } + + return matched; +} + +static bool rga_check_src0(const struct rga_hw_data *data, + struct rga_img_info_t *src0) +{ + int format; + + rga_user_format_convert(&format, src0->format); + + if (src0->act_w < data->min_input.w || + src0->act_h < data->min_input.h) + return false; + + if (src0->act_w > data->max_input.w || + src0->act_h > data->max_input.h) + return false; + + if (!rga_check_format(data, src0->rd_mode, format, 0)) + return false; + + return true; +} + +static bool rga_check_src1(const struct rga_hw_data *data, + struct rga_img_info_t *src1) +{ + int format; + + rga_user_format_convert(&format, src1->format); + + if (src1->act_w < data->min_input.w || + src1->act_h < data->min_input.h) + return false; + + if (src1->act_w > data->max_input.w || + src1->act_h > data->max_input.h) + return false; + + if (!rga_check_format(data, src1->rd_mode, format, 1)) + return false; + + return true; +} + +static bool rga_check_dst(const struct rga_hw_data *data, + struct rga_img_info_t *dst) +{ + int format; + + rga_user_format_convert(&format, dst->format); + + if (dst->act_w < data->min_output.w || + dst->act_h < data->min_output.h) + return false; + + if (dst->act_w > data->max_output.w || + dst->act_h > data->max_output.h) + return false; + + if (!rga_check_format(data, dst->rd_mode, format, 2)) + 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 i; + int min_of_job_count = 0; + 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) { + optional_cores = rga_base->core; + goto skip_functional_policy; + } + } + + feature = rga_set_feature(rga_base); + + /* function */ + for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { + data = rga_drvdata->rga_scheduler[i]->data; + scheduler = rga_drvdata->rga_scheduler[i]; + + if (DEBUGGER_EN(MSG)) + pr_err("start policy on core = %d", scheduler->core); + + if (scheduler->core == RGA2_SCHEDULER_CORE0 && + job->flags & RGA_JOB_UNSUPPORT_RGA2) { + if (DEBUGGER_EN(MSG)) + pr_debug("RGA2 only support under 4G memory!\n"); + continue; + } + + if (feature > 0) { + if (!(feature & data->feature)) { + if (DEBUGGER_EN(MSG)) + pr_err("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_err("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_err("core = %d, ABB break on rd_mode", + scheduler->core); + continue; + } + } + + if (!rga_check_scale(data, rga_base)) { + if (DEBUGGER_EN(MSG)) + pr_err("core = %d, break on rga_check_scale", + scheduler->core); + continue; + } + + if (!rga_check_src0(data, src0)) { + if (DEBUGGER_EN(MSG)) + pr_err("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_err("core = %d, break on rga_check_src1", + scheduler->core); + continue; + } + } + } + + if (!rga_check_dst(data, dst)) { + if (DEBUGGER_EN(MSG)) + pr_err("core = %d, break on rga_check_dst", + 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; + } + +skip_functional_policy: + for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { + scheduler = rga_drvdata->rga_scheduler[i]; + + if (optional_cores & scheduler->core) { + spin_lock_irqsave(&scheduler->irq_lock, flags); + + if (scheduler->running_job == NULL) { + core = scheduler->core; + spin_unlock_irqrestore(&scheduler->irq_lock, + flags); + break; + } else { + if ((min_of_job_count > scheduler->job_count) || + (min_of_job_count == 0)) { + min_of_job_count = scheduler->job_count; + core = scheduler->core; + } + } + + 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; +} \ No newline at end of file