From e8309fcbf552c41a09f2716bee352cf933d6b91b Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Thu, 23 Apr 2020 16:47:17 -0700 Subject: [PATCH] disp: msm: sde: use mdp scratch register to pass drm mode info Use MDP scratch registers to pass drm mode index information between the VMs. Expose the APIs which LA VM can use to set the current mode for all active displays before handoff. LE VM relies on this information to set the corresponding display in correct mode during handoff. Change-Id: I4569dd58e953e588bca816ac718335d3f3f7e29b Signed-off-by: Veera Sundaram Sankaran --- msm/sde/sde_hw_top.c | 49 +++++++++++++++++++++++ msm/sde/sde_hw_top.h | 22 +++++++++++ msm/sde/sde_kms.c | 92 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 160 insertions(+), 3 deletions(-) diff --git a/msm/sde/sde_hw_top.c b/msm/sde/sde_hw_top.c index 975b1c5c..35de4e6d 100644 --- a/msm/sde/sde_hw_top.c +++ b/msm/sde/sde_hw_top.c @@ -9,6 +9,7 @@ #include "sde_dbg.h" #include "sde_kms.h" +#define SCRATCH_REGISTER_0 0x14 #define SSPP_SPARE 0x28 #define UBWC_DEC_HW_VERSION 0x058 #define UBWC_STATIC 0x144 @@ -614,6 +615,51 @@ static u32 sde_hw_get_autorefresh_status(struct sde_hw_mdp *mdp, u32 intf_idx) return autorefresh_status; } +static void sde_hw_clear_mode_index(struct sde_hw_mdp *mdp) +{ + struct sde_hw_blk_reg_map c; + + if (!mdp) + return; + + c = mdp->hw; + c.blk_off = 0x0; + + SDE_REG_WRITE(&c, SCRATCH_REGISTER_0, 0x0); +} + +static void sde_hw_set_mode_index(struct sde_hw_mdp *mdp, u32 display_id, + u32 mode) +{ + struct sde_hw_blk_reg_map c; + u32 value = 0; + + if (!mdp) + return; + + c = mdp->hw; + c.blk_off = 0x0; + + /* 4-bits for mode index of each display */ + value = SDE_REG_READ(&c, SCRATCH_REGISTER_0); + value |= (mode << (display_id * 4)); + SDE_REG_WRITE(&c, SCRATCH_REGISTER_0, value); +} + +static u32 sde_hw_get_mode_index(struct sde_hw_mdp *mdp, u32 display_id) +{ + struct sde_hw_blk_reg_map c; + u32 value = 0; + + c = mdp->hw; + c.blk_off = 0x0; + + value = SDE_REG_READ(&c, SCRATCH_REGISTER_0); + value = (value >> (display_id * 4)) & 0xF; + + return value; +} + static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, unsigned long cap) { @@ -631,6 +677,9 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, ops->reset_ubwc = sde_hw_reset_ubwc; ops->intf_audio_select = sde_hw_intf_audio_select; ops->set_mdp_hw_events = sde_hw_mdp_events; + ops->set_mode_index = sde_hw_set_mode_index; + ops->get_mode_index = sde_hw_get_mode_index; + ops->clear_mode_index = sde_hw_clear_mode_index; if (cap & BIT(SDE_MDP_VSYNC_SEL)) ops->setup_vsync_source = sde_hw_setup_vsync_source; else diff --git a/msm/sde/sde_hw_top.h b/msm/sde/sde_hw_top.h index e27d3666..dd8cc512 100644 --- a/msm/sde/sde_hw_top.h +++ b/msm/sde/sde_hw_top.h @@ -207,6 +207,28 @@ struct sde_hw_mdp_ops { */ void (*set_mdp_hw_events)(struct sde_hw_mdp *mdp, bool enable); + /** + * clear_mode_index - clears the mode index in spare reg + * @mdp: mdp top context driver + */ + void (*clear_mode_index)(struct sde_hw_mdp *mdp); + + /** + * set_mode_index - sets the current drm mode index to spare reg + * @mdp: mdp top context driver + * @display_id: display index + * @mode: drm mode index + */ + void (*set_mode_index)(struct sde_hw_mdp *mdp, u32 display_id, + u32 mode); + + /** + * get_mode_index - gets the current drm mode index from spare reg + * @mdp: mdp top context driver + * @display_id: display index + */ + u32 (*get_mode_index)(struct sde_hw_mdp *mdp, u32 display_id); + /** * set_cwb_ppb_cntl - select the data point for CWB * @mdp: mdp top context driver diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 5946ca37..ac48b4a1 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1179,6 +1179,59 @@ static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms, } } +void _sde_kms_program_mode_info(struct sde_kms *sde_kms) +{ + struct drm_encoder *encoder; + struct drm_crtc *crtc; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct dsi_display *dsi_display; + struct drm_display_mode *drm_mode; + int i; + struct drm_device *dev; + u32 mode_index = 0; + + if (!sde_kms->dev || !sde_kms->hw_mdp) + return; + + dev = sde_kms->dev; + sde_kms->hw_mdp->ops.clear_mode_index(sde_kms->hw_mdp); + + for (i = 0; i < sde_kms->dsi_display_count; i++) { + dsi_display = (struct dsi_display *)sde_kms->dsi_displays[i]; + + if (dsi_display->bridge->base.encoder) { + encoder = dsi_display->bridge->base.encoder; + crtc = encoder->crtc; + + if (!crtc->state->active) + continue; + + mutex_lock(&dev->mode_config.mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->encoder_ids[0] + == encoder->base.id) + break; + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + + list_for_each_entry(drm_mode, &connector->modes, head) { + if (drm_mode_equal( + &crtc->state->mode, drm_mode)) + break; + mode_index++; + } + + sde_kms->hw_mdp->ops.set_mode_index( + sde_kms->hw_mdp, i, mode_index); + SDE_DEBUG("crtc:%d, display_idx:%d, mode_index:%d\n", + DRMID(crtc), i, mode_index); + } + } +} + int sde_kms_vm_trusted_post_commit(struct sde_kms *sde_kms, struct drm_atomic_state *state) { @@ -1285,6 +1338,9 @@ int sde_kms_vm_primary_post_commit(struct sde_kms *sde_kms, /* handle SDE pre-release */ sde_kms_vm_pre_release(sde_kms, state); + /* program the current drm mode info to scratch reg */ + _sde_kms_program_mode_info(sde_kms); + /* handle non-SDE clients pre-release */ if (vm_ops->vm_client_pre_release) { rc = vm_ops->vm_client_pre_release(sde_kms); @@ -2702,6 +2758,32 @@ static int _sde_kms_update_planes_for_cont_splash(struct sde_kms *sde_kms, return 0; } +static struct drm_display_mode *_sde_kms_get_splash_mode( + struct sde_kms *sde_kms, struct drm_connector *connector, + u32 display_idx) +{ + struct drm_display_mode *drm_mode = NULL, *curr_mode = NULL; + u32 i = 0, mode_index; + + if (sde_kms->splash_data.type == SDE_SPLASH_HANDOFF) { + /* currently consider modes[0] as the preferred mode */ + curr_mode = list_first_entry(&connector->modes, + struct drm_display_mode, head); + } else if (sde_kms->hw_mdp && sde_kms->hw_mdp->ops.get_mode_index) { + mode_index = sde_kms->hw_mdp->ops.get_mode_index( + sde_kms->hw_mdp, display_idx); + list_for_each_entry(drm_mode, &connector->modes, head) { + if (mode_index == i) { + curr_mode = drm_mode; + break; + } + i++; + } + } + + return curr_mode; +} + static int sde_kms_cont_splash_config(struct msm_kms *kms) { void *display; @@ -2818,9 +2900,13 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms) crtc->state->encoder_mask = (1 << drm_encoder_index(encoder)); - /* currently consider modes[0] as the preferred mode */ - drm_mode = list_first_entry(&connector->modes, - struct drm_display_mode, head); + drm_mode = _sde_kms_get_splash_mode(sde_kms, connector, i); + if (!drm_mode) { + SDE_ERROR("invalid drm-mode type:%d, index:%d\n", + sde_kms->splash_data.type, i); + return -EINVAL; + } + SDE_DEBUG("drm_mode->name = %s, type=0x%x, flags=0x%x\n", drm_mode->name, drm_mode->type, drm_mode->flags);