瀏覽代碼

disp: msm: sde: dynamic lm reservation for secondary disp

Primary and secondary displays should have first priority
when reserving lms. Static reservation can potentially block
higher resolutions for the required displays. This patch gets
the layer mixer requirement for primary or secondary display
if available. It reserves those layer mixers dynamically
for the respective display when connector is registered.

Change-Id: Id69dac4c72d6b20008049f4aeb71c0f97d0a426b
Signed-off-by: Nilaan Gunabalachandran <[email protected]>
Nilaan Gunabalachandran 6 年之前
父節點
當前提交
52855c704a
共有 10 個文件被更改,包括 100 次插入45 次删除
  1. 6 5
      msm/dsi/dsi_display.c
  2. 2 2
      msm/msm_drv.h
  3. 10 5
      msm/sde/sde_connector.c
  4. 10 0
      msm/sde/sde_connector.h
  5. 12 11
      msm/sde/sde_encoder.c
  6. 2 4
      msm/sde/sde_encoder.h
  7. 42 7
      msm/sde/sde_hw_catalog.c
  8. 5 1
      msm/sde/sde_hw_catalog.h
  9. 2 2
      msm/sde/sde_kms.c
  10. 9 8
      msm/sde/sde_rm.c

+ 6 - 5
msm/dsi/dsi_display.c

@@ -5075,9 +5075,9 @@ static int dsi_display_ext_get_info(struct drm_connector *connector,
 	info->is_connected = connector->status != connector_status_disconnected;
 
 	if (!strcmp(display->display_type, "primary"))
-		info->is_primary = true;
-	else
-		info->is_primary = false;
+		info->display_type = SDE_CONNECTOR_PRIMARY;
+	else if (!strcmp(display->display_type, "secondary"))
+		info->display_type = SDE_CONNECTOR_SECONDARY;
 
 	info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE |
 			MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG);
