From 51de59d06b53cb72ee549fb7d396a0b7a3a65e97 Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Wed, 25 Aug 2021 18:35:18 -0700 Subject: [PATCH 01/50] disp: msm: sde: update rc checks for mask configuration Rounded corner mask layer height/width should match the panel height and width. Change updates rounded corner mask configuration check to ensure that dimensons match. Change-Id: I97f544b0a7df1ebea6d8aa3321813649ebc69d82 Signed-off-by: Gopikrishnaiah Anandan --- include/uapi/display/drm/msm_drm_pp.h | 2 ++ msm/sde/sde_hw_rc.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/uapi/display/drm/msm_drm_pp.h b/include/uapi/display/drm/msm_drm_pp.h index 1be662c6..03b39654 100644 --- a/include/uapi/display/drm/msm_drm_pp.h +++ b/include/uapi/display/drm/msm_drm_pp.h @@ -681,6 +681,8 @@ struct drm_msm_rc_mask_cfg { __u64 cfg_param_07; __u32 cfg_param_08; __u64 cfg_param_09[RC_DATA_SIZE_MAX]; + __u32 height; + __u32 width; }; #define FP16_SUPPORTED diff --git a/msm/sde/sde_hw_rc.c b/msm/sde/sde_hw_rc.c index 4fa75372..31a127e6 100644 --- a/msm/sde/sde_hw_rc.c +++ b/msm/sde/sde_hw_rc.c @@ -588,6 +588,13 @@ static int sde_hw_rc_check_mask_cfg( return -EINVAL; } + if (hw_cfg->panel_height != rc_mask_cfg->height || + rc_mask_cfg->width != hw_cfg->panel_width) { + SDE_ERROR("RC mask Layer: h %d w %d panel: h %d w %d mismatch\n", + rc_mask_cfg->height, rc_mask_cfg->width, + hw_cfg->panel_height, hw_cfg->panel_width); + return -EINVAL; + } flags = rc_mask_cfg->flags; cfg_param_01 = rc_mask_cfg->cfg_param_01; cfg_param_02 = rc_mask_cfg->cfg_param_02; @@ -728,7 +735,8 @@ int sde_hw_rc_check_mask(struct sde_hw_dspp *hw_dspp, void *cfg) if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg) || !hw_cfg->payload) { - SDE_ERROR("invalid payload\n"); + SDE_ERROR("invalid payload len %d exp %zd\n", hw_cfg->len, + sizeof(struct drm_msm_rc_mask_cfg)); return -EINVAL; } From 798f058dfb06878696e18465393f95edc0710bd3 Mon Sep 17 00:00:00 2001 From: Anjaneya Prasad Musunuri Date: Thu, 16 Sep 2021 20:05:03 +0530 Subject: [PATCH 02/50] disp: msm: sde: handle partial update transitions in rounded corner This change clear cached ROIs when rounded corner feature is disabled to ensure full frame ROI for first frame when feature is enabled again. This change depends on HAL change to disable PU for one frame when RC mask config is set. Change-Id: I4c48ccd3f64409d1b0fa19f0e6f92eab5f86d099 Signed-off-by: Anjaneya Prasad Musunuri --- msm/sde/sde_hw_rc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/msm/sde/sde_hw_rc.c b/msm/sde/sde_hw_rc.c index 4fa75372..1ba7338c 100644 --- a/msm/sde/sde_hw_rc.c +++ b/msm/sde/sde_hw_rc.c @@ -773,6 +773,7 @@ int sde_hw_rc_check_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg) roi_list = hw_cfg->payload; if (!roi_list) { SDE_DEBUG("full frame update\n"); + memset(&empty_roi_list, 0, sizeof(struct msm_roi_list)); roi_list = &empty_roi_list; } @@ -835,6 +836,7 @@ int sde_hw_rc_setup_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg) roi_list = hw_cfg->payload; if (!roi_list) { SDE_DEBUG("full frame update\n"); + memset(&empty_roi_list, 0, sizeof(struct msm_roi_list)); roi_list = &empty_roi_list; } @@ -904,6 +906,9 @@ int sde_hw_rc_setup_mask(struct sde_hw_dspp *hw_dspp, void *cfg) memset(RC_STATE(hw_dspp).last_rc_mask_cfg, 0, sizeof(struct drm_msm_rc_mask_cfg)); RC_STATE(hw_dspp).mask_programmed = false; + memset(RC_STATE(hw_dspp).last_roi_list, 0, + sizeof(struct msm_roi_list)); + RC_STATE(hw_dspp).roi_programmed = false; return 0; } From b55d8085d8bfe7b1838a0897378db7eddf0e1da7 Mon Sep 17 00:00:00 2001 From: Sandeep Gangadharaiah Date: Thu, 30 Sep 2021 10:56:55 -0400 Subject: [PATCH 03/50] disp: msm: dp: remove benign warnings about missing properties The parser is throwing warning for missing properties in device tree, which might not be present in all variants. This warning can be ignored and is downgraded as a debug log. Change-Id: I1b3f6e9e3d21a0a84585ace4eba15710464d7b51 Signed-off-by: Sandeep Gangadharaiah --- msm/dp/dp_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index 68541954..a0bcee0e 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -317,7 +317,7 @@ static int dp_parser_get_vreg(struct dp_parser *parser, pm_supply_name = dp_parser_supply_node_name(module); supply_root_node = of_get_child_by_name(of_node, pm_supply_name); if (!supply_root_node) { - DP_WARN("no supply entry present: %s\n", pm_supply_name); + DP_DEBUG("no supply entry present: %s\n", pm_supply_name); goto novreg; } From 7f7c4b8e20ea33bff10f5905ac519da2b3c87636 Mon Sep 17 00:00:00 2001 From: Mahadevan Date: Wed, 29 Sep 2021 15:34:43 +0530 Subject: [PATCH 04/50] disp: msm: sde: add rev checks for diwali target Add required revision checks from display for diwali target. Change-Id: Ib165b1133eea1203de3b946b46cf39ee0ad05e47 Signed-off-by: Mahadevan --- msm/sde/sde_hw_catalog.c | 36 ++++++++++++++++++++++++++++++++++++ msm/sde/sde_hw_catalog.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 9dfabe81..6d262146 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -5128,6 +5128,42 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->dither_luma_mode_support = true; sde_cfg->mdss_hw_block_size = 0x158; sde_cfg->rc_lm_flush_override = false; + } else if (IS_DIWALI_TARGET(hw_rev)) { + sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH; + sde_cfg->has_dedicated_cwb_support = true; + sde_cfg->has_cwb_dither = true; + sde_cfg->has_wb_ubwc = true; + sde_cfg->has_cwb_crop = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 40; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->has_sui_blendstage = true; + sde_cfg->has_3d_merge_reset = true; + sde_cfg->has_hdr = true; + sde_cfg->has_hdr_plus = true; + sde_cfg->skip_inline_rot_threshold = true; + set_bit(SDE_MDP_DHDR_MEMPOOL_4K, &sde_cfg->mdp[0].features); + sde_cfg->has_vig_p010 = true; + sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_1; + sde_cfg->vbif_disable_inner_outer_shareable = true; + sde_cfg->dither_luma_mode_support = true; + sde_cfg->mdss_hw_block_size = 0x158; + sde_cfg->syscache_supported = true; + sde_cfg->sspp_multirect_error = true; + sde_cfg->has_fp16 = true; + set_bit(SDE_MDP_PERIPH_TOP_0_REMOVED, &sde_cfg->mdp[0].features); + sde_cfg->has_precise_vsync_ts = true; + sde_cfg->has_avr_step = true; + sde_cfg->has_trusted_vm_support = true; + sde_cfg->has_ubwc_stats = true; + sde_cfg->has_demura = true; + sde_cfg->demura_supported[SSPP_DMA1][0] = 0; + sde_cfg->demura_supported[SSPP_DMA1][1] = 1; } else { SDE_ERROR("unsupported chipset id:%X\n", hw_rev); sde_cfg->perf.min_prefill_lines = 0xffff; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index cb2a3f4c..b3a3b5da 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -49,6 +49,7 @@ #define SDE_HW_VER_700 SDE_HW_VER(7, 0, 0) /* lahaina */ #define SDE_HW_VER_720 SDE_HW_VER(7, 2, 0) /* yupik */ #define SDE_HW_VER_810 SDE_HW_VER(8, 1, 0) /* waipio */ +#define SDE_HW_VER_820 SDE_HW_VER(8, 2, 0) /* diwali */ /* Avoid using below IS_XXX macros outside catalog, use feature bit instead */ #define IS_SDE_MAJOR_SAME(rev1, rev2) \ @@ -75,6 +76,7 @@ #define IS_LAHAINA_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_700) #define IS_YUPIK_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_720) #define IS_WAIPIO_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_810) +#define IS_DIWALI_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_820) #define SDE_HW_BLK_NAME_LEN 16 From 1b6075d5c14dad53962ab7be9672d5b1f8861f7c Mon Sep 17 00:00:00 2001 From: Yu Wu Date: Wed, 15 Sep 2021 16:04:47 +0800 Subject: [PATCH 05/50] disp: msm: dsi: remove check for reset gpio config in ext bridge mode When validating panel resource, no need to check reset gpio if using ext bridge mode. Change-Id: Id0df84b9e0d8b10f4dd6851d5b3ab31b220f8622 Signed-off-by: Yu Wu --- msm/dsi/dsi_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 1cd9dc99..382490f2 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -4083,7 +4083,8 @@ error: static bool dsi_display_validate_panel_resources(struct dsi_display *display) { if (!is_sim_panel(display)) { - if (!gpio_is_valid(display->panel->reset_config.reset_gpio)) { + if (!display->panel->host_config.ext_bridge_mode && + !gpio_is_valid(display->panel->reset_config.reset_gpio)) { DSI_ERR("invalid reset gpio for the panel\n"); return false; } From 95c0a9e6818f3d47c47e55c0bfb38f798fa4fd0a Mon Sep 17 00:00:00 2001 From: Anjaneya Prasad Musunuri Date: Wed, 1 Sep 2021 14:55:27 +0530 Subject: [PATCH 06/50] disp: msm: sde: reset feature wrappers based on target capabilities Reset feature wrappers of Rounded corner, Demura and SPR based on display processing engine capabilities of target. Change-Id: I0db1f23a1b8b81eb7867680930168e2c3a6999b9 Signed-off-by: Anjaneya Prasad Musunuri --- msm/sde/sde_color_processing.c | 52 ++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index 01fa0863..a1774672 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -908,6 +908,18 @@ static int _set_demura_feature(struct sde_hw_dspp *hw_dspp, return ret; } +static int _feature_unsupported(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *sde_crtc) +{ + if (!hw_dspp || !hw_cfg || !sde_crtc) { + DRM_ERROR("invalid argumets\n"); + return -EINVAL; + } + + return 0; +} + feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; #define setup_check_crtc_feature_wrappers(wrappers) \ do { \ @@ -2192,6 +2204,45 @@ exit: sde_cp_disable_features(crtc); } +void sde_cp_reset_unsupported_feature_wrappers(struct sde_mdss_cfg *catalog) +{ + if (!catalog) { + DRM_ERROR("invalid catalog\n"); + return; + } + + if (!catalog->rc_count) { + check_crtc_feature_wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = + _feature_unsupported; + check_crtc_pu_feature_wrappers[SDE_CP_CRTC_DSPP_RC_PU] = + _feature_unsupported; + set_crtc_feature_wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = + _feature_unsupported; + set_crtc_pu_feature_wrappers[SDE_CP_CRTC_DSPP_RC_PU] = + _feature_unsupported; + } + + if (!catalog->demura_count) { + check_crtc_pu_feature_wrappers[SDE_CP_CRTC_DSPP_DEMURA_PU] = + _feature_unsupported; + set_crtc_feature_wrappers[SDE_CP_CRTC_DSPP_DEMURA_INIT] = + _feature_unsupported; + set_crtc_pu_feature_wrappers[SDE_CP_CRTC_DSPP_DEMURA_PU] = + _feature_unsupported; + } + + if (!catalog->spr_count) { + check_crtc_pu_feature_wrappers[SDE_CP_CRTC_DSPP_SPR_PU] = + _feature_unsupported; + set_crtc_feature_wrappers[SDE_CP_CRTC_DSPP_SPR_INIT] = + _feature_unsupported; + set_crtc_pu_feature_wrappers[SDE_CP_CRTC_DSPP_SPR_PU] = + _feature_unsupported; + } + + return; +} + void sde_cp_crtc_install_properties(struct drm_crtc *crtc) { struct sde_kms *kms = NULL; @@ -2249,6 +2300,7 @@ void sde_cp_crtc_install_properties(struct drm_crtc *crtc) setup_check_crtc_pu_feature_wrappers( check_crtc_pu_feature_wrappers); setup_dspp_caps_funcs(dspp_cap_update_func); + sde_cp_reset_unsupported_feature_wrappers(catalog); } if (!priv->cp_property) goto exit; From b14335c311d1d8b5011e9ff10df0e8a5de33aaa9 Mon Sep 17 00:00:00 2001 From: Shashank Babu Chinta Venkata Date: Mon, 11 Oct 2021 10:26:29 -0700 Subject: [PATCH 07/50] disp: msm: dsi: change allocation to kvzalloc Alter allocation method from kzalloc to kvzalloc since virtually contiguous allocation should suffice requirement. This will avoid unnecessary invocation of OOO handlers. Change-Id: I8291ddae08f6427478cdd9b88d6148e02d7ab002 Signed-off-by: Shashank Babu Chinta Venkata --- msm/dsi/dsi_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 1cd9dc99..599c0c88 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -7204,7 +7204,8 @@ int dsi_display_find_mode(struct dsi_display *display, return rc; } - priv_info = kzalloc(sizeof(struct dsi_display_mode_priv_info), GFP_KERNEL); + priv_info = kvzalloc(sizeof(struct dsi_display_mode_priv_info), + GFP_KERNEL); if (ZERO_OR_NULL_PTR(priv_info)) return -ENOMEM; @@ -7239,7 +7240,7 @@ int dsi_display_find_mode(struct dsi_display *display, cmp->priv_info = NULL; mutex_unlock(&display->display_lock); - kfree(priv_info); + kvfree(priv_info); if (!*out_mode) { DSI_ERR("[%s] failed to find mode for v_active %u h_active %u fps %u pclk %u\n", From b17cb158614413c44543616695c71ce533db0c53 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Thu, 23 Sep 2021 17:05:05 -0700 Subject: [PATCH 08/50] disp: msm: sde: fix reclaim error handling On reclaim error, mem handle is still valid and reclaim should be retried on next commit. This change keeps the mem_handle valid. Change-Id: Ie3e0cc3d37c7f1f260a7655f48a6aadece65a1ca Signed-off-by: Abhijit Kulkarni --- msm/sde/sde_vm_primary.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_vm_primary.c b/msm/sde/sde_vm_primary.c index 970bc866..28a6cc77 100644 --- a/msm/sde/sde_vm_primary.c +++ b/msm/sde/sde_vm_primary.c @@ -53,11 +53,11 @@ int _sde_vm_reclaim_mem(struct sde_kms *sde_kms) rc = gh_rm_mem_reclaim(sde_vm->base.io_mem_handle, 0); if (rc) { SDE_ERROR("failed to reclaim IO memory, rc=%d\n", rc); - goto reclaim_fail; + return rc; } SDE_INFO("mem reclaim succeeded\n"); -reclaim_fail: + sde_vm->base.io_mem_handle = -1; return rc; From e13444d9ac8a576852a61052df0315785b80990a Mon Sep 17 00:00:00 2001 From: Shashank Babu Chinta Venkata Date: Wed, 13 Oct 2021 14:05:01 -0700 Subject: [PATCH 09/50] disp: msm: dsi: avoid updating bitclk when dyn clk is disabled Currently the bit clk rate is overridden by cached clock rate even in dynamic clock disabled usecase where it is not configured. Avoid this override by retaining calculated bit clock rate for respective mode in such usecase. Change-Id: Ib159219fd50ab977edb8332c83bc8b34aee2dc0f Signed-off-by: Shashank Babu Chinta Venkata --- msm/dsi/dsi_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 1cd9dc99..cfd00c9e 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6804,6 +6804,10 @@ int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_ return -EINVAL; } + /* avoid updating bit_clk for dyn clk feature disbaled usecase */ + if (!display->panel->dyn_clk_caps.dyn_clk_support) + return 0; + clk_rate_hz = display->cached_clk_rate; if (mode->priv_info->bit_clk_list.count) { From 25c3b955c693274818eeb6720e89be08237882a0 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 13 Oct 2021 11:52:56 -0700 Subject: [PATCH 10/50] disp: msm: move thread priority call from component bind Move thread priority call to kernel worker thread because component bind API may run from vendor_modeprobe process context when all drivers probe succeed. Thread priority update is not allowed from vendor_modeprobe process context. Change-Id: Iafac97ce02942d6a2134495232f3c395ba4a362f Signed-off-by: Dhaval Patel --- msm/msm_drv.c | 53 ++++++++++++++++++++++++--------------------------- msm/msm_drv.h | 2 ++ 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 0ab04da6..ce7a41d5 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -104,6 +104,24 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(priv->fbdev); } +static void msm_drm_display_thread_priority_worker(struct kthread_work *work) +{ + int ret = 0; + struct sched_param param = { 0 }; + struct task_struct *task = current->group_leader; + + /** + * this priority was found during empiric testing to have appropriate + * realtime scheduling to process display updates and interact with + * other real time and normal priority task + */ + param.sched_priority = 16; + ret = sched_setscheduler(task, SCHED_FIFO, ¶m); + if (ret) + pr_warn("pid:%d name:%s priority update failed: %d\n", + current->tgid, task->comm, ret); +} + /** * msm_atomic_helper_check - validate state object * @dev: DRM device @@ -575,20 +593,13 @@ static int msm_component_bind_all(struct device *dev, } #endif -static int msm_drm_display_thread_create(struct sched_param param, - struct msm_drm_private *priv, struct drm_device *ddev, +static int msm_drm_display_thread_create(struct msm_drm_private *priv, struct drm_device *ddev, struct device *dev) { int i, ret = 0; - /** - * this priority was found during empiric testing to have appropriate - * realtime scheduling to process display updates and interact with - * other real time and normal priority task - */ - param.sched_priority = 16; + kthread_init_work(&priv->thread_priority_work, msm_drm_display_thread_priority_worker); for (i = 0; i < priv->num_crtcs; i++) { - /* initialize display thread */ priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; kthread_init_worker(&priv->disp_thread[i].worker); @@ -597,11 +608,7 @@ static int msm_drm_display_thread_create(struct sched_param param, kthread_run(kthread_worker_fn, &priv->disp_thread[i].worker, "crtc_commit:%d", priv->disp_thread[i].crtc_id); - ret = sched_setscheduler(priv->disp_thread[i].thread, - SCHED_FIFO, ¶m); - if (ret) - pr_warn("display thread priority update failed: %d\n", - ret); + kthread_queue_work(&priv->disp_thread[i].worker, &priv->thread_priority_work); if (IS_ERR(priv->disp_thread[i].thread)) { dev_err(dev, "failed to create crtc_commit kthread\n"); @@ -623,11 +630,7 @@ static int msm_drm_display_thread_create(struct sched_param param, * frame_pending counters beyond 2. This can lead to commit * failure at crtc commit level. */ - ret = sched_setscheduler(priv->event_thread[i].thread, - SCHED_FIFO, ¶m); - if (ret) - pr_warn("display event thread priority update failed: %d\n", - ret); + kthread_queue_work(&priv->event_thread[i].worker, &priv->thread_priority_work); if (IS_ERR(priv->event_thread[i].thread)) { dev_err(dev, "failed to create crtc_event kthread\n"); @@ -662,12 +665,7 @@ static int msm_drm_display_thread_create(struct sched_param param, kthread_init_worker(&priv->pp_event_worker); priv->pp_event_thread = kthread_run(kthread_worker_fn, &priv->pp_event_worker, "pp_event"); - - ret = sched_setscheduler(priv->pp_event_thread, - SCHED_FIFO, ¶m); - if (ret) - pr_warn("pp_event thread priority update failed: %d\n", - ret); + kthread_queue_work(&priv->pp_event_worker, &priv->thread_priority_work); if (IS_ERR(priv->pp_event_thread)) { dev_err(dev, "failed to create pp_event kthread\n"); @@ -677,8 +675,8 @@ static int msm_drm_display_thread_create(struct sched_param param, } return 0; - } + static struct msm_kms *_msm_drm_component_init_helper( struct msm_drm_private *priv, struct drm_device *ddev, struct device *dev, @@ -803,7 +801,6 @@ static int msm_drm_component_init(struct device *dev) struct msm_drm_private *priv = ddev->dev_private; struct msm_kms *kms = NULL; int ret; - struct sched_param param = { 0 }; struct drm_crtc *crtc; ret = msm_mdss_init(ddev); @@ -842,7 +839,7 @@ static int msm_drm_component_init(struct device *dev) sde_rotator_register(); sde_rotator_smmu_driver_register(); - ret = msm_drm_display_thread_create(param, priv, ddev, dev); + ret = msm_drm_display_thread_create(priv, ddev, dev); if (ret) { dev_err(dev, "msm_drm_display_thread_create failed\n"); goto fail; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 89130a09..635a45bc 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -976,6 +976,8 @@ struct msm_drm_private { struct task_struct *pp_event_thread; struct kthread_worker pp_event_worker; + struct kthread_work thread_priority_work; + unsigned int num_encoders; struct drm_encoder *encoders[MAX_ENCODERS]; From d3d3794b51be1139cb2810cb75b61fe109c5dc21 Mon Sep 17 00:00:00 2001 From: Sandeep Gangadharaiah Date: Thu, 14 Oct 2021 16:05:50 -0400 Subject: [PATCH 11/50] disp: msm: dp: destroy mst topology on unplug On an MST unplug, the MST topology manager state needs to be cleared so it can properly destroy the current topology. But since the mst active state is cleared prematurely in the driver, this call is skipped and on a subsequent plug-in, the topology manager ends up using stale topology from previous configuration. Incorrect RAD values are used for sideband, causing them to fail. This change fixes the order of operations, so the topology manager state is properly updated on unplug. It also removes a duplicate hpd notification to usermode. Change-Id: Idcff17be113a361a0b58e54d85957f30d1d4e2d6 Signed-off-by: Sandeep Gangadharaiah --- msm/dp/dp_display.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 09e600e7..3faeb1a1 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -907,7 +907,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) if (!dp->mst.cbs.hpd) goto skip_wait; - dp->mst.cbs.hpd(&dp->dp_display, true); + dp->mst.cbs.hpd(&dp->dp_display, hpd); } if (hpd) { @@ -1289,21 +1289,18 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) /* * HPD unplug callflow: - * 1. send hpd unplug event with status=disconnected - * 2. send hpd unplug on base connector so usermode can disable - * all external displays. - * 3. unset mst state in the topology mgr so the branch device + * 1. send hpd unplug on base connector so usermode can disable + * all external displays. + * 2. unset mst state in the topology mgr so the branch device * can be cleaned up. */ - if (dp->mst.cbs.hpd) - dp->mst.cbs.hpd(&dp->dp_display, false); if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) || dp_display_state_is(DP_STATE_ENABLED))) rc = dp_display_send_hpd_notification(dp); - dp_display_update_mst_state(dp, false); dp_display_set_mst_mgr_state(dp, false); + dp_display_update_mst_state(dp, false); } DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active); From 511c546a52165ef20a510722a989df4c2850b549 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 15 Oct 2021 13:39:21 -0700 Subject: [PATCH 12/50] disp: msm: sde: disable vsync counter before tear check update Disable vsync counter before single buffer tear check update. It allows to trigger the resolution switch frame as posted start frame. Change-Id: I2726372fd0e6d14ab0f79e3e3b0731a074158682 Signed-off-by: Dhaval Patel --- msm/sde/sde_hw_intf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 0e12addc..e805cf29 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -615,20 +615,20 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, struct sde_hw_tear_check *te) { struct sde_hw_blk_reg_map *c; - int cfg; + u32 cfg = 0; if (!intf) return -EINVAL; c = &intf->hw; - cfg = BIT(19); /* VSYNC_COUNTER_EN */ if (te->hw_vsync_mode) cfg |= BIT(20); cfg |= te->vsync_count; SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); + wmb(); /* disable vsync counter before updating single buffer registers */ SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); SDE_REG_WRITE(c, INTF_TEAR_VSYNC_INIT_VAL, te->vsync_init_val); SDE_REG_WRITE(c, INTF_TEAR_RD_PTR_IRQ, te->rd_ptr_irq); @@ -639,6 +639,8 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, te->sync_threshold_start)); SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT, (te->start_pos + te->sync_threshold_start + 1)); + cfg |= BIT(19); /* VSYNC_COUNTER_EN */ + SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); return 0; } From 4413e3bb7ee87754b30c7f5b5b154e528f6181a8 Mon Sep 17 00:00:00 2001 From: Satya Rama Aditya Pinapala Date: Tue, 19 Oct 2021 12:03:08 -0700 Subject: [PATCH 13/50] disp: msm: dsi: terminate buffer with NULL character Change terminates the copied buffer with a null character. Change-Id: I18d6b3ca861058a242bde399f631771d3a48eddd Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/msm/dsi/dsi_parser.c b/msm/dsi/dsi_parser.c index b4c737d2..ba9686f7 100644 --- a/msm/dsi/dsi_parser.c +++ b/msm/dsi/dsi_parser.c @@ -925,6 +925,7 @@ void *dsi_parser_get_head_node(void *in, buf = parser->buf; memcpy(buf, data, size); + buf[size] = '\0'; strreplace(buf, '\n', ' '); strreplace(buf, '\t', '*'); From 4d27e37beb65128023597a32edfa62f37566d213 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Tue, 19 Oct 2021 20:32:06 -0700 Subject: [PATCH 14/50] disp: msm: sde: add new function for updating the cp feature lists only When sde_crtc_atomic_begin is called before crtc is enabled, all the color processing features need to be moved from active_list to dirty_list after sde_cp_crtc_apply_properties(). However, the ltm_hist_en flag doesn't need to be set to false in this case. Setting ltm_hist_en to false in this case will result LTM merge_en bit being cleared incorrectly. This change replaces sde_cp_crtc_suspend() with a new function that only updates the color processing feature lists in sde_crtc_atomic_begin(). Change-Id: I75d7874899838855bda05a1e8eca0cb9523417e9 Signed-off-by: Ping Li --- msm/sde/sde_color_processing.c | 27 ++++++++++++++++++++++----- msm/sde/sde_color_processing.h | 6 ++++++ msm/sde/sde_crtc.c | 2 +- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index 01fa0863..6bfe3a52 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -2612,12 +2612,11 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc) INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); } -void sde_cp_crtc_suspend(struct drm_crtc *crtc) +void sde_cp_crtc_mark_features_dirty(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = NULL; struct sde_cp_node *prop_node = NULL, *n = NULL; bool ad_suspend = false; - unsigned long irq_flags; if (!crtc) { DRM_ERROR("crtc %pK\n", crtc); @@ -2644,12 +2643,30 @@ void sde_cp_crtc_suspend(struct drm_crtc *crtc) } mutex_unlock(&sde_crtc->crtc_cp_lock); + if (ad_suspend) + _sde_cp_ad_set_prop(sde_crtc, AD_SUSPEND); +} + +void sde_cp_crtc_suspend(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = NULL; + unsigned long irq_flags; + + if (!crtc) { + DRM_ERROR("crtc %pK\n", crtc); + return; + } + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("sde_crtc %pK\n", sde_crtc); + return; + } + + sde_cp_crtc_mark_features_dirty(crtc); + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); sde_crtc->ltm_hist_en = false; spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); - - if (ad_suspend) - _sde_cp_ad_set_prop(sde_crtc, AD_SUSPEND); } void sde_cp_crtc_resume(struct drm_crtc *crtc) diff --git a/msm/sde/sde_color_processing.h b/msm/sde/sde_color_processing.h index a2fef789..32f40905 100644 --- a/msm/sde/sde_color_processing.h +++ b/msm/sde/sde_color_processing.h @@ -228,6 +228,12 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc); int sde_cp_crtc_get_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t *val); +/** + * sde_cp_crtc_mark_features_dirty: Move the cp features from active list to dirty list + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_mark_features_dirty(struct drm_crtc *crtc); + /** * sde_cp_crtc_suspend: Suspend the crtc features * @crtc: Pointer to crtc. diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 6373507f..5e024cb1 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3620,7 +3620,7 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, sde_cp_crtc_apply_properties(crtc); if (!sde_crtc->enabled) - sde_cp_crtc_suspend(crtc); + sde_cp_crtc_mark_features_dirty(crtc); /* * PP_DONE irq is only used by command mode for now. From 6cd653bf2ff31bbe9ea978ac8bfe40dcb9c19906 Mon Sep 17 00:00:00 2001 From: Samantha Tran Date: Wed, 20 Oct 2021 21:26:49 -0700 Subject: [PATCH 15/50] disp: msm: sde: add null check while getting pointer to kms Add a null check to avoid null pointer access while getting pointer to sde_kms. Change-Id: I00f77e2a5bf63217fa57408ee5ac238dcac3fb03 Signed-off-by: Samantha Tran --- msm/sde/sde_core_perf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/msm/sde/sde_core_perf.c b/msm/sde/sde_core_perf.c index c15ed858..69749a04 100644 --- a/msm/sde/sde_core_perf.c +++ b/msm/sde/sde_core_perf.c @@ -843,6 +843,11 @@ void sde_core_perf_crtc_reserve_res(struct drm_crtc *crtc, u64 reserve_rate) /* use current perf, which are the values voted */ sde_crtc = to_sde_crtc(crtc); kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->dev) { + SDE_ERROR("invalid kms\n"); + return; + } + priv = kms->dev->dev_private; kms->perf.core_clk_reserve_rate = max(kms->perf.core_clk_reserve_rate, reserve_rate); From af002925b88219205e354ac42b43d8e9facdc534 Mon Sep 17 00:00:00 2001 From: Rajkumar Subbiah Date: Tue, 19 Oct 2021 15:50:22 -0400 Subject: [PATCH 16/50] disp: msm: dp: set vco divider during pll configure The divider value for vco clock is only dependent on the link rate and is known during pll configure. Instead of depending on the clock framework to program this divider as part of stream clock enable, this change moves the configuration to pll configuration and removes the set rate call on the vco clock. Change-Id: If687a8ab057fdfd6c3b3ad2bd1c51663d9182ff4 Signed-off-by: Rajkumar Subbiah --- msm/dp/dp_pll_5nm.c | 138 ++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 74 deletions(-) diff --git a/msm/dp/dp_pll_5nm.c b/msm/dp/dp_pll_5nm.c index df14f63f..afb48e0a 100644 --- a/msm/dp/dp_pll_5nm.c +++ b/msm/dp/dp_pll_5nm.c @@ -129,6 +129,69 @@ #define DP_5NM_PHY_READY BIT(1) #define DP_5NM_TSYNC_DONE BIT(0) +static int dp_vco_clk_set_div(struct dp_pll *pll, unsigned int div) +{ + u32 val = 0; + + if (!pll) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + if (is_gdsc_disabled(pll)) + return -EINVAL; + + val = dp_pll_read(dp_phy, DP_PHY_VCO_DIV); + val &= ~0x03; + + switch (div) { + case 2: + val |= 1; + break; + case 4: + val |= 2; + break; + case 6: + /* When div = 6, val is 0, so do nothing here */ + ; + break; + case 8: + val |= 3; + break; + default: + DP_DEBUG("unsupported div value %d\n", div); + return -EINVAL; + } + + dp_pll_write(dp_phy, DP_PHY_VCO_DIV, val); + /* Make sure the PHY registers writes are done */ + wmb(); + + DP_DEBUG("val=%d div=%x\n", val, div); + return 0; +} + +static int set_vco_div(struct dp_pll *pll, unsigned long rate) +{ + int div; + int rc = 0; + + if (rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) + div = 6; + else if (rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) + div = 4; + else + div = 2; + + rc = dp_vco_clk_set_div(pll, div); + if (rc < 0) { + DP_DEBUG("set vco div failed\n"); + return rc; + } + + return 0; +} + static int dp_vco_pll_init_db_5nm(struct dp_pll_db *pdb, unsigned long rate) { @@ -336,7 +399,7 @@ static int dp_config_vco_rate_5nm(struct dp_pll *pll, /* Make sure the PHY register writes are done */ wmb(); - return rc; + return set_vco_div(pll, rate); } enum dp_5nm_pll_status { @@ -475,48 +538,6 @@ static void dp_pll_disable_5nm(struct dp_pll *pll) wmb(); } -static int dp_vco_clk_set_div(struct dp_pll *pll, unsigned int div) -{ - u32 val = 0; - - if (!pll) { - DP_ERR("invalid input parameters\n"); - return -EINVAL; - } - - if (is_gdsc_disabled(pll)) - return -EINVAL; - - val = dp_pll_read(dp_phy, DP_PHY_VCO_DIV); - val &= ~0x03; - - switch (div) { - case 2: - val |= 1; - break; - case 4: - val |= 2; - break; - case 6: - /* When div = 6, val is 0, so do nothing here */ - ; - break; - case 8: - val |= 3; - break; - default: - DP_DEBUG("unsupported div value %d\n", div); - return -EINVAL; - } - - dp_pll_write(dp_phy, DP_PHY_VCO_DIV, val); - /* Make sure the PHY registers writes are done */ - wmb(); - - DP_DEBUG("val=%d div=%x\n", val, div); - return 0; -} - static int dp_vco_set_rate_5nm(struct dp_pll *pll, unsigned long rate) { int rc = 0; @@ -787,36 +808,6 @@ static long dp_pll_vco_div_clk_round(struct clk_hw *hw, unsigned long rate, return dp_pll_vco_div_clk_recalc_rate(hw, *parent_rate); } -static int dp_pll_vco_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct dp_pll *pll = NULL; - struct dp_pll_vco_clk *pll_link = NULL; - int rc = 0; - - if (!hw) { - DP_ERR("invalid input parameters\n"); - return -EINVAL; - } - - pll_link = to_dp_vco_hw(hw); - pll = pll_link->priv; - - if (rate != dp_pll_vco_div_clk_get_rate(pll)) { - DP_ERR("unsupported rate %lu failed\n", rate); - return rc; - } - - rc = dp_vco_clk_set_div(pll, pll->vco_rate / rate); - if (rc < 0) { - DP_DEBUG("set rate %lu failed\n", rate); - return rc; - } - - DP_DEBUG("set rate %lu success\n", rate); - return 0; -} - static const struct clk_ops pll_link_clk_ops = { .recalc_rate = dp_pll_link_clk_recalc_rate, .round_rate = dp_pll_link_clk_round, @@ -825,7 +816,6 @@ static const struct clk_ops pll_link_clk_ops = { static const struct clk_ops pll_vco_div_clk_ops = { .recalc_rate = dp_pll_vco_div_clk_recalc_rate, .round_rate = dp_pll_vco_div_clk_round, - .set_rate = dp_pll_vco_div_clk_set_rate, }; static struct dp_pll_vco_clk dp0_phy_pll_clks[DP_PLL_NUM_CLKS] = { From 14e61d16d8022ef5ea6a5edd264865ae026946c1 Mon Sep 17 00:00:00 2001 From: Rajkumar Subbiah Date: Tue, 19 Oct 2021 15:51:02 -0400 Subject: [PATCH 17/50] disp: msm: dp: park pixel clock before disable When switching between 2 dongles/adapters it is possible to have the same resolution with different link configuration. Even though the pixel clock could be the same on replug, the vco clock could be different depending on the link configuration. Since the dp driver only exposes limited clocks to the clock framework, in this specific scenario, the clock driver is unable to recognize the change in source clock rate and ends up skipping the clock reconfiguration. This change adds support to park the pixel clocks on disable, thereby forcing a reconfiguration on subsequent replug even if the pixel clocks are the same. Change-Id: If90b37d6285f6cad23cf1c11a7d6ccd6b4cf850c Signed-off-by: Rajkumar Subbiah --- msm/dp/dp_power.c | 104 +++++++++++++++++++++++++++++++++++++++++++++- msm/dp/dp_power.h | 2 + 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/msm/dp/dp_power.c b/msm/dp/dp_power.c index ccb7063b..cc44c7d1 100644 --- a/msm/dp/dp_power.c +++ b/msm/dp/dp_power.c @@ -11,6 +11,7 @@ #include "dp_pll.h" #define DP_CLIENT_NAME_SIZE 20 +#define XO_CLK_KHZ 19200 struct dp_power_private { struct dp_parser *parser; @@ -19,6 +20,7 @@ struct dp_power_private { struct clk *pixel_clk_rcg; struct clk *pixel_parent; struct clk *pixel1_clk_rcg; + struct clk *xo_clk; struct dp_power dp_power; @@ -26,6 +28,8 @@ struct dp_power_private { bool link_clks_on; bool strm0_clks_on; bool strm1_clks_on; + bool strm0_clks_parked; + bool strm1_clks_parked; }; static int dp_power_regulator_init(struct dp_power_private *power) @@ -220,6 +224,14 @@ static int dp_power_clk_init(struct dp_power_private *power, bool enable) goto err_pixel_parent; } + power->xo_clk = clk_get(dev, "rpmh_cxo_clk"); + if (IS_ERR(power->xo_clk)) { + DP_ERR("Unable to get XO clk: %d\n", PTR_ERR(power->xo_clk)); + rc = PTR_ERR(power->xo_clk); + power->xo_clk = NULL; + goto err_xo_clk; + } + if (power->parser->has_mst) { power->pixel1_clk_rcg = clk_get(dev, "pixel1_clk_rcg"); if (IS_ERR(power->pixel1_clk_rcg)) { @@ -244,8 +256,9 @@ static int dp_power_clk_init(struct dp_power_private *power, bool enable) } return rc; - err_pixel1_clk_rcg: + clk_put(power->xo_clk); +err_xo_clk: clk_put(power->pixel_parent); err_pixel_parent: clk_put(power->pixel_clk_rcg); @@ -255,6 +268,59 @@ exit: return rc; } +static int dp_power_park_module(struct dp_power_private *power, enum dp_pm_type module) +{ + struct dss_module_power *mp; + struct clk *clk = NULL; + int rc = 0; + bool *parked; + + mp = &power->parser->mp[module]; + + if (module == DP_STREAM0_PM) { + clk = power->pixel_clk_rcg; + parked = &power->strm0_clks_parked; + } else if (module == DP_STREAM1_PM) { + clk = power->pixel1_clk_rcg; + parked = &power->strm1_clks_parked; + } else { + goto exit; + } + + if (!clk) { + DP_WARN("clk type %d not supported\n", module); + rc = -EINVAL; + goto exit; + } + + if (!power->xo_clk) { + rc = -EINVAL; + goto exit; + } + + if (*parked) + goto exit; + + rc = clk_set_parent(clk, power->xo_clk); + if (rc) { + DP_ERR("unable to set xo parent on clk %d\n", module); + goto exit; + } + + mp->clk_config->rate = XO_CLK_KHZ; + rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); + if (rc) { + DP_ERR("failed to set clk rate.\n"); + goto exit; + } + + *parked = true; + +exit: + return rc; +} + + static int dp_power_clk_set_rate(struct dp_power_private *power, enum dp_pm_type module, bool enable) { @@ -287,6 +353,8 @@ static int dp_power_clk_set_rate(struct dp_power_private *power, DP_ERR("failed to disable clks\n"); goto exit; } + + dp_power_park_module(power, module); } exit: return rc; @@ -367,6 +435,11 @@ static int dp_power_clk_enable(struct dp_power *dp_power, else if (pm_type == DP_LINK_PM) power->link_clks_on = enable; + if (pm_type == DP_STREAM0_PM) + power->strm0_clks_parked = false; + if (pm_type == DP_STREAM1_PM) + power->strm1_clks_parked = false; + /* * This log is printed only when user connects or disconnects * a DP cable. As this is a user-action and not a frequent @@ -581,6 +654,34 @@ static void dp_power_client_deinit(struct dp_power *dp_power) dp_power_regulator_deinit(power); } +static int dp_power_park_clocks(struct dp_power *dp_power) +{ + int rc = 0; + struct dp_power_private *power; + + if (!dp_power) { + DP_ERR("invalid power data\n"); + return -EINVAL; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + rc = dp_power_park_module(power, DP_STREAM0_PM); + if (rc) { + DP_ERR("failed to park stream 0. err=%d\n", rc); + goto error; + } + + rc = dp_power_park_module(power, DP_STREAM1_PM); + if (rc) { + DP_ERR("failed to park stream 1. err=%d\n", rc); + goto error; + } + +error: + return rc; +} + static int dp_power_set_pixel_clk_parent(struct dp_power *dp_power, u32 strm_id) { int rc = 0; @@ -764,6 +865,7 @@ struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll) dp_power->clk_enable = dp_power_clk_enable; dp_power->clk_status = dp_power_clk_status; dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent; + dp_power->park_clocks = dp_power_park_clocks; dp_power->clk_get_rate = dp_power_clk_get_rate; dp_power->power_client_init = dp_power_client_init; dp_power->power_client_deinit = dp_power_client_deinit; diff --git a/msm/dp/dp_power.h b/msm/dp/dp_power.h index 8d0c7d08..86d7247a 100644 --- a/msm/dp/dp_power.h +++ b/msm/dp/dp_power.h @@ -18,6 +18,7 @@ * @clk_enable: enable/disable the DP clocks * @clk_status: check for clock status * @set_pixel_clk_parent: set the parent of DP pixel clock + * @park_clocks: park all clocks driven by PLL * @clk_get_rate: get the current rate for provided clk_name * @power_client_init: configures clocks and regulators * @power_client_deinit: frees clock and regulator resources @@ -32,6 +33,7 @@ struct dp_power { bool enable); bool (*clk_status)(struct dp_power *power, enum dp_pm_type pm_type); int (*set_pixel_clk_parent)(struct dp_power *power, u32 stream_id); + int (*park_clocks)(struct dp_power *power); u64 (*clk_get_rate)(struct dp_power *power, char *clk_name); int (*power_client_init)(struct dp_power *power, struct sde_power_handle *phandle, From 45380adf3879cba8f61aba5ab2dbe308bbbdbf84 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Fri, 8 Oct 2021 10:25:24 +0530 Subject: [PATCH 18/50] disp: msm: sde: protect file private structure with mutex lock Access file private data structures inside the mutex lock only to avoid use-after-free issues. Change-Id: If70731f517bcb47d4515f131fecafe702064cb45 Signed-off-by: Krishna Manikandan --- msm/msm_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/msm_drv.c b/msm/msm_drv.c index ce7a41d5..e98e3a8b 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1443,7 +1443,7 @@ void msm_mode_object_event_notify(struct drm_mode_object *obj, static int msm_release(struct inode *inode, struct file *filp) { - struct drm_file *file_priv = filp->private_data; + struct drm_file *file_priv; struct drm_minor *minor; struct drm_device *dev; struct msm_drm_private *priv; @@ -1455,6 +1455,7 @@ static int msm_release(struct inode *inode, struct file *filp) mutex_lock(&msm_release_lock); + file_priv = filp->private_data; if (!file_priv) { ret = -EINVAL; goto end; From 43697d6331e1719de5d05a5dfa7af91a069b0a08 Mon Sep 17 00:00:00 2001 From: Shashank Babu Chinta Venkata Date: Thu, 21 Oct 2021 15:04:12 -0700 Subject: [PATCH 19/50] disp: msm: dsi: limit dma read commands to sublink 0 Limit dma read commands to sublink 0 in split link configuration since all panels do not support read on sublink 1. Change-Id: I537abafc02afe1c3306175ac850f4f080154f443 Signed-off-by: Shashank Babu Chinta Venkata --- msm/dsi/dsi_ctrl_hw_2_2.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/msm/dsi/dsi_ctrl_hw_2_2.c b/msm/dsi/dsi_ctrl_hw_2_2.c index 437d2877..07fd1d7d 100644 --- a/msm/dsi/dsi_ctrl_hw_2_2.c +++ b/msm/dsi/dsi_ctrl_hw_2_2.c @@ -299,6 +299,14 @@ void dsi_ctrl_hw_22_configure_splitlink(struct dsi_ctrl_hw *ctrl, else reg |= (BIT(12) | BIT(13)); + /** + * Avoid dma trigger on sublink1 for read commands. This can be + * enabled in future if panel supports sending read command on sublink1. + */ + if (flags & DSI_CTRL_CMD_READ) { + reg = reg & ~BIT(13); + } + DSI_W32(ctrl, DSI_SPLIT_LINK, reg); /* Make sure the split link config is updated */ From 1317b11bc2c4f36950f3521580834e7e4c433830 Mon Sep 17 00:00:00 2001 From: Satya Rama Aditya Pinapala Date: Mon, 11 Oct 2021 12:01:03 -0700 Subject: [PATCH 20/50] disp: msm: dsi: implement ESD recovery cleanup After an ESD failure, the PHY lanes and controller can be stuck in an unknown state. This can result in interrupt storms and watchdog failures, if these error states are not handled correctly. The following change implements the below mechanism to avoid failures. 1) Disable error interrupts during an ESD reg read, which are re-enabled once ESD check is successful. 2) On ESD failure, before turning off LP clocks, reset the PHY lanes and DSI controller. 3) After the HS clocks are turned off, issue a PHY hard reset. 4) Before enabling/disabling error interrupts, clear the error status registers as they are not cleared as part of controller reset. Change-Id: If10e4edf095a334a9416d109ec4b1401d1a84505 Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 36 +++++++++++------------- msm/dsi/dsi_ctrl.h | 4 +++ msm/dsi/dsi_ctrl_hw_cmn.c | 16 +++++++++++ msm/dsi/dsi_display.c | 59 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 20 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index fb207707..8abff6e1 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -448,10 +448,8 @@ static void dsi_ctrl_post_cmd_transfer(struct dsi_ctrl *dsi_ctrl) if (rc) DSI_CTRL_ERR(dsi_ctrl, "failed to disable command engine\n"); - if (dsi_ctrl->pending_cmd_flags & DSI_CTRL_CMD_READ) - mask |= BIT(DSI_FIFO_UNDERFLOW); - - dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, false); + if (!(dsi_ctrl->pending_cmd_flags & DSI_CTRL_CMD_READ)) + dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, false); mutex_unlock(&dsi_ctrl->ctrl_lock); @@ -1909,16 +1907,18 @@ static int dsi_disable_ulps(struct dsi_ctrl *dsi_ctrl) return rc; } -static void dsi_ctrl_enable_error_interrupts(struct dsi_ctrl *dsi_ctrl) +void dsi_ctrl_toggle_error_interrupt_status(struct dsi_ctrl *dsi_ctrl, bool enable) { - if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && - !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && - !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, - 0xFF00A0); - else - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, - 0xFF00E0); + if (!enable) { + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0); + } else { + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && + !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && + !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00A0); + else + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); + } } static int dsi_ctrl_drv_state_init(struct dsi_ctrl *dsi_ctrl) @@ -2597,7 +2597,7 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) &dsi_ctrl->host_config.common_config); dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl_enable_error_interrupts(dsi_ctrl); + dsi_ctrl_toggle_error_interrupt_status(dsi_ctrl, true); dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); @@ -3131,7 +3131,7 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool skip_op) } dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl_enable_error_interrupts(dsi_ctrl); + dsi_ctrl_toggle_error_interrupt_status(dsi_ctrl, true); DSI_CTRL_DEBUG(dsi_ctrl, "Host initialization complete, skip op: %d\n", skip_op); @@ -3417,10 +3417,8 @@ int dsi_ctrl_transfer_prepare(struct dsi_ctrl *dsi_ctrl, u32 flags) mutex_lock(&dsi_ctrl->ctrl_lock); - if (flags & DSI_CTRL_CMD_READ) - mask |= BIT(DSI_FIFO_UNDERFLOW); - - dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, true); + if (!(flags & DSI_CTRL_CMD_READ)) + dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, true); rc = dsi_ctrl_set_cmd_engine_state(dsi_ctrl, DSI_CTRL_ENGINE_ON, false); if (rc) { diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index f0ef3167..b1a5a900 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -920,4 +920,8 @@ int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl); */ int dsi_ctrl_get_io_resources(struct msm_io_res *io_res); +/** + * dsi_ctrl_toggle_error_interrupt_status() - Toggles error interrupt status + */ +void dsi_ctrl_toggle_error_interrupt_status(struct dsi_ctrl *dsi_ctrl, bool enable); #endif /* _DSI_CTRL_H_ */ diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index 6534bff6..b4589ce7 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -1411,6 +1411,22 @@ void dsi_ctrl_hw_cmn_enable_error_interrupts(struct dsi_ctrl_hw *ctrl, { u32 int_ctrl = 0; u32 int_mask0 = 0x7FFF3BFF; + u32 dln0_phy_err = 0x11111; + u32 fifo_status = 0xCCCC0789; + u32 ack_error = 0x1193BFFF; + u32 timeout_status = 0x11111111; + u32 clk_status = 0x10000; + u32 dsi_status_error = 0x80000000; + u32 reg = 0; + + DSI_W32(ctrl, DSI_DLN0_PHY_ERR, dln0_phy_err); + DSI_W32(ctrl, DSI_FIFO_STATUS, fifo_status); + DSI_W32(ctrl, DSI_TIMEOUT_STATUS, timeout_status); + DSI_W32(ctrl, DSI_ACK_ERR_STATUS, ack_error); + reg = DSI_R32(ctrl, DSI_CLK_STATUS); + DSI_W32(ctrl, DSI_CLK_STATUS, reg | clk_status); + reg = DSI_R32(ctrl, DSI_STATUS); + DSI_W32(ctrl, DSI_STATUS, reg | dsi_status_error); int_ctrl = DSI_R32(ctrl, DSI_INT_CTRL); if (errors) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index db3f3089..c0f1662c 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -921,6 +921,19 @@ static int dsi_display_status_check_te(struct dsi_display *display, return rc; } +void dsi_display_toggle_error_interrupt_status(struct dsi_display * display, bool enable) +{ + int i = 0; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + dsi_ctrl_toggle_error_interrupt_status(ctrl->ctrl, enable); + } +} + int dsi_display_check_status(struct drm_connector *connector, void *display, bool te_check_override) { @@ -966,6 +979,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, dsi_display_set_ctrl_esd_check_flag(dsi_display, true); + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + + /* Disable error interrupts while doing an ESD check */ + dsi_display_toggle_error_interrupt_status(dsi_display, false); + if (status_mode == ESD_MODE_REG_READ) { rc = dsi_display_status_reg_read(dsi_display); } else if (status_mode == ESD_MODE_SW_BTA) { @@ -990,7 +1008,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, /* Handle Panel failures during display disable sequence */ if (rc <=0) atomic_set(&panel->esd_recovery_pending, 1); + else + /* Enable error interrupts post an ESD success */ + dsi_display_toggle_error_interrupt_status(dsi_display, true); + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); release_panel_lock: dsi_panel_release_panel_lock(panel); SDE_EVT32(SDE_EVTLOG_FUNC_EXIT, rc); @@ -1040,18 +1062,23 @@ static int dsi_display_cmd_rx(struct dsi_display *display, flags = DSI_CTRL_CMD_READ; + dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + dsi_display_toggle_error_interrupt_status(display, false); cmd->ctrl_flags = flags; dsi_display_set_cmd_tx_ctrl_flags(display, cmd); rc = dsi_ctrl_transfer_prepare(m_ctrl->ctrl, cmd->ctrl_flags); if (rc) { DSI_ERR("prepare for rx cmd transfer failed rc = %d\n", rc); - goto release_panel_lock; + goto enable_error_interrupts; } rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, cmd); if (rc <= 0) DSI_ERR("rx cmd transfer failed rc = %d\n", rc); dsi_ctrl_transfer_unprepare(m_ctrl->ctrl, cmd->ctrl_flags); +enable_error_interrupts: + dsi_display_toggle_error_interrupt_status(display, true); + dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); release_panel_lock: dsi_panel_release_panel_lock(display->panel); return rc; @@ -3573,6 +3600,21 @@ static void dsi_display_ctrl_isr_configure(struct dsi_display *display, bool en) } } +static void dsi_display_cleanup_post_esd_failure(struct dsi_display *display) +{ + int i = 0; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + + dsi_phy_lane_reset(ctrl->phy); + dsi_ctrl_soft_reset(ctrl->ctrl); + } +} + int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk, enum dsi_lclk_type l_type, @@ -3584,6 +3626,14 @@ int dsi_pre_clkoff_cb(void *priv, if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) && (l_type & DSI_LINK_LP_CLK)) { + + /* + * Clean up the DSI controller on a previous ESD failure. This requires a DSI + * controller soft reset. Also reset PHY lanes before resetting controller. + */ + if (atomic_read(&display->panel->esd_recovery_pending)) + dsi_display_cleanup_post_esd_failure(display); + /* * If continuous clock is enabled then disable it * before entering into ULPS Mode. @@ -3777,6 +3827,13 @@ int dsi_post_clkoff_cb(void *priv, return -EINVAL; } + /* Reset PHY to clear the PHY status once the HS clocks are turned off */ + if ((clk_type & DSI_LINK_CLK) && (curr_state == DSI_CLK_OFF) + && (l_type == DSI_LINK_HS_CLK)) { + if (atomic_read(&display->panel->esd_recovery_pending)) + dsi_display_phy_sw_reset(display); + } + if ((clk_type & DSI_CORE_CLK) && (curr_state == DSI_CLK_OFF)) { rc = dsi_display_phy_power_off(display); From 35f07ca601a9350d35d0cf47b823523111501e65 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Wed, 20 Oct 2021 16:50:03 -0700 Subject: [PATCH 21/50] disp: msm: fix rsc static wakeup time calculation Currently RSC timer register programming is optimized for updating only during timing param changes and not during RSC state changes with same timing. Static wakeup time computation should consider panel jitter for RSC clk state too, else it can result in RSC hang. This change also removes extra logic for video mode prefil lines computation for rsc config as video mode does not enable RSC solver. Current issue scenario exposing the hang is in dual dsi display scenario where RSC is in clock state and static wakeup time is programmed by not considering panel jitter, after suspend/pmsuspend while waking up if RSC switches to command state if primary enabled first and vsync may arrive much early based on the panel jitter. RSC hw can not handle if TE arrives earlier than static wakeup time causing RSC hang. Change-Id: I1434fdd71eb04fdbe22b3601500493c818e9126d Signed-off-by: Prabhanjan Kandula --- msm/sde/sde_encoder.c | 13 +------------ msm/sde_rsc.c | 9 ++------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index eae32184..d6a35dcf 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1559,20 +1559,9 @@ static int _sde_encoder_update_rsc_client( (rsc_config->prefill_lines != mode_info->prefill_lines) || (rsc_config->jitter_numer != mode_info->jitter_numer) || (rsc_config->jitter_denom != mode_info->jitter_denom)) { - rsc_config->fps = mode_info->frame_rate; rsc_config->vtotal = mode_info->vtotal; - /* - * for video mode, prefill lines should not go beyond vertical - * front porch for RSCC configuration. This will ensure bw - * downvotes are not sent within the active region. Additional - * -1 is to give one line time for rscc mode min_threshold. - */ - if (is_vid_mode && (mode_info->prefill_lines >= v_front_porch)) - rsc_config->prefill_lines = v_front_porch - 1; - else - rsc_config->prefill_lines = mode_info->prefill_lines; - + rsc_config->prefill_lines = mode_info->prefill_lines; rsc_config->jitter_numer = mode_info->jitter_numer; rsc_config->jitter_denom = mode_info->jitter_denom; sde_enc->rsc_state_init = false; diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index afe39256..2ffb67b2 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -312,7 +312,7 @@ static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc, default_prefill_lines = (rsc->cmd_config.fps * DEFAULT_PANEL_MIN_V_PREFILL) / DEFAULT_PANEL_FPS; - if ((state == SDE_RSC_CMD_STATE) || !rsc->cmd_config.prefill_lines) + if (!rsc->cmd_config.prefill_lines) rsc->cmd_config.prefill_lines = default_prefill_lines; pr_debug("frame fps:%d jitter_numer:%d jitter_denom:%d vtotal:%d prefill lines:%d\n", @@ -333,12 +333,7 @@ static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc, line_time_ns = div_u64(line_time_ns, rsc->cmd_config.vtotal); prefill_time_ns = line_time_ns * rsc->cmd_config.prefill_lines; - /* only take jitter into account for CMD mode */ - if (state == SDE_RSC_CMD_STATE) - total = frame_time_ns - frame_jitter - prefill_time_ns; - else - total = frame_time_ns - prefill_time_ns; - + total = frame_time_ns - frame_jitter - prefill_time_ns; if (total < 0) { pr_err("invalid total time period time:%llu jiter_time:%llu blanking time:%llu\n", frame_time_ns, frame_jitter, prefill_time_ns); From ce86cc5397d303e6121383f9b152202e2cfb7532 Mon Sep 17 00:00:00 2001 From: Sandeep Gangadharaiah Date: Fri, 22 Oct 2021 18:58:13 -0400 Subject: [PATCH 22/50] disp: msm: dp: fix warnings due to dp_hdcp2p2 thread reparking This change checks "dp_hdcp2p2" thread's parked state, before attempting to park the thread. This would avoid a warning message from the kernel module, in case if the thread is already parked. Change-Id: I3133da7159c9806981e4760be275c0a54036958b Signed-off-by: Sandeep Gangadharaiah --- msm/dp/dp_hdcp2p2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/dp/dp_hdcp2p2.c b/msm/dp/dp_hdcp2p2.c index d346ae89..bd94ca39 100644 --- a/msm/dp/dp_hdcp2p2.c +++ b/msm/dp/dp_hdcp2p2.c @@ -316,7 +316,8 @@ static int dp_hdcp2p2_authenticate(void *input) ctrl->sink_status = SINK_CONNECTED; atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING); - kthread_park(ctrl->thread); + if (kthread_should_park()) + kthread_park(ctrl->thread); kfifo_reset(&ctrl->cmd_q); kthread_unpark(ctrl->thread); From c6b0d1fbe9d3894eab8bfa2a8588ea3fdaaf8c0d Mon Sep 17 00:00:00 2001 From: Andhavarapu Karthik Date: Mon, 25 Oct 2021 16:05:46 +0530 Subject: [PATCH 23/50] disp: msm: sde: Move TVM related code under SDE VM config This change moves TVM related code under SDE VM config. Change-Id: I8357d6a984fd97f18f24eee33464299e8ea66b12 Signed-off-by: Andhavarapu Karthik --- msm/sde/sde_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index d1f7359b..e43a42db 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -58,7 +58,9 @@ #include #include "soc/qcom/secure_buffer.h" #include +#ifdef CONFIG_DRM_SDE_VM #include +#endif #define CREATE_TRACE_POINTS #include "sde_trace.h" @@ -4823,6 +4825,7 @@ parse_fail: return rc; } +#ifdef CONFIG_DRM_SDE_VM int sde_kms_get_io_resources(struct sde_kms *sde_kms, struct msm_io_res *io_res) { struct platform_device *pdev = to_platform_device(sde_kms->dev->dev); @@ -4854,6 +4857,7 @@ int sde_kms_get_io_resources(struct sde_kms *sde_kms, struct msm_io_res *io_res) return rc; } +#endif static int sde_kms_hw_init(struct msm_kms *kms) { From 213d49059349bcfc98e3436e3601b5197a52b8de Mon Sep 17 00:00:00 2001 From: Shashank Babu Chinta Venkata Date: Wed, 27 Oct 2021 00:11:05 -0700 Subject: [PATCH 24/50] disp: msm: dsi: fix pll lane count in split link usecase In split link usecase with single DSI and dual sublink, the pixel clock rate should be calculated based on effective lanes rather than cumulative lanes on that DSI PHY. This effective lanes can be expressed as number of lanes being used per sublink. Change-Id: Ia534e816cc64b62c5fe0b9fcaabb9ba52d05bab0 Signed-off-by: Shashank Babu Chinta Venkata --- msm/dsi/dsi_defs.h | 17 ----------------- msm/dsi/dsi_phy.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 11074df7..4ab7abee 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -771,23 +771,6 @@ static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt) return 24; } -/* return number of DSI data lanes */ -static inline int dsi_get_num_of_data_lanes(enum dsi_data_lanes dlanes) -{ - int num_of_lanes = 0; - - if (dlanes & DSI_DATA_LANE_0) - num_of_lanes++; - if (dlanes & DSI_DATA_LANE_1) - num_of_lanes++; - if (dlanes & DSI_DATA_LANE_2) - num_of_lanes++; - if (dlanes & DSI_DATA_LANE_3) - num_of_lanes++; - - return num_of_lanes; -} - static inline u64 dsi_h_active_dce(struct dsi_mode_info *mode) { u64 h_active = 0; diff --git a/msm/dsi/dsi_phy.c b/msm/dsi/dsi_phy.c index 2305790f..a6160a24 100644 --- a/msm/dsi/dsi_phy.c +++ b/msm/dsi/dsi_phy.c @@ -764,6 +764,40 @@ error: return rc; } +/** + * dsi_phy_get_data_lanes_count() - Count the data lines need to be configured + * @dsi_phy: DSI PHY handle. + * + * Return: Count of data lanes being used + */ +static inline int dsi_phy_get_data_lanes_count(struct msm_dsi_phy *phy) +{ + int num_of_lanes = 0; + enum dsi_data_lanes dlanes; + + dlanes = phy->data_lanes; + + /** + * For split link use case effective data lines need to be used + * rather than total lanes on PHY for clock calculation and hence we + * fall back pll->lanes to lanes_per_sublink rather than total + * lanes. + */ + if (phy->cfg.split_link.enabled) + return phy->cfg.split_link.lanes_per_sublink; + + if (dlanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (dlanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (dlanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (dlanes & DSI_DATA_LANE_3) + num_of_lanes++; + + return num_of_lanes; +} + /** * dsi_phy_configure() - Configure DSI PHY PLL * @dsi_phy: DSI PHY handle. @@ -779,7 +813,8 @@ int dsi_phy_configure(struct msm_dsi_phy *phy, bool commit) phy->pll->type = phy->cfg.phy_type; phy->pll->bpp = dsi_pixel_format_to_bpp(phy->dst_format); - phy->pll->lanes = dsi_get_num_of_data_lanes(phy->data_lanes); + phy->pll->lanes = dsi_phy_get_data_lanes_count(phy); + if (phy->hw.ops.configure) rc = phy->hw.ops.configure(phy->pll, commit); From 994d2568be996b66b5530e2a1a9e2e31b3fc9aa3 Mon Sep 17 00:00:00 2001 From: Sandeep Gangadharaiah Date: Thu, 28 Oct 2021 15:43:15 -0400 Subject: [PATCH 25/50] disp: msm: dp: send mst act signal after link maintenance If MST is enabled, the controller needs MST ACT to be completed to successfully transition to 'Ready for Video' state. The driver is sending ACT during the normal flow when transitioning from link training to stream enable. But it is not sending ACT, if a link maintenance is triggered after stream enable. This change adds the ACT update to the link maintenance call flow. Change-Id: I7aea53a1e54202f1d9059a8eb59f01fa97fe9eb9 Signed-off-by: Sandeep Gangadharaiah --- msm/dp/dp_ctrl.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/msm/dp/dp_ctrl.c b/msm/dp/dp_ctrl.c index 5f35d1f5..b564d587 100644 --- a/msm/dp/dp_ctrl.c +++ b/msm/dp/dp_ctrl.c @@ -943,6 +943,26 @@ static void dp_ctrl_fec_setup(struct dp_ctrl_private *ctrl) DP_WARN("failed to enable sink fec\n"); } +static int dp_ctrl_mst_send_act(struct dp_ctrl_private *ctrl) +{ + bool act_complete; + + if (!ctrl->mst_mode) + return 0; + + ctrl->catalog->trigger_act(ctrl->catalog); + msleep(20); /* needs 1 frame time */ + + ctrl->catalog->read_act_complete_sts(ctrl->catalog, &act_complete); + + if (!act_complete) + DP_ERR("mst act trigger complete failed\n"); + else + DP_MST_DEBUG("mst ACT trigger complete SUCCESS\n"); + + return 0; +} + static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) { int ret = 0; @@ -980,6 +1000,7 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) if (ctrl->stream_count) { dp_ctrl_send_video(ctrl); + dp_ctrl_mst_send_act(ctrl); dp_ctrl_wait4video_ready(ctrl); dp_ctrl_fec_setup(ctrl); } @@ -1168,26 +1189,6 @@ static void dp_ctrl_mst_calculate_rg(struct dp_ctrl_private *ctrl, DP_DEBUG("x_int: %d, y_frac_enum: %d\n", x_int, y_frac_enum); } -static int dp_ctrl_mst_send_act(struct dp_ctrl_private *ctrl) -{ - bool act_complete; - - if (!ctrl->mst_mode) - return 0; - - ctrl->catalog->trigger_act(ctrl->catalog); - msleep(20); /* needs 1 frame time */ - - ctrl->catalog->read_act_complete_sts(ctrl->catalog, &act_complete); - - if (!act_complete) - DP_ERR("mst act trigger complete failed\n"); - else - DP_MST_DEBUG("mst ACT trigger complete SUCCESS\n"); - - return 0; -} - static void dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl, struct dp_panel *panel) { From 6e05f12db7712f4209f1b8288f12a10ad922ecb8 Mon Sep 17 00:00:00 2001 From: Karthik Andhavarapu Date: Thu, 12 Aug 2021 13:01:12 +0530 Subject: [PATCH 26/50] disp: msm: add display config support for neo Add display config support for compilation on neo target. Change-Id: Ia2b9b8b76f833e233a8bf801485c6dd2104e1700 Signed-off-by: Karthik Andhavarapu --- config/gki_neodisp.conf | 11 +++++++++++ config/gki_neodispconf.h | 14 ++++++++++++++ msm/Kbuild | 5 +++++ 3 files changed, 30 insertions(+) create mode 100644 config/gki_neodisp.conf create mode 100644 config/gki_neodispconf.h diff --git a/config/gki_neodisp.conf b/config/gki_neodisp.conf new file mode 100644 index 00000000..e37085cf --- /dev/null +++ b/config/gki_neodisp.conf @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2021, The Linux Foundation. All rights reserved. + +export CONFIG_DRM_MSM=y +export CONFIG_DRM_MSM_SDE=y +export CONFIG_SYNC_FILE=y +export CONFIG_DRM_MSM_DSI=y +export CONFIG_DSI_PARSER=y +export CONFIG_QCOM_MDSS_PLL=y +export CONFIG_DRM_MSM_REGISTER_LOGGING=y +export CONFIG_DISPLAY_BUILD=m diff --git a/config/gki_neodispconf.h b/config/gki_neodispconf.h new file mode 100644 index 00000000..c8bf59de --- /dev/null +++ b/config/gki_neodispconf.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_DRM_MSM 1 +#define CONFIG_DRM_MSM_SDE 1 +#define CONFIG_SYNC_FILE 1 +#define CONFIG_DRM_MSM_DSI 1 +#define CONFIG_DSI_PARSER 1 +#define CONFIG_DRM_MSM_REGISTER_LOGGING 1 +#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1 +#define CONFIG_QCOM_MDSS_PLL 1 +#define CONFIG_GKI_DISPLAY 1 diff --git a/msm/Kbuild b/msm/Kbuild index 0dab5b22..8fca1d17 100644 --- a/msm/Kbuild +++ b/msm/Kbuild @@ -12,6 +12,11 @@ else endif endif +ifeq ($(CONFIG_ARCH_NEO), y) + include $(DISPLAY_ROOT)/config/gki_neodisp.conf + LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_neodispconf.h +endif + LINUX_INC += -Iinclude/linux \ -Iinclude/linux/drm From 0ecc150e069ae42e22096fdc6ec4bd33776a9abb Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 29 Oct 2021 17:42:49 -0700 Subject: [PATCH 27/50] disp: rsc: update mode-1 threshold config to 1 hz Update mode-1 threshold configuration to 1 hz to avoid selecting mode-2 if panel vsync is irregular. Change-Id: I06b16b8ff35fc145df2af480353a45348548cc3b Signed-off-by: Dhaval Patel --- msm/sde_rsc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index 2ffb67b2..2935cccf 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -366,9 +366,8 @@ static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc, rsc_time_slot_0_ns = div_u64(rsc_time_slot_0_ns, cxo_period_ns); rsc->timer_config.rsc_time_slot_0_ns = (u32) rsc_time_slot_0_ns; - /* time_slot_1 for mode1 latency */ - rsc_time_slot_1_ns = frame_time_ns; - rsc_time_slot_1_ns = div_u64(rsc_time_slot_1_ns, cxo_period_ns); + /* time_slot_1 for mode1 latency - 1 fps */ + rsc_time_slot_1_ns = div_u64(TICKS_IN_NANO_SECOND, cxo_period_ns); rsc->timer_config.rsc_time_slot_1_ns = (u32) rsc_time_slot_1_ns; /* mode 2 is infinite */ From a70e704ef0bdd80c2cd45b58bc54644a7189c32c Mon Sep 17 00:00:00 2001 From: Lakshmi Narayana Kalavala Date: Tue, 2 Nov 2021 15:30:02 -0700 Subject: [PATCH 28/50] disp: msm: sde: Add spr and demura to handoff features list SPR and Demura modules being disabled when switching back from Trusted VM to HLOS VM. The change adds the support to restore the modules to restore to their original state. Change-Id: I0a843671672179a4bc62da512baf02e911fb50aa Signed-off-by: Lakshmi Narayana Kalavala --- msm/sde/sde_color_processing.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index 44d5ca58..9bf8ad58 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -169,6 +169,8 @@ static bool feature_handoff_mask[SDE_CP_CRTC_MAX_FEATURES] = { [SDE_CP_CRTC_DSPP_SIXZONE] = 1, [SDE_CP_CRTC_DSPP_GAMUT] = 1, [SDE_CP_CRTC_DSPP_DITHER] = 1, + [SDE_CP_CRTC_DSPP_SPR_INIT] = 1, + [SDE_CP_CRTC_DSPP_DEMURA_INIT] = 1, }; typedef void (*dspp_cap_update_func_t)(struct sde_crtc *crtc, From f5d5133807c8fbe7dfc397090390de7957150aca Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Wed, 3 Nov 2021 14:25:49 +0530 Subject: [PATCH 29/50] disp: msm: sde: add rev checks for cape target Add required revision checks from display for cape target. Change-Id: Ieb2b0b23462ff122b0090e7c78d8da41fa78fc07 Signed-off-by: Raviteja Tamatam --- msm/sde/sde_hw_catalog.c | 2 +- msm/sde/sde_hw_catalog.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index ea868ca2..db9d2f4c 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -5079,7 +5079,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->mdss_hw_block_size = 0x158; sde_cfg->has_trusted_vm_support = true; sde_cfg->syscache_supported = true; - } else if (IS_WAIPIO_TARGET(hw_rev)) { + } else if (IS_WAIPIO_TARGET(hw_rev) || IS_CAPE_TARGET(hw_rev)) { sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH; sde_cfg->has_dedicated_cwb_support = true; sde_cfg->has_cwb_dither = true; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index eff6deaf..e7d5f50d 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -50,6 +50,7 @@ #define SDE_HW_VER_720 SDE_HW_VER(7, 2, 0) /* yupik */ #define SDE_HW_VER_810 SDE_HW_VER(8, 1, 0) /* waipio */ #define SDE_HW_VER_820 SDE_HW_VER(8, 2, 0) /* diwali */ +#define SDE_HW_VER_850 SDE_HW_VER(8, 5, 0) /* cape */ /* Avoid using below IS_XXX macros outside catalog, use feature bit instead */ #define IS_SDE_MAJOR_SAME(rev1, rev2) \ @@ -77,6 +78,7 @@ #define IS_YUPIK_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_720) #define IS_WAIPIO_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_810) #define IS_DIWALI_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_820) +#define IS_CAPE_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_850) #define SDE_HW_BLK_NAME_LEN 16 From f2499b50d8bb149b08cd13af2abc8a7919b3cf87 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Thu, 14 Oct 2021 19:15:51 +0530 Subject: [PATCH 30/50] disp: msm: dsi: remove early return from dma_cmd_wait_for_done In ASYNC wait mode, next command kickoff can happen before previous command ISR execution is completed in below sequence: ASYNC command A -> triggered dsi_ctrl_isr for command A -> fired and executed atomic_set(&dsi_ctrl->dma_irq_trig, 1); wait_for_done for command A -> returns early as dsi_ctrl->dma_irq_trig is 1 ASYNC Command B -> triggered wait_for_done for command B -> waiting for cmd_dma_done dsi_ctrl_isr for command A -> executes complete_all(&dsi_ctrl->irq_info.cmd_dma_done); wait_for_done for command B -> returns success incorrectly based on complete_all of previous command isr and disable_status_interrupt() is not called. This leads to refcount of dma_done going wrong and dsi_ctrl_isr is not enabled on suspend resume. To fix this issue, mark command transfer successful only based on complete_all(cmd_dma_done). This way disable_status_interrupt() will be always called either from dsi_ctrl_isr or wait_for_done(). Change-Id: I0379ea7ff82a1e077b95f6996d11d1722de00936 Signed-off-by: Ritesh Kumar --- msm/dsi/dsi_ctrl.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 8abff6e1..f3f16189 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -370,13 +370,6 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct dsi_ctrl *dsi_ctrl) dsi_hw_ops = dsi_ctrl->hw.ops; SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY); - /* - * This atomic state will be set if ISR has been triggered, - * so the wait is not needed. - */ - if (atomic_read(&dsi_ctrl->dma_irq_trig)) - return; - ret = wait_for_completion_timeout( &dsi_ctrl->irq_info.cmd_dma_done, msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); @@ -397,6 +390,7 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct dsi_ctrl *dsi_ctrl) dsi_ctrl_disable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE); } + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_EXIT); } From 683f6bc6af220bb36b91f194480479314dcd76ef Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Tue, 2 Nov 2021 18:19:18 -0700 Subject: [PATCH 31/50] disp: msm: sde: send event on trusted vm transition This change sends a notification to user mode after msm_drm driver releases the mmio and irq resources on trusted vm transition request. This is required as user mode has no other way to know when the resources where actually released. User mode driver earlier relied on retire fence signaling but retire fences are send before releasing the hw. Change-Id: Ia218cfcbf398b2de1ad9578fb9baedf348b067df Signed-off-by: Abhijit Kulkarni --- include/uapi/display/drm/sde_drm.h | 1 + msm/sde/sde_crtc.c | 14 ++++++++++++++ msm/sde/sde_crtc.h | 5 +++++ msm/sde/sde_kms.c | 2 ++ 4 files changed, 22 insertions(+) diff --git a/include/uapi/display/drm/sde_drm.h b/include/uapi/display/drm/sde_drm.h index 0df3a78c..11186fc8 100644 --- a/include/uapi/display/drm/sde_drm.h +++ b/include/uapi/display/drm/sde_drm.h @@ -814,6 +814,7 @@ struct drm_msm_noise_layer_cfg { #define DRM_EVENT_MMRM_CB 0X8000000B #define DRM_EVENT_FRAME_DATA 0x8000000C #define DRM_EVENT_DIMMING_BL 0X8000000D +#define DRM_EVENT_VM_RELEASE 0X8000000E #ifndef DRM_MODE_FLAG_VID_MODE_PANEL #define DRM_MODE_FLAG_VID_MODE_PANEL 0x01 diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 5e024cb1..7b161eba 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -70,6 +70,9 @@ static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en, static int _sde_crtc_set_noise_layer(struct sde_crtc *sde_crtc, struct sde_crtc_state *cstate, void __user *usr_ptr); +static int sde_crtc_vm_release_handler(struct drm_crtc *crtc_drm, + bool en, struct sde_irq_callback *irq); + static struct sde_crtc_custom_events custom_events[] = { {DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt}, @@ -81,6 +84,7 @@ static struct sde_crtc_custom_events custom_events[] = { {DRM_EVENT_LTM_WB_PB, sde_cp_ltm_wb_pb_interrupt}, {DRM_EVENT_LTM_OFF, sde_cp_ltm_off_event_handler}, {DRM_EVENT_MMRM_CB, sde_crtc_mmrm_interrupt_handler}, + {DRM_EVENT_VM_RELEASE, sde_crtc_vm_release_handler}, }; /* default input fence timeout, in ms */ @@ -7506,6 +7510,11 @@ static int sde_crtc_mmrm_interrupt_handler(struct drm_crtc *crtc_drm, return 0; } +static int sde_crtc_vm_release_handler(struct drm_crtc *crtc_drm, + bool en, struct sde_irq_callback *irq) +{ + return 0; +} /** * sde_crtc_update_cont_splash_settings - update mixer settings * and initial clk during device bootup for cont_splash use case @@ -7662,3 +7671,8 @@ void sde_crtc_disable_cp_features(struct drm_crtc *crtc) { sde_cp_disable_features(crtc); } + +void _sde_crtc_vm_release_notify(struct drm_crtc *crtc) +{ + sde_crtc_event_notify(crtc, DRM_EVENT_VM_RELEASE, sizeof(uint32_t), 1); +} diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 44d94ce9..1b74a0ef 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -1063,4 +1063,9 @@ void sde_crtc_cancel_delayed_work(struct drm_crtc *crtc); */ struct drm_encoder *sde_crtc_get_src_encoder_of_clone(struct drm_crtc *crtc); +/* + * _sde_crtc_vm_release_notify- send event to usermode on vm release + */ +void _sde_crtc_vm_release_notify(struct drm_crtc *crtc); + #endif /* _SDE_CRTC_H_ */ diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index e43a42db..158f2f89 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1466,6 +1466,8 @@ int sde_kms_vm_primary_post_commit(struct sde_kms *sde_kms, } sde_vm_unlock(sde_kms); + _sde_crtc_vm_release_notify(crtc); + exit: return rc; } From 13f4082d58459fe624ed89ba67f6e20b2043f6f5 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Tue, 26 Oct 2021 20:12:23 +0530 Subject: [PATCH 32/50] disp: msm: dsi: Fix post cmd tx sequence for read commands For read commands, wait_for_done() should be called in dsi_message_rx function. Currently, its being called twice from dsi_message_rx and dsi_ctrl_post_cmd_transfer. This change adds a check to skip wait_for_done() from dsi_ctrl_post_cmd_transfer. Change-Id: Icb7ccd0f8dde24c6c26732f7cb92a20bebb26f5d Signed-off-by: Ritesh Kumar --- msm/dsi/dsi_ctrl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index f3f16189..1e740a53 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -433,7 +433,8 @@ static void dsi_ctrl_post_cmd_transfer(struct dsi_ctrl *dsi_ctrl) if ((dsi_ctrl->pending_cmd_flags & DSI_CTRL_CMD_BROADCAST) && !(dsi_ctrl->pending_cmd_flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { dsi_ctrl_clear_dma_status(dsi_ctrl); - } else { + } else if (!(dsi_ctrl->pending_cmd_flags & DSI_CTRL_CMD_READ)) { + /* Wait for read command transfer to complete is done in dsi_message_rx. */ dsi_ctrl_dma_cmd_wait_for_done(dsi_ctrl); } From 986c7b1028f9d5b0d6330ac4d26acac5ae21d289 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Tue, 2 Nov 2021 17:17:37 +0530 Subject: [PATCH 33/50] disp: msm: dsi: Logging Improvement in dsi driver This change adds additional logs in dsi driver for easy debugging of issues related to command transfer. Change-Id: Ica784bed6c360b2760d6606d625837e23a22410c Signed-off-by: Ritesh Kumar --- msm/dsi/dsi_ctrl.c | 12 +++++++++--- msm/dsi/dsi_ctrl_hw_cmn.c | 2 ++ msm/dsi/dsi_display.c | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 1e740a53..659d2dac 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1502,7 +1502,7 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, struct dsi_cmd_desc *cmd_de goto error; } - SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, *flags); + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, *flags, dsi_ctrl->cmd_len); if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { cmd_mem.offset = dsi_ctrl->cmd_buffer_iova; @@ -2952,7 +2952,10 @@ void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl, intr_idx >= DSI_STATUS_INTERRUPT_COUNT) return; - SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, intr_idx); + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, intr_idx, + dsi_ctrl->irq_info.irq_num, dsi_ctrl->irq_info.irq_stat_mask, + dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]); + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx] == 0) { @@ -2985,7 +2988,10 @@ void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl, if (!dsi_ctrl || intr_idx >= DSI_STATUS_INTERRUPT_COUNT) return; - SDE_EVT32_IRQ(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, intr_idx); + SDE_EVT32_IRQ(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, intr_idx, + dsi_ctrl->irq_info.irq_num, dsi_ctrl->irq_info.irq_stat_mask, + dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]); + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]) diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index b4589ce7..efc5bc0c 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -882,6 +882,8 @@ void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl, if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER)) DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); + + SDE_EVT32(ctrl->index, cmd->length, flags); } /** diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index fe9b9317..821805dc 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -1124,6 +1124,8 @@ int dsi_display_cmd_transfer(struct drm_connector *connector, goto end; } + SDE_EVT32(dsi_display->tx_cmd_buf_ndx, cmd_buf_len); + /* * Reset the dbgfs buffer if the commands sent exceed the available * buffer size. For video mode, limiting the buffer size to 2K to @@ -1256,6 +1258,8 @@ int dsi_display_cmd_receive(void *display, const char *cmd_buf, goto end; } + SDE_EVT32(cmd_buf_len, recv_buf_len); + rc = dsi_display_cmd_rx(dsi_display, &cmd); if (rc <= 0) DSI_ERR("[DSI] Display command receive failed, rc=%d\n", rc); From 50aa3cd2101dc9bfe0fc7b53f12fdcb3058920d1 Mon Sep 17 00:00:00 2001 From: Yashwanth Date: Wed, 27 Oct 2021 13:23:33 +0530 Subject: [PATCH 34/50] disp: msm: sde: fix traffic shaper prefill calculations This change fixes traffic shaper prefill calculations for prefill count and bytes per clock as per hardware recommendations in the HPG which are calcualted as below: ts_ count = ts_end*19200000/fps/(vtotal) ts_bytes_per_clk = ceil(h_src*v_src*bpp*fps/ 19200000*amortized_pref_rate) Change-Id: Icc2348421a2124daa3b0056f46d7a6a45021381b Signed-off-by: Yashwanth --- msm/sde/sde_hw_sspp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/msm/sde/sde_hw_sspp.c b/msm/sde/sde_hw_sspp.c index 45e6e8f5..b6d65977 100644 --- a/msm/sde/sde_hw_sspp.c +++ b/msm/sde/sde_hw_sspp.c @@ -1082,17 +1082,14 @@ static void sde_hw_sspp_setup_ts_prefill(struct sde_hw_pipe *ctx, } if (cfg->time) { - u64 temp = DIV_ROUND_UP_ULL(TS_CLK * 1000000ULL, cfg->time); - - ts_bytes = temp * cfg->size; + ts_count = DIV_ROUND_UP_ULL(TS_CLK * cfg->time, 1000000ULL); + ts_bytes = DIV_ROUND_UP_ULL(cfg->size, ts_count); if (ts_bytes > SSPP_TRAFFIC_SHAPER_BPC_MAX) ts_bytes = SSPP_TRAFFIC_SHAPER_BPC_MAX; } - if (ts_bytes) { - ts_count = DIV_ROUND_UP_ULL(cfg->size, ts_bytes); + if (ts_count) ts_bytes |= BIT(31) | BIT(27); - } SDE_REG_WRITE(&ctx->hw, ts_offset, ts_bytes); SDE_REG_WRITE(&ctx->hw, ts_prefill_offset, ts_count); From 0ba21c667ded56f1d184abf3042d59b0af93570a Mon Sep 17 00:00:00 2001 From: Nilaan Gunabalachandran Date: Thu, 4 Nov 2021 15:55:23 -0400 Subject: [PATCH 35/50] disp: msm: increase size of sde_kms_info With requirements to support an increased number of display modes, the current size of sde_kms_info is insufficient. This change increases the sde_kms_info max size. Change-Id: Ie0f29003732870dad9ce31ee7d484e84f12ba542 Signed-off-by: Nilaan Gunabalachandran --- msm/sde/sde_kms.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index c200f4b1..1ec52094 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -480,7 +480,11 @@ void *sde_debugfs_get_root(struct sde_kms *sde_kms); * These functions/definitions allow for building up a 'sde_info' structure * containing one or more "key=value\n" entries. */ -#define SDE_KMS_INFO_MAX_SIZE 4096 +#if IS_ENABLED(CONFIG_DRM_LOW_MSM_MEM_FOOTPRINT) +#define SDE_KMS_INFO_MAX_SIZE (1 << 12) +#else +#define SDE_KMS_INFO_MAX_SIZE (1 << 14) +#endif /** * struct sde_kms_info - connector information structure container From 6acf9fddfd411b91d5b6d68391b6865434f37706 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Wed, 3 Nov 2021 16:03:03 -0700 Subject: [PATCH 36/50] disp: msm: update rsc vsync timeout value dynamic Considering requirement for supporting panel refresh rates upto 1Hz current default timeout value is not sufficient. Based on panel refresh rate update vsync wait timeout value so that any vsync waits from here on will have adjusted timeout value. Change-Id: I65af152c4bd3decdd7135a4cc38f54e3bb3d5c92 Signed-off-by: Prabhanjan Kandula --- msm/sde_rsc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index 2935cccf..efd12b46 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -62,6 +62,10 @@ #define DEFAULT_PANEL_MIN_V_PREFILL 35 +/* add 10ms constant for low fps cases and use default timeout for existing cases */ +#define RSC_VSYNC_TIMEOUT_MS(x) ((x && x->cmd_config.fps < 30) ? \ + ((1000 / x->cmd_config.fps) + 10) : PRIMARY_VBLANK_WORST_CASE_MS) + static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT]; static struct device *rpmh_dev[MAX_RSC_COUNT]; @@ -169,7 +173,7 @@ void sde_rsc_client_destroy(struct sde_rsc_client *client) SDE_EVT32(client->id, state, rsc->current_state, client->crtc_id, wait_vblank_crtc_id, SDE_EVTLOG_ERROR); - msleep(PRIMARY_VBLANK_WORST_CASE_MS); + msleep(RSC_VSYNC_TIMEOUT_MS(rsc)); } } mutex_lock(&rsc->client_lock); @@ -538,7 +542,7 @@ vsync_wait: SDE_EVT32(caller_client->id, rsc->current_state, caller_client->crtc_id, wait_vblank_crtc_id, SDE_EVTLOG_ERROR); - msleep(PRIMARY_VBLANK_WORST_CASE_MS); + msleep(RSC_VSYNC_TIMEOUT_MS(rsc)); } else { *wait_vblank_crtc_id = rsc->primary_client->crtc_id; } @@ -585,7 +589,7 @@ static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc, rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0); if (!wait_vblank_crtc_id) { pr_err("invalid crtc id wait pointer provided\n"); - msleep(PRIMARY_VBLANK_WORST_CASE_MS); + msleep(RSC_VSYNC_TIMEOUT_MS(rsc)); } else { *wait_vblank_crtc_id = rsc->primary_client->crtc_id; @@ -600,7 +604,7 @@ static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc, /* Wait for the vsync, if the refcount is set */ rc = wait_event_timeout(rsc->rsc_vsync_waitq, atomic_read(&rsc->rsc_vsync_wait) == 0, - msecs_to_jiffies(PRIMARY_VBLANK_WORST_CASE_MS*2)); + msecs_to_jiffies(RSC_VSYNC_TIMEOUT_MS(rsc) * 2)); if (!rc) { pr_err("Timeout waiting for vsync\n"); rc = -ETIMEDOUT; @@ -686,7 +690,7 @@ vsync_wait: SDE_EVT32(caller_client->id, rsc->current_state, caller_client->crtc_id, wait_vblank_crtc_id, SDE_EVTLOG_ERROR); - msleep(PRIMARY_VBLANK_WORST_CASE_MS); + msleep(RSC_VSYNC_TIMEOUT_MS(rsc)); } else { *wait_vblank_crtc_id = rsc->primary_client->crtc_id; } From ce678e896e800e32815f328c8a1d579b50386c25 Mon Sep 17 00:00:00 2001 From: Sandeep Gangadharaiah Date: Wed, 3 Nov 2021 16:20:14 -0400 Subject: [PATCH 37/50] disp: msm: dp: check for active panels ptr before cleanup During a probable race condition where usermode is triggering a delayed cleanup, this instance would be empty leading to a null pointer dereference. This change will add protection around this pointer. Change-Id: I8e90a1ba3ca925f08678e5fa67616420204edae7 Signed-off-by: Sandeep Gangadharaiah --- msm/dp/dp_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 3faeb1a1..7ee2fd2b 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -403,7 +403,7 @@ static void dp_display_hdcp_register_streams(struct dp_display_private *dp) static void dp_display_hdcp_deregister_stream(struct dp_display_private *dp, enum dp_stream_id stream_id) { - if (dp->hdcp.ops->deregister_streams) { + if (dp->hdcp.ops->deregister_streams && dp->active_panels[stream_id]) { struct stream_info stream = {stream_id, dp->active_panels[stream_id]->vcpi}; From 1025b3c40ac3642cfc2e6562135972db4c43d3c6 Mon Sep 17 00:00:00 2001 From: Sandeep Gangadharaiah Date: Mon, 8 Nov 2021 21:02:12 -0500 Subject: [PATCH 38/50] disp: msm: dp: reduce hdcp error level for inactive state During an HPD, HDCP IRQ handler prints error log and exit if HDCP state is inactive or authentication failure. Inactive state is a benign error and auth failure will be reported by hdcp kernel module. This change will downgrade this error log to debug log. Change-Id: I2a64e3c94a6661db70e93d07f5e3608202fe8871 Signed-off-by: Sandeep Gangadharaiah --- msm/dp/dp_hdcp2p2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msm/dp/dp_hdcp2p2.c b/msm/dp/dp_hdcp2p2.c index bd94ca39..4e2531eb 100644 --- a/msm/dp/dp_hdcp2p2.c +++ b/msm/dp/dp_hdcp2p2.c @@ -680,7 +680,7 @@ static int dp_hdcp2p2_cp_irq(void *input) if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - DP_ERR("invalid hdcp state\n"); + DP_DEBUG("invalid hdcp state\n"); return -EINVAL; } From 6c8c95f99e4233120eee83f975cfad856ba845af Mon Sep 17 00:00:00 2001 From: Rajkumar Subbiah Date: Mon, 1 Nov 2021 19:18:33 -0400 Subject: [PATCH 39/50] disp: msm: dp: add qos vote during hdcp authentication HDCP authentication has strict timing requirements and if the display is on static screen during this time, it is possible that SDE removes the QOS vote when it detects static display, thereby affecting the hdcp authentication process. This change adds qos support in dp driver to vote exclusively for DP. If valid QOS settings are provided in dtsi, then the driver adds the vote when it starts authentication and removes the vote when authentication is completed. Change-Id: I1d8bc098d0857b13fdf1ca089b6dd2d3f381bdb8 Signed-off-by: Rajkumar Subbiah --- msm/dp/dp_display.c | 38 ++++++++++++++++++++++++++++++++++++++ msm/dp/dp_parser.c | 21 +++++++++++++++++++++ msm/dp/dp_parser.h | 6 +++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 3faeb1a1..25cb16d4 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sde_connector.h" @@ -201,6 +202,8 @@ struct dp_display_private { u32 tot_dsc_blks_in_use; bool process_hpd_connect; + struct dev_pm_qos_request pm_qos_req[NR_CPUS]; + bool pm_qos_requested; struct notifier_block usb_nb; }; @@ -285,6 +288,36 @@ static void dp_audio_enable(struct dp_display_private *dp, bool enable) } } +static void dp_display_qos_request(struct dp_display_private *dp, bool add_vote) +{ + struct device *cpu_dev; + int cpu = 0; + struct cpumask *cpu_mask; + u32 latency = dp->parser->qos_cpu_latency; + unsigned long mask = dp->parser->qos_cpu_mask; + + if (!dp->parser->qos_cpu_mask || (dp->pm_qos_requested == add_vote)) + return; + + cpu_mask = to_cpumask(&mask); + for_each_cpu(cpu, cpu_mask) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + SDE_DEBUG("%s: failed to get cpu%d device\n", __func__, cpu); + continue; + } + + if (add_vote) + dev_pm_qos_add_request(cpu_dev, &dp->pm_qos_req[cpu], + DEV_PM_QOS_RESUME_LATENCY, latency); + else + dev_pm_qos_remove_request(&dp->pm_qos_req[cpu]); + } + + SDE_EVT32_EXTERNAL(add_vote, mask, latency); + dp->pm_qos_requested = add_vote; +} + static void dp_display_update_hdcp_status(struct dp_display_private *dp, bool reset) { @@ -499,6 +532,11 @@ static void dp_display_hdcp_process_state(struct dp_display_private *dp) dp->debug->force_encryption && ops && ops->force_encryption) ops->force_encryption(data, dp->debug->force_encryption); + if (status->hdcp_state == HDCP_STATE_AUTHENTICATED) + dp_display_qos_request(dp, false); + else + dp_display_qos_request(dp, true); + switch (status->hdcp_state) { case HDCP_STATE_INACTIVE: dp_display_hdcp_register_streams(dp); diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index a0bcee0e..6efcf30a 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -742,6 +742,26 @@ static void dp_parser_dsc(struct dp_parser *parser) parser->dsc_continuous_pps); } +static void dp_parser_qos(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + u32 mask, latency; + int rc; + + rc = of_property_read_u32(dev->of_node, "qcom,qos-cpu-latency-us", &latency); + if (rc) + return; + + rc = of_property_read_u32(dev->of_node, "qcom,qos-cpu-mask", &mask); + if (rc) + return; + + parser->qos_cpu_mask = mask; + parser->qos_cpu_latency = latency; + + DP_DEBUG("qos parsing successful. mask:%x latency:%ld\n", mask, latency); +} + static void dp_parser_fec(struct dp_parser *parser) { struct device *dev = &parser->pdev->dev; @@ -817,6 +837,7 @@ static int dp_parser_parse(struct dp_parser *parser) dp_parser_dsc(parser); dp_parser_fec(parser); dp_parser_widebus(parser); + dp_parser_qos(parser); err: return rc; } diff --git a/msm/dp/dp_parser.h b/msm/dp/dp_parser.h index 67818570..5a4e844a 100644 --- a/msm/dp/dp_parser.h +++ b/msm/dp/dp_parser.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #ifndef _DP_PARSER_H_ @@ -198,6 +198,8 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) * @dsc_continuous_pps: PPS sent every frame by HW * @has_widebus: widebus (2PPC) feature eanble status *@mst_fixed_port: mst port_num reserved for fixed topology + * @qos_cpu_mask: CPU mask for QOS + * @qos_cpu_latency: CPU Latency setting for QOS * @parse: function to be called by client to parse device tree. * @get_io: function to be called by client to get io data. * @get_io_buf: function to be called by client to get io buffers. @@ -227,6 +229,8 @@ struct dp_parser { bool gpio_aux_switch; bool lphw_hpd; u32 mst_fixed_port[MAX_DP_MST_STREAMS]; + u32 qos_cpu_mask; + unsigned long qos_cpu_latency; int (*parse)(struct dp_parser *parser); struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name); From dd2e1fd03f3177b4998531fa697bafa1b4f1b469 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Tue, 5 Oct 2021 17:04:25 -0700 Subject: [PATCH 40/50] disp: msm: sde: add check for sunlight visibility scale Add check to clip the sunlight visibility scale to an upper limit of MAX_SV_BL_SCALE_LEVEL * 4. Change-Id: I8cc7bf8fba90e115d046ec030983801ce6d93c1d Signed-off-by: Ping Li Signed-off-by: Yuchao Ma --- include/uapi/display/drm/msm_drm_pp.h | 2 ++ msm/dsi/dsi_panel.h | 1 + msm/sde/sde_connector.c | 5 ++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/uapi/display/drm/msm_drm_pp.h b/include/uapi/display/drm/msm_drm_pp.h index e8802114..b0ea33ce 100644 --- a/include/uapi/display/drm/msm_drm_pp.h +++ b/include/uapi/display/drm/msm_drm_pp.h @@ -732,6 +732,8 @@ struct drm_msm_backlight_info { __u32 bl_scale_sv; __u32 status; __u32 min_bl; + __u32 bl_scale_max; + __u32 bl_scale_sv_max; }; #define DIMMING_BL_LUT_LEN 8192 diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index a5a55922..e3000cb9 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -25,6 +25,7 @@ #define MAX_BL_LEVEL 4096 #define MAX_BL_SCALE_LEVEL 1024 #define MAX_SV_BL_SCALE_LEVEL 65535 +#define SV_BL_SCALE_CAP (MAX_SV_BL_SCALE_LEVEL * 4) #define DSI_CMD_PPS_SIZE 135 #define DSI_CMD_PPS_HDR_SIZE 7 diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index c27cfdce..765b9281 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -120,6 +120,8 @@ static void sde_dimming_bl_notify(struct sde_connector *conn, struct dsi_backlig bl_info.bl_scale_sv = config->bl_scale_sv; bl_info.status = config->dimming_status; bl_info.min_bl = config->dimming_min_bl; + bl_info.bl_scale_max = MAX_BL_SCALE_LEVEL; + bl_info.bl_scale_sv_max = SV_BL_SCALE_CAP; event.type = DRM_EVENT_DIMMING_BL; event.length = sizeof(bl_info); SDE_DEBUG("dimming BL event bl_level %d bl_scale %d, bl_scale_sv = %d " @@ -833,7 +835,8 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) bl_config->bl_scale = c_conn->bl_scale > MAX_BL_SCALE_LEVEL ? MAX_BL_SCALE_LEVEL : c_conn->bl_scale; - bl_config->bl_scale_sv = c_conn->bl_scale_sv; + bl_config->bl_scale_sv = c_conn->bl_scale_sv > SV_BL_SCALE_CAP ? + SV_BL_SCALE_CAP : c_conn->bl_scale_sv; SDE_DEBUG("bl_scale = %u, bl_scale_sv = %u, bl_level = %u\n", bl_config->bl_scale, bl_config->bl_scale_sv, From 29534b6d5c4405d55a62a65072ac8fbaa2ad9c5c Mon Sep 17 00:00:00 2001 From: Rajkumar Subbiah Date: Tue, 9 Nov 2021 17:00:40 -0500 Subject: [PATCH 41/50] disp: msm: dp: clear all dp interrupts before deinit If there are any uncleared DP interrupts before deinitialing and turning off the clocks, the interrupt might get stuck at the MDP level and can't be cleared without turning the DP clocks back on. To avoid this situation, this change clears all the interrupts before turning off the clocks. Change-Id: Id13b102fa81c85f92ae8c1d11ffaf7d5bad5fd12 Signed-off-by: Rajkumar Subbiah --- msm/dp/dp_catalog.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index 67e18962..15cf7404 100644 --- a/msm/dp/dp_catalog.c +++ b/msm/dp/dp_catalog.c @@ -1684,9 +1684,17 @@ static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl, dp_write(DP_INTR_STATUS2, DP_INTR_MASK2); dp_write(DP_INTR_STATUS5, DP_INTR_MASK5); } else { + /* disable interrupts */ dp_write(DP_INTR_STATUS, 0x00); dp_write(DP_INTR_STATUS2, 0x00); dp_write(DP_INTR_STATUS5, 0x00); + wmb(); + + /* clear all pending interrupts */ + dp_write(DP_INTR_STATUS, DP_INTERRUPT_STATUS1 << 1); + dp_write(DP_INTR_STATUS2, DP_INTERRUPT_STATUS2 << 1); + dp_write(DP_INTR_STATUS5, DP_INTERRUPT_STATUS5 << 1); + wmb(); } } From a5382aff7e13a173ee82509d270fe6f422185870 Mon Sep 17 00:00:00 2001 From: Yashwanth Date: Thu, 28 Oct 2021 15:57:55 +0530 Subject: [PATCH 42/50] disp: msm: sde: deprecate idle notify work scheduling This change deprecates idle notify work for video mode since idle timer will be maintained by userspace. As part of idle notify work, syscache state is changed from CACHE_STATE_NORMAL to CACHE_STATE_PRE_CACHE along with notifying to the userspace. This change removes CACHE_STATE_PRE_CACHE in the state machine and state is updated from CACHE_STATE_NORMAL to CACHE_STATE_FRAME_WRITE whenever the cache property is set. Change-Id: If3b2c34be954cb625aca76da81fd854c077a8250 Signed-off-by: Yashwanth --- msm/msm_drv.h | 1 - msm/sde/sde_crtc.c | 74 ++-------------------------------------------- msm/sde/sde_crtc.h | 4 --- 3 files changed, 3 insertions(+), 76 deletions(-) diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 635a45bc..4edb8008 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -174,7 +174,6 @@ enum msm_mdp_crtc_property { CRTC_PROP_ROT_CLK, CRTC_PROP_ROI_V1, CRTC_PROP_SECURITY_LEVEL, - CRTC_PROP_IDLE_TIMEOUT, CRTC_PROP_DEST_SCALER, CRTC_PROP_CAPTURE_OUTPUT, diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 5e024cb1..cc9fb9d4 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3675,7 +3675,7 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, dev = crtc->dev; priv = dev->dev_private; - if ((sde_crtc->cache_state == CACHE_STATE_PRE_CACHE) && + if ((sde_crtc->cache_state == CACHE_STATE_NORMAL) && sde_crtc_get_property(cstate, CRTC_PROP_CACHE_STATE)) sde_crtc_static_img_control(crtc, CACHE_STATE_FRAME_WRITE, false); @@ -3844,37 +3844,6 @@ static void _sde_crtc_remove_pipe_flush(struct drm_crtc *crtc) } } -static void _sde_crtc_schedule_idle_notify(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state); - struct sde_kms *sde_kms = _sde_crtc_get_kms(crtc); - struct msm_drm_private *priv; - struct msm_drm_thread *event_thread; - int idle_time = 0; - - if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) - return; - - priv = sde_kms->dev->dev_private; - - idle_time = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_TIMEOUT); - - if (!idle_time || - !sde_encoder_check_curr_mode(sde_crtc->mixers[0].encoder, - MSM_DISPLAY_VIDEO_MODE) || - (crtc->index >= ARRAY_SIZE(priv->event_thread)) || - (sde_crtc->cache_state > CACHE_STATE_NORMAL)) - return; - - /* schedule the idle notify delayed work */ - event_thread = &priv->event_thread[crtc->index]; - - kthread_mod_delayed_work(&event_thread->worker, - &sde_crtc->idle_notify_work, msecs_to_jiffies(idle_time)); - SDE_DEBUG("schedule idle notify work in %dms\n", idle_time); -} - /** * sde_crtc_reset_hw - attempt hardware reset on errors * @crtc: Pointer to DRM crtc instance @@ -4099,8 +4068,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, spin_unlock_irqrestore(&dev->event_lock, flags); } - _sde_crtc_schedule_idle_notify(crtc); - SDE_ATRACE_END("crtc_commit"); } @@ -4516,7 +4483,6 @@ static void sde_crtc_disable(struct drm_crtc *crtc) mutex_lock(&sde_crtc->crtc_lock); kthread_cancel_delayed_work_sync(&sde_crtc->static_cache_read_work); - kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work); SDE_EVT32(DRMID(crtc), sde_crtc->enabled, crtc->state->active, crtc->state->enable, sde_crtc->cached_encoder_mask); @@ -5842,10 +5808,6 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, sde_crtc_install_perf_properties(sde_crtc, sde_kms, catalog, info); - msm_property_install_range(&sde_crtc->property_info, - "idle_time", 0, 0, U64_MAX, 0, - CRTC_PROP_IDLE_TIMEOUT); - if (catalog->has_trusted_vm_support) { int init_idx = sde_in_trusted_vm(sde_kms) ? 1 : 0; @@ -7038,12 +7000,8 @@ void sde_crtc_static_img_control(struct drm_crtc *crtc, kthread_cancel_delayed_work_sync( &sde_crtc->static_cache_read_work); break; - case CACHE_STATE_PRE_CACHE: - if (sde_crtc->cache_state != CACHE_STATE_NORMAL) - return; - break; case CACHE_STATE_FRAME_WRITE: - if (sde_crtc->cache_state != CACHE_STATE_PRE_CACHE) + if (sde_crtc->cache_state != CACHE_STATE_NORMAL) return; break; case CACHE_STATE_FRAME_READ: @@ -7139,33 +7097,10 @@ void sde_crtc_static_cache_read_kickoff(struct drm_crtc *crtc) msecs_to_jiffies(msecs_fps)); } -/* - * __sde_crtc_idle_notify_work - signal idle timeout to user space - */ -static void __sde_crtc_idle_notify_work(struct kthread_work *work) -{ - struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc, - idle_notify_work.work); - struct drm_crtc *crtc; - int ret = 0; - - if (!sde_crtc) { - SDE_ERROR("invalid sde crtc\n"); - } else { - crtc = &sde_crtc->base; - sde_crtc_event_notify(crtc, DRM_EVENT_IDLE_NOTIFY, sizeof(u32), ret); - - SDE_DEBUG("crtc[%d]: idle timeout notified\n", crtc->base.id); - - sde_crtc_static_img_control(crtc, CACHE_STATE_PRE_CACHE, false); - } -} - void sde_crtc_cancel_delayed_work(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; - bool idle_status; bool cache_status; if (!crtc || !crtc->state) @@ -7174,9 +7109,8 @@ void sde_crtc_cancel_delayed_work(struct drm_crtc *crtc) sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(crtc->state); - idle_status = kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work); cache_status = kthread_cancel_delayed_work_sync(&sde_crtc->static_cache_read_work); - SDE_EVT32(DRMID(crtc), idle_status, cache_status); + SDE_EVT32(DRMID(crtc), cache_status); } /* initialize crtc */ @@ -7271,8 +7205,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) sde_crtc->new_perf.llcc_active[i] = false; } - kthread_init_delayed_work(&sde_crtc->idle_notify_work, - __sde_crtc_idle_notify_work); kthread_init_delayed_work(&sde_crtc->static_cache_read_work, __sde_crtc_static_cache_read_work); diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 44d94ce9..757ebc03 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -80,7 +80,6 @@ enum sde_crtc_idle_pc_state { * CACHE_STATE_DISABLED: sys cache has been disabled * CACHE_STATE_ENABLED: sys cache has been enabled * CACHE_STATE_NORMAL: sys cache is normal state - * CACHE_STATE_PRE_CACHE: frame cache is being prepared * CACHE_STATE_FRAME_WRITE: sys cache is being written to * CACHE_STATE_FRAME_READ: sys cache is being read */ @@ -88,7 +87,6 @@ enum sde_crtc_cache_state { CACHE_STATE_DISABLED, CACHE_STATE_ENABLED, CACHE_STATE_NORMAL, - CACHE_STATE_PRE_CACHE, CACHE_STATE_FRAME_WRITE, CACHE_STATE_FRAME_READ }; @@ -304,7 +302,6 @@ struct sde_frame_data { * @misr_reconfigure : boolean entry indicates misr reconfigure status * @misr_frame_count : misr frame count provided by client * @misr_data : store misr data before turning off the clocks. - * @idle_notify_work: delayed worker to notify idle timeout to user space * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver * @plane_mask_old: keeps track of the planes used in the previous commit @@ -394,7 +391,6 @@ struct sde_crtc { bool misr_enable_debugfs; bool misr_reconfigure; u32 misr_frame_count; - struct kthread_delayed_work idle_notify_work; struct sde_power_event *power_event; From 8bccb3e2128c8d7189f2e2ecf57db1c912e333a7 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Thu, 28 Oct 2021 15:45:45 -0700 Subject: [PATCH 43/50] disp: msm: enable dsc support for 422 with 10bpc and 8bpp Add DSCv1.2 native 422 format with 10bpc and 8bpp config and format specific fixed rate control parameter table entries as per the systems recommended settings. Change-Id: Ibd1a5203be2c59f4699537a31f9ae6d69bcfe5ab Signed-off-by: Prabhanjan Kandula --- msm/sde_dsc_helper.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/msm/sde_dsc_helper.c b/msm/sde_dsc_helper.c index 06a226b8..6c8b5cbb 100644 --- a/msm/sde_dsc_helper.c +++ b/msm/sde_dsc_helper.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. */ #include "msm_drv.h" @@ -23,6 +23,7 @@ enum sde_dsc_ratio_type { DSC_V12_422_8BPC_7BPP, DSC_V12_422_8BPC_8BPP, DSC_V12_422_10BPC_7BPP, + DSC_V12_422_10BPC_8BPP, DSC_V12_422_10BPC_10BPP, DSC_V12_420_8BPC_6BPP, DSC_V12_420_10BPC_6BPP, @@ -50,6 +51,7 @@ static char sde_dsc_rc_range_min_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { {0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11}, {0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10}, {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + {0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14}, {0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12}, /* DSC v1.2 YUV420 */ {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10}, @@ -73,6 +75,7 @@ static char sde_dsc_rc_range_max_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { {3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12}, {2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11}, {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + {2, 5, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15}, {2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13}, /* DSC v1.2 YUV420 */ {2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 12}, @@ -96,6 +99,7 @@ static char sde_dsc_rc_range_bpg[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12}, {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, {10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12}, /* DSC v1.2 YUV420 */ {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, @@ -125,6 +129,7 @@ static struct sde_dsc_rc_init_params_lut { {11, 11, 5632, 410, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_7BPP */ {11, 11, 2048, 341, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_8BPP */ {15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_7BPP */ + {15, 15, 2048, 341, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_8BPP */ {15, 15, 2048, 273, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_10BPP */ /* DSC v1.2 YUV420 */ {11, 11, 5632, 410, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_7BPP */ @@ -161,6 +166,7 @@ static struct sde_dsc_table_index_lut { {MSM_CHROMA_422, -1, 2, 8, 7, DSC_V12_422_8BPC_7BPP}, {MSM_CHROMA_422, -1, 2, 8, 8, DSC_V12_422_8BPC_8BPP}, {MSM_CHROMA_422, -1, 2, 10, 7, DSC_V12_422_10BPC_7BPP}, + {MSM_CHROMA_422, -1, 2, 10, 8, DSC_V12_422_10BPC_8BPP}, {MSM_CHROMA_422, -1, 2, 10, 10, DSC_V12_422_10BPC_10BPP}, {MSM_CHROMA_420, -1, 2, 8, 6, DSC_V12_420_8BPC_6BPP}, From 479a5292e630afacc1e9d81aedf48411b33c43fb Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Mon, 18 Oct 2021 01:04:21 +0530 Subject: [PATCH 44/50] disp: msm: limit display brightness max cooling device level Based on panel hardware support, display brightness levels can be very high value. This high value display brightness cooling device levels can cause exceeding PAGE_SIZE for cooling device stat buffer. It leads to buffer failure for cooling device stat feature. Limit display panel mitigation level max to 255. If hardware supports more than 255, then scale brightness levels fit into above limit. Change-Id: Ieeee4ff2aa5cd884819b30b4fd9839e48ac4d804 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- msm/msm_cooling_device.c | 21 ++++++++++++++++----- msm/msm_cooling_device.h | 3 ++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/msm/msm_cooling_device.c b/msm/msm_cooling_device.c index 73ce8f20..c2cc26e7 100644 --- a/msm/msm_cooling_device.c +++ b/msm/msm_cooling_device.c @@ -1,17 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. */ #include #include #include "msm_cooling_device.h" +#define BRIGHTNESS_CDEV_MAX 255 + static int sde_cdev_get_max_brightness(struct thermal_cooling_device *cdev, unsigned long *state) { struct sde_cdev *disp_cdev = (struct sde_cdev *)cdev->devdata; - *state = disp_cdev->bd->props.max_brightness; + *state = disp_cdev->bd->props.max_brightness / disp_cdev->cdev_sf; return 0; } @@ -21,7 +23,8 @@ static int sde_cdev_get_cur_brightness(struct thermal_cooling_device *cdev, { struct sde_cdev *disp_cdev = (struct sde_cdev *)cdev->devdata; - *state = disp_cdev->bd->props.max_brightness - disp_cdev->thermal_state; + *state = ((disp_cdev->bd->props.max_brightness - + disp_cdev->thermal_state) / disp_cdev->cdev_sf); return 0; } @@ -32,10 +35,11 @@ static int sde_cdev_set_cur_brightness(struct thermal_cooling_device *cdev, struct sde_cdev *disp_cdev = (struct sde_cdev *)cdev->devdata; unsigned long brightness_lvl = 0; - if (state > disp_cdev->bd->props.max_brightness) + if (state > disp_cdev->bd->props.max_brightness / disp_cdev->cdev_sf) return -EINVAL; - brightness_lvl = disp_cdev->bd->props.max_brightness - state; + brightness_lvl = disp_cdev->bd->props.max_brightness - + (state * disp_cdev->cdev_sf); if (brightness_lvl == disp_cdev->thermal_state) return 0; disp_cdev->thermal_state = brightness_lvl; @@ -67,6 +71,13 @@ struct sde_cdev *backlight_cdev_register(struct device *dev, return ERR_PTR(-ENOMEM); disp_cdev->thermal_state = 0; disp_cdev->bd = bd; + + if (bd->props.max_brightness > BRIGHTNESS_CDEV_MAX) + disp_cdev->cdev_sf = (bd->props.max_brightness / + BRIGHTNESS_CDEV_MAX); + else + disp_cdev->cdev_sf = 1; + disp_cdev->cdev = thermal_of_cooling_device_register(dev->of_node, (char *)dev_name(&bd->dev), disp_cdev, &sde_cdev_ops); diff --git a/msm/msm_cooling_device.h b/msm/msm_cooling_device.h index b95bf45c..5533aaba 100644 --- a/msm/msm_cooling_device.h +++ b/msm/msm_cooling_device.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. */ #ifndef __SDE_THERMAL_CORE_H__ @@ -16,6 +16,7 @@ struct sde_cdev { struct thermal_cooling_device *cdev; struct backlight_device *bd; unsigned long thermal_state; + unsigned int cdev_sf; }; #ifdef CONFIG_THERMAL_OF From d098764f5bb7448f7bfc09b8a86ad5a6a81d843d Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Mon, 8 Nov 2021 14:18:45 +0530 Subject: [PATCH 45/50] disp: msm: sde: update uidle_db_updates in both enable/disable cases uidle_db_updates are generated when CTL_x_UIDLE_ACTIVE is set to 1. It needs to enabled in both uidle enable and disable cases. CTL_x_UIDLE_ACTIVE is set to 0 only in cases where uidle configuration is not updated. Change-Id: If7655e4eae351bac248f0906c473cdfaf93f2b8a Signed-off-by: Raviteja Tamatam Signed-off-by: Samantha Tran --- msm/sde/sde_core_perf.c | 11 +++++++---- msm/sde/sde_core_perf.h | 7 +++++++ msm/sde/sde_crtc.c | 8 +++++++- msm/sde/sde_crtc.h | 1 + msm/sde/sde_hw_catalog.h | 2 ++ 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/msm/sde/sde_core_perf.c b/msm/sde/sde_core_perf.c index 69749a04..257aac4f 100644 --- a/msm/sde/sde_core_perf.c +++ b/msm/sde/sde_core_perf.c @@ -514,7 +514,7 @@ static void _sde_core_uidle_setup_cfg(struct sde_kms *kms, uidle->ops.set_uidle_ctl(uidle, &cfg); } -static void _sde_core_uidle_setup_ctl(struct drm_crtc *crtc, +void sde_core_perf_uidle_setup_ctl(struct drm_crtc *crtc, bool enable) { struct drm_encoder *drm_enc; @@ -544,7 +544,7 @@ static int _sde_core_perf_enable_uidle(struct sde_kms *kms, SDE_EVT32(uidle_state); _sde_core_uidle_setup_wd(kms, enable); _sde_core_uidle_setup_cfg(kms, uidle_state); - _sde_core_uidle_setup_ctl(crtc, enable); + sde_core_perf_uidle_setup_ctl(crtc, true); kms->perf.uidle_enabled = enable; @@ -599,7 +599,7 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, struct drm_crtc *tmp_crtc; struct sde_kms *kms; enum sde_uidle_state uidle_status = UIDLE_STATE_FAL1_FAL10; - u32 fps; + u32 fps, num_crtc = 0; if (!crtc) { SDE_ERROR("invalid crtc\n"); @@ -627,6 +627,7 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) { + num_crtc++; /* * If DFPS is enabled with VFP, SDE clock and * transfer time will get fixed at max FPS @@ -644,7 +645,7 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, _sde_core_perf_is_cwb(tmp_crtc), uidle_status, uidle_crtc_status, enable); - if (_sde_core_perf_is_wb(tmp_crtc) || + if ((num_crtc > 1) || _sde_core_perf_is_wb(tmp_crtc) || _sde_core_perf_is_cwb(tmp_crtc) || !fps) { uidle_status = UIDLE_STATE_DISABLE; break; @@ -669,6 +670,8 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, _sde_core_perf_enable_uidle(kms, crtc, enable ? uidle_status : UIDLE_STATE_DISABLE); + kms->perf.catalog->uidle_cfg.dirty = !enable; + /* If perf counters enabled, set them up now */ if (kms->catalog->uidle_cfg.debugfs_perf) _sde_core_perf_uidle_setup_cntr(kms, enable); diff --git a/msm/sde/sde_core_perf.h b/msm/sde/sde_core_perf.h index 884e0334..718a2729 100644 --- a/msm/sde/sde_core_perf.h +++ b/msm/sde/sde_core_perf.h @@ -147,6 +147,13 @@ void sde_core_perf_crtc_reserve_res(struct drm_crtc *crtc, u64 reserve_rate); */ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable); +/** + * sde_core_perf_uidle_setup_ctl - enable uidle DB control + * @crtc: Pointer to crtc + * @enable: enable/disable uidle DB + */ +void sde_core_perf_uidle_setup_ctl(struct drm_crtc *crtc, bool enable); + /** * sde_core_perf_destroy - destroy the given core performance context * @perf: Pointer to core performance context diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 5e024cb1..ec5b24b3 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3599,8 +3599,13 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, _sde_crtc_dest_scaler_setup(crtc); sde_cp_crtc_apply_noise(crtc, old_state); - if (crtc->state->mode_changed) + if (crtc->state->mode_changed || sde_kms->perf.catalog->uidle_cfg.dirty) { sde_core_perf_crtc_update_uidle(crtc, true); + } else if (!test_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask) && + sde_kms->perf.uidle_enabled) + sde_core_perf_uidle_setup_ctl(crtc, false); + + test_and_clear_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask); /* * Since CP properties use AXI buffer to program the @@ -4317,6 +4322,7 @@ void sde_crtc_reset_sw_state(struct drm_crtc *crtc) /* mark other properties which need to be dirty for next update */ set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, &sde_crtc->revalidate_mask); + set_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask); if (cstate->num_ds_enabled) set_bit(SDE_CRTC_DIRTY_DEST_SCALER, cstate->dirty); } diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 44d94ce9..09787a1c 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -444,6 +444,7 @@ enum sde_crtc_dirty_flags { SDE_CRTC_DIRTY_DEST_SCALER, SDE_CRTC_DIRTY_DIM_LAYERS, SDE_CRTC_NOISE_LAYER, + SDE_CRTC_DIRTY_UIDLE, SDE_CRTC_DIRTY_MAX, }; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index eff6deaf..9051f964 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1008,6 +1008,7 @@ struct sde_mdp_cfg { * logging * @debugfs_ctrl: uidle is enabled/disabled through debugfs * @perf_cntr_en: performance counters are enabled/disabled + * @dirty: dirty flag for uidle update */ struct sde_uidle_cfg { SDE_HW_BLK_INFO; @@ -1027,6 +1028,7 @@ struct sde_uidle_cfg { u32 debugfs_perf; bool debugfs_ctrl; bool perf_cntr_en; + bool dirty; }; /* struct sde_mdp_cfg : MDP TOP-BLK instance info From c079b51c81b71c3ca772f6a1a75fdb36effca4a9 Mon Sep 17 00:00:00 2001 From: Kashish Jain Date: Tue, 12 Oct 2021 16:01:52 +0530 Subject: [PATCH 46/50] disp: msm: dsi: allocate priv info and bit clk list per fps Currently, in dsi_display_get_modes, priv_info, rates, front_porches and pixel_clks_khz memory is allocated for each timing node and the same memory is copied for each supported fps. The values of front porches calculated to maintain constant fps for each bit clk rate gets overwritten with the values for last fps in the dfps list. But the values of front porches should be different in case where DFPS and dynamic clock are both supported either by vfp approach or hfp approach. To fix this, allocate memory separately for each fps. Change-Id: Ibf753aa8cca8d77b02b20785b5435f1aba05106e Signed-off-by: Kashish Jain --- msm/dsi/dsi_display.c | 79 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 821805dc..810ed48a 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6868,6 +6868,57 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, int star } } +static int dsi_display_mode_dyn_clk_cpy(struct dsi_display *display, + struct dsi_display_mode *src, struct dsi_display_mode *dst) +{ + int rc = 0; + u32 count = 0; + struct dsi_dyn_clk_caps *dyn_clk_caps; + struct msm_dyn_clk_list *bit_clk_list; + + dyn_clk_caps = &(display->panel->dyn_clk_caps); + if (!dyn_clk_caps->dyn_clk_support) + return rc; + + count = dst->priv_info->bit_clk_list.count; + bit_clk_list = &dst->priv_info->bit_clk_list; + bit_clk_list->front_porches = + kcalloc(count, sizeof(u32), GFP_KERNEL); + if (!bit_clk_list->front_porches) { + DSI_ERR("failed to allocate space for front porch list\n"); + rc = -ENOMEM; + goto error; + } + + bit_clk_list->rates = + kcalloc(count, sizeof(u32), GFP_KERNEL); + if (!bit_clk_list->rates) { + DSI_ERR("failed to allocate space for rates list\n"); + rc = -ENOMEM; + goto error; + } + + memcpy(bit_clk_list->rates, src->priv_info->bit_clk_list.rates, + count*sizeof(u32)); + + bit_clk_list->pixel_clks_khz = + kcalloc(count, sizeof(u32), GFP_KERNEL); + if (!bit_clk_list->pixel_clks_khz) { + DSI_ERR("failed to allocate space for pixel clocks list\n"); + rc = -ENOMEM; + goto error; + } + + return rc; + +error: + kfree(bit_clk_list->rates); + kfree(bit_clk_list->front_porches); + kfree(bit_clk_list->pixel_clks_khz); + + return rc; +} + int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode) { int i; @@ -6967,6 +7018,7 @@ int dsi_display_get_modes(struct dsi_display *display, int topology_override = NO_OVERRIDE; bool is_preferred = false; u32 frame_threshold_us = ctrl->ctrl->frame_threshold_time_us; + struct msm_dyn_clk_list *bit_clk_list; memset(&display_mode, 0, sizeof(display_mode)); @@ -7060,10 +7112,24 @@ int dsi_display_get_modes(struct dsi_display *display, * Qsync min fps for the mode will be populated in the timing info * in dsi_panel_get_mode function. */ - sub_mode->priv_info->qsync_min_fps = sub_mode->timing.qsync_min_fps; + display_mode.priv_info->qsync_min_fps = sub_mode->timing.qsync_min_fps; if (!dfps_caps.dfps_support || !support_video_mode) continue; + sub_mode->priv_info = kmemdup(display_mode.priv_info, + sizeof(*sub_mode->priv_info), GFP_KERNEL); + if (!sub_mode->priv_info) { + rc = -ENOMEM; + goto error; + } + + rc = dsi_display_mode_dyn_clk_cpy(display, + &display_mode, sub_mode); + if (rc) { + DSI_ERR("unable to copy dyn clock list\n"); + goto error; + } + sub_mode->mode_idx += (array_idx - 1); curr_refresh_rate = sub_mode->timing.refresh_rate; sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i]; @@ -7086,6 +7152,17 @@ int dsi_display_get_modes(struct dsi_display *display, /* Set first timing sub mode as preferred mode */ display->modes[start].is_preferred = true; } + + bit_clk_list = &display_mode.priv_info->bit_clk_list; + if (support_video_mode && dfps_caps.dfps_support) { + if (dyn_clk_caps->dyn_clk_support) { + kfree(bit_clk_list->rates); + kfree(bit_clk_list->front_porches); + kfree(bit_clk_list->pixel_clks_khz); + } + + kfree(display_mode.priv_info); + } } if (dsc_modes && nondsc_modes) From 2bc4fbcd9445b795a8ff4d5bc119937feb8e8fb5 Mon Sep 17 00:00:00 2001 From: Soutrik Mukhopadhyay Date: Mon, 22 Nov 2021 15:00:34 +0530 Subject: [PATCH 47/50] disp: msm: dp: add DP PHY support for 4nm target Changes include support for specific DP PHY registers and related code changes for 4nm target. Change-Id: I9b349e47ff057421fa465a59e1206fd09f7e367a Signed-off-by: Soutrik Mukhopadhyay --- msm/dp/dp_catalog.c | 34 +++++++++++++++++++++++++++++++++- msm/dp/dp_catalog.h | 1 + msm/dp/dp_catalog_v420.c | 36 +++++++++++++++++++++++++----------- msm/dp/dp_reg.h | 3 +++ 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index 15cf7404..8f771454 100644 --- a/msm/dp/dp_catalog.c +++ b/msm/dp/dp_catalog.c @@ -124,6 +124,7 @@ struct dp_catalog_private { char exe_mode[SZ_4]; u32 dp_core_version; + u32 dp_phy_version; }; static u32 dp_read_sw(struct dp_catalog_private *catalog, @@ -452,12 +453,20 @@ static void dp_catalog_aux_get_irq(struct dp_catalog_aux *aux, bool cmd_busy) static bool dp_catalog_ctrl_wait_for_phy_ready( struct dp_catalog_private *catalog) { - u32 reg = DP_PHY_STATUS, state; + u32 phy_version; + u32 reg, state; void __iomem *base = catalog->io.dp_phy->io.base; bool success = true; u32 const poll_sleep_us = 500; u32 const pll_timeout_us = 10000; + phy_version = dp_catalog_get_dp_phy_version(&catalog->dp_catalog); + if (phy_version >= 60000000) { + reg = DP_PHY_STATUS_V600; + } else { + reg = DP_PHY_STATUS; + } + if (readl_poll_timeout_atomic((base + reg), state, ((state & DP_PHY_READY) > 0), poll_sleep_us, pll_timeout_us)) { @@ -1975,6 +1984,29 @@ u32 dp_catalog_get_dp_core_version(struct dp_catalog *dp_catalog) return dp_read(DP_HW_VERSION); } +u32 dp_catalog_get_dp_phy_version(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!dp_catalog) { + DP_ERR("invalid input\n"); + return 0; + } + + catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog); + if (catalog->dp_phy_version) + return catalog->dp_phy_version; + + io_data = catalog->io.dp_phy; + catalog->dp_phy_version = (dp_read(DP_PHY_REVISION_ID3) << 24) | + (dp_read(DP_PHY_REVISION_ID2) << 16) | + (dp_read(DP_PHY_REVISION_ID1) << 8) | + dp_read(DP_PHY_REVISION_ID0); + + return catalog->dp_phy_version; +} + static int dp_catalog_reg_dump(struct dp_catalog *dp_catalog, char *name, u8 **out_buf, u32 *out_buf_len) { diff --git a/msm/dp/dp_catalog.h b/msm/dp/dp_catalog.h index f5c804be..829a2e8a 100644 --- a/msm/dp/dp_catalog.h +++ b/msm/dp/dp_catalog.h @@ -337,4 +337,5 @@ struct dp_catalog_sub *dp_catalog_get_v200(struct device *dev, struct dp_catalog *catalog, struct dp_catalog_io *io); u32 dp_catalog_get_dp_core_version(struct dp_catalog *dp_catalog); +u32 dp_catalog_get_dp_phy_version(struct dp_catalog *dp_catalog); #endif /* _DP_CATALOG_H_ */ diff --git a/msm/dp/dp_catalog_v420.c b/msm/dp/dp_catalog_v420.c index 91f93d17..4a9915f5 100644 --- a/msm/dp/dp_catalog_v420.c +++ b/msm/dp/dp_catalog_v420.c @@ -91,22 +91,33 @@ static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux, struct dp_catalog_private_v420 *catalog; struct dp_io_data *io_data; int i = 0; - + u32 phy_version; if (!aux || !cfg) { DP_ERR("invalid input\n"); return; } catalog = dp_catalog_get_priv_v420(aux); + phy_version = dp_catalog_get_dp_phy_version(catalog->dpc); + if (phy_version >= 60000000) { + io_data = catalog->io->dp_phy; + dp_write(DP_PHY_PD_CTL, 0x79); + wmb(); /* make sure PD programming happened */ - io_data = catalog->io->dp_phy; - dp_write(DP_PHY_PD_CTL, 0x67); - wmb(); /* make sure PD programming happened */ + /* Turn on BIAS current for PHY/PLL */ + io_data = catalog->io->dp_pll; + dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN_V600, 0x1D); + wmb(); /* make sure BIAS programming happened */ + } else { + io_data = catalog->io->dp_phy; + dp_write(DP_PHY_PD_CTL, 0x67); + wmb(); /* make sure PD programming happened */ - /* Turn on BIAS current for PHY/PLL */ - io_data = catalog->io->dp_pll; - dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17); - wmb(); /* make sure BIAS programming happened */ + /* Turn on BIAS current for PHY/PLL */ + io_data = catalog->io->dp_pll; + dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17); + wmb(); /* make sure BIAS programming happened */ + } io_data = catalog->io->dp_phy; /* DP AUX CFG register programming */ @@ -126,16 +137,19 @@ static void dp_catalog_aux_clear_hw_int_v420(struct dp_catalog_aux *aux) struct dp_catalog_private_v420 *catalog; struct dp_io_data *io_data; u32 data = 0; - + u32 phy_version; if (!aux) { DP_ERR("invalid input\n"); return; } catalog = dp_catalog_get_priv_v420(aux); + phy_version = dp_catalog_get_dp_phy_version(catalog->dpc); io_data = catalog->io->dp_phy; - - data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V420); + if (phy_version >= 60000000) + data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V600); + else + data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V420); dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x1f); wmb(); /* make sure 0x1f is written before next write */ diff --git a/msm/dp/dp_reg.h b/msm/dp/dp_reg.h index 6425191d..f48eaf6c 100644 --- a/msm/dp/dp_reg.h +++ b/msm/dp/dp_reg.h @@ -378,9 +378,11 @@ #define TXn_HIGHZ_DRVR_EN (0x0060) #define DP_PHY_STATUS (0x00DC) +#define DP_PHY_STATUS_V600 (0x00E4) #define DP_PHY_AUX_INTERRUPT_MASK_V420 (0x0054) #define DP_PHY_AUX_INTERRUPT_CLEAR_V420 (0x0058) #define DP_PHY_AUX_INTERRUPT_STATUS_V420 (0x00D8) +#define DP_PHY_AUX_INTERRUPT_STATUS_V600 (0x00E0) #define DP_PHY_SPARE0_V420 (0x00C8) #define TXn_TX_DRV_LVL_V420 (0x0014) #define TXn_TRANSCEIVER_BIAS_EN_V420 (0x0054) @@ -388,6 +390,7 @@ #define TXn_TX_POL_INV_V420 (0x005C) #define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x044) +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN_V600 (0x0DC) /* DP MMSS_CC registers */ #define MMSS_DP_PIXEL_M (0x01B4) From bbc87c5dde34a36220693d5336bf8cd677644bd0 Mon Sep 17 00:00:00 2001 From: Soutrik Mukhopadhyay Date: Mon, 22 Nov 2021 12:23:40 +0530 Subject: [PATCH 48/50] disp: msm: dp: add support for 4nm DP PLL Changes include support for 4nm DP PHY and DP PLL. Added dp_pll_4nm.c file with register programming sequences for DP PHY and PLL. Change-Id: I104cf69964904c9a47a17e75a84df011d7994c9f Signed-off-by: Soutrik Mukhopadhyay --- msm/Kbuild | 3 +- msm/dp/dp_pll.c | 8 + msm/dp/dp_pll.h | 8 +- msm/dp/dp_pll_4nm.c | 930 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 947 insertions(+), 2 deletions(-) create mode 100644 msm/dp/dp_pll_4nm.c diff --git a/msm/Kbuild b/msm/Kbuild index 8fca1d17..a384ea77 100644 --- a/msm/Kbuild +++ b/msm/Kbuild @@ -117,7 +117,8 @@ msm_drm-$(CONFIG_DRM_MSM_DP) += dp/dp_altmode.o \ sde_hdcp_1x.o \ sde_hdcp_2x.o \ dp/dp_pll.o \ - dp/dp_pll_5nm.o + dp/dp_pll_5nm.o \ + dp/dp_pll_4nm.o msm_drm-$(CONFIG_DRM_MSM_DP_MST) += dp/dp_mst_drm.o diff --git a/msm/dp/dp_pll.c b/msm/dp/dp_pll.c index 3f31b856..22ac5719 100644 --- a/msm/dp/dp_pll.c +++ b/msm/dp/dp_pll.c @@ -54,6 +54,9 @@ static int dp_pll_clock_register(struct dp_pll *pll) case DP_PLL_5NM_V2: rc = dp_pll_clock_register_5nm(pll); break; + case DP_PLL_4NM_V1: + rc = dp_pll_clock_register_4nm(pll); + break; default: rc = -ENOTSUPP; break; @@ -69,6 +72,9 @@ static void dp_pll_clock_unregister(struct dp_pll *pll) case DP_PLL_5NM_V2: dp_pll_clock_unregister_5nm(pll); break; + case DP_PLL_4NM_V1: + dp_pll_clock_unregister_4nm(pll); + break; default: break; } @@ -131,6 +137,8 @@ struct dp_pll *dp_pll_get(struct dp_pll_in *in) pll->revision = DP_PLL_5NM_V1; } else if (!strcmp(label, "5nm-v2")) { pll->revision = DP_PLL_5NM_V2; + } else if (!strcmp(label, "4nm-v1")) { + pll->revision = DP_PLL_4NM_V1; } else { DP_ERR("Unsupported pll revision\n"); rc = -ENOTSUPP; diff --git a/msm/dp/dp_pll.h b/msm/dp/dp_pll.h index 9b45f5bf..46825cbd 100644 --- a/msm/dp/dp_pll.h +++ b/msm/dp/dp_pll.h @@ -34,6 +34,7 @@ enum dp_pll_revision { DP_PLL_UNKNOWN, DP_PLL_5NM_V1, DP_PLL_5NM_V2, + DP_PLL_4NM_V1, }; static inline const char *dp_pll_get_revision(enum dp_pll_revision rev) @@ -42,6 +43,7 @@ static inline const char *dp_pll_get_revision(enum dp_pll_revision rev) case DP_PLL_UNKNOWN: return "DP_PLL_UNKNOWN"; case DP_PLL_5NM_V1: return "DP_PLL_5NM_V1"; case DP_PLL_5NM_V2: return "DP_PLL_5NM_V2"; + case DP_PLL_4NM_V1: return "DP_PLL_4NM_V1"; default: return "???"; } } @@ -107,7 +109,9 @@ struct dp_pll_db { u32 lock_cmp_en; u32 ssc_step_size1_mode0; u32 ssc_step_size2_mode0; - + u32 ssc_per1; + u32 cmp_code1_mode0; + u32 cmp_code2_mode0; /* PHY vco divider */ u32 phy_vco_div; }; @@ -124,6 +128,8 @@ static inline bool is_gdsc_disabled(struct dp_pll *pll) int dp_pll_clock_register_5nm(struct dp_pll *pll); void dp_pll_clock_unregister_5nm(struct dp_pll *pll); +int dp_pll_clock_register_4nm(struct dp_pll *pll); +void dp_pll_clock_unregister_4nm(struct dp_pll *pll); struct dp_pll_in { struct platform_device *pdev; diff --git a/msm/dp/dp_pll_4nm.c b/msm/dp/dp_pll_4nm.c new file mode 100644 index 00000000..b6bab789 --- /dev/null +++ b/msm/dp/dp_pll_4nm.c @@ -0,0 +1,930 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/* + * Display Port PLL driver block diagram for branch clocks + * + * +------------------------+ +------------------------+ + * | dp_phy_pll_link_clk | | dp_phy_pll_vco_div_clk | + * +------------------------+ +------------------------+ + * | | + * | | + * V V + * dp_link_clk dp_pixel_clk + * + * + */ + +#include +#include +#include +#include +#include +#include +#include "clk-regmap-mux.h" +#include "dp_hpd.h" +#include "dp_debug.h" +#include "dp_pll.h" + +#define DP_PHY_CFG 0x0010 +#define DP_PHY_CFG_1 0x0014 +#define DP_PHY_PD_CTL 0x0018 +#define DP_PHY_MODE 0x001C + +#define DP_PHY_AUX_CFG1 0x0024 +#define DP_PHY_AUX_CFG2 0x0028 + +#define DP_PHY_VCO_DIV 0x0070 +#define DP_PHY_TX0_TX1_LANE_CTL 0x0078 +#define DP_PHY_TX2_TX3_LANE_CTL 0x009C + +#define DP_PHY_SPARE0 0x00C8 +#define DP_PHY_STATUS 0x00E4 + +/* Tx registers */ +#define TXn_CLKBUF_ENABLE 0x0008 +#define TXn_TX_EMP_POST1_LVL 0x000C + +#define TXn_TX_DRV_LVL 0x0014 + +#define TXn_RESET_TSYNC_EN 0x001C +#define TXn_PRE_STALL_LDO_BOOST_EN 0x0020 +#define TXn_TX_BAND 0x0024 +#define TXn_INTERFACE_SELECT 0x002C + +#define TXn_RES_CODE_LANE_OFFSET_TX 0x003C +#define TXn_RES_CODE_LANE_OFFSET_RX 0x0040 + +#define TXn_TRANSCEIVER_BIAS_EN 0x0054 +#define TXn_HIGHZ_DRVR_EN 0x0058 +#define TXn_TX_POL_INV 0x005C +#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0060 + +/* PLL register offset */ +#define QSERDES_COM_BG_TIMER 0x00BC +#define QSERDES_COM_SSC_EN_CENTER 0x00C0 +#define QSERDES_COM_SSC_ADJ_PER1 0x00C4 +#define QSERDES_COM_SSC_PER1 0x00CC +#define QSERDES_COM_SSC_PER2 0x00D0 +#define QSERDES_COM_SSC_STEP_SIZE1_MODE0 0x0060 +#define QSERDES_COM_SSC_STEP_SIZE2_MODE0 0X0064 +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x00DC +#define QSERDES_COM_CLK_ENABLE1 0x00E0 +#define QSERDES_COM_SYS_CLK_CTRL 0x00E4 +#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x00E8 +#define QSERDES_COM_PLL_IVCO 0x00F4 + +#define QSERDES_COM_CP_CTRL_MODE0 0x0070 +#define QSERDES_COM_PLL_RCTRL_MODE0 0x0074 +#define QSERDES_COM_PLL_CCTRL_MODE0 0x0078 +#define QSERDES_COM_SYSCLK_EN_SEL 0x0110 +#define QSERDES_COM_RESETSM_CNTRL 0x0118 +#define QSERDES_COM_LOCK_CMP_EN 0x0120 +#define QSERDES_COM_LOCK_CMP1_MODE0 0x0080 +#define QSERDES_COM_LOCK_CMP2_MODE0 0x0084 + +#define QSERDES_COM_DEC_START_MODE0 0x0088 +#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x0090 +#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x0094 +#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x0098 +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x00A0 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x00A4 +#define QSERDES_COM_VCO_TUNE_CTRL 0x013C +#define QSERDES_COM_VCO_TUNE_MAP 0x0140 + +#define QSERDES_COM_CMN_STATUS 0x01D0 +#define QSERDES_COM_CLK_SEL 0x0164 +#define QSERDES_COM_HSCLK_SEL_1 0x003C + +#define QSERDES_COM_CORECLK_DIV_MODE0 0x007C + +#define QSERDES_COM_CORE_CLK_EN 0x0170 +#define QSERDES_COM_C_READY_STATUS 0x01F8 +#define QSERDES_COM_CMN_CONFIG_1 0x0174 + +#define QSERDES_COM_SVS_MODE_CLK_SEL 0x017C +#define QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x0058 +#define QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x005C +/* Tx tran offsets */ +#define DP_TRAN_DRVR_EMP_EN 0x00C0 +#define DP_TX_INTERFACE_MODE 0x00C4 + +/* Tx VMODE offsets */ +#define DP_VMODE_CTRL1 0x00C8 + +#define DP_PHY_PLL_POLL_SLEEP_US 500 +#define DP_PHY_PLL_POLL_TIMEOUT_US 10000 + +#define DP_VCO_RATE_8100MHZDIV1000 8100000UL +#define DP_VCO_RATE_9720MHZDIV1000 9720000UL +#define DP_VCO_RATE_10800MHZDIV1000 10800000UL + +#define DP_PLL_NUM_CLKS 2 + +#define DP_4NM_C_READY BIT(0) +#define DP_4NM_FREQ_DONE BIT(0) +#define DP_4NM_PLL_LOCKED BIT(1) +#define DP_4NM_PHY_READY BIT(1) +#define DP_4NM_TSYNC_DONE BIT(0) + +static int dp_vco_clk_set_div(struct dp_pll *pll, unsigned int div) +{ + u32 val = 0; + + if (!pll) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + if (is_gdsc_disabled(pll)) + return -EINVAL; + + val = dp_pll_read(dp_phy, DP_PHY_VCO_DIV); + val &= ~0x03; + + switch (div) { + case 2: + val |= 1; + break; + case 4: + val |= 2; + break; + case 6: + /* When div = 6, val is 0, so do nothing here */ + ; + break; + case 8: + val |= 3; + break; + default: + DP_DEBUG("unsupported div value %d\n", div); + return -EINVAL; + } + + dp_pll_write(dp_phy, DP_PHY_VCO_DIV, val); + /* Make sure the PHY registers writes are done */ + wmb(); + + DP_DEBUG("val=%d div=%x\n", val, div); + return 0; +} + +static int set_vco_div(struct dp_pll *pll, unsigned long rate) +{ + int div; + int rc = 0; + + if (rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) + div = 6; + else if (rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) + div = 4; + else + div = 2; + + rc = dp_vco_clk_set_div(pll, div); + if (rc < 0) { + DP_DEBUG("set vco div failed\n"); + return rc; + } + + return 0; +} + +static int dp_vco_pll_init_db_4nm(struct dp_pll_db *pdb, + unsigned long rate) +{ + struct dp_pll *pll = pdb->pll; + u32 spare_value = 0; + + spare_value = dp_pll_read(dp_phy, DP_PHY_SPARE0); + pdb->lane_cnt = spare_value & 0x0F; + pdb->orientation = (spare_value & 0xF0) >> 4; + + DP_DEBUG("spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n", + spare_value, pdb->lane_cnt, pdb->orientation); + + pdb->div_frac_start1_mode0 = 0x00; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + + switch (rate) { + case DP_VCO_HSCLK_RATE_1620MHZDIV1000: + DP_DEBUG("VCO rate: %ld\n", DP_VCO_RATE_9720MHZDIV1000); + pdb->hsclk_sel = 0x05; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x6f; + pdb->lock_cmp2_mode0 = 0x08; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x04; + pdb->ssc_step_size1_mode0 = 0x45; + pdb->ssc_step_size2_mode0 = 0x06; + pdb->ssc_per1 = 0x36; + pdb->cmp_code1_mode0 = 0xE2; + pdb->cmp_code2_mode0 = 0x18; + break; + case DP_VCO_HSCLK_RATE_2700MHZDIV1000: + DP_DEBUG("VCO rate: %ld\n", DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x03; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x0f; + pdb->lock_cmp2_mode0 = 0x0e; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x08; + pdb->ssc_step_size1_mode0 = 0x13; + pdb->ssc_step_size2_mode0 = 0x06; + pdb->ssc_per1 = 0x40; + pdb->cmp_code1_mode0 = 0xE2; + pdb->cmp_code2_mode0 = 0x18; + break; + case DP_VCO_HSCLK_RATE_5400MHZDIV1000: + DP_DEBUG("VCO rate: %ld\n", DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x01; + pdb->dec_start_mode0 = 0x8c; + pdb->div_frac_start2_mode0 = 0x00; + pdb->div_frac_start3_mode0 = 0x0a; + pdb->lock_cmp1_mode0 = 0x1f; + pdb->lock_cmp2_mode0 = 0x1c; + pdb->phy_vco_div = 0x2; + pdb->lock_cmp_en = 0x08; + pdb->ssc_step_size1_mode0 = 0x1a; + pdb->ssc_step_size2_mode0 = 0x08; + pdb->ssc_per1 = 0x40; + pdb->cmp_code1_mode0 = 0x2E; + pdb->cmp_code2_mode0 = 0x21; + break; + case DP_VCO_HSCLK_RATE_8100MHZDIV1000: + DP_DEBUG("VCO rate: %ld\n", DP_VCO_RATE_8100MHZDIV1000); + pdb->hsclk_sel = 0x00; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x2f; + pdb->lock_cmp2_mode0 = 0x2a; + pdb->phy_vco_div = 0x0; + pdb->lock_cmp_en = 0x08; + pdb->ssc_step_size1_mode0 = 0x13; + pdb->ssc_step_size2_mode0 = 0x06; + pdb->ssc_per1 = 0x40; + pdb->cmp_code1_mode0 = 0xE2; + pdb->cmp_code2_mode0 = 0x18; + break; + default: + DP_ERR("unsupported rate %ld\n", rate); + return -EINVAL; + } + return 0; +} + +static int dp_config_vco_rate_4nm(struct dp_pll *pll, + unsigned long rate) +{ + int rc = 0; + struct dp_pll_db *pdb = (struct dp_pll_db *)pll->priv; + + rc = dp_vco_pll_init_db_4nm(pdb, rate); + if (rc < 0) { + DP_ERR("VCO Init DB failed\n"); + return rc; + } + + dp_pll_write(dp_phy, DP_PHY_CFG_1, 0x0F); + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC2) + dp_pll_write(dp_phy, DP_PHY_PD_CTL, 0x6d); + else + dp_pll_write(dp_phy, DP_PHY_PD_CTL, 0x75); + } else { + dp_pll_write(dp_phy, DP_PHY_PD_CTL, 0x7d); + } + + /* Make sure the PHY register writes are done */ + wmb(); + + dp_pll_write(dp_pll, QSERDES_COM_SVS_MODE_CLK_SEL, 0x15); + dp_pll_write(dp_pll, QSERDES_COM_SYSCLK_EN_SEL, 0x3b); + dp_pll_write(dp_pll, QSERDES_COM_SYS_CLK_CTRL, 0x02); + dp_pll_write(dp_pll, QSERDES_COM_CLK_ENABLE1, 0x0c); + dp_pll_write(dp_pll, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06); + dp_pll_write(dp_pll, QSERDES_COM_CLK_SEL, 0x30); + /* Make sure the PHY register writes are done */ + wmb(); + + /* PLL Optimization */ + dp_pll_write(dp_pll, QSERDES_COM_PLL_IVCO, 0x0f); + dp_pll_write(dp_pll, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); + dp_pll_write(dp_pll, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); + dp_pll_write(dp_pll, QSERDES_COM_CP_CTRL_MODE0, 0x06); + /* Make sure the PLL register writes are done */ + wmb(); + + /* link rate dependent params */ + dp_pll_write(dp_pll, QSERDES_COM_HSCLK_SEL_1, pdb->hsclk_sel); + dp_pll_write(dp_pll, QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0); + dp_pll_write(dp_pll, + QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0); + dp_pll_write(dp_pll, + QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0); + dp_pll_write(dp_pll, + QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0); + dp_pll_write(dp_pll, QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0); + dp_pll_write(dp_pll, QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0); + dp_pll_write(dp_pll, QSERDES_COM_LOCK_CMP_EN, pdb->lock_cmp_en); + dp_pll_write(dp_phy, DP_PHY_VCO_DIV, pdb->phy_vco_div); + /* Make sure the PLL register writes are done */ + wmb(); + + dp_pll_write(dp_pll, QSERDES_COM_CMN_CONFIG_1, 0x12); + dp_pll_write(dp_pll, QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3f); + dp_pll_write(dp_pll, QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00); + dp_pll_write(dp_pll, QSERDES_COM_VCO_TUNE_MAP, 0x00); + /* Make sure the PHY register writes are done */ + wmb(); + + dp_pll_write(dp_pll, QSERDES_COM_BG_TIMER, 0x0e); + dp_pll_write(dp_pll, QSERDES_COM_CORECLK_DIV_MODE0, 0x14); + dp_pll_write(dp_pll, QSERDES_COM_VCO_TUNE_CTRL, 0x00); + + if (pll->bonding_en) + dp_pll_write(dp_pll, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1f); + else + dp_pll_write(dp_pll, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1D); + + dp_pll_write(dp_pll, QSERDES_COM_CORE_CLK_EN, 0x1f); + dp_pll_write(dp_pll, QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0, pdb->cmp_code1_mode0); + dp_pll_write(dp_pll, QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0, pdb->cmp_code2_mode0); + /* Make sure the PHY register writes are done */ + wmb(); + + if (pll->ssc_en) { + dp_pll_write(dp_pll, QSERDES_COM_SSC_EN_CENTER, 0x01); + dp_pll_write(dp_pll, QSERDES_COM_SSC_ADJ_PER1, 0x00); + dp_pll_write(dp_pll, QSERDES_COM_SSC_PER1, pdb->ssc_per1); + dp_pll_write(dp_pll, QSERDES_COM_SSC_PER2, 0x01); + dp_pll_write(dp_pll, QSERDES_COM_SSC_STEP_SIZE1_MODE0, + pdb->ssc_step_size1_mode0); + dp_pll_write(dp_pll, QSERDES_COM_SSC_STEP_SIZE2_MODE0, + pdb->ssc_step_size2_mode0); + } + + if (pdb->orientation == ORIENTATION_CC2) + dp_pll_write(dp_phy, DP_PHY_MODE, 0x4c); + else + dp_pll_write(dp_phy, DP_PHY_MODE, 0x5c); + + dp_pll_write(dp_phy, DP_PHY_AUX_CFG1, 0x13); + dp_pll_write(dp_phy, DP_PHY_AUX_CFG2, 0xA4); + /* Make sure the PLL register writes are done */ + wmb(); + + /* TX-0 register configuration */ + dp_pll_write(dp_phy, DP_PHY_TX0_TX1_LANE_CTL, 0x05); + dp_pll_write(dp_ln_tx0, DP_VMODE_CTRL1, 0x40); + dp_pll_write(dp_ln_tx0, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + dp_pll_write(dp_ln_tx0, TXn_INTERFACE_SELECT, 0x3b); + dp_pll_write(dp_ln_tx0, TXn_CLKBUF_ENABLE, 0x0f); + dp_pll_write(dp_ln_tx0, TXn_RESET_TSYNC_EN, 0x03); + dp_pll_write(dp_ln_tx0, DP_TRAN_DRVR_EMP_EN, 0xf); + dp_pll_write(dp_ln_tx0, TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + dp_pll_write(dp_ln_tx0, DP_TX_INTERFACE_MODE, 0x00); + dp_pll_write(dp_ln_tx0, TXn_RES_CODE_LANE_OFFSET_TX, 0x0A); + dp_pll_write(dp_ln_tx0, TXn_RES_CODE_LANE_OFFSET_RX, 0x11); + dp_pll_write(dp_ln_tx0, TXn_TX_BAND, 0x04); + /* Make sure the PLL register writes are done */ + wmb(); + + /* TX-1 register configuration */ + dp_pll_write(dp_phy, DP_PHY_TX2_TX3_LANE_CTL, 0x05); + dp_pll_write(dp_ln_tx1, DP_VMODE_CTRL1, 0x40); + dp_pll_write(dp_ln_tx1, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + dp_pll_write(dp_ln_tx1, TXn_INTERFACE_SELECT, 0x3b); + dp_pll_write(dp_ln_tx1, TXn_CLKBUF_ENABLE, 0x0f); + dp_pll_write(dp_ln_tx1, TXn_RESET_TSYNC_EN, 0x03); + dp_pll_write(dp_ln_tx1, DP_TRAN_DRVR_EMP_EN, 0xf); + dp_pll_write(dp_ln_tx1, TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + dp_pll_write(dp_ln_tx1, DP_TX_INTERFACE_MODE, 0x00); + dp_pll_write(dp_ln_tx1, TXn_RES_CODE_LANE_OFFSET_TX, 0x0A); + dp_pll_write(dp_ln_tx1, TXn_RES_CODE_LANE_OFFSET_RX, 0x11); + dp_pll_write(dp_ln_tx1, TXn_TX_BAND, 0x04); + /* Make sure the PHY register writes are done */ + wmb(); + + return set_vco_div(pll, rate); +} + +enum dp_4nm_pll_status { + C_READY, + FREQ_DONE, + PLL_LOCKED, + PHY_READY, + TSYNC_DONE, +}; + +char *dp_4nm_pll_get_status_name(enum dp_4nm_pll_status status) +{ + switch (status) { + case C_READY: + return "C_READY"; + case FREQ_DONE: + return "FREQ_DONE"; + case PLL_LOCKED: + return "PLL_LOCKED"; + case PHY_READY: + return "PHY_READY"; + case TSYNC_DONE: + return "TSYNC_DONE"; + default: + return "unknown"; + } +} + +static bool dp_4nm_pll_get_status(struct dp_pll *pll, + enum dp_4nm_pll_status status) +{ + u32 reg, state, bit; + void __iomem *base; + bool success = true; + + switch (status) { + case C_READY: + base = dp_pll_get_base(dp_pll); + reg = QSERDES_COM_C_READY_STATUS; + bit = DP_4NM_C_READY; + break; + case FREQ_DONE: + base = dp_pll_get_base(dp_pll); + reg = QSERDES_COM_CMN_STATUS; + bit = DP_4NM_FREQ_DONE; + break; + case PLL_LOCKED: + base = dp_pll_get_base(dp_pll); + reg = QSERDES_COM_CMN_STATUS; + bit = DP_4NM_PLL_LOCKED; + break; + case PHY_READY: + base = dp_pll_get_base(dp_phy); + reg = DP_PHY_STATUS; + bit = DP_4NM_PHY_READY; + break; + case TSYNC_DONE: + base = dp_pll_get_base(dp_phy); + reg = DP_PHY_STATUS; + bit = DP_4NM_TSYNC_DONE; + break; + default: + return false; + } + + if (readl_poll_timeout_atomic((base + reg), state, + ((state & bit) > 0), + DP_PHY_PLL_POLL_SLEEP_US, + DP_PHY_PLL_POLL_TIMEOUT_US)) { + DP_ERR("%s failed, status=%x\n", + dp_4nm_pll_get_status_name(status), state); + + success = false; + } + + return success; +} + +static int dp_pll_enable_4nm(struct dp_pll *pll) +{ + int rc = 0; + + pll->aux->state &= ~DP_STATE_PLL_LOCKED; + + dp_pll_write(dp_phy, DP_PHY_CFG, 0x01); + dp_pll_write(dp_phy, DP_PHY_CFG, 0x05); + dp_pll_write(dp_phy, DP_PHY_CFG, 0x01); + dp_pll_write(dp_phy, DP_PHY_CFG, 0x09); + dp_pll_write(dp_pll, QSERDES_COM_RESETSM_CNTRL, 0x20); + wmb(); /* Make sure the PLL register writes are done */ + + if (!dp_4nm_pll_get_status(pll, C_READY)) { + rc = -EINVAL; + goto lock_err; + } + + if (!dp_4nm_pll_get_status(pll, FREQ_DONE)) { + rc = -EINVAL; + goto lock_err; + } + + if (!dp_4nm_pll_get_status(pll, PLL_LOCKED)) { + rc = -EINVAL; + goto lock_err; + } + + dp_pll_write(dp_phy, DP_PHY_CFG, 0x19); + /* Make sure the PHY register writes are done */ + wmb(); + + if (!dp_4nm_pll_get_status(pll, TSYNC_DONE)) { + rc = -EINVAL; + goto lock_err; + } + + if (!dp_4nm_pll_get_status(pll, PHY_READY)) { + rc = -EINVAL; + goto lock_err; + } + + pll->aux->state |= DP_STATE_PLL_LOCKED; + DP_DEBUG("PLL is locked\n"); + +lock_err: + return rc; +} + +static void dp_pll_disable_4nm(struct dp_pll *pll) +{ + /* Assert DP PHY power down */ + dp_pll_write(dp_phy, DP_PHY_PD_CTL, 0x2); + /* + * Make sure all the register writes to disable PLL are + * completed before doing any other operation + */ + wmb(); +} + +static int dp_vco_set_rate_4nm(struct dp_pll *pll, unsigned long rate) +{ + int rc = 0; + + if (!pll) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + DP_DEBUG("DP lane CLK rate=%ld\n", rate); + + rc = dp_config_vco_rate_4nm(pll, rate); + if (rc < 0) { + DP_ERR("Failed to set clk rate\n"); + return rc; + } + + return rc; +} + +static int dp_regulator_enable_4nm(struct dp_parser *parser, + enum dp_pm_type pm_type, bool enable) +{ + int rc = 0; + struct dss_module_power mp; + + if (pm_type < DP_CORE_PM || pm_type >= DP_MAX_PM) { + DP_ERR("invalid resource: %d %s\n", pm_type, + dp_parser_pm_name(pm_type)); + return -EINVAL; + } + + mp = parser->mp[pm_type]; + rc = msm_dss_enable_vreg(mp.vreg_config, mp.num_vreg, enable); + if (rc) { + DP_ERR("failed to '%s' vregs for %s\n", + enable ? "enable" : "disable", + dp_parser_pm_name(pm_type)); + return rc; + } + + DP_DEBUG("success: '%s' vregs for %s\n", enable ? "enable" : "disable", + dp_parser_pm_name(pm_type)); + return rc; +} + +static int dp_pll_configure(struct dp_pll *pll, unsigned long rate) +{ + int rc = 0; + + if (!pll || !rate) { + DP_ERR("invalid input parameters rate = %lu\n", rate); + return -EINVAL; + } + + rate = rate * 10; + + if (rate <= DP_VCO_HSCLK_RATE_1620MHZDIV1000) + rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000) + rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000) + rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000; + + rc = dp_vco_set_rate_4nm(pll, rate); + if (rc < 0) { + DP_ERR("pll rate %s set failed\n", rate); + return rc; + } + + pll->vco_rate = rate; + DP_DEBUG("pll rate %lu set success\n", rate); + return rc; +} + +static int dp_pll_prepare(struct dp_pll *pll) +{ + int rc = 0; + + if (!pll) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + /* + * Enable DP_PM_PLL regulator if the PLL revision is 4nm-V1 and the + * link rate is 8.1Gbps. This will result in voting to place Mx rail in + * turbo as required for V1 hardware PLL functionality. + */ + if (pll->revision == DP_PLL_4NM_V1 && + pll->vco_rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) { + rc = dp_regulator_enable_4nm(pll->parser, DP_PLL_PM, true); + if (rc < 0) { + DP_ERR("enable pll power failed\n"); + return rc; + } + } + + rc = dp_pll_enable_4nm(pll); + if (rc < 0) + DP_ERR("ndx=%d failed to enable dp pll\n", pll->index); + + return rc; +} + +static int dp_pll_unprepare(struct dp_pll *pll) +{ + int rc = 0; + + if (!pll) { + DP_ERR("invalid input parameter\n"); + return -EINVAL; + } + + if (pll->revision == DP_PLL_4NM_V1 && + pll->vco_rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) { + rc = dp_regulator_enable_4nm(pll->parser, DP_PLL_PM, false); + if (rc < 0) { + DP_ERR("disable pll power failed\n"); + return rc; + } + } + + dp_pll_disable_4nm(pll); + + return rc; +} + +unsigned long dp_vco_recalc_rate_4nm(struct dp_pll *pll) +{ + u32 hsclk_sel, link_clk_divsel, hsclk_div, link_clk_div = 0; + unsigned long vco_rate = 0; + + if (!pll) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + if (is_gdsc_disabled(pll)) + return 0; + + hsclk_sel = dp_pll_read(dp_pll, QSERDES_COM_HSCLK_SEL_1); + hsclk_sel &= 0x0f; + + switch (hsclk_sel) { + case 5: + hsclk_div = 5; + break; + case 3: + hsclk_div = 3; + break; + case 1: + hsclk_div = 2; + break; + case 0: + hsclk_div = 1; + break; + default: + DP_DEBUG("unknown divider. forcing to default\n"); + hsclk_div = 5; + break; + } + + link_clk_divsel = dp_pll_read(dp_phy, DP_PHY_AUX_CFG2); + link_clk_divsel >>= 2; + link_clk_divsel &= 0x3; + + if (link_clk_divsel == 0) + link_clk_div = 5; + else if (link_clk_divsel == 1) + link_clk_div = 10; + else if (link_clk_divsel == 2) + link_clk_div = 20; + else + DP_ERR("unsupported div. Phy_mode: %d\n", link_clk_divsel); + + if (link_clk_div == 20) { + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + } else { + if (hsclk_div == 5) + vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (hsclk_div == 3) + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (hsclk_div == 2) + vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + vco_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000; + } + + DP_DEBUG("hsclk: sel=0x%x, div=0x%x; lclk: sel=%u, div=%u, rate=%lu\n", + hsclk_sel, hsclk_div, link_clk_divsel, link_clk_div, vco_rate); + + return vco_rate; +} + +static unsigned long dp_pll_link_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dp_pll *pll = NULL; + struct dp_pll_vco_clk *pll_link = NULL; + unsigned long rate = 0; + + if (!hw) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + pll_link = to_dp_vco_hw(hw); + pll = pll_link->priv; + + rate = pll->vco_rate; + rate = pll->vco_rate / 10; + + return rate; +} + +static long dp_pll_link_clk_round(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct dp_pll *pll = NULL; + struct dp_pll_vco_clk *pll_link = NULL; + + if (!hw) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + pll_link = to_dp_vco_hw(hw); + pll = pll_link->priv; + + rate = pll->vco_rate / 10; + + return rate; +} + +static unsigned long dp_pll_vco_div_clk_get_rate(struct dp_pll *pll) +{ + if (pll->vco_rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) + return (pll->vco_rate / 6); + else if (pll->vco_rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) + return (pll->vco_rate / 4); + else + return (pll->vco_rate / 2); +} + +static unsigned long dp_pll_vco_div_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dp_pll *pll = NULL; + struct dp_pll_vco_clk *pll_link = NULL; + + if (!hw) { + DP_ERR("invalid input parameters\n"); + return -EINVAL; + } + + pll_link = to_dp_vco_hw(hw); + pll = pll_link->priv; + + return dp_pll_vco_div_clk_get_rate(pll); +} + +static long dp_pll_vco_div_clk_round(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return dp_pll_vco_div_clk_recalc_rate(hw, *parent_rate); +} + +static const struct clk_ops pll_link_clk_ops = { + .recalc_rate = dp_pll_link_clk_recalc_rate, + .round_rate = dp_pll_link_clk_round, +}; + +static const struct clk_ops pll_vco_div_clk_ops = { + .recalc_rate = dp_pll_vco_div_clk_recalc_rate, + .round_rate = dp_pll_vco_div_clk_round, +}; + +static struct dp_pll_vco_clk dp0_phy_pll_clks[DP_PLL_NUM_CLKS] = { + { + .hw.init = &(struct clk_init_data) { + .name = "dp0_phy_pll_link_clk", + .ops = &pll_link_clk_ops, + }, + }, + { + .hw.init = &(struct clk_init_data) { + .name = "dp0_phy_pll_vco_div_clk", + .ops = &pll_vco_div_clk_ops, + }, + }, +}; + +static struct dp_pll_vco_clk dp_phy_pll_clks[DP_PLL_NUM_CLKS] = { + { + .hw.init = &(struct clk_init_data) { + .name = "dp_phy_pll_link_clk", + .ops = &pll_link_clk_ops, + }, + }, + { + .hw.init = &(struct clk_init_data) { + .name = "dp_phy_pll_vco_div_clk", + .ops = &pll_vco_div_clk_ops, + }, + }, +}; + +static struct dp_pll_db dp_pdb; + +int dp_pll_clock_register_4nm(struct dp_pll *pll) +{ + int rc = 0; + struct platform_device *pdev; + struct dp_pll_vco_clk *pll_clks; + + if (!pll) { + DP_ERR("pll data not initialized\n"); + return -EINVAL; + } + pdev = pll->pdev; + + pll->clk_data = kzalloc(sizeof(*pll->clk_data), GFP_KERNEL); + if (!pll->clk_data) + return -ENOMEM; + + pll->clk_data->clks = kcalloc(DP_PLL_NUM_CLKS, sizeof(struct clk *), + GFP_KERNEL); + if (!pll->clk_data->clks) { + kfree(pll->clk_data); + return -ENOMEM; + } + + pll->clk_data->clk_num = DP_PLL_NUM_CLKS; + pll->priv = &dp_pdb; + dp_pdb.pll = pll; + + pll->pll_cfg = dp_pll_configure; + pll->pll_prepare = dp_pll_prepare; + pll->pll_unprepare = dp_pll_unprepare; + + if (pll->dp_core_revision >= 0x10040000) + pll_clks = dp0_phy_pll_clks; + else + pll_clks = dp_phy_pll_clks; + + rc = dp_pll_clock_register_helper(pll, pll_clks, DP_PLL_NUM_CLKS); + if (rc) { + DP_ERR("Clock register failed rc=%d\n", rc); + goto clk_reg_fail; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, pll->clk_data); + if (rc) { + DP_ERR("Clock add provider failed rc=%d\n", rc); + goto clk_reg_fail; + } + + DP_DEBUG("success\n"); + return rc; + +clk_reg_fail: + dp_pll_clock_unregister_4nm(pll); + return rc; +} + +void dp_pll_clock_unregister_4nm(struct dp_pll *pll) +{ + kfree(pll->clk_data->clks); + kfree(pll->clk_data); +} From f288c1248d9ebf47c6ff66a18a5f4a29e991791a Mon Sep 17 00:00:00 2001 From: Srihitha Tangudu Date: Mon, 22 Nov 2021 17:44:49 +0530 Subject: [PATCH 49/50] disp: msm: add display config support for parrot Add display config support for compilation on parrot target. Change-Id: I994b18687187f89b2794a886286280901ca44edb Signed-off-by: Srihitha Tangudu --- config/gki_parrotdisp.conf | 11 +++++++++++ config/gki_parrotdispconf.h | 16 ++++++++++++++++ msm/Kbuild | 5 +++++ 3 files changed, 32 insertions(+) create mode 100644 config/gki_parrotdisp.conf create mode 100644 config/gki_parrotdispconf.h diff --git a/config/gki_parrotdisp.conf b/config/gki_parrotdisp.conf new file mode 100644 index 00000000..a41c10f8 --- /dev/null +++ b/config/gki_parrotdisp.conf @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +export CONFIG_DRM_MSM=y +export CONFIG_DRM_MSM_SDE=y +export CONFIG_SYNC_FILE=y +export CONFIG_DRM_MSM_DSI=y +export CONFIG_DSI_PARSER=y +export CONFIG_DRM_SDE_WB=y +export CONFIG_QCOM_MDSS_PLL=y +export CONFIG_DRM_MSM_REGISTER_LOGGING=y +export CONFIG_DISPLAY_BUILD=m diff --git a/config/gki_parrotdispconf.h b/config/gki_parrotdispconf.h new file mode 100644 index 00000000..7efc517d --- /dev/null +++ b/config/gki_parrotdispconf.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define CONFIG_DRM_MSM 1 +#define CONFIG_DRM_MSM_SDE 1 +#define CONFIG_SYNC_FILE 1 +#define CONFIG_DRM_MSM_DSI 1 +#define CONFIG_DSI_PARSER 1 +#define CONFIG_DRM_SDE_WB 1 +#define CONFIG_DRM_MSM_REGISTER_LOGGING 1 +#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1 +#define CONFIG_QCOM_MDSS_PLL 1 +#define CONFIG_GKI_DISPLAY 1 diff --git a/msm/Kbuild b/msm/Kbuild index 8fca1d17..12ef51c2 100644 --- a/msm/Kbuild +++ b/msm/Kbuild @@ -17,6 +17,11 @@ ifeq ($(CONFIG_ARCH_NEO), y) LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_neodispconf.h endif +ifeq ($(CONFIG_ARCH_PARROT), y) + include $(DISPLAY_ROOT)/config/gki_parrotdisp.conf + LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_parrotdispconf.h +endif + LINUX_INC += -Iinclude/linux \ -Iinclude/linux/drm From aa0eacb5226e2104157eada027a44eab8939e087 Mon Sep 17 00:00:00 2001 From: Soutrik Mukhopadhyay Date: Fri, 3 Dec 2021 08:45:16 +0530 Subject: [PATCH 50/50] disp: msm: dp: fixed version check 4nm target Changes include support to correct the version check for DP PHY changes for 4nm target. Change-Id: Ib891d43bd5db10edc4b49a70f7a3b8af073167cd Signed-off-by: Soutrik Mukhopadhyay --- msm/dp/dp_catalog.c | 2 +- msm/dp/dp_catalog_v420.c | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index 8f771454..ac1e75a4 100644 --- a/msm/dp/dp_catalog.c +++ b/msm/dp/dp_catalog.c @@ -461,7 +461,7 @@ static bool dp_catalog_ctrl_wait_for_phy_ready( u32 const pll_timeout_us = 10000; phy_version = dp_catalog_get_dp_phy_version(&catalog->dp_catalog); - if (phy_version >= 60000000) { + if (phy_version >= 0x60000000) { reg = DP_PHY_STATUS_V600; } else { reg = DP_PHY_STATUS; diff --git a/msm/dp/dp_catalog_v420.c b/msm/dp/dp_catalog_v420.c index 4a9915f5..4ae0f23f 100644 --- a/msm/dp/dp_catalog_v420.c +++ b/msm/dp/dp_catalog_v420.c @@ -98,21 +98,18 @@ static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux, } catalog = dp_catalog_get_priv_v420(aux); - phy_version = dp_catalog_get_dp_phy_version(catalog->dpc); - if (phy_version >= 60000000) { - io_data = catalog->io->dp_phy; - dp_write(DP_PHY_PD_CTL, 0x79); - wmb(); /* make sure PD programming happened */ + io_data = catalog->io->dp_phy; + dp_write(DP_PHY_PD_CTL, 0x67); + wmb(); /* make sure PD programming happened */ + + phy_version = dp_catalog_get_dp_phy_version(catalog->dpc); + if (phy_version >= 0x60000000) { /* Turn on BIAS current for PHY/PLL */ io_data = catalog->io->dp_pll; dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN_V600, 0x1D); wmb(); /* make sure BIAS programming happened */ } else { - io_data = catalog->io->dp_phy; - dp_write(DP_PHY_PD_CTL, 0x67); - wmb(); /* make sure PD programming happened */ - /* Turn on BIAS current for PHY/PLL */ io_data = catalog->io->dp_pll; dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17); @@ -146,7 +143,7 @@ static void dp_catalog_aux_clear_hw_int_v420(struct dp_catalog_aux *aux) catalog = dp_catalog_get_priv_v420(aux); phy_version = dp_catalog_get_dp_phy_version(catalog->dpc); io_data = catalog->io->dp_phy; - if (phy_version >= 60000000) + if (phy_version >= 0x60000000) data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V600); else data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V420);