/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #define LOG_TAG "OVL" #include #include "ddp_log.h" #include "ddp_clkmgr.h" #include "ddp_m4u.h" #include #include "ddp_info.h" #include "ddp_hal.h" #include "ddp_reg.h" #include "ddp_ovl.h" #include "primary_display.h" #include "disp_rect.h" #include "disp_assert_layer.h" #include "ddp_mmp.h" #include "cmdq_record.h" #include "ddp_dump.h" #include "disp_drv_platform.h" #define OVL_REG_BACK_MAX (40) #define OVL_LAYER_OFFSET (0x20) #define OVL_RDMA_DEBUG_OFFSET (0x4) #ifdef CONFIG_MTK_ROUND_CORNER_SUPPORT #define ASSERT_LAYER_OFFSET (1) #else #define ASSERT_LAYER_OFFSET (0) #endif enum OVL_COLOR_SPACE { OVL_COLOR_SPACE_RGB = 0, OVL_COLOR_SPACE_YUV, }; struct OVL_REG { unsigned long address; unsigned int value; }; static enum DISP_MODULE_ENUM ovl_index_module[OVL_NUM] = { DISP_MODULE_OVL0 }; static unsigned int gOVLBackground = 0xFF000000; static inline int is_module_ovl(enum DISP_MODULE_ENUM module) { if (module == DISP_MODULE_OVL0) return 1; else return 0; } unsigned long ovl_base_addr(enum DISP_MODULE_ENUM module) { switch (module) { case DISP_MODULE_OVL0: return DISPSYS_OVL0_BASE; default: DDPERR("invalid ovl module=%d\n", module); /* BUG(); */ } return 0; } static inline unsigned long ovl_layer_num(enum DISP_MODULE_ENUM module) { switch (module) { case DISP_MODULE_OVL0: return 4; default: DDPERR("invalid ovl module=%d\n", module); /* BUG(); */ } return 0; } enum CMDQ_EVENT_ENUM ovl_to_cmdq_event_nonsec_end(enum DISP_MODULE_ENUM module) { switch (module) { case DISP_MODULE_OVL0: return CMDQ_SYNC_DISP_OVL0_2NONSEC_END; default: DDPERR("invalid ovl module=%d, get cmdq event nonsecure fail\n", module); ASSERT(0); } return 0; } static inline unsigned long ovl_to_cmdq_engine(enum DISP_MODULE_ENUM module) { switch (module) { case DISP_MODULE_OVL0: return CMDQ_ENG_DISP_OVL0; default: DDPERR("invalid ovl module=%d, get cmdq engine fail\n", module); ASSERT(0); return DISP_MODULE_UNKNOWN; } return 0; } unsigned long ovl_to_index(enum DISP_MODULE_ENUM module) { int i; for (i = 0; i < OVL_NUM; i++) { if (ovl_index_module[i] == module) return i; } DDPERR("invalid ovl module=%d, get ovl index fail\n", module); ASSERT(0); return 0; } static inline enum DISP_MODULE_ENUM ovl_index_to_module(int index) { if (index >= OVL_NUM) { DDPERR("invalid ovl index=%d\n", index); ASSERT(0); } return ovl_index_module[index]; } int ovl_start(enum DISP_MODULE_ENUM module, void *handle) { unsigned long ovl_base = ovl_base_addr(module); unsigned int reg_val = 0; DISP_REG_SET_FIELD(handle, EN_FLD_OVL_EN, ovl_base + DISP_REG_OVL_EN, 0x1); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_INTEN, 0x21F0 | REG_FLD_VAL(INTEN_FLD_FME_CPL_INTEN, 1) | REG_FLD_VAL(INTEN_FLD_START_INTEN, 0)); reg_val = 0; /* if ovl use smi id, emi can do "out-of-order-arbitration", * this aciton will optimize DRAM transaction, and save more power! */ reg_val |= REG_FLD_VAL(DATAPATH_CON_FLD_LAYER_SMI_ID_EN, 1); reg_val |= REG_FLD_VAL(DATAPATH_CON_FLD_OUTPUT_NO_RND, 0); reg_val |= REG_FLD_VAL(DATAPATH_CON_FLD_GCLAST_EN, 1); reg_val |= REG_FLD_VAL(OVL_WIDE_GAMUT_EN, 1); reg_val |= REG_FLD_VAL(DATAPATH_CON_FLD_OUTPUT_CLAMP, 1); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_DATAPATH_CON, reg_val); return 0; } int ovl_stop(enum DISP_MODULE_ENUM module, void *handle) { unsigned long ovl_base = ovl_base_addr(module); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_INTEN, 0x00); DISP_REG_SET_FIELD(handle, EN_FLD_OVL_EN, ovl_base + DISP_REG_OVL_EN, 0x0); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_INTSTA, 0x00); return 0; } int ovl_is_idle(enum DISP_MODULE_ENUM module) { unsigned long ovl_base = ovl_base_addr(module); unsigned int ovl_flow_ctrl_dbg; ovl_flow_ctrl_dbg = DISP_REG_GET(ovl_base + DISP_REG_OVL_FLOW_CTRL_DBG); if ((ovl_flow_ctrl_dbg & 0x3ff) != 0x1 && (ovl_flow_ctrl_dbg & 0x3ff) != 0x2) return 0; return 1; } int ovl_reset(enum DISP_MODULE_ENUM module, void *handle) { #define OVL_IDLE (0x3) int ret = 0; unsigned int delay_cnt = 0; unsigned long ovl_base = ovl_base_addr(module); unsigned int ovl_flow_ctrl_dbg; DISP_CPU_REG_SET(ovl_base + DISP_REG_OVL_RST, 0x1); DISP_CPU_REG_SET(ovl_base + DISP_REG_OVL_RST, 0x0); /*only wait if not cmdq */ if (handle) return ret; ovl_flow_ctrl_dbg = DISP_REG_GET(ovl_base + DISP_REG_OVL_FLOW_CTRL_DBG); while (!(ovl_flow_ctrl_dbg & OVL_IDLE)) { delay_cnt++; udelay(10); if (delay_cnt > 2000) { DDPERR("%s reset timeout!\n", ddp_get_module_name(module)); ret = -1; break; } ovl_flow_ctrl_dbg = DISP_REG_GET(ovl_base + DISP_REG_OVL_FLOW_CTRL_DBG); } return ret; } int ovl_roi(enum DISP_MODULE_ENUM module, unsigned int bg_w, unsigned int bg_h, unsigned int bg_color, void *handle) { unsigned long ovl_base = ovl_base_addr(module); if ((bg_w > OVL_MAX_WIDTH) || (bg_h > OVL_MAX_HEIGHT)) { DDPERR("%s,exceed OVL max size, w=%d, h=%d\n", __func__, bg_w, bg_h); ASSERT(0); } DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_ROI_SIZE, bg_h << 16 | bg_w); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_ROI_BGCLR, bg_color); DDPMSG("%s:(%ux%u)\n", __func__, bg_w, bg_h); return 0; } int disable_ovl_layers(enum DISP_MODULE_ENUM module, void *handle) { unsigned long ovl_base = ovl_base_addr(module); int ovl_idx = ovl_to_index(module); /* physical layer control */ DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_SRC_CON, 0); /* ext layer control */ DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_DATAPATH_EXT_CON, 0); DDPSVPMSG("[SVP] switch ovl%d to nonsec: disable all the layers first!\n", ovl_idx); return 0; } int ovl_layer_switch(enum DISP_MODULE_ENUM module, unsigned int layer, unsigned int en, void *handle) { unsigned long ovl_base = ovl_base_addr(module); ASSERT(layer <= 3); switch (layer) { case 0: DISP_REG_SET_FIELD(handle, SRC_CON_FLD_L0_EN, ovl_base + DISP_REG_OVL_SRC_CON, en); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_RDMA0_CTRL, en); break; case 1: DISP_REG_SET_FIELD(handle, SRC_CON_FLD_L1_EN, ovl_base + DISP_REG_OVL_SRC_CON, en); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_RDMA1_CTRL, en); break; case 2: DISP_REG_SET_FIELD(handle, SRC_CON_FLD_L2_EN, ovl_base + DISP_REG_OVL_SRC_CON, en); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_RDMA2_CTRL, en); break; case 3: DISP_REG_SET_FIELD(handle, SRC_CON_FLD_L3_EN, ovl_base + DISP_REG_OVL_SRC_CON, en); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_RDMA3_CTRL, en); break; default: DDPERR("invalid layer=%d\n", layer); ASSERT(0); } return 0; } static int ovl_layer_config(enum DISP_MODULE_ENUM module, unsigned int layer, unsigned int is_engine_sec, const struct OVL_CONFIG_STRUCT *const cfg, const struct disp_rect *const ovl_partial_roi, const struct disp_rect *const layer_partial_roi, void *handle) { unsigned int value = 0; unsigned int Bpp, input_swap, input_fmt; unsigned int rgb_swap = 0; int is_rgb; int color_matrix = 0x4; int rotate = 0; int is_ext_layer = cfg->ext_layer != -1; unsigned long ovl_base = ovl_base_addr(module); unsigned long ext_layer_offset = is_ext_layer ? (DISP_REG_OVL_EL0_CON - DISP_REG_OVL_L0_CON) : 0; unsigned long ext_layer_offset_clr = is_ext_layer ? (DISP_REG_OVL_EL0_CLEAR - DISP_REG_OVL_L0_CLR) : 0; unsigned long ext_layer_offset_addr = is_ext_layer ? (DISP_REG_OVL_EL0_ADDR - DISP_REG_OVL_L0_ADDR) : 0; unsigned long layer_offset = ovl_base + ext_layer_offset + (is_ext_layer ? cfg->ext_layer : layer) * OVL_LAYER_OFFSET; unsigned long layer_offset_clr = ovl_base + ext_layer_offset_clr + (is_ext_layer ? cfg->ext_layer : layer) * 4; unsigned long layer_offset_rdma_ctrl = ovl_base + layer * OVL_LAYER_OFFSET; unsigned long layer_offset_addr = ovl_base + ext_layer_offset_addr + (is_ext_layer ? cfg->ext_layer * 4 : layer * OVL_LAYER_OFFSET); unsigned int offset = 0; enum UNIFIED_COLOR_FMT format = cfg->fmt; unsigned int src_x = cfg->src_x; unsigned int src_y = cfg->src_y; unsigned int dst_x = cfg->dst_x; unsigned int dst_y = cfg->dst_y; unsigned int dst_w = cfg->dst_w; unsigned int dst_h = cfg->dst_h; if (ovl_partial_roi != NULL) { dst_x = layer_partial_roi->x - ovl_partial_roi->x; dst_y = layer_partial_roi->y - ovl_partial_roi->y; dst_w = layer_partial_roi->width; dst_h = layer_partial_roi->height; src_x = cfg->src_x + layer_partial_roi->x - cfg->dst_x; src_y = cfg->src_y + layer_partial_roi->y - cfg->dst_y; DDPDBG("layer partial (%d,%d)(%d,%d,%d,%d) to (%d,%d)(%d,%d,%d,%d)\n", cfg->src_x, cfg->src_y, cfg->dst_x, cfg->dst_y, cfg->dst_w, cfg->dst_h, src_x, src_y, dst_x, dst_y, dst_w, dst_h); } if (dst_w > OVL_MAX_WIDTH) ASSERT(dst_w < OVL_MAX_WIDTH); if (dst_h > OVL_MAX_HEIGHT) ASSERT(dst_h < OVL_MAX_HEIGHT); if (!cfg->addr && cfg->source == OVL_LAYER_SOURCE_MEM) { DDPERR("source from memory, but addr is 0!\n"); ASSERT(0); return -1; } #ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATION_HW rotate = 1; #endif if (rotate) { if (is_slt_test()) rotate = 0; } if (is_slt_test()) { DISP_REG_SET_FIELD(handle, DATAPATH_CON_FLD_OUTPUT_CLAMP, ovl_base + DISP_REG_OVL_DATAPATH_CON, 0x0); } else { DISP_REG_SET_FIELD(handle, DATAPATH_CON_FLD_OUTPUT_CLAMP, ovl_base + DISP_REG_OVL_DATAPATH_CON, 0x1); } /* check dim layer fmt */ if (cfg->source == OVL_LAYER_SOURCE_RESERVED) { if (cfg->aen == 0) DDPERR("dim layer%d ahpha enable should be 1!\n", layer); format = UFMT_RGB888; } Bpp = ufmt_get_Bpp(format); input_swap = ufmt_get_byteswap(format); input_fmt = ufmt_get_format(format); is_rgb = ufmt_get_rgb(format); if (rotate) { unsigned int bg_h, bg_w; bg_h = DISP_REG_GET(ovl_base + DISP_REG_OVL_ROI_SIZE); bg_w = bg_h & 0xFFFF; bg_h = bg_h >> 16; DISP_REG_SET(handle, DISP_REG_OVL_L0_OFFSET + layer_offset, ((bg_h - dst_h - dst_y) << 16) | (bg_w - dst_w - dst_x)); } else { DISP_REG_SET(handle, DISP_REG_OVL_L0_OFFSET + layer_offset, (dst_y << 16) | dst_x); } if (format == UFMT_UYVY || format == UFMT_VYUY || format == UFMT_YUYV || format == UFMT_YVYU) { unsigned int regval = 0; if (src_x % 2) { src_x -= 1; /* make src_x to even */ dst_w += 1; regval |= REG_FLD_VAL(OVL_L_CLIP_FLD_LEFT, 1); } if ((src_x + dst_w) % 2) { dst_w += 1; /* make right boundary even */ regval |= REG_FLD_VAL(OVL_L_CLIP_FLD_RIGHT, 1); } DISP_REG_SET(handle, DISP_REG_OVL_L0_CLIP + layer_offset, regval); } else { DISP_REG_SET(handle, DISP_REG_OVL_L0_CLIP + layer_offset, 0); } switch (cfg->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: DDPERR("un-recognized yuv_range=%d!\n", cfg->yuv_range); color_matrix = 4; break; } DISP_REG_SET(handle, DISP_REG_OVL_RDMA0_CTRL + layer_offset_rdma_ctrl, 0x1); value = (REG_FLD_VAL((L_CON_FLD_LSRC), (cfg->source)) | REG_FLD_VAL((L_CON_FLD_CFMT), (input_fmt)) | REG_FLD_VAL((L_CON_FLD_AEN), (cfg->aen)) | REG_FLD_VAL((L_CON_FLD_APHA), (cfg->alpha)) | REG_FLD_VAL((L_CON_FLD_SKEN), (cfg->keyEn)) | REG_FLD_VAL((L_CON_FLD_BTSW), (input_swap))); if (ufmt_is_old_fmt(format)) { if (format == UFMT_PARGB8888 || format == UFMT_PABGR8888 || format == UFMT_PRGBA8888 || format == UFMT_PBGRA8888) { rgb_swap = ufmt_get_rgbswap(format); value |= REG_FLD_VAL((L_CON_FLD_RGB_SWAP), (rgb_swap)); } value |= REG_FLD_VAL((L_CON_FLD_CLRFMT_MAN), (1)); } if (!is_rgb) value = value | REG_FLD_VAL((L_CON_FLD_MTX), (color_matrix)); if (rotate) value |= REG_FLD_VAL((L_CON_FLD_VIRTICAL_FLIP), (1)) | REG_FLD_VAL((L_CON_FLD_HORI_FLIP), (1)); DISP_REG_SET(handle, DISP_REG_OVL_L0_CON + layer_offset, value); DISP_REG_SET(handle, DISP_REG_OVL_L0_CLR + layer_offset_clr, 0xff000000 | cfg->dim_color); DISP_REG_SET(handle, DISP_REG_OVL_L0_SRC_SIZE + layer_offset, dst_h << 16 | dst_w); if (rotate) offset = (src_x + dst_w) * Bpp + (src_y + dst_h - 1) * cfg->src_pitch - 1; else offset = src_x * Bpp + src_y * cfg->src_pitch; if (!is_engine_sec) { DISP_REG_SET(handle, DISP_REG_OVL_L0_ADDR + layer_offset_addr, cfg->addr + offset); } else { unsigned int size; int m4u_port; size = (dst_h - 1) * cfg->src_pitch + dst_w * Bpp; m4u_port = module_to_m4u_port(module); if (cfg->security != DISP_SECURE_BUFFER) { /* * ovl is sec but this layer is non-sec * we need to tell cmdq to help map non-sec * mva to sec mva */ cmdqRecWriteSecure(handle, disp_addr_convert(DISP_REG_OVL_L0_ADDR + layer_offset_addr), CMDQ_SAM_NMVA_2_MVA, cfg->addr + offset, 0, size, m4u_port); } else { /* * 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(DISP_REG_OVL_L0_ADDR + layer_offset_addr), CMDQ_SAM_H_2_MVA, cfg->addr, offset, size, m4u_port); } } DISP_REG_SET(handle, DISP_REG_OVL_L0_SRCKEY + layer_offset, cfg->key); value = REG_FLD_VAL(L_PITCH_FLD_SA_SEL, cfg->src_alpha & 0x3) | REG_FLD_VAL(L_PITCH_FLD_SRGB_SEL, cfg->src_alpha & 0x3) | REG_FLD_VAL(L_PITCH_FLD_DA_SEL, cfg->dst_alpha & 0x3) | REG_FLD_VAL(L_PITCH_FLD_DRGB_SEL, cfg->dst_alpha & 0x3) | REG_FLD_VAL(L_PITCH_FLD_SURFL_EN, cfg->src_alpha & 0x1) | REG_FLD_VAL(L_PITCH_FLD_SRC_PITCH, cfg->src_pitch); if (cfg->const_bld) value |= REG_FLD_VAL((L_PITCH_FLD_CONST_BLD), (1)); DISP_REG_SET(handle, DISP_REG_OVL_L0_PITCH + layer_offset, value); return 0; } int ovl_clock_on(enum DISP_MODULE_ENUM module, void *handle) { DDPDBG("%s clock_on\n", ddp_get_module_name(module)); ddp_clk_prepare_enable(ddp_get_module_clk_id(module)); return 0; } int ovl_clock_off(enum DISP_MODULE_ENUM module, void *handle) { DDPDBG("%s clock_off\n", ddp_get_module_name(module)); ddp_clk_disable_unprepare(ddp_get_module_clk_id(module)); return 0; } int ovl_init(enum DISP_MODULE_ENUM module, void *handle) { return 0; } int ovl_deinit(enum DISP_MODULE_ENUM module, void *handle) { return 0; } int ovl_connect(enum DISP_MODULE_ENUM module, enum DISP_MODULE_ENUM prev, enum DISP_MODULE_ENUM next, int connect, void *handle) { unsigned long ovl_base = ovl_base_addr(module); if (connect && is_module_ovl(prev)) DISP_REG_SET_FIELD(handle, DATAPATH_CON_FLD_BGCLR_IN_SEL, ovl_base + DISP_REG_OVL_DATAPATH_CON, 1); else DISP_REG_SET_FIELD(handle, DATAPATH_CON_FLD_BGCLR_IN_SEL, ovl_base + DISP_REG_OVL_DATAPATH_CON, 0); return 0; } unsigned int ddp_ovl_get_cur_addr(bool rdma_mode, int layerid) { /*just workaround, should remove this func */ unsigned long ovl_base = ovl_base_addr(DISP_MODULE_OVL0); unsigned long Lx_base = 0; if (rdma_mode) return DISP_REG_GET(DISP_REG_RDMA_MEM_START_ADDR); Lx_base = layerid * OVL_LAYER_OFFSET + ovl_base; if (DISP_REG_GET(DISP_REG_OVL_RDMA0_CTRL + Lx_base) & 0x1) return DISP_REG_GET(DISP_REG_OVL_L0_ADDR + Lx_base); return 0; } void ovl_get_address(enum DISP_MODULE_ENUM module, unsigned long *add) { int i = 0; unsigned long ovl_base = ovl_base_addr(module); unsigned long layer_off = 0; unsigned int src_on = DISP_REG_GET(DISP_REG_OVL_SRC_CON + ovl_base); for (i = 0; i < 4; i++) { layer_off = i * OVL_LAYER_OFFSET + ovl_base; if (src_on & (0x1 << i)) add[i] = DISP_REG_GET(layer_off + DISP_REG_OVL_L0_ADDR); else add[i] = 0; } } void ovl_get_info(enum DISP_MODULE_ENUM module, void *data) { unsigned int i = 0; struct OVL_BASIC_STRUCT *pdata = data; unsigned long ovl_base = ovl_base_addr(module); unsigned long layer_off = 0; unsigned int src_on = DISP_REG_GET(DISP_REG_OVL_SRC_CON + ovl_base); struct OVL_BASIC_STRUCT *p = NULL; for (i = 0; i < ovl_layer_num(module); i++) { unsigned int val = 0; layer_off = i * OVL_LAYER_OFFSET + ovl_base; p = &pdata[i]; p->layer = i; p->layer_en = src_on & (0x1 << i); if (!p->layer_en) { DDPDBG("%s:layer%d,en %d,w %d,h %d,bpp %d,addr %lu\n", __func__, i, p->layer_en, p->src_w, p->src_h, p->bpp, p->addr); continue; } val = DISP_REG_GET(DISP_REG_OVL_L0_CON + layer_off); p->fmt = display_fmt_reg_to_unified_fmt( REG_FLD_VAL_GET(L_CON_FLD_CFMT, val), REG_FLD_VAL_GET(L_CON_FLD_BTSW, val), REG_FLD_VAL_GET(L_CON_FLD_RGB_SWAP, val)); p->addr = DISP_REG_GET(layer_off + DISP_REG_OVL_L0_ADDR); val = DISP_REG_GET(DISP_REG_OVL_L0_SRC_SIZE + layer_off); p->src_w = val & 0xfff; p->src_h = (val >> 16) & 0xfff; val = DISP_REG_GET(DISP_REG_OVL_L0_PITCH + layer_off); p->src_pitch = val & 0xffff; p->bpp = UFMT_GET_bpp(p->fmt) / 8; val = DISP_REG_GET(DISP_REG_OVL_DATAPATH_CON + layer_off); p->gpu_mode = (val & (0x1 << (8 + i))) ? 1 : 0; p->adobe_mode = (val & (0x1 << 12)) ? 1 : 0; p->ovl_gamma_out = (val & (0x1 << 15)) ? 1 : 0; p->alpha = (DISP_REG_GET(layer_off + DISP_REG_OVL_L0_CON + (i * 0x20)) & (0x1 << 8)) ? 1 : 0; DDPDBG("ovl_get_info:layer%d,en %d,w %d,h %d,bpp %d,addr %lu\n", i, p->layer_en, p->src_w, p->src_h, p->bpp, p->addr); } } extern int m4u_query_mva_info(unsigned int mva, unsigned int size, unsigned int *real_mva, unsigned int *real_size); static int ovl_check_input_param(struct OVL_CONFIG_STRUCT *config) { if ((config->addr == 0 && config->source == 0) || config->dst_w == 0 || config->dst_h == 0) { DDPERR("ovl parameter invalidate, addr=%lu, w=%d, h=%d\n", config->addr, config->dst_w, config->dst_h); ASSERT(0); return -1; } return 0; } /* use noinline to reduce stack size */ static noinline void print_layer_config_args(int module, int local_layer, struct OVL_CONFIG_STRUCT *ovl_cfg, struct disp_rect *roi) { DDPDBG("%s, layer=%d(%d), source=%s, off(x=%d, y=%d), dst(%d, %d, %d, %d),pitch=%d,", ddp_get_module_name(module), local_layer, ovl_cfg->layer, (ovl_cfg->source == 0) ? "memory" : "dim", ovl_cfg->src_x, ovl_cfg->src_y, ovl_cfg->dst_x, ovl_cfg->dst_y, ovl_cfg->dst_w, ovl_cfg->dst_h, ovl_cfg->src_pitch); DDPDBG("fmt=%s, addr=%lx, keyEn=%d, key=%d, aen=%d, alpha=%d,", unified_color_fmt_name(ovl_cfg->fmt), ovl_cfg->addr, ovl_cfg->keyEn, ovl_cfg->key, ovl_cfg->aen, ovl_cfg->alpha); DDPDBG("sur_aen=%d,sur_alpha=0x%x,yuv_range=%d,sec=%d,const_bld=%d\n", ovl_cfg->sur_aen, (ovl_cfg->dst_alpha << 2) | ovl_cfg->src_alpha, ovl_cfg->yuv_range, ovl_cfg->security, ovl_cfg->const_bld); if (roi) DDPDBG("dirty(%d,%d,%d,%d)\n", roi->x, roi->y, roi->height, roi->width); } static int ovl_is_sec[OVL_NUM]; static inline int ovl_switch_to_sec(enum DISP_MODULE_ENUM module, void *handle) { unsigned int ovl_idx = ovl_to_index(module); enum CMDQ_ENG_ENUM cmdq_engine; cmdq_engine = ovl_to_cmdq_engine(module); cmdqRecSetSecure(handle, 1); /* * set engine as sec port, it will to access * the sec memory EMI_MPU protected */ if (cmdq_engine < 64) cmdqRecSecureEnablePortSecurity(handle, (1LL << cmdq_engine)); else DDPERR("cmdq engine overflow!:%d\n", cmdq_engine); /* Enable DAPC to protect the engine register */ /* cmdqRecSecureEnableDAPC(handle, (1LL << cmdq_engine)); */ if (ovl_is_sec[ovl_idx] == 0) { DDPSVPMSG("[SVP] switch ovl%d to sec\n", ovl_idx); mmprofile_log_ex(ddp_mmp_get_events()->svp_module[module], MMPROFILE_FLAG_START, 0, 0); } ovl_is_sec[ovl_idx] = 1; return 0; } int ovl_switch_to_nonsec(enum DISP_MODULE_ENUM module, void *handle) { unsigned int ovl_idx = ovl_to_index(module); enum CMDQ_ENG_ENUM cmdq_engine; enum CMDQ_EVENT_ENUM cmdq_event_nonsec_end; cmdq_engine = ovl_to_cmdq_engine(module); if (ovl_is_sec[ovl_idx] == 1) { /* ovl 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 (module != DISP_MODULE_OVL1_2L) { /*Primary Mode*/ if (primary_display_is_decouple_mode()) cmdqRecWaitNoClear(nonsec_switch_handle, CMDQ_EVENT_DISP_WDMA0_EOF); else _cmdq_insert_wait_frame_done_token_mira( nonsec_switch_handle); } else { /*External Mode*/ /*_cmdq_insert_wait_frame_done_token_mira * (nonsec_switch_handle); */ cmdqRecWaitNoClear(nonsec_switch_handle, CMDQ_SYNC_DISP_EXT_STREAM_EOF); } cmdqRecSetSecure(nonsec_switch_handle, 1); /* * we should disable OVL before new (nonsec) setting takes * effect, or translation fault may happen. * if we switch OVL to nonsec BUT its setting is still sec */ disable_ovl_layers(module, nonsec_switch_handle); /*in fact, dapc/port_sec will be disabled by cmdq */ cmdqRecSecureEnablePortSecurity(nonsec_switch_handle, (1LL << cmdq_engine)); /* cmdqRecSecureEnableDAPC(nonsec_switch_handle, (1LL << * cmdq_engine)); */ if (handle) { /* async flush method */ cmdq_event_nonsec_end = ovl_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 ovl%d to nonsec\n", ovl_idx); mmprofile_log_ex(ddp_mmp_get_events()->svp_module[module], MMPROFILE_FLAG_END, 0, 0); } ovl_is_sec[ovl_idx] = 0; return 0; } static int setup_ovl_sec(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig, void *handle) { int ret; int layer_id; int has_sec_layer = 0; struct OVL_CONFIG_STRUCT *ovl_config; /* check if the OVL module has sec layer */ for (layer_id = 0; layer_id < TOTAL_OVL_LAYER_NUM; layer_id++) { ovl_config = &pConfig->ovl_config[layer_id]; if (ovl_config->ovl_index == module && ovl_config->layer_en && ovl_config->security == DISP_SECURE_BUFFER) has_sec_layer = 1; } if (!handle) { DDPDBG("[SVP] bypass ovl sec setting sec=%d,handle=NULL\n", has_sec_layer); return 0; } if (has_sec_layer == 1) ret = ovl_switch_to_sec(module, handle); else ret = ovl_switch_to_nonsec(module, NULL); if (ret) DDPAEE("[SVP]fail to %s ret=%d\n", __func__, ret); return has_sec_layer; } /* * for enabled layers: layout continuously for each OVL HW engine * for disabled layers: ignored */ static int ovl_layer_layout(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig) { int local_layer, global_layer = 0, assert_layer = 0; int ovl_idx = module; int phy_layer = -1, ext_layer = -1, ext_layer_idx = 0; BUILD_BUG_ON(PRIMARY_SESSION_INPUT_LAYER_COUNT > TOTAL_OVL_LAYER_NUM); /* * 1. check if it has been prepared, * just only prepare once for each frame */ #if 0 for (global_layer = 0; global_layer < TOTAL_OVL_LAYER_NUM; global_layer++) { if (!(pConfig->ovl_layer_scanned & (1 << global_layer))) break; } if (global_layer >= TOTAL_OVL_LAYER_NUM) return 0; #else if (pConfig->ovl_layer_scanned != 0) return 0; #endif /* 2. prepare layer layout */ for (local_layer = 0; global_layer < PRIMARY_SESSION_INPUT_LAYER_COUNT; local_layer++, global_layer++) { struct OVL_CONFIG_STRUCT *ovl_cfg = &pConfig->ovl_config[global_layer]; ext_layer = -1; ovl_cfg->phy_layer = 0; ovl_cfg->ext_layer = -1; pConfig->ovl_layer_scanned |= (1 << global_layer); /* * skip disabled layers, but need to decrease * local_layer to make layout continuously * all layers layout continuously by HRT Calc, * so this is not necessary */ if (ovl_cfg->layer_en == 0) { local_layer--; continue; } /* for Assert_layer config special case, do it specially */ assert_layer = primary_display_get_option("ASSERT_LAYER"); if (is_DAL_Enabled() && ovl_cfg->layer == assert_layer) { ovl_cfg->ovl_index = DISP_MODULE_OVL0; ovl_cfg->phy_layer = ovl_layer_num(DISP_MODULE_OVL0) - ASSERT_LAYER_OFFSET - 1; continue; } if (disp_helper_get_option(DISP_OPT_OVL_EXT_LAYER)) { if (ovl_cfg->ext_sel_layer != -1) { /* always layout from idx=0, so layer_idx * here should be the same as ext_sel_layer */ if (phy_layer != ovl_cfg->ext_sel_layer) { DDPERR("L%d layout not match: cur=%d, in=%d\n", global_layer, phy_layer, ovl_cfg->ext_sel_layer); phy_layer++; ext_layer = -1; } else { ext_layer = ext_layer_idx++; } } else { /* all phy layers are layout continuously */ phy_layer++; } } else { phy_layer = local_layer; } /* when OVL is full, update ovl index, ext layer capability is * confirmed before */ if (phy_layer >= ovl_layer_num(ovl_idx)) { phy_layer = 0; local_layer = 0; ext_layer = -1; ext_layer_idx = 0; if (ovl_idx == DISP_MODULE_OVL0) ovl_idx = DISP_MODULE_OVL0_2L; else DDPERR("unknown module: %d\n", ovl_idx); } ovl_cfg->ovl_index = ovl_idx; ovl_cfg->phy_layer = phy_layer; ovl_cfg->ext_layer = ext_layer; DDPDBG("layout:L%d->ovl%d,phy:%d,ext:%d,ext_sel:%d\n", global_layer, ovl_idx, phy_layer, ext_layer, (ext_layer >= 0) ? phy_layer : ovl_cfg->ext_sel_layer); } return 1; } static int ovl_config_l(enum DISP_MODULE_ENUM module, struct disp_ddp_path_config *pConfig, void *handle) { int enabled_layers = 0; int has_sec_layer = 0; int layer_id; int enabled_ext_layers = 0, ext_sel_layers = 0; #if 0 unsigned int tb = 0; unsigned int bb = 0; #endif if (pConfig->dst_dirty) ovl_roi(module, pConfig->dst_w, pConfig->dst_h, gOVLBackground, handle); if (!pConfig->ovl_dirty) return 0; ovl_layer_layout(module, pConfig); #if 0 /* check if the ovl module has sec layer */ for (layer_id = 0; layer_id < TOTAL_OVL_LAYER_NUM; layer_id++) { if (pConfig->ovl_config[layer_id].ovl_index == module && pConfig->ovl_config[layer_id].layer_en && (pConfig->ovl_config[layer_id].security == DISP_SECURE_BUFFER)) has_sec_layer = 1; } setup_ovl_sec(module, handle, has_sec_layer); #else has_sec_layer = setup_ovl_sec(module, pConfig, handle); #endif for (layer_id = 0; layer_id < TOTAL_OVL_LAYER_NUM; layer_id++) { struct OVL_CONFIG_STRUCT *ovl_cfg = &pConfig->ovl_config[layer_id]; int enable = ovl_cfg->layer_en; if (enable == 0) continue; if (ovl_check_input_param(ovl_cfg)) { DDPAEE("invalid layer parameters!\n"); continue; } if (ovl_cfg->ovl_index != module) continue; if (pConfig->ovl_partial_dirty) { struct disp_rect layer_roi = {0, 0, 0, 0}; struct disp_rect layer_partial_roi = {0, 0, 0, 0}; layer_roi.x = ovl_cfg->dst_x; layer_roi.y = ovl_cfg->dst_y; layer_roi.width = ovl_cfg->dst_w; layer_roi.height = ovl_cfg->dst_h; if (rect_intersect(&layer_roi, &pConfig->ovl_partial_roi, &layer_partial_roi)) { print_layer_config_args(module, ovl_cfg->phy_layer, ovl_cfg, &layer_partial_roi); ovl_layer_config(module, ovl_cfg->phy_layer, has_sec_layer, ovl_cfg, &pConfig->ovl_partial_roi, &layer_partial_roi, handle); } else { /* this layer will not be displayed */ enable = 0; } } else { print_layer_config_args(module, ovl_cfg->phy_layer, ovl_cfg, NULL); ovl_layer_config(module, ovl_cfg->phy_layer, has_sec_layer, ovl_cfg, NULL, NULL, handle); } if (ovl_cfg->ext_layer != -1) { enabled_ext_layers |= enable << ovl_cfg->ext_layer; ext_sel_layers |= ovl_cfg->phy_layer << (16 + 4 * ovl_cfg->ext_layer); } else { enabled_layers |= enable << ovl_cfg->phy_layer; } } DDPDBG("ovl%d enabled_layers=0x%01x, enabled_ext_layers=0x%01x, ext_sel_layers=0x%04x\n", module, enabled_layers, enabled_ext_layers, ext_sel_layers >> 16); DISP_REG_SET(handle, ovl_base_addr(module) + DISP_REG_OVL_SRC_CON, enabled_layers); /* ext layer control */ DISP_REG_SET(handle, ovl_base_addr(module) + DISP_REG_OVL_DATAPATH_EXT_CON, enabled_ext_layers | ext_sel_layers); #if 0 /* IP ACTIVE ALGORITHM */ if (pConfig->ovl_partial_dirty) ip_active_algorithm(pConfig->ovl_partial_roi->width, pConfig->ovl_partial_roi->height); else ip_active_algorithm(pConfig->dst_w, pConfig->dst_h); for (layer_id = 0; layer_id < TOTAL_OVL_LAYER_NUM; layer_id++) { struct OVL_CONFIG_STRUCT *ovl_cfg = &pConfig->ovl_config[layer_id]; int enable = ovl_cfg->layer_en; if (enable == 0) continue; if (ovl_check_input_param(ovl_cfg)) { DDPAEE("invalid layer parameters!\n"); continue; } if (ovl_cfg->ovl_index != module) continue; if (ovl_cfg->ext_layer == -1) { get_ip_active_layer_roi(ovl_cfg->phy_layer, 0, &tb, &bb); DISP_REG_SET(handle, ovl_base_addr(module) + DISP_REG_OVL_DVFS_L0_ROI + ovl_cfg->phy_layer*4, bb << 16 | tb); } else { get_ip_active_layer_roi(ovl_cfg->ext_layer, 1, &tb, &bb); DISP_REG_SET(handle, ovl_base_addr(module) + DISP_REG_OVL_DVFS_EL0_ROI + ovl_cfg->ext_layer*4, bb << 16 | tb); } } #endif return 0; } int ovl_build_cmdq(enum DISP_MODULE_ENUM module, void *cmdq_trigger_handle, enum CMDQ_STATE state) { int ret = 0; /* int reg_pa = DISP_REG_OVL_FLOW_CTRL_DBG & 0x1fffffff; */ if (!cmdq_trigger_handle) { DDPERR("cmdq_trigger_handle is NULL\n"); return -1; } if (state == CMDQ_CHECK_IDLE_AFTER_STREAM_EOF) { if (module == DISP_MODULE_OVL0) { ret = cmdqRecPoll(cmdq_trigger_handle, 0x14007240, 2, 0x3f); } else { DDPERR("wrong module: %s\n", ddp_get_module_name(module)); return -1; } } return 0; } static void ovl_printf_status(unsigned int status) { DDPDUMP("- OVL_FLOW_CONTROL_DEBUG -\n"); DDPDUMP("addcon_idle:%d,blend_idle:%d,out_valid:%d,out_ready:%d,out_idle:%d\n", (status >> 10) & (0x1), (status >> 11) & (0x1), (status >> 12) & (0x1), (status >> 13) & (0x1), (status >> 15) & (0x1)); DDPDUMP("rdma3_idle:%d,rdma2_idle:%d,rdma1_idle:%d, rdma0_idle:%d,rst:%d\n", (status >> 16) & (0x1), (status >> 17) & (0x1), (status >> 18) & (0x1), (status >> 19) & (0x1), (status >> 20) & (0x1)); DDPDUMP("trig:%d,frame_hwrst_done:%d,frame_swrst_done:%d,frame_underrun:%d,frame_done:%d\n", (status >> 21) & (0x1), (status >> 23) & (0x1), (status >> 24) & (0x1), (status >> 25) & (0x1), (status >> 26) & (0x1)); DDPDUMP("ovl_running:%d,ovl_start:%d,ovl_clr:%d,reg_update:%d,ovl_upd_reg:%d\n", (status >> 27) & (0x1), (status >> 28) & (0x1), (status >> 29) & (0x1), (status >> 30) & (0x1), (status >> 31) & (0x1)); DDPDUMP("ovl_fms_state:\n"); switch (status & 0x3ff) { case 0x1: DDPDUMP("idle\n"); break; case 0x2: DDPDUMP("wait_SOF\n"); break; case 0x4: DDPDUMP("prepare\n"); break; case 0x8: DDPDUMP("reg_update\n"); break; case 0x10: DDPDUMP("eng_clr(internal reset)\n"); break; case 0x20: DDPDUMP("eng_act(processing)\n"); break; case 0x40: DDPDUMP("h_wait_w_rst\n"); break; case 0x80: DDPDUMP("s_wait_w_rst\n"); break; case 0x100: DDPDUMP("h_w_rst\n"); break; case 0x200: DDPDUMP("s_w_rst\n"); break; default: DDPDUMP("ovl_fsm_unknown\n"); break; } } static void ovl_print_ovl_rdma_status(unsigned int status) { DDPDUMP("wram_rst_cs:0x%x,layer_greq:0x%x,out_data:0x%x,", status & 0x7, (status >> 3) & 0x1, (status >> 4) & 0xffffff); DDPDUMP("out_ready:0x%x,out_valid:0x%x,smi_busy:0x%x,smi_greq:0x%x\n", (status >> 28) & 0x1, (status >> 29) & 0x1, (status >> 30) & 0x1, (status >> 31) & 0x1); } static void ovl_dump_layer_info(int layer, unsigned long layer_offset) { enum UNIFIED_COLOR_FMT fmt; fmt = display_fmt_reg_to_unified_fmt( DISP_REG_GET_FIELD(L_CON_FLD_CFMT, DISP_REG_OVL_L0_CON + layer_offset), DISP_REG_GET_FIELD(L_CON_FLD_BTSW, DISP_REG_OVL_L0_CON + layer_offset), DISP_REG_GET_FIELD(L_CON_FLD_RGB_SWAP, DISP_REG_OVL_L0_CON + layer_offset)); DDPDUMP("layer%d: w=%d,h=%d,off(x=%d,y=%d),pitch=%d,addr=0x%x,fmt=%s,source=%s,aen=%d,alpha=%d\n", layer, DISP_REG_GET(layer_offset + DISP_REG_OVL_L0_SRC_SIZE) & 0xfff, (DISP_REG_GET(layer_offset + DISP_REG_OVL_L0_SRC_SIZE) >> 16) & 0xfff, DISP_REG_GET(layer_offset + DISP_REG_OVL_L0_OFFSET) & 0xfff, (DISP_REG_GET(layer_offset + DISP_REG_OVL_L0_OFFSET) >> 16) & 0xfff, DISP_REG_GET(layer_offset + DISP_REG_OVL_L0_PITCH) & 0xffff, DISP_REG_GET(layer_offset + DISP_REG_OVL_L0_ADDR), unified_color_fmt_name(fmt), (DISP_REG_GET_FIELD(L_CON_FLD_LSRC, DISP_REG_OVL_L0_CON + layer_offset) == 0) ? "memory" : "constant_color", DISP_REG_GET_FIELD(L_CON_FLD_AEN, DISP_REG_OVL_L0_CON + layer_offset), DISP_REG_GET_FIELD(L_CON_FLD_APHA, DISP_REG_OVL_L0_CON + layer_offset)); } static void ovl_dump_ext_layer_info(int layer, unsigned long layer_offset) { unsigned long layer_addr_offset; enum UNIFIED_COLOR_FMT fmt; layer_addr_offset = layer_offset - layer * OVL_LAYER_OFFSET + layer * 4; fmt = display_fmt_reg_to_unified_fmt(DISP_REG_GET_FIELD(L_CON_FLD_CFMT, DISP_REG_OVL_EL0_CON + layer_offset), DISP_REG_GET_FIELD(L_CON_FLD_BTSW, DISP_REG_OVL_EL0_CON + layer_offset), DISP_REG_GET_FIELD(L_CON_FLD_RGB_SWAP, DISP_REG_OVL_EL0_CON + layer_offset)); DDPDUMP("ext layer%d: w=%d,h=%d,off(x=%d,y=%d),pitch=%d,addr=0x%x,fmt=%s,source=%s,aen=%d,alpha=%d\n", layer, DISP_REG_GET(layer_offset + DISP_REG_OVL_EL0_SRC_SIZE) & 0xfff, (DISP_REG_GET(layer_offset + DISP_REG_OVL_EL0_SRC_SIZE) >> 16) & 0xfff, DISP_REG_GET(layer_offset + DISP_REG_OVL_EL0_OFFSET) & 0xfff, (DISP_REG_GET(layer_offset + DISP_REG_OVL_EL0_OFFSET) >> 16) & 0xfff, DISP_REG_GET(layer_offset + DISP_REG_OVL_EL0_PITCH) & 0xffff, DISP_REG_GET(layer_addr_offset + DISP_REG_OVL_EL0_ADDR), unified_color_fmt_name(fmt), (DISP_REG_GET_FIELD( L_CON_FLD_LSRC, DISP_REG_OVL_EL0_CON + layer_offset) == 0) ? "memory" : "constant_color", DISP_REG_GET_FIELD(L_CON_FLD_AEN, DISP_REG_OVL_EL0_CON + layer_offset), DISP_REG_GET_FIELD(L_CON_FLD_APHA, DISP_REG_OVL_EL0_CON + layer_offset)); } void ovl_dump_analysis(enum DISP_MODULE_ENUM module) { int i = 0; unsigned long layer_offset = 0; unsigned long rdma_offset = 0; unsigned long offset = ovl_base_addr(module); unsigned int src_con = DISP_REG_GET(DISP_REG_OVL_SRC_CON + offset); unsigned int ext_con = DISP_REG_GET(DISP_REG_OVL_DATAPATH_EXT_CON + offset); DDPDUMP("== DISP %s ANALYSIS ==\n", ddp_get_module_name(module)); DDPDUMP("ovl_en=%d,layer_enable(%d,%d,%d,%d),bg(w=%d, h=%d)\n", DISP_REG_GET(DISP_REG_OVL_EN + offset) & 0x1, src_con & 0x1, (src_con >> 1) & 0x1, (src_con >> 2) & 0x1, (src_con >> 3) & 0x1, DISP_REG_GET(DISP_REG_OVL_ROI_SIZE + offset) & 0xfff, (DISP_REG_GET(DISP_REG_OVL_ROI_SIZE + offset) >> 16) & 0xfff); DDPDUMP("ext layer: layer_enable(%d,%d,%d), attach_layer(%d,%d,%d)\n", ext_con & 0x1, (ext_con >> 1) & 0x1, (ext_con >> 2) & 0x1, (ext_con >> 16) & 0xf, (ext_con >> 20) & 0xf, (ext_con >> 24) & 0xf); DDPDUMP("cur_pos(x=%d,y=%d),layer_hit(%d,%d,%d,%d),bg_mode=%s,sta=0x%x\n", DISP_REG_GET_FIELD(ADDCON_DBG_FLD_ROI_X, DISP_REG_OVL_ADDCON_DBG + offset), DISP_REG_GET_FIELD(ADDCON_DBG_FLD_ROI_Y, DISP_REG_OVL_ADDCON_DBG + offset), DISP_REG_GET_FIELD(ADDCON_DBG_FLD_L0_WIN_HIT, DISP_REG_OVL_ADDCON_DBG + offset), DISP_REG_GET_FIELD(ADDCON_DBG_FLD_L1_WIN_HIT, DISP_REG_OVL_ADDCON_DBG + offset), DISP_REG_GET_FIELD(ADDCON_DBG_FLD_L2_WIN_HIT, DISP_REG_OVL_ADDCON_DBG + offset), DISP_REG_GET_FIELD(ADDCON_DBG_FLD_L3_WIN_HIT, DISP_REG_OVL_ADDCON_DBG + offset), DISP_REG_GET_FIELD(DATAPATH_CON_FLD_BGCLR_IN_SEL, DISP_REG_OVL_DATAPATH_CON + offset) ? "directlink" : "const", DISP_REG_GET(DISP_REG_OVL_STA + offset)); for (i = 0; i < 4; i++) { unsigned int rdma_ctrl; layer_offset = i * OVL_LAYER_OFFSET + offset; rdma_offset = i * OVL_RDMA_DEBUG_OFFSET + offset; if (src_con & (0x1 << i)) ovl_dump_layer_info(i, layer_offset); else DDPDUMP("layer%d: disabled\n", i); rdma_ctrl = DISP_REG_GET(layer_offset + DISP_REG_OVL_RDMA0_CTRL); DDPDUMP("ovl rdma%d status:(en=%d, fifo_used %d, GMC=0x%x)\n", i, REG_FLD_VAL_GET(RDMA0_CTRL_FLD_RDMA_EN, rdma_ctrl), REG_FLD_VAL_GET(RDMA0_CTRL_FLD_RMDA_FIFO_USED_SZ, rdma_ctrl), DISP_REG_GET(layer_offset + DISP_REG_OVL_RDMA0_MEM_GMC_SETTING)); ovl_print_ovl_rdma_status( DISP_REG_GET(DISP_REG_OVL_RDMA0_DBG + rdma_offset)); } /* ext layer detail info */ for (i = 0; i < 3; i++) { layer_offset = i * OVL_LAYER_OFFSET + offset; rdma_offset = i * OVL_RDMA_DEBUG_OFFSET + offset; if (ext_con & (0x1 << i)) ovl_dump_ext_layer_info(i, layer_offset); else DDPDUMP("ext layer%d: disabled\n", i); } ovl_printf_status(DISP_REG_GET(DISP_REG_OVL_FLOW_CTRL_DBG + offset)); } int ovl_dump(enum DISP_MODULE_ENUM module, int level) { ovl_dump_analysis(module); disp_ovl_dump_reg(module); return 0; } static int ovl_golden_setting(enum DISP_MODULE_ENUM module, enum dst_module_type dst_mod_type, void *cmdq) { unsigned long ovl_base = ovl_base_addr(module); unsigned int regval; int i, layer_num; int is_large_resolution = 0; unsigned int layer_greq_num; unsigned int dst_w, dst_h; layer_num = ovl_layer_num(module); dst_w = primary_display_get_width(); dst_h = primary_display_get_height(); if (dst_w > 1260 && dst_h > 2240) { /* WQHD */ is_large_resolution = 1; } else { /* FHD */ is_large_resolution = 0; } /* DISP_REG_OVL_RDMA0_MEM_GMC_SETTING */ regval = REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC_ULTRA_THRESHOLD, 0x3ff); if (dst_mod_type == DST_MOD_REAL_TIME) regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC_PRE_ULTRA_THRESHOLD, 0x3ff); else regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC_PRE_ULTRA_THRESHOLD, 0xe0); for (i = 0; i < layer_num; i++) { unsigned long layer_offset = i * OVL_LAYER_OFFSET + ovl_base; DISP_REG_SET(cmdq, layer_offset + DISP_REG_OVL_RDMA0_MEM_GMC_SETTING, regval); } /* DISP_REG_OVL_RDMA0_FIFO_CTRL */ regval = REG_FLD_VAL(FLD_OVL_RDMA_FIFO_SIZE, 128); for (i = 0; i < layer_num; i++) { unsigned long layer_offset = i * OVL_LAYER_OFFSET + ovl_base; DISP_REG_SET(cmdq, layer_offset + DISP_REG_OVL_RDMA0_FIFO_CTRL, regval); } /* DISP_REG_OVL_RDMA0_MEM_GMC_S2 */ regval = 0; if (dst_mod_type == DST_MOD_REAL_TIME) { regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES, 95); regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES_URG, 47); } else { /* decouple */ regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES, 47); regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES_URG, 47); } regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC2_REQ_THRES_PREULTRA, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC2_REQ_THRES_ULTRA, 1); regval |= REG_FLD_VAL(FLD_OVL_RDMA_MEM_GMC2_FORCE_REQ_THRES, 0); for (i = 0; i < layer_num; i++) DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_RDMA0_MEM_GMC_S2 + i * 4, regval); /* DISP_REG_OVL_RDMA_GREQ_NUM */ layer_greq_num = 5; regval = REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER0_GREQ_NUM, layer_greq_num); if (layer_num > 1) regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER1_GREQ_NUM, layer_greq_num); if (layer_num > 2) regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER2_GREQ_NUM, layer_greq_num); if (layer_num > 3) regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER3_GREQ_NUM, layer_greq_num); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_OSTD_GREQ_NUM, 0xff); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_GREQ_DIS_CNT, 1); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_STOP_EN, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_GRP_END_STOP, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_GRP_BRK_STOP, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_IOBUF_FLUSH_PREULTRA, 1); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_IOBUF_FLUSH_ULTRA, 0); DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_RDMA_GREQ_NUM, regval); /* DISP_REG_OVL_RDMA_GREQ_URG_NUM */ regval = REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER0_GREQ_URG_NUM, layer_greq_num); if (layer_num > 0) regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER1_GREQ_URG_NUM, layer_greq_num); if (layer_num > 1) regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER2_GREQ_URG_NUM, layer_greq_num); if (layer_num > 2) regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_LAYER3_GREQ_URG_NUM, layer_greq_num); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_ARG_GREQ_URG_TH, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_GREQ_ARG_URG_BIAS, 0); regval |= REG_FLD_VAL(GREQ_NUM_SHT_VAL, 0); regval |= REG_FLD_VAL(GREQ_NUM_SHT, 0); DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_RDMA_GREQ_URG_NUM, regval); /* DISP_REG_OVL_RDMA_ULTRA_SRC */ regval = REG_FLD_VAL(FLD_OVL_RDMA_PREULTRA_BUF_SRC, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_PREULTRA_SMI_SRC, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_PREULTRA_ROI_END_SRC, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_PREULTRA_RDMA_SRC, 1); regval |= REG_FLD_VAL(FLD_OVL_RDMA_ULTRA_BUF_SRC, 0); regval |= REG_FLD_VAL(FLD_OVL_RDMA_ULTRA_SMI_SRC, 0); if (dst_mod_type == DST_MOD_REAL_TIME) regval |= REG_FLD_VAL(FLD_OVL_RDMA_ULTRA_ROI_END_SRC, 0); else regval |= REG_FLD_VAL(FLD_OVL_RDMA_ULTRA_ROI_END_SRC, 2); regval |= REG_FLD_VAL(FLD_OVL_RDMA_ULTRA_RDMA_SRC, 2); DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_RDMA_ULTRA_SRC, regval); /* DISP_REG_OVL_RDMAn_BUF_LOW */ regval = REG_FLD_VAL(FLD_OVL_RDMA_BUF_LOW_ULTRA_TH, 0); if (dst_mod_type == DST_MOD_REAL_TIME) regval |= REG_FLD_VAL(FLD_OVL_RDMA_BUF_LOW_PREULTRA_TH, 0); else regval |= REG_FLD_VAL(FLD_OVL_RDMA_BUF_LOW_PREULTRA_TH, 0x10); for (i = 0; i < layer_num; i++) DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_RDMAn_BUF_LOW(i), regval); /* DISP_REG_OVL_RDMAn_BUF_HIGH */ regval = REG_FLD_VAL(FLD_OVL_RDMA_BUF_HIGH_PREULTRA_DIS, 1); if (dst_mod_type == DST_MOD_REAL_TIME) regval |= REG_FLD_VAL(FLD_OVL_RDMA_BUF_HIGH_PREULTRA_TH, 0); else regval |= REG_FLD_VAL(FLD_OVL_RDMA_BUF_HIGH_PREULTRA_TH, 0x60); for (i = 0; i < layer_num; i++) DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_RDMAn_BUF_HIGH(i), regval); /* DISP_REG_OVL_FUNC_DCM0 */ DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_FUNC_DCM0, 0x0); /* DISP_REG_OVL_FUNC_DCM1 */ DISP_REG_SET(cmdq, ovl_base + DISP_REG_OVL_FUNC_DCM1, 0x0); /* DISP_REG_OVL_DATAPATH_CON */ /* GCLAST_EN is set @ ovl_start() */ return 0; } int ovl_partial_update(enum DISP_MODULE_ENUM module, unsigned int bg_w, unsigned int bg_h, void *handle) { unsigned long ovl_base = ovl_base_addr(module); if ((bg_w > OVL_MAX_WIDTH) || (bg_h > OVL_MAX_HEIGHT)) { DDPERR("ovl_roi,exceed OVL max size, w=%d, h=%d\n", bg_w, bg_h); ASSERT(0); } DDPDBG("ovl%d partial update\n", module); DISP_REG_SET(handle, ovl_base + DISP_REG_OVL_ROI_SIZE, bg_h << 16 | bg_w); return 0; } static int ovl_ioctl(enum DISP_MODULE_ENUM module, void *handle, enum DDP_IOCTL_NAME ioctl_cmd, void *params) { int ret = 0; if (ioctl_cmd == DDP_OVL_GOLDEN_SETTING) { struct ddp_io_golden_setting_arg *gset_arg = params; ovl_golden_setting(module, gset_arg->dst_mod_type, handle); } else if (ioctl_cmd == DDP_PARTIAL_UPDATE) { struct disp_rect *roi = (struct disp_rect *)params; ovl_partial_update(module, roi->width, roi->height, handle); } else { ret = -1; } return ret; } /* ---------------- driver ---------------- */ struct DDP_MODULE_DRIVER ddp_driver_ovl = { .init = ovl_init, .deinit = ovl_deinit, .config = ovl_config_l, .start = ovl_start, .trigger = NULL, .stop = ovl_stop, .reset = ovl_reset, .power_on = ovl_clock_on, .power_off = ovl_clock_off, .is_idle = NULL, .is_busy = NULL, .dump_info = ovl_dump, .bypass = NULL, .build_cmdq = NULL, .set_lcm_utils = NULL, .ioctl = ovl_ioctl, .connect = ovl_connect, .switch_to_nonsec = ovl_switch_to_nonsec, };