/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #include "ddp_hal.h" #include "ddp_reg.h" #include "disp_pm_qos.h" #include #include "helio-dvfsrc-opp-mt6785.h" #include "layering_rule.h" #include "mmprofile.h" #include "mmprofile_function.h" #include "disp_drv_log.h" #include "disp_drv_platform.h" #ifdef MTK_FB_MMDVFS_SUPPORT #include "mmdvfs_pmqos.h" #include "mt6785/smi_port.h" #endif #include "cmdq_def.h" #include "cmdq_record.h" #include "cmdq_reg.h" #include "cmdq_core.h" #define OCCUPIED_BW_RATIO 1330 #ifdef MTK_FB_MMDVFS_SUPPORT static struct plist_head bw_request_list; /* all module list */ static struct mm_qos_request ovl0_request; static struct mm_qos_request ovl0_fbdc_request; static struct mm_qos_request ovl0_2l_request; static struct mm_qos_request ovl0_2l_fbdc_request; static struct mm_qos_request rdma0_request; static struct mm_qos_request wdma0_request; static struct mtk_pm_qos_request ddr_opp_request; static struct mtk_pm_qos_request mm_freq_request; #ifdef CONFIG_MTK_MT6382_BDG static struct mtk_pm_qos_request vcore_request; #endif static struct plist_head hrt_request_list; static struct mm_qos_request ovl0_hrt_request; static struct mm_qos_request ovl0_2l_hrt_request; static struct mm_qos_request rdma0_hrt_request; static struct mm_qos_request wdma0_hrt_request; static struct mm_qos_request hrt_bw_request; #endif cmdqBackupSlotHandle dispsys_slot; static unsigned int has_hrt_bw; #ifdef MTK_FB_MMDVFS_SUPPORT static enum ddr_opp __remap_to_opp(enum HRT_LEVEL hrt) { enum ddr_opp opp = MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE; switch (hrt) { case HRT_LEVEL_LEVEL0: opp = DDR_OPP_4; /* LP4-1200 */ break; case HRT_LEVEL_LEVEL1: opp = DDR_OPP_2; /* LP4-2100 */ break; case HRT_LEVEL_LEVEL2: opp = DDR_OPP_1; /* LP4-2800 */ break; case HRT_LEVEL_LEVEL3: opp = DDR_OPP_0; /* LP4-3200 */ break; case HRT_LEVEL_DEFAULT: opp = MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE; break; default: DISP_PR_ERR("%s:unknown hrt level:%d\n", __func__, hrt); break; } return opp; } static int __init_cmdq_slots(cmdqBackupSlotHandle *pSlot, int count, int init_val) { int i; cmdqBackupAllocateSlot(pSlot, count); for (i = 0; i < count; i++) cmdqBackupWriteSlot(*pSlot, i, init_val); return 0; } #endif static int __get_cmdq_slots(cmdqBackupSlotHandle Slot, unsigned int slot_index, unsigned int *value) { int ret; ret = cmdqBackupReadSlot(Slot, slot_index, value); /* cmdq get slot fail */ if (ret) DISP_PR_ERR("DISP CMDQ get slot failed:%d\n", ret); return ret; } void disp_pm_qos_init(void) { #ifdef MTK_FB_MMDVFS_SUPPORT unsigned long long bandwidth; /* initialize display slot */ __init_cmdq_slots(&(dispsys_slot), DISP_SLOT_NUM, 0); /* Initialize owner list */ plist_head_init(&bw_request_list); mm_qos_add_request(&bw_request_list, &ovl0_request, SMI_DISP_OVL0); mm_qos_add_request(&bw_request_list, &ovl0_fbdc_request, SMI_DISP_OVL0); mm_qos_add_request(&bw_request_list, &ovl0_2l_request, SMI_DISP_OVL0_2L); mm_qos_add_request(&bw_request_list, &ovl0_2l_fbdc_request, SMI_DISP_OVL0_2L); mm_qos_add_request(&bw_request_list, &rdma0_request, SMI_DISP_RDMA0); mm_qos_add_request(&bw_request_list, &wdma0_request, SMI_DISP_WDMA0); mtk_pm_qos_add_request(&ddr_opp_request, MTK_PM_QOS_DDR_OPP, MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE); mtk_pm_qos_add_request(&mm_freq_request, PM_QOS_DISP_FREQ, PM_QOS_MM_FREQ_DEFAULT_VALUE); #ifdef CONFIG_MTK_MT6382_BDG mtk_pm_qos_add_request(&vcore_request, MTK_PM_QOS_VCORE_OPP, //add for mipi clk 1.7GHz // VCORE_OPP_1); #endif plist_head_init(&hrt_request_list); mm_qos_add_request(&hrt_request_list, &ovl0_hrt_request, SMI_DISP_OVL0); mm_qos_add_request(&hrt_request_list, &ovl0_2l_hrt_request, SMI_DISP_OVL0_2L); mm_qos_add_request(&hrt_request_list, &rdma0_hrt_request, SMI_DISP_RDMA0); mm_qos_add_request(&hrt_request_list, &wdma0_hrt_request, SMI_DISP_WDMA0); mm_qos_add_request(&hrt_request_list, &hrt_bw_request, get_virtual_port(VIRTUAL_DISP)); disp_pm_qos_set_default_bw(&bandwidth); disp_pm_qos_set_default_hrt(); #endif } void disp_pm_qos_deinit(void) { #ifdef MTK_FB_MMDVFS_SUPPORT mm_qos_remove_all_request(&bw_request_list); mtk_pm_qos_remove_request(&ddr_opp_request); mtk_pm_qos_remove_request(&mm_freq_request); #ifdef CONFIG_MTK_MT6382_BDG mtk_pm_qos_remove_request(&vcore_request); #endif #endif } int disp_pm_qos_request_dvfs(enum HRT_LEVEL hrt) { #ifdef MTK_FB_MMDVFS_SUPPORT enum ddr_opp opp = MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE; opp = __remap_to_opp(hrt); mmprofile_log_ex(ddp_mmp_get_events()->dvfs, MMPROFILE_FLAG_START, hrt, opp); mtk_pm_qos_update_request(&ddr_opp_request, opp); mmprofile_log_ex(ddp_mmp_get_events()->dvfs, MMPROFILE_FLAG_END, 0, 0); #endif return 0; } static int __set_hrt_bw(enum DISP_MODULE_ENUM module, unsigned int bandwidth) { #ifdef MTK_FB_MMDVFS_SUPPORT struct mm_qos_request *request; switch (module) { case DISP_MODULE_OVL0: request = &ovl0_hrt_request; break; case DISP_MODULE_OVL0_2L: request = &ovl0_2l_hrt_request; break; case DISP_MODULE_RDMA0: request = &rdma0_hrt_request; break; case DISP_MODULE_WDMA0: request = &wdma0_hrt_request; break; default: DISP_PR_ERR("unsupport module id %s(%d)\n", ddp_get_module_name(module), module); return -1; } mm_qos_set_hrt_request(request, bandwidth); #endif return 0; } static int __set_bw(enum DISP_MODULE_ENUM module, unsigned int bandwidth) { #ifdef MTK_FB_MMDVFS_SUPPORT struct mm_qos_request *request; switch (module) { case DISP_MODULE_OVL0: request = &ovl0_request; break; case DISP_MODULE_OVL0_2L: request = &ovl0_2l_request; break; case DISP_MODULE_RDMA0: request = &rdma0_request; break; case DISP_MODULE_WDMA0: request = &wdma0_request; break; default: DISP_PR_ERR("unsupport module id %s(%d)\n", ddp_get_module_name(module), module); return -1; } bandwidth = bandwidth * OCCUPIED_BW_RATIO / 1000; mm_qos_set_bw_request(request, bandwidth, BW_COMP_NONE); #endif mmprofile_log_ex(ddp_mmp_get_events()->primary_pm_qos, MMPROFILE_FLAG_PULSE, module, bandwidth); return 0; } static int __set_fbdc_bw(enum DISP_MODULE_ENUM module, unsigned int bandwidth) { #ifdef MTK_FB_MMDVFS_SUPPORT struct mm_qos_request *request; switch (module) { case DISP_MODULE_OVL0: request = &ovl0_fbdc_request; break; case DISP_MODULE_OVL0_2L: request = &ovl0_2l_fbdc_request; break; default: DISP_PR_ERR("unsupport module id %s(%d)\n", ddp_get_module_name(module), module); return -1; } bandwidth = bandwidth * OCCUPIED_BW_RATIO / 1000; mm_qos_set_bw_request(request, bandwidth, BW_COMP_DEFAULT); #endif mmprofile_log_ex(ddp_mmp_get_events()->primary_pm_qos, MMPROFILE_FLAG_PULSE, module, bandwidth); return 0; } int disp_pm_qos_update_bw(unsigned long long bandwidth) { mmprofile_log_ex(ddp_mmp_get_events()->primary_pm_qos, MMPROFILE_FLAG_START, !primary_display_is_decouple_mode(), bandwidth); #ifdef MTK_FB_MMDVFS_SUPPORT mm_qos_update_all_request(&bw_request_list); #endif mmprofile_log_ex(ddp_mmp_get_events()->primary_pm_qos, MMPROFILE_FLAG_END, !primary_display_is_decouple_mode(), bandwidth); return 0; } int disp_pm_qos_update_hrt(unsigned long long bandwidth) { mmprofile_log_ex(ddp_mmp_get_events()->primary_hrt_bw, MMPROFILE_FLAG_START, !primary_display_is_decouple_mode(), bandwidth); #ifdef MTK_FB_MMDVFS_SUPPORT mm_qos_update_all_request(&hrt_request_list); #endif mmprofile_log_ex(ddp_mmp_get_events()->primary_hrt_bw, MMPROFILE_FLAG_END, !primary_display_is_decouple_mode(), bandwidth); return 0; } unsigned int get_has_hrt_bw(void) { return has_hrt_bw; } int disp_pm_qos_update_mmclk(int mm_freq) { enum vcore_opp vcore_value = VCORE_OPP_0; #if 0 mmprofile_log_ex(ddp_mmp_get_events()->primary_pm_qos, MMPROFILE_FLAG_START, !primary_display_is_decouple_mode(), vcore_value); #endif #ifdef MTK_FB_MMDVFS_SUPPORT if (mm_freq < 559) vcore_value = VCORE_OPP_1; DISPMSG("%s, force set mmclk=%d, vcore=%s\n", __func__, mm_freq, vcore_value == VCORE_OPP_0 ? "0.825v" : "0.725v"); mtk_pm_qos_update_request(&mm_freq_request, mm_freq); #ifdef CONFIG_MTK_MT6382_BDG mtk_pm_qos_update_request(&vcore_request, vcore_value); #endif #endif #if 0 mmprofile_log_ex(ddp_mmp_get_events()->primary_pm_qos, MMPROFILE_FLAG_END, !primary_display_is_decouple_mode(), 0); #endif return 0; } int prim_disp_request_hrt_bw(int overlap_num, enum DDP_SCENARIO_ENUM scenario, const char *caller, unsigned int active_cfg) { unsigned long long bw_base; unsigned int tmp; unsigned int wdma_bw; /* overlap_num in PAN_DISP ioctl or Assert layer is 0 */ if (overlap_num == HRT_BW_BYPASS) return 0; else if (overlap_num == HRT_BW_UNREQ) { overlap_num = 0; has_hrt_bw = 0; } else has_hrt_bw = 1; bw_base = layering_get_frame_bw(active_cfg); bw_base /= 2; tmp = bw_base * overlap_num; wdma_bw = bw_base * 2; switch (scenario) { case DDP_SCENARIO_PRIMARY_DISP: __set_hrt_bw(DISP_MODULE_OVL0, tmp); __set_hrt_bw(DISP_MODULE_OVL0_2L, tmp); __set_hrt_bw(DISP_MODULE_WDMA0, 0); __set_hrt_bw(DISP_MODULE_RDMA0, 0); break; case DDP_SCENARIO_PRIMARY_RDMA0_COLOR0_DISP: __set_hrt_bw(DISP_MODULE_OVL0, 0); __set_hrt_bw(DISP_MODULE_OVL0_2L, 0); __set_hrt_bw(DISP_MODULE_WDMA0, 0); __set_hrt_bw(DISP_MODULE_RDMA0, tmp); break; case DDP_SCENARIO_PRIMARY_ALL: __set_hrt_bw(DISP_MODULE_OVL0, tmp); __set_hrt_bw(DISP_MODULE_OVL0_2L, tmp); __set_hrt_bw(DISP_MODULE_WDMA0, wdma_bw); __set_hrt_bw(DISP_MODULE_RDMA0, wdma_bw); break; default: DISPINFO("invalid HRT scenario %s\n", ddp_get_scenario_name(scenario)); } #ifdef MTK_FB_MMDVFS_SUPPORT mm_qos_set_hrt_request(&hrt_bw_request, tmp); DISPINFO("%s report HRT BW %u MB overlap %d, %llu/s, scen:%u\n", caller, tmp, overlap_num, bw_base, scenario); mmprofile_log_ex(ddp_mmp_get_events()->primary_hrt_bw, MMPROFILE_FLAG_PULSE, overlap_num, tmp); mm_qos_update_all_request(&hrt_request_list); #endif return 0; } int disp_pm_qos_set_default_bw(unsigned long long *bandwidth) { __set_bw(DISP_MODULE_OVL0, 0); __set_fbdc_bw(DISP_MODULE_OVL0, 0); __set_bw(DISP_MODULE_OVL0_2L, 0); __set_fbdc_bw(DISP_MODULE_OVL0_2L, 0); __set_bw(DISP_MODULE_WDMA0, 0); __set_bw(DISP_MODULE_RDMA0, 0); *bandwidth = 0; return 0; } int disp_pm_qos_set_default_hrt(void) { __set_hrt_bw(DISP_MODULE_OVL0, 0); __set_hrt_bw(DISP_MODULE_OVL0_2L, 0); __set_hrt_bw(DISP_MODULE_WDMA0, 0); __set_hrt_bw(DISP_MODULE_RDMA0, 0); #ifdef MTK_FB_MMDVFS_SUPPORT mm_qos_set_hrt_request(&hrt_bw_request, 0); #endif return 0; } int disp_pm_qos_set_ovl_bw(unsigned long long in_fps, unsigned long long out_fps, unsigned long long *bandwidth) { int ret = 0; unsigned int is_dc; unsigned int ovl0_bw, ovl0_2l_bw, rdma0_bw, wdma0_bw; unsigned int ovl0_fbdc_bw, ovl0_2l_fbdc_bw; unsigned int ovl0_lstf_bw, ovl0_2l_lstf_bw; DISPINFO("%s,fps:[in-%llu,out-%llu]\n", __func__, in_fps, out_fps); ret |= __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_IS_DC, &is_dc); ret |= __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_OVL0_BW, &ovl0_bw); ret |= __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_OVL0_FBDC_BW, &ovl0_fbdc_bw); ret |= __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_OVL0_2L_BW, &ovl0_2l_bw); ret |= __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_OVL0_2L_FBDC_BW, &ovl0_2l_fbdc_bw); ret |= __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_RDMA0_BW, &rdma0_bw); ret |= __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_WDMA0_BW, &wdma0_bw); /*read back ovl last frame bw*/ __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_OVL0_LASTF_BW, &ovl0_lstf_bw); __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_OVL0_2L_LASTF_BW, &ovl0_2l_lstf_bw); /*bw req is in unit of 16bytes, transfer to bytes*/ ovl0_lstf_bw = ovl0_lstf_bw << 4; ovl0_2l_lstf_bw = ovl0_2l_lstf_bw << 4; DISPDBG( "%s ovl0 last bw:%d, ovl0_2l last bw:%d", __func__, ovl0_lstf_bw, ovl0_2l_lstf_bw); /* cmdq get slot fail */ if (ret) { DISP_PR_ERR("DISP CMDQ get slot failed:%d\n", ret); disp_pm_qos_set_default_bw(bandwidth); } else { if (is_dc) *bandwidth = ((((unsigned long long)ovl0_bw + (unsigned long long)ovl0_fbdc_bw + (unsigned long long)ovl0_2l_bw + (unsigned long long)ovl0_2l_fbdc_bw + (unsigned long long)wdma0_bw) * in_fps) + ((unsigned long long)rdma0_bw * out_fps))* OCCUPIED_BW_RATIO; else *bandwidth = ((unsigned long long)ovl0_bw + (unsigned long long)ovl0_fbdc_bw + (unsigned long long)ovl0_2l_bw + (unsigned long long)ovl0_2l_fbdc_bw) * out_fps * OCCUPIED_BW_RATIO; do_div(*bandwidth, 1000 * 1000); /* Call __set_bw API to setup estimated data bw */ if (is_dc) { ovl0_bw = ovl0_bw * in_fps / 1000; ovl0_fbdc_bw = ovl0_fbdc_bw * in_fps / 1000; ovl0_2l_bw = ovl0_2l_bw * in_fps / 1000; ovl0_2l_fbdc_bw = ovl0_2l_fbdc_bw * in_fps / 1000; wdma0_bw = wdma0_bw * in_fps / 1000; rdma0_bw = rdma0_bw * out_fps / 1000; __set_bw(DISP_MODULE_OVL0, ovl0_bw); __set_fbdc_bw(DISP_MODULE_OVL0, ovl0_fbdc_bw); __set_bw(DISP_MODULE_OVL0_2L, ovl0_2l_bw); __set_fbdc_bw(DISP_MODULE_OVL0_2L, ovl0_2l_fbdc_bw); __set_bw(DISP_MODULE_WDMA0, wdma0_bw); __set_bw(DISP_MODULE_RDMA0, rdma0_bw); } else { ovl0_bw = ovl0_bw * out_fps / 1000; ovl0_fbdc_bw = ovl0_fbdc_bw * out_fps / 1000; ovl0_2l_bw = ovl0_2l_bw * out_fps / 1000; ovl0_2l_fbdc_bw = ovl0_2l_fbdc_bw * out_fps / 1000; wdma0_bw = 0; rdma0_bw = 0; __set_bw(DISP_MODULE_OVL0, ovl0_bw); __set_fbdc_bw(DISP_MODULE_OVL0, ovl0_fbdc_bw); __set_bw(DISP_MODULE_OVL0_2L, ovl0_2l_bw); __set_fbdc_bw(DISP_MODULE_OVL0_2L, ovl0_2l_fbdc_bw); __set_bw(DISP_MODULE_WDMA0, wdma0_bw); __set_bw(DISP_MODULE_RDMA0, rdma0_bw); } if (is_dc) { DISPDBG( "%s ovl0:(%d,%d), ovl0_2l:(%d,%d), wdma0:%d, rdma0:%d ", __func__, ovl0_bw, ovl0_fbdc_bw, ovl0_2l_bw, ovl0_2l_fbdc_bw, wdma0_bw, rdma0_bw); DISPDBG( "in_fps:%llu, out_fps:%llu, bw:%llu\n", in_fps, out_fps, *bandwidth); } else DISPDBG( "%s ovl0:(%d,%d), ovl0_2l:(%d,%d), out_fps:%llu, bw:%llu\n", __func__, ovl0_bw, ovl0_fbdc_bw, ovl0_2l_bw, ovl0_2l_fbdc_bw, out_fps, *bandwidth); } return ret; } int disp_pm_qos_set_rdma_bw(unsigned long long out_fps, unsigned long long *bandwidth) { int ret = 0; unsigned int rdma0_bw; unsigned int ovl0_bw, ovl0_2l_bw, wdma0_bw; unsigned int ovl0_fbdc_bw, ovl0_2l_fbdc_bw; ret = __get_cmdq_slots(DISPSYS_SLOT_BASE, DISP_SLOT_RDMA0_BW, &rdma0_bw); /* cmdq get slot fail */ if (ret) { DISP_PR_ERR("DISP CMDQ get slot failed:%d\n", ret); disp_pm_qos_set_default_bw(bandwidth); } else { *bandwidth = (unsigned long long)rdma0_bw * out_fps * OCCUPIED_BW_RATIO; do_div(*bandwidth, 1000 * 1000); /* Call __set_bw API to setup estimated data bw */ ovl0_bw = 0; ovl0_fbdc_bw = 0; ovl0_2l_bw = 0; ovl0_2l_fbdc_bw = 0; wdma0_bw = 0; rdma0_bw = rdma0_bw * out_fps / 1000; __set_bw(DISP_MODULE_OVL0, ovl0_bw); __set_fbdc_bw(DISP_MODULE_OVL0, ovl0_fbdc_bw); __set_bw(DISP_MODULE_OVL0_2L, ovl0_2l_bw); __set_fbdc_bw(DISP_MODULE_OVL0_2L, ovl0_2l_fbdc_bw); __set_bw(DISP_MODULE_WDMA0, wdma0_bw); __set_bw(DISP_MODULE_RDMA0, rdma0_bw); DISPDBG( "%s rdma0:%d, out_fps:%llu, bw:%llu\n", __func__, rdma0_bw, out_fps, *bandwidth); } return ret; }