/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #define LOG_TAG "RDMA" #include "ddp_log.h" #include "ddp_clkmgr.h" #include #include "ddp_info.h" #include "ddp_reg.h" #include "ddp_matrix_para.h" #include "ddp_rdma.h" #include "ddp_rdma_ex.h" #include "ddp_dump.h" #include "lcm_drv.h" #include "primary_display.h" #include "ddp_m4u.h" #include "disp_lowpower.h" #include "ddp_mmp.h" #include "ddp_misc.h" #include "ddp_reg_mmsys.h" #define MMSYS_CLK_LOW (0) #define MMSYS_CLK_HIGH (1) static unsigned int rdma_fps[RDMA_INSTANCES] = { 60, 60 }; static struct golden_setting_context *rdma_golden_setting; struct RDMA_CONFIG_STRUCT g_primary_rdma_cfg; unsigned int rdma_index(enum DISP_MODULE_ENUM module) { int idx = 0; switch (module) { case DISP_MODULE_RDMA0: idx = 0; break; case DISP_MODULE_RDMA1: idx = 1; break; default: DDP_PR_ERR("invalid rdma module=%d\n", module); ASSERT(0); break; } ASSERT((idx >= 0) && (idx < RDMA_INSTANCES)); return idx; } void rdma_set_target_line(enum DISP_MODULE_ENUM module, unsigned int line, void *handle) { unsigned int idx = rdma_index(module); DISP_REG_SET(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_TARGET_LINE, line); } int rdma_init(enum DISP_MODULE_ENUM module, void *handle) { return rdma_clock_on(module, handle); } int rdma_deinit(enum DISP_MODULE_ENUM module, void *handle) { return rdma_clock_off(module, handle); } void rdma_get_address(enum DISP_MODULE_ENUM module, unsigned long *addr) { unsigned int idx = rdma_index(module); *addr = DISP_REG_GET(DISP_REG_RDMA_MEM_START_ADDR + DISP_RDMA_INDEX_OFFSET * idx); } static inline unsigned long rdma_to_cmdq_engine(enum DISP_MODULE_ENUM module) { switch (module) { case DISP_MODULE_RDMA0: return CMDQ_ENG_DISP_RDMA0; case DISP_MODULE_RDMA1: return CMDQ_ENG_DISP_RDMA1; default: DDP_PR_ERR("invalid rdma module=%d,rdma to cmdq engine fail\n", module); ASSERT(0); return DISP_MODULE_UNKNOWN; } return 0; } static inline unsigned long rdma_to_cmdq_event_nonsec_end(enum DISP_MODULE_ENUM module) { switch (module) { case DISP_MODULE_RDMA0: return CMDQ_SYNC_DISP_RDMA0_2NONSEC_END; case DISP_MODULE_RDMA1: return CMDQ_SYNC_DISP_RDMA1_2NONSEC_END; default: DDP_PR_ERR("invalid rdma module=%d,rmda to cmdq event fail\n", module); ASSERT(0); return DISP_MODULE_UNKNOWN; } return 0; } int rdma_enable_irq(enum DISP_MODULE_ENUM module, void *handle, enum DDP_IRQ_LEVEL irq_level) { unsigned int idx = rdma_index(module); ASSERT(idx <= RDMA_INSTANCES); switch (irq_level) { case DDP_IRQ_LEVEL_ALL: DISP_REG_SET(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_INT_ENABLE, 0x1E); break; case DDP_IRQ_LEVEL_ERROR: DISP_REG_SET(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_INT_ENABLE, 0x18); break; case DDP_IRQ_LEVEL_NONE: DISP_REG_SET(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_INT_ENABLE, 0x0); break; default: break; } return 0; } int rdma_start(enum DISP_MODULE_ENUM module, void *handle) { unsigned int idx = rdma_index(module); unsigned int regval; unsigned int value = 0, mask = 0; ASSERT(idx <= RDMA_INSTANCES); regval = REG_FLD_VAL(INT_STATUS_FLD_REG_UPDATE_INT_FLAG, 0) | REG_FLD_VAL(INT_STATUS_FLD_FRAME_START_INT_FLAG, 1) | REG_FLD_VAL(INT_STATUS_FLD_FRAME_END_INT_FLAG, 1) | REG_FLD_VAL(INT_STATUS_FLD_EOF_ABNORMAL_INT_FLAG, 1) | REG_FLD_VAL(INT_STATUS_FLD_FIFO_UNDERFLOW_INT_FLAG, 1) | REG_FLD_VAL(INT_STATUS_FLD_TARGET_LINE_INT_FLAG, 0) | REG_FLD_VAL(INT_STATUS_FLD_FIFO_EMPTY_INT_FLAG, 0); DISP_REG_SET(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_INT_ENABLE, regval); DISP_REG_SET_FIELD(handle, GLOBAL_CON_FLD_ENGINE_EN, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_GLOBAL_CON, 1); if (idx == 0) { value = 0; mask = 0; SET_VAL_MASK(value, mask, 0, FLD_SODI_REQ_MASKEN_CG_RDMA0); SET_VAL_MASK(value, mask, 1, FLD_DVFS_HALT_MASK_RDMA0); DISP_REG_MASK(handle, DISP_REG_CONFIG_MMSYS_SODI_REQ_MASK, value, mask); } else { value = 0; mask = 0; SET_VAL_MASK(value, mask, 0, FLD_SODI_REQ_MASKEN_CG_RDMA1); SET_VAL_MASK(value, mask, 1, FLD_DVFS_HALT_MASK_RDMA1); DISP_REG_MASK(handle, DISP_REG_CONFIG_MMSYS_SODI_REQ_MASK, value, mask); } return 0; } int rdma_stop(enum DISP_MODULE_ENUM module, void *handle) { unsigned int idx = rdma_index(module); unsigned int value = 0, mask = 0; ASSERT(idx <= RDMA_INSTANCES); DISP_REG_SET_FIELD(handle, GLOBAL_CON_FLD_ENGINE_EN, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_GLOBAL_CON, 0); DISP_REG_SET(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_INT_ENABLE, 0); DISP_REG_SET(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_INT_STATUS, 0); if (idx == 0) { value = 0; mask = 0; SET_VAL_MASK(value, mask, 1, FLD_SODI_REQ_MASKEN_CG_RDMA0); SET_VAL_MASK(value, mask, 0, FLD_DVFS_HALT_MASK_RDMA0); DISP_REG_MASK(handle, DISP_REG_CONFIG_MMSYS_SODI_REQ_MASK, value, mask); } else { value = 0; mask = 0; SET_VAL_MASK(value, mask, 1, FLD_SODI_REQ_MASKEN_CG_RDMA1); SET_VAL_MASK(value, mask, 0, FLD_DVFS_HALT_MASK_RDMA1); DISP_REG_MASK(handle, DISP_REG_CONFIG_MMSYS_SODI_REQ_MASK, value, mask); } return 0; } int rdma_reset_by_cmdq(enum DISP_MODULE_ENUM module, void *handle) { int ret = 0; unsigned int idx = rdma_index(module); ASSERT(idx <= RDMA_INSTANCES); DISP_REG_SET_FIELD(handle, GLOBAL_CON_FLD_SOFT_RESET, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_GLOBAL_CON, 1); DISP_REG_SET_FIELD(handle, GLOBAL_CON_FLD_SOFT_RESET, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_GLOBAL_CON, 0); DISP_REG_CMDQ_POLLING(handle, idx * DISP_RDMA_INDEX_OFFSET + DISP_REG_RDMA_GLOBAL_CON, 0x100, 0x700); return ret; } int rdma_reset(enum DISP_MODULE_ENUM module, void *handle) { unsigned int delay_cnt = 0; int ret = 0, offset = 0; unsigned int idx = rdma_index(module); ASSERT(idx <= RDMA_INSTANCES); offset = idx * DISP_RDMA_INDEX_OFFSET; DISP_REG_SET_FIELD(handle, GLOBAL_CON_FLD_SOFT_RESET, offset + DISP_REG_RDMA_GLOBAL_CON, 1); while ((DISP_REG_GET(offset + DISP_REG_RDMA_GLOBAL_CON) & 0x700) == 0x100) { delay_cnt++; udelay(10); if (delay_cnt > 10000) { ret = -1; DDP_PR_ERR( "rdma%d_reset timeout, stage 1! DISP_REG_RDMA_GLOBAL_CON=0x%x\n", idx, DISP_REG_GET(offset + DISP_REG_RDMA_GLOBAL_CON)); break; } } DISP_REG_SET_FIELD(handle, GLOBAL_CON_FLD_SOFT_RESET, offset + DISP_REG_RDMA_GLOBAL_CON, 0); delay_cnt = 0; while ((DISP_REG_GET(offset + DISP_REG_RDMA_GLOBAL_CON) & 0x700) != 0x100) { delay_cnt++; udelay(10); if (delay_cnt <= 10000) continue; ret = -1; DDP_PR_ERR( "rdma%d_reset timeout, stage 2! DISP_REG_RDMA_GLOBAL_CON=0x%x\n", idx, DISP_REG_GET(offset + DISP_REG_RDMA_GLOBAL_CON)); break; } return ret; } /* TODO RDMA1, wrot sram */ void rdma_cal_golden_setting(unsigned int idx, unsigned int bpp, struct golden_setting_context *gsc, unsigned int *gs, unsigned int is_vdo) { /* fixed variable */ unsigned int mmsys_clk = 315; unsigned int pre_ultra_low_us = 245, pre_ultra_high_us = 255; unsigned int ultra_low_us = 230, ultra_high_us = 245; unsigned int if_fps = 60; unsigned int FP = 1000; /* input variable */ unsigned int is_wrot_sram = gsc->is_wrot_sram; unsigned long long width = gsc->dst_width, height = gsc->dst_height; unsigned int Bpp = bpp / 8; bool is_dc = gsc->is_dc; unsigned int fill_rate = 0; /* 100 times */ unsigned long long consume_rate = 0; /* 100 times */ #ifdef CONFIG_MTK_HIGH_FRAME_RATE /*use gsc->fps*/ if_fps = gsc->fps; DDPDBG("%s,if_fps=%d\n", __func__, if_fps); #endif /* critical variable calc */ if (is_dc) fill_rate = 96 * mmsys_clk; /* FIFO depth / us */ else fill_rate = 96 * mmsys_clk * 3 / 16; /* FIFO depth / us */ consume_rate = width * height * if_fps * Bpp; do_div(consume_rate, 1000); consume_rate *= 125; do_div(consume_rate, 16 * 1000); /* RDMA golden setting calculation */ /* DISP_RDMA_MEM_GMC_SETTING_0 */ gs[GS_RDMA_PRE_ULTRA_TH_LOW] = DIV_ROUND_UP( consume_rate * (pre_ultra_low_us), FP); gs[GS_RDMA_PRE_ULTRA_TH_HIGH] = DIV_ROUND_UP( consume_rate * (pre_ultra_high_us), FP); if (is_vdo) { gs[GS_RDMA_VALID_TH_FORCE_PRE_ULTRA] = 0; gs[GS_RDMA_VDE_FORCE_PRE_ULTRA] = 1; } else { gs[GS_RDMA_VALID_TH_FORCE_PRE_ULTRA] = 1; gs[GS_RDMA_VDE_FORCE_PRE_ULTRA] = 0; } /* DISP_RDMA_MEM_GMC_SETTING_1 */ gs[GS_RDMA_ULTRA_TH_LOW] = DIV_ROUND_UP( consume_rate * (ultra_low_us), FP); gs[GS_RDMA_ULTRA_TH_HIGH] = gs[GS_RDMA_PRE_ULTRA_TH_LOW]; if (is_vdo) { gs[GS_RDMA_VALID_TH_BLOCK_ULTRA] = 0; gs[GS_RDMA_VDE_BLOCK_ULTRA] = 1; } else { gs[GS_RDMA_VALID_TH_BLOCK_ULTRA] = 1; gs[GS_RDMA_VDE_BLOCK_ULTRA] = 0; } /* DISP_RDMA_FIFO_CON */ if (is_vdo) gs[GS_RDMA_OUTPUT_VALID_FIFO_TH] = 0; else gs[GS_RDMA_OUTPUT_VALID_FIFO_TH] = gs[GS_RDMA_PRE_ULTRA_TH_LOW]; if (is_wrot_sram == 0) gs[GS_RDMA_FIFO_SIZE] = 1536; else gs[GS_RDMA_FIFO_SIZE] = 3584; gs[GS_RDMA_FIFO_UNDERFLOW_EN] = 1; /* DISP_RDMA_MEM_GMC_SETTING_2 */ gs[GS_RDMA_ISSUE_REQ_TH] = gs[GS_RDMA_FIFO_SIZE] - gs[GS_RDMA_PRE_ULTRA_TH_LOW]; /* DISP_RDMA_THRESHOLD_FOR_SODI */ gs[GS_RDMA_TH_LOW_FOR_SODI] = DIV_ROUND_UP( consume_rate * (ultra_low_us + 50), FP); gs[GS_RDMA_TH_HIGH_FOR_SODI] = DIV_ROUND_UP(gs[GS_RDMA_FIFO_SIZE] * FP - (fill_rate - consume_rate) * 12, FP); if (gs[GS_RDMA_TH_HIGH_FOR_SODI] < gs[GS_RDMA_PRE_ULTRA_TH_HIGH]) gs[GS_RDMA_TH_HIGH_FOR_SODI] = gs[GS_RDMA_PRE_ULTRA_TH_HIGH]; /* DISP_RDMA_THRESHOLD_FOR_DVFS */ gs[GS_RDMA_TH_LOW_FOR_DVFS] = gs[GS_RDMA_PRE_ULTRA_TH_LOW]; gs[GS_RDMA_TH_HIGH_FOR_DVFS] = gs[GS_RDMA_PRE_ULTRA_TH_LOW] + 1; /* DISP_RDMA_SRAM_SEL */ if (is_wrot_sram == 0) gs[GS_RDMA_SRAM_SEL] = 0; else gs[GS_RDMA_SRAM_SEL] = 7; /* DISP_RDMA_DVFS_SETTING_PREULTRA */ gs[GS_RDMA_DVFS_PRE_ULTRA_TH_LOW] = DIV_ROUND_UP( consume_rate * (pre_ultra_low_us + 40), FP); gs[GS_RDMA_DVFS_PRE_ULTRA_TH_HIGH] = DIV_ROUND_UP( consume_rate * (pre_ultra_high_us + 40), FP); /* DISP_RDMA_DVFS_SETTING_ULTRA */ gs[GS_RDMA_DVFS_ULTRA_TH_LOW] = DIV_ROUND_UP( consume_rate * (ultra_low_us + 40), FP); gs[GS_RDMA_DVFS_ULTRA_TH_HIGH] = gs[GS_RDMA_DVFS_PRE_ULTRA_TH_LOW]; /* DISP_RDMA_LEAVE_DRS_SETTING */ gs[GS_RDMA_IS_DRS_STATUS_TH_LOW] = DIV_ROUND_UP( consume_rate * (pre_ultra_low_us + 20), FP); gs[GS_RDMA_IS_DRS_STATUS_TH_HIGH] = DIV_ROUND_UP( consume_rate * (pre_ultra_low_us + 20), FP); /* DISP_RDMA_ENTER_DRS_SETTING */ gs[GS_RDMA_NOT_DRS_STATUS_TH_LOW] = DIV_ROUND_UP( consume_rate * (ultra_high_us + 40), FP); gs[GS_RDMA_NOT_DRS_STATUS_TH_HIGH] = DIV_ROUND_UP( consume_rate * (ultra_high_us + 40), FP); /* DISP_RDMA_MEM_GMC_SETTING_3 */ gs[GS_RDMA_URGENT_TH_LOW] = DIV_ROUND_UP( consume_rate * 113, FP); gs[GS_RDMA_URGENT_TH_HIGH] = DIV_ROUND_UP( consume_rate * 117, FP); /* DISP_RDMA_SRAM_CASCADE */ gs[GS_RDMA_SELF_FIFO_SIZE] = 1536; gs[GS_RDMA_RSZ_FIFO_SIZE] = 1536; if (gs[GS_RDMA_OUTPUT_VALID_FIFO_TH] > gs[GS_RDMA_RSZ_FIFO_SIZE]) { gs[GS_RDMA_OUTPUT_VALID_FIFO_TH] = gs[GS_RDMA_RSZ_FIFO_SIZE] - 80; DISPMSG("%s, force set output_valid = %d\n", __func__, gs[GS_RDMA_OUTPUT_VALID_FIFO_TH]); }; } /* Set register with value from rdma_cal_golden_setting. * Do not do any math here! */ static void rdma_set_ultra_l(unsigned int idx, unsigned int bpp, void *handle, struct golden_setting_context *gsc) { unsigned int gs[GS_RDMA_FLD_NUM] = {0}; unsigned int val = 0; unsigned int offset = idx * DISP_RDMA_INDEX_OFFSET; if (idx == 1) { DDPMSG("RDMA1 golden setting not support yet\n"); return; } if (!gsc) { DDPMSG("golden setting is null, %s,%d\n", __FILE__, __LINE__); ASSERT(0); return; } rdma_golden_setting = gsc; /* calculate golden setting */ rdma_cal_golden_setting(idx, bpp, gsc, gs, primary_display_is_video_mode()); /* set golden setting */ val = gs[GS_RDMA_PRE_ULTRA_TH_LOW] + (gs[GS_RDMA_PRE_ULTRA_TH_HIGH] << 16) + (gs[GS_RDMA_VALID_TH_FORCE_PRE_ULTRA] << 30) + (gs[GS_RDMA_VDE_FORCE_PRE_ULTRA] << 31); DISP_REG_SET(handle, offset + DISP_REG_RDMA_MEM_GMC_SETTING_0, val); val = gs[GS_RDMA_ULTRA_TH_LOW] + (gs[GS_RDMA_ULTRA_TH_HIGH] << 16) + (gs[GS_RDMA_VALID_TH_BLOCK_ULTRA] << 30) + (gs[GS_RDMA_VDE_BLOCK_ULTRA] << 31); DISP_REG_SET(handle, offset + DISP_REG_RDMA_MEM_GMC_SETTING_1, val); val = gs[GS_RDMA_ISSUE_REQ_TH]; DISP_REG_SET(handle, offset + DISP_REG_RDMA_MEM_GMC_SETTING_2, val); val = gs[GS_RDMA_OUTPUT_VALID_FIFO_TH] + (gs[GS_RDMA_FIFO_SIZE] << 16) + (gs[GS_RDMA_FIFO_UNDERFLOW_EN] << 31); DISP_REG_SET(handle, offset + DISP_REG_RDMA_FIFO_CON, val); val = gs[GS_RDMA_TH_LOW_FOR_SODI] + (gs[GS_RDMA_TH_HIGH_FOR_SODI] << 16); DISP_REG_SET(handle, offset + DISP_REG_RDMA_THRESHOLD_FOR_SODI, val); val = gs[GS_RDMA_TH_LOW_FOR_DVFS] + (gs[GS_RDMA_TH_HIGH_FOR_DVFS] << 16); DISP_REG_SET(handle, offset + DISP_REG_RDMA_THRESHOLD_FOR_DVFS, val); if (idx == 0) DISP_REG_SET(handle, DISP_REG_RDMA_SRAM_SEL, gs[GS_RDMA_SRAM_SEL]); val = gs[GS_RDMA_DVFS_PRE_ULTRA_TH_LOW] + (gs[GS_RDMA_DVFS_PRE_ULTRA_TH_HIGH] << 16); DISP_REG_SET(handle, offset + DISP_REG_RDMA_DVFS_SETTING_PRE, val); val = gs[GS_RDMA_DVFS_ULTRA_TH_LOW] + (gs[GS_RDMA_DVFS_ULTRA_TH_HIGH] << 16); DISP_REG_SET(handle, offset + DISP_REG_RDMA_DVFS_SETTING_ULTRA, val); val = gs[GS_RDMA_IS_DRS_STATUS_TH_LOW] + (gs[GS_RDMA_IS_DRS_STATUS_TH_HIGH] << 16); DISP_REG_SET(handle, offset + DISP_REG_RDMA_LEAVE_DRS_SETTING, val); val = gs[GS_RDMA_NOT_DRS_STATUS_TH_LOW] + (gs[GS_RDMA_NOT_DRS_STATUS_TH_HIGH] << 16); DISP_REG_SET(handle, offset + DISP_REG_RDMA_ENTER_DRS_SETTING, val); val = gs[GS_RDMA_URGENT_TH_LOW] + (gs[GS_RDMA_URGENT_TH_HIGH] << 16); DISP_REG_SET(handle, offset + DISP_REG_RDMA_MEM_GMC_SETTING_3, val); val = gs[GS_RDMA_SELF_FIFO_SIZE] + (gs[GS_RDMA_RSZ_FIFO_SIZE] << 16); DISP_REG_SET(handle, offset + DISP_RDMA_SRAM_CASCADE, val); } static int rdma_config(enum DISP_MODULE_ENUM module, enum RDMA_MODE mode, unsigned long address, enum UNIFIED_COLOR_FMT inFormat, unsigned int pitch, unsigned int width, unsigned int height, unsigned int ufoe_enable, enum DISP_BUFFER_TYPE sec, unsigned int yuv_range, struct rdma_bg_ctrl_t *bg_ctrl, void *handle, struct golden_setting_context *p_golden_setting, unsigned int bpp) { unsigned int output_is_yuv = 0; unsigned int input_is_yuv = !UFMT_GET_RGB(inFormat); unsigned int input_swap = UFMT_GET_BYTESWAP(inFormat); unsigned int input_format = UFMT_GET_FORMAT(inFormat); unsigned int idx = rdma_index(module); unsigned int matrix_en; unsigned int color_matrix; unsigned int val, offset; unsigned int size_con_0_value = 0, size_con_0_mask = 0; unsigned int value = 0, mask = 0; DDPDBG( "%s:%s,mode:%s,addr:0x%08lx,fmt:%s,pitch:%u,wh(%ux%u),sec:%d\n", __func__, ddp_get_module_name(module), mode ? "MEM" : "DL", address, unified_color_fmt_name(inFormat), pitch, width, height, sec); ASSERT(idx <= RDMA_INSTANCES); if ((width > RDMA_MAX_WIDTH) || (height > RDMA_MAX_HEIGHT)) DDP_PR_ERR( "RDMA input overflow, w=%d, h=%d, max_w=%d, max_h=%d\n", width, height, RDMA_MAX_WIDTH, RDMA_MAX_HEIGHT); offset = idx * DISP_RDMA_INDEX_OFFSET; if (input_is_yuv == 1 && output_is_yuv == 0) { matrix_en = 1; switch (yuv_range) { case 0: color_matrix = 4; break; /* BT601_full */ case 1: color_matrix = 6; break; /* BT601 */ case 2: color_matrix = 7; break; /* BT709 */ default: DDP_PR_ERR("%s,un-recognized yuv_range=%d!\n", __func__, yuv_range); color_matrix = 4; break; } } else if (input_is_yuv == 0 && output_is_yuv == 1) { matrix_en = 1; color_matrix = 0x2; /* 0x0010, RGB_TO_BT601 */ } else { matrix_en = 0; color_matrix = 0; } SET_VAL_MASK(size_con_0_value, size_con_0_mask, matrix_en, SIZE_CON_0_FLD_MATRIX_ENABLE); SET_VAL_MASK(size_con_0_value, size_con_0_mask, color_matrix, SIZE_CON_0_FLD_MATRIX_INT_MTX_SEL); if (mode == RDMA_MODE_DIRECT_LINK) { value = 0; mask = 0; SET_VAL_MASK(value, mask, 0, MEM_CON_FLD_MEM_MODE_INPUT_FORMAT); SET_VAL_MASK(value, mask, 0, MEM_CON_FLD_MEM_MODE_INPUT_SWAP); } else { value = 0; mask = 0; SET_VAL_MASK(value, mask, (input_format & 0xf), MEM_CON_FLD_MEM_MODE_INPUT_FORMAT); SET_VAL_MASK(value, mask, input_swap, MEM_CON_FLD_MEM_MODE_INPUT_SWAP); } DISP_REG_MASK(handle, offset + DISP_REG_RDMA_MEM_CON, value, mask); if (sec != DISP_SECURE_BUFFER) { DISP_REG_SET(handle, offset + DISP_REG_RDMA_MEM_START_ADDR, address); } else { int m4u_port; unsigned int size = pitch * height; m4u_port = idx == 0 ? DISP_M4U_PORT_DISP_RDMA0 : DISP_M4U_PORT_DISP_RDMA1; /* * for sec layer, addr variable stores sec handle * we need to pass this handle and offset to cmdq driver * cmdq sec driver will help to convert handle to * correct address */ cmdqRecWriteSecure(handle, disp_addr_convert(offset + DISP_REG_RDMA_MEM_START_ADDR), CMDQ_SAM_H_2_MVA, address, 0, size, m4u_port); } DISP_REG_SET(handle, offset + DISP_REG_RDMA_MEM_SRC_PITCH, pitch); SET_VAL_MASK(size_con_0_value, size_con_0_mask, width, SIZE_CON_0_FLD_OUTPUT_FRAME_WIDTH); DISP_REG_MASK(handle, offset + DISP_REG_RDMA_SIZE_CON_0, size_con_0_value, size_con_0_mask); DISP_REG_SET_FIELD(handle, SIZE_CON_1_FLD_OUTPUT_FRAME_HEIGHT, offset + DISP_REG_RDMA_SIZE_CON_1, height); /* RDMA bg control */ /* DISP_REG_RDMA_BG_CON_0 */ val = REG_FLD_VAL(RDMA_BG_CON_0_LEFT, bg_ctrl->left); val |= REG_FLD_VAL(RDMA_BG_CON_0_RIGHT, bg_ctrl->right); DISP_REG_SET(handle, offset + DISP_REG_RDMA_BG_CON_0, val); /* DISP_REG_RDMA_BG_CON_1 */ val = REG_FLD_VAL(RDMA_BG_CON_1_TOP, bg_ctrl->top); val |= REG_FLD_VAL(RDMA_BG_CON_1_BOTTOM, bg_ctrl->bottom); DISP_REG_SET(handle, offset + DISP_REG_RDMA_BG_CON_1, val); DISP_REG_SET_FIELD(handle, GLOBAL_CON_FLD_MODE_SEL, offset + DISP_REG_RDMA_GLOBAL_CON, mode); set_rdma_width_height(width, height); rdma_set_ultra_l(idx, bpp, handle, p_golden_setting); return 0; } int rdma_clock_on(enum DISP_MODULE_ENUM module, void *handle) { ddp_clk_prepare_enable(ddp_get_module_clk_id(module)); return 0; } int rdma_clock_off(enum DISP_MODULE_ENUM module, void *handle) { ddp_clk_disable_unprepare(ddp_get_module_clk_id(module)); return 0; } void rdma_dump_golden_setting_context(enum DISP_MODULE_ENUM module) { if (!rdma_golden_setting) return; DDPDUMP("-- %s Golden Setting Context --\n", ddp_get_module_name(module)); DDPDUMP("fifo_mode=%d\n", rdma_golden_setting->fifo_mode); DDPDUMP("hrt_num=%d\n", rdma_golden_setting->hrt_num); DDPDUMP("is_display_idle=%d\n", rdma_golden_setting->is_display_idle); DDPDUMP("is_wrot_sram=%d\n", rdma_golden_setting->is_wrot_sram); DDPDUMP("is_dc=%d\n", rdma_golden_setting->is_dc); DDPDUMP("mmsys_clk=%d\n", rdma_golden_setting->mmsys_clk); DDPDUMP("fps=%d\n", rdma_golden_setting->fps); DDPDUMP("is_one_layer=%d\n", rdma_golden_setting->is_one_layer); DDPDUMP("rdma_width=%d\n", rdma_golden_setting->dst_width); DDPDUMP("rdma_height=%d\n", rdma_golden_setting->dst_height); } void rdma_dump_golden_setting(enum DISP_MODULE_ENUM module) { unsigned int idx = rdma_index(module); unsigned int offset = DISP_RDMA_INDEX_OFFSET * idx; DDPDUMP("-- %s Golden Setting --\n", ddp_get_module_name(module)); DDPDUMP("0x%03x:0x%08x 0x%03x:0x%08x 0x%03x:0x%08x 0x%03x:0x%08x\n", 0x30, DISP_REG_GET(DISP_REG_RDMA_MEM_GMC_SETTING_0 + offset), 0x34, DISP_REG_GET(DISP_REG_RDMA_MEM_GMC_SETTING_1 + offset), 0x3c, DISP_REG_GET(DISP_REG_RDMA_MEM_GMC_SETTING_2 + offset), 0x40, DISP_REG_GET(DISP_REG_RDMA_FIFO_CON + offset)); DDPDUMP("0x%03x:0x%08x 0x%03x:0x%08x 0x%03x:0x%08x 0x%03x:0x%08x\n", 0xa8, DISP_REG_GET(DISP_REG_RDMA_THRESHOLD_FOR_SODI + offset), 0xac, DISP_REG_GET(DISP_REG_RDMA_THRESHOLD_FOR_DVFS + offset), 0xb0, DISP_REG_GET(DISP_REG_RDMA_SRAM_SEL + offset), 0xc8, DISP_REG_GET(DISP_RDMA_SRAM_CASCADE + offset)); DDPDUMP("0x%03x:0x%08x 0x%08x 0x%08x 0x%08x\n", 0xd0, DISP_REG_GET(DISP_REG_RDMA_DVFS_SETTING_PRE + offset), DISP_REG_GET(DISP_REG_RDMA_DVFS_SETTING_ULTRA + offset), DISP_REG_GET(DISP_REG_RDMA_LEAVE_DRS_SETTING + offset), DISP_REG_GET(DISP_REG_RDMA_ENTER_DRS_SETTING + offset)); DDPDUMP("0x%03x:0x%08x\n", 0xe8, DISP_REG_GET(DISP_REG_RDMA_MEM_GMC_SETTING_3 + offset)); DDPDUMP("GMC_SETTING_0 [11:0]:%u [27:16]:%u [30]:%u [31]:%u\n", DISP_REG_GET_FIELD( MEM_GMC_SETTING_0_FLD_PRE_ULTRA_THRESHOLD_LOW, offset + DISP_REG_RDMA_MEM_GMC_SETTING_0), DISP_REG_GET_FIELD( MEM_GMC_SETTING_0_FLD_PRE_ULTRA_THRESHOLD_HIGH, offset + DISP_REG_RDMA_MEM_GMC_SETTING_0), DISP_REG_GET_FIELD( MEM_GMC_SETTING_0_FLD_RG_VALID_THRESHOLD_FORCE_PREULTRA, offset + DISP_REG_RDMA_MEM_GMC_SETTING_0), DISP_REG_GET_FIELD( MEM_GMC_SETTING_0_FLD_RG_VDE_FORCE_PREULTRA, offset + DISP_REG_RDMA_MEM_GMC_SETTING_0)); DDPDUMP("GMC_SETTING_1 [11:0]:%u [27:16]:%u [30]:%u [31]:%u\n", DISP_REG_GET_FIELD(MEM_GMC_SETTING_1_FLD_ULTRA_THRESHOLD_LOW, offset + DISP_REG_RDMA_MEM_GMC_SETTING_1), DISP_REG_GET_FIELD(MEM_GMC_SETTING_1_FLD_ULTRA_THRESHOLD_HIGH, offset + DISP_REG_RDMA_MEM_GMC_SETTING_1), DISP_REG_GET_FIELD( MEM_GMC_SETTING_1_FLD_RG_VALID_THRESHOLD_BLOCK_ULTRA, offset + DISP_REG_RDMA_MEM_GMC_SETTING_1), DISP_REG_GET_FIELD(MEM_GMC_SETTING_1_FLD_RG_VDE_BLOCK_ULTRA, offset + DISP_REG_RDMA_MEM_GMC_SETTING_1)); DDPDUMP("GMC_SETTING_2 [11:0]:%u\n", DISP_REG_GET_FIELD(MEM_GMC_SETTING_2_FLD_ISSUE_REQ_THRESHOLD, offset + DISP_REG_RDMA_MEM_GMC_SETTING_2)); DDPDUMP("FIFO_CON [11:0]:%u [27:16]:%d [31]:%u\n", DISP_REG_GET_FIELD(FIFO_CON_FLD_OUTPUT_VALID_FIFO_THRESHOLD, offset + DISP_REG_RDMA_FIFO_CON), DISP_REG_GET_FIELD(FIFO_CON_FLD_FIFO_PSEUDO_SIZE, offset + DISP_REG_RDMA_FIFO_CON), DISP_REG_GET_FIELD(FIFO_CON_FLD_FIFO_UNDERFLOW_EN, offset + DISP_REG_RDMA_FIFO_CON)); DDPDUMP("THRSHOLD_SODI [11:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_LOW, offset + DISP_REG_RDMA_THRESHOLD_FOR_SODI), DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_HIGH, offset + DISP_REG_RDMA_THRESHOLD_FOR_SODI)); DDPDUMP("THRSHOLD_DVFS [11:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_LOW, offset + DISP_REG_RDMA_THRESHOLD_FOR_DVFS), DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_HIGH, offset + DISP_REG_RDMA_THRESHOLD_FOR_DVFS)); DDPDUMP("SRAM_SEL [0]:%u\n", DISP_REG_GET(offset + DISP_REG_RDMA_SRAM_SEL)); DDPDUMP("SRAM_CASCADE [13:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(RG_DISP_RDMA_FIFO_SIZE, offset + DISP_RDMA_SRAM_CASCADE), DISP_REG_GET_FIELD(RG_DISP_RDMA_RSZ_FIFO_SIZE, offset + DISP_RDMA_SRAM_CASCADE)); DDPDUMP("DVFS_SETTING_PREULTRA [11:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_LOW, offset + DISP_REG_RDMA_DVFS_SETTING_PRE), DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_HIGH, offset + DISP_REG_RDMA_DVFS_SETTING_PRE)); DDPDUMP("DVFS_SETTING_ULTRA [11:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_LOW, offset + DISP_REG_RDMA_DVFS_SETTING_ULTRA), DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_HIGH, offset + DISP_REG_RDMA_DVFS_SETTING_ULTRA)); DDPDUMP("LEAVE_DRS_SETTING [11:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_LOW, offset + DISP_REG_RDMA_LEAVE_DRS_SETTING), DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_HIGH, offset + DISP_REG_RDMA_LEAVE_DRS_SETTING)); DDPDUMP("ENTER_DRS_SETTING [11:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_LOW, offset + DISP_REG_RDMA_ENTER_DRS_SETTING), DISP_REG_GET_FIELD(RDMA_THRESHOLD_FOR_DVFS_FLD_HIGH, offset + DISP_REG_RDMA_ENTER_DRS_SETTING)); DDPDUMP("GMC_SETTING_3 [11:0]:%u [27:16]:%u\n", DISP_REG_GET_FIELD(FLD_LOW_FOR_URGENT, offset + DISP_REG_RDMA_MEM_GMC_SETTING_3), DISP_REG_GET_FIELD(FLD_HIGH_FOR_URGENT, offset + DISP_REG_RDMA_MEM_GMC_SETTING_3)); } void rdma_dump_reg(enum DISP_MODULE_ENUM module) { unsigned int idx = rdma_index(module); unsigned int offset = DISP_RDMA_INDEX_OFFSET * idx; DDPDUMP("== DISP %s REGS ==\n", ddp_get_module_name(module)); DDPDUMP("0x%03x:0x%08x 0x%08x\n", 0x00, DISP_REG_GET(DISP_REG_RDMA_INT_ENABLE + offset), DISP_REG_GET(DISP_REG_RDMA_INT_STATUS + offset)); DDPDUMP("0x%03x:0x%08x 0x%08x 0x%08x 0x%08x\n", 0x10, DISP_REG_GET(DISP_REG_RDMA_GLOBAL_CON + offset), DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_0 + offset), DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_1 + offset), DISP_REG_GET(DISP_REG_RDMA_TARGET_LINE + offset)); DDPDUMP("0x%03x:0x%08x 0x%03x:0x%08x 0x%03x:0x%08x\n", 0xf00, DISP_REG_GET(DISP_REG_RDMA_MEM_START_ADDR + offset), 0x24, DISP_REG_GET(DISP_REG_RDMA_MEM_CON + offset), 0x2c, DISP_REG_GET(DISP_REG_RDMA_MEM_SRC_PITCH + offset)); DDPDUMP("0x%03x:0x%08x 0x%03x:0x%08x\n", 0x38, DISP_REG_GET(DISP_REG_RDMA_MEM_SLOW_CON + offset), 0x44, DISP_REG_GET(DISP_REG_RDMA_FIFO_LOG + offset)); DDPDUMP("0x%03x:0x%08x 0x%08x 0x%03x:0x%08x\n", 0x78, DISP_REG_GET(DISP_REG_RDMA_PRE_ADD_0 + offset), DISP_REG_GET(DISP_REG_RDMA_PRE_ADD_1 + offset), 0x80, DISP_REG_GET(DISP_REG_RDMA_PRE_ADD_2 + offset)); DDPDUMP("0x%03x:0x%08x 0x%08x 0x%08x\n", 0x84, DISP_REG_GET(DISP_REG_RDMA_POST_ADD_0 + offset), DISP_REG_GET(DISP_REG_RDMA_POST_ADD_1 + offset), DISP_REG_GET(DISP_REG_RDMA_POST_ADD_2 + offset)); DDPDUMP("0x%03x:0x%08x 0x%08x 0x%03x:0x%08x 0x%08x\n", 0x90, DISP_REG_GET(DISP_REG_RDMA_DUMMY + offset), DISP_REG_GET(DISP_REG_RDMA_DEBUG_OUT_SEL + offset), 0xa0, DISP_REG_GET(DISP_REG_RDMA_BG_CON_0 + offset), DISP_REG_GET(DISP_REG_RDMA_BG_CON_1 + offset)); DDPDUMP("0x%03x:0x%08x 0x%03x:0x%08x\n", 0xb4, DISP_REG_GET(DISP_REG_RDMA_STALL_CG_CON + offset), 0xbc, DISP_REG_GET(DISP_REG_RDMA_SHADOW_UPDATE + offset)); DDPDUMP("0x%03x:0x%08x 0x%08x 0x%08x 0x%08x\n", 0xf0, DISP_REG_GET(DISP_REG_RDMA_IN_P_CNT + offset), DISP_REG_GET(DISP_REG_RDMA_IN_LINE_CNT + offset), DISP_REG_GET(DISP_REG_RDMA_OUT_P_CNT + offset), DISP_REG_GET(DISP_REG_RDMA_OUT_LINE_CNT + offset)); rdma_dump_golden_setting(module); } void rdma_dump_analysis(enum DISP_MODULE_ENUM module) { unsigned int idx = rdma_index(module); unsigned int offset = idx * DISP_RDMA_INDEX_OFFSET; unsigned int global_ctrl; unsigned int bg0 = DISP_REG_GET(offset + DISP_REG_RDMA_BG_CON_0); unsigned int bg1 = DISP_REG_GET(offset + DISP_REG_RDMA_BG_CON_1); unsigned int fifo = DISP_REG_GET(offset + DISP_REG_RDMA_FIFO_CON); global_ctrl = DISP_REG_GET(DISP_REG_RDMA_GLOBAL_CON + offset); DDPDUMP("== DISP %s ANALYSIS ==\n", ddp_get_module_name(module)); DDPDUMP( "en=%d,mode:%s,smi_busy:%d,wh(%dx%d),pitch=%d,addr=0x%08x,fmt=%s,fifo_sz=%u,output_valid_threshold=%u,fifo_min=%d\n", REG_FLD_VAL_GET(GLOBAL_CON_FLD_ENGINE_EN + offset, global_ctrl), REG_FLD_VAL_GET(GLOBAL_CON_FLD_MODE_SEL + offset, global_ctrl) ? "mem" : "DL", REG_FLD_VAL_GET(GLOBAL_CON_FLD_SMI_BUSY + offset, global_ctrl), DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_0 + offset) & 0xfff, DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_1 + offset) & 0xfffff, DISP_REG_GET(DISP_REG_RDMA_MEM_SRC_PITCH + offset), DISP_REG_GET(DISP_REG_RDMA_MEM_START_ADDR + offset), unified_color_fmt_name(display_fmt_reg_to_unified_fmt( (DISP_REG_GET(DISP_REG_RDMA_MEM_CON + offset) >> 4) & 0xf, (DISP_REG_GET(DISP_REG_RDMA_MEM_CON + offset) >> 8) & 0x1, 0)), REG_FLD_VAL_GET(FIFO_CON_FLD_FIFO_PSEUDO_SIZE, fifo), REG_FLD_VAL_GET(FIFO_CON_FLD_OUTPUT_VALID_FIFO_THRESHOLD, fifo), DISP_REG_GET(DISP_REG_RDMA_FIFO_LOG + offset)); DDPDUMP( "pos:in(%d,%d)out(%d,%d),bg(t%d,b%d,l%d,r%d),start=%lld ns,end=%lld ns\n", DISP_REG_GET(DISP_REG_RDMA_IN_P_CNT + offset), DISP_REG_GET(DISP_REG_RDMA_IN_LINE_CNT + offset), DISP_REG_GET(DISP_REG_RDMA_OUT_P_CNT + offset), DISP_REG_GET(DISP_REG_RDMA_OUT_LINE_CNT + offset), REG_FLD_VAL_GET(RDMA_BG_CON_1_TOP + offset, bg1), REG_FLD_VAL_GET(RDMA_BG_CON_1_BOTTOM + offset, bg1), REG_FLD_VAL_GET(RDMA_BG_CON_0_LEFT + offset, bg0), REG_FLD_VAL_GET(RDMA_BG_CON_0_RIGHT + offset, bg0), rdma_start_time[idx], rdma_end_time[idx]); DDPDUMP("irq cnt:start=%d,end=%d,underflow=%d,targetline=%d\n", rdma_start_irq_cnt[idx], rdma_done_irq_cnt[idx], rdma_underflow_irq_cnt[idx], rdma_targetline_irq_cnt[idx]); rdma_dump_golden_setting_context(module); } static int rdma_dump(enum DISP_MODULE_ENUM module, int level) { rdma_dump_analysis(module); rdma_dump_reg(module); return 0; } void rdma_get_info(int idx, struct RDMA_BASIC_STRUCT *info) { struct RDMA_BASIC_STRUCT *p = info; unsigned int offset = idx * DISP_RDMA_INDEX_OFFSET; p->addr = DISP_REG_GET(DISP_REG_RDMA_MEM_START_ADDR + offset); p->src_w = DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_0 + offset) & 0xfff; p->src_h = DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_1 + offset) & 0xfffff; p->bpp = UFMT_GET_bpp(display_fmt_reg_to_unified_fmt( (DISP_REG_GET(DISP_REG_RDMA_MEM_CON + offset) >> 4) & 0xf, (DISP_REG_GET(DISP_REG_RDMA_MEM_CON + offset) >> 8) & 0x1, 0)) / 8; } static inline enum RDMA_MODE get_rdma_mode(enum DISP_MODULE_ENUM module) { unsigned int idx = rdma_index(module); return DISP_REG_GET_FIELD(GLOBAL_CON_FLD_MODE_SEL, (DISP_RDMA_INDEX_OFFSET * idx) + DISP_REG_RDMA_GLOBAL_CON); } static inline enum RDMA_MODE rdma_config_mode(unsigned long address) { return address ? RDMA_MODE_MEMORY : RDMA_MODE_DIRECT_LINK; } static int do_rdma_config_l(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig, void *handle) { struct RDMA_CONFIG_STRUCT *cfg = &pConfig->rdma_config; enum RDMA_MODE mode = rdma_config_mode(cfg->address); struct LCM_PARAMS *lcm_param = &pConfig->dispif_config; unsigned int width; unsigned int height; struct golden_setting_context *p_golden_setting; enum UNIFIED_COLOR_FMT inFormat = cfg->inputFormat; enum UNIFIED_COLOR_FMT bwFormat; unsigned int bwBpp; unsigned long long rdma_bw; width = pConfig->dst_dirty ? pConfig->dst_w : cfg->width; height = pConfig->dst_dirty ? pConfig->dst_h : cfg->height; p_golden_setting = pConfig->p_golden_setting_context; if (module == DISP_MODULE_RDMA0) memcpy(&g_primary_rdma_cfg, cfg, sizeof(struct RDMA_CONFIG_STRUCT)); if (pConfig->fps) rdma_fps[rdma_index(module)] = pConfig->fps / 100; if (mode == RDMA_MODE_DIRECT_LINK && cfg->security != DISP_NORMAL_BUFFER) DDP_PR_ERR("%s: rdma directlink BUT is sec ??!!\n", __func__); if (mode == RDMA_MODE_DIRECT_LINK) { cfg->bg_ctrl.top = 0; cfg->bg_ctrl.bottom = 0; cfg->bg_ctrl.left = 0; cfg->bg_ctrl.right = 0; } else if (mode == RDMA_MODE_MEMORY) { cfg->bg_ctrl.top = cfg->dst_y; cfg->bg_ctrl.bottom = cfg->dst_h - cfg->dst_y - height; cfg->bg_ctrl.left = cfg->dst_x; cfg->bg_ctrl.right = cfg->dst_w - cfg->dst_x - width; } DDPDBG("%s:(t%u,b%u,l%u,r%u),r.dst(%u,%u,%ux%u),width=%u,height=%u\n", __func__, cfg->bg_ctrl.top, cfg->bg_ctrl.bottom, cfg->bg_ctrl.left, cfg->bg_ctrl.right, cfg->dst_x, cfg->dst_y, cfg->dst_w, cfg->dst_h, width, height); /* PARGB..etc need convert to ARGB..etc */ ufmt_disable_P(cfg->inputFormat, &inFormat); rdma_config(module, mode, (mode == RDMA_MODE_DIRECT_LINK) ? 0 : cfg->address, (mode == RDMA_MODE_DIRECT_LINK) ? UFMT_RGB888 : inFormat, (mode == RDMA_MODE_DIRECT_LINK) ? 0 : cfg->pitch, width, height, lcm_param->dsi.ufoe_enable, cfg->security, cfg->yuv_range, &cfg->bg_ctrl, handle, p_golden_setting, pConfig->lcm_bpp); /* calculate bandwidth */ bwFormat = (mode == RDMA_MODE_DIRECT_LINK) ? UFMT_RGB888 : inFormat; bwBpp = ufmt_get_Bpp(bwFormat); rdma_bw = (unsigned long long)width * height * bwBpp; do_div(rdma_bw, 1000); rdma_bw *= 1250; do_div(rdma_bw, 1000); DDPDBG("R:width=%u,height=%u,Bpp:%u,bw:%llu\n", width, height, bwBpp, rdma_bw); #ifdef MTK_FB_MMDVFS_SUPPORT /* bandwidth report */ if (module == DISP_MODULE_RDMA0) DISP_SLOT_SET(handle, DISPSYS_SLOT_BASE, DISP_SLOT_RDMA0_BW, (unsigned int)rdma_bw); #endif return 0; } static int rdma_is_sec[2]; static inline int rdma_switch_to_sec(enum DISP_MODULE_ENUM module, void *handle) { unsigned int rdma_idx = rdma_index(module); enum CMDQ_ENG_ENUM cmdq_engine; cmdq_engine = rdma_to_cmdq_engine(module); cmdqRecSetSecure(handle, 1); /* set engine as sec port */ cmdqRecSecureEnablePortSecurity(handle, (1LL << cmdq_engine)); /* cmdqRecSecureEnableDAPC(handle, (1LL << cmdq_engine)); */ if (rdma_is_sec[rdma_idx] == 0) { DDPSVPMSG("[SVP] switch rdma%d to sec\n", rdma_idx); mmprofile_log_ex(ddp_mmp_get_events()->svp_module[module], MMPROFILE_FLAG_START, 0, 0); } rdma_is_sec[rdma_idx] = 1; return 0; } int rdma_switch_to_nonsec(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig, void *handle) { unsigned int rdma_idx = rdma_index(module); enum CMDQ_ENG_ENUM cmdq_engine; cmdq_engine = rdma_to_cmdq_engine(module); if (rdma_is_sec[rdma_idx] == 1) { /* RDMA is in sec stat, we need to switch it to nonsec */ struct cmdqRecStruct *nonsec_switch_handle = NULL; int ret; ret = cmdqRecCreate( CMDQ_SCENARIO_DISP_PRIMARY_DISABLE_SECURE_PATH, &(nonsec_switch_handle)); if (ret) DDPAEE("[SVP]fail to create disable handle %s ret=%d\n", __func__, ret); cmdqRecReset(nonsec_switch_handle); if (rdma_idx == 0) { /* Primary Decouple Mode */ _cmdq_insert_wait_frame_done_token_mira( nonsec_switch_handle); } else { /* External Mode */ /* OVL1->RDMA1, do not use. */ _cmdq_insert_wait_frame_done_token_mira( nonsec_switch_handle); } cmdqRecSetSecure(nonsec_switch_handle, 1); /* * ugly workaround by kzhang !! * will remove when cmdq delete disable scenario. * To avoid translation fault like OVL (see notes in ovl.c) * check the mode now, bypass the frame during DL->DC(), * avoid hang when VDO mode. */ if (get_rdma_mode(module) == RDMA_MODE_MEMORY) do_rdma_config_l(module, pConfig, nonsec_switch_handle); /* in fact, dapc/port_sec will be disabled by cmdq */ cmdqRecSecureEnablePortSecurity(nonsec_switch_handle, (1LL << cmdq_engine)); if (handle) { /* Async Flush method */ enum CMDQ_EVENT_ENUM cmdq_event_nonsec_end; cmdq_event_nonsec_end = rdma_to_cmdq_event_nonsec_end(module); cmdqRecSetEventToken(nonsec_switch_handle, cmdq_event_nonsec_end); cmdqRecFlushAsync(nonsec_switch_handle); cmdqRecWait(handle, cmdq_event_nonsec_end); } else { /* Sync Flush method */ cmdqRecFlush(nonsec_switch_handle); } cmdqRecDestroy(nonsec_switch_handle); DDPSVPMSG("[SVP] switch rdma%d to nonsec\n", rdma_idx); mmprofile_log_ex(ddp_mmp_get_events()->svp_module[module], MMPROFILE_FLAG_END, 0, 0); } rdma_is_sec[rdma_idx] = 0; return 0; } int rdma_wait_sec_done(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig, void *handle) { unsigned int rdma_idx = rdma_index(module); enum CMDQ_ENG_ENUM cmdq_engine; struct cmdqRecStruct *wait_handle; int ret; if (rdma_is_sec[rdma_idx] == 0) return 0; cmdq_engine = rdma_to_cmdq_engine(module); /* rdma is in sec stat, we need to switch it to nonsec */ ret = cmdqRecCreate(CMDQ_SCENARIO_PRIMARY_DISP, &(wait_handle)); if (ret) DDPAEE("[SVP]fail to create disable handle %s ret=%d\n", __func__, ret); cmdqRecReset(wait_handle); cmdqRecSetSecure(wait_handle, 1); cmdqRecSecureEnablePortSecurity(wait_handle, (1LL << cmdq_engine)); if (handle != NULL) { /*Async Flush method*/ enum CMDQ_EVENT_ENUM cmdq_event_nonsec_end; cmdq_event_nonsec_end = rdma_to_cmdq_event_nonsec_end(module); cmdqRecSetEventToken(wait_handle, cmdq_event_nonsec_end); cmdqRecFlushAsync(wait_handle); cmdqRecWait(handle, cmdq_event_nonsec_end); } else { /*Sync Flush method*/ cmdqRecFlush(wait_handle); } cmdqRecDestroy(wait_handle); mmprofile_log_ex(ddp_mmp_get_events()->svp_module[module], MMPROFILE_FLAG_END, 0, 0); /* MMProfileLogEx(ddp_mmp_get_events()->svp_module[module], * MMProfileFlagPulse, 1, 1); */ return 0; } static int setup_rdma_sec(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig, void *handle) { int ret; int is_engine_sec = 0; enum RDMA_MODE mode = rdma_config_mode(pConfig->rdma_config.address); if (pConfig->rdma_config.security == DISP_SECURE_BUFFER) is_engine_sec = 1; if (!handle) { DDPDBG("[SVP] bypass rdma sec setting sec=%d,handle=NULL\n", is_engine_sec); return 0; } /* sec setting makes sense only in memory mode! */ if (mode == RDMA_MODE_MEMORY) { if (is_engine_sec == 1) ret = rdma_switch_to_sec(module, handle); else /* handle = NULL, use the sync flush method */ ret = rdma_switch_to_nonsec(module, pConfig, NULL); if (ret) DDPAEE("[SVP]fail to %s: ret=%d\n", __func__, ret); } else { rdma_wait_sec_done(module, pConfig, NULL); } return is_engine_sec; } static int rdma_config_l(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig, void *handle) { if (pConfig->dst_dirty || pConfig->rdma_dirty) { setup_rdma_sec(module, pConfig, handle); do_rdma_config_l(module, pConfig, handle); } return 0; } void rdma_enable_color_transform(enum DISP_MODULE_ENUM module) { unsigned int idx = rdma_index(module); unsigned int offset = DISP_RDMA_INDEX_OFFSET * idx; UINT32 value = DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_0 + offset); value = value | REG_FLD_VAL((SIZE_CON_0_FLD_MATRIX_EXT_MTX_EN), 1) | REG_FLD_VAL((SIZE_CON_0_FLD_MATRIX_ENABLE), 1); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_SIZE_CON_0, value); } void rdma_disable_color_transform(enum DISP_MODULE_ENUM module) { unsigned int idx = rdma_index(module); unsigned int offset = DISP_RDMA_INDEX_OFFSET * idx; UINT32 value = DISP_REG_GET(DISP_REG_RDMA_SIZE_CON_0 + offset); value = value & ~(REG_FLD_VAL((SIZE_CON_0_FLD_MATRIX_EXT_MTX_EN), 1) | REG_FLD_VAL((SIZE_CON_0_FLD_MATRIX_ENABLE), 1)); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_SIZE_CON_0, value); } void rdma_set_color_matrix(enum DISP_MODULE_ENUM module, struct rdma_color_matrix *matrix, struct rdma_color_pre *pre, struct rdma_color_post *post) { unsigned int idx = rdma_index(module); unsigned int offset = DISP_RDMA_INDEX_OFFSET * idx; DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C00, matrix->C00); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C01, matrix->C01); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C02, matrix->C02); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C10, matrix->C10); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C11, matrix->C11); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C12, matrix->C12); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C20, matrix->C20); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C21, matrix->C21); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_C22, matrix->C22); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_PRE_ADD_0, pre->ADD0); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_PRE_ADD_1, pre->ADD1); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_PRE_ADD_2, pre->ADD2); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_POST_ADD_0, post->ADD0); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_POST_ADD_1, post->ADD1); DISP_REG_SET(NULL, offset + DISP_REG_RDMA_POST_ADD_2, post->ADD2); } static int _rdma_partial_update(enum DISP_MODULE_ENUM module, void *arg, void *handle) { struct disp_rect *roi = (struct disp_rect *)arg; int width = roi->width; int height = roi->height; unsigned int idx = rdma_index(module); unsigned int offset = DISP_RDMA_INDEX_OFFSET * idx; DISP_REG_SET_FIELD(handle, SIZE_CON_0_FLD_OUTPUT_FRAME_WIDTH, offset + DISP_REG_RDMA_SIZE_CON_0, width); DISP_REG_SET_FIELD(handle, SIZE_CON_1_FLD_OUTPUT_FRAME_HEIGHT, offset + DISP_REG_RDMA_SIZE_CON_1, height); return 0; } int rdma_ioctl(enum DISP_MODULE_ENUM module, void *cmdq_handle, unsigned int ioctl_cmd, unsigned long *params) { int ret = 0; enum DDP_IOCTL_NAME ioctl = (enum DDP_IOCTL_NAME)ioctl_cmd; unsigned int idx = rdma_index(module); switch (ioctl) { case DDP_RDMA_GOLDEN_SETTING: { struct disp_ddp_path_config *pConfig; struct golden_setting_context *p_golden_setting; pConfig = (struct disp_ddp_path_config *)params; p_golden_setting = pConfig->p_golden_setting_context; rdma_set_ultra_l(idx, pConfig->lcm_bpp, cmdq_handle, p_golden_setting); break; } case DDP_PARTIAL_UPDATE: _rdma_partial_update(module, params, cmdq_handle); break; default: break; } return ret; } static int rdma_build_cmdq(enum DISP_MODULE_ENUM module, void *handle, enum CMDQ_STATE state) { if (handle == NULL) { DDP_PR_ERR("cmdq_trigger_handle is NULL\n"); return -1; } if (state == CMDQ_RESET_AFTER_STREAM_EOF) { /* * if RDMA frame done with underflow, * rdma will hold dvfs request forever * we reset here to solve this issue */ rdma_reset_by_cmdq(module, handle); } return 0; } /* for mmpath */ inline bool MMPathIsPrimaryDL(void) { return (rdma_golden_setting->is_dc == 0); } unsigned int MMPathTracePrimaryRDMA(char *str, unsigned int strlen, unsigned int n) { n += scnprintf(str + n, strlen - n, "in=0x%lx, in_width=%d, in_height=%d, in_fmt=%s, in_Bpp=%u, ", g_primary_rdma_cfg.address, g_primary_rdma_cfg.width, g_primary_rdma_cfg.height, unified_color_fmt_name(g_primary_rdma_cfg.inputFormat), ufmt_get_Bpp(g_primary_rdma_cfg.inputFormat)); return n; } struct DDP_MODULE_DRIVER ddp_driver_rdma = { .init = rdma_init, .deinit = rdma_deinit, .config = rdma_config_l, .start = rdma_start, .trigger = NULL, .stop = rdma_stop, .reset = rdma_reset, .power_on = rdma_clock_on, .power_off = rdma_clock_off, .is_idle = NULL, .is_busy = NULL, .dump_info = rdma_dump, .bypass = NULL, .build_cmdq = rdma_build_cmdq, .set_lcm_utils = NULL, .enable_irq = rdma_enable_irq, .ioctl = (int (*)(enum DISP_MODULE_ENUM, void *, enum DDP_IOCTL_NAME, void *))rdma_ioctl, .switch_to_nonsec = NULL, };