Переглянути джерело

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 <[email protected]>
Veera Sundaram Sankaran 5 роки тому
батько
коміт
e8309fcbf5
3 змінених файлів з 160 додано та 3 видалено
  1. 49 0
      msm/sde/sde_hw_top.c
  2. 22 0
      msm/sde/sde_hw_top.h
  3. 89 3
      msm/sde/sde_kms.c

+ 49 - 0
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

+ 22 - 0
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

+ 89 - 3
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);