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);