瀏覽代碼

Merge "disp: msm: dp: ensure failsafe mode in connector mode list"

qctecmdr 2 年之前
父節點
當前提交
9b23a8f4aa
共有 5 個文件被更改,包括 86 次插入45 次删除
  1. 8 1
      msm/dp/dp_display.c
  2. 53 19
      msm/dp/dp_drm.c
  3. 14 0
      msm/dp/dp_drm.h
  4. 9 3
      msm/dp/dp_mst_drm.c
  5. 2 22
      msm/dp/dp_panel.c

+ 8 - 1
msm/dp/dp_display.c

@@ -3040,6 +3040,12 @@ static enum drm_mode_status dp_display_validate_mode(
 
 	dp_display->convert_to_dp_mode(dp_display, panel, mode, &dp_mode);
 
+	/* As per spec, 640x480 mode should always be present as fail-safe */
+	if ((dp_mode.timing.h_active == 640) && (dp_mode.timing.v_active == 480) &&
+			(dp_mode.timing.pixel_clk_khz == 25175)) {
+		goto skip_validation;
+	}
+
 	rc = dp_display_validate_topology(dp, dp_panel, mode, &dp_mode, avail_res);
 	if (rc == -EAGAIN) {
 		dp_panel->convert_to_dp_mode(dp_panel, mode, &dp_mode);
@@ -3057,6 +3063,7 @@ static enum drm_mode_status dp_display_validate_mode(
 	if (rc)
 		goto end;
 
+skip_validation:
 	mode_status = MODE_OK;
 
 	if (!avail_res->num_lm_in_use) {
@@ -3070,7 +3077,7 @@ static enum drm_mode_status dp_display_validate_mode(
 end:
 	mutex_unlock(&dp->session_lock);
 
-	DP_DEBUG_V("[%s] mode is %s\n", mode->name,
+	DP_DEBUG_V("[%s clk:%d] mode is %s\n", mode->name, mode->clock,
 			(mode_status == MODE_OK) ? "valid" : "invalid");
 
 	return mode_status;

+ 53 - 19
msm/dp/dp_drm.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
@@ -308,6 +308,47 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
 	.mode_set     = dp_bridge_mode_set,
 };
 
+int dp_connector_add_custom_mode(struct drm_connector *conn, struct dp_display_mode *dp_mode)
+{
+	struct drm_display_mode *m, drm_mode;
+
+	memset(&drm_mode, 0x0, sizeof(drm_mode));
+	convert_to_drm_mode(dp_mode, &drm_mode);
+	m = drm_mode_duplicate(conn->dev, &drm_mode);
+	if (!m) {
+		DP_ERR("failed to add mode %ux%u\n", drm_mode.hdisplay, drm_mode.vdisplay);
+		return 0;
+	}
+	m->width_mm = conn->display_info.width_mm;
+	m->height_mm = conn->display_info.height_mm;
+	drm_mode_probed_add(conn, m);
+
+	return 1;
+}
+
+void init_failsafe_mode(struct dp_display_mode *dp_mode)
+{
+	static const struct dp_panel_info fail_safe = {
+		.h_active = 640,
+		.v_active = 480,
+		.h_back_porch = 48,
+		.h_front_porch = 16,
+		.h_sync_width = 96,
+		.h_active_low = 1,
+		.v_back_porch = 33,
+		.v_front_porch = 10,
+		.v_sync_width = 2,
+		.v_active_low = 1,
+		.h_skew = 0,
+		.refresh_rate = 60,
+		.pixel_clk_khz = 25175,
+		.bpp = 24,
+		.widebus_en = true,
+	};
+
+	memcpy(&dp_mode->timing, &fail_safe, sizeof(fail_safe));
+}
+
 int dp_connector_config_hdr(struct drm_connector *connector, void *display,
 	struct sde_connector_state *c_state)
 {
@@ -558,7 +599,6 @@ int dp_connector_get_modes(struct drm_connector *connector,
 	int rc = 0;
 	struct dp_display *dp;
 	struct dp_display_mode *dp_mode = NULL;
-	struct drm_display_mode *m, drm_mode;
 	struct sde_connector *sde_conn;
 
 	if (!connector || !display)
@@ -578,25 +618,19 @@ int dp_connector_get_modes(struct drm_connector *connector,
 
 	/* pluggable case assumes EDID is read when HPD */
 	if (dp->is_sst_connected) {
+		/*
+		 * 1. for test request, rc = 1, and dp_mode will have test mode populated
+		 * 2. During normal operation, dp_mode will be untouched
+		 *    a. if mode query succeeds rc >= 0, valid modes will be added to connector
+		 *    b. if edid read failed, then connector mode list will be empty and rc <= 0
+		 */
 		rc = dp->get_modes(dp, sde_conn->drv_panel, dp_mode);
-		if (!rc)
-			DP_ERR("failed to get DP sink modes, rc=%d\n", rc);
-
-		if (dp_mode->timing.pixel_clk_khz) { /* valid DP mode */
-			memset(&drm_mode, 0x0, sizeof(drm_mode));
-			convert_to_drm_mode(dp_mode, &drm_mode);
-			m = drm_mode_duplicate(connector->dev, &drm_mode);
-			if (!m) {
-				DP_ERR("failed to add mode %ux%u\n",
-				       drm_mode.hdisplay,
-				       drm_mode.vdisplay);
-				kfree(dp_mode);
-				return 0;
-			}
-			m->width_mm = connector->display_info.width_mm;
-			m->height_mm = connector->display_info.height_mm;
-			drm_mode_probed_add(connector, m);
+		if (!rc) {
+			DP_WARN("failed to get DP sink modes, adding failsafe");
+			init_failsafe_mode(dp_mode);
 		}
+		if (dp_mode->timing.pixel_clk_khz) /* valid DP mode */
+			rc = dp_connector_add_custom_mode(connector, dp_mode);
 	} else {
 		DP_ERR("No sink connected\n");
 	}

+ 14 - 0
msm/dp/dp_drm.h

@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
@@ -168,6 +169,19 @@ int dp_connector_update_pps(struct drm_connector *connector,
 int dp_connector_install_properties(void *display,
 		struct drm_connector *conn);
 
+/**
+ * init_failsafe_mode - add failsafe edid mode
+ * @dp_mode: Pointer to mode
+ */
+void init_failsafe_mode(struct dp_display_mode *dp_mode);
+
+/**
+ * dp_connector_add_custom_mode - add edid mode to connector
+ * @conn: Pointer to connector
+ * @dp_mode: Pointer to mode
+ */
+int dp_connector_add_custom_mode(struct drm_connector *conn, struct dp_display_mode *dp_mode);
+
 #else
 static inline int dp_connector_config_hdr(struct drm_connector *connector,
 		void *display, struct sde_connector_state *c_state)

+ 9 - 3
msm/dp/dp_mst_drm.c

@@ -1178,6 +1178,7 @@ static int dp_mst_connector_get_modes(struct drm_connector *connector,
 	struct sde_connector *c_conn = to_sde_connector(connector);
 	struct dp_display *dp_display = display;
 	struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
+	struct dp_display_mode *dp_mode = NULL;
 	int rc = 0;
 	struct edid *edid = NULL;
 
@@ -1195,7 +1196,7 @@ static int dp_mst_connector_get_modes(struct drm_connector *connector,
 			&mst->mst_mgr, c_conn->mst_port);
 
 	if (!edid) {
-		DP_ERR("get edid failed. id: %d\n", connector->base.id);
+		DP_WARN("get edid failed. id: %d\n", connector->base.id);
 		goto end;
 	}
 
@@ -1220,8 +1221,13 @@ duplicate_edid:
 end:
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, connector->base.id, rc);
 	if (rc <= 0) {
-		DP_ERR("conn:%d has no modes, rc=%d\n", connector->base.id, rc);
-		rc = 0;
+		DP_WARN("conn:%d has no modes, adding failsafe. rc=%d\n", connector->base.id, rc);
+		dp_mode = kzalloc(sizeof(*dp_mode),  GFP_KERNEL);
+		if (!dp_mode)
+			return 0;
+
+		init_failsafe_mode(dp_mode);
+		rc = dp_connector_add_custom_mode(connector, dp_mode);
 	} else {
 		DP_MST_INFO("conn:%d has %d modes\n", connector->base.id, rc);
 	}

+ 2 - 22
msm/dp/dp_panel.c

@@ -84,23 +84,6 @@ struct dp_panel_private {
 	u8 minor;
 };
 
-static const struct dp_panel_info fail_safe = {
-	.h_active = 640,
-	.v_active = 480,
-	.h_back_porch = 48,
-	.h_front_porch = 16,
-	.h_sync_width = 96,
-	.h_active_low = 0,
-	.v_back_porch = 33,
-	.v_front_porch = 10,
-	.v_sync_width = 2,
-	.v_active_low = 0,
-	.h_skew = 0,
-	.refresh_rate = 60,
-	.pixel_clk_khz = 25200,
-	.bpp = 24,
-};
-
 /* OEM NAME */
 static const u8 vendor_name[8] = {81, 117, 97, 108, 99, 111, 109, 109};
 
@@ -1540,7 +1523,7 @@ static int dp_panel_dsc_prepare_basic_params(
 	 * 2. The ppr per slice cannot exceed the maximum.
 	 * 3. The number of slices must be explicitly supported.
 	 */
-	while (slice_width >= max_slice_width ||
+	while (slice_width > max_slice_width ||
 			ppr_per_slice > peak_throughput ||
 			!dp_panel_check_slice_support(
 			comp_info->dsc_info.slice_per_pkt, slice_caps_1,
@@ -2060,10 +2043,7 @@ static int dp_panel_get_modes(struct dp_panel *dp_panel,
 		return _sde_edid_update_modes(connector, dp_panel->edid_ctrl);
 	}
 
-	/* fail-safe mode */
-	memcpy(&mode->timing, &fail_safe,
-		sizeof(fail_safe));
-	return 1;
+	return 0;
 }
 
 static void dp_panel_handle_sink_request(struct dp_panel *dp_panel)