123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /*
- * Copyright (C) 2019 MediaTek Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include "mtk_layering_rule.h"
- #include "mtk_drm_crtc.h"
- #include "mtk_disp_pmqos.h"
- #include "mtk_drm_mmp.h"
- #include "mtk_drm_drv.h"
- static struct drm_crtc *dev_crtc;
- /* add for mm qos */
- static struct pm_qos_request mm_freq_request;
- static u64 g_freq_steps[MAX_FREQ_STEP];
- static int g_freq_level = -1;
- static int step_size = 1;
- #ifdef MTK_FB_MMDVFS_SUPPORT
- int __mtk_disp_pmqos_slot_look_up(int comp_id, int mode)
- {
- switch (comp_id) {
- case DDP_COMPONENT_OVL0:
- if (mode == DISP_BW_FBDC_MODE)
- return DISP_PMQOS_OVL0_FBDC_BW;
- else
- return DISP_PMQOS_OVL0_BW;
- case DDP_COMPONENT_OVL1:
- if (mode == DISP_BW_FBDC_MODE)
- return DISP_PMQOS_OVL1_FBDC_BW;
- else
- return DISP_PMQOS_OVL1_BW;
- case DDP_COMPONENT_OVL0_2L:
- if (mode == DISP_BW_FBDC_MODE)
- return DISP_PMQOS_OVL0_2L_FBDC_BW;
- else
- return DISP_PMQOS_OVL0_2L_BW;
- case DDP_COMPONENT_OVL1_2L:
- if (mode == DISP_BW_FBDC_MODE)
- return DISP_PMQOS_OVL1_2L_FBDC_BW;
- else
- return DISP_PMQOS_OVL1_2L_BW;
- case DDP_COMPONENT_OVL2_2L:
- if (mode == DISP_BW_FBDC_MODE)
- return DISP_PMQOS_OVL2_2L_FBDC_BW;
- else
- return DISP_PMQOS_OVL2_2L_BW;
- case DDP_COMPONENT_OVL3_2L:
- if (mode == DISP_BW_FBDC_MODE)
- return DISP_PMQOS_OVL3_2L_FBDC_BW;
- else
- return DISP_PMQOS_OVL3_2L_BW;
- case DDP_COMPONENT_RDMA0:
- return DISP_PMQOS_RDMA0_BW;
- case DDP_COMPONENT_RDMA1:
- return DISP_PMQOS_RDMA1_BW;
- case DDP_COMPONENT_RDMA2:
- return DISP_PMQOS_RDMA2_BW;
- case DDP_COMPONENT_WDMA0:
- return DISP_PMQOS_WDMA0_BW;
- case DDP_COMPONENT_WDMA1:
- return DISP_PMQOS_WDMA1_BW;
- default:
- DDPPR_ERR("%s, unknown comp %d\n", __func__, comp_id);
- break;
- }
- return -EINVAL;
- }
- int __mtk_disp_pmqos_port_look_up(int comp_id)
- {
- switch (comp_id) {
- #if defined(CONFIG_MACH_MT6779)
- case DDP_COMPONENT_OVL0:
- return SMI_PORT_DISP_OVL0;
- case DDP_COMPONENT_OVL1:
- return SMI_PORT_DISP_OVL1;
- case DDP_COMPONENT_OVL0_2L:
- return SMI_PORT_DISP_OVL0_2L;
- case DDP_COMPONENT_OVL1_2L:
- return SMI_PORT_DISP_OVL1_2L;
- case DDP_COMPONENT_OVL2_2L:
- return SMI_PORT_DISP_OVL2;
- case DDP_COMPONENT_OVL3_2L:
- return SMI_PORT_DISP_OVL3;
- case DDP_COMPONENT_RDMA0:
- return SMI_PORT_DISP_RDMA0;
- case DDP_COMPONENT_RDMA1:
- return SMI_PORT_DISP_RDMA1;
- case DDP_COMPONENT_WDMA0:
- return SMI_PORT_DISP_WDMA0;
- #endif
- #if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6893)
- case DDP_COMPONENT_OVL0:
- return M4U_PORT_L0_OVL_RDMA0;
- case DDP_COMPONENT_OVL0_2L:
- return M4U_PORT_L1_OVL_2L_RDMA0;
- case DDP_COMPONENT_OVL1_2L:
- return M4U_PORT_L0_OVL_2L_RDMA1;
- case DDP_COMPONENT_OVL2_2L:
- return M4U_PORT_L1_OVL_2L_RDMA2;
- case DDP_COMPONENT_OVL3_2L:
- return M4U_PORT_L0_OVL_2L_RDMA3;
- case DDP_COMPONENT_RDMA0:
- return M4U_PORT_L0_DISP_RDMA0;
- case DDP_COMPONENT_RDMA1:
- return M4U_PORT_L1_DISP_RDMA1;
- case DDP_COMPONENT_WDMA0:
- return M4U_PORT_L0_DISP_WDMA0;
- case DDP_COMPONENT_WDMA1:
- return M4U_PORT_L1_DISP_WDMA1;
- #endif
- #if defined(CONFIG_MACH_MT6873)
- case DDP_COMPONENT_OVL0:
- return M4U_PORT_L0_OVL_RDMA0;
- case DDP_COMPONENT_OVL0_2L:
- return M4U_PORT_L1_OVL_2L_RDMA0;
- case DDP_COMPONENT_OVL2_2L:
- return M4U_PORT_L1_OVL_2L_RDMA2;
- case DDP_COMPONENT_RDMA0:
- return M4U_PORT_L0_DISP_RDMA0;
- case DDP_COMPONENT_RDMA4:
- return M4U_PORT_L1_DISP_RDMA4;
- case DDP_COMPONENT_WDMA0:
- return M4U_PORT_L0_DISP_WDMA0;
- #endif
- #if defined(CONFIG_MACH_MT6853) || defined(CONFIG_MACH_MT6833)
- case DDP_COMPONENT_OVL0:
- return M4U_PORT_L0_OVL_RDMA0;
- case DDP_COMPONENT_OVL0_2L:
- return M4U_PORT_L1_OVL_2L_RDMA0;
- case DDP_COMPONENT_RDMA0:
- return M4U_PORT_L1_DISP_RDMA0;
- case DDP_COMPONENT_WDMA0:
- return M4U_PORT_L1_DISP_WDMA0;
- #endif
- default:
- DDPPR_ERR("%s, unknown comp %d\n", __func__, comp_id);
- break;
- }
- return -EINVAL;
- }
- int __mtk_disp_set_module_bw(struct mm_qos_request *request, int comp_id,
- unsigned int bandwidth, unsigned int bw_mode)
- {
- int mode;
- if (bw_mode == DISP_BW_FBDC_MODE)
- mode = BW_COMP_DEFAULT;
- else
- mode = BW_COMP_NONE;
- DDPINFO("set module %d, bw %u\n", comp_id, bandwidth);
- bandwidth = bandwidth * 133 / 100;
- mm_qos_set_bw_request(request, bandwidth, mode);
- DRM_MMP_MARK(pmqos, comp_id, bandwidth);
- return 0;
- }
- void __mtk_disp_set_module_hrt(struct mm_qos_request *request,
- unsigned int bandwidth)
- {
- mm_qos_set_hrt_request(request, bandwidth);
- }
- int mtk_disp_set_hrt_bw(struct mtk_drm_crtc *mtk_crtc, unsigned int bw)
- {
- struct drm_crtc *crtc = &mtk_crtc->base;
- struct mtk_drm_private *priv = crtc->dev->dev_private;
- struct mtk_ddp_comp *comp;
- unsigned int tmp;
- int i, j, ret = 0;
- tmp = bw;
- for (i = 0; i < DDP_PATH_NR; i++) {
- if (!(mtk_crtc->ddp_ctx[mtk_crtc->ddp_mode].req_hrt[i]))
- continue;
- for_each_comp_in_crtc_target_path(comp, mtk_crtc, j, i) {
- ret |= mtk_ddp_comp_io_cmd(comp, NULL, PMQOS_SET_HRT_BW,
- &tmp);
- }
- }
- if (ret == RDMA_REQ_HRT)
- tmp = mtk_drm_primary_frame_bw(crtc);
- mm_qos_set_hrt_request(&priv->hrt_bw_request, tmp);
- DRM_MMP_MARK(hrt_bw, 0, tmp);
- DDPINFO("set HRT bw %u\n", tmp);
- mm_qos_update_all_request(&priv->hrt_request_list);
- return ret;
- }
- void mtk_drm_pan_disp_set_hrt_bw(struct drm_crtc *crtc, const char *caller)
- {
- struct mtk_drm_crtc *mtk_crtc;
- struct drm_display_mode *mode;
- unsigned int bw = 0;
- dev_crtc = crtc;
- mtk_crtc = to_mtk_crtc(dev_crtc);
- mode = &crtc->state->adjusted_mode;
- bw = _layering_get_frame_bw(crtc, mode);
- mtk_disp_set_hrt_bw(mtk_crtc, bw);
- DDPINFO("%s:pan_disp_set_hrt_bw: %u\n", caller, bw);
- }
- int mtk_disp_hrt_cond_change_cb(struct notifier_block *nb, unsigned long value,
- void *v)
- {
- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(dev_crtc);
- int i, ret;
- unsigned int hrt_idx;
- DDP_MUTEX_LOCK(&mtk_crtc->lock, __func__, __LINE__);
- switch (value) {
- case BW_THROTTLE_START: /* CAM on */
- DDPMSG("DISP BW Throttle start\n");
- /* TODO: concider memory session */
- DDPINFO("CAM trigger repaint\n");
- hrt_idx = _layering_rule_get_hrt_idx();
- hrt_idx++;
- DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
- drm_trigger_repaint(DRM_REPAINT_FOR_IDLE, dev_crtc->dev);
- for (i = 0; i < 5; ++i) {
- ret = wait_event_timeout(
- mtk_crtc->qos_ctx->hrt_cond_wq,
- atomic_read(&mtk_crtc->qos_ctx->hrt_cond_sig),
- HZ / 5);
- if (ret == 0)
- DDPINFO("wait repaint timeout %d\n", i);
- atomic_set(&mtk_crtc->qos_ctx->hrt_cond_sig, 0);
- if (atomic_read(&mtk_crtc->qos_ctx->last_hrt_idx) >=
- hrt_idx)
- break;
- }
- DDP_MUTEX_LOCK(&mtk_crtc->lock, __func__, __LINE__);
- break;
- case BW_THROTTLE_END: /* CAM off */
- DDPMSG("DISP BW Throttle end\n");
- /* TODO: switch DC */
- break;
- default:
- break;
- }
- DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
- return 0;
- }
- struct notifier_block pmqos_hrt_notifier = {
- .notifier_call = mtk_disp_hrt_cond_change_cb,
- };
- int mtk_disp_hrt_bw_dbg(void)
- {
- mtk_disp_hrt_cond_change_cb(NULL, BW_THROTTLE_START, NULL);
- return 0;
- }
- #endif
- int mtk_disp_hrt_cond_init(struct drm_crtc *crtc)
- {
- struct mtk_drm_crtc *mtk_crtc;
- dev_crtc = crtc;
- mtk_crtc = to_mtk_crtc(dev_crtc);
- mtk_crtc->qos_ctx = vmalloc(sizeof(struct mtk_drm_qos_ctx));
- if (mtk_crtc->qos_ctx == NULL) {
- DDPPR_ERR("%s:allocate qos_ctx failed\n", __func__);
- return -ENOMEM;
- }
- return 0;
- }
- #ifdef MTK_FB_MMDVFS_SUPPORT
- void mtk_drm_mmdvfs_init(void)
- {
- pm_qos_add_request(&mm_freq_request, PM_QOS_DISP_FREQ,
- PM_QOS_MM_FREQ_DEFAULT_VALUE);
- mmdvfs_qos_get_freq_steps(PM_QOS_DISP_FREQ, g_freq_steps, &step_size);
- }
- #endif
- static void mtk_drm_set_mmclk(struct drm_crtc *crtc, int level,
- const char *caller)
- {
- if (drm_crtc_index(crtc) != 0)
- return;
- if (level < 0 || level > MAX_FREQ_STEP)
- level = -1;
- if (level == g_freq_level)
- return;
- g_freq_level = level;
- DDPINFO("%s set mmclk level: %d\n", caller, g_freq_level);
- if (g_freq_level >= 0)
- pm_qos_update_request(&mm_freq_request,
- g_freq_steps[g_freq_level]);
- else
- pm_qos_update_request(&mm_freq_request, 0);
- }
- void mtk_drm_set_mmclk_by_pixclk(struct drm_crtc *crtc,
- unsigned int pixclk, const char *caller)
- {
- int i;
- if (pixclk >= g_freq_steps[0]) {
- DDPMSG("%s:error:pixleclk (%d) is to big for mmclk (%llu)\n",
- caller, pixclk, g_freq_steps[0]);
- mtk_drm_set_mmclk(crtc, 0, caller);
- return;
- }
- if (!pixclk) {
- mtk_drm_set_mmclk(crtc, -1, caller);
- return;
- }
- for (i = 1; i < step_size; i++) {
- if (pixclk >= g_freq_steps[i]) {
- mtk_drm_set_mmclk(crtc, i-1, caller);
- break;
- }
- if (i == step_size - 1)
- mtk_drm_set_mmclk(crtc, -1, caller);
- }
- }
|