/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #include "ddp_reg.h" #include "ddp_mutex.h" #include "ddp_log.h" #include "ddp_info.h" #include "disp_helper.h" static struct module_map_t module_mutex_map[DISP_MODULE_NUM] = { {DISP_MODULE_OVL0, 0, 0}, {DISP_MODULE_OVL0_2L, 1, 0}, {DISP_MODULE_OVL0_2L_VIRTUAL0, -1, 0}, {DISP_MODULE_OVL0_VIRTUAL0, -1, 0}, {DISP_MODULE_RSZ0, 10, 0}, {DISP_MODULE_OVL1, 12, 0}, {DISP_MODULE_OVL1_2L, 13, 0}, {DISP_MODULE_OVL1_2L_VIRTUAL0, -1, 0}, {DISP_MODULE_OVL1_VIRTUAL0, -1, 0}, {DISP_MODULE_RSZ1, 22, 0}, {DISP_MODULE_RDMA0, 2, 0}, {DISP_MODULE_RDMA0_VIRTUAL0, -1, 0}, {DISP_MODULE_WDMA0, 3, 0}, {DISP_MODULE_COLOR0, 4, 0}, {DISP_MODULE_CCORR0, 5, 0}, {DISP_MODULE_RDMA1, 14, 0}, {DISP_MODULE_RDMA1_VIRTUAL0, -1, 0}, {DISP_MODULE_WDMA1, 15, 0}, {DISP_MODULE_COLOR1, 16, 0}, {DISP_MODULE_CCORR1, 17, 0}, {DISP_MODULE_AAL0, 6, 0}, {DISP_MODULE_MDP_AAL4, 0, 1}, {DISP_MODULE_GAMMA0, 7, 0}, {DISP_MODULE_POSTMASK0, 25, 0}, {DISP_MODULE_DITHER0, 8, 0}, {DISP_MODULE_AAL1, 18, 0}, {DISP_MODULE_MDP_AAL5, 1, 1}, {DISP_MODULE_GAMMA1, 19, 0}, {DISP_MODULE_POSTMASK1, 26, 0}, {DISP_MODULE_DITHER1, 20, 0}, {DISP_MODULE_SPLIT0, -1, 0}, {DISP_MODULE_DSI0, 9, 0}, {DISP_MODULE_DSI1, 21, 0}, {DISP_MODULE_DSIDUAL, -1, 0}, {DISP_MODULE_PWM0, 11, 0}, {DISP_MODULE_CONFIG, -1, 0}, {DISP_MODULE_MUTEX, -1, 0}, {DISP_MODULE_SMI_COMMON, -1, 0}, {DISP_MODULE_SMI_LARB0, -1, 0}, {DISP_MODULE_SMI_LARB1, -1, 0}, {DISP_MODULE_MIPI0, -1, 0}, {DISP_MODULE_MIPI1, -1, 0}, {DISP_MODULE_DPI, -1, 0}, {DISP_MODULE_OVL2_2L, 23, 0}, {DISP_MODULE_OVL3_2L, 24, 0}, {DISP_MODULE_RDMA4, 10, 1}, {DISP_MODULE_RDMA5, 11, 1}, {DISP_MODULE_MDP_RDMA4, 2, 1}, {DISP_MODULE_MDP_RDMA5, 3, 1}, {DISP_MODULE_MDP_RSZ4, 6, 1}, {DISP_MODULE_MDP_RSZ5, 7, 1}, {DISP_MODULE_MERGE0, 27, 0}, {DISP_MODULE_MERGE1, 28, 0}, {DISP_MODULE_DP_INTF, 31, 0}, {DISP_MODULE_DSC, 29, 0}, {DISP_MODULE_UNKNOWN, -1, 0}, }; static int ddp_get_mutex_src(enum DISP_MODULE_ENUM dest_module, enum DDP_MODE ddp_mode, unsigned int *SOF_src, unsigned int *EOF_src) { unsigned int src_from_dst_module = 0; if (dest_module == DISP_MODULE_WDMA0) { if (ddp_mode == DDP_VIDEO_MODE) DISP_LOG_W("%s: dst_mode=%s, but is video mode !!\n", __func__, ddp_get_module_name(dest_module)); *SOF_src = SOF_VAL_MUTEX0_SOF_SINGLE_MODE; *EOF_src = SOF_VAL_MUTEX0_EOF_DISABLE; return 0; } if (dest_module == DISP_MODULE_DSI0 || dest_module == DISP_MODULE_DSIDUAL) { src_from_dst_module = SOF_VAL_MUTEX0_SOF_FROM_DSI0; } else if (dest_module == DISP_MODULE_DPI) { src_from_dst_module = SOF_VAL_MUTEX0_SOF_FROM_DPI; } else { DDPERR("%s, invalid param dst module = %s(%d), dsi mode %s\n", __func__, ddp_get_module_name(dest_module), dest_module, ddp_get_mode_name(ddp_mode)); WARN_ON(1); } if (ddp_mode == DDP_CMD_MODE) { *SOF_src = SOF_VAL_MUTEX0_SOF_SINGLE_MODE; if (disp_helper_get_option(DISP_OPT_MUTEX_EOF_EN_FOR_CMD_MODE)) *EOF_src = src_from_dst_module; else *EOF_src = SOF_VAL_MUTEX0_EOF_DISABLE; } else { *SOF_src = *EOF_src = src_from_dst_module; } return 0; } static int ddp_mutex_add_module(int mutex_id, enum DISP_MODULE_ENUM module, void *handle) { int value = 0; if (!is_ddp_module(module)) return value; if (module_mutex_map[module].bit != -1) { DDPDBG("module %s added to mutex %d\n", ddp_get_module_name(module), mutex_id); value = (1 << module_mutex_map[module].bit); if (module_mutex_map[module].mod_num == 0) DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_MOD0(mutex_id), value, value); else if (module_mutex_map[module].mod_num == 1) DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_MOD1(mutex_id), value, value); } else if (module == DISP_MODULE_DSIDUAL) { DDPDBG("module %s added to mutex %d\n", ddp_get_module_name(module), mutex_id); value = (1 << module_mutex_map[DISP_MODULE_DSI0].bit); value |= (1 << module_mutex_map[DISP_MODULE_DSI1].bit); if (module_mutex_map[module].mod_num == 0) DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_MOD0(mutex_id), value, value); } return value; } int ddp_mutex_remove_module(int mutex_id, enum DISP_MODULE_ENUM module, void *handle) { int ret = 0; int value = 0; if (!is_ddp_module(module)) return ret; if (module_mutex_map[module].bit != -1) { DDPDBG("module %s added to mutex %d\n", ddp_get_module_name(module), mutex_id); value = (1 << module_mutex_map[module].bit); if (module_mutex_map[module].mod_num == 0) { DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_MOD0(mutex_id), 0, value); ret = 1; } } else if (module == DISP_MODULE_DSIDUAL) { value = (1 << module_mutex_map[DISP_MODULE_DSI0].bit); value |= (1 << module_mutex_map[DISP_MODULE_DSI1].bit); if (module_mutex_map[module].mod_num == 0) { DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_MOD0(mutex_id), 0, value); ret = 1; } } return ret; } /* id: mutex ID, 0~3 */ static int ddp_mutex_set_l(int mutex_id, int *module_list, enum DDP_MODE ddp_mode, void *handle) { int i = 0; unsigned int value = 0; unsigned int sof_val; unsigned int sof_src = SOF_VAL_MUTEX0_SOF_SINGLE_MODE; unsigned int eof_src = SOF_VAL_MUTEX0_EOF_DISABLE; int module_num = ddp_get_module_num_l(module_list); if (mutex_id < DISP_MUTEX_DDP_FIRST || mutex_id > DISP_MUTEX_DDP_LAST) { DDPERR("exceed mutex max (0 ~ %d)\n", DISP_MUTEX_DDP_LAST); return -1; } /* important */ DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_MOD0(mutex_id), 0); for (i = 0; i < module_num; i++) value |= ddp_mutex_add_module(mutex_id, module_list[i], handle); ddp_get_mutex_src(module_list[module_num - 1], ddp_mode, &sof_src, &eof_src); sof_val = REG_FLD_VAL(SOF_FLD_MUTEX0_SOF, sof_src); sof_val |= REG_FLD_VAL(SOF_FLD_MUTEX0_EOF, eof_src); DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_SOF(mutex_id), sof_val); /* use default timing */ DDPDBG("mutex %d value=0x%x, sof=%s, eof=%s\n", mutex_id, value, ddp_get_mutex_sof_name(sof_src), ddp_get_mutex_sof_name(eof_src)); return 0; } static void ddp_check_mutex_l(int mutex_id, int *module_list, enum DDP_MODE ddp_mode) { int i = 0; uint32_t real_value0 = 0; uint32_t expect_value0 = 0; unsigned int real_sof, real_eof, val; unsigned int expect_sof = SOF_VAL_MUTEX0_SOF_SINGLE_MODE; unsigned int expect_eof = SOF_VAL_MUTEX0_EOF_DISABLE; int module_num = ddp_get_module_num_l(module_list); if (mutex_id < DISP_MUTEX_DDP_FIRST || mutex_id > DISP_MUTEX_DDP_LAST) { DDPDUMP("error:check mutex fail:exceed mutex max (0 ~ %d)\n", DISP_MUTEX_DDP_LAST); return; } /* check mod */ real_value0 = DISP_REG_GET(DISP_REG_CONFIG_MUTEX_MOD0(mutex_id)); for (i = 0; i < module_num; i++) { if (module_mutex_map[module_list[i]].bit != -1) { if (module_mutex_map[module_list[i]].mod_num != 0) continue; expect_value0 |= (1 << module_mutex_map[module_list[i]].bit); } else if (module_list[i] == DISP_MODULE_DSIDUAL) { if (module_mutex_map[module_list[i]].mod_num != 0) continue; expect_value0 |= (1 << module_mutex_map[DISP_MODULE_DSI0].bit); expect_value0 |= (1 << module_mutex_map[DISP_MODULE_DSI1].bit); } } if (expect_value0 != real_value0) DDPDUMP("error:mutex %d error: expect0 0x%x, real0 0x%x\n", mutex_id, expect_value0, real_value0); /* check sof */ val = DISP_REG_GET(DISP_REG_CONFIG_MUTEX_SOF(mutex_id)); real_sof = REG_FLD_VAL_GET(SOF_FLD_MUTEX0_SOF, val); real_eof = REG_FLD_VAL_GET(SOF_FLD_MUTEX0_EOF, val); ddp_get_mutex_src(module_list[module_num - 1], ddp_mode, &expect_sof, &expect_eof); if (expect_sof != real_sof) DDPDUMP("error:mutex %d sof error: expect %s, real %s\n", mutex_id, ddp_get_mutex_sof_name(expect_sof), ddp_get_mutex_sof_name(real_sof)); if (expect_eof != real_eof) DDPDUMP("error:mutex %d eof error: expect %s, real %s\n", mutex_id, ddp_get_mutex_sof_name(expect_eof), ddp_get_mutex_sof_name(real_eof)); } void ddp_mutex_interrupt_enable(int mutex_id, void *handle) { DDPDBG("mutex %d interrupt enable\n", mutex_id); DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN, 0x1 << mutex_id, 0x1 << mutex_id); /* sof irq */ DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN, 0x1 << (mutex_id + DISP_MUTEX_TOTAL), 0x1 << (mutex_id + DISP_MUTEX_TOTAL)); /* stream done irq */ DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN_1, 0x1 << mutex_id, 0x1 << mutex_id); /* regs update irq */ DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN_1, 0x1 << (mutex_id + DISP_MUTEX_TOTAL), 0x1 << (mutex_id + DISP_MUTEX_TOTAL)); /* update timeout irq */ } void ddp_mutex_interrupt_disable(int mutex_id, void *handle) { DDPDBG("mutex %d interrupt disenable\n", mutex_id); DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN, 0, 0x1 << mutex_id); /* sof irq */ DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN, 0, 0x1 << (mutex_id + DISP_MUTEX_TOTAL)); DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN_1, 0, 0x1 << mutex_id); /* regs update irq */ DISP_REG_MASK(handle, DISP_REG_CONFIG_MUTEX_INTEN_1, 0, 0x1 << (mutex_id + DISP_MUTEX_TOTAL)); } void ddp_mutex_reset(int mutex_id, void *handle) { DDPDBG("mutex %d reset\n", mutex_id); DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_RST(mutex_id), 1); DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_RST(mutex_id), 0); } int ddp_is_moudule_in_mutex(int mutex_id, enum DISP_MODULE_ENUM module) { int ret = 0; uint32_t real_value = 0; if (mutex_id < DISP_MUTEX_DDP_FIRST || mutex_id > DISP_MUTEX_DDP_LAST) { DDPDUMP("err:check_module_in_mute fail:exceed max (0~%d)\n", DISP_MUTEX_DDP_LAST); return ret; } if (module_mutex_map[module].mod_num == 0) real_value = DISP_REG_GET(DISP_REG_CONFIG_MUTEX_MOD0(mutex_id)); if (module == DISP_MODULE_DSIDUAL) { uint32_t dsi0_bit, dsi1_bit; dsi0_bit = real_value >> module_mutex_map[DISP_MODULE_DSI0].bit; dsi1_bit = real_value >> module_mutex_map[DISP_MODULE_DSI1].bit; if ((dsi0_bit & 0x01) == 1 && (dsi1_bit & 0x01) == 1) ret = 1; } else { if (1 == ((real_value >> module_mutex_map[module].bit) & 0x01)) ret = 1; } return ret; } void ddp_mutex_clear(int mutex_id, void *handle) { DDPDBG("mutex %d clear\n", mutex_id); /*reset mutex */ ddp_mutex_reset(mutex_id, handle); /* disable mutex */ DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_MOD0(mutex_id), 0); DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_SOF(mutex_id), 0); } int ddp_mutex_set_sof_wait(int mutex_id, struct cmdqRecStruct *handle, int wait) { if (mutex_id < DISP_MUTEX_DDP_FIRST || mutex_id > DISP_MUTEX_DDP_LAST) { DDPERR("exceed mutex max (0 ~ %d)\n", DISP_MUTEX_DDP_LAST); return -1; } DISP_REG_SET_FIELD(handle, SOF_FLD_MUTEX0_SOF_WAIT, DISP_REG_CONFIG_MUTEX_SOF(mutex_id), wait); return 0; } int ddp_mutex_enable(int mutex_id, enum DDP_SCENARIO_ENUM scenario, enum DDP_MODE mode, void *handle) { DDPDBG("mutex %d enable\n", mutex_id); /* disable mutex dcm */ /* use default value */ /* DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_CFG, 0); */ DISP_REG_SET(handle, DISP_REG_CONFIG_MUTEX_EN(mutex_id), 1); return 0; } int ddp_mutex_set(int mutex_id, enum DDP_SCENARIO_ENUM scenario, enum DDP_MODE mode, void *handle) { if (scenario < DDP_SCENARIO_MAX) return ddp_mutex_set_l(mutex_id, module_list_scenario[scenario], mode, handle); DDPERR("Invalid scenario %d when setting mutex\n", scenario); return -1; } void ddp_check_mutex(int mutex_id, enum DDP_SCENARIO_ENUM scenario, enum DDP_MODE mode) { DDPDBG("check mutex %d on scenario %s\n", mutex_id, ddp_get_scenario_name(scenario)); ddp_check_mutex_l(mutex_id, module_list_scenario[scenario], mode); } char *ddp_get_mutex_sof_name(unsigned int regval) { switch (regval) { case SOF_VAL_MUTEX0_SOF_SINGLE_MODE: return "single"; case SOF_VAL_MUTEX0_SOF_FROM_DSI0: return "dsi0"; case SOF_VAL_MUTEX0_SOF_FROM_DPI: return "dpi"; default: DDPDUMP("%s, unknown reg=%d\n", __func__, regval); return "unknown"; } }