@@ -5431,10 +5431,11 @@ int dsi_display_get_info(struct drm_connector *connector,
 		info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
 
 	info->is_connected = true;
-	info->is_primary = false;
 
 	if (!strcmp(display->display_type, "primary"))
-		info->is_primary = true;
+		info->display_type = SDE_CONNECTOR_PRIMARY;
+	else if (!strcmp(display->display_type, "secondary"))
+		info->display_type = SDE_CONNECTOR_SECONDARY;
 
 	info->width_mm = phy_props.panel_width_mm;
 	info->height_mm = phy_props.panel_height_mm;

+ 2 - 2
msm/msm_drv.h

@@ -486,7 +486,7 @@ struct msm_mode_info {
  * @max_height:         Max height of display. In case of hot pluggable display
  *                      this is max height supported by controller
  * @clk_rate:           DSI bit clock per lane in HZ.
- * @is_primary:         Set to true if display is primary display
+ * @display_type:       Enum for type of display
  * @is_te_using_watchdog_timer:  Boolean to indicate watchdog TE is
  *				 used instead of panel TE in cmd mode panels
  * @roi_caps:           Region of interest capability info
@@ -509,7 +509,7 @@ struct msm_display_info {
 	uint32_t max_height;
 	uint64_t clk_rate;
 
-	bool is_primary;
+	uint32_t display_type;
 	bool is_te_using_watchdog_timer;
 	struct msm_roi_caps roi_caps;
 

+ 10 - 5
msm/sde/sde_connector.c

@@ -1533,8 +1533,8 @@ int sde_connector_helper_reset_custom_properties(
 	return 0;
 }
 
-static int _sde_connector_primary_preference(struct sde_connector *sde_conn,
-		struct sde_kms *sde_kms)
+static int _sde_connector_lm_preference(struct sde_connector *sde_conn,
+		 struct sde_kms *sde_kms, uint32_t disp_type)
 {
 	int ret = 0;
 	u32 num_lm = 0;
@@ -1544,6 +1544,11 @@ static int _sde_connector_primary_preference(struct sde_connector *sde_conn,
 		return -EINVAL;
 	}
 
+	if (!disp_type || disp_type >= SDE_CONNECTOR_MAX) {
+		SDE_DEBUG("invalid display_type");
+		return -EINVAL;
+	}
+
 	ret = sde_conn->ops.get_default_lms(sde_conn->display, &num_lm);
 	if (ret || !num_lm) {
 		SDE_DEBUG("failed to get default lm count");
@@ -1557,7 +1562,7 @@ static int _sde_connector_primary_preference(struct sde_connector *sde_conn,
 		return -EINVAL;
 	}
 
-	sde_hw_mixer_set_preference(sde_kms->catalog, num_lm);
+	sde_hw_mixer_set_preference(sde_kms->catalog, num_lm, disp_type);
 
 	return ret;
 }
@@ -2453,8 +2458,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
 		goto error_destroy_property;
 	}
 
-	if (display_info.is_primary)
-		_sde_connector_primary_preference(c_conn, sde_kms);
+	_sde_connector_lm_preference(c_conn, sde_kms,
+			display_info.display_type);
 
 	SDE_DEBUG("connector %d attach encoder %d\n",
 			c_conn->base.base.id, encoder->base.id);

+ 10 - 0
msm/sde/sde_connector.h

@@ -314,6 +314,16 @@ struct sde_connector_ops {
 	int (*get_default_lms)(void *display, u32 *num_lm);
 };
 
+/**
+ * enum sde_connector_display_type - list of display types
+ */
+enum sde_connector_display {
+	SDE_CONNECTOR_UNDEFINED,
+	SDE_CONNECTOR_PRIMARY,
+	SDE_CONNECTOR_SECONDARY,
+	SDE_CONNECTOR_MAX
+};
+
 /**
  * enum sde_connector_events - list of recognized connector events
  */

+ 12 - 11
msm/sde/sde_encoder.c

@@ -408,7 +408,9 @@ bool sde_encoder_is_primary_display(struct drm_encoder *drm_enc)
 {
 	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
 
-	return sde_enc && sde_enc->disp_info.is_primary;
+	return sde_enc &&
+		(sde_enc->disp_info.display_type ==
+		SDE_CONNECTOR_PRIMARY);
 }
 
 int sde_encoder_in_cont_splash(struct drm_encoder *drm_enc)
@@ -659,7 +661,7 @@ void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
 
 	sde_connector_get_mode_info(conn_state, &sde_enc->mode_info);
 	hw_res->topology = sde_enc->mode_info.topology;
-	hw_res->is_primary = sde_enc->disp_info.is_primary;
+	hw_res->display_type = sde_enc->disp_info.display_type;
 }
 
 void sde_encoder_destroy(struct drm_encoder *drm_enc)
@@ -1900,8 +1902,9 @@ static int _sde_encoder_update_rsc_client(
 		qsync_mode = sde_connector_get_qsync_mode(
 				sde_enc->cur_master->connector);
 
-	if (sde_encoder_in_clone_mode(drm_enc) || !disp_info->is_primary ||
-			  (disp_info->is_primary && qsync_mode))
+	if (sde_encoder_in_clone_mode(drm_enc) ||
+			(disp_info->display_type != SDE_CONNECTOR_PRIMARY) ||
+			(disp_info->display_type && qsync_mode))
 		rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
 	else if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
 		rsc_state = enable ? SDE_RSC_CMD_STATE : SDE_RSC_IDLE_STATE;
@@ -1927,7 +1930,7 @@ static int _sde_encoder_update_rsc_client(
 	}
 
 	if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init
-			&& disp_info->is_primary) {
+			&& (disp_info->display_type == SDE_CONNECTOR_PRIMARY)) {
 		/* update it only once */
 		sde_enc->rsc_state_init = true;
 
@@ -2043,7 +2046,7 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
 	struct sde_kms *sde_kms;
 	struct sde_encoder_virt *sde_enc;
 	int rc;
-	bool is_cmd_mode = false, is_primary;
+	bool is_cmd_mode = false;
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
 	priv = drm_enc->dev->dev_private;
@@ -2052,8 +2055,6 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
 	if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
 		is_cmd_mode = true;
 
-	is_primary = sde_enc->disp_info.is_primary;
-
 	SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable);
 	SDE_EVT32(DRMID(drm_enc), enable);
 
@@ -3258,7 +3259,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
 	 * they have been fully disabled, so delay the pre-stop operations
 	 * until after the physical disable calls have returned.
 	 */
-	if (sde_enc->disp_info.is_primary &&
+	if (sde_enc->disp_info.display_type == SDE_CONNECTOR_PRIMARY &&
 	    (intf_mode == INTF_MODE_CMD || intf_mode == INTF_MODE_VIDEO)) {
 		sde_encoder_resource_control(drm_enc,
 				SDE_ENC_RC_EVENT_PRE_STOP);
@@ -4640,7 +4641,6 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
 	SDE_ATRACE_BEGIN("sde_encoder_prepare_for_kickoff");
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		phys = sde_enc->phys_encs[i];
-		params->is_primary = sde_enc->disp_info.is_primary;
 		params->frame_trigger_mode = sde_enc->frame_trigger_mode;
 		params->recovery_events_enabled =
 					sde_enc->recovery_events_enabled;
@@ -5476,7 +5476,8 @@ struct drm_encoder *sde_encoder_init(
 	}
 	snprintf(name, SDE_NAME_SIZE, "rsc_enc%u", drm_enc->base.id);
 	sde_enc->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, name,
-		disp_info->is_primary ? SDE_RSC_PRIMARY_DISP_CLIENT :
+		(disp_info->display_type == SDE_CONNECTOR_PRIMARY) ?
+		SDE_RSC_PRIMARY_DISP_CLIENT :
 		SDE_RSC_EXTERNAL_DISP_CLIENT, intf_index + 1);
 	if (IS_ERR_OR_NULL(sde_enc->rsc_client)) {
 		SDE_DEBUG("sde rsc client create failed :%ld\n",

+ 2 - 4
msm/sde/sde_encoder.h

@@ -43,7 +43,7 @@
  * @needs_cdm:	Encoder requests a CDM based on pixel format conversion needs
  * @display_num_of_h_tiles: Number of horizontal tiles in case of split
  *                          interface
- * @is_primary: set to true if the display is primary display
+ * @display_type: Type of the display
  * @topology:   Topology of the display
  */
 struct sde_encoder_hw_resources {
@@ -51,20 +51,18 @@ struct sde_encoder_hw_resources {
 	enum sde_intf_mode wbs[WB_MAX];
 	bool needs_cdm;
 	u32 display_num_of_h_tiles;
-	bool is_primary;
+	bool display_type;
 	struct msm_display_topology topology;
 };
 
 /**
  * sde_encoder_kickoff_params - info encoder requires at kickoff
- * @is_primary: set to true if the display is primary display
  * @affected_displays:  bitmask, bit set means the ROI of the commit lies within
  *                      the bounds of the physical display at the bit index
  * @recovery_events_enabled: indicates status of client for recoovery events
  * @frame_trigger_mode: indicates frame trigger mode
  */
 struct sde_encoder_kickoff_params {
-	u32 is_primary;
 	unsigned long affected_displays;
 	bool recovery_events_enabled;
 	enum frame_trigger_mode_type frame_trigger_mode;

+ 42 - 7
msm/sde/sde_hw_catalog.c

@@ -15,6 +15,7 @@
 #include "sde_hw_catalog_format.h"
 #include "sde_kms.h"
 #include "sde_hw_uidle.h"
+#include "sde_connector.h"
 
 /*************************************************************
  * MACRO DEFINITION
@@ -1613,16 +1614,50 @@ end:
 	return rc;
 }
 
-void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm)
+void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm,
+		uint32_t disp_type)
 {
-	u32 i;
+	u32 i, cnt = 0, sec_cnt = 0;
+
+	if (disp_type == SDE_CONNECTOR_PRIMARY) {
+		for (i = 0; i < sde_cfg->mixer_count; i++) {
+			/* Check if lm was previously set for secondary */
+			/* Clear pref, primary has higher priority */
+			if (sde_cfg->mixer[i].features &
+					BIT(SDE_DISP_SECONDARY_PREF)) {
+				clear_bit(SDE_DISP_SECONDARY_PREF,
+						&sde_cfg->mixer[i].features);
+				sec_cnt++;
+			}
+			clear_bit(SDE_DISP_PRIMARY_PREF,
+					&sde_cfg->mixer[i].features);
 
-	for (i = 0; i < sde_cfg->mixer_count; i++) {
-		clear_bit(SDE_DISP_PRIMARY_PREF,
-				&sde_cfg->mixer[i].features);
-		if (i < num_lm)
-			set_bit(SDE_DISP_PRIMARY_PREF,
+			/* Set lm for primary pref */
+			if (cnt < num_lm) {
+				set_bit(SDE_DISP_PRIMARY_PREF,
+						&sde_cfg->mixer[i].features);
+				cnt++;
+			}
+
+			/* After primary pref is set, now re apply secondary */
+			if (cnt >= num_lm && cnt < (num_lm + sec_cnt)) {
+				set_bit(SDE_DISP_SECONDARY_PREF,
+						&sde_cfg->mixer[i].features);
+				cnt++;
+			}
+		}
+	} else if (disp_type == SDE_CONNECTOR_SECONDARY) {
+		for (i = 0; i < sde_cfg->mixer_count; i++) {
+			clear_bit(SDE_DISP_SECONDARY_PREF,
 					&sde_cfg->mixer[i].features);
+
+			if (cnt < num_lm && !(sde_cfg->mixer[i].features &
+					BIT(SDE_DISP_PRIMARY_PREF))) {
+				set_bit(SDE_DISP_SECONDARY_PREF,
+						&sde_cfg->mixer[i].features);
+				cnt++;
+			}
+		}
 	}
 }
 

+ 5 - 1
msm/sde/sde_hw_catalog.h

@@ -268,6 +268,7 @@ enum {
  * @SDE_DIM_LAYER             Layer mixer supports dim layer
  * @SDE_DISP_CWB_PREF         Layer mixer preferred for CWB
  * @SDE_DISP_PRIMARY_PREF     Layer mixer preferred for primary display
+ * @SDE_DISP_SECONDARY_PREF   Layer mixer preferred for secondary display
  * @SDE_MIXER_MAX             maximum value
  */
 enum {
@@ -276,6 +277,7 @@ enum {
 	SDE_MIXER_GC,
 	SDE_DIM_LAYER,
 	SDE_DISP_PRIMARY_PREF,
+	SDE_DISP_SECONDARY_PREF,
 	SDE_DISP_CWB_PREF,
 	SDE_MIXER_MAX
 };
@@ -1381,8 +1383,10 @@ struct sde_mdss_hw_cfg_handler {
  *                        overwrite if exists
  * @sde_cfg:              pointer to sspp cfg
  * @num_lm:               num lms to set preference
+ * @disp_type:            is the given display primary/secondary
  */
-void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm);
+void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm,
+		uint32_t disp_type);
 
 /**
  * sde_hw_catalog_init - sde hardware catalog init API parses dtsi property

+ 2 - 2
msm/sde/sde_kms.c

@@ -2347,9 +2347,9 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms)
 			encoder = NULL;
 			continue;
 		}
-		SDE_DEBUG("info.is_connected = %s, info.is_primary = %s\n",
+		SDE_DEBUG("info.is_connected = %s, info.display_type = %d\n",
 			((info.is_connected) ? "true" : "false"),
-			((info.is_primary) ? "true" : "false"));
+			info.display_type);
 
 		if (!encoder) {
 			SDE_ERROR("encoder not initialized\n");

+ 9 - 8
msm/sde/sde_rm.c

@@ -796,7 +796,8 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
 	*dspp = NULL;
 	*ds = NULL;
 	*pp = NULL;
-	display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF);
+	display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF) ||
+			lm_cfg->features & BIT(SDE_DISP_SECONDARY_PREF);
 	cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF);
 
 	SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n",
@@ -831,10 +832,10 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
 			SDE_DEBUG("fail: cwb supported lm not allocated\n");
 			return false;
 		}
-	} else if (!(reqs->hw_res.is_primary && display_pref)) {
+	} else if (!(reqs->hw_res.display_type && display_pref)) {
 		SDE_DEBUG(
-			"display preference is not met. is_primary: %d display_pref: %d\n",
-			(int)reqs->hw_res.is_primary, (int)display_pref);
+			"display preference is not met. display_type: %d display_pref: %d\n",
+			(int)reqs->hw_res.display_type, (int)display_pref);
 		return false;
 	}
 
@@ -1022,11 +1023,11 @@ static int _sde_rm_reserve_ctls(
 			if (top->top_name == SDE_RM_TOPOLOGY_PPSPLIT &&
 					!has_ppsplit)
 				continue;
-		} else if (!(reqs->hw_res.is_primary && primary_pref) &&
-				!_ctl_ids) {
+		} else if (!(reqs->hw_res.display_type ==
+				SDE_CONNECTOR_PRIMARY && primary_pref) && !_ctl_ids) {
 			SDE_DEBUG(
-				"display pref not met. is_primary: %d primary_pref: %d\n",
-				reqs->hw_res.is_primary, primary_pref);
+				"display pref not met. display_type: %d primary_pref: %d\n",
+				reqs->hw_res.display_type, primary_pref);
 			continue;
 		}